From 27215a06c49c3b24fb533ea42785558d28716bba Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 12 Jul 2026 00:53:39 -0500 Subject: feat(gallery): add R21 LED program row MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The classic program-select idiom after a digital reverb's program bank (reference filed in the catalogue's working directory): eight identical dark keys, numbered, with a red LED dot above each. The LED carries the selection, not the key face — exactly one lit at a time, and the readout names the program. Keys press with the same momentary dip as the entry keypad. This maps directly onto a workspace selector for the waybar target. I verified it in headless Chrome: clicking a key moves the single lit LED and renames the readout, no console exceptions. --- docs/prototypes/panel-widget-gallery.html | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'docs/prototypes') diff --git a/docs/prototypes/panel-widget-gallery.html b/docs/prototypes/panel-widget-gallery.html index 6e22c05..fa9d536 100644 --- a/docs/prototypes/panel-widget-gallery.html +++ b/docs/prototypes/panel-widget-gallery.html @@ -724,6 +724,9 @@ card(C,'R19','Waveform region editor', card(C,'R20','Drum roller selector', ``, 'roll to the number. The numbered drum shows through a tall window and the center value sits on an inverted chip. Drag either drum. After an equalizer tone selector.'); +card(C,'R21','LED program row', + ``, + 'identical keys, one lit dot. The LED above the button carries the selection, not the key itself — the classic program-select row. Click a key; readout names the program. After a digital reverb’s program bank.'); /* ============ METERS & GAUGES ============ */ const M=$('meters'); @@ -1762,6 +1765,32 @@ function setDrumr(i,v){v=Math.max(1,Math.min(10,v));DRUMR[i].v=v; setRd('R20',`${DRUMR[0].name} ${Math.round(DRUMR[0].v)} · ${DRUMR[1].name} ${Math.round(DRUMR[1].v)}`);} setDrumr(0,6);setDrumr(1,8); +/* R21 LED program row: exclusive select, the LED carries the state */ +const LEDROW_PROGS=['Sm Hall B','VocPlate','Lg Hall B','Chamber','ParcPlate','Sm Hall A','Room A','Const Plate']; +let ledrowI=5,ledrowLeds=[]; +(function(){const s=$('ledrow'); + const defs=svgEl(s,'defs',{}); + const kb=svgEl(defs,'linearGradient',{id:'lrKey',x1:0,y1:0,x2:0,y2:1}); + svgEl(kb,'stop',{offset:'0','stop-color':'#2b2823'}); + svgEl(kb,'stop',{offset:'1','stop-color':'#171512'}); + LEDROW_PROGS.forEach((name,i)=>{const x=16+i*22.6; + svgEl(s,'text',{x,y:9,'text-anchor':'middle','font-size':6,'font-family':'var(--mono)', + fill:'var(--steel)'}).textContent=i+1; + ledrowLeds.push(svgEl(s,'circle',{cx:x,cy:17,r:2.4,fill:'#3a0f0a'})); + const g=svgEl(s,'g',{});g.style.cursor='pointer';g.style.transition='transform .07s'; + svgEl(g,'rect',{x:x-8.5,y:24,width:17,height:22,rx:2.5,fill:'url(#lrKey)',stroke:'#0a0908','stroke-width':1}); + svgEl(g,'rect',{x:x-6.5,y:26.5,width:13,height:3,rx:1.5,fill:'rgba(255,255,255,.06)'}); + g.addEventListener('click',()=>{g.style.transform='translateY(1.5px)'; + setTimeout(()=>g.style.transform='',80);setLedrow(i);});}); + svgEl(s,'text',{x:95,y:56,'text-anchor':'middle','font-size':6,'letter-spacing':'.16em', + 'font-family':'var(--mono)',fill:'var(--steel)'}).textContent='PROGRAM';})(); +function setLedrow(i){ledrowI=i; + ledrowLeds.forEach((l,k)=>{const on=k===i; + l.setAttribute('fill',on?'var(--jewel-r)':'#3a0f0a'); + l.setAttribute('style',on?'filter:drop-shadow(0 0 3px rgba(255,91,69,.8))':'');}); + setRd('R21',`${ledrowI+1} · ${LEDROW_PROGS[ledrowI]}`);} +setLedrow(5); + /* ============ LIVE SIGNAL LOOPS ============ */ buildBars($('vuL'),16);buildBars($('vuR'),16);$('mini').innerHTML=''; (function(){const eq=$('eq');for(let b=0;b<11;b++){const band=document.createElement('span');band.className='band'; -- cgit v1.2.3