Files
trx-rs/docs/UX_Guidelines.md
T
Claude 28769d01d0 [docs](trx-rs): document UI/UX design guidelines
Add docs/UX_Guidelines.md covering web frontend patterns (theming, responsive
design, accessibility, real-time data), REST API conventions, CLI interface,
configuration wizard, error handling, branding, security UX, and inferred
design principles.

https://claude.ai/code/session_01LC9Yp36ARX47bmKavNPTcB
Signed-off-by: Claude <noreply@anthropic.com>
2026-03-28 14:09:24 +01:00

16 KiB

UX Guidelines

This document captures the UI/UX design patterns, conventions, and principles observed across the trx-rs application. It covers the web frontend, CLI interfaces, configuration wizard, API design, and error handling.

Last reviewed: 2026-03-28


1. Web Frontend (trx-frontend-http)

1.1 Layout and Navigation

The web UI is a single-page application served from embedded assets (no build step). It uses a tab-based navigation model with six top-level tabs:

Tab Icon Purpose
Main House Primary radio control: spectrum, frequency, mode, PTT, VFO, SDR controls
Bookmarks Bookmark Saved frequency/mode presets with folder organisation
Digital modes Bar chart FT8/FT4/FT2, WSPR, CW, APRS, AIS, VDES decode tables
Map Pin Leaflet map for APRS/AIS/FT8 station plotting
Settings Wrench Scheduler, background decode, history retention
About Info circle Server/client/radio/audio/decoder/integration details

Tabs use inline SVG icons with a text label below. On narrow viewports the tab bar wraps and subtitles collapse to save space.

The Settings and About tabs each use a secondary sub-tab bar for further grouping (e.g. Settings > Scheduler | Background Decode | History).

1.2 Theming

The UI supports dark mode (default) and light mode toggled via a header button. Theme preference persists in localStorage.

Additionally, nine colour styles are available via a dropdown:

  • Original (default), Arctic, Lime, Contrast, Neon Disco, Donald (golden-rain), Amber, Fire, Phosphor

Each style provides a full CSS custom-property override set for both dark and light variants. Styles are applied via data-style and data-theme attributes on <html>.

All colours reference CSS custom properties (--bg, --card-bg, --text, --accent-green, --border-light, etc.) so components never use hard-coded colour values.

1.3 Typography

  • Body: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif
  • Frequency display: DSEG14 Classic (14-segment display font, loaded from CDN with preload)
  • Labels: uppercase, 0.68-0.78 rem, font-weight: 700, letter-spacing: 0.04em
  • Section labels use pill-shaped badges (border-radius: 999px) with muted text

1.4 Responsive Design

Six breakpoints handle layout adaptation:

Breakpoint Behaviour
> 1100px Full width with bookmark side gutters on spectrum
< 1100px Side bookmark panels hidden
< 900px Card fills viewport width, reduced padding
< 760px Tab bar wraps, controls stack vertically, safe-area-inset padding for notched devices
< 640px Bottom-fixed tab bar (mobile), subtitles hidden, compact header
< 520px Further compact adjustments

Touch-specific: @media (hover: none) and (pointer: coarse) enlarges hit targets.

The spectrum panel hints adapt: mouse users see "Scroll to zoom / Ctrl+Scroll to tune / Drag to pan" while touch users see "Pinch to zoom / Drag to pan".

1.5 Interactive Controls

  • Jog wheel: Circular CSS-styled draggable dial for frequency tuning (skeuomorphic radial-gradient, grab cursor, shadow/inset). Plus/minus buttons flank it.
  • Step unit buttons: Segmented button group (MHz / kHz / Hz) with .active highlight
  • Step scale: 1x / 0.1x multiplier toggle
  • Frequency input: Monospace DSEG14 font, editable <input> with disabled opacity fix
  • Mode selector: <select> dropdown populated from rig capabilities
  • PTT / Power / Lock buttons: Three-column grid in the transmit/power section
  • VFO picker: Button group (horizontal on desktop, vertical stack on mobile)
  • WFM/SAM controls: Compact labelled controls (de-emphasis, audio mode, denoise, stereo pilot flag, CCI/ACI interference bars)
  • SDR settings row: AGC checkbox, RF/LNA gain inputs with Set buttons, noise blanker

