Commit Graph
16 Commits
Author SHA1 Message Date
toshiocn 1be0e9caf1 feat(airport): add the Hex Airport dispatch lab as a baseline snapshot
Six-side aprons, frozen levels, solver, rewards and verify scripts; the edge-runway readability work continues from here.
2026-09-21 14:25:09 +08:00
cabinwandClaude Opus 5 6e72b95ad8 feat(levels): c50c trades one good idea repeated for five that alternate
c50b is sealed where it stands, as a reference sample rather than a candidate.
Its packed construction was judged good — clearing a board from the rim inward
is the experience it proved out — but at 32 of 50 levels it played as one level
fifty times: 体验太单一了,因为基本都是满盘. The note on why it is kept lives at
the top of its module, because the lesson is the useful part.

It was monotonous on a second axis nobody asked about. 环绕 and 花瓣, the two
route families the brief singles out as the good-looking ones, were absent from
it entirely — not by choice but by a crossing threshold. At 1.0 crossings per
cell, 0% of orbits boards pass and 4% of spirals; at 1.2, 84% and 94% do. The
gate meant to answer "交叉点太多" had quietly deleted the families most worth
looking at, so it moves to 1.2 — still half the 2.36 that drew the complaint.

c50c alternates five kinds of level every three to five: packed boards down to
32%, long-route departures to watch, deep locks to solve, small quick boards,
and segments given over to orbits, petals and spirals by name. All six families
appear, no family exceeds 24%, and the plan is 13 segments rather than 9.

Selection learned to ask for variety outright — by family, piece count and
longest drawn route — instead of hoping it falls out of a difficulty score.

Rule bot across all three: 50/50 cleared and zero dead taps everywhere; c50c
sits between the other two on blind rotations and on how much there is to do.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 15:53:26 +08:00
cabinwandClaude Opus 5 7607f48cb1 feat(levels): boards whose interior is packed and whose rim is left empty
The game has never had a board you simply clear out, and the request for one
turned out to need a construction of its own rather than a denser deep lock.
Filling cells at random can never work: a packed board has nothing that can
move — measured over forty random fills of a 37-cell board, zero pieces free in
all six orientations, every time, because a piece steps to the next cell before
it can leave and on a full board that cell is taken.

So packBoard builds backwards. Start empty, add only a piece that could leave
right now, and the placement order reversed is a removal order — solvability
becomes a property of the construction. Which cell to fill next decides
everything: at random it stalls near half, while filling the most constrained
cell first takes a 19-cell interior to 96% and fills it outright.

The rim is deliberately empty. Those pieces leave first and ask nothing, and
clearing from the rim inward gives a packed board its own difficulty curve
inside one level — the outer cells read easily, and it tightens as it opens.

