# MIRPAMO — notes for Claude Local Mixamo replacement: auto-rig + retarget via **headless Blender**. The CLI ([bin/mirpamo](bin/mirpamo)) is plain python3 stdlib; ALL bpy code lives in `bpy/` and runs as `blender -b --python bpy/.py -- `. Never `pip install` anything — the pipeline must run on a bare Mac with only Blender.app present. ## Verify `make smoke` is the ground truth (procedural mesh → rig → retarget → verify). Run it after touching anything in `bpy/`. It must pass on Blender 5.0 and 5.1 (m1ultra is one minor version behind). ## Conventions - Skeleton naming is **mixamorig:** — do not rename bones; the whole point is 1:1 compatibility with the existing Mixamo clip bank (`~/Documents/mixamo-fetch/out/` on machines that have it). - Blender units: meters, Z-up, character on the floor facing -Y. - Outputs land in `out/` (gitignored). Assets never get committed to this repo — meshes live in `~/Documents/character_kit/` and `~/Documents/3D=models/` per the asset-pipeline skill. - Deploy = `make deploy` (push to Gitea → pull on m3ultra + m1ultra → remote smoke). Hosts are listed in [scripts/deploy.sh](scripts/deploy.sh). ## Gotchas - Bone-heat weighting (`ARMATURE_AUTO`) can fail on non-manifold meshes; autorig dies loudly when a mesh ends up without an armature modifier. - The retargeter computes pose-bone `matrix_basis` by hand (see formula in [bpy/retarget.py](bpy/retarget.py)) instead of setting `pose_bone.matrix`, to avoid a depsgraph update per bone per frame. - glTF export uses `export_animation_mode='ACTIONS'` when available so each retargeted clip becomes its own named animation.