Lane D: clip contract for E — measured wind bands, windBase signal, and the fetch blocker

Gate 2.4 asks E to agree names+thresholds with D before exporting. Filed:

- Blocker E can't see from a JING5 clone: build_player_anims.py's source
  libraries (~/Documents/FBX, 3D=models/animations, mixamo-fetch) do not
  exist on this laptop. All three are on ultra. The pack ships built but is
  not rebuildable here.
- The asked-for clips aren't on disk anywhere (only Stumble Backwards and
  Taking Cover are lean-adjacent, both already shipped), and new Mixamo
  fetches need John's manual browser login. Brace and stagger are ALREADY
  shipped and wired (TakeCover on KeyC, Reaction/StumbleBack on gusts) —
  the lean is the only genuinely new posture.
- Bands measured at the player spawn across all five storms:
  calm <8.3 / lean 8.3-17 / gale >=17 m/s, hysteresis +/-1.5. 8.3 m/s is
  30 km/h, the same number C's leaves start at. Band ladder lands on the
  storm rating ladder.
- Signal is sim.windBase (existing ~4s EMA), not raw wind.speedAt: raw
  strobes at 8-18 band flips/min, windBase gives 0-2 per 90s storm.
  Sustained = posture, gust = event. Deviation from the prompt's literal
  wording flagged to A with the table.
This commit is contained in:
type-two 2026-07-17 23:40:28 +10:00
parent 5859bc83fa
commit 8d0045bb29

View File

@ -4561,3 +4561,87 @@ anchors are your GLB), but the tooling is now waiting, not TODO.
— a bad night reads as a story you did to yourself. The trap fires as theatre, the Vasilaros
brief is perfect bait, and the loop is solid. The gap between how the game PLAYS and how it
LOOKS is the whole of Sprint 13.
[D] 2026-07-17 — 🪢 **LANE E — THE CLIP CONTRACT, MEASURED, AND A BLOCKER YOU CANNOT SEE FROM YOUR
CLONE. Read this before you open Blender.** SPRINT13 says agree names + thresholds with me first,
so here it is, plus the thing that will eat your sprint if nobody says it: **the source library
isn't on this machine.**
**⚠️ 1. THE SOURCES LIVE ON `ultra`, NOT ON JING5.** `build_player_anims.py` reads
`~/Documents/FBX` and `~/Documents/3D=models/animations`. On this laptop **both do not exist**, and
neither does `~/Documents/mixamo-fetch`. I checked ultra over the tailnet: all three are there
(`johnking@100.91.239.7`, 26 FBX). The repo ships the built `player_anims.glb` (2.3 MB, 17 clips)
but the house rule keeps raw DCC out of the repo, so the pack is **not rebuildable from a JING5
clone**. Either run the build on ultra or pull the library across first — don't discover this at
export time.
**⚠️ 2. THE CLIPS YOU'VE BEEN ASKED FOR DON'T EXIST ON DISK, AND ONE MAY NOT EXIST AT ALL.** Of the
26 FBX on ultra the only lean-adjacent ones are `Stumble Backwards.fbx` and `Taking Cover.fbx`
**both already in the pack**. There is no lean, no brace, no walk-into-wind. And your own build
tool's comment (build_player_anims.py:52) already recorded the answer to half of this:
*"Hammering / Sweeping Floor / Bracing don't exist on Mixamo — skipped."* Fetching anything new
needs `mixamo-fetch`, which the wishlist is explicit about: **a MANUAL Google login in a real
browser, by John, and never something a lane fetches on its own.** So the honest status of gate
2.4 is: *blocked on John running a fetch on ultra*, not on your Blender time. Flag it to A now —
the sprint plan doesn't know this.
**3. TWO OF THE THREE ARE ALREADY SHIPPED AND WIRED — don't rebuild them.**
```
brace STATES.shelter → 'TakeCover' already on KeyC, already tuned
(shelterKnockMult 2.0, shelterShoveMult 0.25)
stagger STATES.stagger → 'Reaction' 0.9 s, fires on gust ≥ TUNE.stumbleGust (9 m/s over base)
STATES.stumble → 'StumbleBack' 0.8 s
```
SPRINT13 says "brace pinned to the C key that already exists" — it exists *and so does its clip*.
**The only genuinely new posture is the LEAN**, and it happens to be the exact QA finding ("the
player stands bolt upright and unbothered"). If John's fetch only yields one thing, make it a lean
idle — that single clip buys most of gate 2.4.
**4. THE BANDS — measured at the player's spawn (0, 1.2, 6) across all five storms, not guessed.**
```
storm rating windBase med max calm/lean/gale seconds of 90
gentle 1 6.5 8.6 90 / 0 / 0 ← you stand up straight all night
southerly 2 12.3 16.2 27 / 63 / 0
earlybuster 3 13.1 17.4 18 / 72 / 0
wildnight 4 19.4 25.1 7 / 29 / 54
icenight 5 18.8 23.1 12 / 31 / 47 ← the gale IS nights 4-5
```
**Thresholds (m/s), hysteresis ±1.5: calm < 8.3 · lean 8.317 · gale 17.**
8.3 m/s is 30 km/h **on purpose — it's the same number C's leaves start at (gate 2.3)**, so the
yard and the body agree: when the leaves fly, the man leans. 17 m/s (61 km/h) is where nights 4-5
separate from 2-3. The band ladder lands exactly on the rating ladder, which is the whole point:
**the posture tells you which night you're on before the HUD does.**
**5. THE SIGNAL IS `sim.windBase`, NOT `wind.speedAt` — and this one is measured, not stylistic.**
My prompt says "thresholds off wind.speedAt(player.pos)". Taken literally that strobes, because
the raw local speed is gust-noisy. Band changes per storm:
```
raw speedAt + hysteresis 818 flips/min ← a posture change every 46 s. Unusable.
sim.windBase (EMA) + hysteresis ±1.5 02 flips PER 90 s STORM
```
`sim.windBase` already exists (player.sim.js:162/275) — the ~4 s EMA of the local wind, with
`sim.gust` as the residual, self-calibrating to whatever C authors. It IS derived from the local
sample, so this honours the ask and fixes the signal. It also draws the right line:
**sustained wind = posture (lean), gust = event (stumble/knock)** — and the event half is already
wired. Gentle flips **zero** times; wild flips twice. A posture change becomes a beat in the storm
instead of a flicker. **A — flagging the deviation from the prompt's literal wording; it's one word
and I have the table.**
**6. NAMES — PascalCase, matching STATES' existing contract (build_player_anims.py CLIPS is the
other half of it):**
```
LeanIdle standing, leaning into wind band: lean ← highest value, build first
LeanWalk walking into wind band: lean
GaleIdle hard lean, braced legs band: gale ← stretch
GaleWalk fighting forward band: gale ← stretch
```
In-place only (the game translates the player; player.js keeps rotation tracks only, so root travel
is wasted — your pipeline already knows). **Carry stays out of scope**: carrying keeps Carry /
CarryIdle at every band this sprint. A man hauling a ladder in a gale is a Sprint 14 nicety, and
four clips is already more than John's fetch may return.
**If the fetch is dry on Gale*: say so and ship Lean* only** — I'll drive the gale band off the
lean clips plus a small extra root pitch on my side (player.sim.js already pitches the root for the
knockdown, so the machinery exists). That fallback is mine, not yours; it just means gate 2.4 lands
either way instead of waiting on Mixamo's catalogue.
Nothing here blocks on me. When you've got names, I wire thresholds in player.js the day they land.