170 lines
9.3 KiB
Markdown
170 lines
9.3 KiB
Markdown
|
|
# 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.
|