Building a Cannon Fodder style browser game with AI in ten days
This dev log is about Inselnova: one island, sea wars and alliance politics in a world that never resets. Play free →
TL;DR: On a Saturday night I typed one prompt into Claude Code asking for a Cannon Fodder prototype, and by Sunday lunchtime it was deployed on Render. Ten days later it’s Boots & Bullets, a top-down squad shooter with 50 campaign missions, a zombie horde mode, two-player multiplayer and its own analytics, at bootsandbullets.com. The point was to see whether the way I work on Inselnova transfers to a game that looks nothing like it, with none of Inselnova’s tooling to lean on. It does, but the harness had to be built again from nothing, and about half the ten days went on that.
Play it here, free, in the browser: bootsandbullets.com
One prompt on a Saturday night
Inselnova has an AI harness that has grown since February. Skills, hooks, gates, tests, a release process, a hundred small rules that each came out of a bug. I’ve never had to build it twice, so I didn’t know whether it was the method or just the scar tissue of one project. A second game, as far from an island strategy game as I could get, was the cheapest way to find out.
The prompt went in at ten on Saturday 30 August, typos included:
i want you to build me a prototype of the old classic game cannon fodder
you will setup..
docs/
game/
it will be using a slim nodejs server
it will use svg or sprites, if you can find some sprites that'll be better
it'll have a basic map specified in a data directory as some sort of ascii file
i will be able to move a group of army guys in a herd
they won't overlap with each other
they won't be able to walk through map elements like trees
i will control with my mouse
i will click to move
when i click on an enemy they will move within radius and shoot them
the enemy will try and shoot me
our group can get shot
when all of them are shot then the game restarts
if i kill the last person the game says well done and option to restart
the game should be fluid and the screen will scroll around
it will take up most of the screen
the soilders will be small, and feel fast to move around
the map will include trees, a river, some huts, a pick up crate, some enemies to shoot
--
you will first RESEARCH the game
the mechanics
the movement
see if there are any established clones out there you can get ideas from
break down the code into like.. troops.ts enemies.ts map.ts
etc..
I went to bed.
By seven the next morning there was a first commit. Three prompts later I’d asked what the original had that this didn’t, then for a level generator, an intro screen and better graphics. By half ten on Sunday it was on a Render URL. That evening I renamed it Boots & Bullets, because Cannon Fodder is someone else’s name.
The other nine days were polish, and polish is where all the work is.
What it is now
It’s a demo. That stops me building feature after feature and gets it in front of people sooner. It’s also a desktop browser game, not a phone one, which opens a door Inselnova never had: Steam. Nobody wishlists a slow browser strategy game. A chaotic little shooter with a horde mode might be different.
| Campaign missions | 50, across three zones (Jungle, Desert, the Frozen North) |
| Difficulty | three rungs, but 22 separate levers underneath them |
| Multiplayer | two players over a shared link, four skirmish grounds |
| Challenges | The Herd, 300 zombies on screen, score is how long you last |
| Attract mode | the intro backdrop is two AI sides fighting each other, live, plus a chicken that pecks |
| Economy | War Bonds, spent in an Armoury on guns, throwables and call-ins |
| Character | Major Trumper, an officer who is certain, wrong, and nowhere near the fighting |
| Analytics | its own package, one dependency, counting people rather than events |
The front screen. The battle behind the buttons is live, green against blue on one map, and the chicken is a third side that pecks. The score across the top is real.
The Herd. Three hundred of them on screen at once, from three sides and never the south, so you can always run.
The Herd is the first of what I want to be a lot of challenge maps, and they’re there for two reasons. One is video. Inselnova is nearly impossible to make a video of. I’ve seen strategy games try, and the footage is never really in the game, and I think players feel cheated when they arrive and it looks nothing like the clip. Three hundred zombies pouring at six men is a clip. The other reason is that it made me and the AI optimise for a lot of things on screen at once, which the campaign never forced.
One rule shaped everything. The game has one runtime dependency, ws for multiplayer, and one asset file, the menu music. Every sprite is plotted into a canvas at boot from code. The terrain is derived from a one-character-per-tile grid. The sound effects are synthesised with WebAudio. The constraint makes the AI draw, and drawing is where it’s weakest.
Village. Every pixel here is drawn by code at boot: the river, the bridge, the huts, the men. No image file is loaded.
Trumper came out of a brief that said “a bit rough, silly, stupid, I like dry comedy like Sean Lock”. The AI turned that into the best rule in the docs:
If a line would work with a drum sting after it, it is the wrong line.
Move as a herd and use the trees. I hid in some trees in 1961. Nobody has found me since, in a sense.
Trumper on the comms panel. The portrait is one of the four things in the game that was imported rather than plotted, after the plotted face was rejected.
The comms panel he talks from exists because a friend sat down at a Mac and couldn’t work out how to fire. A new game is the first time I’ve had to solve onboarding from zero rather than patch it.
The harness, again
Nothing came across from Inselnova by copying files. I pointed Claude Code at the Inselnova repo and told it to look at what that game had that this one should. That’s how the analytics package, the release command and the changelog format got built, and each time it copied the shape and rejected the size. Inselnova’s release process is described in the new docs as “not one command, it is a department”.
There are 17 skills after ten days. Two of them, /commit and /release, I asked for on the first morning. The other fifteen exist because a session did something wrong, or did the same thing twice, and I told it to write down how to do it properly. If you’re starting a project with an agent, the skills start on day one, and by the end of the first week their shape decides whether the agent is getting faster or slower.
| Skill | What it does | Why it exists |
|---|---|---|
/commit | reviews the tree and commits in the repo’s voice, staging by name | more than one session edits the tree at once, and git add -A shipped another session’s files under my subject |
/release | ships main to Render and proves the deploy is live | a green dashboard can’t tell a new build from the old instance still serving |
/spec | splits a raw brief into one file per issue, with questions for me and a ledger | one long spec file meant items in the middle got skimmed and silently missed |
/gauntlet | the build-and-critique loop against a reference image, objective and metric fixed before round one | “make it look more like the original” is an adjective, not a target |
/grill | one round of that: capture a screen, hand it to a blind subagent, take back the single largest gap | the agent that drew the thing may not judge it in the same session |
/style | the visual vocabulary: which greens, where the light comes from, how thick an outline is | settles “does this look like our game” without arguing from taste |
/pixel-check | checks drawing code against the laws: no anti-aliasing, no alpha, no gradients | one soft edge in a dithered frame reads as a different game pasted in |
/pixelate | measures a reference image into plottable pixels and puts our sprite beside it at the same scale | sprites were being drawn three times from guesses at the size |
/sprites | opens a live gallery of every baked sprite, deep-linkable | the only way to look at a sprite without making the game show it to you |
/playtest | launches the real game in a browser and drives it | several bugs were invisible to every other check |
/map | writes one mission by hand as a data module, from an idea rather than a seed | the generated campaign needed a few places that were designed |
/arena | works on the CPU-vs-CPU mode, proved with a headless soak rather than a screenshot | four of five arena bugs were invisible for the first thirty seconds and obvious in a five-minute run |
/multiplayer | loads the one rule that decides where code goes across the wire, and the four bugs from not having it | four issues in two briefs were the same mistake made without it |
/speakers | Major Trumper’s register, what he may never say, how to add a second voice | a line that works with a drum sting after it is the wrong line |
/image-prompt | writes a prompt for an external image generator that comes back in the game’s style | the house style is a paragraph, and retyping it drifts |
/work | the work packages: capture, start, park, finish, report | the directory an item sits in is its status, so any session can pick it up |
/improve | turns this session’s mistakes into rules and compacts what’s already there | run at the end of every piece of work, or the next agent pays for it |
About half have an equivalent in Inselnova’s harness under another name. The other half are only here because this is a shooter with hand-plotted pixels. A strategy game never needed a rule about outline thickness.
/work and /spec are the loop the whole ten days ran on. I’d play the game with a briefing.md open and type every problem as I hit it, one thought per paragraph, separated by a line of dashes. At twenty or thirty I’d run /spec. It checks every claim against the code, then fans the one file out into one file per issue, a questions file for the decisions only I can make, and a ledger. The agent works through them one at a time, each fixed with a Playwright check or a headless run before it moves on. The biggest brief became 42 files. The QA ones ran 26 to 35. Thirty-eight packages are finished.
A lot of the pushing happened from my phone. Claude Code’s remote control opens a running session, and I used it to review and nudge, not to start anything. Read what it did, answer its question, tell it to carry on.
The docs outgrew the code. 58,000 lines of TypeScript, 80,000 lines of markdown. Every rule in the rulebook has two lines under it: what breaks without it, and what enforces it. Where the second says “nothing”, that rule will be broken again.
Multiplayer was a little tricky
Multiplayer wasn’t in the plan. The AI told me, more than once, that a two-player mode would turn a week into a month. I did it anyway, because the only way a game this size gets seen is one person making a room and sending the link to a friend. The basics took about an hour and the AI wrote all of it. What it got wrong was one design decision, and finding that took longer than the code did.
The lobby. A private game gives you a code to send to a friend, which is the whole reason it exists.
I keep a Codex session open about the game. It has no access to the code, which is the point. It’s somewhere to bounce ideas without the answer being shaped by what’s already built. Multiplayer got planned there. Claude Code corrected the plan against the code, dropped the Colyseus dependency in favour of ws and its own rooms, noticed the schema had forgotten to hash the credential, and built it. I tested it on 3 September. The shared link didn’t work, I couldn’t click to shoot, and I couldn’t pick anything up.
Each fix held, but the shape of the problem took two days to name. The server runs the real simulation and the client holds a puppet world that’s told what happened. Every new thing in the game needed a second edit in the network code to make the puppet show it, and every time that was forgotten it failed silently:
- A barrel exploded on the server and did nothing on the client.
- A pickup sparkled in the wrong colour.
- The “+2 GRENADES” label never appeared.
- Bullets crawled, because their position was copied every fourth tick and held still in between.
The explosion, four frames in. On the server it always happened. On the other player’s screen, for two days, it didn’t.
Claude had also got confused about which player was which, and that went over to the Codex session for a second opinion. On 5 September I asked the question that fixed it:
If a barrel explodes when hit by a bullet in single player, why would that be any different in multiplayer?
Then: is this the industry standard way, will new things work in multiplayer automatically, and no shortcuts. The answer is one sentence at the top of the multiplayer doc. State is corrected, events are replayed, and the client simulates whatever doesn’t decide an outcome. An effect without a replay is now a compile error.
It should have been the design from the first day. Opus 5 did a decent job of everything else on a fresh project. This was the one place it built the wrong thing confidently.
Two things I only found out by measuring
Where the time went. One long session, timed from its own log: a tenth of its tool calls took five times longer than the other nine tenths put together. The slow calls were the same two things, the full browser playtest, over three minutes, run 47 times in a session that made nine commits, and the full check, run over a hundred times. Every run after the first was re-asking a question that had already been answered. The rule now is to run the nine-second check while you work, run the gate once before the commit, and keep its output.
And a rule that prose couldn’t hold. Every session was told, in the project file and in its own memory, to write files with the editing tools and never with a shell heredoc, because the shell eats backslashes and dollar signs silently. It was broken about thirty times in eight days. Every session that broke it said so at the time:
exactly what my notes warn about
One wrote a control character into 65 files at once. Claude Code’s auto mode injects an instruction mid-session, long after the project file was read, telling the model to prefer sed and heredocs. A rule the model has to remember loses to an instruction it has just been handed. So the rule is a hook now, with sixteen tests. The harness is the bit that doesn’t need to be remembered.
Some numbers
From the transcripts. 62 sessions, 635 MB, often three or four open at once on different work items.
| Calendar days | 10 (30 August to 8 September) |
| Elapsed, first prompt to now | 207 h |
| Agent activity, idle gaps removed | 123 h |
| Busiest day | 4 September, 16 h |
| Commits | 721 |
| Things I asked for | 411 |
| Tool calls the models made | 26,560 |
| Times I interrupted it | 35 |
| Screenshots I pasted in | 37 |
| Context compactions | 16 |
| Plan mode | 6 |
That’s 65 tool calls for every request, against about ten on the last job I costed. The difference is the harness. A request here runs a type check, a test file, a headless soak of the campaign, a playtest section, a screenshot diff, and only then reports back.
| Tool | Calls | |
|---|---|---|
| Bash | 18,018 | 67.8% |
| Edit | 4,308 | 16.2% |
| Write | 1,978 | 7.4% |
| Read | 1,564 | 5.9% |
| Grep | 189 | 0.7% |
| Skill | 128 | 0.5% |
| Agent | 118 | 0.4% |
| everything else | 257 | 1.0% |
Writing and editing files is a quarter of it. Two thirds is running things and reading what came back.
The 123 hours are not me at a keyboard. This was an evening project. I have my normal work in the day, and in the evening I’m usually still doing work things with one set of agents while juggling another set on the game. Most of the 411 requests were typed while playing.
Opus 5 and Fable 5.1
Opus 5 did 77 percent of the turns, Fable 5 and 5.1 the rest, mostly the later polish.
Opus 5 is good on a small project, and this was a small project for the first few days. Once the specs got to twenty and thirty files it started falling short, and the way it falls short is that it doesn’t like reaching the end. It’ll get two thirds through a big spec and stop to ask me a question it could have answered itself, and I have to kick it along. The /goal command helps. You give it the finish line and it won’t let the session stop before it gets there.
Fable 5.1 is fantastic. It specs quickly, it works through the entire thing, and it doesn’t stop to ask. It still has no design taste, but neither does Opus, and Fable is fast and gets the job done. I wish I could have it all the time.
The design taste problem showed up the same way with both. Every time I added something to the game, Opus decided the mission success screen needed to show it too, and that screen turned into a pile of everything the model thought a player might want to know. It’s AI slop, in a UI. A decent slice of the ten days went on removing things the AI had added because it thought they’d be helpful. The win panel now says six things, in my order.
The win panel after the cut. Before it, this card also carried a “fastest” ribbon, a second clear ribbon, a lost-men row, accuracy and best-time suffixes, an itemised bond tally, a “not a scratch” line and a promotions roll.
What it cost
I paid $200, the Claude Code Max subscription for the month, shared with Inselnova. Priced on the API:
| Tokens | |
|---|---|
| Fresh input | 418,571 |
| Cache writes | 165.3 M |
| Cache reads | 17.7 B |
| Output | 48.8 M |
At $5/MTok in and $25/MTok out, with cache reads at a tenth of the input rate, that’s about $11,100. Priced as fresh input it would be $90,500, so long sessions only exist because of caching. Output, meaning every line it wrote, is 11% of the bill. 80% is the model re-reading the conversation.
What I learned
The method transferred. The harness didn’t, not as files, and I no longer think it should. It’s cheaper to point an agent at the old repo and say “look at what that has and decide what this needs” than to port a department.
- Opus 5 is still good, but it’s annoying to talk to.
- Fable 5.1 is still fantastic, and I wish I could have it all the time.
- Harnesses and custom skills take almost no effort to build, and they work. Seventeen in ten days.
- Ignore the advice the agents give you about scope. Multiplayer took about an hour to get the basics in, and if the game does spread it will be through that invite link. You lead it, not the AI.
There’s more character to add, and a lot I’ve learned about hooking people from Inselnova that isn’t in here yet. I’d rather find out what people think of it now, and whether the Steam door is real. It’s free and it runs in the browser.