← back to Dead Agentabrams
Backdrop: confine to the stage-riser area with live X/Y/W/H controls
f5a3143bc451e456990816b0bf80a0e8f5001788 · 2026-09-03 11:57:02 -0700 · Steve Abrams
Steve: "put behind my graphics!! on the bg on stage only" / "the area
in back of where singers would sing" / "allow me to expand to show
how it's done."
Two fixes:
1. playConcertManual() was unconditionally entering yt-hero (the
full-screen "video IS the show" mode reserved for the real
archive.org-down fallback) for every Videos-panel pick too, which
is why "behind the art" never actually looked behind anything —
archive.org is still down right now, so every pick went full-hero.
Manual picks now stay muted + confined to the small backdrop box;
yt-hero stays exclusive to enterYouTubeFallback's real outage path.
2. Replaced the single "Backdrop size" scale slider with 4 controls
(Left/Top/Width/Height, --vr-bd-x/-y/-w/-h) plus a reset button, so
Steve can position the box himself instead of me guessing canvas
coordinates. Default widened (46vw x32vh) so the video peeks out
around the opaque stage-riser graphic rather than being fully
hidden behind it edge-to-edge.
Files touched
Diff
commit f5a3143bc451e456990816b0bf80a0e8f5001788
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Sep 3 11:57:02 2026 -0700
Backdrop: confine to the stage-riser area with live X/Y/W/H controls
Steve: "put behind my graphics!! on the bg on stage only" / "the area
in back of where singers would sing" / "allow me to expand to show
how it's done."
Two fixes:
1. playConcertManual() was unconditionally entering yt-hero (the
full-screen "video IS the show" mode reserved for the real
archive.org-down fallback) for every Videos-panel pick too, which
is why "behind the art" never actually looked behind anything —
archive.org is still down right now, so every pick went full-hero.
Manual picks now stay muted + confined to the small backdrop box;
yt-hero stays exclusive to enterYouTubeFallback's real outage path.
2. Replaced the single "Backdrop size" scale slider with 4 controls
(Left/Top/Width/Height, --vr-bd-x/-y/-w/-h) plus a reset button, so
Steve can position the box himself instead of me guessing canvas
coordinates. Default widened (46vw x32vh) so the video peeks out
around the opaque stage-riser graphic rather than being fully
hidden behind it edge-to-edge.
---
room/index.html | 109 ++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 74 insertions(+), 35 deletions(-)
diff --git a/room/index.html b/room/index.html
index f1884e2..4776bb4 100644
--- a/room/index.html
+++ b/room/index.html
@@ -24,20 +24,24 @@
#stage{position:fixed;inset:0;display:block}
canvas{position:absolute;inset:0;width:100%;height:100%}
#orb{z-index:4;pointer-events:none}
- /* ---- Concert-video backdrop (TK-11178): official GD footage behind the generative scene ---- */
- #venueVideo{position:absolute;inset:0;overflow:hidden;z-index:0;pointer-events:none;background:#000;opacity:0;transition:opacity 1.4s ease}
- #venueVideo iframe,#venueVideo>div{position:absolute;top:50%;left:50%;
- transform:translate(-50%,-50%) scale(var(--vr-bd-scale,1)); /* size dialable from the Videos panel (TK-11178) */
- width:100vw;height:56.25vw;min-height:100vh;min-width:177.78vh;border:0;pointer-events:none}
+ /* ---- Concert-video backdrop (TK-11178): official GD footage behind the generative scene.
+ Confined to a positioned box (Steve: "the area in back of where singers would sing") —
+ defaults roughly over the stage riser, fully dialable via the Videos panel's X/Y/W/H
+ sliders (--vr-bd-x/-y/-w/-h). Contain-fit inside that box — never cropped into a close-up. ---- */
+ #venueVideo{position:absolute;
+ left:var(--vr-bd-x, 50%); top:var(--vr-bd-y, 37%);
+ width:var(--vr-bd-w, 46vw); height:var(--vr-bd-h, 32vh);
+ transform:translate(-50%,-50%);
+ overflow:hidden;z-index:0;pointer-events:none;background:#000;opacity:0;
+ transition:opacity 1.4s ease,left .15s,top .15s,width .15s,height .15s;border-radius:3px}
+ #venueVideo iframe,#venueVideo>div{position:absolute;inset:0;width:100%;height:100%;border:0;pointer-events:none}
#stage.video-bg #venueVideo{opacity:1}
- #stage.video-bg #sky{opacity:.12}
- #stage.video-bg #scene{opacity:.42}
- /* YouTube fallback = the video IS the show → let the concert footage dominate the frame */
+ #stage.video-bg #sky{opacity:.20}
+ #stage.video-bg #scene{opacity:.85}
+ /* YouTube fallback = the video IS the show → let it fill the frame, not just the riser box */
+ #stage.video-bg.yt-hero #venueVideo{left:50%;top:50%;width:100vw;height:56.25vw;min-height:100vh;min-width:177.78vh}
#stage.video-bg.yt-hero #sky{opacity:.04}
#stage.video-bg.yt-hero #scene{opacity:.16}
- /* (TK-11178 consolidation) The separate #vrBackdrop/.vr-bg layer was removed — there is now
- ONE backdrop (#venueVideo), driven by both the automatic era-match failover AND the manual
- Videos-panel pick. Its size is dialable via --vr-bd-scale (Videos panel "Backdrop size"). */
#stage.video-bg.yt-hero #orb{opacity:.5}
.btn:disabled,button:disabled{opacity:.42;cursor:not-allowed}
/* ---- Controls in a collapsed RIGHT drawer, opened by the top-right hamburger (TK-11178 UI) ---- */
@@ -281,7 +285,7 @@
.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}
- .vr-size input[type=range]{width:100%}
+ .vr-size input[type=range]{width:100%;margin-bottom:8px}
.vr-list{max-height:220px;overflow:auto;display:flex;flex-direction:column;gap:2px}
.vr-row{display:flex;gap:9px;align-items:baseline;width:100%;text-align:left;background:none;border:0;
color:var(--ink-dim);font-family:var(--sans);font-size:11.5px;padding:6px 6px;cursor:pointer;border-radius:6px}
@@ -1696,22 +1700,57 @@ const MR_VIDEOS=[
vrToggle.addEventListener('keydown', e => {
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); vrToggle.click(); }
});
- // Backdrop size — dials the ONE #venueVideo backdrop via --vr-bd-scale (wrapped for private-mode).
- const SCALE_KEY = 'vr-bd-scale';
- const savedScale = Math.min(1.5, Math.max(.4, parseFloat((()=>{try{return localStorage.getItem(SCALE_KEY);}catch(e){return null;}})()) || 1));
- try{ document.documentElement.style.setProperty('--vr-bd-scale', savedScale); }catch(e){}
- const sizeWrap = document.createElement('div');
- sizeWrap.className = 'vr-size';
- sizeWrap.innerHTML = `<label for="vrSize">Backdrop size <span class="val" id="vrSizeV">${Math.round(savedScale*100)}%</span></label>
- <input type="range" id="vrSize" min="40" max="150" step="5" value="${Math.round(savedScale*100)}" aria-label="Backdrop video size">`;
- vrList.insertAdjacentElement('beforebegin', sizeWrap);
- const sizeInput = sizeWrap.querySelector('#vrSize');
- const sizeVal = sizeWrap.querySelector('#vrSizeV');
- sizeInput.addEventListener('input', () => {
- const pct = +sizeInput.value;
- try{ document.documentElement.style.setProperty('--vr-bd-scale', pct / 100); localStorage.setItem(SCALE_KEY, pct / 100); }catch(e){}
- sizeVal.textContent = pct + '%';
+ // Backdrop position + size — dials the ONE #venueVideo box (--vr-bd-x/-y/-w/-h) so Steve can
+ // drag it right onto "the area in back of where singers would sing" himself, live.
+ const POS_KEY = 'vr-bd-pos';
+ function readJSON(k){ try{ return JSON.parse(localStorage.getItem(k)); }catch(e){ return null; } }
+ function writeJSON(k,v){ try{ localStorage.setItem(k, JSON.stringify(v)); }catch(e){} }
+ const DEFAULT_POS = { x:50, y:37, w:46, h:32 }; // %,%,vw,vh — wide enough to show around the (opaque) stage riser, not just its exact footprint
+ const pos = Object.assign({}, DEFAULT_POS, readJSON(POS_KEY) || {});
+ function applyPos(){
+ const root = document.documentElement.style;
+ root.setProperty('--vr-bd-x', pos.x + '%');
+ root.setProperty('--vr-bd-y', pos.y + '%');
+ root.setProperty('--vr-bd-w', pos.w + 'vw');
+ root.setProperty('--vr-bd-h', pos.h + 'vh');
+ }
+ applyPos();
+ const posWrap = document.createElement('div');
+ posWrap.className = 'vr-size';
+ posWrap.innerHTML = [
+ ['x','Left','%',5,95,DEFAULT_POS.x],
+ ['y','Top','%',5,95,DEFAULT_POS.y],
+ ['w','Width','vw',8,100,DEFAULT_POS.w],
+ ['h','Height','vh',6,100,DEFAULT_POS.h],
+ ].map(([k,label,unit])=>
+ `<label for="vrBd_${k}">Backdrop ${label} <span class="val" id="vrBd_${k}V">${pos[k]}${unit}</span></label>
+ <input type="range" id="vrBd_${k}" min="${k==='x'||k==='y'?5:(k==='w'?8:6)}" max="${k==='x'||k==='y'?95:100}" step="1" value="${pos[k]}" aria-label="Backdrop ${label}">`
+ ).join('');
+ vrList.insertAdjacentElement('beforebegin', posWrap);
+ ['x','y','w','h'].forEach(k=>{
+ const input = posWrap.querySelector(`#vrBd_${k}`);
+ const val = posWrap.querySelector(`#vrBd_${k}V`);
+ const unit = (k==='x'||k==='y') ? '%' : (k==='w' ? 'vw' : 'vh');
+ input.addEventListener('input', () => {
+ pos[k] = +input.value;
+ val.textContent = pos[k] + unit;
+ applyPos();
+ writeJSON(POS_KEY, pos);
+ });
+ });
+ const resetBtn = document.createElement('button');
+ resetBtn.type = 'button'; resetBtn.className = 'vr-bd-toggle'; resetBtn.textContent = '↺ Reset backdrop position';
+ resetBtn.addEventListener('click', () => {
+ Object.assign(pos, DEFAULT_POS);
+ ['x','y','w','h'].forEach(k=>{
+ const unit = (k==='x'||k==='y') ? '%' : (k==='w' ? 'vw' : 'vh');
+ posWrap.querySelector(`#vrBd_${k}`).value = pos[k];
+ posWrap.querySelector(`#vrBd_${k}V`).textContent = pos[k] + unit;
+ });
+ applyPos();
+ writeJSON(POS_KEY, pos);
});
+ posWrap.insertAdjacentElement('afterend', resetBtn);
MR_VIDEOS.forEach(v => {
const row = document.createElement('button');
row.type = 'button';
@@ -1848,23 +1887,23 @@ function enterYouTubeFallback(show, hadGesture){
announce('archive.org is unreachable — playing the nearest official Grateful Dead concert from YouTube.');
saveResume(); // persist the selected show even in fallback (audio timeupdate won't fire here)
}
-// MANUAL trigger from the Videos panel → play a chosen concert through the ONE backdrop controller (TK-11178).
-// Same engine as the automatic failover, different entry point → one backdrop layer, one audio owner.
+// MANUAL trigger from the Videos panel → a MUTED decoration in the small backdrop box behind
+// the stage (Steve: "put behind my graphics... the area in back of where singers would sing"),
+// NOT the full-screen yt-hero "now watching" mode — that stays reserved for the real
+// archive.org-is-down fallback (enterYouTubeFallback), where the video IS the whole show.
function playConcertManual(id, title){
VB.mode='youtube';
try{ audio.pause(); }catch(e){}
try{ audio.removeAttribute('src'); audio.load(); }catch(e){} // one audio owner — kill archive audio
- const hasAct=!!(navigator.userActivation ? navigator.userActivation.isActive : false);
- VB.wantId=id; VB.wantPlay=true; VB.wantMuted=!hasAct; VB._tried=new Set(); VB._hops=0;
+ VB.wantId=id; VB.wantPlay=true; VB.wantMuted=true; VB._tried=new Set(); VB._hops=0;
_loadYTApi();
if(VB.player && VB.player.loadVideoById) _applyVideo();
- _vbShow(); _stageEl.classList.add('yt-hero');
- if(!hasAct) _primeYTUnlock();
+ _vbShow(); _stageEl.classList.remove('yt-hero');
$('mrNow').textContent='▶ Grateful Dead — '+(title||'concert');
$('mrSub').textContent='Playing your pick from the Videos panel — official concert footage on YouTube.';
const msg=$('mrMsg'); if(msg){ msg.hidden=false;
- msg.innerHTML='Now playing the concert you chose.'+(hasAct?'':' Tap or press any key for sound.')+
- ' <a href="https://www.youtube.com/watch?v='+id+'" target="_blank" rel="noopener noreferrer">Watch on YouTube ↗</a>'; }
+ msg.innerHTML='Now showing behind the stage (muted).'+
+ ' <a href="https://www.youtube.com/watch?v='+id+'" target="_blank" rel="noopener noreferrer">Watch with sound on YouTube ↗</a>'; }
setPlay(true);
if(typeof reactBtn!=='undefined' && reactBtn){ reactBtn.disabled=true; reactBtn.title='Live audio analysis isn’t available on the YouTube stream.'; }
saveResume();
← 8f1b9bf Music room: CONSOLIDATE the two video-backdrop systems into
·
back to Dead Agentabrams
·
Lock in Steve's dialed-in backdrop position as the default ff54235 →