Seven phases in one afternoon
From an empty directory to a playable daily challenge in a single day, and why the game engine never learned what a framework is.
The idea fits in a sentence: you steer a snake by typing words. Every letter advances the snake one step, and four of them, u, d, l and r, also turn it. A word like “cloud” is therefore a path, five steps with turns hidden inside it, and picking words becomes picking routes. Fruit spawns when a word pulls off something structural: a palindrome, an alphabetical streak, an antonym of the previous word, or three direction letters in one word. A daily challenge gives everyone the same board and the same dictionary to fight over.
On 6 April 2026 that idea went from an empty directory to a playable daily challenge with a leaderboard. The commit log records it as seven phases, and the phase boundaries are the actual story.
Phase 1 was foundations only: TypeScript types for the whole game state, a CSS design token system that supported dark, light and high-contrast themes from the first commit, a SQLite schema behind Drizzle, and a dictionary pipeline that boiled public word lists down to 370,079 playable words, 3,382 sentiment scores and 162 antonym pairs. Nothing ran yet.
Phase 2 is the one I still point at. The game engine went in as pure TypeScript: word parsing, grid and collision handling, combo detection, scoring, and one orchestrator tying them together. No Svelte imports, no DOM, no framework code allowed inside. It shipped with 49 passing unit tests before a single pixel existed.
The argument for that restriction, at the time, was testability: pure functions need no DOM to mock, and combo rules are exactly the kind of logic you want covered before a UI starts hiding it. Determinism came along for free. The same small PRNG (Mulberry32) runs on the server that generates the daily challenge and in the browser that plays it, so both sides agree on where fruit lands without asking each other. What the separation made possible later, an AI duel running two snakes through the same engine and a server replaying the engine as the authority for multiplayer, was not planned that afternoon. That part was a bonus.
Phases 3 through 7 wired the engine to the world: API routes for word validation and the daily seed, reactive stores bridging engine state to Svelte 5, an animation queue that collapses to instant steps under reduced motion, the daily challenge page with score submission, a settings panel, and finally a share card that renders your finished board as a small emoji grid. The test count grew to 60, with a Playwright suite on top checking the board’s ARIA structure and keyboard input.
The timestamps deserve a caveat. Phase 1 landed at 14:21 and phase 7 at 14:53, which reads like a speedrun; the README followed at 16:06. Every commit carries a Claude co-author line: the agent wrote the code, I decided the phase boundaries and reviewed between them, and the planning that shaped phase 1 happened before anything was committed. The working day was longer than 32 minutes. It was still one day.
Some of what that day produced is unrecognizable now. The navigation had three entries, Free Play, Daily and Settings, and only two of those concepts survive. Everything went straight to main: no CI, no pull requests, no review gate. That discipline arrived two days later and is its own post.
What survived untouched is the boundary. The engine still has no framework imports, and every mode the game has grown since runs through it.
Next up: what happened when this met a real server and a real phone. Passing tests turned out to say very little about a snake you can watch move.