Twenty
Twenty is a Rubik’s cube in the browser. You can scramble it and solve it yourself, against the clock, or you can use it as a solver for the one on your desk: paint its colours onto a net, or hold it up to your camera and watch a little map of it fill in face by face, and then follow the solution move by move on the animated cube. The name is God’s number: every position of the 3×3×3 can be solved in twenty moves or fewer.
It was built the same way as Syzygy and Ponder: I wrote a brief and a style guide, sat at EILAID’s two gates, and the agents did the rest. I didn’t write any of the code, including the solver. Click the picture and you’re in it.


What I asked for
- Its own solver. Kociemba’s two-phase algorithm, written from scratch in TypeScript, running in a Web Worker with its pruning tables built on the device: no solver library, no copied tables. Every random cube in 25 moves or fewer, a median of 22 or fewer, under a second. And a second, longer solver that solves it the way a beginner learns to, layer by layer, with a named step and a one-line reason for each group of moves.
- Playable. Drag a layer or use the keyboard. Scramble, a timer, best times, confetti when it’s solved.
- Set up by hand. Paint the colours onto a net, and a validator that tells you in plain English what’s impossible, rather than “invalid state”.
- The camera. Hold up your cube and a minimap next to the video fills in as each face is recognised, in any order, with no capture button. Classical computer vision written for the project, no models, and nothing leaves the device.
- Only N×N×N cubes, and only 3×3 for now, with the model and the view written so another size is a small change.
Halfway through I added two more: gestures that make the cube feel good in the hand (flick a layer, twist the whole cube with two fingers, a bit of inertia), and a style picker, because a cube that is only ever black plastic is a missed opportunity.
What’s there
- Play. Drag or flick a layer, or press the face keys. Scramble, timer, best times, undo and redo, and the whole position in the URL so a link brings it back. Two fingers twist or swipe the whole cube; a pinch zooms. Press “show me” and the solver’s answer plays on the cube, shortest or step by step, with a scrubber, speed controls and the solution as text.
- Set up. Paint your cube onto the net, or straight onto the 3D cube, with the keyboard if you like (1 to 6 pick a colour, the arrows move across the net). The palette counts each colour as you go and the validator explains itself: “There are 10 blue stickers; each colour appears exactly nine times.” “This corner has two blues; a real corner never does.”
- Camera. Hold the cube up and turn it. A face is read once it has held still for half a second, the minimap fills in with a stagger across its nine stickers, and a line says what’s still missing. A wrong sticker can be tapped and corrected. When the sixth face lands, the solver takes over.
- Six styles. Classic, stickerless, paper, glass, wireframe and, with the lights off, neon, which is a real bloom pass loaded only when you pick it. Pick neon on a light page and a note says “neon needs the lights off; showing glass until then”, with the switch in the sentence.

