442 lines
28 KiB
Markdown
442 lines
28 KiB
Markdown
# UX Review Test Plan — Pi Multi-FX Pedal Web UI
|
||
|
||
**Date:** June 14, 2026
|
||
**Scope:** Full web UI — React SPA + legacy Jinja2 pages
|
||
**Target URL:** http://pedal.local:8080
|
||
**Methodology:** Nielsen's 10 Usability Heuristics + Flow Analysis + Visual Cohesion Audit
|
||
|
||
---
|
||
|
||
## 1. Scope & Personas
|
||
|
||
### Personas
|
||
|
||
| Persona | Goal | Context |
|
||
|---------|------|---------|
|
||
| **Session Guitarist** | Dial in a tone fast during a live session or recording | On a phone/tablet near the amp, tweaking EQs and effects between takes. Wants minimal taps to hear results. |
|
||
| **Preset Tweaker** | Browse, load, save, and edit presets from a laptop | Sitting at a desk building a pedalboard. Wants deep control over FX chain, NAM models, IR cab sims. |
|
||
| **Headless Stage User** | Switch presets, toggle bypass, check tuner — with footswitches only | Never touches the web UI during performance. Uses it *only* for setup/config behind the scenes. |
|
||
| **Admin / Integrator** | Configure WiFi, Bluetooth MIDI, audio profiles, hotspot | Technical user connecting the pedal to different environments (studio, stage, rehearsal space). |
|
||
|
||
### Flows to Test
|
||
|
||
| # | Flow | Steps | Priority |
|
||
|---|------|-------|----------|
|
||
| F1 | **Load pedal dashboard → check status** | 2 | Critical |
|
||
| F2 | **Browse preset banks → load a preset** | 4 | Critical |
|
||
| F3 | **Edit preset parameters (name, volume, FX chain)** | 5 | High |
|
||
| F4 | **Toggle bypass and adjust master volume** | 3 | Critical |
|
||
| F5 | **Browse and install a NAM model from Tone3000** | 6 | High |
|
||
| F6 | **Upload and load an IR cab sim file** | 4 | High |
|
||
| F7 | **Switch audio latency profile** | 3 | Medium |
|
||
| F8 | **Configure and enable WiFi hotspot** | 5 | Low |
|
||
| F9 | **Scan for, connect to WiFi network** | 4 | Low |
|
||
| F10 | **Bluetooth scan, pair, and view MIDI status** | 5 | Low |
|
||
| F11 | **Toggle 4CM routing mode and set breakpoint** | 3 | Medium |
|
||
| F12 | **Check tuner display with guitar input** | 2 | Medium |
|
||
| F13 | **Save/recall snapshot slots** | 4 | Medium |
|
||
| F14 | **Empty state: unload model, view dashboard with no presets** | 2 | High |
|
||
|
||
### UI Surfaces Reviewed
|
||
|
||
- [ ] React SPA (`/` — root URL)
|
||
- [ ] Legacy Dashboard (`/` — fallback without React build)
|
||
- [ ] Presets page (`/presets`)
|
||
- [ ] Models page (`/models`)
|
||
- [ ] IRs page (`/irs`)
|
||
- [ ] Settings > Connection tab
|
||
- [ ] Settings > Audio tab
|
||
- [ ] Settings > 4CM Routing tab
|
||
- [ ] Settings > Network tab (WiFi scan, hotspot)
|
||
- [ ] Settings > Bluetooth tab
|
||
- [ ] Settings > About tab
|
||
- [ ] Preset Edit modal
|
||
- [ ] WiFi Connect modal
|
||
- [ ] Connection status indicator (global header)
|
||
|
||
---
|
||
|
||
## 2. Heuristic Walkthrough
|
||
|
||
### H1 — Visibility of System Status
|
||
|
||
| # | Test | Action | Expected | Method |
|
||
|---|------|--------|----------|--------|
|
||
| H1.1 | Page load indicator | Navigate to `/` | Loading placeholder or skeleton while API/WS connects | Browser |
|
||
| H1.2 | Connection status | Open page when pedal is off | "Disconnected" badge (red) in header | Browser |
|
||
| H1.3 | Connection status | Open page when pedal is on | "Connected" badge (green) in header | Browser |
|
||
| H1.4 | Preset activation feedback | Click a preset card | Card highlights, dashboard preset name updates, WS broadcast visible | Browser |
|
||
| H1.5 | Volume slider feedback | Drag volume slider | Value % text updates in real time | Browser |
|
||
| H1.6 | Bypass toggle feedback | Click bypass button | Button text toggles BYPASSED/ACTIVE, color changes | Browser |
|
||
| H1.7 | Tuner toggle feedback | Click tuner button | Button toggles ON/OFF, color changes | Browser |
|
||
| H1.8 | WebSocket reconnection | Kill server, wait, restart | "Disconnected" → "Connected" after auto-reconnect | Browser |
|
||
| H1.9 | Model load progress | Click Load on a NAM model | Loading state on the button, list refreshes after | Browser |
|
||
| H1.10 | Tone3000 search feedback | Search Tone3000 for models | "Searching..." spinner shown, results appear, offline warning shown if 503 | Browser |
|
||
| H1.11 | Tone3000 install feedback | Install a model from Tone3000 | Button shows "Downloading...", then "✓ Done", list refreshes | Browser |
|
||
| H1.12 | File upload feedback | Upload a .nam or .wav file | Input clears, list refreshes with new entry | Browser |
|
||
| H1.13 | Audio profile switch | Switch to low latency profile | "restarted: true" in response, brief JACK restart pause | API + Browser |
|
||
| H1.14 | RSSI/connection data in settings | Open Network tab | WiFi SSID, IP, signal % shown, visible from refresh | Browser |
|
||
| H1.15 | BT status indicators | Open Bluetooth tab | Power, discoverable, adapter name visible | Browser |
|
||
| H1.16 | WS client count | Open Settings → Connection | Connected clients count shows active WS sessions | Browser |
|
||
|
||
**Grep for verification:**
|
||
```bash
|
||
# Loading states in source
|
||
grep -n "loading\|spinner\|skeleton\|Loading" src/web/static/*.js src/web/static/style.css
|
||
|
||
# Connection status toggle
|
||
grep -n "connection-status\|Connected\|Disconnected" src/web/static/*.js src/web/templates/base.html
|
||
|
||
# Button disabled states on async actions
|
||
grep -n "\.disabled\|disabled =" src/web/static/*.js
|
||
```
|
||
|
||
---
|
||
|
||
### H2 — Match Between System and Real World
|
||
|
||
| # | Test | Action | Expected | Method |
|
||
|---|------|--------|----------|--------|
|
||
| H2.1 | FX type labels in UI | View FX chain, preset edit modal | Labels use real-world names (e.g., "Noise Gate" not "noise_gate") | Source + Browser |
|
||
| H2.2 | Model/IR list readability | View Models or IRs page | File names appear as human-readable labels | Browser |
|
||
| H2.3 | 4CM routing description | Enable 4CM in Settings | Plain language: "Input 1 (Guitar) → Pre blocks → Send \| Input 2 (Return) → Post blocks → Output" | Browser |
|
||
| H2.4 | Tuner note display | Enable tuner with guitar plugged in | Shows musical note names (A, A#, Bb...) not frequencies only | Browser |
|
||
| H2.5 | Preset meta labels | View preset card | Shows "Bank 0 · Program 2" — accessible musician language | Browser |
|
||
| H2.6 | Audio profile names | View profiles list | "Standard", "Low" — musician-friendly not technical | Browser |
|
||
| H2.7 | NAM architecture info | View model details | Shows "featherwave-v2" or architecture name, not internal paths | Browser |
|
||
|
||
**Grep for verification:**
|
||
```bash
|
||
# Check for snake_case / internal names leaking into UI
|
||
grep -n "fx_type\|replace.*_/g\|FXType" src/web/static/presets.js | head -20
|
||
# presets.js line 92: const label = block.fx_type.replace(/_/g, ' '); — detects raw fx_type
|
||
```
|
||
|
||
---
|
||
|
||
### H3 — User Control and Freedom
|
||
|
||
| # | Test | Action | Expected | Method |
|
||
|---|------|--------|----------|--------|
|
||
| H3.1 | Modal close options | Open preset edit modal | Close on ✕ button, close on overlay click, close on Cancel button | Browser |
|
||
| H3.2 | Modal close on Escape | Open modal, press Escape | Modal closes | Browser |
|
||
| H3.3 | Delete preset confirmation | Click Delete in preset modal | `confirm()` dialog appears before deletion | Browser |
|
||
| H3.4 | Cancel WiFi connect | Open WiFi modal, click Cancel | Modal closes, no connection attempted | Browser |
|
||
| H3.5 | Back navigation | Navigate to any page, press Back | Browser back works, returns to previous page | Browser |
|
||
| H3.6 | Tab navigation persists | Switch to Network tab, navigate away and back | Active tab remembered via URL hash | Browser |
|
||
| H3.7 | Tuner toggle graceful | Toggle tuner ON while playing | Audio mutes or tuner activates without loud pop/clip | Browser + Audio |
|
||
| H3.8 | Bypass toggle graceful | Toggle bypass ON while playing | Clean DI signal, no pop/clip | Browser + Audio |
|
||
| H3.9 | Unload model without issues | Click Unload on loaded model | Model unloads, dashboard shows "None loaded", audio still flows | Browser |
|
||
|
||
---
|
||
|
||
### H4 — Consistency and Standards
|
||
|
||
| # | Test | Action | Expected | Method |
|
||
|---|------|--------|----------|--------|
|
||
| H4.1 | Navigation active state | Click each nav link | Active link highlighted, consistent style across all pages | Browser |
|
||
| H4.2 | Button style consistency | Compare primary/secondary/danger across pages | Same styles everywhere (colors, padding, font size) | Browser |
|
||
| H4.3 | Toggle button pattern | Compare bypass, tuner, 4CM toggles | Same ON/OFF pattern, same active/inactive colors | Browser |
|
||
| H4.4 | Slider pattern | Compare volume sliders on Dashboard vs Settings | Same visual, same behavior, synced values | Browser |
|
||
| H4.5 | Connection status in header | Navigate through all pages | Connection indicator always present, same position | Browser |
|
||
| H4.6 | Page header pattern | Visit Presets, Models, IRs, Settings pages | Consistent page-header with h1, same spacing | Browser |
|
||
| H4.7 | Card structure | Compare all card components | Uniform header/body/footer pattern — identical padding, border, radius | Browser |
|
||
| H4.8 | Danger button meaning | Compare Delete preset, Unload model/IR | All red danger buttons are destructive actions | Browser |
|
||
| H4.9 | Tab pattern (Settings) | Switch between all 6 settings tabs | Underline active indicator, same transition | Browser |
|
||
|
||
---
|
||
|
||
### H5 — Error Prevention
|
||
|
||
| # | Test | Action | Expected | Method |
|
||
|---|------|--------|----------|--------|
|
||
| H5.1 | Disabled submit during load | Click Load on model rapidly | Button disabled after first click, no duplicate load | Browser |
|
||
| H5.2 | Disabled submit during upload | Upload a file, click multiple times | Button disabled during upload | Source |
|
||
| H5.3 | Delete preset confirmation | Click Delete | Confirm dialog: "Delete this preset?" | Browser |
|
||
| H5.4 | File type validation on upload | Try uploading a .txt file | Rejected at client or server level | Browser |
|
||
| H5.5 | Audio profile double-switch | Switch to same profile twice | `restarted: false`, no unnecessary JACK restart | API |
|
||
| H5.6 | 4CM breakpoint bounds | Drag breakpoint slider min/max | Clamped 0–16 | Browser |
|
||
| H5.7 | Volume clamping | Set volume > 100% or < 0% via API | Clamped to 0.0–1.0 | API |
|
||
| H5.8 | Empty preset name | Save preset with empty name | Should default to "Preset" or reject with validation | Browser |
|
||
| H5.9 | Hotspot password length | Try password > 63 chars | Maxlength on input field prevents it | Browser |
|
||
|
||
**Code verification:**
|
||
```bash
|
||
grep -n "confirm\|showModal\|are you sure" src/web/static/*.js
|
||
grep -n "\.disabled" src/web/static/models.js src/web/static/irs.js
|
||
```
|
||
|
||
---
|
||
|
||
### H6 — Recognition Rather Than Recall
|
||
|
||
| # | Test | Action | Expected | Method |
|
||
|---|------|--------|----------|--------|
|
||
| H6.1 | Current preset name visible | Load any page | Preset name clearly shown in Dashboard or in header | Browser |
|
||
| H6.2 | Currently loaded model/IR | View Models/IRs page | "CURRENT" badge visible on active model/IR | Browser |
|
||
| H6.3 | Active preset card highlighted | Browse presets | The active preset card has a distinct border/background | Browser |
|
||
| H6.4 | Bank/program location | View preset card | "Bank N · Slot N" visible without clicking | Browser |
|
||
| H6.5 | Navigation labels visible | All pages | All 5 nav links visible, no hamburger hiding | Browser |
|
||
| H6.6 | FX chain status on dashboard | Connected, preset loaded | Blocks visible with ON/OFF badges | Browser |
|
||
| H6.7 | Modal title shows preset name | Click to edit preset | "Edit: [Preset Name]" — user knows what they're editing | Browser |
|
||
| H6.8 | Routing mode visible from dashboard | Any page | Badge shows "Mono" or "4CM" | Browser |
|
||
| H6.9 | Tone3000 installed state | Revisit after install | Previously installed models show ✓ Installed badge (localStorage) | Browser |
|
||
|
||
---
|
||
|
||
### H7 — Flexibility and Efficiency
|
||
|
||
| # | Test | Action | Expected | Method |
|
||
|---|------|--------|----------|--------|
|
||
| H7.1 | Keyboard submit on search | Type in Tone3000 search, press Enter | Triggers search | Browser |
|
||
| H7.2 | FAQ: Keyboard shortcuts | Test Tab order through form fields | Logical focus order, all interactive elements reachable | Browser |
|
||
| H7.3 | Bulk actions | Models/IRs pages | No bulk select/load/delete — note as missing efficiency | Browser |
|
||
| H7.4 | Auto-refresh on preset save | Save preset edit | Modal closes, preset list auto-refreshes | Browser |
|
||
| H7.5 | Auto-refresh after model/IR upload | Upload model/IR | List auto-refreshes after upload completes | Browser |
|
||
| H7.6 | Trending option on Tone3000 | Click "Trending" | Fetches trending models/IRs without typing a query | Browser |
|
||
| H7.7 | Tab navigation in Settings | URL hash (`#network`, `#bluetooth`) | Deep-linkable settings tabs | Browser |
|
||
| H7.8 | WS-driven live updates | Change volume on another tab | Dashboard and Settings sliders sync in real time | Browser |
|
||
|
||
---
|
||
|
||
### H8 — Aesthetic and Minimalist Design
|
||
|
||
| # | Test | Action | Expected | Method |
|
||
|---|------|--------|----------|--------|
|
||
| H8.1 | Content-to-chrome ratio | View Dashboard | Essential info above the fold: preset, bypass, volume, FX chain | Browser |
|
||
| H8.2 | Visual hierarchy | View any page | Most important element draws eye first (preset name, status) | Browser |
|
||
| H8.3 | Information density | Dashboard page | Not overcrowded — cards with clear sections | Browser |
|
||
| H8.4 | Typography consistency | Compare h1/h2 across pages | Same font sizes, weights, colors for each heading level | Browser |
|
||
| H8.5 | Line length readability | Any card body | Text doesn't span full viewport — contained by max-width | Browser |
|
||
| H8.6 | Dark theme cohesion | All pages | Consistent dark palette, no jarring color changes | Browser |
|
||
| H8.7 | Redundant elements | Check for duplicate info | No data shown in multiple places unnecessarily | Browser |
|
||
| H8.8 | Empty states visual | Unload model, clear presets | Helpful empty states, not just blank areas | Browser |
|
||
| H8.9 | Modal sizing | Open preset edit modal | Appropriate width, doesn't overwhelm on mobile | Browser |
|
||
|
||
---
|
||
|
||
### H9 — Help Users Recognize, Diagnose, and Recover from Errors
|
||
|
||
| # | Test | Action | Expected | Method |
|
||
|---|------|--------|----------|--------|
|
||
| H9.1 | API error → user message | Trigger a 500 on preset load | User-facing error, not raw JSON or console-only | Browser |
|
||
| H9.2 | Tone3000 offline state | Disconnect internet, search | "⚠ Offline — search unavailable" warning shown | Browser |
|
||
| H9.3 | Upload error handling | Upload corrupt .nam file | Alert with error message: "Upload error: ..." | Browser |
|
||
| H9.4 | Model load failure | Try to load corrupt model | Alert: "Failed to load model: ..." | Browser |
|
||
| H9.5 | Preset load failure | Access empty slot via direct URL | 404 — "Preset not found" | Browser |
|
||
| H9.6 | WiFi connect error | Wrong password on WiFi modal | Error message shown in modal, modal stays open | Browser |
|
||
| H9.7 | JACK restart failure | Kill JACK, switch profile | API returns 500 with "Failed to start JACK — rolled back" | API |
|
||
| H9.8 | API error on Dashboard | Kill backend, load dashboard | Silent catch with console.warn — check for user-facing message | Browser |
|
||
| H9.9 | Empty preset slot styling | Presets page, empty slot | Shows "— Empty —" with reduced opacity | Browser |
|
||
|
||
**Code verification:**
|
||
```bash
|
||
# Error handling patterns — check for user-facing messages vs silent console
|
||
grep -n "\.catch\|catch(" src/web/static/*.js | grep -v "console.warn\|console.error"
|
||
grep -n "alert(" src/web/static/*.js
|
||
grep -n "text-muted\|network-error\|Error:" src/web/static/*.js
|
||
```
|
||
|
||
---
|
||
|
||
### H10 — Help and Documentation
|
||
|
||
| # | Test | Action | Expected | Method |
|
||
|---|------|--------|----------|--------|
|
||
| H10.1 | Tooltips on controls | Hover over any button | No tooltips currently — add recommendation | Browser |
|
||
| H10.2 | Upload hints | Check upload sections | "Upload .nam model files to the pedal's model directory." — clear | Browser |
|
||
| H10.3 | Tone3000 hints | Check Tone3000 section | "Search and download NAM models directly from the Tone3000 community." | Browser |
|
||
| H10.4 | Empty state guidance | No models/presets/IRs | Actionable: "No .nam models found" + upload option visible | Browser |
|
||
| H10.5 | About page | Navigate to About tab | Version, platform, repo link available | Browser |
|
||
| H10.6 | Help within the app | Check for question marks, help links | None found — add recommendation for critical flows | Browser |
|
||
| H10.7 | IR details context | View IR list | Shows "1024 taps · 21.3ms @ 48000Hz" — helpful technical detail | Browser |
|
||
|
||
---
|
||
|
||
## 3. Flow Friction Map
|
||
|
||
Each flow from Section 1 tested step-by-step. Score 1-5:
|
||
|
||
| Flow | Step | Friction | Issue Ref | Notes |
|
||
|------|------|----------|-----------|-------|
|
||
| **F1 — Load dashboard** | Navigate to `pedal.local:8080` | 1 | — | React SPA loads (or legacy fallback) |
|
||
| **F1** | Check connection status | 1 | — | Color-coded badge in header |
|
||
| **F1** | View current state | 1 | — | WS pushes state on connect |
|
||
| **F2 — Browse presets** | Click Presets nav | 1 | — | |
|
||
| **F2** | Wait for bank list | 2 | H1-like | Loading indicator present |
|
||
| **F2** | Click preset card | 1 | — | |
|
||
| **F2** | Preset loads, dashboard updates | 1 | — | WS pushes update |
|
||
| **F3 — Edit preset** | Click preset card to open modal | 1 | — | |
|
||
| **F3** | Change name | 1 | — | Text input clear |
|
||
| **F3** | Adjust volume | 1 | — | Slider works |
|
||
| **F3** | View FX chain in modal | 2 | H2, H6 | Labels use `replace(/_/g,' ')` — see notes |
|
||
| **F3** | Click Save | 1 | — | Modal closes, list refreshes |
|
||
| **F3** | Click Delete | 1 | — | Confirm dialog appears |
|
||
| **F4 — Bypass & volume** | Click bypass button | 1 | — | Immediate toggle |
|
||
| **F4** | Verify bypassed audio | 1 | — | Clean DI signal |
|
||
| **F4** | Drag volume slider | 1 | — | Real-time update |
|
||
| **F5 — Tone3000 browse** | Go to Models page | 1 | — | |
|
||
| **F5** | Type search query | 1 | — | Enter triggers search |
|
||
| **F5** | Wait for results | 3 | H1 | "Searching..." spinner, but no timeout info |
|
||
| **F5** | Click Install on result | 2 | H1 | Button shows "Downloading..." |
|
||
| **F5** | Verify model appears in list | 1 | — | Auto-refreshes |
|
||
| **F6 — Upload IR** | Go to IRs page | 1 | — | |
|
||
| **F6** | Click file input | 1 | — | |
|
||
| **F6** | Select .wav file | 1 | — | File type restricted |
|
||
| **F6** | Click Upload | 2 | H1 | No upload progress bar — just button state |
|
||
| **F6** | Verify in list | 1 | — | Refreshes |
|
||
| **F7 — Audio profile switch** | Go to Settings > Audio | 1 | — | |
|
||
| **F7** | Profiles are visible | 2 | — | No explicit "switch profile" button in UI — needs API |
|
||
| **F7** | Switch profile | 2 | H10 | No in-UI profile switcher visible in Audio tab |
|
||
| **F8 — Hotspot config** | Go to Network tab | 1 | — | |
|
||
| **F8** | Edit SSID/password | 1 | — | Input fields ready |
|
||
| **F8** | Click Enable Hotspot | 2 | H1 | No "enabling..." state |
|
||
| **F8** | Verify clients listed | 2 | H1 | Auto-polls or manual refresh? |
|
||
| **F9 — WiFi scan** | Go to Network tab | 1 | — | |
|
||
| **F9** | Click Scan | 2 | H1 | "Scanning..." button state, results appear |
|
||
| **F9** | Click Connect on network | 1 | — | Modal opens |
|
||
| **F9** | Enter password | 1 | — | |
|
||
| **F9** | Click Connect | 2 | H1/H9 | Modal error if fails |
|
||
| **F10 — BT scan** | Go to Bluetooth tab | 1 | — | |
|
||
| **F10** | Scan for devices | 2 | H1 | "Scanning (12s)..." — shows expected duration |
|
||
| **F10** | Pair with device | 2 | H1 | No pairing feedback beyond spinner |
|
||
| **F11 — 4CM routing** | Go to Settings > 4CM Routing | 1 | — | |
|
||
| **F11** | Toggle 4CM ON | 1 | — | Breakpoint row enables |
|
||
| **F11** | Drag breakpoint | 1 | — | Description updates live |
|
||
| **F12 — Tuner** | Toggle tuner ON | 1 | — | |
|
||
| **F12** | Check note detection | 1 | — | Fast poll endpoint |
|
||
| **F13 — Snapshots** | Go to snapshot section | 3 | — | No snapshot UI on dashboard — check React SPA |
|
||
| **F13** | Save snapshot to slot | 2 | — | Via API or in-app? |
|
||
| **F14 — Empty states** | Unload all models | 1 | H6 | "None loaded" shown clearly |
|
||
| **F14** | Delete all presets | 1 | H9 | "No presets found. Create one from the Dashboard." |
|
||
|
||
---
|
||
|
||
## 4. Visual & Interaction Checklist
|
||
|
||
| Check | Pass? | Issues | Notes |
|
||
|-------|-------|--------|-------|
|
||
| Consistent spacing / grid | ✅ | — | Cards share `--radius`, `--border`, `padding: 10-14px` |
|
||
| Typography hierarchy | ✅ | — | h1=1.1rem, h2=0.9-0.95rem, body=0.85rem — clear hierarchy |
|
||
| Color consistency | ✅ | — | Single accent `#4fc3f7`, consistent danger/success |
|
||
| Interactive states | ⚠️ | See below | Hover, active states defined; missing focus-visible styles |
|
||
| Responsive layout | ✅ | — | 82% max-width mobile, 600px/720px breakpoints |
|
||
| Loading states | ⚠️ | H1-series | Most pages have loading indicators; Tone3000 spinner lacks progress |
|
||
| Empty states | ✅ | — | Clear messages: "No models found", "None loaded" |
|
||
| Error states | ⚠️ | H9-series | API errors shown via alert(); silent catches on Dashboard WS |
|
||
| Edge cases (long text, rapid click) | ⚠️ | H5, H8 | Long preset names handled with ellipsis; Button disabled states present |
|
||
| Touch targets ≥ 48px | ⚠️ | — | `.btn` padding 8px 16px — may be borderline on mobile |
|
||
| Dark theme readability | ✅ | — | High contrast: `#e0e0e0` on `#0d0d0d` background |
|
||
| Smooth transitions | ✅ | — | `transition: background 0.2s, border-color 0.2s` on interactive elements |
|
||
|
||
---
|
||
|
||
## 5. Responsive & Mobile UX Checks
|
||
|
||
| # | Test | Viewport | Expected | Method |
|
||
|---|------|----------|----------|--------|
|
||
| R1 | Dashboard on mobile | 375px wide | Status row stacks (grid → 1 column), nav links compact | Browser |
|
||
| R2 | Presets grid on mobile | 375px wide | 2-column grid intact, cards shrink appropriately | Browser |
|
||
| R3 | Settings tabs on mobile | 375px wide | Horizontal scrollable tabs with hidden scrollbar | Browser |
|
||
| R4 | Modal on mobile | 375px wide | Modal fills width with padding, scrollable body | Browser |
|
||
| R5 | Touch targets on mobile | 375px, touch | Buttons have `touch-action: manipulation`, no 300ms delay | Source |
|
||
| R6 | Nav overflow | Very long nav labels | `overflow-x: auto` with hidden scrollbar | Browser |
|
||
| R7 | Header sticky on scroll | Scroll down on any page | Header stays at top (`position: sticky; z-index: 100`) | Browser |
|
||
| R8 | Input fields on mobile | Focus any input | No viewport zoom (`user-scalable=no` set) — intentional? | Browser |
|
||
| R9 | Content max-width on large screen | 1920px wide | `--max-width: 720px` — content centered, not stretched | Browser |
|
||
|
||
---
|
||
|
||
## 6. Real-Time & WebSocket UX
|
||
|
||
| # | Test | Action | Expected | Method |
|
||
|---|------|--------|----------|--------|
|
||
| WS1 | Multiple tabs sync | Open 2 browser tabs, change volume on tab 1 | Tab 2 slider and value update within 1s | Browser |
|
||
| WS2 | Bypass sync across tabs | Toggle bypass on tab 1 | Tab 2 button text and color update | Browser |
|
||
| WS3 | Preset change broadcast | Activate preset via /presets page | Dashboard preset card updates on all connected clients | Browser |
|
||
| WS4 | Reconnection UX | Unplug network cable, wait 10s, reconnect | "Disconnected" appears, then auto-reconnects showing "Connected" | Browser |
|
||
| WS5 | WS reconnection backoff | Keep pedal disconnected for 1 min | Reconnect delay increases from 1s to max 15s | Browser |
|
||
| WS6 | Concurrency: 3 tabs + API | Open 3 browser tabs + curl API calls | All clients receive broadcasts, no dropped messages | Multi-browser |
|
||
| WS7 | Initial state on WS connect | Open fresh browser tab | Receives `{"type": "connected", "state": {...}}` with full current state | Browser |
|
||
|
||
---
|
||
|
||
## 7. Accessibility Quick Checks
|
||
|
||
| # | Test | Expected | Method |
|
||
|---|------|----------|--------|
|
||
| A1 | Tab navigation through nav links | All 5 nav links focused in order | Browser |
|
||
| A2 | Tab navigation through preset grid | Each preset card focusable | Browser |
|
||
| A3 | Tab navigation through modal | Input, slider, Save, Delete, Cancel in logical order | Browser |
|
||
| A4 | Focus-visible styles on interactive | Visible focus ring on buttons, links, inputs | Browser |
|
||
| A5 | Color contrast: text on bg | `#e0e0e0` on `#1a1a1a` — passes WCAG AA | Source |
|
||
| A6 | Color contrast: accent on bg | `#4fc3f7` on `#222` — passes WCAG AA | Source |
|
||
| A7 | Alt text on Tone3000 thumbnails | `alt=""` (decorative) — acceptable | Source |
|
||
| A8 | ARIA labels on toggle buttons | No ARIA — buttons have text content (ON/OFF) so passable | Source |
|
||
| A9 | Form labels associated with inputs | File inputs have no explicit `<label>` — just adjacent text | Source |
|
||
|
||
---
|
||
|
||
## 8. React SPA-Specific Tests (if mounted at root)
|
||
|
||
The React SPA at `src/web/ui-dist/` replaces the legacy dashboard at `/`.
|
||
|
||
| # | Test | Action | Expected | Method |
|
||
|---|------|--------|----------|--------|
|
||
| SPA1 | SPA loads at root | GET `/` | Returns React SPA `index.html` (not legacy dashboard) | Browser |
|
||
| SPA2 | Fallback if no ui-dist | Delete ui-dist dir, restart | Falls back to legacy dashboard at `/` | Browser |
|
||
| SPA3 | SPA navigation | Click through the SPA | Client-side routing, no full page reloads | Browser |
|
||
| SPA4 | SPA ↔ legacy pages | Navigate from SPA root to `/presets` | Full page navigation to legacy page — smooth transition? | Browser |
|
||
| SPA5 | Favicon loads | Check browser tab icon | SVG favicon at `/ui/favicon.svg` | Browser |
|
||
| SPA6 | JS bundle errors | Open browser console on SPA | No console errors, no uncaught exceptions | Browser |
|
||
|
||
---
|
||
|
||
## 9. Key UX Observations from Source Code (Pre-Findings)
|
||
|
||
These are issues visible from code review alone. Confirm in browser during execution.
|
||
|
||
| # | Observation | Heuristic | Source |
|
||
|---|-------------|-----------|--------|
|
||
| O1 | FX type labels use `block.fx_type.replace(/_/g, ' ')` — simple replace, no proper label map. Some types may render with underscores if unmatched. | H2 | `presets.js:92` |
|
||
| O2 | WS `preset_changed` handler updates name/meta but doesn't re-render FX chain on dashboard. Block bypass states may visually lag. | H1 | `app.js:62-69` |
|
||
| O3 | `toggle4cm()` reads button state from DOM classList, not from server — race risk if another client or WS event flips state between read and POST. | H5 | `app.js:142-143` |
|
||
| O4 | No keyboard shortcut support (Ctrl+S for save, / for search). | H7 | Whole codebase |
|
||
| O5 | No undo for any action — delete is permanent after confirm. | H3 | `presets.js:132` |
|
||
| O6 | Signal strength icons for WiFi use the same emoji for all levels (`📶` — same Unicode codepoint, different on each platform). | H8 | `network.js:83-88` |
|
||
| O7 | SN: signal icon `📶` vs `📶` — same char repeated, 4 levels collapse to same visual. | H8 | `network.js:23-26` |
|
||
| O8 | BT scan timeout (12s) displayed to user — good. No cancel option on scan. | H3 + H1 | `bluetooth.js:72` |
|
||
| O9 | No feedback when JACK restarts during profile switch — audio dropout with no visual indicator. | H1 | `server.py:1402-1443` |
|
||
| O10 | Volume slider on Dashboard and Settings page both update via REST per `oninput` — may cause excessive API calls during drag. | H7 | `app.js:227-230` |
|
||
| O11 | Connection status `_handlers` check (`pedalWS._handlers ? '1' : '0'`) looks for handler registration, not actual WS count. | H1 | `app.js:261` |
|
||
|
||
---
|
||
|
||
## 10. Pre-Completion Checklist
|
||
|
||
Before marking a section complete, verify:
|
||
|
||
- [ ] Browser tested: each test executed and result recorded
|
||
- [ ] JS console checked for errors after each interaction
|
||
- [ ] WS messages confirmed where applicable (via browser console: `pedalWS._handlers`)
|
||
- [ ] Responsive view tested for mobile flows (R1-R9)
|
||
- [ ] Code findings (O1-O11) confirmed in live browser session
|
||
- [ ] Screenshots captured for visual issues (use `browser_vision`)
|
||
- [ ] Cross-device sync tested for at least one flow (WS1)
|
||
|
||
---
|
||
|
||
## 11. Test Annotation Legend
|
||
|
||
| Symbol | Meaning |
|
||
|--------|---------|
|
||
| ✅ | Passes — expected behavior confirmed |
|
||
| ❌ | Fails — bug discovered (create Gitea issue) |
|
||
| ⚠️ | Non-critical / minor friction (note in recommendations) |
|
||
| ⏭️ | Skipped — explain why (e.g., "no pedal hardware connected") |
|
||
| 🔄 | Needs retest after fix |
|
||
|
||
---
|
||
|
||
*Generated by Hermes Agent UX Review Skill — based on Nielsen's 10 Usability Heuristics and ux-review methodology.*
|