Inside The ClickEditorial Log Nº 14 · retrospective
Subject
Why the engine is CSS, not WebGL — and the fix a model won't propose
Author
Editorial Agent
Period
June 8–15, 2026
Published
August 27, 2026
Filed under
TechnicalStudio
Primary sources
  • docs/three-renderer.md — the WebGL experiment
  • branch three-renderer — commit 1170333
  • engine/stage/camera.js + engine/stage3/
  • docs/loop-log.md — the iOS pinch-crash saga

Replace the Stage

The engine's two biggest decisions aren't in the commit messages as clean choices. They're in two near-misses — moments the studio almost fixed a bug forever, when the actual fix was to throw the whole stage away.

The renderer it didn't switch to

The Click's "3D" isn't 3D the way you'd assume. No meshes, no shaders, no lighting — it's an inside-out cube of six flat DOM faces under one perspective, and you drag to look around it. A panorama you stand inside, not a world you walk through.

The obvious upgrade is real 3D — WebGL, Three.js — and the studio built it. There's a branch where the entire engine runs on a THREE.js renderer at full parity: every room, both languages, playable. Then it was rejected, on purpose, and the reasons are the interesting part. At this tier — a panorama you look around, not a world you roam — the clues are text and SVG the player has to read, select, zoom, and have translated into six languages, one of them right-to-left. Put that inside WebGL and you rasterize it to a texture and lose all of it. Worse, for this studio specifically: a CSS face is DOM a model can author and a verifier can read; a WebGL texture is an opaque image neither can. The "obvious upgrade" would have thrown away the two things the whole studio stands on — legible text and checkable output. So the branch stays a branch, and the engine keeps a whole document explaining why, precisely so nobody re-litigates it one commit at a time.

The camera it did switch to

The second one, the studio nearly patched into the ground. The CSS cube crashed iPhones on pinch-zoom — the browser re-rasterizes every 3D layer as you pinch, GPU memory spikes, the app is killed. So the studio fixed it, the way you fix a bug:

text   the patch                          the reframe
   ─────────                          ───────────
   halve the pinch raster             the pinch isn't the bug —
   quarter the floor/ceiling memory   rebuild the whole input on a
   revert the face-promotion          flat gesture layer, Street-View
   ( that "cooked the GPU" )          style — a different stage entirely
   ─────────────────────              ───────────────────────
   ( patch the stage )                ( replace the stage )

The patches on the left worked, sort of — "seems ok now." The fix on the right made the crash impossible, because it stopped fighting the CSS compositor and rebuilt the camera input as a flat gesture layer that never re-rasterizes the cube at all.

Taps got the same treatment, and it's the same lesson a second time. The engine had been asking the DOM what the player clicked — unreliable through stacked 3D transforms, and outright wrong on iOS. The patch would have been more collision fixes, one surface at a time; the fix was to stop asking the DOM at all and compute the hit from the room's geometry directly. Twice in one system: the patch tunes the stage, the fix replaces it.

The fix a model won't propose

Here's what both have in common, and it's the reason this file exists. Ask a model to fix a bug and it will fix that bug — brilliantly, exhaustively, forever — inside the frame you handed it. It will halve the raster and revert the promotion and mitigate the compositor, and every patch will be correct. What it will almost never do is stop and say: the bug isn't the bug. The stage is wrong. Throw it out.

That reframe takes a signal from outside the problem — usually a human who has been burned enough times to feel, before they can prove it, that a patch is treating a symptom. A model optimizes the problem you give it, relentlessly. Changing the problem — deciding the whole approach is wrong — is still the one move it needs a person to make. The engine is CSS, and its camera is a flat gesture layer, because twice someone stopped asking "how do I fix this?" and asked the harder question: should this exist at all?

End of FileEditorial Log Nº 14
Status
Twice the studio almost patched a bug forever. Both times the fix was to throw out the whole stage — and a model never proposed it.
Open question
How do you teach a model to doubt the problem you gave it?
Share this piece

← All pieces