|
| 1 | +# ADR-053: UI Design System — Foundation Book + Unity-Inspired Interface |
| 2 | + |
| 3 | +| Field | Value | |
| 4 | +|-------|-------| |
| 5 | +| Status | Proposed | |
| 6 | +| Date | 2026-03-06 | |
| 7 | +| Deciders | ruv | |
| 8 | +| Depends on | ADR-052 (Tauri Desktop Frontend) | |
| 9 | + |
| 10 | +## Context |
| 11 | + |
| 12 | +RuView Desktop (ADR-052) needs a UI design system that communicates authority, precision, and control — befitting a hardware management control plane for embedded sensing infrastructure. The interface must handle dense data (CSI heatmaps, node registries, log streams, mesh topologies) without feeling overwhelming, while remaining usable by both engineers and field operators. |
| 13 | + |
| 14 | +Two established design languages map to this requirement: |
| 15 | + |
| 16 | +1. **Foundation Book** — clean typographic hierarchy, structured layouts, modular card systems, and professional content presentation. Foundation's grid system and component philosophy prioritize clarity and scanability. |
| 17 | + |
| 18 | +2. **Unity Editor** — dockable panel system, inspector/hierarchy/scene separation, property grids, dark professional theme, and dense-but-organized data display. Unity's UI is purpose-built for managing complex real-time systems — exactly what RuView is. |
| 19 | + |
| 20 | +The combination yields an interface that reads like a professional technical reference (Foundation Book) but operates like a real-time system control panel (Unity Editor). |
| 21 | + |
| 22 | +## Decision |
| 23 | + |
| 24 | +### Design Principles |
| 25 | + |
| 26 | +1. **Content-first typography** — Headings establish hierarchy. Data is always the hero, not decoration. |
| 27 | +2. **Panel-based layout** — Resizable, collapsible panels inspired by Unity's docking system. |
| 28 | +3. **Dark professional theme** — Dark backgrounds (#1a1a2e, #16213e) with high-contrast data (#e0e0e0). |
| 29 | +4. **Status through color** — Green (healthy), amber (warning), red (error), blue (info). No gratuitous color. |
| 30 | +5. **Monospace for data** — All technical values (MAC addresses, firmware versions, CSI amplitudes) use monospace. |
| 31 | +6. **Progressive disclosure** — Summary first, detail on interaction. Dashboard cards expand to detail views. |
| 32 | +7. **Powered by rUv** — Branding is subtle: footer tagline, about dialog, splash screen. |
| 33 | + |
| 34 | +### Color System |
| 35 | + |
| 36 | +```css |
| 37 | +:root { |
| 38 | + /* Background layers (darkest to lightest) */ |
| 39 | + --bg-base: #0d1117; /* App background */ |
| 40 | + --bg-surface: #161b22; /* Panel backgrounds */ |
| 41 | + --bg-elevated: #1c2333; /* Cards, modals */ |
| 42 | + --bg-hover: #242d3d; /* Hover state */ |
| 43 | + --bg-active: #2d3748; /* Active/selected state */ |
| 44 | + |
| 45 | + /* Text hierarchy */ |
| 46 | + --text-primary: #e6edf3; /* Headings, primary content */ |
| 47 | + --text-secondary: #8b949e; /* Labels, descriptions */ |
| 48 | + --text-muted: #484f58; /* Disabled, hints */ |
| 49 | + |
| 50 | + /* Status colors */ |
| 51 | + --status-online: #3fb950; /* Node online, server running */ |
| 52 | + --status-warning: #d29922; /* Degraded, OTA in progress */ |
| 53 | + --status-error: #f85149; /* Offline, flash failed */ |
| 54 | + --status-info: #58a6ff; /* Discovery, scanning */ |
| 55 | + |
| 56 | + /* Accent */ |
| 57 | + --accent: #7c3aed; /* rUv purple — buttons, active nav */ |
| 58 | + --accent-hover: #6d28d9; |
| 59 | + |
| 60 | + /* Borders */ |
| 61 | + --border: #30363d; |
| 62 | + --border-active: #58a6ff; |
| 63 | + |
| 64 | + /* Data display */ |
| 65 | + --font-mono: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace; |
| 66 | + --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +### Typography Scale |
| 71 | + |
| 72 | +```css |
| 73 | +/* Foundation Book — typographic hierarchy */ |
| 74 | +.heading-xl { font: 600 28px/1.2 var(--font-sans); } /* Page titles */ |
| 75 | +.heading-lg { font: 600 20px/1.3 var(--font-sans); } /* Section titles */ |
| 76 | +.heading-md { font: 600 16px/1.4 var(--font-sans); } /* Card titles */ |
| 77 | +.heading-sm { font: 600 13px/1.4 var(--font-sans); } /* Panel labels */ |
| 78 | +.body { font: 400 14px/1.6 var(--font-sans); } /* Body text */ |
| 79 | +.body-sm { font: 400 12px/1.5 var(--font-sans); } /* Captions */ |
| 80 | +.data { font: 400 13px/1.4 var(--font-mono); } /* Technical values */ |
| 81 | +.data-lg { font: 500 18px/1.2 var(--font-mono); } /* Key metrics */ |
| 82 | +``` |
| 83 | + |
| 84 | +### Layout System — Unity-Inspired Panels |
| 85 | + |
| 86 | +``` |
| 87 | ++--[ Sidebar ]--+--[ Main Content ]------------------------------+ |
| 88 | +| | | |
| 89 | +| [Nav Items] | +--[ Toolbar ]-------------------------------+ | |
| 90 | +| | | Breadcrumb | Actions | Search | | |
| 91 | +| Dashboard | +-------+-----------------------------------+ | |
| 92 | +| Nodes | | | | | |
| 93 | +| Flash | | List | Detail / Inspector | | |
| 94 | +| OTA | | Panel | Panel | | |
| 95 | +| WASM | | | | | |
| 96 | +| Sensing | | | [Property Grid] | | |
| 97 | +| Mesh | | | [Status Badges] | | |
| 98 | +| Settings | | | [Action Buttons] | | |
| 99 | +| | | | | | |
| 100 | ++-[ Status Bar ]+--+-------+-----------------------------------+ | |
| 101 | +| rUv | 3 nodes online | Server: running | 127.0.0.1:8080 | |
| 102 | ++---------------------------------------------------------------+ |
| 103 | +``` |
| 104 | + |
| 105 | +**Panel behaviors:** |
| 106 | +- Sidebar collapses to icon-only on narrow windows |
| 107 | +- List/Detail split is resizable via drag handle |
| 108 | +- Inspector panel scrolls independently |
| 109 | +- Status bar shows global system state at a glance |
| 110 | + |
| 111 | +### Component Library |
| 112 | + |
| 113 | +#### 1. NodeCard |
| 114 | + |
| 115 | +``` |
| 116 | ++-- NodeCard -----------------------------------------------+ |
| 117 | +| [●] ESP32-S3 Node #2 firmware: 0.3.1 | |
| 118 | +| MAC: AA:BB:CC:DD:EE:FF TDM Slot: 2/4 | |
| 119 | +| IP: 192.168.1.42 Edge Tier: 1 | |
| 120 | +| Last seen: 3s ago [Flash] [OTA] [···] | |
| 121 | ++-----------------------------------------------------------+ |
| 122 | +``` |
| 123 | + |
| 124 | +Status dot uses `--status-online/warning/error`. Card background shifts on hover. |
| 125 | + |
| 126 | +#### 2. FlashProgress |
| 127 | + |
| 128 | +``` |
| 129 | ++-- Flash Progress -----------------------------------------+ |
| 130 | +| Flashing firmware to COM3 (ESP32-S3) | |
| 131 | +| | |
| 132 | +| Phase: Writing | |
| 133 | +| [████████████████████░░░░░░░░░░] 67.3% | |
| 134 | +| 412 KB / 612 KB • 38.2 KB/s • ~5s remaining | |
| 135 | ++-----------------------------------------------------------+ |
| 136 | +``` |
| 137 | + |
| 138 | +Progress bar uses `--accent` fill with subtle pulse animation during active writes. |
| 139 | + |
| 140 | +#### 3. MeshTopologyGraph |
| 141 | + |
| 142 | +``` |
| 143 | ++-- Mesh Topology ------------------------------------------+ |
| 144 | +| | |
| 145 | +| [Node 0]----[Node 1] | |
| 146 | +| | \ / | | |
| 147 | +| | [C] | C = Coordinator | |
| 148 | +| | / \ | | |
| 149 | +| [Node 2]----[Node 3] | |
| 150 | +| | |
| 151 | +| Sync drift: ±0.3ms | TDM cycle: 50ms | 4/4 online | |
| 152 | ++-----------------------------------------------------------+ |
| 153 | +``` |
| 154 | + |
| 155 | +Force-directed graph using D3 or a lightweight canvas renderer. Nodes are color-coded by health. Edge thickness indicates signal strength. Clicking a node opens the Inspector panel. |
| 156 | + |
| 157 | +#### 4. PropertyGrid (Unity Inspector-style) |
| 158 | + |
| 159 | +``` |
| 160 | ++-- Node Inspector -----------------------------------------+ |
| 161 | +| General [▼] | |
| 162 | +| MAC Address AA:BB:CC:DD:EE:FF | |
| 163 | +| IP Address 192.168.1.42 | |
| 164 | +| Firmware 0.3.1 | |
| 165 | +| Chip ESP32-S3 | |
| 166 | +| TDM Configuration [▼] | |
| 167 | +| Slot Index 2 | |
| 168 | +| Total Nodes 4 | |
| 169 | +| Cycle Period 50 ms | |
| 170 | +| Sync Drift +0.12 ms | |
| 171 | +| WASM Modules [▼] | |
| 172 | +| [0] activity_detect running 12.4 KB 83 us/f | |
| 173 | +| [1] vital_monitor stopped 8.1 KB — us/f | |
| 174 | ++-----------------------------------------------------------+ |
| 175 | +``` |
| 176 | + |
| 177 | +Collapsible sections with alternating row backgrounds for scanability. |
| 178 | + |
| 179 | +#### 5. StatusBadge |
| 180 | + |
| 181 | +``` |
| 182 | +[● Online] [◐ Degraded] [○ Offline] [↻ Updating] |
| 183 | +``` |
| 184 | + |
| 185 | +Small inline badges with status dot, label, and optional tooltip. |
| 186 | + |
| 187 | +#### 6. LogViewer |
| 188 | + |
| 189 | +``` |
| 190 | ++-- Server Log (auto-scroll) -----------[ Clear ] [ ⏸ ]---+ |
| 191 | +| 19:42:01.234 INFO sensing-server HTTP on 127.0.0.1:8080| |
| 192 | +| 19:42:01.235 INFO sensing-server WS on 127.0.0.1:8765 | |
| 193 | +| 19:42:01.890 INFO udp_receiver CSI frame from .42 | |
| 194 | +| 19:42:02.003 WARN vital_signs Low signal quality | |
| 195 | ++-----------------------------------------------------------+ |
| 196 | +``` |
| 197 | + |
| 198 | +Monospace, color-coded by log level (INFO=text, WARN=amber, ERROR=red). Virtual scrolling for performance. |
| 199 | + |
| 200 | +### Spacing and Grid |
| 201 | + |
| 202 | +```css |
| 203 | +/* 4px base grid */ |
| 204 | +--space-1: 4px; /* Tight spacing (within components) */ |
| 205 | +--space-2: 8px; /* Component internal padding */ |
| 206 | +--space-3: 12px; /* Between related elements */ |
| 207 | +--space-4: 16px; /* Card padding, section gaps */ |
| 208 | +--space-5: 24px; /* Between sections */ |
| 209 | +--space-6: 32px; /* Page-level spacing */ |
| 210 | +--space-8: 48px; /* Major section breaks */ |
| 211 | + |
| 212 | +/* Panel dimensions */ |
| 213 | +--sidebar-width: 220px; |
| 214 | +--sidebar-collapsed: 52px; |
| 215 | +--statusbar-height: 28px; |
| 216 | +--toolbar-height: 44px; |
| 217 | +``` |
| 218 | + |
| 219 | +### Animations |
| 220 | + |
| 221 | +Minimal and purposeful: |
| 222 | +- Panel collapse/expand: 200ms ease-out |
| 223 | +- Node card health transition: 300ms (color fade, not flash) |
| 224 | +- Progress bar fill: smooth 60fps CSS transition |
| 225 | +- Mesh graph node movement: D3 spring simulation (no easing hacks) |
| 226 | +- No loading spinners — use skeleton placeholders instead |
| 227 | + |
| 228 | +### Branding |
| 229 | + |
| 230 | +- **Splash screen**: rUv logo + "RuView Desktop" + version, 1.5s duration |
| 231 | +- **Status bar**: "Powered by rUv" in `--text-muted`, left-aligned |
| 232 | +- **About dialog**: rUv logo, version, license, links to GitHub and docs |
| 233 | +- **App icon**: Stylized WiFi signal + human silhouette in rUv purple (#7c3aed) |
| 234 | + |
| 235 | +## Consequences |
| 236 | + |
| 237 | +### Positive |
| 238 | + |
| 239 | +- Professional, data-dense UI suitable for hardware management |
| 240 | +- Consistent design language across all 7 pages |
| 241 | +- Foundation Book typography ensures readability at all information densities |
| 242 | +- Unity-inspired panels feel natural to engineers familiar with IDE/editor tools |
| 243 | +- Dark theme reduces eye strain for extended monitoring sessions |
| 244 | + |
| 245 | +### Negative |
| 246 | + |
| 247 | +- Custom design system means no off-the-shelf component library (shadcn/ui partially usable) |
| 248 | +- Dockable panels add complexity to the layout system |
| 249 | +- Dark-only theme may not suit all users (could add light mode later) |
| 250 | + |
| 251 | +### Neutral |
| 252 | + |
| 253 | +- The design system is CSS-only with React components — no heavy UI framework dependency |
| 254 | +- Component library can be extracted as a separate package if other rUv projects need it |
| 255 | + |
| 256 | +## References |
| 257 | + |
| 258 | +- ADR-052: Tauri Desktop Frontend |
| 259 | +- Unity Editor UI Guidelines: https://docs.unity3d.com/Manual/UIE-USS.html |
| 260 | +- Foundation CSS Framework: https://get.foundation/ |
| 261 | +- Inter font: https://rsms.me/inter/ |
| 262 | +- JetBrains Mono: https://www.jetbrains.com/lp/mono/ |
0 commit comments