Documentation
Design system
The rules behind the interface: principles, information architecture, tokens, icons, components and a measurable design QA.
The rules behind vinyl-check’s interface: principles, information architecture, layout, tokens, icons, components, key screens, accessibility and a measurable design QA. The approach follows Otl Aicher’s systematic design: a set of rules rather than a collection of attractive pages.
- Visual preview of icons, colours, type, components and screen sketches: design-preview.html (open it in a browser; it follows the system’s light or dark setting).
- Icon sprite:
vinylcheck/static/icons.svg. Logo files:vinylcheck/static/brand/. - Tokens in code: the custom properties at the top of
vinylcheck/static/style.css.
Parts of this document describe the target state. Items not yet built are marked proposal, and the implementation status lists what is done.
Inputs
| Product | vinyl-check, a web application that records a record side, counts clicks, grades the condition, compares before and after cleaning, measures the turntable’s alignment with a test record, and compares test pressings with the master. Live: levels, a 31-band analyzer, listening with rewind. |
| Users | Audio-aware people at the turntable and at the desk: collectors who care about condition, audio and mastering engineers, studios and pressing plants checking test pressings. Two contexts of use: at the turntable (standing, hands on stylus and record, looking at a tablet or laptop from 1–1.5 m) and at the desk (reading results, comparing, documenting). Occasionally others in the same network read along. There are no accounts and no roles. |
| Main tasks | record a side (before), clean, record again (after), compare, grade; alignment run with the test record and live measurement at the anti-skating dial; create records (Discogs); calibration. Rarely: configuration, retention, integrity. |
| Platform | a responsive web app served by the station on the local network. Desktop browsers, tablets and phones at the turntable. Works offline: no CDNs, no web fonts. |
| Brand | black and anthracite as main colours, dark as the main mood and light as the variant. Own pictograms and wordmark. A red accent stands for the record label. |
| Technology | plain JavaScript without libraries or a build step, FastAPI, status over WebSocket, charts on <canvas>. Everything this system defines must be expressible with CSS custom properties, a small set of classes and one SVG sprite. |
| Language | multilingual (English and German, more via catalogs). Numbers and dates follow the reader’s locale. Units are separated by a space (−20 dBFS, 3.01 g), and negative values use a true minus sign. |
A. Product understanding
What it is: a measuring station with a protocol. Two procedures share the same recording chain: the record check (condition of a record, effect of a cleaning) and the turntable check (condition of the turntable). Both produce recordings (WAV plus measurements) and findings (value, target, verdict, text).
| Context | Goal | Must be grasped quickly | Time-critical |
|---|---|---|---|
| At the turntable | start a recording safely, lower the stylus, let the side play, turn the anti-skating dial | Is it running? Since when? Clipping? Dropouts? Which side and condition? How loud? | start/stop, the “GO” for the stylus, reacting to clipping |
| At the desk | read findings, compare before and after, settle the grade, decide on alignment | grade, clicks per minute, change against the previous recording, status per figure | nothing |
Tasks by frequency
| Level | Tasks |
|---|---|
| Frequent (per record) | choose record · record a side (before) · after · listen · read the result · compare · accept the grade |
| Regular | alignment run (after changes, a new stylus, as a check) · live measurement · calibration (stylus up) |
| Administrative | create a record or take it from Discogs · device and channels in the configuration · retention · integrity check · deployment |
| Special cases | clipping, dropouts, platter stop, network loss, mono recording, live album, 45 rpm, records with four or more sides |
Decisions the interface must support: Is the recording usable (clipping, dropouts)? Did the cleaning help, beyond the repeatability? Which grade? Which alignment setting is better? Do I need to adjust the turntable, and what first?
Where errors are expensive: a lost recording (play the side again, 25 minutes), wrong alignment advice (physical adjustment of stylus and arm), a wrong grade written to Discogs. Consequences: never show a finding without its target and explanation, always show why something stopped, and show the state of the recording chain before every start.
B. Design principles
- The station is a transport, not a form. The deck bar is always on top: state, time, level and one primary button per state (ready → Record side, running → Stop). Everything else ranks below it, because the time-critical actions happen with the hands on the record.
- A number is not a finding. Every figure appears as a quartet of value · target · verdict · explanation. Raw values without context only appear in expandable details.
- Time is the common axis. Overview, spectrogram, events, skips and the listening position share one time axis and one interaction pattern: click = listen, drag = zoom, double-click = everything, keyboard = type a time + ▶. No two charts behave differently.
- Two channels, two colours, everywhere. Left is blue and right is violet, in meters, the analyzer, curves and tables. Status colours (green, yellow, red) are never used for channels, so red is never ambiguous.
- Status speaks in words.
ok · note · problemis always shown as icon, word and colour. The recording state is a word plus time, and grades are letters with a score. Colour alone carries nothing. - Readable from 1.5 metres. While recording, state and time grow to 40 px, meters are wide bars, targets are at least 44 px, and the dark mode suits the listening corner. Nothing important is available on hover only.
- Nothing disappears silently. Automatic stop, retention, dropouts, deleted audio, lost connection: each state has a sentence with the reason and the next action.
- Raw data stays reachable, but second. Band times, WAV path, SHA-256, device and format are there (monospace, under Details), but never before the finding.
- The system lives in tokens, not pages. No library, no web fonts, no build: everything defined here maps to a
--tokenand a class instyle.css. Whatever cannot be expressed that way is designed wrongly.
C. Information architecture
Main navigation (order = frequency):
| Area | Icon | Content |
|---|---|---|
| Overview | tonearm | chain state, recent recordings, next up |
| Record check | disc | list and search → record → recording → comparison |
| Turntable check | sliders | turntable profiles → alignment runs → run → sides and bands → run comparison; live measurement in the deck |
| System | clock | running and queued jobs, machine load |
| Settings | nut | recording, retention, Discogs, clipping, engineer mode, learning, display and language, targets, device and service (read-only) |
The deck belongs to no area. It stays in place when you switch areas, because a recording keeps running wherever you are reading. The mental model is “one device with a transport, plus an archive”.
Hierarchy and addresses (proposal beyond the top-level areas, which already have # addresses): #station ·
#records/12 · #records/12/recording/16 · #compare/15/16 · #turntable/5 · #turntable/compare/4/5. Every
detail page has a breadcrumb (Records › Test Artist – Test Album › Recording 16). At most three levels deep.
Terms (binding): record · side (A, B, C …) · recording (condition: uncleaned, after wet cleaning, after dry cleaning, other; plus calibration and alignment) · comparison · run (alignment) · band (of the test record) · finding (one measured result) · grade (condition) · deck (transport) · chain (turntable → phono stage → interface → station) · copy (one physical copy of a record). Use one term per concept and no synonyms: not “setup” for run, not “session” or “take” for recording, not “monitor” for level check.
Search and filters. The global search is the record search (local records and the Discogs collection in one field, results in two groups). Local filters: recordings by condition and side; events by kind (pop, click, crackle), region and minimum strength; alignment findings by status. Active filters appear as chips above the table with reset all next to them. There are no saved views: Recent on the overview covers the last record and the last run.
Roles: none. Proposal for readers on other devices: identical navigation, transport buttons disabled with the note “operate at the station”.
D. Screen inventory
| # | Screen | Type | Purpose |
|---|---|---|---|
| 1 | Deck | persistent | state, time, level, primary action; expandable: analyzer, listening, live measurement |
| 2 | Overview | dashboard | chain state (calibration, storage, device), recent recordings, next up |
| 3 | Records | list and search | find or create a record, cover, latest grade, number of recordings |
| 4 | Record | detail and table | master data, cover, recordings per side, comparisons, copies, history |
| 5 | Recording report | detail and analysis | grade header, time axis, spectrogram, events, skips, details |
| 6 | Comparison | analysis | two or more recordings: deltas, common time axis, removed / new / persistent clicks, repeatability |
| 7 | Turntable profiles and runs | list | profiles, runs with their settings (tracking force, anti-skating, VTA, hours) |
| 8 | Run | detail and findings | findings of both sides, bands, deviations |
| 9 | Run comparison | analysis | two runs side by side, difference per figure, better or worse |
| 10 | Live measurement | deck, expanded | distortion L/R, test tone, level, frequency trend, analyzer |
| 11 | Settings | settings | editable settings, read-only device and service values with the path of the configuration file |
| 12 | System | status | jobs, queue, history, load |
| 13 | Dialogs | form / critical | record a side (proposal: as a dialog), create record or run, delete with consequences |
| 14 | Banner | system status | connection lost, storage full, not calibrated, demo mode, analysis running, new version waiting |
Layout types: dashboard (2), list (3, 7), detail (4, 8), analysis (5, 6, 9, 10), settings (11), dialog (13). There is one assistant, the five-step turntable profile, because alignment has a fixed order. The record check is linear enough for the deck and the record page to lead it, with a next up line instead of a wizard.
E. Core workflows
W1 – Check a record (most frequent)
- Overview: the deck shows “ready · chain calibrated · 2 GB free”. The primary action Record side stays disabled, with the reason, until a record is chosen.
- Records: search (one field), take a hit from Discogs or create a record. It is now the chosen record.
- Record side with prefilled values (side A, uncleaned, 33⅓, last cleaning method) → Start recording.
- The deck switches to recording (large:
● Recording · uncleaned · Side A · 0:00) with the hint “Lower the stylus, include the lead-in groove”. Listening is possible. - The side plays. Clipping and dropouts appear immediately as a line in the deck (word and number, not just colour).
- End groove → automatic stop with the line “End groove detected, stopped automatically” → “Analysing” with progress.
- The result replaces the progress line: grade, clicks per minute, noise, plus Open recording, Next: side B and Record after cleaning.
- After cleaning: step 3 with the cleaning condition, method prefilled. The record then offers the comparison in one click.
W2 – Alignment run: create a run (settings as number fields with units) → record side 1 → side 2 → findings sorted problem / note / ok → “what to do” per row → compare with the previous run.
W3 – Live at the anti-skating dial: deck Live measurement → play the band → large distortion figures L/R with the distance to the threshold and a 60 s curve → adjust → see the reaction → stop. Nothing needs to be saved.
W4 – Decide after a comparison: the comparison shows the change per figure against the repeatability (two uncleaned recordings): “−18 clicks/min, scatter ±3 → real improvement”. Accept the grade.
W5 – First use and calibration: the overview shows “not calibrated” as a banner with a button → instructions (stylus up, 20–30 s) → result with value and verdict.
W6 – Disruption (proposal): clipping, dropouts or a platter stop → the deck offers Cancel and restart (one action: stop, mark the recording as discarded, start a new one with the same details).
F. Layout system
- Spacing: 8 px system, scale
4 · 8 · 12 · 16 · 24 · 32 · 48(--s-1 … --s-7). Card padding 16, heading to content 12, groups 24, sections 32. - Breakpoints: S < 600 (phone), M 600–1023 (tablet, at the turntable), L 1024–1439 (laptop), XL ≥ 1440 (content limited to 1440 and centred). Page margin 16 / 24 / 32 / 32.
- Grid: 12 columns from L, 8 on M, 4 on S, gutters 16 / 24.
- Page structure: header (title, navigation, system state) → deck (sticky, 64 px when ready, up to 200 px when
active) → content. List and detail as two columns,
320 px | rest, from L. On M and S they follow each other with a back arrow. - Content widths: running text and finding texts at most 72 characters. Tables and charts use the full width, and charts have fixed heights (overview 160, spectrogram 160 per row, analyzer 180).
- Cards only for independent units: record, recording, run, deck. Inside them, spacing and headings structure the content: no nested cards, no shadows.
G. Visual system
Typography
System fonts, no web fonts: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif. Monospace:
ui-monospace, "SF Mono", Menlo, Consolas, monospace. Five sizes, two weights:
| Role | Size / line | Weight | Example |
|---|---|---|---|
| Page title | 24/32 | 600 | “Test Artist – Test Album” |
| Section heading | 18/24 | 600 | “Recordings, side A” |
| Body, tables, labels | 15/22 | 400 (labels 600) | finding texts |
| Meta, help, chips | 13/18 | 400 | “recorded 2026-01-15 14:52 · Turntable A · 24 bit / 48 kHz” |
| Micro (axes, legend) | 12/16 | 400 | “third-octave bands 20 Hz – 20 kHz” |
| Key figure (deck, grade header) | 40/44 | 600, tabular-nums |
“23:41”, “VG+”, “12.4 /min” |
All numbers use font-variant-numeric: tabular-nums. Technical values (hash, path, device hw:CARD=CODEC,DEV=0,
versions) are monospace 13. Units are separated by a space, and negative values use −.
Colours
Tokens for dark (main mood) and light:
| Token | Dark | Light | Role |
|---|---|---|---|
--bg |
#141516 |
#eef0f1 |
page background (black / light grey) |
--card |
#202224 |
#ffffff |
cards, dialogs (anthracite / white) |
--ink |
#e9eaeb |
#1a1b1c |
text |
--muted |
#9da1a5 |
#5f6468 |
meta and help text (AA on bg and card) |
--line |
#34373a |
#d5d8db |
borders, dividers, chart grid |
--accent |
#e05a48 |
#b7382c |
primary action and recording state, nothing else |
--focus |
#7fb3ff |
#1a5fb4 |
focus ring, 2 px with 2 px offset |
--ok / --warn / --bad |
#58c08a / #e3b45c / #e05a48 |
#2a7a4c / #8f6210 / #b7382c |
verdicts ok / note / problem |
--info |
#7fb3ff |
#1a5fb4 |
notes without a verdict |
--left / --right |
#6fa9e8 / #bf8de8 |
#2255a4 / #7640b0 |
channel left / right |
--quiet |
rgba(88,192,138,.12) |
rgba(42,122,76,.10) |
quiet passages on the time axis |
--pop / --click / --tick |
#e05a48 / #e3b45c / #7d8185 |
#b7382c / #8f6210 / #8a8e92 |
event kinds (also by shape: pop = diamond, click = line, crackle = dot) |
--removed / --persistent / --new |
#58c08a / #e05a48 / #7fb3ff |
#2a7a4c / #b7382c / #1a5fb4 |
comparison results |
--wave |
#86a8d4 |
#3d5a80 |
waveforms and level curves |
Neutrals have no colour cast. The right channel is violet, not red, because red already means error and accent.
--warn is dark enough for 4.5 : 1 on white. Contrast: text ≥ 4.5 : 1, bars and icons ≥ 3 : 1 against their
background, checked in the design QA.
Brand
The wordmark “vinyl-check” and the signet (a record with a tonearm, where the red dot is the label) live in
vinylcheck/static/brand/ in anthracite and inverted versions. They are drawn with the same tool as the
pictograms: monoline, stroke 3 on 24 units, square ends, only lines, circles and arcs. Clear space is the height of
the signet. Minimum height is 20 px for the logo and 16 px for the signet (favicon). See the
brand README.
Icons
File icons.svg, used as <svg class="i"><use href="icons.svg#i-rec"/></svg>. 24 px box, 2 px stroke, square ends
and corners (square / miter), 2 px inner margin, only circle, line, rectangle and 45° diagonal. Transport icons
(record, stop, play) are filled, and all others are outlined: two recognisable families with the same
geometry. Sizes are 16 (in text), 20 (buttons, tables) and 24 (navigation). Every icon has exactly one meaning:
| Icon | Meaning | Icon | Meaning |
|---|---|---|---|
disc |
record, record check | tonearm |
station, overview, lower the stylus |
rec ● |
recording, start recording | stop ■ |
stop |
play ▶ |
listen (to a position) | listen |
listen live |
rew prev / next fwd |
30 s or 5 s back / forward (always with the time) | live |
back to live |
back |
rewind (with a time label) | level |
level, level check |
analyzer |
31-band analyzer | spectro |
spectrogram |
click |
clicks, events | skip |
groove skip |
compare |
comparison | clean |
cleaning |
calibrate |
calibration (stylus up) | sliders |
alignment, turntable check |
testrecord |
test record, band | nut |
settings |
search |
search | cover |
cover, Discogs |
ok warn bad info |
verdicts and notes | clock |
retention, time, jobs |
storage |
storage | wifi / offline |
connection / connection lost |
sweep |
sweep | wave |
hum and rumble, master |
trash |
delete | export |
export (WAV, CSV) |
close |
close | chevron |
next, expand |
Rules: important actions always have icon and word (“■ Stop”). Icon-only buttons are only for close, expand and
play, with aria-label and a tooltip. Never two icons for the same function.
Shapes, lines, radii, shadows, motion
Radius 4 (buttons, fields, chips), 8 (cards, dialogs), 0 (tables, charts). Lines are 1 px --line, and focus is 2 px
--focus. Shadows only for dialogs and toasts (0 8px 24px rgba(0,0,0,.18)). Motion: 120 ms in and out, 200 ms for
layer changes. Meters and the analyzer have ballistics for technical reasons, not decoration.
prefers-reduced-motion removes transitions and the meters’ decay.
Data display
One time-axis component for overview, spectrogram and events (same scale, same interaction, same legend: pop ◆ red,
click | yellow, crackle · grey, quiet = --quiet area). Bars for comparisons (before and after per figure), lines
for trends (live distortion, frequency response), tables for findings. No pie charts. Grades appear as a chip
VG+ · 78, always next to their criterion (“12.4 clicks/min in the music”). Every figure carries its period or
reference (“relative to the 1 kHz reference”, “side A, 23:41”).
H. Components
Shared states for all interactive elements: default · hover (background −4 %) · focus-visible (ring) · active
(background −8 %) · selected (border --ink) · disabled (opacity 45 %, with the reason in a tooltip or next to it) ·
loading (16 px spinner on the left, text stays). Keyboard: tab order = reading order, Enter and Space activate, Esc
closes, arrows move in tabs, menus and the time axis (±1 s, Shift ±10 s).
| Component | Variants / sizes | Notes |
|---|---|---|
| Button | primary (--accent, one per area), secondary (outline), danger (delete and discard only: red text, filled on hover), text link; 36 px / 44 px (at the turntable) |
icon and word; long labels do not wrap, the button grows; disabled with a reason |
| Icon button | 36 / 44 px | close, expand, play only; aria-label required |
| Text field, number field with unit, text area | 36 / 44 px, unit inside on the right (g, dB, h) |
label above, help below, error below with an icon; placeholders only as examples |
| Select / combobox | side, condition, speed; record search (local and Discogs, grouped) | arrows and Enter; results with a 32 px cover |
| Checkbox / radio / toggle | 20 px box; toggle only for instant switches (listening, dark mode) | selection in tables = checkbox column |
| Chip (filter, grade, status) | status (icon and word), filter (removable ×), grade | never colour only |
| Badge | on tabs and buttons (“Compare (2)”) | |
| Status line (deck) | ready / level check / recording / analysing / error | word, time and icon; recording in --accent |
| Level meter | L/R, RMS, peak and hold, scale −60 … 0, clip mark | role="meter", number next to it |
| Analyzer | 31 bands, L/R, ballistics | text alternative: “loudest band 125 Hz −32 dB” |
| Finding row | status chip · figure · value with unit · target · text · ▶ band | sortable by status, expandable for raw values |
| Time axis | 160 px high; zoom, click to listen; markers | one component, three data sources |
| Table | sorting, fixed first column, row actions on the right | on S: cards with three key values |
| Tooltip | 13 px, 300 ms, also on focus | never the only source of information |
| Dropdown menu | row actions (“…”) | arrows, Esc |
| Tabs | areas at the top; sub-tabs in a recording (time axis / spectrogram / events / details) | role="tablist" |
| Accordion | Details (raw values, paths, hash) | closed by default |
| Pagination | event table | “Showing 1–50 of 412” |
| Breadcrumb | from depth 2 | |
| Toast | success and error 4 s; errors with Details stay | top right, at most one |
| Banner | connection, storage, calibration, demo mode, analysis running, new version | below the header, with an action |
| Dialog | 480 px, full screen on S; focus moves in and back | primary on the right, cancel on the left |
| Drawer | recording details on M and S instead of two columns | |
| Card | record, recording, run, deck | no shadows |
| Empty state | 24 px icon, sentence and action | see K |
| Skeleton | tables and charts loading longer than 300 ms | |
| Progress | analysis (estimate, progress where known), upload | with cancel where possible |
Long text: titles wrap to at most two lines, then “…” with the full text in a tooltip and the detail view; table cells with titles do the same; numbers never wrap. Small screens: full-width buttons in dialogs, tables become cards, time axes stay full width with zoom, and the spectrogram is shown from M up (on S a note and a link).
I. Key screens
1 · Deck (transport, persistent). Purpose: the state of the station at a glance and one action. Hierarchy:
state and time (large) → level → warning line → buttons. Ready: ready · Turntable A · calibrated (−91 dBFS) · 2.1 GB free, primary Record side (naming the chosen record, or “choose a record”), secondary Check level,
Live measurement, Calibration. Recording: ● Recording · uncleaned · Side A · 12:34 (40 px), wide meters, a
warning line (“0 clipped · 0 dropouts”), primary ■ Stop, secondary Listen (with −30 s, −5 s, Live) and
Analyzer (open/close). Error: a red line with the reason and Cancel and restart. Never empty. On S: two rows
(state and time above the meters), buttons as a bar at the bottom within thumb reach.
2 · Overview. Purpose: “Is everything ready, what happened last, what now?” Cards: Chain (device, format, calibration with date, storage, retention, each line with a verdict) · Recent (last five recordings: record, side, condition, grade, date, open) · Next up (context-dependent: “Record side B of …”, “View comparison 15 ↔ 16”, “Run 5 is missing side 2”). Primary: the first next up action. Empty state on first use: “No recording yet. 1 · Calibrate 2 · Add a record 3 · Record a side” as a list with buttons.
4 · Record. Header: 96 px cover, artist – title (24 px), condition in the collection and measured grade per copy, primary Record side. Table Recordings: side · copy · condition · date · duration · grade · clicks/min · status · actions (open, compare, …). Selecting two rows enables Compare (2). Filters: side and condition as chips. Status: “analysed”, “waiting (2nd)”, “error: recording shorter than 3 s”. Empty: “No recording. Record side A uncleaned.” On S: one card per recording with side, condition, grade and date.
5 · Recording report. Grade header: grade VG+ · 78 with its criterion · clicks per minute (music and quiet
passages) · noise · skips · warnings (clipping, dropouts, mono, live album). Then the time axis (overview with
events, quiet areas, skip markers), spectrogram, events (time, kind, strength, level, channel, region, ▶; filters by
kind, region and minimum strength) and details (device, format, duration, SHA-256, path, audio deleted on …,
analysis version). Primary: Compare with … (proposal: preselect the last other recording of the same side).
Secondary: listen, export, delete (danger, in the menu). Failed analysis: the header shows the reason and Analyse
again. Audio deleted after retention: ▶ disabled with the date, measurements stay.
6 · Comparison. Header: A vs. B (condition, date, cleaning) · delta table (figure, A, B, Δ, repeatability, verdict “real / within scatter”) · common time axis (removed green, new blue, persistent red; Shift+click plays B) · skips. Empty: only one recording → “A second recording of the same side is needed.”
8 · Alignment run. Header: settings as chips (3.01 g · anti-skating 3 · no weight · Turntable A), sides with
status (side 1 ✓, side 2 missing → primary Record side 2). Findings sorted problem → note → ok, columns status ·
figure · value · target · explanation · ▶ band. Below: bands (time, type, channel image, role, level; unassigned
ones grey with the reason). Comparison with the previous run as an optional Δ column. Empty: “No side recorded yet.”
10 · Live measurement. Expanded deck: on the left, large distortion figures L / R (40 px, with the distance to
the 3 % threshold as text), the test tone (315 Hz · −18.2 dBFS) and the channel image; on the right, 60 s curves
(distortion, level, frequency) and the analyzer. “No test tone” only after 2 s. Responsive: figures first, curves
below.
11 · Settings. Two columns, label · value with explanation and default. Values that live in the configuration file (device, format, channels, paths) are shown read-only, with the path of the file and what to do after changing it, because the sandboxed service cannot write there.
J. Accessibility checklist (WCAG 2.2 AA)
- Every action by keyboard: deck buttons, table actions, the time axis (arrows ±1 s / ±10 s, Enter = listen), dialogs (Esc, focus trap, focus return).
- Focus ring 2 px
--focuswith 2 px offset on everything interactive, neveroutline: nonewithout a replacement. - Contrast ≥ 4.5 : 1 for text (including
--mutedand--warn), ≥ 3 : 1 for icons, bars, borders and focus, checked in both themes. - Status never by colour alone: chips with icon and word, channels labelled “L” and “R”, event kinds with shapes.
- Meters and the analyzer with
role="meter"/aria-valuenowor a text alternative; time axes with a summary text and the event table as an equivalent view. - Every form field with a
<label>, errors viaaria-describedby, required fields marked in the label. - Live changes (recording state, automatic stop, analysis finished) in an
aria-live="polite"region, errorsassertive. - Targets at least 24 × 24 px everywhere, at least 44 px in the deck and on M and S.
- 200 % zoom without horizontal scrolling (except tables in a scroll container), text sizes in
rem. -
prefers-reduced-motion: no transitions, meters without decay, analyzer in 1 s steps. - The
langattribute matches the interface language. Abbreviations explained on first use (THD, IMD, dBFS in a tooltip or glossary). - Icon-only buttons with
aria-label; tooltips also on focus.
K. Edge cases
| Case | Behaviour |
|---|---|
| First use | the overview leads: calibrate → record → side; the deck’s primary action is disabled with the reason |
| No calibration | banner with a button; recording allowed, noise verdict “without reference” |
| No Discogs match / Discogs unreachable | local matches first; “Discogs not reachable” as a note; manual creation still possible |
| Clipping or dropouts while recording | warning line in the deck at once, with a number; the result carries the warning |
| Platter stop, stylus skips, wrong side | as above; proposal: mark the recording as discarded (stays visible, greyed out) |
| Automatic stop fails or stops too early | the reason line shows what was detected; manual stop always possible; switch in the settings |
| Connection lost | banner “Connection to the station lost · for 12 s · recording continues”, deck frozen with a timestamp, listening stops with a note |
| Low storage / data drive missing | banner with the number, start blocked with the reason (“1.2 GB free, minimum 2 GB”) |
| Mono recording, wrong format | warning in the findings; figures that cannot be measured say “not measurable: …” instead of staying empty |
| Live album, pedal tones | a note instead of a misleading figure: “quiet passages contain audience” |
| 45 rpm, 10” / 7”, box sets | speed in the form; free side names (C1, D2); radius estimate marked as an estimate |
| Very long titles or artists | two lines, then “…”, tooltip and detail view; flexible title column |
| Audio deleted after retention | ▶ disabled with the date, spectrogram from the database stays, listening not available |
| Analysis error / queue | status “waiting (2nd)”, “error: …” with retry |
| Two browsers at once | both see the same state; start and stop from either |
| Invalid address | “Record 999 does not exist (deleted?)” and back to the list |
| Demo mode (file instead of turntable) | a permanent yellow banner |
L. Design QA (measurable)
- Every view has exactly one primary button (
.primary), counted by a DOM test. - Every status display consists of icon and word (no
.pillwithout text, no coloured dot without a label). - Contrast of all text tokens ≥ 4.5 : 1 and of all icons and bars ≥ 3 : 1 in both themes (script over the token table).
- All numbers in tables and the deck use
tabular-nums; technical values are monospace (sample check). - Only values of the spacing scale in
margin,paddingandgap(lint: multiples of 4). - At most five font sizes plus the key-figure size in the CSS; no inline
font-size. - No function by hover only; every row action is reachable by keyboard (tab through).
- Targets: deck ≥ 44 px, otherwise ≥ 24 px (measured in the DOM).
- Every table has an empty state with reason and action; every list a skeleton from 300 ms.
- Every figure in the grade header has its unit and reference in the same element.
- Icons only from
icons.svg, and every<use>points to a defined ID (lint). prefers-reduced-motiondisables all transitions (CSS test).- Lighthouse accessibility ≥ 95 on overview, record, recording report and run.
- First render without any network request except to the station (network log).
- No user-visible text outside the translation catalogs (test:
tests/test_i18n.py), and layouts checked with the longest language.
Risks
- Canvas charts stay pictures. Without text alternatives and keyboard access, half of the information is
mouse-only. Countermeasure: build the time axis as one component with an
ariasummary, arrow keys and the event table as an equivalent view before adding further charts. - The deck gets overloaded (analyzer, listening, live measurement, warnings). Countermeasure, a hard rule: the bar only holds state, time, level, the warning line and buttons. Everything else is expandable and closed by default on M and S.
- Translations break layouts. German words are long, and other languages may be longer. Countermeasure: buttons grow instead of truncating, labels wrap, and every new screen is checked in the longest language.
Implementation status
Done:
- Tokens and the icon sprite in
style.cssandicons.svg; channel right in violet; focus ring;prefers-reduced-motion; tabular numbers. - Logo and signet in the header and as favicon.
- Deck with meters, recording state, warnings and transport buttons; listening with rewind; analyzer and live measurement.
- Overview with chain, recent recordings and next up; System and Settings as separate areas.
- The recording report as its own page with a synchronised time cursor across clicks, level and spectrogram charts.
- Multilingual interface with catalogs.
Open (proposals), in order of benefit:
- Status chips with icon and word everywhere; banners instead of pills for states that need an action.
- URL state for detail pages and breadcrumbs.
- Tabs in the recording report; the time axis as one keyboard-operable component.
- A Record side dialog with prefilled values; Cancel and restart; discarded recordings.