classicblack body, inset stickers
stickerlesscolour fills the whole face
paperflat colour, thin printed lines
glasssee-through body, bright stickers
wireframehollow outlines, the body gone
neona glow on black; glass with the lights onThe day
At 12:02 UT on 8 October I sent one message: build Twenty from the brief and the style guide, as an epic from an empty repo. The architect took 20 minutes and $3.64 to split it into 16 items and write 14 decision records, one of which answers the other-sizes question (more on that below). I read all 16 briefs and approved them without a change, which I hadn’t managed on either of the earlier projects. The scaffold was at gate 2 thirty-seven minutes after the ask.
The pure parts came first and came fast. The cube model, the validator (55 tests) and the layer-by-layer solver each landed on their first attempt. The two-phase solver landed at 13:48, first attempt, and it beat the brief: 1,000 random cubes out of 1,000 solved, a median of 21 moves and a worst of 25, the tables built in 0.6 seconds from cold, and the first solution in a median of 23 milliseconds. The first thing I did with it was feed it a scramble and watch the cube solve itself.
Then the day got harder, in the way the earlier projects had taught me to expect. The afternoon was the view, play mode and the player; the evening was set-up and the camera; the night was gestures and styles. The last feature, wireframe, merged at 03:57 the next morning, and the chores trailed on until half past six.
Two things stopped the run entirely. At 15:25 every agent failed at once with “You’ve hit your org’s monthly spend limit, resets 4:10pm UTC”, and 13 items were blocked within a minute. Fifty minutes later the API came back, I unblocked them all, and nothing was lost. And the box itself restarted twice, once that afternoon and once at 04:00, each time taking the daemon down mid-flight. Both times the state was all on disk, and the queue picked up within a minute of the daemon coming back.
What I caught
The gates earned their keep again. At gate 2 I sent four changes back:
- TWY-3, the app shell. Raw millisecond durations in the CSS instead of the tokens, a theme toggle 29 by 18 pixels on a phone, and key chips that stretched. The style guide had said 44-pixel targets; nobody had measured.
- TWY-8, the cube view. It worked, with twenty passing browser tests, but it had its own copy of the move engine rather than using the model’s, its orbit tests waited on fixed sleeps, and a WebGL failure left a dead canvas with no message.
- TWY-15, colour assignment. The reviewer had marked it minor: a zero channel in white balance produces a NaN, and a NaN makes the Hungarian assignment loop spin forever. A black sample is a normal thing for a camera to see. Back it went, and it came back with the degenerate cases tested (lens covered, deep red light).
- TWY-97, a flaky-test fix, that left one of the two stale snapshots it existed to remove.
The rest I accepted with follow-ups, and the follow-ups were where the taste came in. The camera’s minimap covered the cube on a phone once the solution opened; a link with the wrong centre stickers was a dead end nobody could paint their way out of; the “all six faces read” line was 4.3 to 1 against a light video when the guide asks for 4.5. None of those is a bug a test would find.
The agents caught things too. A reviewer found that the two-finger gesture could get stuck for the whole session because cancelling a drag released the first finger’s pointer capture. The design reviewer found that the neon bloom was being clipped into a visible rectangle at the edge of the canvas, which the builder fixed on its third attempt by dropping the two widest blur passes. The builder working on the style picker found, on the way, that the router remounted the whole mode when you pressed Back across a #fragment, filed it, and it was fixed and merged four hours later. And a shaper noticed that the player’s scrubber was drawn last on a phone but focused early, which was exactly the rule a decision record had just written down.
The camera, on real cubes
The computer vision is the part I was least sure about, so I went and found twenty photographs of real cubes with open licences and put them in the repo, with attribution, as fixtures. The first detector found a face in 5 of the 20: hand-held, head-on, fine; any three-quarter view, nothing. I filed a ticket with the number I wanted (at least 9 of the 11 photos that show a clean face), and the next version found 10 of the 11, at 4.2 milliseconds a frame. The one it still misses has a 4×4 in the foreground, and it reads the 3×3 beside it instead, which seems fair.
The rest of the camera work is a small state machine: a face counts once it has held still for 500 milliseconds, the six faces are assigned colours so that each colour appears exactly nine times (a balanced assignment, not a nearest-colour guess), the orientation is resolved from the centres, and if the orientation was a guess the player says so.
Flaky tests, again
Every one of these projects has had the same fight, and this one had it less. The rules from Syzygy were in the brief from the start: never time the wall clock, count the work instead, one port per worktree, no fixed sleeps. Most of the agents followed them. The interesting failures were the ones that followed the letter and not the spirit: a helper called rested() that waited 150 milliseconds of real time inside page.evaluate, which the lint ban on waitForTimeout couldn’t see. That became a lesson in the builder’s spec, a stricter lint rule (no performance.now, Date.now or setTimeout(n) in a browser test), and a fix.
The one that made me laugh was a check in a brief: grep -rn "hash || ''" src/app/style.ts, meant to prove a fallback was gone. A grep that finds nothing exits 1, so the item failed its own check three times and blocked itself with its code correct. The same thing had happened on the first afternoon (TWY-38). Now the shaper’s spec says a check that must find nothing is written as ! grep, and that every grep in a brief is run against the tree before the brief ships.
Other sizes
The brief asked for 3×3 only, but for the model and view to be written so another size is a small change, and the first decision records say how small. The facelet model, the moves and the view are written for any N from 2 to 7 already. Playing a 2×2 or a 4×4 is about one item of work (a size picker and the slice moves). Solving a 2×2 is one item: it’s a corners-only subset of what the two-phase solver already does. Solving a 4×4 or bigger is about three items, because the standard approach reduces the big cube to a 3×3 first (centres, then paired edges, then the existing solver) and has its own parity cases. The camera for a bigger cube is about two: the grid detector and the colour balancing both assume nine stickers a face.
What EILAID got wrong
- Dependencies are the owner’s job, and I missed one. Glass and neon were dispatched before the style framework they build on had merged, because I never recorded that they depended on it. The builder noticed, blocked itself, and I parked it. Twice more I had to pull an item back the moment it was approved, because approving dispatches.
- A small chore storm. Coaches and builders file follow-up tickets well, so well that by the second night most of the queue was one-file chores: dedupe these two test helpers, add a column to the style guide, measure the contrast instead of estimating it. I cancelled 15 items in all, mostly duplicates and meta-tickets (one asked to fix another ticket’s brief).
- Briefs written before my answer landed. Twice a shaper quoted my answer as an open point and kept its own version in the acceptance criteria, so the builder had to go against the brief to follow me. That’s now a shaper lesson: the owner’s answer wins.
- The spend limit. Not EILAID’s fault, but EILAID had no idea. Thirteen “env-broken” blockers with the same text, and a human to notice that the fix was to wait fifty minutes.
Where it ended up
Twenty is live at /twenty/. In all, 95 items shipped (24 features, 11 bugs and 59 chores, nearly all of the last two filed by the agents themselves) and 15 were cancelled, over 18 and a half hours from the first message to the last merge.
By hand I restarted the daemon twice, edited the config four times (how many agents at a time, and the run budget), promoted 32 versions of the builder’s spec, 8 of the shaper’s and 2 of the designer’s, answered 55 questions, and committed twenty photographs of cubes. The Oracle answered another 58 on its own, from the project. The agents’ findings on each other’s work came to 247: 17 major, 101 minor and 129 nits, and 25 of the items needed more than one attempt.
If you only try one thing, scramble it, press “show me” and pick “step by step”. Then pick neon and turn the lights off.
start again · part 1Engineers decide, agents build →The idea behind EILAID. A methodology for building big projects with AI agents, where engineers sit at two gates and the project remembers everything.