0b4dd0d0bd
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0ceff91d5a |
Lane D: the ladder sub-system (decision 12)
New ladder.js. The whole mechanic is 200 mm: the fascia bracket sits at 2.48 m, a 1.72 m person's hands reach 2.20, and E's ladder tops out at 2.90. The asset and the yard were already built for each other; this is the verb between them. Carry-ladder is a second carry type, so the ladder and the spare compete for the same pair of hands and a fascia repair costs two trips while a post repair costs one — DESIGN.md's "limited hands" rule doing real work, and the reason the house is the expensive anchor to depend on (which E's ratingHint 0.35 / collateral "gutter" was already saying in the data). Climb height is code-driven with ClimbLadder playing on top — the knockdown precedent, since _rotOnly strips the root and a clip can no more lift the body than Falling could lay it down. You can't brace up there (both hands on the rungs), the wind's bar drops to 0.6x, and being blown off is a fall that feeds straight into the existing get-up chain. needsLadder is scoped to the fascia on purpose: a height test would have roped in the 3.95 m posts and 5.05 m limbs, made every repair a two-trip job, and silently invalidated the recorded §7 run — and it isn't true to rigging either. Landed with no change to main.js: createLadder self-wires from createPlayer, which Lane A already hands the scene, world and interact. Two bugs found by building on my own API, both now asserted: a canUse that reads player.state cancels its own hold (starting a hold sets busy) — it ate the climb AND the reach gate before I keyed both on physical height instead; and onLadder had to become height-based for the same reason. Documented on register(). Selftest 194/0/0 (was 184). Full loop driven by hand in the real game. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
264c2e25d2 |
Lane D: solids collision, the M3 verbs, shelter and stumble
At gate 1 the ped walked straight through the house. Collision now stops it 0.30 m off the wall face (expected -9.70, measured -9.70), off trunks, posts and the fence, and slides along a wall hit at an angle. Injected as opts.collide the way groundAt already was, so player.sim.js stays zero-import and node-runnable. Two things the real yard taught, neither guessable from the plan: - `fence` is a GROUP of 37 child meshes whose combined box is the entire 30x20 m yard, so one box per solids entry is useless. Flattened to 43 leaf boxes. - the house ROOF spans y 2.99-3.21 and reaches 0.4 m FURTHER into the yard than the wall under it (eaves overhang). A flat footprint test would stop a 1.7 m person dead at an invisible eave, so every box is filtered by vertical overlap with the body and the roof drops out on its own. Boxes are built once (solids are static) and distance-pruned — no per-frame raycast, which is the thing Lane A measured as catastrophic on the terrain. The M3 pack is wired: carrying swaps locomotion to Carry/CarryIdle; an interaction names its own verb through a new `clip` field on the interact spec (Crank at a turnbuckle, PickUp at the shed table); StumbleBack fires on a gust that breaks your stride but can't floor you — below knockWind on purpose, so a storm reads as shoved → stumbling → floored rather than fine-fine-fine-flat. TakeCover (hold C) became a real mechanic rather than a pose: brace and knockWind x2.0, shove x0.25. A 38 m/s gale floors you standing and doesn't while braced; let go in the same gale and you're down in half a second. It raises the bar, it does not remove it — a big enough gust still wins, braced or not. So the storm's answer to "the gusts are too strong to cross the yard" is now wait one out and move in the lull, which is the repair-window language DESIGN.md already uses. wireYardActions now reads sailRig.corners[i] live by index instead of capturing the corner object — per Lane A's warning that attach() replaces the array, a captured corner is one the sim no longer steps and would gate forever on a `broken` flag that can never change again. 35 Lane D asserts, 0 fail (was 20). Carry/shelter/knockdown verified against the real 17-clip pack in the assembled game, not only in the harness. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6382e604b8 |
Lane D: the small person — player, interactions, selftests
player.sim.js Deterministic core, zero imports: camera-relative movement, the
state-machine table, wind slow/gust-shove/knockdown. step(dt,t)
is the whole clock — no Date.now, no Math.random, no rAF — so a
storm fast-forwards identically in selftest and in the game.
player.js The view: rig load per the 90sDJsim DEVMANUAL rig rules
(SkeletonUtils.clone, height-normalise off the MEASURED head
bone, canonicalised bone namespace), clip retarget, and
createPlayer() satisfying the Player contract.
interact.js Hold-E with radial progress + wireYardActions (re-rig 2.5 s,
turnbuckle trim 1.2 s, carry-one-item), duck-typed so it no-ops
cleanly until Lane B lands sailRig.repair/trim.
d.test.js 20 asserts in Lane A's harness: 38 pass / 3 skip overall.
Ported from the 2D prototype's shape (game.js:250-252), retuned to m/s: the
slow curve, and shove gated to gusts only and scaling with speed² so gusts have
teeth. Knockdown needs 0.5 s of SUSTAINED overload — deliberately the same rule
as a sail corner letting go, so cloth and people speak one language.
Two decisions worth the review:
- The knockdown pitches the root in code rather than playing the Falling clip's
root. Shared clips must drop Hips.quaternion (a different-orientation source
lays the target flat), so a clip physically cannot lie the body down. Doing it
in code also lets the fall go DOWNWIND of the gust that caused it, which a
canned clip could never do, and keeps it deterministic.
- Gust magnitude is recovered from a slow EMA of local wind rather than widening
Lane C's contract: wind.sample() gives the total and gustTelegraph() only fires
BEFORE a gust, so nothing reports gust size during the hold. The EMA
self-calibrates to whatever storm JSON Lane C authors.
Verified in a real scene, not only in asserts: head bone 1.715 m at fig scale
0.983, all six clips bound, walk/run at the tuned speeds, the body lies down and
gets back up, hold-E fires exactly once per press.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|