Seven phases in one afternoon
From an empty directory to a playable daily challenge in one 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. Picking words is therefore picking routes, fruit spawns when a word pulls off something structural (a palindrome, an alphabetical streak, an antonym of the previous word, three turns in one word), and a daily challenge gives everyone the same board and the same dictionary to fight over.
One day, seven phases#
On 6 April 2026 that idea went from an empty directory to a playable daily challenge with a leaderboard. The day ran as seven phases, and the phases were the working arrangement, not an afterthought: I decided what each one was allowed to contain and whether it was done, and the agent wrote the code inside those boundaries. Foundations came first, the game engine second, and the rest of the day wired that engine to the world, so that by the evening there was a board to play, a score to submit and a result to share.
The engine never met the framework#
Phase 2 is the decision I expect to defend the longest. The game engine went in as pure TypeScript, no Svelte imports and no DOM: the rules of the game in a handful of small modules, with 49 unit tests passing before a single pixel existed. The argument was testability, since 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 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. The contract was written at the top of the orchestrator on day one:
/**
* GameEngine — pure TypeScript orchestrator.
*
* No Svelte, no DOM, no side effects.
* Takes state in, returns new state out.
* Fully unit-testable without mounting
* any components.
*/
export function processWordSubmission(
state: GameState,
word: string
): WordSubmissionResult;
flowchart LR
accTitle: The engine boundary
accDescr: The browser UI built on Svelte 5 and the daily challenge server both call the same pure TypeScript engine. Inside the engine, the GameEngine orchestrator delegates to WordProcessor, EdibleManager and ScoreEngine. Nothing inside the engine imports framework code.
browser["Svelte 5 UI"] --> ge
server["Daily server"] --> ge
subgraph engine["Pure TypeScript engine"]
ge["GameEngine"] --> wp["WordProcessor"]
ge --> em["EdibleManager"]
ge --> se["ScoreEngine"]
endWho wrote what#
Every commit from the day carries a Claude co-author line, and that is an honest record: the agent wrote the code, while the game idea, the phase boundaries and the go or no-go between phases were mine. The commit log compresses the whole build into what looks like half an hour, and the planning that shaped it never touched the log, which is worth remembering whenever a commit history looks superhuman. This split is the experiment the project exists to run: I want to know what these tools are actually good for across planning, architecture, design, testing and deployment, and a game I would enjoy building anyway is a better lab than a toy exercise.
The agent wrote the code; the phase boundaries were mine.
Where this leaves things#
Everything from the day went straight to main: no CI, no pull requests, no review gate beyond me reading diffs between phases. That is fine for a repository that is one day old, and it will not stay fine. The more immediate gap is that the game only runs on my machine, and a daily challenge with a leaderboard is not much of a challenge without other people. Next is a real server.