feat(qc): loop_qc tool + loop-qc agent — measure loop-seam smoothness
Pose gap / velocity gap / root drift at the LoopMode.Linear wrap; exit-code gated. Skill updated: loop QC is workflow step 5, with the Blender-side fixer playbook. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,10 +16,11 @@ This skill is the accumulated **do-it-this-way** knowledge from real runs.
|
||||
2. **Retarget each FBX** with the exact command below → GLB in `exchange/converted-glb/`.
|
||||
3. **Commit + push the GLBs** in *this* repo (use `tinqs push`, not raw `git push` — it self-heals auth and uploads LFS direct-to-S3).
|
||||
4. **Copy GLBs into ariki-game** `assets/quaternius/dancegen/`, write a dance JSON per clip.
|
||||
5. **Import** so Godot generates sidecars: `bash tools/game.sh import` (from ariki-game root).
|
||||
6. **Verify** clip names, then commit in ariki-game.
|
||||
7. **Launch the test bed only after asking** (see below).
|
||||
8. Leave `exchange/` cleanup until Jeremy confirms the batch looks right in-game.
|
||||
5. **Loop QC gate** — run `loop_qc.py` on each converted GLB (see below). Flag anything that isn't smooth *before* it ships.
|
||||
6. **Import** so Godot generates sidecars: `bash tools/game.sh import` (from ariki-game root).
|
||||
7. **Verify** clip names, then commit in ariki-game.
|
||||
8. **Launch the test bed only after asking** (see below).
|
||||
9. Leave `exchange/` cleanup until Jeremy confirms the batch looks right in-game.
|
||||
|
||||
### The retarget command (canonical)
|
||||
```bash
|
||||
@@ -50,6 +51,35 @@ Default **bpm 100, loops 1** to match the sibling `hakadance1`. bpm only matters
|
||||
- **Commit the `.glb.import` sidecar with the GLB.** Godot embeds the `uid://` inside the `.import` file — there is **no separate `.uid`** for GLBs. Commit GLB + `.import` + JSON together.
|
||||
- **`game.sh import` shows scary warnings** (tree impostors, meta drift, stale bakes, hair-texture case mismatch, missing `res://src/polynesia/data`) — those are **pre-existing and unrelated**. Only care about `errors`, not `warnings`.
|
||||
|
||||
## Loop QC (clips are meant to loop — most raw takes don't)
|
||||
The game loops clips with Godot `LoopMode.Linear` (wraps last keyframe → frame 0), so a
|
||||
clip only looks right if the **pose, motion velocity, and root position** are continuous
|
||||
across that seam. Raw iClone/mocap takes almost never satisfy this — they start from a
|
||||
held pose and end mid-motion, or the performer walks across the floor. **QC every clip
|
||||
before shipping** with the `loop-qc` agent, or directly:
|
||||
|
||||
```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. Don't pipe through grep if you need the code.
|
||||
```
|
||||
Three metrics, three failure modes (the tool ranks the worst bones so you know where):
|
||||
- **root drift high, pose gap low** → performer travels; needs in-place authoring / trim back to origin.
|
||||
- **pose gap high, velocity gap ~0** → starts & ends in different *still* holds; match end pose to start in iClone.
|
||||
- **both high** → starts held / ends mid-move; trim to a full cycle or blend the seam (Animation Layer weight ramp, or bracket clean keys — see `iclone-video-mocap`).
|
||||
|
||||
Two Blender-side fixers exist (no iClone round-trip needed):
|
||||
- `tools/loop_fix.py` — de-drift + trim to best natural loop point + motion-graph seam
|
||||
blend (crossfade toward the frames before the loop start). Keeps 60–90% of the clip.
|
||||
Outputs to `exchange/looped-glb/`. See `plans/loop-fix-plan-2026-07-16.md` + results.
|
||||
- `tools/pingpong_bake.py` — palindrome bake (forward then reversed as ONE clip):
|
||||
end frame == start frame by construction, drift self-cancels, full choreography kept,
|
||||
but motion visibly reverses at the turn point. Outputs `exchange/pingpong-glb/*_pp.glb`,
|
||||
shipped as separate `<pack>_pp` packs. Prefer for sway-heavy dances (hula); judge
|
||||
per-dance for percussive ones (haka) where reverse playback can read as moonwalking.
|
||||
Both verified by re-running `loop_qc.py` to exit 0. iClone re-authoring remains the
|
||||
fallback for clips where neither result looks right in the test bed.
|
||||
|
||||
## Launching the game
|
||||
- **Always ask Jeremy before launching** (this session he said "let's launch" — that's the go-ahead; don't assume it next time).
|
||||
- Command: `SCENE=dance_test_bed bash tools/game.sh spawn` from `ariki-game/` root. Also `animation_showcase` for paging every clip.
|
||||
|
||||
Reference in New Issue
Block a user