From e3a62be5008ff28ce3e5c7a1f65480617bf92c96 Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Tue, 2 Jun 2026 12:10:50 -0400 Subject: [PATCH] =?UTF-8?q?zebra-spaces:=20game=20thumbs=20are=20pure=20st?= =?UTF-8?q?atic=20cards=20=E2=80=94=20no=20iframe,=20click=20to=20play?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Confirming the design fox specified: each game (unmario, cake murder adventure) is a separate STABLE tile in the left column. The thumbnail NEVER mounts an iframe (no game JS running in the background, no audio bleed, no network cost) — it's a card with the game's name in chunkfive and a green '▶ play' cue in the meta strip. Clicking a tile: - Mounts a fresh iframe in the middle spotlight slot (only then does the game actually load and become playable) - Updates spotlight state to { kind: 'game', pubHex: id } - Broadcasts the spotlight change so every other person in the room sees 'fxhp now viewing unmario' in their log - Re-orders thumbnails by popularity (viewer count) - The previous spotlight tile's iframe is torn out of the DOM, so switching games stops the previous one cleanly Clicking the already-spotlit game tile is a no-op (already playing). CSS rename: .game-label → .game-poster + new .game-meta strip with the play cue. Title now uses the chunkfive serif (same family as the page headings) so the games read as 'content' rather than 'UI'. --- web/zebra-spaces.html | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/web/zebra-spaces.html b/web/zebra-spaces.html index 110a54d..d5c82b9 100644 --- a/web/zebra-spaces.html +++ b/web/zebra-spaces.html @@ -184,18 +184,27 @@ * sort knows people are watching. */ .games-h2 { margin-top: 0.5rem; } #games-thumbs { display: grid; grid-template-columns: 1fr; gap: 0.45rem; } + /* game thumb is a STATIC tile — never loads the iframe; it's just a + * card with title + 'play' cue. The iframe only mounts when the tile + * is clicked into the spotlight slot. Click → spotlight + broadcast. */ .game-thumb { border: 1px solid #ddd; background: #fff; padding: 0; - display: grid; grid-template-columns: 1fr; gap: 0; + display: grid; grid-template-rows: 1fr auto; gap: 0; cursor: pointer; position: relative; aspect-ratio: 16 / 9; } .game-thumb:hover { outline: 1px solid #888; } - .game-thumb .game-label { + .game-thumb .game-poster { display: grid; place-items: center; text-align: center; - font-family: monospace; font-size: 0.85rem; padding: 0.5rem; - background: #f0f0f0; color: #333; + font-family: 'chunkfiveregular', serif; font-size: 1.05rem; + padding: 0.5rem; background: #f0f0f0; color: #333; + letter-spacing: 0.02em; } + .game-thumb .game-meta { + background: #111; color: #ddd; font-size: 0.65rem; padding: 0.2rem 0.4rem; + display: grid; grid-template-columns: 1fr auto; gap: 0.4rem; align-items: center; + } + .game-thumb .game-meta .play-cue { color: #6c6; letter-spacing: 0.04em; } /* spotlit game shows the iframe at full size in the middle column */ #spotlight > .game-tile { border: 1px solid #ddd; background: #fff; @@ -210,7 +219,7 @@ display: grid; grid-template-columns: 1fr auto; align-items: center; } html.theme-dark .game-thumb { background: #000; border-color: #000; } - html.theme-dark .game-thumb .game-label { background: #111; color: #ddd; } + html.theme-dark .game-thumb .game-poster { background: #111; color: #ddd; } html.theme-dark #spotlight > .game-tile { background: #000; border-color: #000; } html.theme-dark #spotlight > .game-tile iframe { background: #000; } html.theme-dark #spotlight > .game-tile .screen-meta { background: #111; color: #ddd; } @@ -1533,17 +1542,25 @@ function ownerLabel(kind, pubHex){ const handle = m ? (m.mm.handle || shortHex(pubHex)) : shortHex(pubHex); return handle + "'s " + (TILE_KINDS[kind] ? TILE_KINDS[kind].labelPrefix : kind); } -/* game thumbs live in #games-thumbs and click → setSpotlight('game', id) */ +/* game thumbs are STATIC cards. No iframe → no game JS, no network, no + * audio. The game only loads (in an iframe in the spotlight slot) when + * the tile is clicked. Click also broadcasts the spotlight choice so + * the room sees 'alice now viewing unmario'. */ function buildGameThumb(id){ const g = GAMES[id]; if (!g) return null; const tile = document.createElement('div'); tile.className = 'game-thumb'; tile.dataset.pubHex = id; tile.dataset.kind = 'game'; - const label = document.createElement('div'); - label.className = 'game-label'; - label.textContent = g.label; - tile.appendChild(label); + const poster = document.createElement('div'); + poster.className = 'game-poster'; + poster.textContent = g.label; + tile.appendChild(poster); + const meta = document.createElement('div'); meta.className = 'game-meta'; + const who = document.createElement('span'); who.textContent = 'game'; + const cue = document.createElement('span'); cue.className = 'play-cue'; cue.textContent = '▶ play'; + meta.appendChild(who); meta.appendChild(cue); + tile.appendChild(meta); const view = document.createElement('div'); view.className = 'viewing-badge'; view.textContent = 'viewing'; tile.appendChild(view); tile.addEventListener('click', () => { @@ -3363,8 +3380,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');