[object Object]

← back to Dead Agentabrams

Videos panel: add Prev/Next concert + 30s back/fwd seek buttons

20eefcffbfd015e2f61a1b92dd0d52c68b19721f · 2026-09-03 12:48:01 -0700 · Steve Abrams

Steve: "allow user to go fwd bwd on video" / "and 30 seconds back and
fwd buttons." Added a transport bar (⏮ / ⏪30 / 30⏩ / ⏭) above the
show list. Prev/Next step through MR_VIDEOS relative to whatever's
selected (wraps at both ends); the 30s buttons seek the currently
playing YouTube player via getCurrentTime()/seekTo(), clamped to
[0, duration]. Verified: stepping through 3 shows forward and back
lands on the right titles each time, seek buttons don't throw.

Files touched

Diff

commit 20eefcffbfd015e2f61a1b92dd0d52c68b19721f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Sep 3 12:48:01 2026 -0700

    Videos panel: add Prev/Next concert + 30s back/fwd seek buttons
    
    Steve: "allow user to go fwd bwd on video" / "and 30 seconds back and
    fwd buttons." Added a transport bar (⏮ / ⏪30 / 30⏩ / ⏭) above the
    show list. Prev/Next step through MR_VIDEOS relative to whatever's
    selected (wraps at both ends); the 30s buttons seek the currently
    playing YouTube player via getCurrentTime()/seekTo(), clamped to
    [0, duration]. Verified: stepping through 3 shows forward and back
    lands on the right titles each time, seek buttons don't throw.
---
 room/index.html | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 52 insertions(+), 7 deletions(-)

diff --git a/room/index.html b/room/index.html
index 3fe47fe..41e38b3 100644
--- a/room/index.html
+++ b/room/index.html
@@ -306,6 +306,8 @@
   .videoroom[data-open="false"] .vrbody{display:none}
   .vrbody{padding:0 14px 14px}
   .vr-hint{font-size:11px;font-style:italic;color:var(--ink-dim);margin-bottom:9px}
+  .vr-transport{display:flex;align-items:center;gap:6px;margin-bottom:9px}
+  .vr-transport .btn{flex:1;padding:8px 6px;min-height:40px;justify-content:center;font-size:12px}
   .vr-size{margin-bottom:9px}
   .vr-size label{display:block;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-dim);margin-bottom:4px}
   .vr-size .val{font-family:var(--serif);font-style:italic;color:var(--gold);font-size:12px;text-transform:none;letter-spacing:0}
@@ -441,6 +443,12 @@
     </header>
     <div class="vrbody" id="vrbody">
       <div class="vr-hint">Pick a concert — it plays on the stage.</div>
+      <div class="vr-transport" role="group" aria-label="Video transport">
+        <button type="button" class="btn" id="vrPrev" aria-label="Previous concert">⏮</button>
+        <button type="button" class="btn" id="vrBack30" aria-label="Back 30 seconds">⏪ 30</button>
+        <button type="button" class="btn" id="vrFwd30" aria-label="Forward 30 seconds">30 ⏩</button>
+        <button type="button" class="btn" id="vrNext" aria-label="Next concert">⏭</button>
+      </div>
       <div class="vr-list" id="vrList" role="list" aria-label="Concert videos"></div>
     </div>
   </section>
@@ -1763,21 +1771,58 @@ const MR_VIDEOS=[
   });
   // Steve: "it's a movie screen!" — the concert plays on a FIXED movie screen on the stage
   // (.movie-on in CSS), so the old backdrop position/size sliders are gone (they controlled
-  // the retired small #venueVideo box and now do nothing). Panel = header + hint + year list.
+  // the retired small #venueVideo box and now do nothing). Panel = header + hint + transport + year list.
+  const rows = [];
+  function selectVideo(v){
+    vrList.querySelectorAll('.vr-row.on').forEach(r => r.classList.remove('on'));
+    const row = rows.find(r => r.dataset.vid === v.id);
+    if (row) { row.classList.add('on'); row.scrollIntoView({ block: 'nearest' }); }
+    vr.dataset.curId = v.id;
+    playConcertManual(v.id, v.title);   // manual trigger → the one backdrop controller (hoisted from the Music Room IIFE)
+  }
   MR_VIDEOS.forEach(v => {
     const row = document.createElement('button');
     row.type = 'button';
     row.className = 'vr-row';
+    row.dataset.vid = v.id;
     row.setAttribute('role', 'listitem');
     row.innerHTML = `<span class="ry">${v.year}</span><span class="rt">${v.title}</span>`;
-    row.addEventListener('click', () => {
-      vrList.querySelectorAll('.vr-row.on').forEach(r => r.classList.remove('on'));
-      row.classList.add('on');
-      vr.dataset.curId = v.id;
-      playConcertManual(v.id, v.title);   // manual trigger → the one backdrop controller (hoisted from the Music Room IIFE)
-    });
+    row.addEventListener('click', () => selectVideo(v));
     vrList.appendChild(row);
+    rows.push(row);
+  });
+  // Prev/Next concert — step through MR_VIDEOS relative to whatever's currently selected.
+  function curIndex(){
+    const i = MR_VIDEOS.findIndex(v => v.id === vr.dataset.curId);
+    return i; // -1 if nothing selected yet
+  }
+  const prevBtn = document.getElementById('vrPrev');
+  const nextBtn = document.getElementById('vrNext');
+  if (prevBtn) prevBtn.addEventListener('click', () => {
+    const i = curIndex();
+    const next = MR_VIDEOS[i <= 0 ? MR_VIDEOS.length - 1 : i - 1];   // wrap from the first to the last
+    selectVideo(next);
+  });
+  if (nextBtn) nextBtn.addEventListener('click', () => {
+    const i = curIndex();
+    const next = MR_VIDEOS[i < 0 || i >= MR_VIDEOS.length - 1 ? 0 : i + 1];   // wrap from the last back to the first
+    selectVideo(next);
   });
+  // ±30s seek within whatever's currently playing. (VB is a same-script top-level const,
+  // declared further down but already initialized by the time any click can fire.)
+  function seekBy(deltaSeconds){
+    const p = (typeof VB !== 'undefined') ? VB.player : null;
+    if (!p || !p.getCurrentTime || !p.seekTo) return;
+    try {
+      const dur = p.getDuration ? p.getDuration() : Infinity;
+      const t = Math.max(0, Math.min(dur || Infinity, p.getCurrentTime() + deltaSeconds));
+      p.seekTo(t, true);
+    } catch (e) {}
+  }
+  const back30 = document.getElementById('vrBack30');
+  const fwd30 = document.getElementById('vrFwd30');
+  if (back30) back30.addEventListener('click', () => seekBy(-30));
+  if (fwd30) fwd30.addEventListener('click', () => seekBy(30));
 })();
 
 // ---- Movie screen: drag anywhere to move, drag the gold corner to scale up/down (Steve). Persisted. ----

← 8769b6f Music room: mobile-friendly pass — shrink + fluid-scale text  ·  back to Dead Agentabrams  ·  Fast onload: cache archive.org's down state, cut timeouts 6b22391 →