diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..3b5cfc2 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,112 @@ +# AGENTS.md — animation repo + +Guidance for AI agents working in `local.repo/animation`. This repo is Jeremy's +animation-pipeline hub **and** the Mac↔PC bridge that carries iClone exports into +`ariki-game`. iClone 8 + Video Mocap live on the PC; Blender 5, the retarget tools, +and the game repo live on both machines. + +Deeper knowledge lives in the repo skills (`.claude/skills/`): use **`animation`** +for the operator's playbook and hard-won lessons, **`animation-creation`** for +authoring new clips, **`iclone-video-mocap`** for iClone-side "how do I X", and +**`pose-estimation`** for video→pose extraction. `docs/dances/REGISTRY.md` is the +source of truth for clip names. This file is the fast orientation; the skills and +registry are authoritative. + +## The batch workflow ("process the incoming animations") + +1. **Pull first** — `tinqs pull` (raw `git pull` hangs on LFS in tinqs.com repos). + Incoming FBX + textures + JSON land in `exchange/incoming-fbx/`. +2. **Retarget each FBX** → GLB in `exchange/converted-glb/` (command below). + Every dance ships as a **pair**: also bake its loop variant with + `tools/pingpong_bake.py` → `exchange/pingpong-glb/_pp.glb` (clip `PP`). +3. **Commit + push the GLBs in this repo** with `tinqs push` (self-heals auth, + uploads LFS direct-to-S3). Report the commit hash. +4. **Copy GLBs into ariki-game** `assets/quaternius/dancegen/`, write one dance + JSON per clip in `ariki-game/assets/dances/`. +5. **Loop QC gate** — run `loop_qc.py` on each GLB; flag anything not smooth + *before* it ships. +6. **Import** so Godot generates sidecars: `bash tools/game.sh import` (ariki root). +7. **Verify** clip names, then commit in ariki-game. +8. **Launch the test bed only after asking Jeremy.** +9. Leave `exchange/` cleanup until Jeremy confirms the batch looks right in-game. + +### Canonical retarget command +```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 is **5.1.2**. `--target` is **required** when running from this repo (the +tool's default target path is ariki-relative and won't resolve here). Other +retargeters: `mixamo_retarget.py` (Mixamo), `kevin_retarget.py` (Kevin Iglesias +`B-*` rig, hardcoded target), `mocap_retarget.py` (MediaPipe pose JSON). + +## Naming (see `docs/dances/REGISTRY.md`) + +Lowercase snake_case, matching the game's item-id convention. **New takes get a +provisional `nd_##` id, never a content name** — pack `nd_08`, clip `ND08`, JSON +`nd_08.json`, variants `nd_08_pp` / `ND08PP`. Only when Jeremy **adopts** a take +for a ceremony is it renamed to its dance code (snake_case of the sim's `DanceType` +enum + index, e.g. `war_dance_01` / `WarDance01`). Never guess the ceremony — +Jeremy assigns it. Rename via `tools/rename_clip.py` + JSON + registry update. +Rejected takes are **archived, never deleted**; numbers are never reused. Update +the registry row on every convert/adopt/archive. + +- Pack name = GLB basename (lowercase); clip name = `--name` baked into the GLB. +- Clip ref in JSON = `/` (e.g. `nd08/ND08`). +- ClipCatalog auto-discovers anything in `dancegen/` (also `kevin/`, `mixamo/`) — + no code change needed. + +## Loop QC + +The game loops with Godot `LoopMode.Linear` (last keyframe → frame 0). A clip only +looks right if pose, motion velocity, and root position are continuous across the +seam — raw takes rarely are. QC every clip: +```bash +/Applications/Blender.app/Contents/MacOS/Blender --background --python tools/loop_qc.py -- \ + --src exchange/converted-glb/.glb # exit 0 = SMOOTH, 1 = NOT SMOOTH, 2 = error +``` +Fixers (no iClone round-trip): `tools/loop_fix.py` (de-drift + trim + seam blend → +`exchange/looped-glb/`) and `tools/pingpong_bake.py` (palindrome bake, seam-perfect +but motion reverses at the turn — prefer for sway-heavy dances). Re-run `loop_qc.py` +to confirm exit 0. Or use the `loop-qc` agent. + +## Gotchas that have actually bitten + +- **2-frame `_TempMotion` FBX = no motion.** The tool rejects by frame count, not + name; that's the guard working. Re-export from iClone with Include/Export Motion. +- **A-pose arms.** CC/iClone bind in A-pose. Eyeball arm orientation in the test + bed on the first clip of any new source; re-export with *Use T-Pose As Bind Pose* + if wrong. +- **Verify GLB `animations[].name` == JSON clip ref** before shipping — a mismatch + is a silent no-play. +- **Commit the `.glb.import` sidecar with the GLB** (Godot embeds `uid://` there; + no separate `.uid`). GLB + `.import` + JSON go together. +- **`game.sh import` warnings are pre-existing noise** — only `errors` matter. +- **Green verify ≠ correct.** An agent-authored gate once passed an upside-down + boat export. Always render and eyeball a new visual asset before shipping. + +## Repo etiquette + +- **Don't touch unrelated uncommitted work.** ariki-game often has in-flight files; + stage only this batch's files **by explicit path**, never `git add -A`. +- Use **`tinqs push` / `tinqs pull`**, not raw git — this repo uses Git LFS for + `.fbx/.glb/.mp4/.task`. Report the commit hash after pushing. +- Commit co-author line: `Co-Authored-By: Claude Fable 5 `. +- **ariki-game commits stay local until Jeremy asks to push** — pushing the game + repo is not part of the bridge steps. +- **Ask before launching the game.** `SCENE=dance_test_bed bash tools/game.sh spawn` + (from ariki root); `animation_showcase` pages every clip. Never use `*RM` / + `*RootMotion` variants — everything is in-place. If you pipe spawn through `tail`, + the log stays 0 bytes until exit — confirm via the lease file + `pgrep`, don't + assume it failed. + +## Layout + +- `.claude/skills/` — repo skills (see intro); `.claude/agents/loop-qc.md`. +- `tools/` — Blender-headless retargeters, loop tools, prop export, `rename_clip.py`. +- `exchange/` — files in flight: `incoming-fbx/`, `converted-glb/`, `looped-glb/`, + `pingpong-glb/`, `outgoing-props/`, `reference-video/`, `INBOX/`. +- `docs/` — `dances/REGISTRY.md`, `iclone-bridge.md`. +- `plans/` — pipeline design docs. `archive/` — retired takes. `devops-reports/`.