Lip sync cannot be judged silently. extract.sh now pulls the audio track and
writes manifest.json alongside the frames; the page reads the true extraction
rate from it rather than assuming one, since a guessed fps desynchronises
picture from sound - the one thing this view exists to show.
Audio is the clock: frame = floor(currentTime * fps). A slow render loop drops
frames instead of drifting, and half/quarter speed work via playbackRate with
the picture following for free. Scrubbing, stepping and clicking a thumbnail
all seek the audio too.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Analysis half of the pipeline in docs/roto-puppet.md. Stabilises a face out
of a clip via a similarity fit on rigid landmarks, reduces the lip contour to
a fixed vertex budget, selects sparse keys on velocity minima, and previews
the result as flat indexed fills so timing can be judged without an Animator
Pro render.
- landmarks.js ordered lip/oval rings; slot position is vertex identity
- mathutil.js closed-form 2D similarity, Procrustes mean, transform smoothing
- pipeline.js stabilise -> subsample -> key-select
- raster.js indexed scanline fill, no antialiasing
- take.js take-file writer
- selftest.js 29 assertions, incl. ring simplicity at every vertex budget
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>