Files
animation/.claude/skills/animation/SKILL.md
T
jeremy 854dbb5ce4 chore(agents): migrate to agents.md protocol — .agents/ wiki/plans/rules/skills
Root AGENTS.md is now a thin entry point + knowledge map; the batch-workflow
detail it duplicated already lived in .claude/skills/animation/SKILL.md.
Folded docs/ (dances registry + iclone-bridge stub), root plans/, and
devops-reports/ into .agents/wiki/ and .agents/plans/ per the per-repo .agents/
convention. Added .agents/SOUL.md, .agents/AGENTS.md, wiki/ARCHITECTURE.md,
wiki/architecture/, and wiki/master-plan.md (derived from the closed plans +
the dance registry's live ceremony-slot table). Fixed doc-path references in
exchange/GUIDE.md, the animation skill, and the iclone-bridge stub. All moves
via mv (git detected as renames) — no content deleted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 15:02:47 -07:00

9.6 KiB
Raw Blame History

name, description
name description
animation Jeremy's working preferences and hard-won lessons for the animation pipeline in this repo — the Mac↔PC bridge, retargeting iClone/CC FBX to Quaternius GLB, wiring clips into ariki-game as dances, launching the dance test bed, and the gotchas that bite each step. Use when processing incoming animations through the pipeline, or when deciding how to commit/verify/launch anything in this repo or ariki-game.

Animation pipeline — preferences & lessons

This is the operator's playbook for this repo (local.repo/animation), the Mac↔PC bridge that carries iClone exports into ariki-game. For iClone-side "how do I do X" questions use iclone-video-mocap; for authoring new clips use animation-creation. This skill is the accumulated do-it-this-way knowledge from real runs.

The batch workflow (what "process the incoming animations" means)

  1. Pull first. git pull (or tinqs pull) — incoming FBX + textures + JSON land in exchange/incoming-fbx/.
  2. Retarget each FBX with the exact command below → GLB in exchange/converted-glb/. Every dance ships as a pair: also bake its loop variant with tools/pingpong_bake.pyexchange/pingpong-glb/<id>_pp.glb (clip <Clip>PP).
  3. Commit + push the GLBs in this repo (use tinqs push, not raw git push — it self-heals auth and uploads LFS direct-to-S3).
  4. Copy GLBs into ariki-game assets/quaternius/dancegen/, write a dance JSON per clip.
  5. Loop QC gate — run loop_qc.py on each converted GLB (see below). Flag anything that isn't smooth before it ships.
  6. Import so Godot generates sidecars: bash tools/game.sh import (from ariki-game root).
  7. Verify clip names, then commit in ariki-game.
  8. Launch the test bed only after asking (see below).
  9. Leave exchange/ cleanup until Jeremy confirms the batch looks right in-game.

The retarget command (canonical)

/Applications/Blender.app/Contents/MacOS/Blender --background --python tools/cc_retarget.py -- \
  --src exchange/incoming-fbx/<take>.fbx \
  --out exchange/converted-glb/<pack>.glb --name <ClipName> \
  --target "/Users/jeremykashkett/Tinqs/local.repo/ariki-game/assets/quaternius/base-characters/Universal Base Characters[Standard]/Base Characters/Godot - UE/Superhero_Male_FullBody.gltf"

Blender here is 5.1.2. When running from this repo the --target is required — the tool's default target path is ariki-relative and won't resolve.

Naming system (registry: .agents/wiki/dances/REGISTRY.md — read it, it is the source of truth)

Two-stage names, following the game's item-id convention (lowercase snake_case). New dances get a provisional id, never a content name: at conversion, assign the next free nd_## from the registry — pack nd_08, clip ND08, JSON nd_08.json, variants nd_08_pp/ND08PP — regardless of what the PC export was called (a take named "firedance1" turned out to be dance1's choreography). Only when Jeremy adopts a take for a specific in-game dance ceremony is it renamed to its dance code — snake_case of the sim's DanceType enum + index: pack war_dance_01, clip WarDance01, variants war_dance_01_pp/WarDance01PP. The 13 ceremony slots are tabled in the registry. Rename via tools/rename_clip.py + JSON rename + registry update. Never guess the ceremony; Jeremy assigns it. Rejected takes are archived (archive/ here; archive/dances/ in ariki-game, which is .gdignored), never deleted. Numbers are never reused. Always update the registry row when converting/adopting/archiving.

Structural rules (unchanged):

  • Pack name = GLB basename (lowercase); clip name = --name baked into the GLB.
  • Clip ref in JSON = <pack>/<ClipName>: nd08/ND08.
  • ClipCatalog auto-discovers anything dropped in dancegen/ (also kevin/, mixamo/) — no code change needed.

Dance JSON (single-clip default)

{ "name": "aloha1", "bpm": 100, "moves": [ { "clip": "aloha1/Aloha1", "loops": 1 } ] }

