From 81b237eaa78b883f693f12b2b23958528b328949 Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Tue, 2 Jun 2026 11:32:09 -0400 Subject: [PATCH] =?UTF-8?q?zebra-spaces:=20listeners=20auto-spotlight=20th?= =?UTF-8?q?e=20latest=20screen=20=E2=80=94=20audience=20experience?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per fox: 'listeners should be able to see all shared screens as audience'. Listeners are passive — they're not running the meeting, they're watching. So they shouldn't have to know they CAN click the screen thumbnail to see the screen big; the system should auto-promote the most recent screen-share into their spotlight. Promotion rules in renderVideoTile when a new tile arrives: - no spotlight up → first tile auto-promotes (anyone) - listener + new screen + spotlight is camera/game → switch to the screen (load-bearing content) - listener + new screen + spotlight is older screen → switch to the newer screen - listener + new camera → do NOT override an active screen spotlight - speakers + new anything → keep their manual choice All other screens stay in the screens-thumbs column as before, so a listener can still click any prior screen to view it. The thumbnails of arriving cameras / screens still render normally — listeners just get the new screen pre-spotlit instead of buried. Speakers / hosts keep their existing behavior: first tile auto- spotlights, subsequent tiles become thumbnails, manual click swaps. --- web/zebra-spaces.html | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/web/zebra-spaces.html b/web/zebra-spaces.html index 67b32ac..813d2cf 100644 --- a/web/zebra-spaces.html +++ b/web/zebra-spaces.html @@ -1771,9 +1771,26 @@ function renderVideoTile(kind, pubHex, stream, opts){ if (spotlight && spotlight.kind === kind && spotlight.pubHex === pubHex && spotlight.video){ spotlight.video.srcObject = stream; } - /* first arrival auto-spotlights — no spotlight up yet AND this is new */ - if (isNew && !spotlight){ - setSpotlight(kind, pubHex); + /* spotlight promotion rules: + * - no spotlight yet → first tile auto-promotes (anyone) + * - listener role + new SCREEN arrives → auto-promote so the + * audience always sees the most recent share without clicking; + * speakers/hosts get to keep their current focus + * - listener role + new CAMERA → don't override an active screen + * spotlight (cameras are less load-bearing than a screen-share) + */ + if (isNew){ + const isListener = !canSpeak(myRole); + if (!spotlight){ + setSpotlight(kind, pubHex); + } else if (isListener && !local && kind === 'screen' && spotlight.kind !== 'screen'){ + /* listener: a screen just arrived and we're spotlighting a camera + * or game — switch to the screen */ + setSpotlight(kind, pubHex); + } else if (isListener && !local && kind === 'screen' && spotlight.kind === 'screen'){ + /* listener: prefer the newer screen over the older one */ + setSpotlight(kind, pubHex); + } } updateContainerVisibility(); if (isNew) logLine('', k.labelPrefix+' share: '+(local?'local preview ':'receiving ')+label); @@ -3331,8 +3348,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');