Experiments

Hand-built experiments that start from a bakeoff world. First: one of them rebuilt at the same visual bar inside a real game frame budget. The bakeoff worlds are one-shot artifacts and stay that way — these are what happens when one of them is taken apart and rebuilt on purpose.

Neon City, game-ready

Neon City, game-ready

One bakeoff world rebuilt by hand at the same visual bar, this time inside a real game frame budget. Walk it and watch the frame-time readout.

GPU / frame
2.72ms 11.4
draw calls
118 149
triangles
824,448 1,462,730

Struck-through: the one-shot bakeoff world it rebuilds. 4.2× less GPU time for the same street.

Neon City, game-ready — how it was built

Why this exists

Every world in the bakeoff is a one-shot artifact: a model received a brief and had a single autonomous attempt, with no profiler, no device to test on, and no second pass. That is the contest, and it is a fair test of what a model produces cold.

It is not a fair test of what the idea can cost. This is Opus 5's Neon Rain rebuilt by hand at the same visual bar — same street, same rain, same signage, same wet road — with a frame budget as a hard constraint and a measurement harness built alongside it. The interesting result is not that the rebuild is faster. It is which things turned out to be expensive, because almost none of them were the things you would guess.

What a frame actually costs

A 60 fps frame is 16.7 ms, and that is the budget for everything — player controls, physics, AI, UI, audio, and the world. An environment is meant to be a fraction of it.

the same street, rendered byGPU timeleft for the rest of the game
the one-shot bakeoff world11.4 ms5.3 ms
this rebuild2.72 ms14.0 ms

That is the whole point of the number. 4.2× is a ratio; 14.0 ms instead of 5.3 ms is the difference between an environment you can build a game on top of and one that has already spent your frame.

The finding: it was never the polygons

The obvious plan is to cut geometry. That plan was wrong, and the way it was found to be wrong is by ablating the original by cause — removing exactly one mechanism at a time and re-measuring — rather than by profiling it by render pass.

removed from the one-shot worldGPU time saved
its 16 × PointLight4.90 ms
post-processing (4 passes)2.70 ms
the planar Reflector2.50 ms
all 425,000 triangles of towers, under lean lighting0.10 ms
all 29,000 rain instances0.00 ms

The build's own ablation of the reference, control 11.30 ms. Measured during development, not re-run for this page.

Deleting every building in the city saves a tenth of a millisecond. Geometry on this GPU costs roughly 0.024 ms per 100,000 triangles. The towers were never expensive because of their vertices — they were the surface area over which MeshStandardMaterial evaluated a twenty-light loop, once per fragment. Apple's hidden-surface removal cannot help with that: these are visible pixels, shaded once, just very expensively.

What replaced them

One hand-written analytic material instead of MeshStandardMaterial plus twenty lights. The lighting is evaluated as a closed-form function of position and normal rather than as a loop over light sources, which removes the 4.90 ms above and, incidentally, the reason the tower count mattered at all.

The tone map, colour grade and vignette folded into every material. The original spends a full-screen pass on them; here they run at the end of each material's fragment shader, so the frame needs no post-processing chain to look finished. Worth about 2.70 ms — and it is why the neon still glows with post switched off, since the bloom is carried by additive glow cards baked into the sign atlas rather than by a blur pass.

Interior mapping, which is the one that is free and does not look it. Each lit window ray-traces a virtual room box in the fragment shader — ceiling, back wall, side walls, floor, furniture silhouettes — so the depth behind the glass is real and parallaxes correctly as you walk past. No extra triangles, no extra draw calls, +0.03 ms. The original painted a flat lit-window grid. Walk close to a facade and look along it: the rooms turn.

The sign atlas is drawn rather than downloaded, which is the same mistake as the towers in a different currency. The build shipped signs.png — 1.01 MB gzipped, 43% of the entire download — so that a phone would not have to run the ~30 canvas operations that generate it. Measured, those operations cost 0.9 ms on a desktop and 2.7 ms at 4× CPU throttle. A megabyte to save three milliseconds. Generating it at load instead takes the payload from 1.49 MB to 0.46 MB. ?atlas=baked restores the download, which is the right trade for a game that wants pixel-identical output across devices — the generated atlas is bit-identical to the PNG on the same canvas rasteriser, but Chromium's Metal-backed 2D canvas antialiases strokes differently, so "deterministic" here means per rasteriser, not per machine.

The wet road was rebuilt twice, and the failure is more instructive than the fix. The first version sampled a cubemap reflection probe baked once at load — one texture fetch per road pixel, effectively zero per-frame cost, and by ordinary game-engine reasoning the right call for a rough surface at grazing angles. It was wrong for a reason no amount of tuning could reach: a cubemap has no position. It answers "what lies in direction R", so a noodle stall twenty metres away reflects at the bearing it has from the probe, not from you — which puts its reflection somewhere other than beneath it, or nowhere. Five rounds of increasingly specific workarounds were all attempts to hand-place sources that a real mirror places for free. It now renders the scene once more from a camera mirrored in the road plane and samples that projectively. The mechanism was the bug.

Measured

one-shot worldthis rebuild
GPU time per frame11.4 ms2.72 ms
draw calls149118
triangles1,462,730824,448
download, gzipped0.46 MB

Apple M3 Pro, headless Chromium, ANGLE Metal backend, 1920x1080, vsync and frame cap disabled. GPU time is the minimum EXT_disjoint_timer_query_webgl2 sample; three runs each, agreeing within 2%; draw calls counted at the GL level, so the reflection pass cannot hide inside them. Both pages measured minutes apart in one session on 2026-07-27, against the exact build served here. Download is all 33 requests this page makes, gzipped and summed — Cloudflare prefers brotli, so it is an upper bound; the one-shot world is a single file and not usefully comparable. Caveat: the same pair measured on a busy machine read 2.93 and 12.06 — absolutes shift with contention, the ratio barely moves.

What this does not claim

Reading the number in the corner

The readout is wall-clock time between animation frames, not GPU time — EXT_disjoint_timer_query_webgl2 does not exist in mobile Safari, so there is no honest way to report GPU cost on a phone from inside the page. It is capped by your display's refresh rate, which means ≈16.7 ms is the floor, not the cost: it tells you the frame is being hit, not by how much. p95 is the number to watch — it catches the hitches a median hides.

?perf=0 hides it. ?post=0 drops the bloom chain, ?q=low selects the headroom tier, ?refl=off removes the road reflection, and ?refl=probe restores the cheap cubemap so you can see the near-field failure described above. The full parameter list is in the build's README.

Controls

W A S D to walk, mouse to look, Shift to run, click to capture the cursor. On a phone, a joystick appears bottom-left and dragging anywhere else looks around.

Walk it ↗