aboutsummaryrefslogtreecommitdiff
path: root/docs/prototypes/2026-07-02-desktop-settings-panel-prototype-11.html
diff options
context:
space:
mode:
Diffstat (limited to 'docs/prototypes/2026-07-02-desktop-settings-panel-prototype-11.html')
-rw-r--r--docs/prototypes/2026-07-02-desktop-settings-panel-prototype-11.html205
1 files changed, 205 insertions, 0 deletions
diff --git a/docs/prototypes/2026-07-02-desktop-settings-panel-prototype-11.html b/docs/prototypes/2026-07-02-desktop-settings-panel-prototype-11.html
new file mode 100644
index 0000000..d58fbfc
--- /dev/null
+++ b/docs/prototypes/2026-07-02-desktop-settings-panel-prototype-11.html
@@ -0,0 +1,205 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Desktop Settings — Prototype 11 (mixing desk, Dupre Kit)</title>
+<link rel="stylesheet" href="desktop-settings-shared.css">
+<style>
+ :root{
+ --ground:#151311; --panel:#100f0f; --well:#0a0c0d; --raise:#1a1917;
+ --silver:#bfc4d0; --cream:#f3e7c5; --steel:#969385; --dim:#7c838a;
+ --slate:#424f5e; --slate-hi:#54677d; --wash:#2c2f32;
+ --pass:#74932f; --fail:#cb6b4d;
+ --phos:#7fe0a0; --phos-dim:#1c3626; --vfd:#63e6c8;
+ --sevgrn:#57d357; --sevred:#e2543f; --sevoff:#1a1613;
+ --jewel-r:#ff5b45; --jewel-a:#ffb43a; --jewel-g:#6fce33;
+ --gold:#e2a038; --gold-hi:#ffbe54;
+ --amber-grad-top:#f2c76a; --amber-grad-mid:#d29638; --amber-grad-bot:#8f671f;
+ --amber-edge:#7d5c16; --amber-warn:#f0b552;
+ --glow-hi:255,190,84; --glow-lo:226,160,56;
+ --mono:"BerkeleyMono Nerd Font","Berkeley Mono",monospace;
+ --pulse-rate:1s;
+ }
+ .row { display: flex; justify-content: center; align-items: flex-start; gap: 10px; flex-wrap: wrap; }
+ .dupre-rotsel, .dupre-keylock { display: inline-block; }
+ .cellcap { color: var(--steel); font-size: 8.5px; letter-spacing: 0.12em; text-align: center; margin-top: 2px; text-transform: uppercase; }
+ .fader-cell { display: flex; flex-direction: column; align-items: center; }
+ .chips { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
+ .vu-well { display: flex; justify-content: center; padding: 2px 0 6px; }
+ .stomp-cell { display: flex; flex-direction: column; align-items: center; }
+</style>
+</head>
+<body class="ds-stage">
+ <div class="ds-caption">
+ <b>Direction 11 — Mixing desk (Dupre Kit).</b> Channel strips: slot faders
+ ride the two levels in dB (the VU bridge follows), scenes punch in on the
+ radio preset bank, toggles are lit chips with DND on a stomp pedal, power
+ is a rotary selector. Lock/suspend/wallpaper are arm-to-fire.
+ </div>
+
+ <div class="ds-bar"><span>19:24</span><span class="gear">⚙</span></div>
+
+ <div class="ds-panel" id="panel">
+ <div class="ds-face">
+ <span class="glyph">⚙</span>
+ <span class="title">Settings</span>
+ <span class="sub" id="scene-sub"></span>
+ <span class="x">✕</span>
+ </div>
+ <div id="body"></div>
+ <div class="ds-toast" id="toast"></div>
+ <div class="ds-subview" id="subview"></div>
+ </div>
+
+<script src="widgets.js"></script>
+<script src="desktop-settings-shared.js"></script>
+<script>
+const h = DS.h;
+const body = document.getElementById("body");
+const subview = document.getElementById("subview");
+DS.bindToast(document.getElementById("toast"));
+
+const SCENES = Object.keys(DS.SCENES);
+const BANK = ["OFF", "FOCUS", "PRESNT", "BATT", "NIGHT"];
+const CHIPS = [
+ ["autodim", "DIM"], ["caffeine", "CAFF"], ["touchpad", "TPAD"], ["mouse", "MOUSE"],
+ ["nightlight", "NIGHT"], ["weathergeo", "WXGEO"], ["airplane", "AIR"],
+];
+const dbOf = (pct) => -24 + (pct / 100) * 36;
+const pctOf = (db) => Math.round(((db + 24) / 36) * 100);
+let booting = true;
+
+function openWallpaper() {
+ subview.innerHTML = "";
+ subview.appendChild(DS.wallpaperSubview(() => subview.classList.remove("open")));
+ subview.classList.add("open");
+}
+
+function sceneOff() {
+ DS.state.scene = null;
+ DS.toast("Scene: off", true);
+ render();
+}
+
+const debounce = (fn, ms) => { let t; return (...a) => { clearTimeout(t); t = setTimeout(() => fn(...a), ms); }; };
+
+function render() {
+ booting = true;
+ body.innerHTML = "";
+ const col = h("div", "ds-col");
+
+ // VU bridge + channel faders.
+ col.appendChild(DS.engrave("Channel strips — levels"));
+ const vuWell = h("div", "vu-well");
+ const vu = DUPRE.vuPair(vuWell, {});
+ vu.set(DS.state.brightness / 100, DS.state.kbd / 100);
+ col.appendChild(vuWell);
+
+ const fRow = h("div", "row");
+ [["brightness", "BRIGHT", 0], ["kbd", "KBD", 1]].forEach(([key, label, ch]) => {
+ const cell = h("div", "fader-cell");
+ const host = h("div");
+ const commit = debounce((db) => {
+ const pct = Math.max(DS.SLIDERS[key].floor, pctOf(db));
+ if (pct !== DS.state[key]) DS.setSlider(key, pct, cell);
+ }, 350);
+ DUPRE.slotFader(host, {
+ value: dbOf(DS.state[key]),
+ onChange: (db) => {
+ if (booting) return;
+ const l = ch === 0 ? Math.max(0, Math.min(1, pctOf(db) / 100)) : DS.state.brightness / 100;
+ const r = ch === 1 ? Math.max(0, Math.min(1, pctOf(db) / 100)) : DS.state.kbd / 100;
+ vu.set(l, r);
+ commit(db);
+ },
+ });
+ cell.appendChild(host);
+ cell.appendChild(h("div", "cellcap", label));
+ fRow.appendChild(cell);
+ });
+ col.appendChild(fRow);
+
+ // Scenes: punch a preset.
+ col.appendChild(DS.engrave("Presets — scenes"));
+ const pbHost = h("div");
+ DUPRE.presetBank(pbHost, {
+ items: BANK,
+ active: DS.state.scene ? SCENES.indexOf(DS.state.scene) + 1 : 0,
+ onChange: (i) => {
+ if (booting) return;
+ if (i === 0) sceneOff();
+ else DS.applyScene(SCENES[i - 1], pbHost);
+ },
+ });
+ col.appendChild(pbHost);
+
+ // Toggles: lit chips; DND gets the stomp pedal.
+ col.appendChild(DS.engrave("Mutes — toggles"));
+ const chips = h("div", "chips");
+ CHIPS.filter(([k]) => k !== "airplane" || DS.state.laptop).forEach(([k, label]) => {
+ const host = h("span");
+ DUPRE.chipToggle(host, {
+ label,
+ on: DS.state[k],
+ accent: k === "airplane" ? "red" : "amber",
+ onChange: (on) => { if (!booting && on !== DS.state[k]) DS.setToggle(k, host); },
+ });
+ chips.appendChild(host);
+ });
+ col.appendChild(chips);
+
+ const sRow = h("div", "row");
+ const sCell = h("div", "stomp-cell");
+ const sHost = h("div");
+ DUPRE.stompSwitch(sHost, {
+ on: DS.state.dnd,
+ onChange: (on) => { if (!booting && on !== DS.state.dnd) DS.setToggle("dnd", sCell); },
+ });
+ sCell.appendChild(sHost);
+ sCell.appendChild(h("div", "cellcap", "DND — stomp to silence"));
+ sRow.appendChild(sCell);
+
+ // Power beside the pedal: rotary selector.
+ const pCell = h("div", "stomp-cell");
+ const rHost = h("div");
+ DUPRE.rotarySelector(rHost, {
+ values: ["PERF", "BAL", "SAVER"],
+ index: DS.PROFILES.findIndex((p) => p.id === DS.state.powerprofile),
+ onChange: (v) => {
+ if (booting) return;
+ const i = ["PERF", "BAL", "SAVER"].indexOf(v);
+ if (i >= 0) DS.setProfile(DS.PROFILES[i].id, pCell);
+ },
+ });
+ pCell.appendChild(rHost);
+ pCell.appendChild(h("div", "cellcap", "POWER"));
+ sRow.appendChild(pCell);
+ col.appendChild(sRow);
+
+ // Actions: arm-to-fire.
+ col.appendChild(DS.engrave("Actions"));
+ const aRow = h("div", "row");
+ [["LOCK", () => DS.momentary("Lock")],
+ ["SUSPEND", () => DS.momentary("Suspend")],
+ ["WALLPAPER", openWallpaper]].forEach(([label, fn]) => {
+ const host = h("div");
+ DUPRE.armButton(host, {
+ label,
+ armLabel: label + "?",
+ onChange: (st) => { if (!booting && st === "fired") fn(); },
+ });
+ aRow.appendChild(host);
+ });
+ col.appendChild(aRow);
+
+ body.appendChild(col);
+ document.getElementById("scene-sub").textContent = DS.state.scene ? "▶ " + DS.state.scene : "";
+ booting = false;
+}
+
+DS.onChange(render);
+render();
+</script>
+</body>
+</html>