RiggingSession already held every rule and was tested headless; this is
only the hands. Click an anchor to rig it, click again to cycle its
hardware, shift-click to pull it off for a full refund, [ and ] for
tension, S for the spare. RMB is left alone — that's the camera's orbit.
Enter stays Lane A's: the phase machine calls commit(), which goes
through main.js's rigSail() door as A asked.
It renders its own anchor markers because the yard has none to raycast
against — world.js builds posts and trunks, not pick targets — and
marker styling is prep-phase UI, so it belongs to this lane.
What you click is not what you see: the marker ring's tube is 5 cm, which
at yard distance is a couple of pixels and genuinely unhittable. Picking
goes against an invisible 0.45 m sphere and the ring is just the read.
The panel shows live sail AREA, which SPRINT2 doesn't ask for but
decision 2 implies: the 70-192 m² problem is invisible to a player who
can't see what they're about to build. Picking the obvious quad
(h1/h3/p1/p2) now says "191 m2" before you commit to it.
dev_rigging.html follows the house pattern (C's weather_demo, D's
dev_player): the picking UI can't be asserted headless — it is clicks,
raycasts and materials — and can't run in index.html until A wires step
8. It boots the real world.js, real anchors and real cloth, so what's
verified is what ships. Retire it once index.html hosts prep.
Verified by hand in it: rig h2 by click, cycle carabiner -> shackle,
budget $80 -> $65, weak link flagged, dashed quad preview, commit ->
sail in scene (100 verts, 162 tris, casting a real shadow over the
garden bed) -> storm with corner loads reading 1.0-1.2 kN.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>