docs: add AGENTS.md — agent orientation guide for the animation bridge

Fast-orientation guide synthesized from README.md and the animation skill:
batch workflow, canonical retarget command, nd_## naming, loop QC, gotchas,
and repo etiquette. Points to the skills and docs/dances/REGISTRY.md as
authoritative sources.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 13:20:27 -07:00
parent 078b0b7a07
commit 06d950649b
+112
View File
@@ -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/<id>_pp.glb` (clip `<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/<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 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 = `<pack>/<ClipName>` (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/<pack>.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 <noreply@anthropic.com>`.
- **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/`.