diff --git a/.claude/skills/animation/SKILL.md b/.claude/skills/animation/SKILL.md new file mode 100644 index 0000000..cc3e48d --- /dev/null +++ b/.claude/skills/animation/SKILL.md @@ -0,0 +1,63 @@ +--- +name: animation +description: 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/`. +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. **Import** so Godot generates sidecars: `bash tools/game.sh import` (from ariki-game root). +6. **Verify** clip names, then commit in ariki-game. +7. **Launch the test bed only after asking** (see below). +8. Leave `exchange/` cleanup until Jeremy confirms the batch looks right in-game. + +### The retarget command (canonical) +```bash +/Applications/Blender.app/Contents/MacOS/Blender --background --python tools/cc_retarget.py -- \ + --src exchange/incoming-fbx/.fbx \ + --out exchange/converted-glb/.glb --name \ + --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 conventions (must be internally consistent) +- **Pack name = GLB basename** (lowercase): `aloha1`, `dance1`, `hakadance2`. +- **Clip name = `--name` = the animation name baked into the GLB** (PascalCase): `Aloha1`, `Dance1`, `HakaDance2`. +- **Clip ref in JSON = `/`**: `aloha1/Aloha1`. +- ClipCatalog auto-discovers anything dropped in `dancegen/` (also `kevin/`, `mixamo/`) — no code change needed. + +### Dance JSON (single-clip default) +```json +{ "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 ``. 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`. + +## 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-.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 `. +- 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.