Fix figure IK snapping and gate the library on a fail-hard motion checker
Three solver defects made limbs teleport, twist, or windmill: write-back angles wrapped at ±180 and lerped the long way around; branch flips landed on configurations the anatomical write-back cannot represent, silently pulling pinned extremities off their pins; and the degenerate straight-limb bend plane fell back to the camera axis instead of the anatomical anterior. solve_limb now verifies each branch reproduces the solved end before accepting it, resolve unwraps written-back angles toward the pose they replace, and the degenerate plane comes from the parent's anterior axis. render.py --check replays every exercise's full tween loop and fails hard on six invariants (pin fidelity, continuity, wraps, authored-vs-resolved drift, ground penetration, resolved ROM); --export refuses to ship a failing exercise. All 66 motions re-authored or retouched to pass: honest authored angles where pins used to override them silently, grounded feet on the seated machines, a vertical bench-press bar path, straight-armed child's pose, a butterfly stretch seated on the mat, and FK arms where pins forced impossible reaches. MotionSolver.swift mirrors the solver changes line for line, held by regenerated fixtures. Claude-Session: https://claude.ai/code/session_01PKptrgbx74peTwHGRxBojv
This commit is contained in:
@@ -221,10 +221,27 @@ python3 render.py --orbit "Bird Dog" # orbit.gif: camera sweeps 360° while loo
|
||||
python3 render.py --figure=female # render with another skeleton profile
|
||||
python3 render.py --flip # view from the other side (camera + 180°)
|
||||
python3 render.py --strict # fail on any ROM violation, listing each
|
||||
python3 render.py --check # simulate every tick; fail hard on solver inconsistencies
|
||||
python3 render.py --export # bake app resources into Workouts/Resources/ExerciseMotions
|
||||
python3 render.py --fixtures # regenerate WorkoutsTests/Fixtures/figure-fixtures.json
|
||||
```
|
||||
|
||||
`--check` goes further than `--strict`'s authored-frame ROM gate: it's compute-only (no
|
||||
frames/GIFs written) and replays the exact pipeline `render_exercise` drives — resolve
|
||||
every key frame, build the tween timeline, re-resolve every tick — at the flat, unpitched
|
||||
camera with no mat (elevation and the mat are presentation-only), watching for the ways
|
||||
the solver has historically swallowed inconsistencies: **pin fidelity** (a pinned hand or
|
||||
foot drifting off its canvas target as it tweens), **pin-unreachable** (an authored pin
|
||||
farther than the limb can physically reach, reported as its own authoring-error class),
|
||||
**continuity** (any drawn joint teleporting between adjacent ticks), **wrap** (an angle
|
||||
DoF swinging more than 180° between adjacent key frames, including the loop closure —
|
||||
an unnaturally long lerp arc), **authored-vs-resolved drift** (a pin silently overriding
|
||||
the authored pose by more than 45°), and **resolved ROM** (the ROM gate re-run on
|
||||
post-IK angles, with slack). Violations print per exercise, grouped and capped to a
|
||||
worst-instance-plus-count per class/joint, ending in a pass/fail tally; **`--export`
|
||||
always runs the full `--check` across the folders it's about to copy first and aborts
|
||||
if anything fails** — there's no override, bad geometry must never ship.
|
||||
|
||||
`render.py` needs only Pillow (for GIFs/sheets; the SVGs have no dependency).
|
||||
The library lives at the repo root, outside every target's source folders —
|
||||
same-named files per entry (`info.md`, `visual.svg`) would collide in Xcode's
|
||||
|
||||
Reference in New Issue
Block a user