AI 资讯
The Evolution of Web Forms — Part 1
The Evolution of Web Forms Part-1 — From Plain HTML to AJAX Modern React forms can feel unnecessarily complicated when you first encounter tools such as React Hook Form, Zod, resolvers, controlled inputs, refs, formState , and server-error handling. Why do we need all of that? Why not simply read the value from an input and send it to the server? To understand why modern form libraries exist, we need to understand the problems developers faced before those libraries were created. In this series, we will evolve the same idea step by step: Plain HTML ↓ Native HTML validation ↓ JavaScript validation ↓ AJAX submission ↓ React controlled forms ↓ Form libraries ↓ React Hook Form ↓ React Hook Form + Zod ↓ Production form architecture This first part covers the first four stages: Plain HTML forms Native HTML validation Vanilla JavaScript validation AJAX form submission By the end, you will understand how forms worked before React and why each new approach became necessary. Stage 1: Plain HTML Forms Before React, AJAX, or even large amounts of client-side JavaScript, browsers already knew how to submit forms. HTML forms are not just visual containers. They are a built-in browser mechanism for collecting data and sending an HTTP request. A basic registration form <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" /> <meta name= "viewport" content= "width=device-width, initial-scale=1.0" /> <title> Registration Form </title> </head> <body> <h1> Create an account </h1> <form action= "/register" method= "POST" > <div> <label for= "username" > Username </label> <input id= "username" name= "username" type= "text" /> </div> <div> <label for= "email" > Email </label> <input id= "email" name= "email" type= "email" /> </div> <div> <label for= "password" > Password </label> <input id= "password" name= "password" type= "password" /> </div> <button type= "submit" > Register </button> </form> </body> </html> There is no JavaScript in this example. The browser handles the ent
AI 资讯
7 Signs You're Over-Engineering Your AI App (and How to Stop)
There's a very specific kind of AI project that looks incredibly impressive in the architecture diagram and does almost nothing a simple version couldn't do better. It has a vector database. It has a multi-agent orchestration graph. It has a fine-tuned model, a memory layer, custom tool wrappers, three retries with exponential backoff, and a couple of "future-proof" abstractions nobody's actually using yet. The agent at the center is simple. The scaffolding around it is a cathedral. Here's the uncomfortable truth most teams learn the hard way: AI apps rarely fail because someone picked the wrong model or framework. They fail because layers got added before anyone could name the problem each layer was supposed to solve. The biggest mistake in building AI apps isn't starting too small — it's starting too big. So here are 7 signs you've crossed into over-engineering, the simpler thing to do instead, and — at the end — a practical playbook for not falling into the trap in the first place. See how many feel a little too familiar. 1. You reached for a vector database before you needed one "First, set up your vector database" became the default opening line of every AI tutorial — so teams spin up Pinecone or Chroma reflexively, before they've confirmed they even have a retrieval problem that requires embeddings. The plot twist of the last year is how often that's overkill. Some of the most capable coding agents around quietly dropped vector search in favor of plain tool-driven search — grep, reading the file tree, asking for files by name. In one widely-cited case, ripping out the embedding pipeline and replacing it with grep reportedly outperformed the vector setup, by a lot. That doesn't mean vector DBs are dead — they're still a strong fit for large, stable knowledge bases (product docs, FAQs, glossaries) with a good reranker. But if your data is small enough to fit in context, or searchable with keywords and filters, you may be maintaining an entire embedding-and-migra
AI 资讯
Generating 50+ SEO Landing Pages from a Static Site Build Script
I run TextTimeTools , a free site with speaking-time and reading-time calculators. It's a pure static site deployed to Cloudflare Pages — no backend, no database, no CMS. The calculators themselves are one page. But the site has 50+ pages , each targeting a different keyword like "how many words is a 5 minute speech" or "how long to read 1000 words". Every single one of those pages is generated by a build script. I've never written one by hand. Here's the pattern, and why it's the highest-leverage thing I've done for this site's organic traffic. The problem with a single calculator page A speaking-time calculator answers one query well: "how many words is my speech". But people don't search for tools — they search for answers : "how many words is a 5 minute speech" "how many words for a 3 minute speech" "how long to read 1000 words" "how long to read 5000 words" Each of those is a separate keyword with its own search intent and its own competition. One calculator page can't rank for all of them — a page titled "Speaking Time Calculator" has no reason to show up for "how long to read 1000 words". The classic fix is to write a page per keyword. That works, but it doesn't scale — every new keyword means hand-writing another page, and keeping them consistent is a nightmare. The fix: generate pages at build time The build script ( gen-longtail.cjs ) takes a list of keyword targets and emits a complete, keyword-specific HTML page for each one. The word count pages and reading time pages are both generated this way. const PAGES = [ { minutes : 1 , slug : ' how-many-words-is-a-1-minute-speech ' , variant : ' is-a ' }, { minutes : 2 , slug : ' how-many-words-is-a-2-minute-speech ' , variant : ' is-a ' }, { minutes : 5 , slug : ' how-many-words-is-a-5-minute-speech ' , variant : ' is-a ' }, // ... up to 15 minutes { minutes : 2 , slug : ' how-many-words-for-a-2-minute-speech ' , variant : ' for-a ' }, { minutes : 5 , slug : ' how-many-words-for-a-5-minute-speech ' , variant :
开发者
How to Extract Colors From an Image Using JavaScript and Canvas?
How to Extract Colors From an Image Using JavaScript and Canvas Have you ever looked at an image and wanted to know the exact HEX color of a particular pixel? Designers often need to extract colors from photographs, screenshots, logos, UI designs, and illustrations. You can do this directly in the browser without uploading the image to a server. The browser Canvas API gives us everything we need. Reading pixels with Canvas The basic process is: Load an image. Draw it onto a canvas. Read the pixel data. Convert the RGBA values into a color format such as HEX or RGB. The important API is getImageData() . javascript const imageData = ctx.getImageData(x, y, 1, 1); const pixel = imageData.data; const r = pixel[0]; const g = pixel[1]; const b = pixel[2]; const a = pixel[3];
开发者
I Used React DataGrid to Build a Real Space Mission Explorer
I went through the documentation and feature list of React DataGrid, and I wrote React DataGrid: A...
AI 资讯
Architectural Breakdown: We fixed the eval platform we're competing on: a TypeError that crashed thr
We Fixed the Eval Platform: The TypeError That Took Down Three Benchmark Pipelines At 3 AM, Sentry lit up with TypeError: Cannot read property 'map' of undefined . Three benchmark pipelines crashed. Not a memory leak, not a segfault, but a race condition hiding behind a TypeError, turning a high-stakes eval run into chaos. Here is how we resolved it, with no fluff. The Root Cause: Async Data Meets Blind Faith in .map() The error trace pointed to evaluator.ts:42 , where .map() assumed inputData.metrics would always exist. The junior dev tested with clean data, but in production, fetchBenchmarkData() (async) and evaluatePipeline() (sync) were racing . At 100+ RPS, metrics was often undefined . The Offending Code: const results = inputData . metrics . map ( metric => computeScore ( metric )); Why It Failed: Race Condition : inputData was fetched asynchronously, but evaluatePipeline() treated it as synchronous. OOM Risk : Unbounded .map() on 10K+ metrics could exhaust 8GB RAM. Worker Starvation : No concurrency limits led to thread pool exhaustion. The Fix: Guard Clauses, Bounded Queues, and Pragmatism Step 1: Fail Fast, Fail Loud Added zero-overhead runtime checks to reject bad data early: // eval-platform/core/evaluator.ts import { isNullOrUndefined } from ' ../utils/guards ' ; async function evaluatePipeline ( inputData : BenchmarkInput ): Promise < EvaluationResult > { if ( isNullOrUndefined ( inputData ?. metrics )) { throw new Error ( ' EVAL_400: metrics missing ' ); } // Proceed only if data is valid } Why? Stops TypeError crashes immediately. Cost: 1-2 CPU cycles. Negligible. Step 2: Chunked Processing for 8GB RAM Original code processed all metrics at once, causing OOM crashes. Fixed with 100-item chunks: const CHUNK_SIZE = 100 ; // 100 items ≈ 10MB peak memory const results : number [] = []; for ( let i = 0 ; i < inputData . metrics . length ; i += CHUNK_SIZE ) { const chunk = inputData . metrics . slice ( i , i + CHUNK_SIZE ); results . push (... chunk . map
AI 资讯
Building PickTool with Next.js and Laravel: Lessons from Creating a Software Discovery Platform
Finding software is easy. Finding the right software is not. Search for almost any category—email marketing, CRM, productivity, design, or AI—and you will find hundreds of options. Every product presents itself as the best choice, while many comparison articles repeat the same features without explaining which users each tool actually suits. That problem inspired me to build PickTool , a platform for discovering and comparing AI and SaaS tools. PickTool is still evolving. I am currently improving its content quality, tool coverage, comparison experience, performance, and SEO structure. This is not a polished launch announcement. It is an honest look at the architecture behind the project and some of the lessons I have learned while building it. What Is PickTool? The goal of PickTool is simple: Help people find the right software in minutes, not hours. Instead of creating a basic directory filled with product names and affiliate links, I want each important tool to include useful and structured information, such as: Core features Pricing model Best use cases Strengths and limitations Ratings and evaluation criteria Alternatives Direct comparisons Related guides and category pages The challenge is that this creates several interconnected types of content. A single product can appear on its own tool page, inside a category, in multiple comparisons, and in articles about the best software for a particular use case. Keeping all of this consistent requires more than publishing isolated blog posts. Why I Chose Next.js and Laravel PickTool uses a decoupled architecture: Next.js powers the public-facing website. Laravel powers the backend, API, database logic, and administration system. MySQL stores tools, categories, ratings, pricing information, and editorial content. I chose this combination because I wanted the frontend and content-management logic to evolve independently. Laravel provides a structured backend for managing relationships between tools and content. Next.js
AI 资讯
Why I Built an Ad-Free Alternative to Untappd
I've used Untappd for years to log the beers I drink. It works. It also drives me a little crazy every time I open it. Between the ads wedged into my feed, the check-in pressure that makes logging a beer feel like a social performance, and an interface that's accumulated more features than I've ever asked for, opening the app to do one simple thing — "I liked this beer, I want to remember it" — started to feel like more work than it should be. So a few weeks ago, I decided to build my own. The idea: Letterboxd, but for beer If you haven't used Letterboxd, it's a film-logging app that took a genre Untappd basically also occupies — "social logging app for a hobby" — and did it with a fraction of the clutter. Clean, fast, personal-journal-first, social-second. That's the model I wanted for beer. I called it HopLog. The pitch, in one sentence: log what you drink, remember what you liked, discover something new — without ads, without check-in pressure, without a hundred features you'll never touch. Building it like an actual product, not just a weekend hack I didn't want to just start writing code and see what happened. Before a single line was written, I worked through the process a real product team would use: A product requirements doc — what's actually in scope for a first version, and just as importantly, what's not User personas — who is this actually for? (Turns out: the casual drinker who wants a nice photo journal, the homebrewer who wants precise tasting notes, and the traveler hunting for good local breweries — three genuinely different people with different needs) User stories, wireframes, a database schema, an API design, and a milestone-by-milestone roadmap Only after all of that did I start building — six milestones, one at a time, each one tested and verified before moving to the next: authentication, a real beer/brewery database, the actual tasting-logging flow, profiles with stats and badges, a social layer with feeds and follows, and finally search pol
AI 资讯
Enforcing a style rule with a linter that actually fails the build
Background I run a fleet of static sites that publish new content every day, mostly unattended. One of the house style rules is simple: no emoji anywhere in our own copy. That rule is impossible to hold by hand. A single site builds a few hundred HTML files, and emoji can slip into nav icons, button labels, <title> , the RSS feed, or JSON-LD (the JSON-formatted metadata embedded in a page to describe its structure to search engines). Nobody is going to review all of that before every deploy. So I wrote emoji-lint , a check that exits 1 the moment it finds a single emoji . It sits in the pre-deploy gate, which means a failure stops that day's publish. This post is not about the regex. It's about what happens when you put a failing check into real operation: you immediately discover the places where the rule must not apply. How it works The core is unremarkable. A regex holds the emoji code point ranges, the scanner walks each file line by line, and matching lines are reported as JSON. const EMOJI_RE = / [\u {1F000}- \u {1FAFF} \u {2600}- \u {27BF} \u {2B00}- \u {2BFF} \u {1F1E6}- \u {1F1FF} \u {FE0F} \u {200D} \u {2049} \u {203C} \u {2122} \u {2139} ] /u ; \u{FE0F} (variation selector) and \u{200D} (ZWJ) are in there because emoji are not always a single code point. Arrows and similar symbols used in ordinary technical writing are deliberately left out. Catch everything and the check drowns in false positives, at which point people stop reading it. The interesting part came later. Three categories of content look exactly like a violation but must not be treated as one: Verbatim quotes from other people Real proper nouns whose official spelling contains a symbol Passages where the emoji itself is the subject being explained Delete the emoji in any of those and you break something more important than the style rule. One term up front: "masking" here means replacing a range with spaces so the scanner cannot see it. Nothing is deleted from the file. Implementation Scope
AI 资讯
Don't validate the output. Validate that you were allowed to generate it.
Introduction I run a site that collects overseas viewer comments about individual anime episodes, translates them, and publishes them. It updates automatically every day. There is one failure mode that matters more than all the others: creating a page for an episode that has not aired yet. If the page exists before the broadcast, there are no comments to put on it. But the heading "Episode 8 — overseas reactions" is already live. An empty page is recoverable. What is not recoverable is a pipeline that decides an empty page looks bad and fills it with something plausible. At that point invented sentences are wearing the face of real people. This post is about the check that prevents that, and about the day it actually fired. The overall shape The obvious implementation is arithmetic on dates: Take the air date of episode 1 Assume weekly broadcast Count the weeks elapsed until today Treat every episode up to that number as aired That works for producing candidates, but it is not evidence that anything aired . A skipped week makes the real count lower. So does a recap episode. Calendar arithmetic never observes the broadcast; it only restates an assumption. So I split the pipeline in two: Candidate generation — weekly arithmetic, guessing which episodes are missing. Guessing is fine here. Existence check — does an observation from outside my system exist for this episode? No guessing allowed here. For the existence check I use the per-episode discussion threads on MyAnimeList (a large anime database; MAL from here on). One thread is created per episode after it airs, and the timestamp of the first post in that thread is readable. Viewers post after watching. So that timestamp is external evidence that the broadcast happened. Better still, it lives in exactly the same place I fetch the comments from, so verification costs no additional data source. The core of the implementation The check is a subtraction between what I claim and what the outside world recorded. /** * @
AI 资讯
How I Actually Code with Claude Code: My Real Workflow on a Real Project
There are two kinds of articles about coding with AI. The ones that generate a sorting function and...
AI 资讯
Too Many Req: A Bucket List Guide to Building a Rate Limiter
Hello, I'm Maneshwar. I'm building git-lrc, a Micro AI code reviewer that runs on every commit. It is free and source-available on Github. Star git-lrc to help devs discover the project. Do give it a try and share your feedback. Every serious API will eventually tell you to sit down and be quiet. Hammer GitHub, Stripe, or AWS a little too eagerly and your requests start bouncing back with a polite but firm 429 . I always found that fascinating, so let's build the thing that says no. By the end of this post we'll have designed a rate limiter that actually holds up when you put it in front of real traffic, and I promise to only make a reasonable number of bucket puns along the way. A rate limiter does one job: it decides how many requests a client is allowed to make in a given window of time. It protects your system from getting flattened, and it keeps one greedy user from eating everyone else's lunch. Simple idea. Surprisingly spicy implementation. Let's build it up piece by piece, the way you'd actually reason through it in an interview or a design doc. First, what are we even building? Before writing a single line, let's agree on what "good" looks like. Here's my wishlist: Configurable limits. Something like "100 requests per minute per user." The rules should not be hardcoded, because free users and premium users deserve different amounts of pain. Honest rejections. When someone goes over, we return HTTP 429 Too Many Requests and include helpful headers telling them how many requests they have left and when the window resets. No mystery. Barely-there latency. This check runs on every single request , so it has to be fast. Let's aim for under 3ms at P95. If your rate limiter is slow, congratulations, you built a second bottleneck. Highly available and shared. Multiple servers need to agree on the same counts. More on why that word "shared" is doing a lot of heavy lifting later. Cool. Now let's start naive and let reality punch us in the face a few times. Attempt 1:
AI 资讯
Checking Polish companies from code: VAT, KRS, REGON, EU VAT (REST + Python + MCP)
If you invoice or onboard Polish companies, sooner or later you have to check two dull things that turn out to matter a lot: is this company actually a registered VAT payer, and is the bank account they gave you the one that's on the government's official white list ("Biała Lista")? Both of those affect whether you can deduct the cost and reclaim VAT, so it's not really optional. The annoying part is that the data lives in four different places: the Ministry of Finance, the KRS court register, GUS (the stats office), and the EU's VIES service. Each one has its own API and its own quirks. I got tired of gluing those together every time, so I wrapped them behind a few plain HTTP calls that return JSON. Full disclosure: skanfirmy.pl is mine. It's free, no key, no signup, and the web layer runs client-side with no tracking. Here's how you'd actually use it. REST: one GET, one JSON Cheapest thing you can do is check a NIP (the tax ID): curl https://skanfirmy.pl/nip/5260250995 You get back the VAT status (active, exempt, or not registered), the company details from the VAT register, and the accounts sitting on the white list. The paths: GET /nip/{nip} gives VAT status + white-list data for one NIP GET /nips/{list} takes several NIPs at once (comma-separated) GET /regon/{nip} returns data from the REGON register (GUS) GET /vies/{country}/{number} validates an EU VAT number, e.g. /vies/DE/811128135 It's a plain GET that returns JSON, so it drops into anything that can make an HTTP request: a cron job, a lambda, a CI step, whatever. Python requests and a few lines. This one raises if the company isn't an active VAT payer: import requests def check_vat ( nip : str ) -> dict : r = requests . get ( f " https://skanfirmy.pl/nip/ { nip } " , timeout = 10 ) r . raise_for_status () data = r . json () status = data . get ( " vatStatus " ) or data . get ( " status " ) if status != " Czynny " : # status comes back in Polish; compare against the raw value raise ValueError ( f " NIP { n
AI 资讯
App-like UX in Next.js 16.3
Building App-like Experiences with Next.js 16.3 A hands-on look at how Next.js 16.3 helps apps feel fast and smooth, more like a single-page app, without losing the benefits of server rendering. Using four demo apps, it shows how features like Instant Navigations, Cache Components, Partial Prefetching, optimistic updates, Suspense streaming, offline retry, and View Transitions work together in real apps ⚡️ Sponsor: Arcjet AI compliance controls Protect your AI applications from prompt injection, PII leaks, and unauthorized tool calls. 📙 Articles / Tutorials / News Next.js team AMA The Next.js team opened the floor to community questions and covered a lot of ground. The AMA focused on Next.js 16.3, performance, caching, App Router, React Server Components, and upgrading apps, along with some insight into how the team works on the framework Coordinating Optimistic Updates in Next.js This guide shows how useActionState and useOptimistic can work together to keep the UI updated right away, save changes in the right order, and roll back cleanly if something fails Using next/root-params in Next.js 16.3 The new next/root-params API lets Server Components read top-level params like [locale] from deep in the tree, which makes next-intl much easier to use Docs for React's new browser() API The docs for React's new browser() API are now available in Canary. You can pass it to use() , where it suspends to the nearest Suspense boundary on the server, then renders normally in the browser 📦 Projects / Packages / Tools Better Auth 1.7 A big release for Better Auth, especially around OAuth, OpenID Connect, SCIM, SSO, MCP, and device login flows. The main theme here is stronger auth, better enterprise identity support, and more standards-based ways for apps and devices to sign in and get access Next 16 Calendar "Flow" A calendar and booking demo exploring Async React, Cache Components, Partial Prefetching, and View Transitions with Next.js 16.3, React 19, Tailwind CSS v4, and Prisma.
AI 资讯
I’ve spent the last few years deeply embedded in Web3: running operations, building products, and pitching to VCs. Here's how i pick a dev team:
The single biggest operational risk for early-stage founders remains hiring traditional hourly dev shops. Before partnering with any external dev team, I've learned to run them through this 5-point evaluation framework: The 5-Point Evaluation (co-founder approved) 1. Quality of Questions If a team asks zero questions, it’s an immediate red flag. It's impossible to deeply understand a project without asking anything. But quality matters. Weak devs ask easily googled questions about basic blockchain mechanics. Strong engineers ask highly specific questions focused entirely on your business logic, edge cases, and tokenomics. 2. Proposing Solutions, Not Problems (obvious one) A weak team will message you saying, "We have a problem, how should we fix it?" A mature team says, "We hit a blocker. Here are three architectural workarounds, the trade-offs for each, and our recommendation." 3. Deep Ecosystem Knowledge Coding isn't enough. If an agency claims they can build a top-tier lending protocol but doesn't understand the role of risk engines and oracles, they are tourists. Your developers need to know top-tier market leaders like Gauntlet, Steakhouse, Chaos Labs, and RedStone, and understand how their risk modeling and data feeds directly dictate market parameters. If they lack this context, their expertise is strictly surface-level. 4. Full Product Lifecycle Understanding Writing code and calling it a day is a massive mistake. A real partner understands what happens outside the IDE. They account for security audit buffers, integration with risk providers and oracles before mainnet, and the proper setup of on-chain governance and admin functions. 5. High Agency & Proactivity Elite teams care about your overall success, not just their Jira tickets. To quote a BD i work closely with: “When a client is about to make a massive mistake, you have two choices: stay silent and watch them fail, or step in with your expertise, even uninvited, and say: 'We hear what you want to do,
AI 资讯
Knowing When to Use If/Else vs. Switch in JavaScript
If/else statements - We all know and love them. While they are incredibly powerful, there comes a point where a long chain of conditions only makes your code look messy. Choosing between if/else and switch depends on readability, but there's a hidden pro tip that makes switch much more powerful than many people think at first. Traditional Approach: If/Else Normally, we use if/else when our logic depends on complex ranges and multiple variables: // Hard to scan, bulky, and prone to typos let weatherAdvice = "" ; if ( temperature < 15 && isRaining ) { weatherAdvice = " Grab a heavy coat and an umbrella! 🌧️🧥 " ; } else if ( temperature < 15 && ! isRaining ) { weatherAdvice = " It's cold but dry. Just a jacket is fine! 🧥 " ; } else if ( temperature >= 15 && isRaining && isNightTime ) { weatherAdvice = " Warm, rainy night. Stay indoors if you can! 🌧️🌃 " ; } else if ( temperature >= 15 && isRaining && ! isNightTime ) { weatherAdvice = " Warm rain during the day. Don't forget your umbrella! 🌧️🌦️ " ; } else if ( temperature >= 30 && ! isRaining ) { weatherAdvice = " It's scorching hot! Stay hydrated! ☀️🥤 " ; } else { weatherAdvice = " Weather seems pleasant today! 😎 " ; } Pro Tip: Using switch(true) Many developers think you can only use switch when you're checking a single variable against fixed values. However, you can use a switch statement for complex ranges by passing the boolean value true into the switch condition. Here is a cleaner switch statement version of the above code block: // Much easier on the eyes let weatherAdvice = "" ; switch ( true ) { case ( temperature < 15 && isRaining ): weatherAdvice = " Grab a heavy coat and an umbrella! 🌧️🧥 " ; break ; case ( temperature < 15 && ! isRaining ): weatherAdvice = " It's cold but dry. Just a jacket is fine! 🧥 " ; break ; case ( temperature >= 15 && isRaining && isNightTime ): weatherAdvice = " Warm, rainy night. Stay indoors if you can! 🌧️🌃 " ; break ; case ( temperature >= 15 && isRaining && ! isNightTime ): weather
AI 资讯
I turned browser cookie counts into game currency - meet Crumbongo
Crumbongo started from a pretty stupid little question: What if the number of accessible cookies on the website you're visiting could become game currency? So I built it. Crumbongo is a tiny local Chrome game where you choose a website, let the extension count the accessible cookie records for that site, and turn only that number into game rewards. No cookie names or values are used for gameplay. From a tiny experiment to an actual little game The first version was basically: choose a website; check its accessible cookie count; harvest that number into a Cookie Jar; spend the cookies on Bongo. Then I kept building on top of it. Crumbongo now has: a level and progression system; pixel-art cosmetics; multiple habitats; companions; local statistics; Monkey Climb; Cookie Stack. The whole thing still lives inside a Chrome extension popup. The technical side Crumbongo is deliberately small. There is no React, TypeScript, Vite, game engine, backend or framework involved. It's built with: vanilla JavaScript; HTML; CSS; Chrome Extension APIs; requestAnimationFrame for the minigames; chrome.storage.local for persistent game progress. The minigames are built with regular DOM elements and CSS rather than Canvas. That constraint became part of the fun: figuring out how far I could push a tiny extension popup without turning the project into something much larger. Local by design Because the core mechanic involves browser cookies, I wanted the privacy model to be extremely clear. Crumbongo requests access one site at a time. For gameplay it only uses the number of accessible cookie records returned for that site. It does not: store or transmit cookie names; store or transmit cookie values; modify or delete browser cookies; use an account system; use analytics or tracking; send gameplay data to a backend. Game progress stays locally in the browser. The game-design part became more interesting than I expected Once I added progression, I realized the cookie mechanic could support mu
AI 资讯
Making webpack's Docs Update Themselves | GSoC 2026, wrapped
Contributor: Nikhil Kumar Rajak ( @ryzrr ) Organization: webpack · Project: webpack-doc-kit Mentors: Aviv Keller ( @avivkeller ), Claudio Wunder ( @ovflowd ), Sebastian Beltran ( @bjohansebas ) Teammates: Mohamed Shams El-Deen ( @moshams272 ), Tushar Thakur ( @TusharThakur04 ) Period: 25 May to 17 August 2026 The problem webpack's docs lived at webpack.js.org and every API change meant somebody updating them by hand. Pages go stale and nobody notices until a reader does. webpack-doc-kit fixes that. It takes webpack's TypeScript declarations, runs them through TypeDoc, hands the output to nodejs/doc-kit for linking and UI, and produces a site that regenerates itself. We split the work three ways. Shams took AST parsing and content, Tushar took routing and navigation and UI, and I took the operational side: how docs get generated on a release, versioned & deployed. My six deliverables were PR-based doc sync, release-aware doc generation, versioned output folders, a deployment pipeline, CI validation before merge, and README fetch automation. All six shipped. Merged PRs in webpack-doc-kit 31 Lines added / removed +1,959 / −1,419 Distinct files touched 89 First / last merge 28 May ( #110 ) / 14 Aug ( #241 ) Merged PRs in other repos 2 Upstream issue filed and fixed 1 Everything below is merged into main . Nothing is open or pending. The release pipeline webpack releases happen in webpack/webpack . The docs live in webpack/webpack-doc-kit . A release in one needs to produce updated docs in the other with nobody doing anything. #110 set up versions.json as the single source of truth everything downstream reads, plus the script that maintains it and the workflow that runs it. My mentor proposed an object schema with latest , label , major , exactVersion , commit and frozen per entry. Review cut it to a flat array of tag strings, because everything else is derivable from the semver string and position [0] with unshift() already tells you which is latest. Right call, and I d
AI 资讯
Building a Personal Blog with Laravel: A Real World Project
A personal blog sounds like a simple Laravel project. Create posts, show them on the homepage, and you are done. But once you start adding search, categories, tags, comments, SEO, authentication, analytics, and an admin panel, things become much more interesting. I built this Laravel Personal Blog as a real world project to explore those problems instead of building another basic CRUD application. The complete source code is available on GitHub: https://github.com/arafat-web/laravel-personal-blog Table of Contents What Is This Project? Technology Stack Main Features Project Structure How Visitor Analytics Works SEO and Content Management How to Run the Project What I Learned Final Thoughts What Is This Project? This is a complete single-author blogging platform built with Laravel. It includes both a public blog and a custom admin panel. The project was built without additional application packages, so most of the important functionality is visible in the codebase itself. The public side contains: Homepage Blog posts Categories Tags Search Comments RSS feed Sitemap SEO metadata Post view tracking The admin panel contains: Dashboard Post management Category and tag management Comment moderation User management General settings SEO settings Visitor analytics Technology Stack The project uses: PHP 8.3+ Laravel 13.17 MySQL or SQLite Blade Eloquent ORM JavaScript CSS PHPUnit The current project configuration requires PHP 8.3 and Laravel 13.17. Main Features The project goes beyond basic CRUD. For example, posts can have categories, tags, comments, authors, featured images, publishing status, and view counts. The Post model defines these relationships using Eloquent: public function user (): BelongsTo { return $this -> belongsTo ( User :: class ); } public function categories (): BelongsToMany { return $this -> belongsToMany ( Category :: class ); } public function tags (): BelongsToMany { return $this -> belongsToMany ( Tag :: class ); } public function comments (): HasMa
AI 资讯
About Me: Afee Muhammod Wafy
Hello world! 👋 I'm Afee Muhammod Wafy , though most people know me simply as Wafy . I am a science student and self-taught web developer from Rangpur, Bangladesh. If you asked me what truly drives my journey, the answer wouldn't just be lines of code or complex syntax—it is pure, relentless curiosity. The Spark of Building Things From a very young age, I was always fascinated by how things work behind the scenes. Moving into science education naturally shaped how I approach problems: breaking down complex ideas, analyzing the core logic, and finding structured ways to solve them. When I first encountered programming, it felt like having an infinite canvas. I code not because it is an academic requirement or a routine chore, but because there is genuine joy in turning an abstract thought into something functional, accessible, and meaningful to real users. Consistency Over Perfection My learning philosophy is straightforward: stay consistent, stay humble, and never stop exploring . Every bug encountered, every new tool tested, and every experiment with full-stack development, modern APIs, or emerging AI technologies is a stepping stone. I believe true growth comes from getting your hands dirty with real-world problem-solving rather than just absorbing passive tutorials. Why This Journal Exists I started this dev.to journal to document my evolution as a developer in raw, unfiltered detail. Here, I'll be sharing: Real reflections on navigating self-directed learning alongside formal science studies. Honest lessons learned from debugging and architecting digital products. Perspectives on the ever-evolving tech landscape, open-source culture, and developer workflows. Let's Connect The tech community thrives on collaboration and shared knowledge. Whether you're a fellow student balancing studies with code, a seasoned developer, or someone who loves building things—I'd love to hear your story. Portfolio: amwafy.xyz GitHub: github.com/afeemuhammodwafy1 LinkedIn: linkedin.com