Pieces still read as slow. Cruising speed goes from 120ms per unit to 85: the
median departure across the shipped fifty drops 970ms → 763ms and a level's
whole animation budget 15.6s → 12.7s, about 18% off. The longest departures do
not move — the cap holds them at 3.46s — so if those still drag, the dial is the
cap, which was settled separately and is left alone.
The gates that guarantee a level opens with something worth watching are stated
in milliseconds, and they were picked while a piece crossed a unit in 120ms.
Held fixed while the speed changes, they stop meaning what they meant: this
change alone made 20 of the 50 shipped levels "fail" an opening gate every one
of them had passed, purely from the unscaled number. Scaled to the dial, none
fail — the set is unchanged, and the alarm was an artifact of the constant. So
the cruise threshold and the opening floor now derive from the speed, naming
the speed they were calibrated at.
exitTiming takes msPerUnit the way it already took knee and maxMs, and the
comparison lab gets a speed slider, reads the levels actually shipping rather
than the prototype sweep they were selected from, and totals every route in the
campaign instead of the four on screen — those four skew long, where the cap
flattens any speed change to 6%.
The test that pins constant cruising speed now reads the dial from the token
instead of hard-coding 120, so tuning motion no longer looks like a broken
guarantee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Exit timing was linear in path length with no ceiling, so the longest route in
the shipped set animated for 17.4s and 19% of all departures ran past two
seconds. MOTION already carried exitMaxTravelMs and exitLongMaxMs for this;
nothing read them.
Below the knee nothing changes — every piece still cruises at the same speed,
which is the property the old test protected and the reason motion reads as
physical. Past it the piece accelerates rather than taking longer, approaching
a ceiling. Length is still legible: longer routes still play longer, just with
a compressing tail.
The test now states the rule it is protecting instead of "no duration cap":
constant speed below the knee, a bounded and monotone tail above it.
labs/exit-timing plays the same real route side by side, uncapped against a
candidate setting, with knee and ceiling on sliders — the numbers say 3.5s but
only watching it says whether that is right. Defaults are provisional at
2.4s / 3.2s pending that call.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The shipped 1000 levels have a hole: 568 of them need no rotation at all, and
none needs more than two — the mechanic the game is built on is mostly
decoration. This fills the empty band with levels that need at least three.
createDeepLock builds a four-piece chain where each link only releases at a
later orientation, and growDeepLevel packs the rest of the board around it
without opening a shortcut. Candidate pools are built per orientation and left
untruncated; ranking by bend count first starved the packer and capped levels
at four to six pieces instead of twelve.
deadTurnAudit enumerates every reachable (orientation, remaining-set) state to
prove no dead ends exist, and counts how long a player can be left with
nothing to do — solvable and feeling solvable are different things, which is
what "level 2 is impossible" turned out to be about.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Watch an agent play in real time, replayed with the main game's renderer and
animations. The board holds the stage with the live panel beside it: a
millisecond stopwatch, how long the current step has been thinking, steps,
decisions, pieces cleared, dead taps and rotations, then the agent's running
commentary. A banner over the board names who is playing, self-reported by the
agent via --agent.
The page polls unconditionally; the checkbox only decides whether the cursor
chases the newest step, and it follows the agent into its next run once this
one ends. Clicking any step in the feed replays the board at that moment, and
the arrow keys walk it — there is no scrub bar, since the feed already is one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Let any agent with a shell play a level the way a person does: look at the
board, decide what to tap or which way to turn, read the feedback, decide
again. Every step carries the agent's own reason, so a human can watch and
judge the level from how it was played.
observe() returns what the eye sees — each piece's drawn route, which cells it
crosses, who is sitting on it, and who it brushes past — never "which pieces
can leave". act() goes through the real Game rules; metrics() scores the run
afterwards with the solver.
Pieces are wide, so a route with nobody standing on it can still be blocked by
a neighbour the curve hugs. That is invisible in a cell listing, so every
obstacle is reported, on-route and grazing alike: reporting only the leading
one hid the rest, and in 113 of 581 such cases clearing the blocker sprang a
collision the agent had never been shown.
AGENT.md is the single file an agent reads — rules, board reading, commands,
rating scale, worked example.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Restore v0.1 and v0.2 archives with separate progress, publish the curved v0.3 campaign, and document the original 24-level design with reproducible evidence. Refine board presentation and movement, and keep video lab tooling within its own directory.