The game below — terrain, helicopter, enemies, missiles, sound and mission — came out of nine instructions of mine, over one Saturday afternoon.
The numbers above are that first version. What's online to play is the same idea with art, sound and thirteen rounds of critique on top of it.
Why this game
A tribute and an anchor
There's a game from 1992 called Desert Strike. You fly an attack helicopter in isometric view, manage ammo and fuel, winch hostages to safety, and choose the order in which you hit targets. It was one of the games of my childhood.
Thirty-four years later I wanted to build my tribute to it. And the game also became an anchor project: a good excuse to learn game development, AI-assisted programming, and this business of working in public, which I'd never done.
An anchor solves a real problem. It's easy to "learn about" something and end up nowhere. It gets hard to fool yourself when there's an artifact that either runs or doesn't. The game is the judge.
How the work splits
Three sessions in parallel
I don't work in one session. I work in three, simultaneously, each with a different job:
| The session | For what | Which is |
|---|---|---|
| A conversation about ideas | thinking through the mechanism, deciding | method |
| A control session | preparing the environment, building the tool | instrumentation |
| A sealed, isolated session | producing, with long autonomy | production |
I measured all three:
| Where | My sentences | Tool uses | Tool uses per sentence |
|---|---|---|---|
| Thinking up the method | 28 | 36 | 1.3 |
| Building the tool | 20 | 218 | 10.9 |
| Making the game | 9 | 1,240 | 137.8 |
Two orders of magnitude from one end to the other. Thinking is conversation: one sentence from me, one answer. Building tools already runs to nearly eleven steps per instruction. Producing is starting the engine and getting out of the way.
I talked three times more to invent the method than to build the entire game.
How it works inside
One function at the center
Eleven files, 133 KB of JavaScript, no game engine.
main.js is what stitches them together. Not that this is the best possible architecture, or that it needs no refactoring: it's what the AI produced, and for now I'm leaving it as it is.It all starts in noise. noise.js is 1.6 KB with no
dependencies: math functions that, given a point, always return the same pseudo-random
value. Summed across several frequencies, they become terrain relief.
And it converges on a single function. terrain.js takes
that noise and exposes getHeight(x, z) — given a point on the map, the ground
height there. Five modules import the terrain, and what they all want from it is that
function. The helicopter, to know how high it's flying. Entities, to sit on the ground.
Projectiles, to know they've hit. Particles, to burst on the right surface. The panel, to
draw the minimap. No physics engine, no scene-graph query — a pure
function anyone can call.
And nobody knows their neighbor. Helicopter, entities, projectiles,
particles and panel sit in the same row and don't care about each other. What stitches
them together is main.js, alone at the end. That's why six files could be
rewritten at once, in a single pass, without breaking anything — each only had to keep
answering to the terrain.
The subsystems
What a ready-made engine would give you off the shelf is code here:
| Subsystem | What it does |
|---|---|
| Terrain | generates relief, roads, oases and flat zones out of the noise |
| Render | draws the scene and runs it through a post-processing chain with bloom — the glow that bleeds off light sources |
| Audio | synthesizes everything in real time: rotor, weapons, explosions, alarm |
| Particles | fire, smoke, dust and debris, from a fixed recycled pool |
| Projectiles | trajectory, range, and the collision test against ground and targets |
| Entities | radar, anti-air battery, tank, jeep, soldier, hostage, supply crate, landing zone |
| Mission | objectives, tallies, and the win state |
| Input | keyboard and mouse, with aim derived from the cursor's position in the world |
The build, minute by minute
Saturday, 12:02
What follows is the real order things came into being — not a tidy rearrangement by topic afterward. I took the file modification times and the session log. This is literally the game assembling itself.
<canvas>, and an
import map pointing at the 3D library. Nothing happens yet.entities.js alone is 40 KB: it's the
file that knows what a radar is, an anti-air battery, a soldier, a hostage, a command
post. It's the world.

