← Back to the theaters ★STAR ON GITHUB

COMICZOMBIES

A GAME THAT DRAWS ITSELF

A Call-of-Duty-style round-based zombies shooter that runs in a browser tab, styled like a graphic novel. Heavy ink, halftone screen-tone, saturated flats — and not one downloaded asset. No models. No textures. No audio files. No webfonts.

Every mesh is built from code, every texture is painted to a canvas at boot, every sound is synthesised from oscillators and noise. The entire game is 75,860 lines of TypeScript and a single runtime dependency, now spanning five distinct playable theaters.

0downloaded assets
1runtime dependency
75.9klines of typescript
156source files
7original firearms
5playable arenas
155live gallery exhibits
DESKTOP ONLY — FOR NOW

The game wants a keyboard and a mouse, so tapping PLAY on a phone gets you a polite notice instead. This page, though, is built for the phone — and every asset below is still generated live, right here, on whatever you are holding.

What shipped lately

The project is still running. Recent builds, and the measurement that drove each one — because on this project a fix does not count until a number says it worked.

INKSAINT · THE UNWRITTEN

An entire city drawn in ballpoint. Cut seams, dash through openings and Unravel a crowd. Enter INKSAINT.

ASTRA 6 · THE SUNKEN SUN

A suspended solar foundry, four machine classes and aerial combat built around a relic blade, grappling and dive slams. Enter ASTRA 6.

REAPER PROTOCOL

RAZORWIND and GUILLOTINE add deliberate melee strikes and an execution loop to the original arenas. Finish an opened target to recover health and ammunition.

BUILD 031 · FIELD DOSSIER

Hold Tab for a production in-run read: both weapon rails, ammo, round state, kills, headshots, accuracy, points, best chain, threats and every stacked boon.

THE ORIGINAL THREE ARENAS

Municipal Block's loud graphic novel, Blackline Terminal's ink-noir station and Nightglass Array's stable cinematic/PBR look now share one authored Ready Room.

FIRST CONTACT IS PREWARMED

The first 15-headshot fan-out fell to 6.1 ms cold / 1.7 ms warm. Hidden VFX families, enemy programs and the word atlas now compile behind the loading cover.

ONE KILL, ONE HEADLINE

One pooled kill word can live at once; lethal hitstop has one owner; gibbed deaths no longer emit a redundant second 18-shard silhouette. The spectacle remains, the pile-up does not.

CONTACTS TELL THE TRUTH

Minimap contacts wait for the 0.34 s spawn reveal. Every hit invalidates its held pose, so the body reacts on the next rendered frame without increasing animation cadence.

THE WORLD IS SOLID

Every discovered wall face is challenged by nine movement compositions. Walk surfaces, stairs and authored horde holds are checked for pass-throughs, embeds and stalls before a build ships.

How it was built

Not "one prompt, one game". The project runs like a small studio: a milestone is planned, agents build it in sequence, adversarial reviewers try to break it, a fix pass applies what they found, and then a human plays the result and says what's wrong. Their feedback outranks the plan. That loop has produced 31 playable builds so far.

MILESTONE scoped + specced AGENTS BUILD in sequence REVIEWERS try to break it FIX PASS blockers first HUMAN PLAYS IT answers HUMAN_JUDGE.md FEEDBACK OUTRANKS THE PLAN next milestone is whatever they said ship "it makes me dizzy"

Agents verify facts — types, draw calls, allocation, hit registration. The human judges everything subjective. That split is deliberate: machines are good at "is this leaking", bad at "is this satisfying".

What the reviewers actually caught

The adversarial pass is where most of the quality comes from. A sample of real bugs it found, each of which had already passed its author's own tests:

Bug Why nobody saw it
Every zombie rendered translucent The depth prepass used a stock material that couldn't run the vertex shader posing the body. Two individually-correct decisions, broken only together.
Slide silently dropped on every kill Input edges died on frames that ran zero fixed steps — and hitstop, added later, opened exactly that hole on every kill.
Knockback was squared A units mismatch across a module boundary: 386 m/s of knockback threw a zombie 65 m, so every follow-up shot missed.
The player floated instead of falling grounded was only ever set true and never derived from the world. Measured: 0 of 17 ledges fell.
Every ground light pool was invisible Fan geometry wound the wrong way, so all 55 were backface-culled. Proven by A/B: "lights on" and "no lights at all" rendered bit-identically.

Nothing is downloaded

The constraint drives the art direction, not the other way round. Bold, flat, ink-outlined comic art is achievable in code at a quality that reads as premium — photorealism is not. So the style was chosen to fit the constraint, and then the constraint was never broken.

TypeScript 43,645 lines Canvas 2D textures, lettering GLSL + BufferGeometry shading, meshes WebAudio every sound THE GAME boots in seconds 0 FILES FETCHED EVER

