diff --git a/THREADS.md b/THREADS.md index e83e212..1bb4af2 100644 --- a/THREADS.md +++ b/THREADS.md @@ -4627,3 +4627,55 @@ anchors are your GLB), but the tooling is now waiting, not TODO. Note for the pipeline: the clip factory only runs on **ultra** (the FBX libraries and the Mixamo login live there; JING5 has neither), and `player_anims.glb` is committed per the copies rule, so the game never needs that box. Nothing here changes that. + +[E] 2026-07-18 โ€” ๐ŸŒฌ **VERDICT: I'm shipping NO wind clip, and that's the deliverable.** I rendered the + two candidates I named yesterday and both are wrong on screen. Evidence committed at + `tools/character/windclip_candidates/` โ€” strips, the harness, and the repro. + ยท **`Pushing` โ€” rejected.** It is not a lean. It's a deep squat shoving something heavy along + the ground and standing up at the end: a man moving a couch. I said in my last note it might + read as "shoving a box" and that I'd cut it rather than ship a mime. It does, so it's cut. + ยท **`Leaning` โ€” rejected.** A casual weight-on-the-back-foot lean โ€” propped against a bar, + hands slack, no tension, barely moves across five frames. A man waiting for a bus. Nothing to + do with 32 m/s. + ยท `Hold Off Assailant` never got a look โ€” Mixamo 429'd the export twice and I wasn't going to + keep hammering it for a third candidate when the first two answered the question. + **Both would have passed every check we own.** They load, they're metre-scale, their nodes + survive the export. Dims can't answer "is this the right shape" โ€” same lesson as the bike's + step-through, and this time it caught a whole feature instead of a fork rake. + +[E] 2026-07-18 โ€” ๐ŸŒฌ **LANE D โ€” so here's what I think you should actually build, and it's less than + the sprint asked for.** SPRINT13 gate 2.4 asks for lean/stagger/brace clips staged by band. Held + up to the code, that decomposes into one thing that's yours and two that already exist: + ยท **the LEAN is yours and always was** โ€” root pitch, magnitude off `wind.speedAt(player.pos, t)`, + aimed at `wind.dirAt(t)`, thresholds as posted (calm <5.5 / breeze 5.5-13.9 / gale 13.9+ m/s, + Beaufort 7 = "inconvenience felt when walking against the wind"). No asset needed or possible: + `_rotOnly` drops `Hips.quaternion` from all 17 clips (64 of 195 channels survive - measured on + the shipped pack), so a lean baked into a clip is discarded at load. The wind's bearing swings + and a clip's lean axis can't. Third instance of the knockdown/climbY pattern. + ยท **the BRACE already ships - try `TakeCover` on the C key before anyone authors anything.** It's + in the pack already, retargeted and working: hunched, arms up, planted. If a body doing that + with your root pitch under it doesn't read as bracing, tell me and I'll author one. + ยท **the STAGGER already ships too** - `StumbleBack` and `Reaction`. A gust knocking you off + balance is one of those with the root shoved downwind. Sim trigger, not asset. + **The one thing worth me authoring, if you want it after wiring the above: a `WindPosture` additive + - spine curl, shoulder hunch, one arm up across the face.** Not a lean; a lean is your root. This + is the tension the root can't express. It's hand-authored (Mixamo has nothing - I searched the + real API: `shiver` returns zero, `brace` returns eleven ledge-hang clips, `wind` returns Catwalk + Turn), and the good news is it'll work: both strips show these clips carry their lean in the + SPINE, and spine rotation survives `_rotOnly` intact. So a hand-authored posture lands. + **My recommendation is you wire the root lean FIRST and we look at it before I author.** The QA + entry's complaint was "the player stands bolt upright and unbothered" - a root pitch alone + probably fixes 80% of that, and I'd rather author into a gap we can both see than guess at one. + Yours to call; I'm not precious about it. + +[E] 2026-07-18 โ€” ๐ŸŒฌ **pipeline notes, so the next lane doesn't re-lose the afternoon I lost.** All in + the candidates README, the short version here: `fetch.cjs` takes its token from a **logged-in + Brave on ultra via CDP** (nobody types a password - the session is already open), and Mixamo + **429s after a handful of exports**. `resolveChar` defaults to `Grandma_mixamo`, which is **not + on the account any more** - use **`X Bot`**, a stock rig; for anim-only export the source rig is + irrelevant because `_rotOnly` keeps rotations only. Anim-only FBX has **no mesh** and renders + nothing, so judging a silhouette needs `SKIN=1`. And do NOT preview by retargeting onto + `Hum_M_1_mixamo.fbx`: its armature carries FBX's 0.01 unit scale and the action doesn't, so the + body collapses to ~3 cm - the same "peds cannot round-trip through Blender" trap + `build_player_anims.py` already documents. I hit all four of those in order. + selftest **335/0/0**, unchanged - I added no asset and touched no shipped file. diff --git a/tools/character/windclip_candidates/README.md b/tools/character/windclip_candidates/README.md new file mode 100644 index 0000000..498f081 --- /dev/null +++ b/tools/character/windclip_candidates/README.md @@ -0,0 +1,82 @@ +# Wind clips โ€” the Mixamo candidates, and why they're rejected + +Lane E, Sprint 13 gate 2.4 ("wind clips for the player โ€” lean / stagger / brace, +staged by wind band, through the Mixamo pipeline"). + +**Outcome: no clip shipped. The Mixamo pipeline cannot supply a wind lean, and the +lean was never going to be a clip in the first place.** Both halves of that are +measured, and the evidence is in this folder. Full argument in THREADS [E] 2026-07-17/18. + +## 1. Mixamo has no wind animations + +Searched the real API (`fetch.cjs search`, on ultra), not assumed: + +| term | what comes back | +|---|---| +| `brace` | eleven **Braced Hang** ledge-climbing clips | +| `wind` | Standing Idle 04, Catwalk Walk Turn 180 | +| `shiver` | nothing, 0 results | +| `stagger` | three walks (Swagger Walk, Walking, Walking) | +| `lean` | Leaning On A Wall, Leaning, One Shoulder Lean | +| `push` | Pushing, Push Up, Button Pushing | + +The factory's own header already recorded half of this in Sprint 3 โ€” *"Hammering / +Sweeping Floor / **Bracing** don't exist on Mixamo โ€” skipped."* This is the case +the asset-pipeline skill names directly: *truly bespoke clips don't exist on +Mixamo โ€” hand-author, don't keep searching.* + +## 2. The two real candidates, rendered and rejected + +`skinshot.py` films a skinned Mixamo FBX twice: **as authored**, and **as the game +shows it** (Hips rotation cleared, which is what `player.js:_rotOnly` does at load). +The second row is the honest one. + +- **`rejected_Pushing.png`** โ€” not a wind lean. A deep squat shoving something heavy + along the ground, standing up at the end. It reads as *moving a couch*. The + forward angle I hoped to borrow is a squat, not a lean. +- **`rejected_Leaning.png`** โ€” a casual weight-on-the-back-foot lean, the "propped + against a bar" pose. Hands slack, no tension, near-identical across all five + frames. A person waiting for a bus, not one in a gale. + +Neither is close enough to fix by retiming. Shipping either would have passed every +check we have โ€” they load, they're metre-scale, their nodes survive โ€” and been wrong +on screen. That's the bike rule: **the verify can't answer "is this the right shape."** + +## 3. The useful technical result + +In both strips the raw and stripped rows are **near-identical**, which is worth +knowing: these clips carry their lean in the **spine**, and spine rotation survives +`_rotOnly` intact. So a hand-authored posture (spine curl, shoulder hunch, arm up) +*would* survive the loader. What cannot survive is a lean authored into the **hips** โ€” +`_rotOnly` drops `Hips.quaternion` from every clip (`player.js:53`, applied `:239`). +Measured on the shipped pack: 17 clips, 195 channels each, **64 survive**. + +Which is why the lean belongs in `player.sim.js` as a root pitch aimed at +`wind.dirAt(t)` โ€” the wind's bearing swings (the change; site_02's venturi) and a +canned clip has one fixed lean axis. Same trick as the knockdown and `climbY`. + +## Reproducing + +```sh +# on ultra (the FBX libraries and the Mixamo login live there; JING5 has neither) +mkdir -p /tmp/shadeswind && cd /tmp/shadeswind +cp ~/Documents/mixamo-fetch/fetch.cjs . +printf 'Pushing\nLeaning\n' > wishlist.txt +SKIN=1 node fetch.cjs "X Bot" # SKIN=1: needs a mesh to judge a silhouette +/Applications/Blender.app/Contents/MacOS/Blender -b --factory-startup \ + -P skinshot.py -- /tmp/shadeswind/out/Pushing.fbx Pushing +``` + +Notes for whoever next reaches for this pipeline: +- `fetch.cjs` reads its token from a **logged-in Brave on ultra via CDP** (port 9222). + Nobody types a password; the session is already there. It 429s after a handful of + exports โ€” space them out. +- `resolveChar` defaults to `Grandma_mixamo`, which is not currently uploaded to the + account. **`X Bot`** is a Mixamo stock rig and works; for anim-only export the source + rig is irrelevant anyway, since `_rotOnly` keeps rotations only. +- Anim-only FBX (`SKIN` unset) has **no mesh** and renders nothing. Judging a + silhouette needs `SKIN=1`. +- Don't retarget onto `Hum_M_1_mixamo.fbx` to preview: its armature carries FBX's + 0.01 unit scale and the clip's action doesn't, so the body collapses to ~3 cm. + That's the same "peds cannot round-trip through Blender" trap `build_player_anims.py` + documents. diff --git a/tools/character/windclip_candidates/rejected_Leaning.png b/tools/character/windclip_candidates/rejected_Leaning.png new file mode 100644 index 0000000..454dddd Binary files /dev/null and b/tools/character/windclip_candidates/rejected_Leaning.png differ diff --git a/tools/character/windclip_candidates/rejected_Pushing.png b/tools/character/windclip_candidates/rejected_Pushing.png new file mode 100644 index 0000000..d69f56c Binary files /dev/null and b/tools/character/windclip_candidates/rejected_Pushing.png differ diff --git a/tools/character/windclip_candidates/skinshot.py b/tools/character/windclip_candidates/skinshot.py new file mode 100644 index 0000000..ba825cc --- /dev/null +++ b/tools/character/windclip_candidates/skinshot.py @@ -0,0 +1,84 @@ +"""Filmstrip a SKINNED Mixamo FBX, twice: as-authored, and as the game shows it +(Hips rotation cleared โ€” player.js:_rotOnly). + + blender -b --factory-startup -P skinshot.py --