zebra-report/web
Russell Ballestrini 227588f147
zebra-spaces: spotlight tile DOM-move (instant switch, lip-sync intact)
Fox 2026-06-05: "listeners should still be synced it should just be
that the gesture to change feeds after they are all live should be
immediately to make that feed full sized... reverse your bs and do
what I asked."

Reverted the listener-video-no-delay shortcut. Listener video keeps
playoutDelayHint matched to audio (lip-sync preserved). The actual
fix for slow tile-switching: REUSE the existing thumb tile's <video>
element instead of building a fresh one when promoting to spotlight.

Before: setSpotlight built a brand-new <video> in #spotlight and
assigned the existing MediaStream as its srcObject. The fresh video
element had no decoder state — had to wait for the next keyframe
inside the receiver's 4s-deep buffer to show its first frame,
manifesting as up to 4s of "blank" on listener mobile.

After: setSpotlight DOM-moves the existing thumb tile (with its
already-playing <video> element) into #spotlight. The video element
NEVER stops — no keyframe wait, no re-buffer, no decode-init.
clearSpotlightDOM does the reverse: moves the spotlit tile back to
its thumbs container. Browser DOM-move on an HTMLMediaElement does
not reset playback state.

Supporting changes:

1. CSS: viewing-badge default-hidden; only visible in .tile-thumb.viewing
   context (which no longer exists post-DOM-move since the tile IS
   the spotlight, no separate thumb to mark).

2. CSS: .tile-thumb .fs-btn { display: none } — buildTile always
   includes the fullscreen button now (so we don't have to add it
   dynamically when moving thumb → spotlight). The button is hidden
   when the tile is in thumb context.

3. buildTile: always builds fsBtn (used to be !isThumb only).

4. setSpotlight: same-target click = no-op (idempotent); previous
   spotlight is moved back via clearSpotlightDOM before installing
   the new one.

5. The mid-spotlight supplant path (publisher republishes the same
   kind): the entry-video swap also IS the spotlight-video swap now
   (same DOM node) — removed the redundant second swap, just mirror
   the new entry.video reference into spotlight.video.

6. Game spotlight unchanged — game tiles are static iframes built
   fresh each spotlight, not DOM-moved.

End result: lip-sync stays correct for every role (audio + video
share the same playoutDelayHint), tile switching is instant.
2026-06-05 13:00:41 -04:00
..
blog phase 1: unfirehose reconstruction from session JSONL ingest 2026-05-27 13:51:14 -04:00
fonts phase 2: gap analysis — cat>> append + binary asset recovery 2026-05-27 13:54:19 -04:00
chat.html zebra-spaces: listener mute button doubles as audio-unlock gesture 2026-06-03 20:57:09 -04:00
host-your-own.html zebra-spaces: listener mute button doubles as audio-unlock gesture 2026-06-03 20:57:09 -04:00
how-it-works.html zebra-spaces: listener mute button doubles as audio-unlock gesture 2026-06-03 20:57:09 -04:00
index.html web: bump mobile body padding from 1rem to 1.25rem so the right edge has visible breathing room 2026-05-31 14:13:25 -04:00
kernel.html web: bump mobile body padding from 1rem to 1.25rem so the right edge has visible breathing room 2026-05-31 14:13:25 -04:00
stamp.js web: stamp each zebra-report page with build date + md5/sha256 2026-05-28 17:50:12 -04:00
zebra-audio.html zebra-spaces: listener mute button doubles as audio-unlock gesture 2026-06-03 20:57:09 -04:00
zebra-spaces.html zebra-spaces: spotlight tile DOM-move (instant switch, lip-sync intact) 2026-06-05 13:00:41 -04:00