- stage.js detectVisemes: NONMOUTH blocklist + side-stripped matching —
/(^|_)l($|_)/ was swallowing every ARKit left-side morph (eyeblink_l,
browdown_l), so setMorph('L') would blink the eye; self-check hardened to
assert group contents (L === tongue only, smile lands on E)
- CLAUDE.md: lanes stage own files explicitly, never git add -A (laneB's
attribution finding)
- README.md: run + feature summary; lane files: session 4 accepted for all,
v1 declared complete, optional backlog recorded
Verified: node + 9 server test groups green, /rhubarb 503 gate live,
audio lane (tone.wav block, gain) + cut markers + sun keys on screen,
zero console errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- stage.js: applyState no longer skips camera/light entities (source
'upload' but no bytes needed) — loaded scenes were silently losing the
directing rig; PLAN schema adds source.type 'none' for the clean fix
- lane files: A session-3 + C M4 accepted; A→absorb hotfix + viseme lane
(M4-A), B→audio rows + Web Audio sync + morphs track (M4-B), C complete
Verified: 6/6 entities restored on scene load, PiP 178x99 capped+visible,
lady 26/26 textured, audio-muxed render h264+aac 8.000s both streams,
graft_limb --selftest green under Blender 5.0.1, node+server suites green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- timeline.js: _mirror — Timeline subscribes stage.onChange, upserts/removes
live stage entities into scene.entities (closes the dock-added-entity gap
both lanes flagged; keyframing now works without a scene load)
- lane files: M2/M3 accepted for all lanes; A→PiP sizing + lady.glb material
polish, B→absorb _mirror + test + setDuration mutator, C→M4 (audio mux,
graft_limb, MB proxy)
SYNC 2: lady+man+street+2cams+sunset built via live dock path, all
frame-exact (probes in transcript). SYNC 3: finalRender → 240 frames
1920x1080 → ffmpeg h264 8.000s, cuts + sunset verified in extracted frames.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>