The stack
I imposed one constraint at the start: it has to run in a browser, in 3D, with nothing to install. That led to a web 3D library and plain JavaScript, with no game engine. No visual editor, no ready-made physics, no ready-made particle system — all written by hand.
It was the right call for chapter one, and it will probably be the wrong one at some point.
The quality engine
The builder doesn't judge
The problem with building alongside an AI is that it agrees with you. Ask for an explosion, it makes an explosion, and it thinks it's great. If whoever builds also evaluates, the bar slides down until it rests on whatever was already made.
So, taking after the gauntlet loop — the idea of putting a builder and a critic on opposite sides, with fresh context each time around —, I split the roles. On one side, the builder. On the other, a critic that has never seen the code, doesn't know what was tried, and receives only two images side by side — mine and a quality reference — with one question: which of the two is better, and why, in each aspect separately? Palette. Light. Motion. Silhouettes. Camera. Each aspect gets its own verdict.
The references given to the critic were never the goal. They're a steering instrument: it's far easier for an evaluator to say "this one is worse because the palette is monochrome" than to say "this is good." The comparison exists to produce specific, actionable criticism.
The first visual verdict was brutal: five aspects to zero against me. And it was useful, because it came with names: monochrome palette, sun too high with blown-out exposure, flat explosions, camera over-anticipating movement, enemies with no visual marker.
The gameplay critic, running in parallel, was both kinder and harsher:
resources, transport, armament, mission · TIES
combat tactics · LOSES — anti-air missile undodgeable, 0 of 8 evasions
The six gaps named by the two critics were fixed in one go, across six files. Midway through, a snag: the model's safety filter refused one of the commands — the one changing the color of the sky and the sunlight. Resent unchanged, thirty-five seconds later, it went through.
The missile you couldn't dodge
On the second round the critic came back with measurements instead of opinions: the "DODGE!" warning appeared 0.20 seconds before impact — human reaction time doesn't exist in there — the maneuver's cooldown was 2.2 seconds, which didn't cover a salvo of three missiles, and two enemy weapon types gave no warning at all.
Three numbers, three fixes. Next round: a 0.62-second window, 6 evasions out of 6 attempts, and a three-missile salvo survived. From undodgeable to fair in two iterations — and none of it started with me. I wasn't even watching.
The camera, which lost the first two rounds, tied on the third and stayed there. Target met, aspect locked, nobody touches it again.
Where it stopped
"One single sand, lollipop trees"
Five rounds in, four visual aspects wouldn't budge: palette, light, motion and silhouettes. And the critic, who had no idea what I'd tried, kept saying the same thing in increasingly precise words:
"enemy classes are only distinguishable by the colored ring on the ground"
It was right. Look again at the first image in this post: it's a desert of one color, with bushes that are flattened green spheres.
And then came the decision I consider the best of the chapter, and it was to stop.
When an aspect fails to converge for three rounds running, the rule is to report the cause rather than lower the bar. The cause here was structural and obvious in hindsight: you cannot reach visual richness by generating art with procedural code. Every round was tuning a parameter in a system that had no way to produce the requested result.
So the loop stopped on its own, recorded "blocked for lack of means" on all four aspects, and handed the problem back to me. One hour and forty-seven minutes after starting, I had a playable game, an honest diagnosis of what was missing, and no lies in the record.
The pause
Two and a half hours building a tool
The diagnosis was a missing means of producing art. The game sat still for almost twelve hours — I slept through part of that — and inside that window there were two and a half hours of continuous work building an asset pipeline: a piece that takes a request ("tileable desert ground", "short palm tree", "military vehicle") and returns a finished file, sourced from free art libraries or generated to order, with its provenance recorded.
And "I built" is a figure of speech. What worked through the night was Claude, let loose in yolo mode — not stopping to ask my permission at every step — inside the sandbox where it can go wrong without taking anything else down with it.
Before that, a decisive step: going and getting real visual references. You can't ask for "make it pretty". You can take images from the genre, pull a palette and a lighting direction out of them, and use that as working material. A good chunk of the quality that came later was born in that boring half hour of collecting pictures.
And there was one failure I wouldn't have predicted. To cut the background out of the generated textures, I asked the generator to paint it pure magenta — a color that shows up in nothing natural, precisely so it would be easy to find and erase later. It returned an almost pure magenta.
To the eye, identical. To the cutout, which was looking for an exact color value, there was no magenta at all: nothing got erased, and every texture came out wrapped in a garish rectangle. The fix was to stop assuming the color and start measuring it at the edge of each image.
It's a failure that only exists when you automate on top of a generator. It gets right what a human would judge and gets wrong what a machine requires — and the gap between the two is invisible until the machine breaks.
Before and after
The desert gets texture
With the tool ready, the loop restarted. Thirteen rounds of criticism, seventeen generated textures, and real three-dimensional models replacing boxes.
The same military base, at three points in the process:



