Files

170 lines
9.3 KiB
Markdown
Raw Permalink Normal View History

# 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: <category>_<descriptor>_<##>.glb (lowercase snake_case) e.g. work_haul_01.glb
clip name: PascalCase of the file e.g. WorkHaul01
game key: <semantic snake_case> 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.