--- name: animation-creation description: Create new skeletal animations for ariki-game on the shared Quaternius skeleton — retarget Mixamo/Kevin-Iglesias FBX to game-ready GLB packs, bake composite clips (upper body of one clip over lower body of another), and author dance sequences as hot-reload JSON. Use when the user wants a new animation, dance, or move that doesn't exist in the shipped packs. --- # Animation Creation (ariki-game) Every animation in the game runs on the **one shared Quaternius skeleton** (65 bones, UE names: `pelvis`, `spine_01..03`, `Head` capital-H, `thigh_l`, ...). Creating an animation means getting motion onto that skeleton. Four proven paths, cheapest first. ## Path 1 — It probably already exists (~810 clips) Check before creating. Packs: `assets/quaternius/kevin/*.glb` (12 packs, male+female × combat/idles/misc/movement/social/work — social has `Dance01`–`Dance18`, `DancePose01_Loop`–`07` with `_Begin`/`_Stop`, claps, waves, cheers), UAL1/UAL2 standard libraries, `assets/quaternius/mixamo/*.glb`. List a pack's clips: ```bash # clip names live in the GLB's JSON chunk node -e "const b=require('fs').readFileSync('assets/quaternius/kevin/kevin_male_social.glb');const len=b.readUInt32LE(12);const j=JSON.parse(b.slice(20,20+len));console.log(j.animations.map(a=>a.name).join('\n'))" ``` ## Path 2 — Retarget a Mixamo FBX (new motion from Mixamo's huge library) Download FBX(s) from mixamo.com (any character, "Without Skin" is fine), then: ```bash /Applications/Blender.app/Contents/MacOS/Blender --background \ --python tools/mixamo_retarget.py -- \ --src "[,...]" --out assets/quaternius/mixamo/.glb ``` - World-rotation-delta method; handles `mixamorig:` prefix variants automatically. - Proven end-to-end: `northern_soul.glb`, `run_to_dive.glb`. - Output GLBs in `assets/quaternius/mixamo/` are auto-discovered by ClipCatalog / AnimationShowcase — referenceable immediately as `/`. - Kevin Iglesias FBX sources use the sibling `tools/kevin_retarget.py` (different rig root handling — Kevin has a demo-scene offset bone). ## Path 3 — Composite clips (new move from two existing clips, no Blender) The dance system bakes "upper body of clip A over lower body of clip B" at load time. Author it as a move in `assets/dances/*.json` — hot-reloads in ~0.5s while the dance test bed runs: ```json { "layers": [ { "mask": "upper", "clip": "kevin_male_social/HandClap01" }, { "mask": "lower", "clip": "kevin_male_movement/Crouch01_Walk_Forward" } ], "duration": 4.0 } ``` - Masks: `lower` = `root|pelvis|thigh*|calf*|foot*|ball*` (owns hip position AND rotation — always); `upper` = everything else. Authoritative predicate: `tools/bake_run_punch.mjs`. - For a composite needed **outside** the dance system, pre-bake a merged pack with a `bake_run_punch.mjs`-style node script instead (same mask logic, writes a GLB). ## Path 4 — Dance sequences (choreography = ordered moves + BPM) A full "animation" at the choreography level is a JSON file in `assets/dances/`: `{ "name", "bpm", "moves": [ {"clip": "pack/Clip", "loops": 2}, {composite...} ] }`. Move transitions quantize to the beat clock. View in the test bed: `SCENE=dance_test_bed bash tools/game.sh spawn` (ASK Jeremy before launching the game). See `.agents/plans/dance-test-bed-2026-07-13.md` for full format + class specs. ## Path 5 — Author in live Blender (blender-mcp) For motion that exists nowhere and can't be composited from existing clips — hand-keyed poses, IK-assisted tweaks, NLA layering of retargeted clips. Prerequisites: Blender 5.1.2 open with the BlenderMCP addon connected (sidebar → BlenderMCP → Connect) and the `blender` MCP server registered in `.mcp.json`. Workflow: import an existing game GLB to pull in the real Quaternius armature → author (keyframes, IK, NLA) → export GLB into `assets/quaternius/mixamo/` so ClipCatalog auto-discovers it as `/`. Recipes: `references/blender-mcp-recipes.md`. ## GLB surgery without Blender (gltf-transform) Inspect clip names, transplant or merge clips between same-skeleton GLBs, and resample/prune/dedup to shrink packs — no Blender required. Runs via `npx @gltf-transform/cli`, or as a JS SDK from a node script like the existing `tools/bake_run_punch.mjs`. Complements Path 3's node-script compositing when the job is a clip move or pack merge, not new motion. Recipes: `references/gltf-transform-recipes.md`. ## Hard rules (violations = invisible or broken animation) - **Never use `*RM` root-motion clip variants** in dances/composites — they translate the rig. - **Skeleton path remap is mandatory** when playing raw GLB clips on a game rig: GLB tracks target `Armature/Skeleton3D:bone`; derive the rig's real prefix from an already-remapped clip (`ap.GetAnimation("idle").TrackGetPath(0)`), remap once, share. - Clip name fallback: exact → `+"_Loop"` → `-"_Loop"` (Godot import sometimes strips it). - Skip `RESET` clips; set `LoopMode.Linear` on extracted clips. - `.uid` files auto-generate — never hand-author. ## Verify what you created - Single clips / packs: `scenes/animation_showcase.tscn` pages through every shipped clip. - Dances / composites: dance test bed; `VideoRecorder` (in-scene) records the viewport to `~/Downloads/*.mp4` for review — feed that to the `pose-estimation` skill to score a recreation against source footage (crop-zoom one dancer first; wide shots don't detect). ## Path 6 — Generate from video (pose-driven mocap, BUILT 2026-07-13) `tools/mocap_retarget.py` turns `pose-estimation` skill output (extract_pose.py JSON, world landmarks) into a GLB clip on the Quaternius skeleton: ```bash /Applications/Blender.app/Contents/MacOS/Blender --background \ --python tools/mocap_retarget.py -- \ --pose --out assets/quaternius/mixamo/.glb --name \ --range 166:192 --smooth 5 --render-check /tmp/check # renders frames to eyeball ``` - Limb bones: shortest-arc aim from rest direction (preserves rest roll); pelvis/spine: full-basis deltas conjugated through char-frame alignment (same convention as mixamo_retarget.py — landmark space is subject-left=+X, up=+Z, facing=-Y, NOT identity). - MediaPipe world landmarks are hip-centered → no root motion; pelvis height is reconstructed from pelvis-above-ankle extent vs standing (carries squats). - Known v1 limits: no twist control, no fingers, no horizontal root motion. - Proven: `haka_mocap.glb` / `HakaFull` (26s, 208 keys) generated from a YouTube haka tutorial via `~/.claude/skills/pose-estimation`. Full pipeline context: `.agents/plans/animation-gen-pipeline-2026-07-13.md`.