And the anti-air battery — the same one that was undodgeable earlier — before and after:




In motion


Across the rounds, six silent regressions were caught: the base occluding the explosion fireball, a filter darkening fire frames, the particle pool running dry mid-combat, grenades detonating during image capture, code comments accidentally swallowing lines, and half of every fireball vanishing because the engine discards the back face of polygons. None of them broke the game. All of them surfaced because there was an evaluator looking frame by frame.
The bill
Sixteen dollars
Everything was logged from the start, so the accounting closes line by line.
| Method | Tool | Game | Total | |
|---|---|---|---|---|
| My sentences | 28 | 20 | 9 | 57 |
| Machine replies | 32 | 152 | 564 | 748 |
| Tool uses | 36 | 218 | 1,240 | 1,494 |
| Active time | 2.4 h | 4.3 h | 8.7 h | 15.4 h |
| Tokens processed | — | — | — | ≈ 370M |
And the cost, which needs two lines so as not to mislead anyone:
(share of subscription)
on metered API
The monthly subscription is $200. I prorated it by week and measured what share of my total consumption this chapter took: 34%. That's sixteen dollars. The other number is the same work billed as a metered service.
One thing you'll hear. On the radio, the helicopter answers to Sandstorm. It's a fossil: that was the game's first name, until I found out a published game already had it. The name changed; the callsign stayed.
After the game was done
The other half of the work
The game was playable in 1h47. Getting it somewhere anyone could open it, and telling how it was made, took four days and 35.9 hours of work.
That part doesn't show up in the numbers from the previous section because it's about something else: turning a folder that runs on my machine into something that opens on a stranger's — and then explaining what happened inside it.
Four versions before it could be played on itch.io
The game already ran. Open the file and play — that's how I played the whole chapter. Publishing it took four tries.
v0.1.3 · the play button returned 404 — itch.io's server doesn't resolve folder addresses
v0.1.3 · the game opened in Portuguese for everyone
v0.1.4 · inside itch.io's frame the mouse wheel scrolled the page behind it, the keyboard never got focus, and the screen went black and shook until it settled
Between the first and the last, no rule, art or audio changed. What changed was what makes a game work inside someone else's page.
The last item took new code in the game. Without it, the first seconds inside itch.io's
frame were a black screen that shook until it settled — the graphics card
compiling, mid-session, the little programs it draws with. The fix was shader
prewarming: compile everything up front, while LOADING is still on screen.
It's ordinary practice in games, and what brought it here was publishing.
And before that, what nobody sees
| What | Why |
|---|---|
| A separate build for the public | strip the test hooks out of the bundle, embed the 3D library instead of fetching it from a CDN, lower the precision of the meshes |
| Security review | no globals leaking, no address reading, no development-only branches left behind |
| Asset diet | from 8.7 MB down to 5 MB per player — nobody opening a page expects to wait |
| A license | a decision I didn't know I'd have to make this early |
| Hosting, decided twice | the first choice was undone once itch.io proved better for a browser game |
| Three renamings | the first name collided with a published game; the second I dropped on my own. Each change touched the title, the opening screen, the license and the language key |
| Two languages | in the game and in this text, decided separately and arriving at the same answer: English by default, Portuguese one click away |
The diet paid off more than I expected, because the weight was concentrated. The game shipped at 8.7 MB per player, and one file accounted for more than a third of it: the soldier, at 3.6 MB. Almost all of that was animation — twenty-four movement sequences, of which the game uses eight. With the sixteen nobody sees removed and the geometry compressed, it came down to 1.4 MB.
The sky, stored at a resolution nobody can make out in play, went from 1.5 MB to half a meg. With the vehicles added in, the total landed at 5 MB — and the bundle now carries only the files the game actually asks for — nine that nothing references stayed out of the bundle.
And the front you're reading right now
Publishing the game is half of it. The other half is this — the text, the site that holds it, and everything that makes a post exist for anyone besides me.
| What | What it took |
|---|---|
| This text | written, measured and rewritten more times than I counted — the first draft came out with every tell of machine prose |
| The numbers | counted one by one from the session logs. The first count came out inflated by as much as four and a half times, and had to be redone from scratch |
| The images | the day-one game was recovered from a folder that never became a repository, and run again just to capture what it used to look like |
| Languages | the whole text translated, with an address for each language and the markup that tells search engines they're the same page |
| The site | a domain, hosting, and the page that will collect the chapters as they come |
| Measurement | knowing how many arrive, how many read to the end, and how many switch languages. Plus the cookie notice the law requires |
| Mailing list | picking the service, building the form, and writing the line that says what happens to whatever you send me |
| Accounts | one on itch.io, one on X, a domain — each needing a name that was still free |
The first draft of this post was full of what people have taken to calling AI slop: sentences announcing that something is interesting instead of showing it, tidy symmetries that contradict the number right below them, rhetorical questions the text never answers. Asking for "better writing" removes none of it. What worked was picking out the bad passages one at a time and turning each one into a rule — and the list that came out of that holds for the chapters ahead.
The second bill
Both halves — making the game, and then making it public — measured the same way. The first column is the whole bill from the previous section: method, tools and game. The second is what came after: the public build, the store page, the site, and this text in four languages.
| Making the game method, tools and game | Publishing and telling after the cut | Both | |
|---|---|---|---|
| Window | Sep 4, 18:39 → Sep 6, 19:18 | Sep 6, 23:05 → Sep 10, 23:05 | — |
| Wall-clock time | 48.6 h | 96 h | 144.7 h |
| Active work | 15.4 h | 35.9 h | 51.3 h |
| My sentences | 57 | 303 | 360 |
| Machine replies | 748 | 2,685 | 3,433 |
| Tool uses | 1,494 | 2,524 | 4,018 |
| Cost in subscription | $16 | $25 | $41 |
In money the two nearly tie — $16 against $25. The difference is in how much of me each one took: 57 sentences to make the game, 303 to publish it.
What's next
Chapter 2, already under way
By the time this post went out, the next chapter had already begun. What's on the bench now:
Sound for real. The day-one oscillator audio did its job, but it's time for an actual audio engine — event-driven sound, mixing, and an evaluator judging whether the gun sounds like the gun it's supposed to be.
Performance. Quality tiers that adapt to the player's machine, geometry merging, and a frame budget the game respects instead of hoping for the best.
Assets a tier up. Terrain sculpted from real elevation data, physically-based materials per model, destruction, and volumetric effects.
And the thing I want most: putting this online for you to play. One level, in the browser, nothing to install.
On code and tools
For now I've decided not to open the code, the prompts I used, or the tools I built. Maybe further down the line I will. For the time being I'm going to focus on sharing my process: the logic, the decisions, the mistakes, the numbers and the backstage. That's what I have to tell.
If you want to follow along
The game grows in public, mistakes on display and numbers open, chapter by chapter. And I want to hear from you — not about the code, about the game. Does the difficulty feel fair? Does the helicopter respond the way it should? What was missing from this first level? Send it here, or reply on my X profile.