Default bpm 100, loops 1 to match the sibling hakadance1. bpm only matters once moves are chained (it drives transition beat-quantization). Lives in ariki-game/assets/dances/*.json, hot-reloads in the test bed.

Gotchas that have actually bitten

  • 2-frame TempMotion = no motion. iClone names every take ..._TempMotion; the tool distinguishes by frame count, not name. A ~2-frame FBX was exported without motion and cc_retarget.py rejects it. Fix: re-export from iClone with Include Motion / Export Motion checked. (Real takes here are 1800f @60fps.) Don't treat the rejection as a tool bug — it's the guard working.
  • A-pose arm QA (open item). CC/iClone characters bind in A-pose, not T-pose. First exports through this pipeline can bake arms rotated. Eyeball arm orientation in the test bed on the first clip of any new source; if wrong, re-export with FBX Advanced > Use T-Pose As Bind Pose, or add a per-arm rest-alignment fix in cc_retarget.py.
  • Verify GLB animation name == JSON clip ref before shipping. Read the GLB's animations[].name (glTF JSON chunk) and confirm it equals <ClipName>. A mismatch = silent no-play.
  • Commit the .glb.import sidecar with the GLB. Godot embeds the uid:// inside the .import file — there is no separate .uid for GLBs. Commit GLB + .import + JSON together.
  • game.sh import shows scary warnings (tree impostors, meta drift, stale bakes, hair-texture case mismatch, missing res://src/polynesia/data) — those are pre-existing and unrelated. Only care about errors, not warnings.

Loop QC (clips are meant to loop — most raw takes don't)

The game loops clips with Godot LoopMode.Linear (wraps last keyframe → frame 0), so a clip only looks right if the pose, motion velocity, and root position are continuous across that seam. Raw iClone/mocap takes almost never satisfy this — they start from a held pose and end mid-motion, or the performer walks across the floor. QC every clip before shipping with the loop-qc agent, or directly:

/Applications/Blender.app/Contents/MacOS/Blender --background --python tools/loop_qc.py -- \
  --src exchange/converted-glb/<pack>.glb
# exit 0 = SMOOTH, 1 = NOT SMOOTH, 2 = error. Don't pipe through grep if you need the code.

Three metrics, three failure modes (the tool ranks the worst bones so you know where):

  • root drift high, pose gap low → performer travels; needs in-place authoring / trim back to origin.
  • pose gap high, velocity gap ~0 → starts & ends in different still holds; match end pose to start in iClone.
  • both high → starts held / ends mid-move; trim to a full cycle or blend the seam (Animation Layer weight ramp, or bracket clean keys — see iclone-video-mocap).

Two Blender-side fixers exist (no iClone round-trip needed):

  • tools/loop_fix.py — de-drift + trim to best natural loop point + motion-graph seam blend (crossfade toward the frames before the loop start). Keeps 6090% of the clip. Outputs to exchange/looped-glb/. See plans/loop-fix-plan-2026-07-16.md + results.
  • tools/pingpong_bake.py — palindrome bake (forward then reversed as ONE clip): end frame == start frame by construction, drift self-cancels, full choreography kept, but motion visibly reverses at the turn point. Outputs exchange/pingpong-glb/*_pp.glb, shipped as separate <pack>_pp packs. Prefer for sway-heavy dances (hula); judge per-dance for percussive ones (haka) where reverse playback can read as moonwalking. Both verified by re-running loop_qc.py to exit 0. iClone re-authoring remains the fallback for clips where neither result looks right in the test bed.

Outgoing props (game → iClone staging)

exchange/outgoing-props/ carries game assets exported as iClone staging props (the reverse direction of the bridge). tools/export_boat_prop.py builds the boat prop (hull at game scale + placeholder mast/sail/oar + seat markers + waterline + 1.9 m ref figure) with a self-verify gate incl. right-side-up checks — the FBX ships via git for the PC to pull. Boat ACTION clips use direct names (no nd_## stage): see the "Boat actions" table in the registry. Lesson from building it: an agent-authored verify gate can pass a visually-wrong export (the first boat was upside down with all checks green) — always render and eyeball a new prop before shipping, and encode what the eyeball caught as new asserts.

Launching the game

  • Always ask Jeremy before launching (this session he said "let's launch" — that's the go-ahead; don't assume it next time).
  • Command: SCENE=dance_test_bed bash tools/game.sh spawn from ariki-game/ root. Also animation_showcase for paging every clip.
  • Never use *RM / *RootMotion clip variants — everything is in-place.
  • Spawn-log buffering trap: if you pipe the spawn through | tail, the log file stays 0 bytes until the process exits — do NOT conclude the launch failed. Confirm it's actually up via the lease file (ariki-game/.game-cli/sessions/lease-<id>.json) and pgrep -fl tinqs.macos.editor. Closing the game window auto-stops that spawn's sim.

Repo etiquette

  • Don't touch unrelated uncommitted work. ariki-game often has in-flight files from prior sessions (e.g. hakadance1_static.*, local cc_retarget.py edits) — stage only this batch's files by explicit path, never git add -A.
  • Commit co-author line: Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>.
  • This repo uses Git LFS for .fbx/.glb/.mp4/.task; prefer tinqs push.
  • ariki-game commits are local until Jeremy asks to push — pushing the game repo is not part of the bridge steps.