- stage: detectVisemes() maps CC/ARKit/plain morph names -> canonical
A/E/I/O/U/MBP/FV/L at character load; visemeTargets(id) + setMorph(id,name,w)
for the timeline to drive lip sync; visemeSelfCheck() asserts the matcher
- dock: inspector 🗣 badge (greyed when a rig has no mouth morphs)
- stage: camera/light default source:{type:'none'} (PLAN §4.1); applyState
skips only upload mesh/backdrop bytes -> rig survives save/load (SYNC4)
Verified live at :8020: selfcheck ok=[A,FV,L,MBP,U]; save/load keeps cam+light.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- stagestub.js: removeEntity now fires onChange WITH the removed entity (real
Stage contract) so _mirror's getEntity(id)===null removal path is testable.
- timeline.js: setDuration(x) — clamps the playhead, keeps out-of-range keys
(lossless), notifies UI via onLoad. (Reviewed orchestrator's _mirror seam.)
- tlui.js: dur field → setDuration; snap-increment select (frame/0.1/0.25/1s);
keyable-param add via dblclick on a params lane (captures current param
values, skips 'type'/bool descriptors); params lane only when keys exist or
kind is camera/light (no empty lane for characters).
- timeline_test.mjs: _mirror lifecycle (add→keyframe→remove) + setDuration.
Verified in browser (throwaway harness, not committed): dock-adds mirror into
rows, param capture, setDuration clamp+bar refresh, snap-step math.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- timeline.js: onLoad hook (rebuilds rows + refreshes scene bar after load()),
scenegod:clipdrop handler (addClipDrop: block at playhead, out=clip duration,
auto 0.25 fade where it abuts a neighbour), crossfade now fade-IN + fade-OUT
(pre-roll pulls successor start earlier for continuous local time).
- tlui.js: reads tracks from the TIMELINE (authoritative) not the stage copy —
fixes post-load addKey/clipdrop not appearing. Params lanes (per-key color),
camera-cut lane add via dblclick, snap toggle, box-select + multi-drag +
Delete, selection highlight, fade wedge on blocks, grow-to-content height.
- timeline_test.mjs: + onLoad, addClipDrop duration, crossfade weight sum=1.
Verified in browser (throwaway harness, not committed): SYNC #3a/#3b repro
fixed, both clip blocks render, clipdrop/add-key show immediately, cut-add and
box-select multi-drag work.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>