One dependency: three. Everything else is standard browser APIs.

The render pipeline

The comic look is not a filter bolted on at the end — it is the rendering architecture. Nine passes, in a fixed order, and the first three are never dropped by a quality tier because losing them loses the art direction.

SCENE+ prepass INKsobel edges HALFTONEscreen-tone BLOOM CHROMAmisregister GRADE GRAIN VIGNETTE OVERLAYspeed lines ◆ NEVER DROPPED — these three ARE the art direction Quality tiers drop passes from the right. Better to lose resolution than lose the style.

One rule that fixed everything

Early builds made the playtester ill. Their words: "every pixel seems to be jumping like glitching." The diagnosis was a principle, not a bug — a comic page does not animate its own texture. Paper doesn't shimmer, halftone dots don't crawl, CMYK plates don't re-register every frame. Those things are printed.

Layer Rule
Halftone latticePerfectly static in screen space. Nailed to the page.
Paper grainStatic. One sheet, not a new one every frame.
Chromatic misregistrationOne constant offset per session — like one bad print run.
Boiling ink line12 fps, hero contours only, with a hard coverage budget.

The measurable version: with the camera parked, consecutive frames must differ by under 0.5% of pixels. It went from 24.77% → 0.065%. Stand still in the finished game and the image is frozen — only the world moves.

Why the guns are drawn with a fat crayon

The weapon is the single most-looked-at object in the game — it is on screen 100% of the session, about 30 cm from the eye. It is also the thing the ink line is hardest on. The outline is an inverted hull inflated by a screen-space 7 pixels, so a part thinner than roughly twice that band has no colour left between its two inflated faces and prints as a solid black blob. This is not a theory: a trigger guard, a trigger, four muzzle fins and a front sight were all modelled, all under the band, and all being erased every frame.

So "more detail" cannot mean more small parts. It means fewer, bigger, harder marks — and the playtester picked that over fine realism deliberately. Every generated weapon surface obeys the same rule: two values, hard edges, countable.

What a realistic renderer would draw What survives the line
40 fine wood grain lines3–4 broad bands and one knot
8 thin barrel vents3 big slots with a lit lip and a dark one
A fine knurl texture5 diamonds you could count, every one inked
Soft noise-based paint wear7 blocky chips, inked on one side only
A baked halftone in the textureNone — the print is fixed in screen space, only the drawing moves

The other half is material separation: four flat value fields — polymer 0.29, frame 0.44, steel 0.57, wood 0.43 — instead of one grey. Under a cel shader a hard value break between two adjacent masses reads as detail at zero geometric cost, and it is the one kind of interior detail a 7-pixel line cannot erase.

The game that spawned a toolchain

Building this meant writing about a hundred asset generators — brick, rust, concrete, blood, muzzle flash, lettering, every gunshot. Somewhere around the fiftieth it stopped being a game problem. Every person vibecoding a three.js game with an AI hits the exact same challenge: keeping a growing art library coherent and reproducible. We chose procedural authoring so every material, shape and sound could be edited alongside the game.

So the same pipeline that built this game was pointed at that wall, and it built Seedbank — a standard, a studio and a Claude Code bridge, built on one idea: an asset is a function, not a file. A texture is forty lines of canvas code. A crate is a geometry builder with a seed. A gunshot is an envelope over a noise burst. Write brick() once and every future game calls it for free.

The game gave Seedbank Seedbank gave the game back
Its whole pattern library, mined from shipped code. Seedbank's reference doc is an extraction, not a hypothesis — every rule in it is quoted from a file in this repo that survived a real playtest. A harder question than the game had asked itself: style is a parameter. One generator, many manifests. That reframing is why the guns are authored in multiplier space instead of hard-coded colour.
The failure modes, free. Ink-floor blowout, halftone crawl, the tiling seam that only shows on one layer — all found the expensive way here first. The sharpest review this game's art code has ever had. Building a general standard forced a list of where the game is wrong — places its shortcuts don't generalise — and that list is a to-do.
Proof that the constraint ships. A finished, zero-downloaded-asset game is an existence argument no README can make. Coherence as a first-class problem. A single beautiful crate never was the hard part — forty assets that look like one game is.

Two projects, one pipeline, each one the other's test case. The game is where a generator proves it survives a frame at 60 fps; the toolchain is where it proves it was worth writing once.

Every asset, generated live

Everything below is produced right now, in your browser, by the same functions the game calls. This page imports the game's own modules — it is not a mock-up, and if a generator ever changed, this page would change with it. Each tile prints the exact call that made it. That includes the weapon surfaces and the seven guns, which are asked for by name and shaded with the game's own ink material.

▶ PLAY IT ★ STAR ON GITHUB

Built with Claude Code and Codex. Sibling project: Seedbank. The source is open — every generator on this page is in the repo.