Two things were tried against the ceiling and failed, and are recorded as such:
depth-first backtracking made it worse on both counts (65-78% filled against
greedy's 89%, at 2000-3000 seconds a board) because recomputing every cell's
legal directions per node spends the budget three levels deep. And the audit's
dead-turn gate could not be trusted here at all — on a packed board its breadth
search truncates, so it certified levels the rule bot then walked through three
blind turns in a row. The pool is filtered by playing it instead: a full pass
takes one second and does not lie.

The campaign is 32 packed levels to 18 deep locks, alternating, with the closing
six at a completely full interior. Same rule bot, both editions: worst blind
streak 1 either way, dead taps zero, and half again as much to do per level.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 00:23:18 +08:00
cabinwandClaude Opus 5 073b682234 feat(motion): raise the cruising speed, and make the show gates follow it
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>
2026-09-14 18:46:32 +08:00
cabinwandClaude Opus 5 b35ea201db fix(campaign): register c50 with the fields the app actually reads
Opening the c50 edition threw `campaign.legacyStorageKeys is not iterable`
and left the board blank — the header still drew, so the level set looked
loaded. Every other edition carries the array; the hand-written c50 entry
did not, and 197 passing tests had nothing to say about it, because nothing
tested the registration itself.

The test now walks every edition and asserts the shape app.js relies on,
including that the chapter list can actually hold the levels. It fails on the
entry as it shipped.

The task board was reading levels/prototypes/d5.json while the campaign sat in
levels/campaign-50.json, so it showed "候选关卡 18 / 50" with fifty levels
built. It reads the shipping set when there is one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 17:03:37 +08:00
cabinwandClaude Opus 5 96e5e4c21f feat(levels): assemble the 50-level campaign and the sheet to review it
The deep-lock construction cannot go below three turns, so it cannot supply an
opening band — every level it makes lands mid-difficulty and the curve comes
out flat. harvest-easy pulls the shallow end from the shipped v0.5 set, but
only the 3% of it that holds up: 568 of 1000 need no rotation at all and 51
more are clearable by tapping at random, which is what the monkey threshold is
for. 33 levels survive, at one and two turns.

select-50 scores candidates on mechanical features only, spreads the pick
evenly across that range, and caps any one route grammar at 36% so the campaign
cannot quietly become one template repeated — the shipped 1000 turned out to be
thirty. Weights are a flag, so refitting them from a round of agent ratings is
a re-run rather than an edit.

The result is a curve rather than a plateau: difficulty score 3.85 / 6.24 /
7.60 across the three bands, rotations 1.8 / 3.0 / 3.5, and every level keeps
three or more opening choices with a show of at least a second.

The 50 register as a playable campaign edition, so review happens in the real
game; docs/review-50.html is the handover sheet, one card per level with the
opening position drawn from the solver rather than sketched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 16:53:57 +08:00
cabinwandClaude Opus 5 a250baba53 fix(motion): stop a long departure from playing for seventeen seconds
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>
2026-09-14 16:41:06 +08:00
cabinwandClaude Opus 5 acc374e276 feat(levels): two-sided endgame release, and a board to track the 50-level run
The chain built its own worst moment: hero and tail deadlock at orientations 0
and +2 and open only at +1, with +3/+4/+5 left entirely to chance. That is why
some levels released at exactly one of six orientations, and why every model
kept writing "I don't know which way to turn" — at +2 one direction was right
and the other five were dead ends.

createDeepLock now traces candidates at all six orientations and requires the
tail to also release at +3, certified with the real swept tracer. A player
stuck at +2 turns either way and something moves. Measured by the rule bot
over the regenerated set: blind rotations, wrong-way turns and extra rotations
all go to zero, from 1.17 / 0.44 / 1.22 per level. Endgame orientation counts
shift from {1:4, 2:10, 3:4} to {2:3, 3:13, 4:1}.

It costs yield: switchback r3 and crossing r3 now produce nothing, and the set
comes out at 17 levels rather than 18. The test witnesses moved with it — a
witness is whichever seed still satisfies the construction, so they are
re-derived from the sweep rather than pinned.

docs/level-board.html is the task board for getting to 50 levels. Task state is
in bench/board.json; every number on the page — candidate count, rotation
quota, blind turns, monkey actions-per-piece, the agent batches — is measured
from the level set and the run archive at build time.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 16:22:08 +08:00
cabinwandClaude Opus 5 643cba0ed9 feat(levels): D5 three-rotation prototype
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>
2026-09-14 14:00:33 +08:00
cabinwandClaude Opus 5 c760c23fd1 feat(bench): agent bench session core and CLI
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>
2026-09-14 14:00:33 +08:00
cabinw 10cf93a324 feat: add Paper Routes and package five design systems
Add the paper direction with thin tracks, outlined hexagons and line arrows, without exterior color markers or piece numbers. Add a unified catalog for five designs and their 25 themes, with direct review links.

Organize each design into an authored design.md, generated tokens.json and preview. Add Agent routing, shared integration guidance, a machine-readable manifest and an executable rendering example. Preserve legacy preview and document links.

Validation: 16 focused design, theme and package tests passed; npm run design and static build passed. Confirmed all eight authored documents survive generation unchanged. Browser checks covered mobile, tablet and desktop layouts, theme links and migrated previews. Native engine integration and visual verification remain pending.
2026-09-13 13:24:34 +08:00
cabinw 4644e975b0 feat: add production campaigns, gameplay labs, and review documentation 2026-09-13 12:27:10 +08:00
cabinw d1dffa9338 Add three playable puzzle variants in an isolated lab 2026-09-13 12:19:13 +08:00
cabinw e92cccba82 feat: version campaigns and document original puzzle design
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.
2026-09-09 13:17:30 +08:00
cabinw 70b021d4cc feat: expand campaign and refine puzzle visuals and controls 2026-09-09 11:02:45 +08:00
cabinw ef2724bb2e feat: add hex trail puzzle, level editor, and visual design guide 2026-09-08 21:45:44 +08:00