1.6 Spectrum and Waterfall

The spectrum panel uses <canvas> elements (WebGL renderer optional) and offers:

  • Drag to pan, scroll to zoom, Ctrl+scroll to tune
  • Bandwidth edges are draggable to resize the filter
  • Keyboard shortcuts: +/- zoom, arrows pan, 0 reset
  • Minimap for orientation when zoomed
  • Resize grip to adjust spectrum height
  • Controls: bandwidth input, auto-BW, sweet-spot, peak hold (0-60s), floor (dB), range (dB), auto-level, contrast gamma slider
  • Waterfall/waveform split slider (20%-80%, default 50/50)
  • Bookmark axis overlays on left/right sides at wider viewports
  • Decoder overlays: RDS station name, AIS/VDES/FT8/APRS/CW bar overlays using aria-live="polite"

1.7 Real-Time Data

  • SSE (Server-Sent Events) on /events for rig state updates. Each SSE session gets a UUID, enabling per-tab rig selection without interfering with other tabs.
  • Named events: data (state), session (session UUID), channels (virtual channels), b (spectrum bins as base64), rds, vchan_rds, ping (5-second heartbeat)
  • WebSocket on /audio for Opus-encoded RX audio streaming
  • Connection lost banner: #server-lost-banner with pulsing dot, text "trx-server connection lost -- waiting for reconnect", uses aria-live="assertive"
  • Loading state: Centered "Initializing (rig)..." with subtitle, content hidden until ready

1.8 Accessibility

  • All interactive elements have aria-label attributes
  • Spectrum overlays use aria-live="polite" for screen reader announcements
  • Connection-lost banner uses aria-live="assertive"
  • aria-hidden="true" on decorative canvases and visual-only elements
  • SVG icons include aria-hidden="true" with descriptive labels on parent buttons
  • Spectrum resize grip has both title and aria-label

1.9 Authentication UX

