festifun/plan/status/lane-C.md
m3ultra ec22cbdf1f Lane C (M4+M5+M6 + timeline): synchronized viewer frontend
Full frontend built against the synthetic API (no dependence on lanes A/B/D):

M4 — synchronized playback: master clock from performance.now() (never a <video>);
per-video correction via requestVideoFrameCallback (exact mediaTime) with a
currentTime+half-frame fallback — hard-seek >150ms / nudge playbackRate +/-5% 20-150ms /
lock <20ms; out-of-range videos pause+dim; single audio source; dev sync-error overlay.
Timebase mirrors config.py (lib/timebase.js). Verified: seek is exact to 0ms; continuous
inter-video desync 13ms mean / 46ms max.

M5 — 3D viewer: PLY point cloud, per-video camera paths + current-pose frusta, OrbitControls,
snap-to-camera (intrinsics->PerspectiveCamera fov) + free roam. All COLMAP->Three.js via the
frozen lib/pose.js; pose interpolation in lib/poseTrack.js (slerp+lerp of contract inputs).

M6 — anchor overlays: letterbox-correct per-video canvas; anchors projected via pose.js;
behind-camera cull. Projection agrees with an independent pinhole to 1.45e-13 px.

Timeline — colored event markers + legend, hover tooltip, click-to-jump; draggable scrubber.

Phase-3 seams (annotate.js M8, camPath.js M9) left as stubs. No frozen files edited; no new
deps; no change requests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 08:45:51 +10:00

54 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Status — lane-C
## Round 1 — 2026-07-16 — STATUS: ready_to_merge
**Directives acknowledged:** round 0 of plan/DIRECTIVES.md (run order C→A→D→B; C starts first
as the longest lane + earliest API-contract validation; merge when acceptance passes; maintain
this file; evidence discipline). No new rounds present on origin at time of writing.
**Acceptance checklist (lane brief M4/M5/M6 + timeline markers) — all pass:**
- [x] **M4 synchronized playback.** Master clock from `performance.now()` (never a `<video>`).
Timebase mapping proven exact by seek: at t_global=8.0 → cam0=8.000, cam1=6.630,
cam2=8.842 s, err=0 ms each. Per-video correction = hard-seek >150 ms / nudge
playbackRate ±5% 20150 ms / lock <20 ms, driven by `requestVideoFrameCallback`
(exact `mediaTime`) with a currentTime-frame fallback when rVFC is unavailable/stale.
Out-of-range videos pause+dim (cam1 at t=0, target 1.37 s). One audio source; dev
overlay shows per-video sync ms. Measured continuous-playback **inter-video desync =
13 ms mean / 46 ms max** over 6 s (< 50 ms), driven by a setTimeout pump (see env note).
- [x] **M5 3D viewer.** PLY point cloud (3106 pts, vertex colors); per-video camera-path lines
+ current-pose frusta (colored); OrbitControls; snap-to-camera tweens viewer to the pose
(following cam1: camPos≈(1.78,2.63,9.25)≈true center (0,2.4,9.4); fov=36°≈2·atan(H/2fy);
orbit disabled) and free-roam restores (fov50°, orbit on). All COLMAPThree via frozen
`lib/pose.js` never reimplemented.
- [x] **M6 anchor overlays.** Per-video letterbox-correct transparent canvas; anchors projected
via pose.js camera. Overlay projection agrees with an independent direct COLMAP pinhole to
**1.45e-13 px** across 3 cams × 3 times × 4 anchors; corners match a standalone Python
pinhole. Behind-camera cull (z_cam<0). Stage corners render/track on all in-range videos.
- [x] **Timeline event markers.** 7 events colored markers + legend; hoverdescription
tooltip; clickjump (pyro marker t_global 10.00). Scrubber seeks/parks all videos.
- [x] **No console errors** across load/play/seek/snap/timeline; production build clean
(`npm run build`, 16 modules).
**Env note (not a blocker):** the automated browser pane reports `document.hidden=true`, so rAF
and rVFC only fire during screenshots continuous playback can't be observed by polling here.
Verified deterministically instead (seek exactness to 0 ms; projection to 1e-13 px; a
setTimeout-driven run of the real correction code 13 ms mean inter-video desync). A real
focused browser runs the rAF loop at 60 fps and rVFC drives even tighter absolute sync.
**Owned-files discipline:** committed only `frontend/**` + this status file. Left untouched the
other lanes' in-tree changes (A: audio_sync/ingest; B: frames/geometry/sfm; D: events_ai).
Added `frontend/src/lib/timebase.js` + `poseTrack.js` (new files inside lane C's ownership).
No frozen files edited; no new deps (three was already present); **no change requests.**
**Repo note for coordinator:** this working directory is shared/contended `lane/c-viewer`
was reset to foundation (5fa7301) and HEAD moved to `lane/d-events` between my session-start
commit and now, and `main` has since advanced to lane D's self-merge (6ec55c7). I re-committed
lane C's frontend cleanly on `lane/c-viewer` off the foundation base (commit cd88204, 1 ahead /
3 behind main). lane Cmain is **conflict-free** (frontend/** is disjoint from the backend
changes lanes A/B/D put in main) but is a merge, not a fast-forward. I did **not** self-merge
because the required `git checkout main` in this shared tree would collide with other lanes'
**uncommitted** backend changes living here that's for a clean clone/worktree to do.
**Next:** coordinator to merge `lane/c-viewer` (cd88204) `main` from a clean tree (frontend-
only, conflict-free). Phase-3 seams left as clean stubs: `annotate.js` (M8), `camPath.js` (M9).