Commit Graph

44 Commits

Author SHA1 Message Date
m3ultra
0b4dd0d0bd Merge remote-tracking branch 'origin/lane/d'
# Conflicts:
#	THREADS.md
2026-07-17 02:39:41 +10:00
m3ultra
34712bf297 Merge remote-tracking branch 'origin/lane/b'
# Conflicts:
#	THREADS.md
2026-07-17 02:39:41 +10:00
m3ultra
da35a954e0 Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
2026-07-17 02:39:40 +10:00
m3ultra
ce8d22cb60 Merge remote-tracking branch 'origin/lane/e' 2026-07-17 02:39:40 +10:00
m3ultra
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>
2026-07-17 02:34:49 +10:00
m3ultra
966dda9590 Post Sprint 4 gate 1 and the garden-HP finding
The face's first act was to expose that garden HP barely responds to rigging: a
perfect rig scores 53% on storm_02 and rigging nothing at all scores 48%. Cause
is measured (rain shadow decays 0.38 -> 0.04 as wind builds) and it is not a bug
in anyone's lane — but it means decision 7's headline score is nearly
independent of the game. Flagged for Lane C with the numbers; the design call
about whether garden HP is even the right storm score is left open.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:32:44 +10:00
m3ultra
acb35752ee Log ponding data, the router gap, decision 7 helper and the night pass
Leads with the router allowlist gap: rig.step() gets the router, which doesn't
forward rainMmPerHour, so B's ponding would pass every assert and do nothing
in-game. Two lines in main.js.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:29:17 +10:00
m3ultra
4bb0efcfd1 Add the pond visual, the broom, and rename the snapped panel
Pond (SPRINT4 §E-1, decision 10): pond_water.png and pond_normal.png, for a
patch Lane B builds from the cloth's own nodes — same ride-the-nodes rule as the
tears, since a rigid disc would sit still while the belly moves under it. Alpha
is a radial feather and RGB darkens toward the centre, both encoded radially so
the shading survives being scaled per pondMass (radius ~ sqrt(mass)). Water is
grey-green, not blue: rain caught in a sail is shallow, murky and mirrors an
overcast sky.

Both at 256², not 512²: smooth low-frequency content, and at 512 they were
256 KB + 320 KB against ~20 KB for every other texture here. The chop is seven
waves at golden-angle directions rather than three crossed sines, which
interfered into a lattice and read as basketweave; the normal map gets six
integer-frequency waves for the same reason, and still asserts its own tiling.

broom_01 (§E-2): poke_tip sits on the bristle end deliberately — a broomstick
jabbed at a loaded sail holes it.

Renames fence_panel_broken to fence_panel_snapped to match SPRINT4 §A-4/§E-3.
Lane A's dress() guards every load, so the mismatch would not have crashed —
the wreckage would silently never have appeared, which is worse.

All 21 assets pass, 33 output files byte-identical across two runs, 186/0/0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:27:55 +10:00
m3ultra
ea128e1307 Log decision 11: concede the bar, post the numbers, flag what's open
The 60% bar passes on the real yard at every value tested. My
"unachievable" verdict was measured against a 16.7-degree reference rig
the game cannot build; the yard is 4.8 degrees, where it clears easily.
Records the pitch table so nobody re-runs this argument, and flags that
ponding v1 and D's tension cliff remain open on lane/b.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:22:01 +10:00
m3ultra
89fd4e60b9 Merge Sprint 3 lanes; rule on the downdraft dispute; green-light ponding
Selftest on merged main: 184 pass / 0 fail. Gate 3 met (on-record §7 run).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 02:02:09 +10:00
m3ultra
997ea0bab1 Merge remote-tracking branch 'origin/lane/d'
# Conflicts:
#	THREADS.md
2026-07-17 01:58:30 +10:00
m3ultra
ecb1ee7f43 Merge remote-tracking branch 'origin/lane/b'
# Conflicts:
#	THREADS.md
2026-07-17 01:58:30 +10:00
m3ultra
44a4a3e6ec Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
2026-07-17 01:58:30 +10:00
m3ultra
6880ec7d8e Merge remote-tracking branch 'origin/lane/e' 2026-07-17 01:58:30 +10:00
m3ultra
9b97bcfd00 Log decision-8 landing, the 0.45 target proof, and the B re-point ask
Semantic done + both-gates measurements + the finding that A's anchors alone
don't unblock 0.45 (B's §7 rig is still 141 m²). storm_02 held at 0.12 to keep
main green until B re-points to a small quad.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:53:56 +10:00
m3ultra
135b3dcda5 Log the on-record §7 hand-run, the failure-envelope finding, and the ladder deferral
The §7 loop is closed by hand on the merged game: pick up a spare at the shed,
carry it across the storm, the carabiner weak-link blows on its own, chase the
flogging corner (prompt tracks it live), hold-E re-rig → 4/4, ride out → survives
with full coverage. Definition of done met with a real storm break, not induced.

