diff options
Diffstat (limited to 'docs/prototypes')
| -rw-r--r-- | docs/prototypes/panel-widget-gallery.html | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/docs/prototypes/panel-widget-gallery.html b/docs/prototypes/panel-widget-gallery.html index 890c862..8268935 100644 --- a/docs/prototypes/panel-widget-gallery.html +++ b/docs/prototypes/panel-widget-gallery.html @@ -706,6 +706,12 @@ card(C,'R06','Chicken-head selector', card(C,'R12','Chrome slot fader', `<svg id="slotf" class="rsvg drag" viewBox="0 0 90 150" width="90" height="150"></svg>`, '<b>the console gain slide.</b> A chrome T-handle rides a recessed slot, the dB scale engraved on the plate — gain above zero, cut below. Drag; readout shows signed dB. After a vintage channel-strip output fader.'); +card(C,'R14','Spade-pointer tuning knob', + `<svg id="spade" class="rsvg drag" viewBox="0 0 140 124" width="140" height="124"></svg>`, + '<b>the pointer rides the knob.</b> A knurled bakelite knob carries a bright spade pointer over a scale engraved into the panel itself. Drag up/down to tune. After a 1920s radio receiver dial.'); +card(C,'R15','Multi-band dial', + `<svg id="mband" class="rsvg" viewBox="0 0 190 110" width="190" height="110"></svg>`, + '<b>four scales, one needle.</b> Nested band arcs on a cream face; the active ring reads bold. Drag the left dial to tune; click the bandspread dial to switch bands. After a shortwave receiver dial pair.'); /* ============ METERS & GAUGES ============ */ const M=$('meters'); @@ -1470,6 +1476,84 @@ function setEdge(f){edgeFrac=Math.max(.08,Math.min(.94,f)); setRd('R13','−'+db.toFixed(1)+' dB');} setEdge(.62); +/* R14 spade-pointer tuning knob: engraved panel arc, pointer rides the knob */ +let spadeV=8.3,spadeGrp=null; +(function(){const s=$('spade'),cx=70,cy=82,sweep=v=>-80+v/10*160; + const defs=svgEl(s,'defs',{}); + const bk=svgEl(defs,'radialGradient',{id:'spadeKnob',cx:'42%',cy:'34%',r:'80%'}); + svgEl(bk,'stop',{offset:'0','stop-color':'#33302a'}); + svgEl(bk,'stop',{offset:'1','stop-color':'#080706'}); + const mt=svgEl(defs,'linearGradient',{id:'spadeMetal',x1:0,y1:0,x2:1,y2:1}); + svgEl(mt,'stop',{offset:'0','stop-color':'#e9e7e0'}); + svgEl(mt,'stop',{offset:'1','stop-color':'#8d897f'}); + // engraved arc: every stroke carries a faint light twin offset below (incised relief) + const engrave=(x1,y1,x2,y2,w)=>{ + svgEl(s,'line',{x1,y1:y1+.8,x2,y2:y2+.8,stroke:'rgba(255,255,255,.13)','stroke-width':w}); + svgEl(s,'line',{x1,y1,x2,y2,stroke:'#050404','stroke-width':w});}; + for(let i=0;i<=40;i++){const v=i/4,a=sweep(v),major=i%4===0; + const [x1,y1]=polar(cx,cy,major?50:52,a),[x2,y2]=polar(cx,cy,58,a); + engrave(x1,y1,x2,y2,major?1.6:.9); + if(major){const [nx,ny]=polar(cx,cy,65,a); + svgEl(s,'text',{x:nx,y:ny+3.2,'text-anchor':'middle','font-size':7.5,'font-family':'var(--mono)', + fill:'rgba(255,255,255,.13)'}).textContent=v; + svgEl(s,'text',{x:nx,y:ny+2.4,'text-anchor':'middle','font-size':7.5,'font-family':'var(--mono)', + fill:'#0a0908'}).textContent=v;}} + spadeGrp=svgEl(s,'g',{}); + svgEl(spadeGrp,'path',{d:`M ${cx-2} ${cy-28} L ${cx-4.5} ${cy-42} L ${cx} ${cy-54} L ${cx+4.5} ${cy-42} L ${cx+2} ${cy-28} Z`, + fill:'url(#spadeMetal)',stroke:'#55524a','stroke-width':.6}); + svgEl(spadeGrp,'circle',{cx,cy,r:30,fill:'url(#spadeKnob)',stroke:'#000','stroke-width':.8}); + svgEl(spadeGrp,'circle',{cx,cy,r:28.5,fill:'none',stroke:'#0a0908','stroke-width':3,'stroke-dasharray':'2.2 2.2'}); + svgEl(spadeGrp,'circle',{cx,cy,r:22,fill:'url(#spadeKnob)'}); + svgEl(spadeGrp,'ellipse',{cx:cx-8,cy:cy-9,rx:8,ry:5,fill:'rgba(255,255,255,.08)',transform:`rotate(-30,${cx-8},${cy-9})`});})(); +function setSpade(v){spadeV=Math.max(0,Math.min(10,v)); + spadeGrp.setAttribute('transform',`rotate(${-80+spadeV/10*160},70,82)`); + setRd('R14',spadeV.toFixed(1));} +dragDelta($('spade'),()=>spadeV,setSpade,{min:0,max:10,sens:.05});setSpade(8.3); + +/* R15 multi-band dial: nested arcs, one needle; bandspread selects the ring */ +const MBAND_RANGES=[[0.54,1.6],[1.6,5.1],[5.1,15.5],[15.5,30.5]]; +let mbandV=45,mbandB=2,mbNeedle=null,mbRings=[],mbSpread=null; +(function(){const s=$('mband'),cx=62,cy=62,sweep=t=>-70+t*140; + const defs=svgEl(s,'defs',{}); + const pf=svgEl(defs,'linearGradient',{id:'mbFace',x1:0,y1:0,x2:1,y2:1}); + svgEl(pf,'stop',{offset:'0','stop-color':'#eee5c8'}); + svgEl(pf,'stop',{offset:'1','stop-color':'#dcd2ae'}); + svgEl(s,'rect',{x:4,y:4,width:182,height:102,rx:12,fill:'#171412',stroke:'#060505'}); + svgEl(s,'rect',{x:9,y:9,width:172,height:92,rx:9,fill:'url(#mbFace)',stroke:'#0a0908'}); + const INK='#2c2318'; + [18,26,34,42].forEach((r,bi)=>{const ring=svgEl(s,'g',{}); + const [x1,y1]=polar(cx,cy,r,-70),[x2,y2]=polar(cx,cy,r,70); + svgEl(ring,'path',{d:`M ${x1} ${y1} A ${r} ${r} 0 0 1 ${x2} ${y2}`,fill:'none',stroke:INK,'stroke-width':.9}); + for(let i=0;i<=8;i++){const a=sweep(i/8),[tx1,ty1]=polar(cx,cy,r,a),[tx2,ty2]=polar(cx,cy,r+3,a); + svgEl(ring,'line',{x1:tx1,y1:ty1,x2:tx2,y2:ty2,stroke:INK,'stroke-width':.8});} + mbRings.push(ring);}); + mbNeedle=svgEl(s,'line',{x1:cx,y1:cy,x2:cx,y2:cy-46,stroke:'#1a1613','stroke-width':1.6,'stroke-linecap':'round'}); + svgEl(s,'circle',{cx,cy,r:7,fill:'url(#spadeKnob)',stroke:'#000','stroke-width':.6}); + svgEl(s,'text',{x:14,y:100,'font-size':5,'letter-spacing':'.12em','font-family':'var(--mono)', + fill:INK,opacity:.8}).textContent='MEGACYCLES'; + // bandspread dial (click = band select) + const bx=142,by=56; + for(let i=0;i<12;i++){const a=i*30,[x1,y1]=polar(bx,by,24,a),[x2,y2]=polar(bx,by,21,a); + svgEl(s,'line',{x1,y1,x2,y2,stroke:INK,'stroke-width':.8});} + svgEl(s,'circle',{cx:bx,cy:by,r:17,fill:'none',stroke:INK,'stroke-width':.7,opacity:.5}); + mbSpread=svgEl(s,'line',{x1:bx,y1:by,x2:bx,y2:by-22,stroke:'#1a1613','stroke-width':1.4,'stroke-linecap':'round'}); + svgEl(s,'circle',{cx:bx,cy:by,r:6,fill:'url(#spadeKnob)',stroke:'#000','stroke-width':.6}); + svgEl(s,'text',{x:bx,y:96,'text-anchor':'middle','font-size':5,'letter-spacing':'.12em', + 'font-family':'var(--mono)',fill:INK,opacity:.8}).textContent='BANDSPREAD'; + const dragHit=svgEl(s,'rect',{x:9,y:9,width:100,height:92,fill:'transparent'}); + dragHit.style.cursor='ns-resize'; + dragDelta(dragHit,()=>mbandV,v=>setMband(v,mbandB),{min:0,max:100}); + const clickHit=svgEl(s,'rect',{x:112,y:9,width:69,height:92,fill:'transparent'}); + clickHit.style.cursor='pointer'; + clickHit.addEventListener('click',()=>setMband(mbandV,(mbandB+1)%4));})(); +function setMband(v,b){mbandV=Math.max(0,Math.min(100,v));mbandB=b; + mbNeedle.setAttribute('transform',`rotate(${-70+mbandV/100*140},62,62)`); + mbSpread.setAttribute('transform',`rotate(${-45+b*30},142,56)`); + mbRings.forEach((g,i)=>g.setAttribute('opacity',i===b?'1':'.4')); + const [lo,hi]=MBAND_RANGES[b];const mc=lo+mbandV/100*(hi-lo); + setRd('R15',`B${b+1} · ${mc.toFixed(2)} Mc`);} +setMband(45,2); + /* ============ LIVE SIGNAL LOOPS ============ */ buildBars($('vuL'),16);buildBars($('vuR'),16);$('mini').innerHTML='<i></i><i></i><i></i><i></i>'; (function(){const eq=$('eq');for(let b=0;b<11;b++){const band=document.createElement('span');band.className='band'; |
