77a757cee6
- Fix dashboard 500 when deps disconnected — _gather_state() now returns
full defaults instead of bare {'connected': False}
- Phase 2: FX param schemas aligned with DSP implementations
- Phase 7: Pipeline routing, preset manager improvements
- Factory presets: cleanup and normalization
Fixes dashboard crash on disconnected state (dogfood issue #1)
566 lines
18 KiB
HTML
566 lines
18 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Pi Multi-FX Pedal — UI Mockup Template</title>
|
||
<style>
|
||
/* Figma-like canvas */
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||
background: #1e1e1e;
|
||
display: flex;
|
||
justify-content: center;
|
||
padding: 40px 20px;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
.canvas {
|
||
background: #2c2c2c;
|
||
border-radius: 12px;
|
||
padding: 40px;
|
||
width: 1080px;
|
||
box-shadow: 0 8px 32px rgba(0,0,0,0.5);
|
||
}
|
||
.canvas-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 24px;
|
||
color: #888;
|
||
font-size: 12px;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
.canvas-header h1 {
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: #aaa;
|
||
}
|
||
.canvas-header span {
|
||
color: #666;
|
||
}
|
||
|
||
/* Frame styles — like Figma frames */
|
||
.frame {
|
||
background: #3a3a3a;
|
||
border: 1px solid #4a4a4a;
|
||
border-radius: 8px;
|
||
padding: 16px;
|
||
margin-bottom: 24px;
|
||
position: relative;
|
||
}
|
||
.frame-label {
|
||
position: absolute;
|
||
top: -8px;
|
||
left: 12px;
|
||
background: #3a3a3a;
|
||
padding: 0 6px;
|
||
font-size: 10px;
|
||
color: #888;
|
||
letter-spacing: 0.3px;
|
||
font-weight: 500;
|
||
}
|
||
.frame-title {
|
||
font-size: 11px;
|
||
color: #999;
|
||
margin-bottom: 12px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
|
||
/* Device screen mockup */
|
||
.device {
|
||
display: flex;
|
||
gap: 24px;
|
||
margin-bottom: 24px;
|
||
}
|
||
.touchscreen {
|
||
background: #1a1a2e;
|
||
border: 2px solid #555;
|
||
border-radius: 12px;
|
||
padding: 16px;
|
||
width: 480px;
|
||
height: 320px;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.touchscreen .status-bar {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-size: 10px;
|
||
color: #666;
|
||
margin-bottom: 8px;
|
||
padding-bottom: 6px;
|
||
border-bottom: 1px solid #2a2a3e;
|
||
}
|
||
|
||
/* UI elements on the screen */
|
||
.ui-rig {
|
||
display: flex;
|
||
gap: 6px;
|
||
margin-bottom: 10px;
|
||
}
|
||
.amp-block {
|
||
background: #2a2a4a;
|
||
border-radius: 6px;
|
||
padding: 8px;
|
||
flex: 1;
|
||
text-align: center;
|
||
}
|
||
.amp-block .knob {
|
||
width: 24px;
|
||
height: 24px;
|
||
border-radius: 50%;
|
||
background: #444;
|
||
margin: 0 auto 4px;
|
||
border: 2px solid #666;
|
||
cursor: grab;
|
||
}
|
||
.amp-block .knob-label {
|
||
font-size: 7px;
|
||
color: #888;
|
||
}
|
||
.amp-block .value {
|
||
font-size: 8px;
|
||
color: #aaa;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
/* FX chain row */
|
||
.fx-chain {
|
||
display: flex;
|
||
gap: 4px;
|
||
margin: 10px 0;
|
||
}
|
||
.fx-block {
|
||
background: #2a2a3a;
|
||
border-radius: 4px;
|
||
padding: 6px 8px;
|
||
font-size: 8px;
|
||
color: #ccc;
|
||
text-align: center;
|
||
flex: 1;
|
||
border: 1px solid #3a3a4a;
|
||
min-width: 60px;
|
||
}
|
||
.fx-block.active {
|
||
border-color: #4a9;
|
||
background: #1a3a2a;
|
||
}
|
||
.fx-block.bypassed {
|
||
opacity: 0.4;
|
||
}
|
||
|
||
/* Tuner overlay */
|
||
.tuner-overlay {
|
||
position: absolute;
|
||
top: 0; left: 0; right: 0; bottom: 0;
|
||
background: rgba(0,0,0,0.85);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.tuner-note {
|
||
font-size: 48px;
|
||
color: #4a9;
|
||
font-weight: 700;
|
||
letter-spacing: 4px;
|
||
}
|
||
.tuner-meter {
|
||
width: 200px;
|
||
height: 4px;
|
||
background: #333;
|
||
border-radius: 2px;
|
||
margin-top: 12px;
|
||
position: relative;
|
||
}
|
||
.tuner-meter .indicator {
|
||
position: absolute;
|
||
left: 48%;
|
||
width: 4px;
|
||
height: 4px;
|
||
background: #4a9;
|
||
border-radius: 2px;
|
||
}
|
||
|
||
/* Footswitch row */
|
||
.footswitch-row {
|
||
display: flex;
|
||
gap: 12px;
|
||
margin-top: 12px;
|
||
justify-content: center;
|
||
}
|
||
.footswitch {
|
||
width: 44px;
|
||
height: 44px;
|
||
border-radius: 50%;
|
||
background: #333;
|
||
border: 2px solid #555;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 8px;
|
||
color: #aaa;
|
||
cursor: pointer;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.4), inset 0 -2px 4px rgba(0,0,0,0.3);
|
||
}
|
||
.footswitch.active {
|
||
border-color: #4a9;
|
||
color: #4a9;
|
||
box-shadow: 0 0 12px rgba(68, 153, 153, 0.3);
|
||
}
|
||
|
||
/* Label / shape palette (Figa element toolbox) */
|
||
.palette {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
padding: 12px;
|
||
background: #333;
|
||
border-radius: 6px;
|
||
margin-bottom: 16px;
|
||
}
|
||
.palette-label {
|
||
font-size: 10px;
|
||
color: #888;
|
||
width: 100%;
|
||
margin-bottom: 4px;
|
||
}
|
||
.palette-item {
|
||
background: #444;
|
||
border-radius: 4px;
|
||
padding: 6px 10px;
|
||
font-size: 10px;
|
||
color: #ccc;
|
||
cursor: grab;
|
||
border: 1px solid transparent;
|
||
}
|
||
.palette-item.shape {
|
||
background: #3a3a5a;
|
||
border-color: #5a5a8a;
|
||
}
|
||
.palette-item.text {
|
||
background: #3a4a3a;
|
||
border-color: #5a8a5a;
|
||
}
|
||
.palette-item.knob {
|
||
background: #4a3a3a;
|
||
border-color: #8a5a5a;
|
||
}
|
||
|
||
/* Schematic layout area */
|
||
.schematic {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 16px;
|
||
margin-top: 8px;
|
||
}
|
||
.schematic .column {
|
||
background: #333;
|
||
border-radius: 6px;
|
||
padding: 12px;
|
||
min-height: 160px;
|
||
}
|
||
.schematic .column-title {
|
||
font-size: 10px;
|
||
color: #777;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
/* Annotation arrows */
|
||
.arrow-annotation {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
color: #666;
|
||
font-size: 10px;
|
||
margin: 4px 0;
|
||
}
|
||
.arrow-line {
|
||
flex: 1;
|
||
height: 1px;
|
||
background: #555;
|
||
position: relative;
|
||
}
|
||
.arrow-line::after {
|
||
content: '▶';
|
||
position: absolute;
|
||
right: -12px;
|
||
top: -6px;
|
||
font-size: 8px;
|
||
color: #666;
|
||
}
|
||
|
||
/* Four-cable method diagram */
|
||
.signal-flow {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8px;
|
||
padding: 16px;
|
||
background: #2a2a2a;
|
||
border-radius: 6px;
|
||
margin-bottom: 16px;
|
||
}
|
||
.signal-flow .node {
|
||
background: #444;
|
||
border-radius: 4px;
|
||
padding: 6px 10px;
|
||
font-size: 9px;
|
||
color: #aaa;
|
||
text-align: center;
|
||
min-width: 60px;
|
||
}
|
||
.signal-flow .arrow {
|
||
color: #666;
|
||
font-size: 14px;
|
||
}
|
||
.signal-flow .split {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
/* Colors */
|
||
.color-swatches {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin: 8px 0;
|
||
}
|
||
.swatch {
|
||
width: 24px;
|
||
height: 24px;
|
||
border-radius: 4px;
|
||
border: 1px solid #555;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="canvas">
|
||
<div class="canvas-header">
|
||
<h1>🎛️ Pi Multi-FX Pedal UI — Figma Template</h1>
|
||
<span>v1 · 480×320 touchscreen · 4.3" DSI</span>
|
||
</div>
|
||
|
||
<!-- Color palette -->
|
||
<div class="frame" style="margin-bottom: 16px;">
|
||
<div class="frame-label">COLORS</div>
|
||
<div class="color-swatches">
|
||
<div class="swatch" style="background:#1a1a2e;" title="Screen BG"></div>
|
||
<div class="swatch" style="background:#2a2a4a;" title="Card bg"></div>
|
||
<div class="swatch" style="background:#4a9;" title="Accent green"></div>
|
||
<div class="swatch" style="background:#e85;" title="Warning orange"></div>
|
||
<div class="swatch" style="background:#f44;" title="Clip red"></div>
|
||
<div class="swatch" style="background:#48f;" title="Blue (MIDI)"></div>
|
||
<div class="swatch" style="background:#888;" title="Text muted"></div>
|
||
<div class="swatch" style="background:#ccc;" title="Text primary"></div>
|
||
</div>
|
||
<div style="font-size:9px; color:#666; margin-top:4px;">bg=#1a1a2e · card=#2a2a4a · accent=#44aa99 · warn=#ee8855 · clip=#ff4444 · midi=#4488ff</div>
|
||
</div>
|
||
|
||
<!-- Element palette -->
|
||
<div class="palette">
|
||
<div class="palette-label">🧩 ELEMENTS</div>
|
||
<div class="palette-item shape">▭ Knob (48×48)</div>
|
||
<div class="palette-item shape">▭ FX Block (72×48)</div>
|
||
<div class="palette-item shape">▭ Footswitch ⏺</div>
|
||
<div class="palette-item text">T Title</div>
|
||
<div class="palette-item text">T Label 10px</div>
|
||
<div class="palette-item text">T Value 8px</div>
|
||
<div class="palette-item knob">📊 VU Meter</div>
|
||
<div class="palette-item knob">📡 Tuner</div>
|
||
<div class="palette-item shape">▭ Preset Slot</div>
|
||
<div class="palette-item shape">▭ Divider</div>
|
||
</div>
|
||
|
||
<!-- Device preview -->
|
||
<div class="frame">
|
||
<div class="frame-label">MAIN SCREEN — RIG VIEW</div>
|
||
<div class="device">
|
||
<div class="touchscreen">
|
||
<div class="status-bar">
|
||
<span>🔊 Preset 03 — Crunch</span>
|
||
<span>⚡ 34% | 🎛️ BNK 1</span>
|
||
</div>
|
||
|
||
<!-- Amp section -->
|
||
<div class="frame-title">AMP</div>
|
||
<div class="ui-rig">
|
||
<div class="amp-block"><div class="knob"></div><div class="knob-label">GAIN</div><div class="value">68</div></div>
|
||
<div class="amp-block"><div class="knob"></div><div class="knob-label">BASS</div><div class="value">52</div></div>
|
||
<div class="amp-block"><div class="knob"></div><div class="knob-label">MID</div><div class="value">45</div></div>
|
||
<div class="amp-block"><div class="knob"></div><div class="knob-label">TREBLE</div><div class="value">61</div></div>
|
||
<div class="amp-block"><div class="knob"></div><div class="knob-label">VOL</div><div class="value">72</div></div>
|
||
</div>
|
||
|
||
<!-- FX chain -->
|
||
<div class="frame-title">FX CHAIN</div>
|
||
<div class="fx-chain">
|
||
<div class="fx-block active">🎸 NS Gate</div>
|
||
<div class="fx-block active">🔊 Comp</div>
|
||
<div class="fx-block active">🔥 OD</div>
|
||
<div class="fx-block bypassed">🌀 Chorus</div>
|
||
<div class="fx-block active">⏳ Delay</div>
|
||
<div class="fx-block active">🌊 Reverb</div>
|
||
</div>
|
||
|
||
<!-- Footswitch indicators -->
|
||
<div class="footswitch-row">
|
||
<div class="footswitch active">A</div>
|
||
<div class="footswitch">B</div>
|
||
<div class="footswitch">C</div>
|
||
<div class="footswitch">D</div>
|
||
<div class="footswitch">▲</div>
|
||
<div class="footswitch">▼</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Side annotation -->
|
||
<div style="flex:1; padding: 8px;">
|
||
<div class="frame-title" style="color:#777;">SCREEN LAYOUT</div>
|
||
<div class="arrow-annotation"><span>Status bar</span><div class="arrow-line"></div><span style="color:#aaa;">preset name + CPU</span></div>
|
||
<div class="arrow-annotation"><span>AMP section</span><div class="arrow-line"></div><span style="color:#aaa;">5 knobs, values inline</span></div>
|
||
<div class="arrow-annotation"><span>FX chain row</span><div class="arrow-line"></div><span style="color:#aaa;">scrollable, active/bypassed</span></div>
|
||
<div class="arrow-annotation"><span>Footswitch bar</span><div class="arrow-line"></div><span style="color:#aaa;">A-D + bank nav</span></div>
|
||
<div style="margin-top:16px; border-top:1px solid #3a3a3a; padding-top:12px;">
|
||
<div class="frame-title" style="color:#777;">ALTERNATE SCREENS</div>
|
||
<div style="display:flex; gap:8px; flex-wrap:wrap;">
|
||
<div class="palette-item">🎛️ FX Edit</div>
|
||
<div class="palette-item">📋 Presets</div>
|
||
<div class="palette-item">🎸 Captures</div>
|
||
<div class="palette-item">🏚️ IRs</div>
|
||
<div class="palette-item">⚙️ Settings</div>
|
||
<div class="palette-item">📡 Tuner</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Signal flow diagram -->
|
||
<div class="frame">
|
||
<div class="frame-label">SIGNAL FLOW — 4CM</div>
|
||
<div class="signal-flow">
|
||
<div class="node">🎸 Guitar</div>
|
||
<div class="arrow">→</div>
|
||
<div class="node">Noise Gate</div>
|
||
<div class="arrow">→</div>
|
||
<div class="node">Compressor</div>
|
||
<div class="arrow">→</div>
|
||
<div class="node">OD / Dist</div>
|
||
<div class="arrow">→</div>
|
||
<div class="split">
|
||
<div style="display:flex; gap:4px;">
|
||
<div class="node" style="background:#3a3a5a;">PRE blocks</div>
|
||
<div class="arrow">→</div>
|
||
<div class="node" style="border-color:#4a9;">SEND → Amp</div>
|
||
</div>
|
||
<div style="display:flex; gap:4px; margin-top:4px;">
|
||
<div class="node" style="border-color:#4a9;">RETURN ← FX</div>
|
||
<div class="arrow">→</div>
|
||
<div class="node" style="background:#3a3a5a;">POST blocks</div>
|
||
</div>
|
||
</div>
|
||
<div class="arrow">→</div>
|
||
<div class="node">Delay</div>
|
||
<div class="arrow">→</div>
|
||
<div class="node">Reverb</div>
|
||
<div class="arrow">→</div>
|
||
<div class="node">🔊 Output</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- FX Edit screen -->
|
||
<div class="schematic">
|
||
<div class="column">
|
||
<div class="column-title">🎛️ FX EDIT PANEL (tap a block)</div>
|
||
<div style="display:flex; gap:6px; flex-wrap:wrap;">
|
||
<div class="amp-block" style="width:56px;"><div class="knob" style="width:28px;height:28px;"></div><div class="knob-label">MIX</div></div>
|
||
<div class="amp-block" style="width:56px;"><div class="knob" style="width:28px;height:28px;"></div><div class="knob-label">TIME</div></div>
|
||
<div class="amp-block" style="width:56px;"><div class="knob" style="width:28px;height:28px;"></div><div class="knob-label">FDBK</div></div>
|
||
<div class="amp-block" style="width:56px;"><div class="knob" style="width:28px;height:28px;"></div><div class="knob-label">TONE</div></div>
|
||
</div>
|
||
<div style="font-size:9px;color:#666;margin-top:8px;">Per-FX params from block-params schema</div>
|
||
</div>
|
||
<div class="column">
|
||
<div class="column-title">📋 PRESET BROWSER</div>
|
||
<div style="display:flex; flex-direction:column; gap:4px;">
|
||
<div style="background:#2a2a4a; border-radius:4px; padding:6px 8px; display:flex; justify-content:space-between;">
|
||
<span style="color:#4a9; font-size:10px;">01 Clean</span>
|
||
<span style="color:#666; font-size:9px;">Fender Twin</span>
|
||
</div>
|
||
<div style="background:#2a2a4a; border-radius:4px; padding:6px 8px; display:flex; justify-content:space-between;">
|
||
<span style="color:#ccc; font-size:10px;">02 Blues</span>
|
||
<span style="color:#666; font-size:9px;">Marshall Bluesbreaker</span>
|
||
</div>
|
||
<div style="background:#3a3a5a; border-radius:4px; padding:6px 8px; display:flex; justify-content:space-between; border:1px solid #4a9;">
|
||
<span style="color:#4a9; font-size:10px; font-weight:600;">03 Crunch</span>
|
||
<span style="color:#666; font-size:9px;">▶ Playing</span>
|
||
</div>
|
||
<div style="background:#2a2a4a; border-radius:4px; padding:6px 8px; display:flex; justify-content:space-between;">
|
||
<span style="color:#666; font-size:10px; opacity:0.6;">04 Lead</span>
|
||
<span style="color:#555; font-size:9px;">——</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- VU Meter component -->
|
||
<div class="frame" style="margin-top: 16px;">
|
||
<div class="frame-label">VU METERS</div>
|
||
<div style="display:flex; gap:24px; align-items:center;">
|
||
<div style="flex:1;">
|
||
<div style="font-size:9px; color:#777; margin-bottom:4px;">INPUT</div>
|
||
<div style="display:flex; gap:2px; align-items:flex-end; height:40px;">
|
||
<div style="width:8px; background:#4a9; height:24px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#4a9; height:28px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#4a9; height:20px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#4a9; height:32px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#4a9; height:26px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#4a9; height:16px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#e85; height:10px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#e85; height:6px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#f44; height:3px; border-radius:2px;"></div>
|
||
</div>
|
||
</div>
|
||
<div style="flex:1;">
|
||
<div style="font-size:9px; color:#777; margin-bottom:4px;">OUTPUT</div>
|
||
<div style="display:flex; gap:2px; align-items:flex-end; height:40px;">
|
||
<div style="width:8px; background:#4a9; height:28px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#4a9; height:32px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#4a9; height:36px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#4a9; height:30px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#4a9; height:22px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#4a9; height:14px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#e85; height:8px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#f44; height:4px; border-radius:2px;"></div>
|
||
<div style="width:8px; background:#f44; height:2px; border-radius:2px;"></div>
|
||
</div>
|
||
</div>
|
||
<div style="border-left:1px solid #3a3a3a; padding-left:16px;">
|
||
<div style="font-size:9px; color:#777;">PEAK</div>
|
||
<div style="font-size:18px; color:#4a9; font-weight:700;">-6.2</div>
|
||
<div style="font-size:9px; color:#666;">dBu</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Notes -->
|
||
<div style="margin-top:16px; padding:12px; background:#2a2a2a; border-radius:6px; border-left: 3px solid #4a9;">
|
||
<div style="font-size:10px; color:#888; font-weight:600; margin-bottom:4px;">📝 DESIGN NOTES</div>
|
||
<div style="font-size:10px; color:#666; line-height:1.6;">
|
||
• Screen: 480×320 @ 4.3" DSI — design at 1x, renders pixel-perfect on the LCD<br>
|
||
• Color scheme: dark bg (#1a1a2e) with green accent (#4a9) for active state<br>
|
||
• Knobs: 48×48px on touch targets (Fitts-friendly), 24×24px in the mockup here<br>
|
||
• FX chain row scrolls horizontally if >6 blocks — indicator dots at bottom<br>
|
||
• Status bar: preset name left, CPU/memory right. Red if >80% CPU<br>
|
||
• Footswitch row doubles as page indicator (active = current screen)<br>
|
||
• 4CM mode shows SEND/RETURN labels on the split point in the FX chain
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>
|