# Animation Naming Conventions **Decision (Ozan, 2026-07-24): do NOT mass-rename existing animations.** Renaming clip strings inside purchased vendor packs (Quaternius UAL, Kevin Iglesias) breaks the vendor re-download/upgrade path, forces a risky full-pack re-export through Blender, and buys only cosmetic consistency. Instead: **document the conventions that already exist, keep each source's native names, and name new files to conform going forward.** Provenance and status are tracked in the registry catalogue, not by renaming. This file is the source of truth for *how animations are named*. `.agents/wiki/dances/REGISTRY.md` remains the source of truth for the dance/boat clip roster. --- ## 1. The three name-spaces Animation naming spans three independent layers. They are joined by explicit mappings, not by making the strings equal. **You almost never need them to match.** | Layer | What it is | Case style | Example | Who reads it | |---|---|---|---|---| | **Pack file** | the `.glb` basename on disk | lowercase snake_case | `kevin_male_movement.glb`, `UAL1.glb`, `war_dance_01.glb` | filesystem, `ClipCatalog` (discovers by basename) | | **Clip name** | the animation string baked inside the GLB | *source-dependent* (see §3) | `Swim01_Forward`, `TreeChopping_Loop`, `WarDance01` | GLB metadata, dance JSON `clip` field, `SetupAnimations()` mapping | | **Game key** | the logical id the game code plays | lowercase snake_case | `swim`, `chop`, `war_dance_01` | `PlayerAnimController`, `PlayerAnimationLogic`, `AnimationTree`, AI, dance JSON `name` | **Key fact:** the game controller speaks *only game keys* — it never references a raw clip name. The single place the clip-name layer meets the game-key layer is the mapping arrays in `ariki-game/src/Viewer/PlayerController.cs → SetupAnimations()` (`clip name → game key`). That indirection is why we can keep vendor clip names untouched: the game key is our stable API, the vendor clip name is just what that key happens to bind to. --- ## 2. Game keys — the one namespace we fully own Game keys are the cleanest, most important naming layer, because they are the game's actual vocabulary and we control them 100%. **Rules:** - **lowercase snake_case**, matching the game's item-id convention (`ceremonial_garb`, `dance_platform`). - **Semantic, not source-derived.** Name the *action*, never the vendor clip it currently points at: `chop`, not `treechopping`. If we later swap the underlying clip, the key is stable. - **Directional suffixes** use short forms: `_fwd`, `_bwd`, `_l`, `_r`, and diagonals `_fwd_l`, `_fwd_r`, `_bwd_l`, `_bwd_r`. - **State suffixes:** `_idle`, `_enter`, `_exit`, `_start`, `_land`. - Examples in use: `idle`, `walk`, `run`, `sprint`, `crouch_idle`, `crouch_walk`, `swim`, `swim_idle`, `swim_up`, `swim_down`, `swim_strafe_left`, `chop`, `mine`, `fish`, `gathering`, `farm`, `carry`, `eat`, `sleep`, `skin`, `pray`, `weapon_attack`, `shield_block`, `turn90_l`. When you wire a new animation, **the game key is what you invent** — pick a semantic snake_case key and add the `clip → key` row in `SetupAnimations()`. The clip name stays whatever the source produced. --- ## 3. Current clip-name conventions, by source We keep each source's native convention. Recognise them; don't fight them. ### 3a. Quaternius UAL (`anim/UAL1.glb`, `anim/UAL2.glb`) — VENDOR, keep as-is - **PascalCase, `_`-separated.** `Climb_Idle_Loop`, `Jog_Fwd_Loop`, `TreeChopping_Loop`. - Looping clips end **`_Loop`** (or `_Idle_Loop`). - Directions: **`_Fwd` / `_Bwd` / `_Left` / `_Right`**; diagonals **`_Fwd_L` / `_Fwd_R` / `_Bwd_L` / `_Bwd_R`**. - Transitions: **`_Enter` / `_Exit`**; jumps **`_Start` / `_Land`**; variants numbered **`01`, `02`**. - Root-motion twins carry **`_RM`** (in the `*_RM.glb` packs; game loads non-RM only). ### 3b. Kevin Iglesias (`kevin/kevin_{male,female}_*.glb`) — VENDOR, keep as-is - **PascalCase, action + zero-padded number, then full-word direction.** `Walk01_ForwardLeft`, `Swim01_Forward`, `Crouch01_Walk_BackwardRight`. - Looping clips end **`_Loop`**; handedness uses **`_L` / `_R`** (`SkinningGround01_R_Loop`, `ThrowSpear02_R`); root-motion uses a trailing **`RM`** (`Walk01_ForwardRM`). - Packs are split by theme: `combat`, `movement`, `work`, `social`, `idles`, `misc`. ### 3c. Our authored clips — the convention WE apply to new content This is the part you actively control. Two sub-cases: **Dances & boat actions** — follow `.agents/wiki/dances/REGISTRY.md` exactly: - New dance take → **provisional** id `nd_##` (never a content-guessed name): pack/file `nd_08`, clip `ND08`, dance JSON `nd_08.json`. Variants keep the base id + suffix: `nd_08_pp` / `ND08PP`. - On **adoption** to a ceremony → dance code = snake_case of the sim `DanceType` enum + index: pack `war_dance_01`, clip **`WarDance01`** (PascalCase, matches the enum), JSON `war_dance_01.json`. - **Loop-pair rule:** every adopted dance ships base + ping-pong `_pp` variant (`war_dance_01_pp` / `WarDance01PP`), baked with `tools/pingpong_bake.py`, must pass `loop_qc.py`. - Boat actions get direct `boat_*` codes (no provisional stage): `boat_dive`, `boat_row_loop`, clip `BoatDive` / `BoatRowLoop`. **Other authored one-offs (Mixamo, iClone mocap, composites):** - Pack file = **lowercase snake_case**: `run_to_dive.glb`, `northern_soul.glb`, `Run_Punch.glb`. - Clip name = **PascalCase of the file**: `RunToDive`, `NorthernSoulFloorCombo`, `Run_Punch`. - Game key = **semantic snake_case**: `run_to_dive`, `dance_soul`, `run_punch`. ### The general rule for a NEW authored clip ``` pack file: __<##>.glb (lowercase snake_case) e.g. work_haul_01.glb clip name: PascalCase of the file e.g. WorkHaul01 game key: e.g. haul ``` Categories (closed set): `loco`, `swim`, `work`, `combat`, `dance`, `boat`, `emote`, `misc`. Variants numbered, **never reused**. Looping authored clips ship a `_pp` (or `_loop`) variant that passes `loop_qc.py`. --- ## 4. Suffix & direction quick-reference | Meaning | Game key (ours) | UAL (vendor) | Kevin (vendor) | |---|---|---|---| | looping | `_idle` / (implicit) | `_Loop` | `_Loop` | | forward / back | `_fwd` / `_bwd` | `_Fwd` / `_Bwd` | `_Forward` / `_Backward` | | left / right | `_l` / `_r` | `_Left` / `_Right` | `_Left` / `_Right` | | diagonal | `_fwd_l` … | `_Fwd_L` … | `_ForwardLeft` … | | transition | `_enter` / `_exit` | `_Enter` / `_Exit` | — | | ping-pong loop | `_pp` | — | — | | root motion | (not loaded) | `_RM` | `RM` | | variant index | `_01` | `01` | `01` | --- ## 5. Decision tree — naming a future file 1. **Is it a vendor clip (UAL/Kevin/other purchased pack)?** → Keep the vendor's clip name and pack layout untouched. To use it, add a `clip → game key` row in `SetupAnimations()` and a catalogue entry in the registry. Do **not** re-export or rename. 2. **Is it a dance or boat action?** → Follow `.agents/wiki/dances/REGISTRY.md` (`nd_##` → ceremony code; boat `boat_*`; loop-pair rule). 3. **Is it another clip we author (Mixamo/iClone/composite)?** → Apply the §3c general rule: snake_case file, PascalCase clip, semantic snake_case game key, closed-set category, `_pp` loop. 4. **In all cases:** add/update the registry row (§6) in the same commit, and — if the game plays it — the `SetupAnimations()` mapping. --- ## 6. The registry catalogue (provenance & status — no renaming) The catalogue records, per clip we care about, the fields Jeremy asked for — **without changing any names**: `canonical_id` (our snake_case handle) · `clip` (actual name in GLB, vendor or ours) · `pack` · `category` · `game_keys` · `source` · `created` · `method` · `status` (`approved` / `wip` / `not_started`) · `notes`. - For vendor clips, `canonical_id` is just our stable handle for the catalogue; `clip` stays the vendor string. Nothing on disk changes. - `not_started` rows capture animations the game *needs but doesn't have yet* (the 13 dance ceremony slots, the 6 boat actions awaiting takes, any gap from the removals audit). - Kept machine-readable (YAML/JSON) with a generated Markdown view; see the audit doc for the build plan. This is the deliverable that survives Ozan's no-rename decision. --- ## 7. Maintenance - Every convert / adopt / archive **updates the registry row in the same commit** — the rule already in `.agents/wiki/dances/REGISTRY.md`, generalized to all categories. - **Archive, never delete; numbers never reused.** Rejected/superseded takes move to `archive/` (this repo) and `archive/dances/` (ariki-game), keeping their names. - Sync via `tinqs push` / `tinqs pull` (raw git pull hangs on LFS). Report commit hashes. --- ## 8. Why this shape (rationale, for future readers) The game controller is decoupled from asset names by the game-key layer, so the *valuable* outcomes — provenance, status, a "what do we still need" list, and a stable controller vocabulary — come from the **registry + game-key discipline**, not from mutating vendor clip strings. Renaming purchased packs would cost a full-pack Blender re-export (risking rig-pose drift, caught only by `rig_pose_gate.py`), permanent vendor-upgrade friction, and LFS bloat, for cosmetic gain. Hence: document the conventions, name new files to fit, catalogue everything, rename nothing that already ships.