Also logged for B+C: the sail's failure envelope is a cliff — 4/4 up to tn 1.03
(~1.2kN peaks), instant ~10kN double-cascade at tn 1.04. Good rigs survive, flat
rigs cascade; the thesis holds and the decision-8 downdraft semantic won't move
the cliff (it's a cloth-stability ceiling). Ladder stretch goal deferred to
Sprint 4 with reasoning — it's a second carry type + placement + code-driven
climb height, bigger than what's left of this sprint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:43:49 +10:00
m3ultra
9f83fd4f20 Report that decisions 3 and 8 are unachievable, with the algebra
Implemented and swept fraction-of-total downdraft: it pincers exactly
like gust-only did. The cause is not the semantics, it's the bar. A
pitched sail's normal is still 96% vertical, so a downdraft loads it too,
and on its worst heading pitch and downdraft add: |d| = 0.287 + 0.958f
against the horizontal sail's f. The ratio asymptotes at 109% and needs
f=0.86 (28 m/s of falling air) to reach 60%. No value works under any
semantics.

Recommend retiring it as a wind problem. DESIGN.md's own answer is
ponding, and the arithmetic dwarfs wind (1250 kg vs 8 kg of fabric vs
1 kN of wind) — but it can't bite in 90 s without a ~40x time-compression
fiat, so it's an M4 item with an owner, not a Sprint 3 fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:30:54 +10:00
m3ultra
a34cbd6d19 Log the decision-2 result and the full-coverage finding in THREADS
Records the measured before/after for Lane B (their pre-tension cascade is gone),
and flags that full bed coverage costing >=59 m2 is deliberate design rather than
a tuning miss — with an assert in both directions so nobody optimises the
tradeoff away by accident.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:30:53 +10:00
m3ultra
446ed2f14a Log shed dressing verified in-game
Booted merged main and looked at Lane A's dress(): shed and workbench are
standing, scale reads against the fence, and world.shedTable.pos resolves to my
baked pickup_anchor rather than the fallback. First Lane E GLB in the running
game with the contract intact end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:28:42 +10:00
m3ultra
fccbeb9319 Add aftermath wreckage props and verify glTF extras survive
The aftermath screen needs something to point at (SPRINT3 §Lane E-2).
garden_gnome_01_broken snaps at the ankles with the base left where the player
last saw him, head rolled clear with the beard still on, hat off — recognisably
him rather than a shattered pile, because wreckage nobody can identify is just
gravel. fence_panel_broken loses a few palings and hangs one off a nail; most of
it stays standing, which is what makes the hole read as damage rather than as a
design choice. Both keep their intact twin's origin and ground plane so Lane A
swaps mesh-for-mesh with no offsets, asserted both ways.

Also asserts something claimed since Sprint 1 and never checked: that glTF
extras reach three's userData. They do — the gnome's collateral_value, the
canopy's sway_amp, branch_anchor rating_hint and the bin's mass_hint all arrive
as numbers. Had that silently dropped, Lane A's gnome would score $0 and every
anchor would rate identical, which reads as a gameplay decision rather than a
missing field.

Contact-sheet framing now keys the capsule off height, not max(dims): the broken
gnome is 0.39 m across but stands 0.11, so spread-based framing buried it the
same way it once buried the shackle.

Selftest 175/0/0, 30 output files byte-identical across two runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:24:19 +10:00
m3ultra
823dbb942b Post Sprint 3 gate 1 in THREADS — Lane D unblocked
Also records the KeyboardInput.holding getter trap: assigning to it from a probe
silently no-ops and looks identical to broken interact wiring. Cost me a nearly
false bug report; Lane D needs it for the on-record §7 run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:21:02 +10:00
m3ultra
1ace50da0f Merge Sprint 2 lanes; wire debris into sail step; settle downdraft dispute as documented skip
Selftest on merged main: 169 pass / 0 fail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 01:09:51 +10:00
m3ultra
cd173d1ce0 Merge remote-tracking branch 'origin/lane/d'
# Conflicts:
#	THREADS.md
2026-07-17 01:01:48 +10:00
m3ultra
3f6fc27d00 Merge remote-tracking branch 'origin/lane/b'
# Conflicts:
#	THREADS.md
2026-07-17 01:01:48 +10:00
m3ultra
ac5021d279 Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
2026-07-17 01:01:48 +10:00
m3ultra
0f5f4d8368 Make rake_pivot a real pivot; log Sprint 2 in THREADS
rake_pivot shipped as a childless empty, so rotating it moved nothing — and
rotating the whole GLB instead, which is the only alternative, tips the concrete
footing out of the ground along with the post. DESIGN.md makes raking away from
the load a player decision, so the handle has to actually work.

It now holds post + pad_eye + top_anchor, with footing left on the root: rake it
8° and the post leans while the concrete stays planted. Asserted both directions
in e.test.js — the head must travel over 0.3 m and the footing under 0.01.

Same class as the canopy bug, found the same way: by driving the handle in a
test instead of eyeballing the model. Exported dims unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 00:56:15 +10:00
m3ultra
fd6dfc77da Log Sprint 2 landing, and block Lane C's decision 3 on real numbers
Decision 3 doesn't clear its own 60% bar: measured against lane/c over 8
headings and the full 90 s, flat-horizontal is 34% of flat-pitched, not
>=60%. The downdraft is 0.3 of the GUST component only, so storm_02's
strongest is -4.5 m/s against a 32.6 m/s horizontal peak, and pressure
goes as v^2. Needs ~0.55-0.6, or a fraction of total speed.

Also flags for A: rig.step needs the 4th debris arg or crates fly through
the sail; and the cheap-rig cascade fires at t=0.4s from pre-tension on
the 192 m2 quad, which decision 2 fixes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 00:26:38 +10:00
m3ultra
43ab43d3fb Log the proven §7 loop and the exact seams A and B need
Stood in for world.shedTable and rig.repair/cornerPos in the live game and drove
the whole scenario through the real sim, real interact and real rig: take a
spare, carry it to a blown corner, hold to re-rig, spare consumed, corner back.
Lane D's half of gate 3 is done; the gap is two small seams, now specified with
working code rather than a request.

Selftest 136/0/0 across all five lanes (was 121) — no other suite moved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 00:12:29 +10:00
m3ultra
d6aa124cb7 Log Sprint 2 landing: decisions 3 & 5, rain occlusion, fog fix
Includes the controlled downdraft rebalance table for Lane B, the frozen
debris.pieces seam, and the garden-HP design question for Lane A (rain shadow
vs sun coverage).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 00:12:03 +10:00
m3ultra
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>
2026-07-17 00:08:46 +10:00
m3ultra
de86aa1662 Post gate 1 in THREADS — Lane D is unblocked
Also records what the assembly turned up for the other lanes: the rigSail() door
Lane B's picking adapter must come through, the knockdown(t, ...) argument order
that would have silently broken Lane D's get-up, and the evidence for Lane C's
dispose() light-restoration ask.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 23:38:54 +10:00
m3ultra
6083151af6 Bake M3 animation pack: 11 new Mixamo clips into player_anims.glb
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 23:06:40 +10:00
m3ultra
41ad12dede Merge all lanes; add importmap; fix /world/ absolute paths
Selftest on merged main: 121 pass / 0 skip / 0 fail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 22:23:20 +10:00
m3ultra
31d9946a04 Merge remote-tracking branch 'origin/lane/d' 2026-07-16 22:14:20 +10:00
m3ultra
e7639c4264 Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
2026-07-16 22:14:20 +10:00
m3ultra
8791eccc08 Merge remote-tracking branch 'origin/lane/e'
# Conflicts:
#	THREADS.md
2026-07-16 22:14:09 +10:00
m3ultra
703dbc499f Log Lane B landing, unit change and two findings in THREADS
Flags for other lanes: load/rating are newtons now (HUD shows kN); the
yard's 7 anchors only admit 70-192 m2 quads when real shade sails are
20-50 m2; and flat-horizontal is currently the lowest-load geometry,
which inverts DESIGN.md's central shade-vs-survival tension and can't be
fixed inside sail.js.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 21:55:37 +10:00
m3ultra
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>
2026-07-16 21:55:16 +10:00
m3ultra
31a887bf75 Log Lane C landing, contract note and per-lane asks in THREADS
Also corrects the worktree-collision attribution: the checkout that moved HEAD
off lane/a was mine, not Lane D's.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 21:53:00 +10:00
m3ultra
302972cc6e Fill in Lane E selftest suite: assets verified in three.js
Replaces the skip stub with the checks Lane A's header asked for — every GLB
loads, is metre-scale with height on +Y, and keeps the nodes other lanes query
by name — plus anchor world-position and the garden bed's three damage states.

This catches what the Blender side structurally cannot: Blender exports
Z-up->Y-up and imports Y-up->Z-up, so a broken export_yup round-trips green.
A native glTF reader is the only thing that can prove the file.

GLTFLoader is imported dynamically on purpose. Three.js addons import the bare
specifier `three`, no page in the repo has an importmap yet, and selftest.html
turns an un-importable lane module into a hard FAIL — so a static import would
redden Lane A's merge gate over a harness gap rather than a real defect. It
skips with the fix instead, and lights up by itself once the importmap lands.
Verified behind a temporary probe first: 36/36 pass. Need logged in THREADS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 21:50:43 +10:00
m3ultra
219dd55716 Log Lane E landing and PLAN3D asset-path corrections
PLAN3D §2's inventory was verified against the M1 Ultra, but we build on the
M3 Ultra, where several of those libraries are absent or moved. Records the
real paths and flags the gaps that block Lanes A and D, plus the node/anchor
contracts other lanes consume.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 21:42:40 +10:00
m3ultra
8d76340f49 Log the shared-worktree collision in THREADS
Lane D is working in the shared ~/Documents/shades checkout rather than its own
clone, so its git checkout moved HEAD off lane/a mid-session and Lane A's M0
commits landed straight on main. No damage this time, but two agents sharing one
HEAD and one index will eventually eat someone's uncommitted work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 21:36:44 +10:00
m3ultra
868ea5699d Correct PLAN3D asset inventory; log M0 contract additions
§2's paths were substantially wrong. Re-verified against the filesystem:
3D-STORE is at ~/Documents/Destroyulater/3D-STORE (its clean_glbs debris set is
real, just relocated), while 3D=models/, character_kit/, mixamo-fetch/ and FBX/
do not exist on this box at all. That last group is Lane D's whole animation
pipeline, so it's flagged loudly rather than quietly patched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 21:33:42 +10:00
m3ultra
8338c0fa99 Add 3D execution plan, lane prompts, and THREADS log
PLAN3D.md: locked stack (vendored three.js r175 + stdlib server, DJsim
house style), verified asset inventory on the M1 Ultra, module contracts,
five parallel lanes (world/sail/weather/player/assets) with acceptance
criteria and integration order.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 21:05:57 +10:00