diff options
Diffstat (limited to 'docs/prototypes/2026-07-03-panel-widget-gallery-prototype.html')
| -rw-r--r-- | docs/prototypes/2026-07-03-panel-widget-gallery-prototype.html | 1126 |
1 files changed, 0 insertions, 1126 deletions
diff --git a/docs/prototypes/2026-07-03-panel-widget-gallery-prototype.html b/docs/prototypes/2026-07-03-panel-widget-gallery-prototype.html deleted file mode 100644 index 65973bd..0000000 --- a/docs/prototypes/2026-07-03-panel-widget-gallery-prototype.html +++ /dev/null @@ -1,1126 +0,0 @@ -<!doctype html> -<html lang="en"> -<head> -<meta charset="utf-8"> -<meta name="viewport" content="width=device-width, initial-scale=1"> -<title>Panel widget gallery — dupre instrument console (interactive)</title> -<style> -:root{ - --ground:#151311; --panel:#100f0f; --well:#0a0c0d; --raise:#1a1917; - --gold:#dab53d; --gold-hi:#ffd75f; --silver:#bfc4d0; --cream:#f3e7c5; - --steel:#969385; --dim:#7c838a; --slate:#424f5e; --slate-hi:#54677d; - --wash:#2c2f32; --pass:#74932f; --fail:#cb6b4d; - --mono:"BerkeleyMono Nerd Font","Berkeley Mono",monospace; - --phos:#7fe0a0; --phos-dim:#1c3626; --vfd:#63e6c8; --sevgrn:#57d357; --sevred:#e2543f; - --sevoff:#1a1613; --jewel-r:#ff5b45; --jewel-a:#ffb43a; --jewel-g:#6fce33; -} -*{box-sizing:border-box;margin:0;padding:0} -html{background:var(--ground)} -body{font-family:var(--mono);color:var(--silver);padding:2.4rem 2rem 5rem;line-height:1.45; - background:radial-gradient(1200px 600px at 70% -10%,#1c1915 0%,transparent 60%),var(--ground)} -.wrap{max-width:1320px;margin:0 auto} -.eyebrow{color:var(--steel);font-size:.72rem;letter-spacing:.28em;text-transform:uppercase} -h1{color:var(--gold);font-size:1.5rem;margin:.35rem 0 .4rem} -.masthead p{color:var(--dim);font-size:.86rem;max-width:86ch} -.masthead p b{color:var(--silver)} -h2{color:var(--steel);font-size:.74rem;letter-spacing:.24em;text-transform:uppercase; - margin:2.2rem 0 .2rem;display:flex;align-items:center;gap:12px} -h2::after{content:"";height:1px;background:var(--wash);flex:1} - -.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(232px,1fr));gap:14px;margin-top:1rem} -.card{background:linear-gradient(180deg,var(--raise),var(--panel));border:1px solid #262320;border-radius:12px; - padding:13px 14px 12px;display:flex;flex-direction:column;gap:9px; - box-shadow:inset 0 1px 0 rgba(255,255,255,.04),0 6px 14px rgba(0,0,0,.4)} -.wname{color:var(--cream);font-size:.82rem;font-weight:700;display:flex;align-items:center;gap:8px} -.wname .no{color:var(--panel);background:var(--gold);border-radius:4px;font-size:.6rem;padding:0 5px;font-weight:400} -.stagew{background:var(--well);border:1px solid #201d17;border-radius:9px;padding:14px 12px; - min-height:78px;display:flex;align-items:center;justify-content:center;gap:12px;flex-wrap:wrap} -.wrd{color:var(--gold-hi);font-size:.68rem;letter-spacing:.06em;font-variant-numeric:tabular-nums; - min-height:.95rem;display:flex;align-items:center;gap:6px} -.wrd::before{content:"▸";color:var(--steel);font-size:.6rem} -.wnote{color:var(--dim);font-size:.72rem;line-height:1.4} -.wnote b{color:var(--steel);font-weight:400} - -/* ---- shared primitives ---- */ -.lamp{width:9px;height:9px;border-radius:50%;background:var(--pass);box-shadow:0 0 6px 1px rgba(116,147,47,.55)} -.lamp.gold{background:var(--gold);box-shadow:0 0 6px 1px rgba(218,181,61,.6)} -.lamp.red{background:var(--fail);box-shadow:0 0 6px 1px rgba(203,107,77,.55)} -.lamp.off{background:var(--wash);box-shadow:none} -.lamp.busy{background:var(--gold);animation:pulse .7s ease-in-out infinite} -@keyframes pulse{50%{opacity:.25}} - -.switch{width:40px;height:21px;border-radius:11px;background:var(--wash);border:1px solid var(--slate); - position:relative;cursor:pointer} -.switch::after{content:"";position:absolute;top:2px;left:2px;width:15px;height:15px;border-radius:50%; - background:var(--dim);transition:left .15s} -.switch.on{background:var(--slate);border-color:var(--gold)} -.switch.on::after{left:21px;background:var(--gold)} -.switch.red{background:rgba(203,107,77,.2);border-color:var(--fail)} -.switch.red::after{background:var(--fail);left:2px} - -.key{font:inherit;font-size:11.5px;letter-spacing:.06em;color:var(--silver);cursor:pointer; - background:linear-gradient(180deg,#23211e,#191715);border:1px solid #33302b;border-bottom-color:#0c0b0a; - border-radius:8px;padding:8px 12px;box-shadow:inset 0 1px 0 rgba(255,255,255,.04),0 2px 3px rgba(0,0,0,.4)} -.key:hover{color:var(--gold);border-color:var(--gold)} -.key:active{transform:translateY(1px)} -.key.on{color:var(--panel);background:linear-gradient(180deg,#f0d879,var(--gold));border-color:var(--gold-hi);font-weight:700} -.key.red{color:var(--cream);background:linear-gradient(180deg,#d98a6f,var(--fail));border-color:var(--fail)} -.key.off{opacity:.4} - -.chip{color:var(--dim);cursor:pointer;border-bottom:1px dotted var(--wash);font-size:12px} -.chip.on{color:var(--gold);border-color:var(--gold)} - -.badge{font-size:.62rem;letter-spacing:.18em;color:var(--panel);background:var(--gold);border-radius:4px;padding:1px 6px} -.badge.red{background:var(--fail);color:var(--cream)} -.badge.ghost{background:transparent;border:1px solid var(--slate);color:var(--silver)} - -/* fader */ -.fader{width:150px;height:16px;position:relative;cursor:pointer;touch-action:none} -.fader .slot{position:absolute;top:6px;left:0;right:0;height:4px;border-radius:2px;background:#0d0f10;border:1px solid #231f18;overflow:hidden} -.fader .fill{position:absolute;top:0;left:0;bottom:0;background:linear-gradient(90deg,#8a7524,var(--gold))} -.fader .cap{position:absolute;top:1px;width:7px;height:14px;border-radius:2px;margin-left:-3.5px; - background:linear-gradient(180deg,#f0d879,#caa233);border:1px solid #7a6414;box-shadow:0 1px 2px rgba(0,0,0,.5)} -/* vertical fader */ -.vfader{width:16px;height:64px;position:relative;cursor:pointer;touch-action:none} -.vfader .slot{position:absolute;left:6px;top:0;bottom:0;width:4px;border-radius:2px;background:#0d0f10;border:1px solid #231f18;overflow:hidden} -.vfader .fill{position:absolute;left:0;right:0;bottom:0;background:linear-gradient(0deg,#8a7524,var(--gold))} -.vfader .cap{position:absolute;left:1px;height:7px;width:14px;border-radius:2px;margin-top:-3.5px; - background:linear-gradient(90deg,#caa233,#f0d879);border:1px solid #7a6414} - -/* rotary knob */ -.knob{width:52px;height:52px;border-radius:50%;position:relative;cursor:ns-resize;touch-action:none; - background:radial-gradient(circle at 40% 35%,#2a2622,#141210);border:1px solid #3a352c; - box-shadow:inset 0 2px 3px rgba(255,255,255,.05),0 3px 6px rgba(0,0,0,.5)} -.knob .ind{position:absolute;left:50%;top:5px;width:2px;height:16px;background:var(--gold-hi); - margin-left:-1px;transform-origin:50% 21px;border-radius:1px;box-shadow:0 0 5px rgba(255,215,95,.6)} - -/* needle gauge */ -.gauge{width:96px;cursor:ns-resize;touch-action:none} -.gauge .dial{position:relative;height:48px;overflow:hidden} -.gauge .arc{position:absolute;inset:0 0 -48px 0;border:2px solid var(--wash);border-radius:50%} -.gauge .tk{position:absolute;left:50%;bottom:0;width:1.5px;height:8px;background:var(--steel);transform-origin:50% 48px} -.gauge .ndl{position:absolute;left:50%;bottom:0;width:2px;height:40px;background:var(--gold-hi); - transform-origin:50% 100%;transform:rotate(0deg);border-radius:2px;box-shadow:0 0 6px rgba(255,215,95,.5); - transition:transform .12s cubic-bezier(.3,1.3,.5,1)} -.gauge .hub{position:absolute;left:50%;bottom:-4px;width:8px;height:8px;margin-left:-4px;border-radius:50%;background:var(--gold)} -.gauge .gv{color:var(--cream);text-align:center;font-size:12px;font-weight:700;margin-top:5px;font-variant-numeric:tabular-nums} - -/* segmented VU / LED bar */ -.vu{width:170px;display:flex;flex-direction:column;gap:5px} -.vurow{display:flex;align-items:center;gap:7px} -.vurow .ch{color:var(--steel);font-size:.6rem;width:8px} -.vubar{flex:1;display:flex;gap:2px;height:9px} -.vubar i{flex:1;background:var(--wash);border-radius:1px;opacity:.3} -.vubar i.on{opacity:1;background:var(--pass)}.vubar i.hot{opacity:1;background:var(--gold)} -.vubar i.clip{opacity:1;background:var(--fail)}.vubar i.peak{outline:1px solid var(--gold-hi);outline-offset:-1px} - -/* mini 4-bar signal */ -.sig{display:flex;align-items:flex-end;gap:2px;height:18px} -.sig i{width:4px;background:var(--wash);border-radius:1px} -.sig i:nth-child(1){height:5px}.sig i:nth-child(2){height:9px}.sig i:nth-child(3){height:13px}.sig i:nth-child(4){height:17px} -.sig i.on{background:var(--pass)}.sig i.hot{background:var(--gold)}.sig i.clip{background:var(--fail)} - -/* signal ladder (wifi bars) */ -.ladder{display:inline-flex;gap:3px;align-items:flex-end;height:18px;cursor:pointer} -.ladder i{width:5px;background:var(--wash);border-radius:1px} -.ladder i:nth-child(1){height:6px}.ladder i:nth-child(2){height:10px} -.ladder i:nth-child(3){height:14px}.ladder i:nth-child(4){height:18px} - -/* linear progress / fuel bar */ -.bar{width:160px;height:12px;background:#0d0f10;border:1px solid #231f18;border-radius:6px;overflow:hidden;position:relative;cursor:pointer;touch-action:none} -.bar>span{position:absolute;left:0;top:0;bottom:0;background:linear-gradient(90deg,#8a7524,var(--gold));border-radius:6px} -.bar.warn>span{background:linear-gradient(90deg,#a35a3f,var(--fail))} - -/* radial ring */ -.ring{width:60px;height:60px;border-radius:50%;cursor:ns-resize;touch-action:none; - background:conic-gradient(var(--gold) calc(var(--p)*1%),var(--wash) 0); - display:grid;place-items:center;position:relative} -.ring::before{content:"";position:absolute;inset:6px;border-radius:50%;background:var(--well)} -.ring b{position:relative;color:var(--cream);font-size:12px;font-weight:700;font-variant-numeric:tabular-nums} - -/* tabular readout */ -.readout{color:var(--cream);font-size:24px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:.04em;cursor:pointer} -.readout small{color:var(--dim);font-size:12px;font-weight:400} -.readout .u{color:var(--steel);font-size:.6rem;letter-spacing:.2em;display:block;text-align:center;margin-top:2px} - -/* sparkline */ -.spark{width:170px;height:44px} -.spark svg{display:block;width:100%;height:100%} - -/* lamp row (list item) */ -.lrow{width:190px;display:flex;align-items:center;gap:9px;padding:6px 8px;border-radius:7px;background:#141210;cursor:pointer;font-size:12.5px} -.lrow:hover{background:var(--wash)} -.lrow .who{color:var(--silver)}.lrow .who b{color:var(--cream)} -.lrow .what{margin-left:auto;color:var(--dim);font-size:11px} - -/* arm-to-fire */ -.arm{font:inherit;font-size:11.5px;color:var(--silver);cursor:pointer;background:#191715;border:1px solid #33302b; - border-radius:8px;padding:7px 12px} -.arm.armed{background:rgba(203,107,77,.12);border-color:var(--fail);color:var(--fail)} - -/* stepper / segmented selector */ -.seg{display:flex;border:1px solid #33302b;border-radius:8px;overflow:hidden} -.seg button{font:inherit;font-size:11px;color:var(--silver);background:#191715;border:0;border-right:1px solid #33302b;padding:7px 11px;cursor:pointer} -.seg button:last-child{border-right:0} -.seg button.on{background:linear-gradient(180deg,#f0d879,var(--gold));color:var(--panel);font-weight:700} - -/* engraved section label */ -.engrave{width:180px;color:var(--steel);font-size:.62rem;letter-spacing:.3em;text-transform:uppercase;cursor:pointer; - display:flex;align-items:center;gap:9px} -.engrave::before,.engrave::after{content:"";height:1px;background:var(--wash);flex:1} -.engrave::before{max-width:10px} -.engrave .cnt{color:var(--dim);letter-spacing:.1em;text-transform:none} - -/* waveform strip */ -.wave{width:170px;height:38px} -.wave svg{width:100%;height:100%;display:block} - -/* toast */ -.toastw{font-size:11px;color:var(--cream);background:var(--slate);border-radius:7px;padding:5px 10px;cursor:pointer} - -/* output well (log step) */ -.owell{width:200px;background:var(--well);border:1px solid var(--wash);border-radius:8px;padding:7px 9px;font-size:11px;cursor:pointer} -.ostep{display:flex;gap:7px;align-items:flex-start;padding:2px 0} -.ostep .lamp{margin-top:3px;width:7px;height:7px} -.ostep b{color:var(--cream);font-weight:700}.ostep .ev{color:var(--steel);display:block;font-size:10.5px} - -/* rotary selector */ -.rotsel{position:relative;width:118px;height:74px} -.rotsel>.knob{position:absolute;left:50%;top:20px;margin-left:-26px;cursor:pointer} -.rotsel .pos{position:absolute;font-size:9px;color:var(--dim);transform:translate(-50%,-50%);letter-spacing:.02em} -.rotsel .pos.on{color:var(--gold-hi);text-shadow:0 0 6px rgba(255,215,95,.55)} - -/* slide-rule tuner dial */ -.tuner{width:180px;height:46px;position:relative;border-radius:6px;overflow:hidden;cursor:pointer; - background:linear-gradient(180deg,#191510,#0b0908);border:1px solid #2a251c; - box-shadow:inset 0 0 20px rgba(218,181,61,.12),inset 0 1px 0 rgba(255,255,255,.03)} -.tuner .tick{position:absolute;top:6px;width:1px;height:11px;background:var(--steel);transform:translateX(-50%)} -.tuner .mk{position:absolute;bottom:8px;transform:translateX(-50%);color:var(--steel);font-size:10px} -.tuner .mk.on{color:var(--gold-hi);text-shadow:0 0 6px rgba(255,215,95,.6)} -.tuner:focus-visible{outline:2px solid var(--gold);outline-offset:2px} -.tuner .ndl{position:absolute;top:3px;bottom:3px;width:2px;margin-left:-1px;border-radius:1px; - background:var(--fail);box-shadow:0 0 7px rgba(203,107,77,.85);transition:left .25s} - -/* nixie tube */ -.nixie{display:inline-flex;gap:5px;cursor:pointer} -.nixie .tube{width:30px;height:44px;border-radius:5px;position:relative;overflow:hidden; - background:radial-gradient(circle at 50% 38%,#241a12,#0b0807);border:1px solid #2c261d; - display:grid;place-items:center;box-shadow:inset 0 0 12px rgba(0,0,0,.6)} -.nixie .tube b{font-size:26px;font-weight:400;color:#ff9a3c; - text-shadow:0 0 6px rgba(255,140,50,.85),0 0 15px rgba(255,120,40,.45)} -.nixie .tube.off b{color:#3a2a1c;text-shadow:none} -.nixie .tube::after{content:"";position:absolute;inset:0;pointer-events:none; - background:linear-gradient(180deg,rgba(255,255,255,.06),transparent 32%)} - -/* magic-eye tube */ -.magiceye{width:52px;height:52px;border-radius:50%;position:relative;overflow:hidden;cursor:ns-resize;touch-action:none; - background:radial-gradient(circle,#08160a 55%,#040c05);border:1px solid #1b2c1b; - box-shadow:inset 0 0 14px rgba(0,0,0,.7)} -.magiceye .fan{position:absolute;inset:5px;border-radius:50%; - background:conic-gradient(from 140deg,#0c1e0c 0 var(--gap,64deg),#6fce33 0 360deg); - box-shadow:0 0 12px rgba(111,206,51,.4)} -.magiceye::after{content:"";position:absolute;left:50%;top:50%;width:9px;height:9px;margin:-4.5px; - border-radius:50%;background:#08160a;box-shadow:0 0 3px rgba(0,0,0,.6)} - -/* ===== candidate-unique CSS ===== */ -/* rocker */ -.rocker{width:66px;height:40px;border-radius:7px;cursor:pointer;position:relative; - background:linear-gradient(180deg,#25211c,#141210);border:1px solid #34302a; - box-shadow:inset 0 1px 0 rgba(255,255,255,.05),0 3px 6px rgba(0,0,0,.5);overflow:hidden} -.rocker .half{position:absolute;left:0;right:0;height:50%;display:flex;align-items:center;justify-content:center; - font-size:12px;letter-spacing:.06em;color:var(--dim)} -.rocker .top{top:0;border-bottom:1px solid #0c0b0a;background:linear-gradient(180deg,#211d19,#181513)} -.rocker .bot{bottom:0;background:linear-gradient(180deg,#141210,#100e0c);box-shadow:inset 0 3px 5px rgba(0,0,0,.55)} -.rocker.on .top{background:linear-gradient(180deg,#f0d879,var(--gold));color:var(--panel);font-weight:700;box-shadow:0 0 10px rgba(255,215,95,.35)} -.rocker.on .bot{color:var(--steel)} -.rocker:not(.on) .top{color:var(--steel)} -.rocker:not(.on) .bot{background:linear-gradient(180deg,#2a1512,#1c0f0d);color:var(--fail);box-shadow:inset 0 3px 5px rgba(0,0,0,.55),0 0 8px rgba(203,107,77,.25)} - -/* transport */ -.reels{display:flex;gap:16px;align-items:center;justify-content:center;margin-bottom:2px} -.reel{width:26px;height:26px;border-radius:50%;border:2px solid #34302a;position:relative; - background:radial-gradient(circle at 45% 40%,#211d18,#0d0b09)} -.reel::before{content:"";position:absolute;inset:9px;border-radius:50%;border:1px solid #4a443a;background:#161310} -.reel i{position:absolute;left:50%;top:50%;width:2px;height:11px;background:#4a443a;margin:-5.5px 0 0 -1px;transform-origin:50% 5.5px} -.reel i:nth-child(2){transform:rotate(120deg)}.reel i:nth-child(3){transform:rotate(240deg)} -.transport{display:flex;gap:5px} -.tbtn{font:inherit;font-size:12px;color:var(--silver);cursor:pointer;width:30px;height:26px;display:grid;place-items:center; - background:linear-gradient(180deg,#23211e,#191715);border:1px solid #33302b;border-bottom-color:#0c0b0a;border-radius:6px} -.tbtn:hover{color:var(--gold);border-color:var(--gold)} -.tbtn.on{color:var(--panel);background:linear-gradient(180deg,#f0d879,var(--gold));border-color:var(--gold-hi)} -.tbtn.rec.on{color:var(--cream);background:linear-gradient(180deg,#d98a6f,var(--fail));border-color:var(--fail)} - -/* radio bank */ -.radiobank{display:flex;gap:0;border:1px solid #0c0b0a;border-radius:7px;overflow:hidden; - background:#0c0b0a;padding:3px;box-shadow:inset 0 2px 4px rgba(0,0,0,.5)} -.preset{font:inherit;font-size:11px;color:var(--dim);cursor:pointer;padding:8px 9px;border:0;border-radius:4px; - background:linear-gradient(180deg,#211d19,#161310);box-shadow:inset 0 1px 0 rgba(255,255,255,.04)} -.preset+.preset{margin-left:3px} -.preset:hover{color:var(--silver)} -.preset.on{color:var(--panel);background:linear-gradient(180deg,#f0d879,var(--gold));font-weight:700; - box-shadow:inset 0 2px 4px rgba(0,0,0,.4)} - -/* concentric dual knob */ -.dualknob{width:64px;height:64px;position:relative} -.dualknob .outer{width:64px;height:64px;border-radius:50%;position:absolute;inset:0;cursor:ns-resize;touch-action:none; - background:radial-gradient(circle at 40% 35%,#2a2622,#100e0c);border:1px solid #3a352c; - box-shadow:inset 0 2px 3px rgba(255,255,255,.05),0 3px 6px rgba(0,0,0,.5)} -.dualknob .outer .tick{position:absolute;left:50%;top:3px;width:2px;height:9px;background:var(--steel);margin-left:-1px;transform-origin:50% 29px} -.dualknob .inner{width:34px;height:34px;border-radius:50%;position:absolute;left:15px;top:15px;cursor:ns-resize;touch-action:none; - background:radial-gradient(circle at 40% 35%,#37322a,#1a1713);border:1px solid #4a443a;box-shadow:0 2px 4px rgba(0,0,0,.5)} -.dualknob .inner .ind{position:absolute;left:50%;top:3px;width:2px;height:11px;background:var(--gold-hi);margin-left:-1px; - transform-origin:50% 14px;border-radius:1px;box-shadow:0 0 5px rgba(255,215,95,.6)} - -/* rotary encoder + LED ring */ -.encoder{position:relative;width:66px;height:66px;display:grid;place-items:center;cursor:ns-resize;touch-action:none} -.encoder .led{position:absolute;width:5px;height:5px;border-radius:50%;background:var(--wash); - left:50%;top:50%;margin:-2.5px} -.encoder .led.on{background:var(--gold);box-shadow:0 0 5px 1px rgba(218,181,61,.7)} -.encoder .knob{width:40px;height:40px;cursor:ns-resize} -.encoder .knob .ind{transform-origin:50% 15px;top:4px;height:12px} - -/* keyed mode switch */ -.keylock{position:relative;width:110px;height:70px} -.keylock .body{position:absolute;left:50%;top:30px;margin-left:-21px;width:42px;height:42px;border-radius:50%; - background:radial-gradient(circle at 42% 36%,#2a2622,#0f0d0b);border:1px solid #3a352c;cursor:pointer; - box-shadow:inset 0 2px 3px rgba(255,255,255,.05),0 3px 6px rgba(0,0,0,.5)} -.keylock .barrel{position:absolute;left:50%;top:50%;width:5px;height:5px;margin:-2.5px;border-radius:1px;background:#0a0908; - box-shadow:0 0 2px rgba(0,0,0,.8)} -.keylock .bit{position:absolute;left:50%;top:50%;width:3px;height:15px;margin:-15px 0 0 -1.5px;background:var(--gold-hi); - border-radius:1px;transform-origin:50% 100%;box-shadow:0 0 5px rgba(255,215,95,.55);transition:transform .2s} -.keylock .kpos{position:absolute;font-size:9px;color:var(--dim);letter-spacing:.05em;transform:translate(-50%,-50%)} -.keylock .kpos.on{color:var(--gold-hi);text-shadow:0 0 6px rgba(255,215,95,.55)} - -/* crossfader */ -.xfader{width:160px;height:22px;position:relative;cursor:pointer;touch-action:none} -.xfader .slot{position:absolute;top:9px;left:0;right:0;height:4px;border-radius:2px;background:#0d0f10;border:1px solid #231f18} -.xfader .detent{position:absolute;top:2px;left:50%;width:1px;height:18px;background:var(--steel);margin-left:-.5px;opacity:.7} -.xfader .end{position:absolute;top:11px;font-size:9px;color:var(--steel);transform:translateY(-50%)} -.xfader .cap{position:absolute;top:3px;width:9px;height:16px;border-radius:2px;margin-left:-4.5px;transition:left .05s; - background:linear-gradient(180deg,#f0d879,#caa233);border:1px solid #7a6414;box-shadow:0 1px 2px rgba(0,0,0,.5)} - -/* thumbwheel */ -.thumbw{display:flex;align-items:center;gap:10px} -.thumbwheel{width:34px;height:52px;border-radius:6px;cursor:ns-resize;touch-action:none;position:relative;overflow:hidden; - border:1px solid #34302a;box-shadow:inset 0 0 8px rgba(0,0,0,.6); - background:repeating-linear-gradient(0deg,#0e0c0a 0 2px,#221e19 2px 3px,#2f2a23 3px 5px,#221e19 5px 6px)} -.thumbwheel::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(0,0,0,.55),transparent 30%,transparent 70%,rgba(0,0,0,.55))} -.thumbw .win{color:var(--cream);font-size:15px;font-weight:700;font-variant-numeric:tabular-nums; - background:var(--well);border:1px solid #231f18;border-radius:4px;padding:3px 8px} - -/* DIP bank */ -.dip{display:flex;gap:3px;padding:6px 7px;background:#0f1a2a;border:1px solid #24344a;border-radius:5px; - box-shadow:inset 0 1px 3px rgba(0,0,0,.5)} -.dipsw{width:12px;height:26px;background:#0a1220;border-radius:2px;position:relative;cursor:pointer;border:1px solid #1c2c42} -.dipsw i{position:absolute;left:1px;right:1px;height:11px;border-radius:1px;background:linear-gradient(180deg,#eae4d2,#b4ad98); - bottom:1px;transition:bottom .12s,top .12s} -.dipsw.on i{bottom:auto;top:1px;background:linear-gradient(180deg,#f0d879,var(--gold))} - -/* jog / shuttle */ -.jog{position:relative;width:74px;height:74px;cursor:ns-resize;touch-action:none} -.jog .shuttle{position:absolute;inset:0;border-radius:50%;border:6px solid #1a1713; - background:conic-gradient(from -90deg,#3a352c 0 var(--sh,40deg),#141210 0 360deg); - box-shadow:inset 0 0 8px rgba(0,0,0,.6)} -.jog .inner{position:absolute;inset:12px;border-radius:50%;transition:transform .05s linear; - background:radial-gradient(circle at 42% 36%,#2c2822,#100e0c);border:1px solid #3a352c;box-shadow:0 2px 5px rgba(0,0,0,.6)} -.jog .dimple{position:absolute;left:50%;top:7px;width:8px;height:8px;margin-left:-4px;border-radius:50%; - background:radial-gradient(circle at 40% 35%,#151210,#000);box-shadow:inset 0 1px 2px rgba(0,0,0,.9)} - -/* oscilloscope */ -.scope{width:176px;height:78px;border-radius:6px;position:relative;overflow:hidden; - background:radial-gradient(circle at 50% 45%,#04140a,#020a05);border:1px solid #123018; - box-shadow:inset 0 0 16px rgba(0,0,0,.7)} -.scope .grat{position:absolute;inset:0;opacity:.5; - background-image:linear-gradient(rgba(111,206,51,.18) 1px,transparent 1px),linear-gradient(90deg,rgba(111,206,51,.18) 1px,transparent 1px); - background-size:22px 19.5px} -.scope .grat::after{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:rgba(111,206,51,.35)} -.scope svg{position:absolute;inset:0;width:100%;height:100%} -.scope polyline{fill:none;stroke:var(--phos);stroke-width:1.6;filter:drop-shadow(0 0 3px rgba(127,224,160,.8))} - -/* spectrum / EQ */ -.eq{display:flex;align-items:flex-end;gap:3px;height:60px} -.eq .band{width:9px;display:flex;flex-direction:column-reverse;gap:2px;height:100%} -.eq .band i{height:5px;border-radius:1px;background:var(--wash);opacity:.3} -.eq .band i.on{opacity:1;background:var(--pass)} -.eq .band i.hot{opacity:1;background:var(--gold)} -.eq .band i.clip{opacity:1;background:var(--fail)} - -/* crossed-needle */ -.crossm{width:120px} -.crossm .face{position:relative;height:56px;overflow:hidden;cursor:ns-resize;touch-action:none} -.crossm .arc{position:absolute;inset:2px 4px -56px;border:2px solid var(--wash);border-radius:50%} -.crossm .nA{position:absolute;left:14px;bottom:2px;width:2px;height:52px;background:var(--gold-hi);transform-origin:50% 100%; - border-radius:2px;box-shadow:0 0 5px rgba(255,215,95,.5);transition:transform .12s cubic-bezier(.3,1.2,.5,1)} -.crossm .nB{position:absolute;right:14px;bottom:2px;width:2px;height:52px;background:var(--fail);transform-origin:50% 100%; - border-radius:2px;box-shadow:0 0 5px rgba(203,107,77,.5);transition:transform .12s cubic-bezier(.3,1.2,.5,1)} -.crossm .lbl{display:flex;justify-content:space-between;color:var(--steel);font-size:9px;margin-top:2px} - -/* thermometer */ -.thermo{display:flex;align-items:flex-end;gap:6px;height:74px;cursor:ns-resize;touch-action:none} -.thermo .tube{width:12px;height:64px;border-radius:6px 6px 0 0;position:relative;background:#0d0f10;border:1px solid #231f18;overflow:hidden} -.thermo .fill{position:absolute;left:0;right:0;bottom:0;background:linear-gradient(0deg,#a35a3f,var(--fail))} -.thermo .bulb{width:20px;height:20px;border-radius:50%;background:var(--fail);position:absolute;left:-4px;bottom:-9px; - box-shadow:0 0 6px rgba(203,107,77,.5)} -.thermo .scale{display:flex;flex-direction:column;justify-content:space-between;height:64px;font-size:9px;color:var(--steel)} -.thermo .wrapcol{position:relative;padding-bottom:9px} - -/* bourdon */ -.bourdon{width:82px;height:82px;border-radius:50%;position:relative;cursor:ns-resize;touch-action:none; - background:radial-gradient(circle at 48% 42%,#1d1a16,#0c0b09);border:2px solid #2c261d; - box-shadow:inset 0 2px 5px rgba(0,0,0,.6)} -.bourdon svg{position:absolute;inset:0} -.bourdon .ndl{position:absolute;left:50%;top:50%;width:2px;height:32px;margin:-32px 0 0 -1px;background:var(--gold-hi); - transform-origin:50% 100%;border-radius:2px;box-shadow:0 0 5px rgba(255,215,95,.55);transition:transform .12s cubic-bezier(.3,1.2,.5,1)} -.bourdon .hub{position:absolute;left:50%;top:50%;width:8px;height:8px;margin:-4px;border-radius:50%;background:var(--gold)} -.bourdon .cap{position:absolute;left:0;right:0;bottom:12px;text-align:center;font-size:8px;letter-spacing:.16em;color:var(--steel)} - -/* strip-chart */ -.strip{width:176px;height:62px;border-radius:5px;position:relative;overflow:hidden; - background:#0c0e0f;border:1px solid #231f18} -.strip .rule{position:absolute;inset:0;opacity:.4; - background-image:linear-gradient(90deg,rgba(150,147,133,.14) 1px,transparent 1px);background-size:16px 100%} -.strip svg{position:absolute;inset:0;width:100%;height:100%} -.strip polyline{fill:none;stroke:var(--gold);stroke-width:1.4} -.strip .pen{position:absolute;right:2px;width:6px;height:6px;margin:-3px;border-radius:50%;background:var(--gold-hi); - box-shadow:0 0 6px rgba(255,215,95,.8);transition:top .08s linear} - -/* correlation */ -.corr{width:150px;cursor:pointer;touch-action:none} -.corr .face{position:relative;height:44px;overflow:hidden} -.corr .arc{position:absolute;inset:0 0 -44px;border:2px solid var(--wash);border-radius:50%} -.corr .zero{position:absolute;left:50%;top:2px;width:1px;height:10px;background:var(--gold);margin-left:-.5px} -.corr .ndl{position:absolute;left:50%;bottom:0;width:2px;height:38px;background:var(--gold-hi);transform-origin:50% 100%; - border-radius:2px;box-shadow:0 0 5px rgba(255,215,95,.5);transition:transform .1s ease-out} -.corr .lbl{display:flex;justify-content:space-between;color:var(--steel);font-size:9px;margin-top:2px} - -/* battery */ -.batt{display:flex;align-items:center;cursor:pointer;touch-action:none} -.batt .cells{display:flex;gap:2px;padding:3px;border:1px solid #34302a;border-radius:4px;background:#0d0f10} -.batt .cell{width:12px;height:26px;border-radius:1px;background:var(--wash);opacity:.35} -.batt .cell.on{opacity:1;background:linear-gradient(180deg,var(--pass),#5c7526)} -.batt .cell.warn.on{background:linear-gradient(180deg,var(--fail),#a04a34)} -.batt .nub{width:4px;height:12px;background:#34302a;border-radius:0 2px 2px 0} - -/* split-flap */ -.flap{display:inline-flex;gap:4px;cursor:pointer} -.flapd{width:30px;height:42px;border-radius:5px;position:relative;overflow:hidden; - background:linear-gradient(180deg,#211d18,#141210);border:1px solid #34302a;box-shadow:0 2px 4px rgba(0,0,0,.5)} -.flapd b{position:absolute;inset:0;display:grid;place-items:center;font-size:24px;color:var(--cream); - text-shadow:0 1px 2px rgba(0,0,0,.7)} -.flapd::after{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:rgba(0,0,0,.65);box-shadow:0 1px 0 rgba(255,255,255,.03)} -.flapd.flip b{animation:flipdrop .3s ease-in} -@keyframes flipdrop{0%{transform:translateY(-42%) scaleY(.4);opacity:.3}100%{transform:none;opacity:1}} - -/* seven-segment */ -.seven{display:inline-flex;gap:6px;padding:6px 9px;border-radius:6px;background:#0a0806;border:1px solid #231f18;cursor:pointer; - box-shadow:inset 0 0 10px rgba(0,0,0,.6)} -.seg7{width:22px;height:40px;filter:drop-shadow(0 0 3px rgba(87,211,87,.55))} -.seg7.red{filter:drop-shadow(0 0 3px rgba(226,84,63,.55))} -.seven .colon{align-self:center;display:flex;flex-direction:column;gap:9px} -.seven .colon i{width:4px;height:4px;border-radius:50%;background:var(--sevgrn);box-shadow:0 0 4px rgba(87,211,87,.7)} - -/* VFD marquee */ -.vfdm{width:176px;height:34px;border-radius:5px;overflow:hidden;position:relative;cursor:pointer; - background:linear-gradient(180deg,#04100e,#020807);border:1px solid #123028;box-shadow:inset 0 0 12px rgba(0,0,0,.6)} -.vfdm .txt{position:absolute;top:50%;transform:translateY(-50%);white-space:nowrap;font-size:15px;letter-spacing:.22em; - color:var(--vfd);text-shadow:0 0 6px rgba(99,230,200,.65)} -.vfdm .mesh{position:absolute;inset:0;pointer-events:none;opacity:.35; - background-image:radial-gradient(rgba(0,0,0,.6) 40%,transparent 41%);background-size:3px 3px} - -/* annunciator */ -.annun{display:grid;grid-template-columns:repeat(3,1fr);gap:3px} -.acell{font-size:8.5px;letter-spacing:.08em;text-align:center;color:var(--dim);padding:6px 4px;border-radius:3px;cursor:pointer; - background:#141210;border:1px solid #262320;line-height:1.2} -.acell.warn{color:var(--panel);background:linear-gradient(180deg,#f0c25f,var(--gold));font-weight:700;box-shadow:0 0 8px rgba(218,181,61,.4)} -.acell.fault{color:var(--cream);background:linear-gradient(180deg,#d98a6f,var(--fail));font-weight:700;box-shadow:0 0 8px rgba(203,107,77,.4);animation:pulse 1s ease-in-out infinite} - -/* jewel */ -.jewel{width:24px;height:24px;border-radius:50%;position:relative;cursor:pointer; - background:radial-gradient(circle at 36% 30%,rgba(255,255,255,.75),var(--jc) 42%,#3a0d08 100%); - box-shadow:0 0 10px 1px var(--jc),inset 0 -2px 3px rgba(0,0,0,.5)} -.jewel::after{content:"";position:absolute;inset:0;border-radius:50%; - background:conic-gradient(from 0deg,rgba(255,255,255,.12) 0 22deg,transparent 22deg 45deg,rgba(0,0,0,.18) 45deg 67deg,transparent 67deg 90deg); - background-repeat:repeat} -.jewel.dim{background:radial-gradient(circle at 36% 30%,rgba(120,120,120,.3),#241f1b 55%,#0e0c0a);box-shadow:inset 0 -2px 3px rgba(0,0,0,.5)} - -/* tape counter */ -.counter{display:inline-flex;gap:2px;padding:4px;background:#0c0b0a;border:1px solid #2c261d;border-radius:4px; - box-shadow:inset 0 1px 3px rgba(0,0,0,.6)} -.cwheel{width:18px;height:34px;border-radius:2px;position:relative;overflow:hidden; - background:linear-gradient(180deg,#efe9d6,#c7c0ac);box-shadow:inset 0 0 3px rgba(0,0,0,.3)} -.cwheel .col{position:absolute;left:0;right:0;text-align:center;color:#1a1613;font-size:18px;font-weight:700;line-height:34px; - transition:top .35s cubic-bezier(.4,1.4,.5,1)} -.cwheel .col span{display:block;height:34px} -.cwheel::before,.cwheel::after{content:"";position:absolute;left:0;right:0;height:9px;z-index:2;pointer-events:none} -.cwheel::before{top:0;background:linear-gradient(180deg,rgba(0,0,0,.4),transparent)} -.cwheel::after{bottom:0;background:linear-gradient(0deg,rgba(0,0,0,.4),transparent)} -.counter .redw{background:linear-gradient(180deg,#e7b46a,#cf9440)} - -/* analog clock */ -.clock{width:78px;height:78px;border-radius:50%;position:relative; - background:radial-gradient(circle at 46% 40%,#1c1915,#0c0b09);border:2px solid #2c261d;box-shadow:inset 0 2px 5px rgba(0,0,0,.6)} -.clock .tk{position:absolute;left:50%;top:4px;width:1.5px;height:6px;background:var(--steel);margin-left:-.75px;transform-origin:50% 35px} -.clock .hh{position:absolute;left:50%;top:50%;width:3px;height:20px;margin:-20px 0 0 -1.5px;background:var(--cream); - transform-origin:50% 100%;border-radius:2px} -.clock .mh{position:absolute;left:50%;top:50%;width:2px;height:28px;margin:-28px 0 0 -1px;background:var(--silver); - transform-origin:50% 100%;border-radius:2px} -.clock .sh{position:absolute;left:50%;top:50%;width:1px;height:30px;margin:-30px 0 0 -.5px;background:var(--gold-hi); - transform-origin:50% 100%;box-shadow:0 0 4px rgba(255,215,95,.5)} -.clock .pin{position:absolute;left:50%;top:50%;width:6px;height:6px;margin:-3px;border-radius:50%;background:var(--gold)} - -/* frequency-dial scale */ -.freqscale{width:184px;height:44px;position:relative;border-radius:5px;overflow:hidden;cursor:pointer;touch-action:none; - background:linear-gradient(180deg,#191510,#0b0908);border:1px solid #2a251c; - box-shadow:inset 0 0 16px rgba(218,181,61,.1)} -.freqscale .tick{position:absolute;top:5px;width:1px;background:var(--steel);transform:translateX(-50%)} -.freqscale .mk{position:absolute;bottom:6px;transform:translateX(-50%);color:var(--steel);font-size:9px} -.freqscale .band{position:absolute;bottom:2px;left:6px;color:var(--gold);font-size:8px;letter-spacing:.18em} -.freqscale .fptr{position:absolute;top:3px;bottom:14px;width:2px;margin-left:-1px;border-radius:1px; - background:var(--fail);box-shadow:0 0 7px rgba(203,107,77,.85)} - -/* patch-bay */ -.patch{padding:7px 9px;background:#141210;border:1px solid #2c261d;border-radius:5px;position:relative} -.patch .row{display:flex;gap:9px} -.patch .row+.row{margin-top:9px} -.patch .jack{width:13px;height:13px;border-radius:50%;cursor:pointer;background:radial-gradient(circle at 40% 35%,#3a352c,#0a0908 70%); - border:1px solid #4a443a;box-shadow:inset 0 1px 2px rgba(0,0,0,.8)} -.patch .jack.hot{background:radial-gradient(circle at 40% 35%,#7a6414,#1a1408 70%)} -.patch .jack.sel{border-color:var(--gold-hi);box-shadow:0 0 6px 1px rgba(255,215,95,.7)} -.patch svg{position:absolute;inset:0;pointer-events:none;width:100%;height:100%} -.patch svg path{fill:none;stroke:var(--gold);stroke-width:2.4;opacity:.85;stroke-linecap:round} - -@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}} -</style> -</head> -<body> -<div class="wrap"> -<header class="masthead"> - <div class="eyebrow">archsetup · dupre panel family · live kit</div> - <h1>Widget gallery — the instrument-console kit, fully driveable</h1> - <p>Every control + display idiom in the dupre faceplate language, merged into one live console — the base kit - plus the candidate batch, ~55 widgets rendering from the same tokens the net / bt / sound panels use. - <b>Controls</b> take input; <b>meters & gauges</b> show a live analog value; <b>indicators & - readouts</b> show state or a number. Every widget is operable: drag the faders, knobs and gauges; click the - switches, keys and lamps. Each card carries a live readout that tracks what you do. The trace displays run - a live signal; the pointer types drive from your drag.</p> -</header> - -<h2>Controls — take input</h2> -<div class="grid" id="controls"></div> - -<h2>Meters & gauges — live analog value</h2> -<div class="grid" id="meters"></div> - -<h2>Indicators & readouts — state or number</h2> -<div class="grid" id="indicators"></div> - -</div> -<script> -const $ = id => document.getElementById(id); -const reduced = matchMedia('(prefers-reduced-motion: reduce)').matches; -function card(host, no, name, html, note){ - const c=document.createElement('div'); c.className='card'; - c.innerHTML=`<div class="wname"><span class="no">${no}</span>${name}</div>`+ - `<div class="stagew">${html}</div><div class="wrd" id="rd-${no}">—</div><div class="wnote">${note}</div>`; - host.appendChild(c); return c; -} -function setRd(no,txt){const e=$('rd-'+no);if(e)e.textContent=txt;} -function buildBars(el,n){el.innerHTML='';for(let k=0;k<n;k++)el.appendChild(document.createElement('i'));} - -/* ---- pointer-drag helpers ---- */ -function dragX(el,onPct){ el.style.touchAction='none'; - const at=e=>{const r=el.getBoundingClientRect();onPct(Math.max(0,Math.min(100,(e.clientX-r.left)/r.width*100)));}; - el.addEventListener('pointerdown',e=>{el.setPointerCapture(e.pointerId);at(e); - const mv=ev=>at(ev),up=()=>{el.removeEventListener('pointermove',mv);el.removeEventListener('pointerup',up);el.removeEventListener('pointercancel',up);}; - el.addEventListener('pointermove',mv);el.addEventListener('pointerup',up);el.addEventListener('pointercancel',up);e.preventDefault();}); -} -function dragY(el,onPct){ el.style.touchAction='none'; - const at=e=>{const r=el.getBoundingClientRect();onPct(Math.max(0,Math.min(100,(r.bottom-e.clientY)/r.height*100)));}; - el.addEventListener('pointerdown',e=>{el.setPointerCapture(e.pointerId);at(e); - const mv=ev=>at(ev),up=()=>{el.removeEventListener('pointermove',mv);el.removeEventListener('pointerup',up);el.removeEventListener('pointercancel',up);}; - el.addEventListener('pointermove',mv);el.addEventListener('pointerup',up);el.addEventListener('pointercancel',up);e.preventDefault();}); -} -function dragDelta(el,get,set,opts){ opts=opts||{}; el.style.touchAction='none'; - const min=opts.min==null?0:opts.min, max=opts.max==null?100:opts.max, sens=opts.sens||((max-min)/160); - el.addEventListener('pointerdown',e=>{if(opts.stop)e.stopPropagation();el.setPointerCapture(e.pointerId); - const y0=e.clientY, v0=get(); - const mv=ev=>{let v=v0+(y0-ev.clientY)*sens;set(Math.max(min,Math.min(max,v)));}; - const up=()=>{el.removeEventListener('pointermove',mv);el.removeEventListener('pointerup',up);el.removeEventListener('pointercancel',up);}; - el.addEventListener('pointermove',mv);el.addEventListener('pointerup',up);el.addEventListener('pointercancel',up);e.preventDefault();}); -} - -/* ---- seven-segment digit builder ---- */ -const SEG={'0':'abcdef','1':'bc','2':'abged','3':'abgcd','4':'fbgc','5':'afgcd','6':'afgedc','7':'abc','8':'abcdefg','9':'abcdfg','-':'g',' ':''}; -function hseg(cy){return `5,${cy} 7,${cy-2} 17,${cy-2} 19,${cy} 17,${cy+2} 7,${cy+2}`;} -function vseg(cx,ty,by){return `${cx},${ty} ${cx-2},${ty+2} ${cx-2},${by-2} ${cx},${by} ${cx+2},${by-2} ${cx+2},${ty+2}`;} -const SEGPTS={a:hseg(3),g:hseg(22),d:hseg(41),f:vseg(5,4,21),b:vseg(19,4,21),e:vseg(5,23,40),c:vseg(19,23,40)}; -function seg7(ch,cls){ - const lit=SEG[ch]||''; let s=`<svg class="seg7 ${cls||''}" viewBox="0 0 24 44">`; - for(const k of 'abcdefg'){const on=lit.includes(k); - const col=on?(cls==='red'?'var(--sevred)':'var(--sevgrn)'):'var(--sevoff)'; - s+=`<polygon points="${SEGPTS[k]}" fill="${col}"/>`;} - return s+'</svg>'; -} - -/* ============ CONTROLS ============ */ -const C=$('controls'); -card(C,'01','Toggle switch', - `<span id="toggle01"><span class="switch on"></span></span>`, - '<b>on / off.</b> The faceplate master control — power, mute, enable. Click to flip; readout shows the state.'); -card(C,'02','Console key', - `<span id="keys02"><button class="key on">LIVE</button><button class="key">SCAN</button><button class="key red">MUTED</button></span>`, - '<b>physical push button.</b> Mutually exclusive — click one to engage. Gold = live, terracotta = muted.'); -card(C,'03','Horizontal fader', - `<div class="fader" id="f1"><div class="slot"><div class="fill" style="width:68%"></div></div><div class="cap" style="left:68%"></div></div>`, - '<b>continuous 0-100.</b> Per-device volume, brightness. Drag the gold cap; readout tracks.'); -card(C,'04','Vertical fader', - `<div class="vfader" id="v1"><div class="slot"><div class="fill" style="height:60%"></div></div><div class="cap" style="bottom:60%"></div></div> - <div class="vfader" id="v2"><div class="slot"><div class="fill" style="height:35%"></div></div><div class="cap" style="bottom:35%"></div></div>`, - '<b>channel-strip style.</b> A mixer column per device. Drag each fader up or down.'); -card(C,'05','Rotary knob', - `<span class="knob" id="knob"><span class="ind" id="kind"></span></span>`, - '<b>dial in a value.</b> Volume/gain the analog way. Drag up/down to turn; readout shows the level.'); -card(C,'06','Segmented selector', - `<div class="seg" id="seg06"><button class="on">TIMER</button><button>ALARM</button><button>POMO</button></div>`, - '<b>pick one of a few.</b> Timer type, layout mode. Click a segment; readout names the choice.'); -card(C,'07','Chip toggle', - `<span class="chip on" id="chip07">discoverable on</span>`, - '<b>inline binary.</b> A soft toggle inside a line of text. Click to flip; gold when on.'); -card(C,'08','Arm-to-fire', - `<button class="arm" id="arm">forget</button>`, - '<b>two-stage confirm.</b> Destructive actions. First click arms (red), second fires. Readout shows the stage.'); -card(C,'09','Lamp row', - `<div class="lrow" id="lrow9"><span class="lamp gold"></span><span class="who"><b>WH-1000XM4</b></span><span class="what">tap to connect</span></div>`, - '<b>actionable list item.</b> Lamp + name + status. Click to cycle idle → connecting → connected.'); -card(C,'24','Rotary selector', - `<span class="rotsel" id="rotsel24"> - <span class="pos" style="left:14%;top:53%">4</span><span class="pos" style="left:28%;top:18%">6</span><span class="pos on" style="left:50%;top:7%">8</span><span class="pos" style="left:72%;top:18%">10</span><span class="pos" style="left:86%;top:53%">12</span> - <span class="knob"><span class="ind"></span></span> - </span>`, - '<b>pick one of N by position.</b> Printed detents, the pointer names the value. Click to turn; readout shows it.'); -card(C,'25','Slide-rule dial', - `<span class="tuner" id="tuner" tabindex="0" role="slider" aria-label="slide-rule value"> - <span class="tick" style="left:12px"></span><span class="tick" style="left:51px"></span><span class="tick" style="left:90px"></span><span class="tick" style="left:129px"></span><span class="tick" style="left:168px"></span> - <span class="mk" style="left:12px">4</span><span class="mk" style="left:51px">6</span><span class="mk on" style="left:90px">8</span><span class="mk" style="left:129px">10</span><span class="mk" style="left:168px">12</span> - <span class="ndl" id="tundl" style="left:90px"></span> - </span>`, - '<b>value on a printed scale.</b> A lit pointer glides a warm-backlit strip. Click a mark to jump, or focus it and press ←/→ (↑/↓); readout shows it.'); -card(C,'N01','Rocker power switch', - `<span class="rocker on" id="rocker"><span class="half top">ON</span><span class="half bot">OFF</span></span>`, - '<b>hard on / off, lit legend.</b> A master power paddle — the pressed half glows. Click to rock.'); -card(C,'N02','Transport cluster', - `<div style="display:flex;flex-direction:column;gap:6px;align-items:center"> - <div class="reels"><span class="reel spin"><i></i><i></i><i></i></span><span class="reel spin"><i></i><i></i><i></i></span></div> - <div class="transport" id="tport"> - <button class="tbtn" data-t="rew" onclick="transport(this)">⏮</button> - <button class="tbtn on" data-t="play" onclick="transport(this)">▶</button> - <button class="tbtn" data-t="stop" onclick="transport(this)">⏹</button> - <button class="tbtn rec" data-t="rec" onclick="transport(this)">⏺</button> - </div></div>`, - '<b>run / pause / capture.</b> One mode lit at a time, reels turn while it plays. Click a button.'); -card(C,'N03','Radio preset bank', - `<div class="radiobank" id="rbank"> - <button class="preset on" onclick="preset(this)">WIFI</button> - <button class="preset" onclick="preset(this)">ETH</button> - <button class="preset" onclick="preset(this)">CELL</button> - <button class="preset" onclick="preset(this)">OFF</button> - </div>`, - '<b>pick one, the rest release.</b> The car-radio preset row — mechanically exclusive. Click one.'); -card(C,'N04','Concentric dual knob', - `<span class="dualknob"> - <span class="outer" id="dko"><span class="tick" style="transform:rotate(-120deg)"></span><span class="tick" style="transform:rotate(120deg)"></span></span> - <span class="inner" id="dki"><span class="ind"></span></span> - </span>`, - '<b>two values on one spindle.</b> Bass / treble, coarse / fine. Drag the outer ring or inner cap — each is independent.'); -card(C,'N05','Rotary encoder + LED ring', - `<span class="encoder" id="enc"></span>`, - '<b>endless dial, lit position.</b> A detentless encoder; the LED arc lights to the level and the value keeps accumulating. Drag to turn.'); -card(C,'N06','Keyed mode switch', - `<span class="keylock" id="keylock6"> - <span class="kpos" style="left:16%;top:64%">OFF</span><span class="kpos on" style="left:50%;top:12%">ON</span><span class="kpos" style="left:84%;top:64%">RUN</span> - <span class="body" onclick="keyTurn()"><span class="bit" id="kbit"></span><span class="barrel"></span></span> - </span>`, - '<b>guarded three-position mode.</b> Off · on · run. The key-bit points at the live position. Click to turn.'); -card(C,'N07','Center-detented crossfader', - `<div class="xfader" id="xf"> - <div class="slot"></div><div class="detent"></div> - <span class="end" style="left:0">A</span><span class="end" style="right:0">B</span> - <div class="cap" id="xfcap" style="left:50%"></div> - </div>`, - '<b>throw to either side of zero.</b> A fader notched at center — balance, L/R mix. Drag; readout shows the signed value.'); -card(C,'N08','Thumbwheel', - `<div class="thumbw"><span class="thumbwheel" id="thumbwheel"></span><span class="win" id="thval">42</span></div>`, - '<b>ribbed edge-wheel, one value.</b> A knurled wheel with a windowed number. Drag up/down to roll.'); -card(C,'N09','DIP-switch bank', - `<span class="dip" id="dips"> - <span class="dipsw on" onclick="dip(this)"><i></i></span><span class="dipsw" onclick="dip(this)"><i></i></span> - <span class="dipsw on" onclick="dip(this)"><i></i></span><span class="dipsw on" onclick="dip(this)"><i></i></span> - <span class="dipsw" onclick="dip(this)"><i></i></span><span class="dipsw" onclick="dip(this)"><i></i></span> - </span>`, - '<b>a bank of hard flags.</b> Hardware slide switches — up is on. Click each to flip; readout is the binary word.'); -card(C,'N10','Jog / shuttle wheel', - `<span class="jog" id="jog10"><span class="shuttle" style="--sh:40deg"></span><span class="inner" id="jogi"><span class="dimple"></span></span></span>`, - '<b>scrub fine, shuttle fast.</b> The edit-deck wheel. Drag to jog the inner wheel; readout shows the position.'); - -/* ============ METERS & GAUGES ============ */ -const M=$('meters'); -card(M,'10','Needle gauge', - `<div class="gauge" id="gauge10"><div class="dial"><div class="arc"></div> - <div class="tk" style="transform:rotate(-60deg)"></div><div class="tk" style="transform:rotate(0)"></div><div class="tk" style="transform:rotate(60deg)"></div> - <div class="ndl" id="g1"></div><div class="hub"></div></div><div class="gv"><span id="g1v">0</span>%</div></div>`, - '<b>analog dial.</b> Throughput, battery, volume. Drag up/down to sweep the needle; readout tracks. <b>Smooth sweep wants a Cairo/GTK area.</b>'); -card(M,'11','Stereo VU (LED bar)', - `<div class="vu"><div class="vurow"><span class="ch">L</span><span class="vubar" id="vuL"></span></div> - <div class="vurow"><span class="ch">R</span><span class="vubar" id="vuR"></span></div></div>`, - '<b>live signal level.</b> The sound panel meter row, peak-hold outline. Runs a live signal; readout shows L/R.'); -card(M,'12','Mini signal (4-bar)', - `<span class="sig" id="mini"></span>`, - '<b>compact activity.</b> Per-row "is this device playing". Live signal; readout shows activity %.'); -card(M,'13','Signal ladder', - `<span class="ladder" id="ladder"><i></i><i></i><i></i><i></i></span>`, - '<b>discrete strength.</b> Wifi bars, bt RSSI — a stepped 0-4. Click to cycle strength; readout shows bars.'); -card(M,'14','Linear fuel bar', - `<div class="bar" id="bar14"><span style="width:72%"></span></div><div class="bar" id="bar14b"><span style="width:40%"></span></div>`, - '<b>a single 0-100.</b> Battery, disk, download. Drag either bar; warn tint under threshold; readout tracks.'); -card(M,'15','Radial ring', - `<span class="ring" id="ring15" style="--p:68"><b>68</b></span>`, - '<b>percentage as a donut.</b> CPU, battery. Drag up/down to set; conic-gradient tracks the readout.'); -card(M,'16','Sparkline', - `<span class="spark" id="spark"><svg viewBox="0 0 170 44" preserveAspectRatio="none"><polyline id="sparkp" fill="none" stroke="var(--gold-hi)" stroke-width="1.5"/></svg></span>`, - '<b>recent history.</b> Throughput/CPU over the last minute. Live trace; readout shows the current value.'); -card(M,'17','Waveform strip', - `<span class="wave" id="wave"><svg viewBox="0 0 170 38" preserveAspectRatio="none"><path id="wavep" fill="none" stroke="var(--gold)" stroke-width="1.2"/></svg></span>`, - '<b>audio waveform / scope.</b> A richer signal view. Live trace; readout shows amplitude. <b>Needs a drawing surface.</b>'); -card(M,'N11','Oscilloscope', - `<span class="scope"><span class="grat"></span><svg viewBox="0 0 176 78" preserveAspectRatio="none"><polyline id="scopep"/></svg></span>`, - '<b>a live phosphor trace.</b> A waveform swept over a graticule. Live; readout shows Vpp. <b>Needs a Cairo/GTK area for a smooth trace.</b>'); -card(M,'N12','Spectrum / EQ bars', - `<span class="eq" id="eq"></span>`, - '<b>level across bands.</b> A live multi-band bar graph — spectrum, per-core CPU. Live; readout shows the peak band.'); -card(M,'N13','Crossed-needle meter', - `<div class="crossm"><div class="face" id="crossm13"><div class="arc"></div><div class="nA" id="cnA"></div><div class="nB" id="cnB"></div></div> - <div class="lbl"><span>FWD</span><span>RFL</span></div></div>`, - '<b>two readings, one face.</b> Forward + reflected needles cross. Drag up/down to drive power; readout shows both. <b>Round build wants a drawing surface.</b>'); -card(M,'N14','Thermometer column', - `<div class="thermo" id="thermo14"><div class="scale"><span>90</span><span>60</span><span>30</span></div> - <div class="wrapcol"><div class="tube"><div class="fill" id="thermf" style="height:58%"></div></div><div class="bulb"></div></div></div>`, - '<b>a rising column.</b> The classic mercury tube — temperature, a climbing load. Drag up/down; readout shows the value.'); -card(M,'N15','Bourdon pressure gauge', - `<div class="bourdon" id="bourdon15"> - <svg viewBox="0 0 82 82"><path d="M14 62 A34 34 0 0 1 68 62" fill="none" stroke="#2c2f32" stroke-width="3"/> - <path d="M52 22 A34 34 0 0 1 68 62" fill="none" stroke="#cb6b4d" stroke-width="3"/></svg> - <div class="ndl" id="bourd" style="transform:rotate(30deg)"></div><div class="hub"></div><div class="cap">PSI</div></div>`, - '<b>a round dial with a red zone.</b> Needle over a printed arc, redline in terracotta. Drag to set PSI; readout tracks. <b>Round sweep is a drawing-area job.</b>'); -card(M,'N16','Strip-chart recorder', - `<span class="strip"><span class="rule"></span><svg viewBox="0 0 176 62" preserveAspectRatio="none"><polyline id="stripp"/></svg><span class="pen" id="strippen" style="top:31px"></span></span>`, - '<b>a scrolling pen trace.</b> History scrolls left, the pen writes at the right edge. Live; readout shows the current value. <b>Real trace wants a drawing surface.</b>'); -card(M,'N17','Correlation meter (±)', - `<div class="corr" id="corr17"><div class="face"><div class="arc"></div><div class="zero"></div><div class="ndl" id="corrn" style="transform:rotate(8deg)"></div></div> - <div class="lbl"><span>−1</span><span>0</span><span>+1</span></div></div>`, - '<b>deviation from center.</b> The needle rests at 0 and swings ±. Drag left/right; readout shows the signed value.'); -card(M,'N18','Battery-cell gauge', - `<div class="batt" id="batt18"><div class="cells" id="battc"></div><span class="nub"></span></div>`, - '<b>charge as discrete cells.</b> Filled cells count up, the last warn in terracotta. Drag left/right to set; readout shows %.'); - -/* ============ INDICATORS & READOUTS ============ */ -const I=$('indicators'); -card(I,'18','Status lamp', - `<span id="lamp18"><span class="lamp"></span><span class="lamp gold"></span><span class="lamp red"></span><span class="lamp off"></span><span class="lamp busy"></span></span>`, - '<b>one-glance health.</b> Green ok · gold engaged · red fail · dim off · pulsing busy. Click any lamp to cycle its state.'); -card(I,'19','Badge / tag', - `<span id="badge19"><span class="badge">TUNNEL</span> <span class="badge red">LOW BATT</span> <span class="badge ghost">2.4G</span></span>`, - '<b>a labelled flag.</b> MUTED, AIRPLANE, a band tag. Click a badge to cycle its variant.'); -card(I,'20','Tabular readout', - `<div style="text-align:center"><div class="readout" id="treadout">24:10</div><span class="u">timer</span></div>`, - '<b>a precise number.</b> Clock, countdown, volume %. Runs a live countdown; click to pause/resume.'); -card(I,'21','Engraved label', - `<span class="engrave" id="engrave">outputs<span class="cnt" id="engc">· 3</span></span>`, - '<b>section divider.</b> The hairline-flanked caps label with a count. Click to bump the count.'); -card(I,'22','Output well', - `<div class="owell" id="owell"><div class="ostep"><span class="lamp"></span><span><b>Link</b><span class="ev">wlp170s0 · @Hyatt</span></span></div> - <div class="ostep"><span class="lamp gold"></span><span><b>DNS</b><span class="ev">resolving…</span></span></div></div>`, - '<b>streaming step log.</b> Lamp-per-step with evidence. Click to stream the next step.'); -card(I,'23','Toast / status line', - `<span class="toastw" id="toast">joined @Hyatt_WiFi — saved</span>`, - '<b>transient confirmation.</b> The one-line result after an action. Click to fire the next toast.'); -card(I,'26','Nixie tube', - `<span class="nixie" id="nixie"><span class="tube off"><b>0</b></span><span class="tube"><b>8</b></span></span>`, - '<b>a single warm-glowing numeral.</b> One lit digit per tube, leading zeros dark. Click to increment the count.'); -card(I,'27','Magic-eye tube', - `<span class="magiceye" id="meye"><span class="fan"></span></span>`, - '<b>the glowing tuning eye.</b> A phosphor tube whose dark wedge narrows as the value peaks. Drag up/down to set; readout tracks.'); -card(I,'N20','Split-flap display', - `<span class="flap" id="flap"><span class="flapd"><b>D</b></span><span class="flapd"><b>N</b></span><span class="flapd"><b>S</b></span></span>`, - '<b>flips to the new value.</b> Each card drops to the next glyph with the mechanical clack. Auto-flips; click to flip now.'); -card(I,'N21','Seven-segment display', - `<span class="seven" id="seven"></span>`, - '<b>a lit-segment number.</b> Green segments, distinct from the nixie glow. Live countdown; click to add a minute.'); -card(I,'N22','VFD marquee', - `<span class="vfdm" id="vfdm"><span class="txt" id="vfdt">ARCHSETUP · NET OK · BT 2 · SND 62%</span><span class="mesh"></span></span>`, - '<b>scrolling status line.</b> Teal glow, dot-matrix mesh, text tracks across. Scrolls live; click to change the message.'); -card(I,'N23','Annunciator panel', - `<div class="annun" id="annun"> - <span class="acell">SYNC</span><span class="acell warn">LOW BATT</span><span class="acell">LINK</span> - <span class="acell fault">NO DNS</span><span class="acell">VPN</span><span class="acell">DISK</span> - </div>`, - '<b>a grid of named alarms.</b> Cells light amber to warn, red to fault (faults pulse). Click a cell to cycle its state.'); -card(I,'N24','Jewel pilot lamps', - `<span id="jewels"><span class="jewel" style="--jc:var(--jewel-r)"></span><span class="jewel" style="--jc:var(--jewel-a)"></span> - <span class="jewel" style="--jc:var(--jewel-g)"></span><span class="jewel dim"></span></span>`, - '<b>a faceted glass indicator.</b> The chunky bezel pilot lamp with a real bloom. Click a jewel to cycle red · amber · green · dark.'); -card(I,'N25','Tape counter', - `<span class="counter" id="counter"></span>`, - '<b>rolling odometer digits.</b> Numbered wheels roll to the next figure. Rolls live; readout shows the total.'); -card(I,'N26','Analog clock', - `<span class="clock" id="clock"><span class="hh" id="clkh"></span><span class="mh" id="clkm"></span><span class="sh" id="clks"></span><span class="pin"></span></span>`, - '<b>time on a real face.</b> Engraved ticks, three hands, live seconds sweep. Runs live; readout shows the time.'); -card(I,'N27','Frequency-dial scale', - `<span class="freqscale" id="fscale"><span class="band">MHz</span></span>`, - '<b>a printed log scale.</b> Marks crowd low, spread high — a real logarithmic axis. Drag the pointer; readout shows the frequency.'); -card(I,'N28','Patch-bay jack field', - `<div class="patch" id="patch"></div>`, - '<b>routing shown as patches.</b> A grid of jacks with cables between connected pairs. Click one jack then another to add/remove a cable.'); - -/* ============ CONTROL WIRING ============ */ -/* 01 toggle */ -(function(){const sw=$('toggle01').querySelector('.switch'); - function upd(){setRd('01',sw.classList.contains('on')?'ON':'OFF');} - sw.onclick=()=>{sw.classList.toggle('on');upd();};upd();})(); -/* 02 console key */ -$('keys02').querySelectorAll('.key').forEach(k=>k.onclick=()=>{ - $('keys02').querySelectorAll('.key').forEach(x=>x.classList.remove('on','red')); - k.classList.add(k.textContent==='MUTED'?'red':'on');setRd('02',k.textContent);}); -setRd('02','LIVE'); -/* 03 horizontal fader */ -function setF1(p){const f=$('f1');f.querySelector('.fill').style.width=p+'%';f.querySelector('.cap').style.left=p+'%';setRd('03','level '+Math.round(p));} -dragX($('f1'),setF1);setF1(68); -/* 04 vertical faders */ -let vfA=60,vfB=35; -function vfUpd(){setRd('04','A '+Math.round(vfA)+' · B '+Math.round(vfB));} -function setVf(el,p){el.querySelector('.fill').style.height=p+'%';el.querySelector('.cap').style.bottom=p+'%';} -dragY($('v1'),p=>{vfA=p;setVf($('v1'),p);vfUpd();}); -dragY($('v2'),p=>{vfB=p;setVf($('v2'),p);vfUpd();}); -setVf($('v1'),60);setVf($('v2'),35);vfUpd(); -/* 05 knob */ -let knobV=53; -function setKnob(v){knobV=v;$('kind').style.transform=`rotate(${-150+v/100*300}deg)`;setRd('05','gain '+Math.round(v));} -dragDelta($('knob'),()=>knobV,setKnob,{min:0,max:100});setKnob(53); -/* 06 segmented */ -$('seg06').querySelectorAll('button').forEach(b=>b.onclick=()=>{ - $('seg06').querySelectorAll('button').forEach(x=>x.classList.remove('on'));b.classList.add('on');setRd('06',b.textContent);}); -setRd('06','TIMER'); -/* 07 chip */ -$('chip07').onclick=()=>{$('chip07').classList.toggle('on');setRd('07',$('chip07').classList.contains('on')?'ON':'OFF');}; -setRd('07','ON'); -/* 08 arm */ -let armed=false; -$('arm').onclick=()=>{const a=$('arm');if(!armed){armed=true;a.classList.add('armed');a.textContent='forget? again';setRd('08','ARMED');} - else{armed=false;a.classList.remove('armed');a.textContent='forget';setRd('08','FIRED · reset');}}; -setRd('08','SAFE'); -/* 09 lamp row */ -const lrStates=[['gold','tap to connect'],['busy','connecting…'],['','connected']];let lrI=0; -$('lrow9').onclick=()=>{lrI=(lrI+1)%3;const s=lrStates[lrI];$('lrow9').querySelector('.lamp').className='lamp '+s[0]; - $('lrow9').querySelector('.what').textContent=s[1];setRd('09',s[1]);}; -setRd('09','tap to connect'); -/* 24 rotary selector */ -const rotVals=[4,6,8,10,12];let rotIdx=2;const rotAng=[-70,-35,0,35,70]; -$('rotsel24').querySelector('.knob').onclick=()=>{rotIdx=(rotIdx+1)%5; - $('rotsel24').querySelector('.ind').style.transform=`rotate(${rotAng[rotIdx]}deg)`; - $('rotsel24').querySelectorAll('.pos').forEach((p,i)=>p.classList.toggle('on',i===rotIdx));setRd('24','size '+rotVals[rotIdx]);}; -setRd('24','size 8'); -/* 25 slide-rule */ -const tunVals=[4,6,8,10,12];let tunIdx=2;const tunX=[12,51,90,129,168]; -function setTun(i){tunIdx=Math.max(0,Math.min(tunVals.length-1,i));$('tundl').style.left=tunX[tunIdx]+'px'; - $('tuner').querySelectorAll('.mk').forEach((m,j)=>m.classList.toggle('on',j===tunIdx));setRd('25','pos '+tunVals[tunIdx]);} -$('tuner').onclick=(e)=>{const r=$('tuner').getBoundingClientRect(),x=e.clientX-r.left; - let best=0,bd=1e9;tunX.forEach((tx,j)=>{const d=Math.abs(tx-x);if(d<bd){bd=d;best=j;}});setTun(best);$('tuner').focus();}; -$('tuner').onkeydown=(e)=>{if(e.key==='ArrowLeft'||e.key==='ArrowDown'){e.preventDefault();setTun(tunIdx-1);} - else if(e.key==='ArrowRight'||e.key==='ArrowUp'){e.preventDefault();setTun(tunIdx+1);}}; -setRd('25','pos 8'); -/* N01 rocker */ -$('rocker').onclick=()=>{$('rocker').classList.toggle('on');setRd('N01',$('rocker').classList.contains('on')?'ON':'OFF');}; -setRd('N01','ON'); -/* N02 transport */ -function transport(b){b.parentElement.querySelectorAll('.tbtn').forEach(x=>x.classList.remove('on'));b.classList.add('on'); - const playing=b.dataset.t==='play';document.querySelectorAll('.reel.spin').forEach(r=>r.style.animationPlayState=playing&&!reduced?'running':'paused'); - setRd('N02',{rew:'REW',play:'PLAY',stop:'STOP',rec:'REC'}[b.dataset.t]);} -setRd('N02','PLAY'); -/* N03 radio preset */ -function preset(b){b.parentElement.querySelectorAll('.preset').forEach(x=>x.classList.remove('on'));b.classList.add('on');setRd('N03',b.textContent);} -setRd('N03','WIFI'); -/* N04 concentric dual knob */ -let dkoV=50,dkiV=50; -function setDual(){$('dko').style.transform=`rotate(${-150+dkoV/100*300}deg)`;$('dki').style.transform=`rotate(${-150+dkiV/100*300}deg)`; - setRd('N04','bass '+Math.round(dkoV)+' · treble '+Math.round(dkiV));} -dragDelta($('dko'),()=>dkoV,v=>{dkoV=v;setDual();},{min:0,max:100}); -dragDelta($('dki'),()=>dkiV,v=>{dkiV=v;setDual();},{min:0,max:100,stop:true}); -setDual(); -/* N05 encoder */ -let encV=7; -function paintEnc(){const leds=$('enc').querySelectorAll('.led');const lit=((Math.floor(encV)%12)+12)%12; - leds.forEach((l,i)=>l.classList.toggle('on',i<=lit));} -function setEnc(v){encV=v;paintEnc();const ind=$('enc').querySelector('.knob .ind');if(ind)ind.parentElement.style.transform=`rotate(${encV*30}deg)`; - setRd('N05','pos '+Math.round(encV));} -(function(){const enc=$('enc');const R=27,cx=33,cy=33; - for(let i=0;i<12;i++){const a=(i*30-90)*Math.PI/180;const d=document.createElement('span');d.className='led'; - d.style.left=(cx+R*Math.cos(a))+'px';d.style.top=(cy+R*Math.sin(a))+'px';enc.appendChild(d);} - const k=document.createElement('span');k.className='knob';k.innerHTML='<span class="ind"></span>';enc.appendChild(k);})(); -dragDelta($('enc'),()=>encV,setEnc,{min:0,max:100000,sens:0.25});setEnc(7); -/* N06 keylock */ -let keyIdx=1;const keyAng=[-70,0,70];const keyNm=['OFF','ON','RUN']; -function keyTurn(){keyIdx=(keyIdx+1)%3;$('kbit').style.transform=`rotate(${keyAng[keyIdx]}deg)`; - $('keylock6').querySelectorAll('.kpos').forEach((p,i)=>p.classList.toggle('on',i===keyIdx));setRd('N06',keyNm[keyIdx]);} -setRd('N06','ON'); -/* N07 crossfader */ -function setXf(p){$('xfcap').style.left=p+'%';const v=Math.round(p-50);setRd('N07',(v>0?'+':'')+v);} -dragX($('xf'),setXf);setXf(50); -/* N08 thumbwheel */ -let thumbV=42; -function setThumb(v){thumbV=Math.round(v);const s=(((thumbV%100)+100)%100);$('thval').textContent=String(s).padStart(2,'0');setRd('N08','value '+s);} -dragDelta($('thumbwheel'),()=>thumbV,setThumb,{min:0,max:99,sens:0.2});setThumb(42); -/* N09 DIP */ -function dipUpd(){const bits=[...$('dips').querySelectorAll('.dipsw')].map(x=>x.classList.contains('on')?'1':'0').join('');setRd('N09',bits);} -function dip(s){s.classList.toggle('on');dipUpd();} -dipUpd(); -/* N10 jog */ -let jogV=0; -function setJog(v){jogV=v;$('jogi').style.transform=`rotate(${jogV*4}deg)`;setRd('N10','pos '+Math.round(jogV));} -dragDelta($('jog10'),()=>jogV,setJog,{min:-100000,max:100000,sens:0.5});setJog(0); - -/* ============ METER WIRING (drag-driven) ============ */ -/* 10 needle gauge */ -let gV=50; -function setGauge(v){gV=v;$('g1').style.transform=`rotate(${-60+v/100*120}deg)`;$('g1v').textContent=Math.round(v);setRd('10','value '+Math.round(v)+'%');} -dragDelta($('gauge10'),()=>gV,setGauge,{min:0,max:100});setGauge(50); -/* 13 signal ladder */ -let ladV=3; -function setLadder(v){ladV=v;const bars=$('ladder').children; - for(let i=0;i<bars.length;i++)bars[i].style.background=i<v?'var(--gold)':'var(--wash)';setRd('13',v+'/4');} -$('ladder').onclick=()=>setLadder((ladV+1)%5);setLadder(3); -/* 14 fuel bars */ -function setBar(id,no,p){const b=$(id);b.querySelector('span').style.width=p+'%';b.classList.toggle('warn',p<20);setRd(no,Math.round(p)+'%');} -dragX($('bar14'),p=>setBar('bar14','14',p));dragX($('bar14b'),p=>setBar('bar14b','14',p)); -setBar('bar14','14',72); -/* 15 radial ring */ -let ringV=68; -function setRing(v){ringV=v;const r=$('ring15');r.style.setProperty('--p',v);r.querySelector('b').textContent=Math.round(v);setRd('15',Math.round(v)+'%');} -dragDelta($('ring15'),()=>ringV,setRing,{min:0,max:100});setRing(68); -/* N13 crossed-needle */ -let cnPow=55; -function setCross(v){cnPow=v;const fwd=v,rfl=v*0.68;$('cnA').style.transform=`rotate(${-42+fwd/100*84}deg)`; - $('cnB').style.transform=`rotate(${42-rfl/100*84}deg)`;setRd('N13','FWD '+Math.round(fwd)+' · RFL '+Math.round(rfl));} -dragDelta($('crossm13'),()=>cnPow,setCross,{min:0,max:100});setCross(55); -/* N14 thermometer */ -let thV=58; -function setThermo(v){thV=v;$('thermf').style.height=v+'%';setRd('N14',Math.round(30+v/100*60)+'°');} -dragDelta($('thermo14'),()=>thV,setThermo,{min:0,max:100});setThermo(58); -/* N15 bourdon */ -let bV=45; -function setBour(v){bV=v;$('bourd').style.transform=`rotate(${-60+v/100*120}deg)`;setRd('N15',Math.round(v/100*160)+' PSI');} -dragDelta($('bourdon15'),()=>bV,setBour,{min:0,max:100});setBour(45); -/* N17 correlation */ -function setCorr(p){const v=(p-50)/50;$('corrn').style.transform=`rotate(${v*38}deg)`;setRd('N17',(v>=0?'+':'')+v.toFixed(2));} -dragX($('corr17'),setCorr);setCorr(58); -/* N18 battery */ -(function(){const bc=$('battc');for(let i=0;i<8;i++){const c=document.createElement('span');c.className='cell';bc.appendChild(c);}})(); -function setBatt(p){const cells=$('battc').children,lit=Math.round(p/100*cells.length); - for(let i=0;i<cells.length;i++)cells[i].className='cell'+(i<lit?' on':'')+((p<=25&&i<lit)?' warn':'');setRd('N18',Math.round(p)+'%');} -dragX($('batt18'),setBatt);setBatt(62); - -/* ============ INDICATOR WIRING ============ */ -/* 18 status lamp */ -(function(){const lst=['lamp','lamp gold','lamp red','lamp off','lamp busy'];const nm=['ok','engaged','fault','off','busy']; - $('lamp18').querySelectorAll('.lamp').forEach(l=>{l.style.cursor='pointer';l.onclick=()=>{ - let i=lst.indexOf(l.className);if(i<0)i=0;i=(i+1)%lst.length;l.className=lst[i];setRd('18',nm[i]);};});})(); -setRd('18','five states'); -/* 19 badge */ -(function(){const bv=['badge','badge red','badge ghost']; - $('badge19').querySelectorAll('.badge').forEach(b=>{b.style.cursor='pointer';b.onclick=()=>{ - let i=bv.indexOf(b.className);if(i<0)i=0;i=(i+1)%bv.length;b.className=bv[i];setRd('19',b.textContent);};});})(); -setRd('19','three variants'); -/* 21 engraved */ -let engN=3;$('engrave').onclick=()=>{engN=engN%9+1;$('engc').textContent='· '+engN;setRd('21','count '+engN);}; -setRd('21','count 3'); -/* 22 output well */ -const owSteps=[['gold','Probe','8.8.8.8 …'],['','Gateway','10.0.0.1 ok'],['','DNS','1.1.1.1 ok'],['red','Retry','timeout']];let owI=0; -$('owell').onclick=()=>{owI=(owI+1)%owSteps.length;const s=owSteps[owI];const d=document.createElement('div');d.className='ostep'; - d.innerHTML=`<span class="lamp ${s[0]}"></span><span><b>${s[1]}</b><span class="ev">${s[2]}</span></span>`; - $('owell').appendChild(d);while($('owell').children.length>5)$('owell').removeChild($('owell').firstChild);setRd('22','+ '+s[1]);}; -setRd('22','click to stream'); -/* 23 toast */ -const toastMsgs=['link up · 300 Mbps','bt paired — WH-1000XM4','profile switched','joined @Hyatt_WiFi — saved'];let toastN=0; -$('toast').onclick=()=>{toastN++;$('toast').textContent=toastMsgs[toastN%toastMsgs.length]; - $('toast').style.opacity='0';requestAnimationFrame(()=>{$('toast').style.transition='opacity .3s';$('toast').style.opacity='1';});setRd('23','fired '+toastN);}; -setRd('23','click to fire'); -/* 26 nixie */ -let nixV=8; -function setNix(v){nixV=v;const t=$('nixie').children,s=String(v).padStart(2,'0'); - t[0].classList.toggle('off',v<10);t[0].querySelector('b').textContent=s[0];t[1].querySelector('b').textContent=s[1];setRd('26',s);} -$('nixie').onclick=()=>setNix((nixV+1)%100);setNix(8); -/* 27 magic-eye */ -let meV=48; -function setEye(v){meV=v;$('meye').querySelector('.fan').style.setProperty('--gap',(8+(100-v)/100*118)+'deg');setRd('27',Math.round(v)+'%');} -dragDelta($('meye'),()=>meV,setEye,{min:0,max:100});setEye(48); -/* N23 annunciator */ -(function(){const st=['acell','acell warn','acell fault'];const nm=['ok','warn','fault']; - $('annun').querySelectorAll('.acell').forEach(cell=>{const label=cell.textContent;cell.onclick=()=>{ - let cur=cell.className.trim();let i=st.indexOf(cur);if(i<0)i=0;i=(i+1)%st.length;cell.className=st[i];setRd('N23',label+' → '+nm[i]);};});})(); -setRd('N23','click a cell'); -/* N24 jewel */ -(function(){const cols=['var(--jewel-r)','var(--jewel-a)','var(--jewel-g)'];const nm=['red','amber','green']; - $('jewels').querySelectorAll('.jewel').forEach(j=>{j.onclick=()=>{ - if(j.classList.contains('dim')){j.classList.remove('dim');j.style.setProperty('--jc',cols[0]);setRd('N24','red');return;} - let cur=j.style.getPropertyValue('--jc').trim();let i=cols.indexOf(cur); - if(i>=cols.length-1||i<0){j.classList.add('dim');setRd('N24','dark');}else{j.style.setProperty('--jc',cols[i+1]);setRd('N24',nm[i+1]);}};});})(); -setRd('N24','click to cycle'); -/* N27 frequency-dial + pointer */ -(function(){const fs=$('fscale');const W=184;const marks=[0.5,1,2,3,5,7,10,14,20];const lo=Math.log10(0.5),hi=Math.log10(20); - marks.forEach(m=>{const x=6+((Math.log10(m)-lo)/(hi-lo))*(W-12); - const tk=document.createElement('span');tk.className='tick';tk.style.left=x+'px';tk.style.height='11px';fs.appendChild(tk); - const mk=document.createElement('span');mk.className='mk';mk.style.left=x+'px';mk.textContent=m;fs.appendChild(mk);}); - for(let m=0.5;m<=20;m+=(m<2?0.25:m<10?1:2)){const x=6+((Math.log10(m)-lo)/(hi-lo))*(W-12); - const tk=document.createElement('span');tk.className='tick';tk.style.left=x+'px';tk.style.height='6px';tk.style.opacity='.5';fs.appendChild(tk);} - const ptr=document.createElement('span');ptr.className='fptr';fs.appendChild(ptr); - function freqAt(p){return Math.pow(10,lo+(p/100)*(hi-lo));} - window.setFreq=function(p){ptr.style.left=(6+p/100*(W-12))+'px';const f=freqAt(p);setRd('N27',(f<10?f.toFixed(1):Math.round(f))+' MHz');}; - dragX(fs,window.setFreq);window.setFreq(45);})(); -/* N28 patch-bay */ -(function(){const patch=$('patch');const rows=2,cols=4;const jacks=[]; - for(let r=0;r<rows;r++){const rowEl=document.createElement('div');rowEl.className='row'; - for(let c=0;c<cols;c++){const j=document.createElement('span');j.className='jack';j.dataset.id=(r*cols+c);rowEl.appendChild(j);jacks.push(j);} - patch.appendChild(rowEl);} - const svg=document.createElementNS('http://www.w3.org/2000/svg','svg');patch.appendChild(svg); - let conns=[];let pending=null; - function key(a,b){return Math.min(a,b)+'-'+Math.max(a,b);} - function draw(){while(svg.firstChild)svg.removeChild(svg.firstChild); - const pr=patch.getBoundingClientRect(); - jacks.forEach(j=>j.classList.remove('hot')); - conns.forEach(pair=>{const[a,b]=pair.split('-').map(Number); - const ra=jacks[a].getBoundingClientRect(),rb=jacks[b].getBoundingClientRect(); - const x1=ra.left-pr.left+ra.width/2,y1=ra.top-pr.top+ra.height/2; - const x2=rb.left-pr.left+rb.width/2,y2=rb.top-pr.top+rb.height/2; - const p=document.createElementNS('http://www.w3.org/2000/svg','path'); - const my=Math.max(y1,y2)+16;p.setAttribute('d',`M${x1} ${y1} C${x1} ${my} ${x2} ${my} ${x2} ${y2}`);svg.appendChild(p); - jacks[a].classList.add('hot');jacks[b].classList.add('hot');}); - setRd('N28',conns.length?conns.map(c=>{const[a,b]=c.split('-');return a+'↔'+b;}).join(' '):'no cables');} - jacks.forEach(j=>{j.onclick=()=>{const id=+j.dataset.id; - if(pending==null){pending=id;j.classList.add('sel');return;} - if(pending===id){pending=null;j.classList.remove('sel');return;} - const k=key(pending,id);const i=conns.indexOf(k);if(i>=0)conns.splice(i,1);else conns.push(k); - jacks[pending].classList.remove('sel');pending=null;draw();};}); - conns=['0-5','2-7'];draw();window.addEventListener('resize',draw);})(); - -/* ============ 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'; - for(let s=0;s<9;s++)band.appendChild(document.createElement('i'));eq.appendChild(band);}})(); -(function(){const cl=$('clock');for(let i=0;i<12;i++){const t=document.createElement('span');t.className='tk'; - t.style.transform=`rotate(${i*30}deg)`;cl.insertBefore(t,cl.firstChild);}})(); -const counterDigits=[4,7,1,3,0,0]; -(function(){const ct=$('counter');counterDigits.forEach((d,idx)=>{const w=document.createElement('span'); - w.className='cwheel'+(idx>=4?' redw':'');const col=document.createElement('span');col.className='col'; - for(let n=-1;n<=10;n++){const s=document.createElement('span');s.textContent=((n+10)%10);col.appendChild(s);} - w.appendChild(col);ct.appendChild(w);setWheel(w,d);});})(); -function setWheel(w,d){w.querySelector('.col').style.top=(-(d+1)*34)+'px';} - -let ph=0; -const hist=Array.from({length:40},()=>0.5); -const eqBands=Array.from({length:11},(_,i)=>({v:0.4,ph:i*0.6})); -const stripHist=Array.from({length:60},()=>31); -const pkL={v:0},pkR={v:0}; -function paintVU(el,l,pk){const b=el.children,n=b.length,lit=Math.round(l*n); - pk.v=Math.max(lit,(pk.v||0)-0.4);const p=Math.round(pk.v); - for(let k=0;k<n;k++){let c=k<lit?(k>=n-2?'clip':k>=n-4?'hot':'on'):'';if(p>0&&k===p-1)c=(c?c+' ':'')+'peak';b[k].className=c;}} -function paintMini(el,l){const b=el.children,lit=Math.round(l*4);for(let k=0;k<4;k++)b[k].className=k<lit?(k>=3?'clip':k>=2?'hot':'on'):'';} -function paintEq(){const bands=$('eq').children;let peak=0; - for(let b=0;b<bands.length;b++){const cells=bands[b].children,n=cells.length,val=eqBands[b].v;const lit=Math.round(val*n);peak=Math.max(peak,val); - for(let k=0;k<n;k++){let c='';if(k<lit)c=(k>=n-1?'clip':k>=n-3?'hot':'on');cells[k].className=c?c:'';}}return peak;} -function lvl(){return Math.max(0,Math.min(1,0.5+0.4*Math.sin(ph*1.3)+(Math.random()<0.15?Math.random()*0.4:0)-Math.random()*0.08));} -function fastTick(){ - ph+=0.09; - const a=lvl(),b=lvl(); - paintVU($('vuL'),a,pkL);paintVU($('vuR'),b,pkR);paintMini($('mini'),a); - setRd('11','L '+Math.round(a*100)+' · R '+Math.round(b*100)); - setRd('12',Math.round(a*100)+'%'); - hist.push(0.5+0.42*Math.sin(ph*0.9)+(Math.random()-0.5)*0.25);hist.shift(); - $('sparkp').setAttribute('points',hist.map((v,i)=>`${i/(hist.length-1)*170},${44-Math.max(0,Math.min(1,v))*40-2}`).join(' ')); - setRd('16',Math.round(Math.max(0,Math.min(1,hist[hist.length-1]))*100)); - let d='M0 19';const env=Math.min(1,0.6+0.3*Math.sin(ph*0.4)); - for(let x=0;x<=170;x+=3){const y=19+Math.sin(x*0.18+ph*3)*Math.sin(x*0.05)*14;d+=` L${x} ${y.toFixed(1)}`;} - $('wavep').setAttribute('d',d);setRd('17','amp '+Math.round(env*100)+'%'); - let sp='';for(let x=0;x<=176;x+=3){const y=39+Math.sin(x*0.16+ph*3.2)*Math.min(1,0.6+0.3*Math.sin(ph*0.4))*22;sp+=`${x},${y.toFixed(1)} `;} - $('scopep').setAttribute('points',sp.trim());setRd('N11','Vpp '+Math.round((0.6+0.3*Math.sin(ph*0.4))*100)); - eqBands.forEach(bd=>{bd.ph+=0.16;bd.v=Math.max(0.05,Math.min(1,0.5+0.42*Math.sin(bd.ph)+(Math.random()<0.2?Math.random()*0.3:0)-Math.random()*0.06));}); - const peak=paintEq();setRd('N12','peak '+Math.round(peak*100)+'%'); - stripHist.push(31-24*Math.sin(ph*0.7)*(0.6+0.4*Math.sin(ph*0.13))+(Math.random()-0.5)*4);stripHist.shift(); - const last=Math.max(3,Math.min(59,stripHist[stripHist.length-1])); - $('stripp').setAttribute('points',stripHist.map((v,i)=>`${i/(stripHist.length-1)*176},${Math.max(3,Math.min(59,v)).toFixed(1)}`).join(' ')); - $('strippen').style.top=last+'px';setRd('N16',Math.round((59-last)/56*100)); -} -/* clock */ -function tickClock(){const d=new Date();const s=d.getSeconds(),m=d.getMinutes(),h=d.getHours()%12; - $('clks').style.transform=`rotate(${s*6}deg)`;$('clkm').style.transform=`rotate(${m*6+s*0.1}deg)`;$('clkh').style.transform=`rotate(${h*30+m*0.5}deg)`; - setRd('N26',String(d.getHours()).padStart(2,'0')+':'+String(m).padStart(2,'0')+':'+String(s).padStart(2,'0'));} -/* split-flap */ -const flapWords=['DNS ','LINK','SYNC','WIFI','SCAN'];let flapI=0; -function tickFlap(){flapI=(flapI+1)%flapWords.length;const w=flapWords[flapI].padEnd(4,' '); - $('flap').querySelectorAll('.flapd').forEach((dd,i)=>{const ch=w[i]||' ';const bel=dd.querySelector('b'); - if(bel.textContent!==ch){bel.textContent=ch;if(!reduced){dd.classList.remove('flip');void dd.offsetWidth;dd.classList.add('flip');}}}); - setRd('N20',flapWords[flapI].trim());} -$('flap').onclick=tickFlap; -/* seven-segment countdown */ -let sevenSecs=24*60+10; -function renderSeven(){const mm=String(Math.floor(sevenSecs/60)).padStart(2,'0'),ss=String(sevenSecs%60).padStart(2,'0'); - $('seven').innerHTML=seg7(mm[0])+seg7(mm[1])+'<span class="colon"><i></i><i></i></span>'+seg7(ss[0])+seg7(ss[1]);setRd('N21',mm+':'+ss);} -function tickSeven(){sevenSecs=(sevenSecs-1+3600)%3600;renderSeven();} -$('seven').onclick=()=>{sevenSecs=(sevenSecs+60)%3600;renderSeven();}; -renderSeven(); -/* tabular timer */ -let tSecs=24*60+10,tRun=true; -function renderT(){$('treadout').textContent=String(Math.floor(tSecs/60)).padStart(2,'0')+':'+String(tSecs%60).padStart(2,'0'); - setRd('20',tRun?'running':'paused');} -function tickT(){if(tRun){tSecs=(tSecs-1+3600)%3600;renderT();}} -$('treadout').onclick=()=>{tRun=!tRun;renderT();};renderT(); -/* VFD marquee */ -const vfdMsgs=['ARCHSETUP · NET OK · BT 2 · SND 62%','WIFI @Hyatt · 300 Mbps · VPN UP','BATTERY 84% · DISK 61% · TEMP 47C'];let vfdMi=0,vfdX=176; -function tickVfd(){const t=$('vfdt');vfdX-=1.1;if(vfdX< -t.offsetWidth)vfdX=176;t.style.left=vfdX+'px';} -$('vfdm').onclick=()=>{vfdMi=(vfdMi+1)%vfdMsgs.length;$('vfdt').textContent=vfdMsgs[vfdMi];vfdX=176;setRd('N22','msg '+(vfdMi+1)+'/'+vfdMsgs.length);}; -setRd('N22','scrolling'); -/* tape counter */ -let ctrVal=471300; -function tickCounter(){ctrVal+=137;const s=String(ctrVal).padStart(6,'0'); - $('counter').querySelectorAll('.cwheel').forEach((w,i)=>setWheel(w,+s[i]));setRd('N25',s);} -setRd('N25',String(ctrVal).padStart(6,'0')); - -/* reels spin keyframe */ -(function(){const st=document.createElement('style');st.textContent='@keyframes reelspin{to{transform:rotate(360deg)}}';document.head.appendChild(st);})(); -document.querySelectorAll('.reel.spin').forEach(r=>{r.style.animation='reelspin 2.6s linear infinite';}); - -/* static paint for reduced motion */ -function paintStatic(){ - paintVU($('vuL'),0.55,pkL);paintVU($('vuR'),0.5,pkR);paintMini($('mini'),0.55); - setRd('11','L 55 · R 50');setRd('12','55%'); - $('sparkp').setAttribute('points',hist.map((v,i)=>`${i/(hist.length-1)*170},${44-0.5*40-2}`).join(' '));setRd('16','50'); - $('wavep').setAttribute('d','M0 19 L170 19');setRd('17','amp 60%'); - eqBands.forEach((bd,i)=>bd.v=0.3+0.5*Math.abs(Math.sin(i*0.9)));setRd('N12','peak '+Math.round(paintEq()*100)+'%'); - $('scopep').setAttribute('points',Array.from({length:60},(_,i)=>`${i*3},${39+Math.sin(i*0.5)*18}`).join(' '));setRd('N11','Vpp 74'); - $('stripp').setAttribute('points',stripHist.map((v,i)=>`${i/(stripHist.length-1)*176},${31-Math.sin(i*0.3)*16}`).join(' '));setRd('N16','50'); - tickClock();renderSeven();setRd('N20','DNS');setRd('N22','scrolling');setRd('N25',String(ctrVal).padStart(6,'0')); -} - -if(!reduced){ - setInterval(fastTick,80); - setInterval(tickClock,1000);tickClock(); - setInterval(tickFlap,1500); - setInterval(tickVfd,32); - setInterval(tickCounter,1600); - setInterval(tickSeven,1000); - setInterval(tickT,1000); - document.querySelectorAll('.reel.spin').forEach(r=>r.style.animationPlayState='running'); -}else{ - paintStatic(); - document.querySelectorAll('.reel.spin').forEach(r=>r.style.animationPlayState='paused'); -} -</script> -</body> -</html> |