When auth is enabled, an auth gate blocks the UI with:

  • Title: "Access Required"
  • Subtitle: "Enter passphrase to continue"
  • Password input + Login button (green accent, full-width)
  • Optional "Continue as Guest" button (shown when RX passphrase is not set)
  • Error message area (red #ff6b6b)
  • Role badge display

Two roles: Rx (read-only) and Control (full access including TX/PTT).

Session cookie: trx_http_sid, HttpOnly, configurable Secure and SameSite attributes.

The header shows a Login/Logout button when auth is enabled (#header-auth-btn).

1.10 Multi-Rig Support

  • Header rig switcher: <select> dropdown in the top bar for switching between connected rigs
  • Per-tab rig binding: each SSE session independently selects a rig via ?remote= query parameter
  • Rig state isolation: only the disconnected rig shows the connection-lost banner
  • About tab shows active rig, available rigs list

2. REST API Design

2.1 Conventions

  • Read operations use GET (e.g. /status, /events, /decode/history, /rigs, /bookmarks)
  • Mutations use POST for actions and toggles (e.g. /set_freq, /toggle_power, /toggle_ft8_decode)
  • CRUD resources use proper verbs: GET /bookmarks, POST /bookmarks, PUT /bookmarks/{id}, DELETE /bookmarks/{id}
  • Batch operations: POST /bookmarks/batch_delete, POST /bookmarks/batch_move
  • Nested resources: /channels/{remote}/{channel_id}/subscribe, /scheduler/{remote}/status
  • Responses are JSON with Content-Type: application/json
  • SSE stream uses Content-Type: text/event-stream with no-cache and keep-alive headers

2.2 Request Timeout

All rig command requests have a 15-second timeout (REQUEST_TIMEOUT). If the command doesn't complete in time, the request returns an error rather than hanging.

2.3 Error Responses

  • 401 Unauthorized: {"error": "Invalid credentials"} or {"error": "Authentication required"}
  • 429 Too Many Requests: {"error": "Too many login attempts, please try again later"}
  • 404 Not Found: Auth endpoints when auth is disabled
  • 500 Internal Server Error: Serialization failures
  • Rate limiting: 10 attempts per 60-second window per IP, counter resets on successful login

2.4 State Enrichment

API responses merge rig state with frontend metadata (FrontendMeta) via serde(flatten):

http_clients, rigctl_clients, audio_clients, rigctl_addr,
active_remote, remotes[], owner_callsign, owner_website_url,
owner_website_name, ais_vessel_url_base, show_sdr_gain_control,
initial_map_zoom, spectrum_coverage_margin_hz, spectrum_usable_span_ratio,
decode_history_retention_min, server_connected

This single-payload approach avoids extra round trips for UI configuration.


3. CLI Interface

3.1 Argument Style

Both trx-server and trx-client use clap for argument parsing with short and long flags:

-C, --config FILE           Path to configuration file
--print-config              Print example configuration and exit
-r, --rig NAME              Rig backend name
-l, --listen ADDR           Listen address
-p, --port NUM              Port number

Positional arguments are used sparingly (e.g. RIG_ADDR for serial/TCP address).

3.2 Configuration Resolution

Config files are searched in priority order:

  1. Current directory: trx-rs.toml
  2. XDG config: ~/.config/trx-rs/trx-rs.toml
  3. System: /etc/trx-rs/trx-rs.toml

The loaded config path is logged: INFO Loaded configuration from /path/to/config.toml

3.3 Example Config Generation

--print-config outputs a complete, commented TOML file to stdout with example values (callsign N0CALL, coordinates 52.2297, 21.0122). Each section has a header comment and each field has an inline description.

3.4 Startup Log Sequence

Server:

INFO Loaded configuration from /path/to/config.toml
INFO Starting trx-server with N rig(s): [rig-names]
INFO Callsign: CALL
INFO [rig-id] Starting (rig: ft817, access: serial /dev/ttyUSB0 @ 9600 baud)
INFO Listening on 0.0.0.0:4530

Client:

INFO Loaded configuration from /path/to/config.toml
INFO Starting trx-client (remotes: [remote-names], frontends: http,rigctl)
INFO rigctl frontend for rig 'default' on 127.0.0.1:4532

4. Configuration Wizard (trx-configurator)

4.1 Interactive Mode

Uses the dialoguer crate for terminal prompts:

  • Select menus for enumerated choices (config type, rig model, access type, log level)
  • Input for free-text with defaults (callsign defaults to N0CALL, listen defaults to 127.0.0.1)
  • Confirm for yes/no questions (enable auth, set location, etc.)
  • Serial port auto-detection with fallback to /dev/ttyUSB0

4.2 Non-Interactive Mode

--defaults generates a config file without prompts, using sensible defaults.

4.3 Config Validation

--check FILE validates an existing config file:

/path/to/config.toml: valid TOML
  Detected type: server
  warning: [general].log_level 'verbose' is invalid (expected: trace, debug, info, warn, error)
  1 warning(s), 0 error(s)

Validates: TOML syntax, unknown keys, log levels, coordinate ranges (-90..90 lat, -180..180 lon with pair requirement), access types, port ranges (0-65535).

4.4 File Write Confirmation

Prompts before overwriting an existing file. Outputs Wrote /path/to/file on success.


5. Error Handling and User-Facing Messages

5.1 Error Message Conventions

  • Contextual: Include file paths, section names, and peer addresses
    • "Failed to parse config file /path: error details"
    • "Unknown rig model: X (available: ft817, ft450d, soapysdr)"
  • Actionable: Suggest alternatives when available
    • "Rig model not specified. Use --rig or set [rig].model in config."
    • "Unknown frontend: X (available: http, rigctl, httpjson)"
  • Structured: Use field=value format in structured logging

5.2 Log Level Guidelines

Level Usage
INFO Startup milestones, configuration loaded, listening, client connect/disconnect, decoder state changes
WARN Non-fatal issues: command took too long, panel lock blocking, VFO priming failed, initial tune failed
ERROR Fatal or significant failures: CAT polling errors, client errors, parse failures

Logs suppress module targets (with_target(false)) for cleaner output.

5.3 Connection State Communication

  • Server logs: "Client connected: {peer}", "Client {peer} disconnected", "Client {peer} closing due to shutdown"
  • Rig task: "[rig-id] Rig backend ready", "Serial: /dev/ttyUSB0 @ 9600 baud"
  • Web UI: Connection-lost banner with reconnect indication, per-rig isolation

5.4 Graceful Degradation

  • Startup continues after non-fatal failures: "Initial PowerOn failed (continuing)"
  • Stream errors are deduplicated with 60-second summaries to avoid log flooding
  • Lock poisoning is recovered from rather than panicking
  • Unknown SSE events or lagged broadcast channels are silently skipped

6. Branding and Customisation

6.1 Owner Branding

Configurable via TOML and exposed via FrontendMeta:

  • owner_callsign -- displayed in header subtitle and About tab
  • owner_website_url / owner_website_name -- optional link in header
  • ais_vessel_url_base -- base URL for linking AIS vessel MMSI numbers

6.2 UI Behaviour Configuration

  • http_show_sdr_gain_control -- show/hide RF gain controls
  • http_initial_map_zoom -- default map zoom level
  • http_spectrum_coverage_margin_hz -- guard margin for spectrum center retune
  • http_spectrum_usable_span_ratio -- fraction of spectrum span treated as usable
  • http_decode_history_retention_min -- default history retention (per-rig overrides supported)

6.3 Embedded Assets

Logo and favicon are embedded at compile time via include_bytes!. The logo image has an onerror handler to hide itself if loading fails (this.style.display='none').


7. Security UX

7.1 Route Access Classification

Routes are classified into three tiers:

Tier Examples Requirement
Public /, /index.html, /map, /auth/*, static assets None
Read /status, /events, /audio, /decode, /spectrum, /bookmarks Rx or Control role
Control /set_freq, /set_mode, /set_ptt, /toggle_power, all other POST Control role only

7.2 Session Management

  • Sessions are 128-bit random hex tokens stored in HttpOnly cookies
  • Configurable TTL (default from TOML config)
  • Expired sessions auto-pruned on access
  • Constant-time passphrase comparison to mitigate timing attacks

7.3 TX Access Control

An additional tx_access_control_enabled flag can restrict transmit-related actions even for Control-role users, providing an extra safety layer.


8. Virtual Channels (SDR)

Virtual channels allow SDR users to monitor multiple frequencies simultaneously:

  • Channels appear in a picker row below the VFO controls
  • CRUD API: POST /channels/{remote} to create, DELETE to remove, PUT to update freq/mode/BW
  • Subscribe/unsubscribe audio per channel
  • Background decode channels (hidden, no audio stream back)
  • Channels auto-destroyed when out-of-bandwidth after center-frequency retune
  • Channel-list changes broadcast to SSE clients via event: channels

9. Design Principles (Inferred)

  1. Server-rendered SPA: All HTML/CSS/JS embedded in the binary -- zero external build tooling, no CDN dependency for core functionality (CDN used only for fonts and Leaflet maps).

  2. Progressive disclosure: Advanced controls (WFM, SAM, SDR settings, spectrum controls) are hidden by default and revealed based on the active mode and backend type.

  3. Keyboard-first, touch-aware: Spectrum supports full keyboard navigation alongside mouse and touch gestures. Mobile breakpoints enlarge hit targets and adapt layout.

  4. Real-time by default: SSE + WebSocket provide sub-second state updates without polling from the browser. 5-second ping heartbeat detects stale connections.

  5. Per-tab isolation: Each browser tab gets its own SSE session UUID and can independently select a rig, preventing cross-tab interference.

  6. Configuration over code: UI behaviour knobs (gain visibility, map zoom, history retention, spectrum margins) are exposed as TOML config rather than requiring code changes.

  7. Graceful degradation: The UI handles server disconnection gracefully with visible banners, and only the affected rig shows as disconnected in multi-rig setups.

  8. Defensive security defaults: Auth disabled by default for ease of setup, but when enabled, provides role-based access, rate limiting, constant-time comparison, and HttpOnly cookies.