# Hand poses — pre-ship staging for ariki-game Canonical hand-pose library. Poses live here first; when a pose is adopted for the game it is **copied** to `ariki-game/assets/quaternius/hand-poses/` (keep the two byte-identical — the runtime `HandPoseLayer` reads the game copy). ## Format `{"bones": {"": [x, y, z, w], ...}}` — glTF node-local quaternions on the **canonical Quaternius skeleton**, which is exactly Godot bone-pose space for these bodies. 40 bones per pose, including `*_04_leaf_*` tip bones. Some bodies lack the leaf bones — **skip bones `FindBone` returns -1 for**, never error. **Apply REST-RELATIVE, not directly** (runtime does this as of 2026-08-18): ```csharp // delta = canonicalRest^-1 * pose; target = thisBodysRest * delta var target = boneRest * (canonRest.Inverse() * pose); skeleton.SetBonePoseRotation(idx, target); ``` `canonical_rest.json` (regenerate with `tools/make_canonical_rest.py`) holds the canonical finger rests this correction needs. On a rig whose finger rest matches canonical the correction is algebraically a no-op, so nothing changes for the Quaternius/QuatSkin bodies. On one that deviates it is the only correct form — Mako's `*_01` knuckles sit **11.5°** off canonical, and writing poses straight in wrenched them away from his own rest and tore the palm/wrist boundary. ## Poses | File | Source (Kevin packs) | Runtime status | |---|---|---| | `pose_flat.json` | **= canonical REST** (see below) | **SHIPPED** — verified in-engine on Mako 2026-08-18 | | `pose_relaxed.json` | `HandWave01` f0 (~10° off rest) | staged | | `pose_fist.json` | `AttackPunch01_R/L` f7, merged (~61° off rest) | blocked on finger-weight repair (shreds on exp01–exp05 and on Mako) | | `pose_grip.json` | `CombatIdle1H01` f0, both hands (~44° off rest) | blocked, same repair | ### `pose_flat` is the REST pose — and that is why it is useful Measured 2026-08-18: `pose_flat.json` matches `kevin_female_combat.glb`'s finger rests to **0.04°** — it is the canonical rest pose, not a separately harvested "flat hand". Do not expect it to straighten a hand that is already at rest. It is still the load-bearing pose, because **the shipped clips do not hold fingers at rest** — they pin them in a permanent curl (frozen tracks, spread 0.0°). `UAL1 Idle_Loop` holds the fingers **53.9° off rest on average, up to 86.8°** (`thumb_03_r`) — near a clench. So the FLAT layer's real job is to undo that baked-in curl. On Mako that curl is what shreds his hands. It does not fling verts (max displacement only 23.3 cm, i.e. legitimate fingertip travel) — it **tears**: 2,258 edges stretched >5×, max 198×, which rips his fused hand open into sheets. Turning FLAT on removes the bulk of it. Evidence (in-engine, the only honest judge here): `characters/work/mako/handfix/review/ingame_handcam_flat_{OFF,ON}.png` and the `ingame_mako_{left,right}_hand_flat_ON_zoom.png` crops. **Residual:** at close range his RIGHT hand still shows a torn patch with FLAT on — his right hand owns far less finger geometry than his left (4,283 verts vs 10,532; `middle_02_r` owns just 157), so it is not fully fixed. FLAT only holds the FINGER bones at rest; `hand_l/r` still follow the clip. ## Verification (before shipping a pose) - `tools/handpose_bake_preview.py body.glb pose.json out.glb` — bake into rest rotations. - `tools/skin_displacement_check.py posed.glb original.glb` — Godot-exact LBS travel; cm-scale = sane, m-scale = broken. **Blind to fin tearing** — pair it with the edge-stretch check (`tools/edge_stretch.py`). - `tools/handpose_skin_to_obj.py` + `tools/handpose_render_objs.py` — clay render. Never judge by importing a baked-pose GLB into Blender (false shards). Pass an ABSOLUTE outdir (a relative one silently writes nothing), name inputs `_hand_.obj` (the glob requires it), and crop to the hand with `tools/obj_crop.py` or the arm dominates the frame. - `tools/skin_lever_audit.py body.glb` — finds bindings whose joint is implausibly far away in rest, and verts bound across the midline to the opposite hand. **Invisible at rest**, so nothing else catches them: this is what found Mako's 444 cross-hand verts. - `tools/skin_crosshand_repair.py in.glb out.glb` — repairs those by inpainting from the mesh's own healthy neighbours (`--diagnose` to preview). - `tools/hand_bone_ownership.py body.glb [l|r]` — which finger bones actually own geometry. Run it before trusting a pose on a new body: Mako is a **two-finger rig**, so only his thumb and middle chains own verts and index/ring/pinky own nothing. - `tools/rest_deviation.py canonical.glb other.glb` — per-bone finger rest deviation, i.e. whether a body needs the rest-relative correction. **Ratio alone is not the tearing gate.** `edge_stretch.py` reports huge ratios on this mesh's sub-millimetre sliver edges (unwelded duplicates) — judge the **absolute posed length**. On Mako, flat's worst stretched edge reaches ~1–2.4 cm (benign, sub-pixel in engine) while fist/grip reach 10–15 cm (real, visible needles).