Files
pi-multifx-pedal/docs/ux-review-test-plan.md
T

28 KiB
Raw Blame History

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:

# 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:

# 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 016 Browser
H5.7 Volume clamping Set volume > 100% or < 0% via API Clamped to 0.01.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:

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:

# 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.