feat(refboard): video budget system, lazy lifecycle, incremental sync fixes

Video memory:
- Lazy <video> creation: constructor makes placeholder only, initVideo()
  creates element with preload='metadata' when near viewport
- Tiered budgets: 1 playing / 6 initialized / 4 poster textures max
- Aggressive teardown: offscreen videos lose <video> element, poster,
  and all textures — zero memory for offscreen videos
- Poster textures dropped while playing (don't keep both resident)
- Dimension caching in scene data (nativeW/nativeH) avoids re-init

Server:
- HTTP Range support (206 Partial Content) for video seeking
- Proper end clamping and invalid range rejection (416)

Sync:
- Remove redundant broadcastSceneDebounced() from broadcastTransform()
- Remove duplicate broadcastElements() from drag-end handler

VideoControls:
- Event-driven (timeupdate/play/pause/seeked) instead of rAF polling
- Tracks actual HTMLVideoElement reference, rebinds on init/teardown
- Seek uses ref-based commit on pointerUp, not conditional onChange
This commit is contained in:
Hiren Kangad
2026-03-10 11:56:33 +05:30
parent ae050d2119
commit 89010335be
8 changed files with 523 additions and 311 deletions
+12 -1
View File
@@ -268,7 +268,15 @@ export class SceneManager {
case 'video': {
const vidData = data as VideoObject;
const videoUrl = this.textures.urlForAsset(vidData.asset);
const videoSprite = new VideoSprite(vidData.asset, vidData.w, vidData.h, videoUrl);
// Use cached native dimensions if available (avoids re-init just to discover size)
const vw = vidData.nativeW || vidData.w;
const vh = vidData.nativeH || vidData.h;
const videoSprite = new VideoSprite(vidData.asset, vw, vh, videoUrl);
// Apply cached native dims to scene data so display matches
if (vidData.nativeW && vidData.nativeH) {
data.w = vw;
data.h = vh;
}
// Auto-correct dimensions when video metadata loads
// NOTE: callback must update item.data (the stored copy), not the original `data` param.
// We wire this after the item is created below (see post-creation video wiring).
@@ -330,6 +338,9 @@ export class SceneManager {
displayObject.onDimensionsKnown = (realW, realH) => {
item.data.w = realW;
item.data.h = realH;
// Cache native dimensions so future scene loads skip re-init for size
(item.data as VideoObject).nativeW = realW;
(item.data as VideoObject).nativeH = realH;
this._onChange?.();
this._onItemDimensionsChanged?.(item.id);
};