← Devblog

One room, one zombie, no engine

BRAINBOX (working title — it’s the name of a house, long story, not telling it yet) is a top-down grid puzzle game about being bait. You are in the room with them. You cannot fight. You dig tunnels, they chase you through the tunnels, and you collapse the tunnels behind them. That’s the whole game, and M0 exists to answer the only question that matters before anything else gets built:

Is being the bait fun for three minutes?

If the answer is no, the project stops. Not “pivots.” Stops. This is written into the plan on purpose, because the graveyard of hobby games is full of projects that built the fun part last, and we would rather find out for the price of one room than for the price of a season. So M0 is one room, one zombie, one behaviour (it chases you), two verbs (dig, seal), and a deliberate absence of everything else. No narrator — there will be a narrator, and he is the best part, and that is exactly why he’s banned from the building until the part he can’t rescue is proven fun without him.

A dark top-down grid room split into two chambers by a vertical wall with a single brown diggable cell in the middle. A white player square sits bottom-left, a grey zombie square idles mid-left behind a pillar, and a green exit glows bottom-right.
First light: headless Chrome's very first look at the room. The white square is you. The grey square is a zombie that cannot currently see you, which is the only reason it is being so polite about it. The brown cell is the only way through the wall. The green cell is the exit, and it is lying to you — it will not open until the zombie is sealed away.

The room is its own level editor

The room is authored as an ASCII grid in the source — # walls, . floor, + diggable, @ you, 1 zombie, X exit. The whole design bet of this project is that a room is data: a text file a person can read like a floorplan, not a scene graph a person appeases like a small god. The full data format (a proper file-per-room affair) comes later; M0’s room is a string constant, because M0 is a question, not a product.

The simulation is deliberately boring, in the way load-bearing things should be: a fixed 20 Hz tick, one flat World struct, five functions called in the same order every tick, and no pathfinding — a zombie that can see you walks at you, a zombie that can’t see you commits to the last place it saw you for about a second, and then gives up and stands there. That “about a second” is the entire difference between a monster that hunts you through a tunnel and a monster that face-plants into the first corner and retires. We know, because the first draft of the spec had the face-plant version, and it got caught on paper before anyone built it.

Numbers, because devlogs without numbers are horoscopes: the whole game is 489 KB of WebAssembly, uncompressed. Not because of heroic optimization — because we skipped the engine and wrote the five functions. The sim compiles with no graphics dependency at all, which means the room’s solution is replayable in a test: a recorded sequence of inputs that digs, crosses, seals, and exits, asserted green on every build. The game literally cannot ship in a state where its own room is unsolvable. (It can absolutely still ship in a state where the room is unsolvable by you. That’s the three minutes. We’ll see.)

The review found two bugs in rooms that don’t exist yet

A second set of eyes went over the sim against the spec, point by point, and confirmed the satisfying stuff (containment is a live flood-fill, the exit gate can’t latch stale, no damage numbers anywhere because there is no damage). It also found two real bugs — both in geometry this room doesn’t have. Diagonal movement could corner-clip through a free-standing single-cell pillar; this room’s pillars are all 2×2, so you couldn’t. The containment flood-fill would panic if an entity ever stood outside the grid; this room has a solid border, so nothing could. Both fixed anyway, with regression tests, because M0’s code is the shipping code, and “the current room forgives it” is how a bug gets a pension plan.

We died on purpose

Death needed testing. Rather than mock it, the test harness walked the player straight at the zombie and stood still, like a hero.

The same dark room, dimmed, with CAUGHT in large white letters and 'Continue? (Y/Y)' below. In the bottom-left, a red zombie square is directly on top of the grey player square.
Journalism. Note the prompt: Continue? (Y/Y). Both options are yes. This is not a bug, it is a policy, and the reasons for it are narrator business we are not discussing yet.

Getting caught is ordinary and instant to retry — it’s how you learn a room. The other failure state (harming one of them — forbidden, career- endingly forbidden, in a way the story takes very seriously) can’t even be triggered by anything in this room’s tile set. That’s deliberate too.

Next: sit real people in front of it, say nothing except “lead them, don’t get caught,” and watch three minutes very, very closely.