Repository navigation
App Design Guidelines
Snapshot of
app/DESIGN.mdat commit707b4a0, preserved before the docs were compacted. History only: the current specs are in the repository.
How the app looks and how to style new things. Theme Midnight (dark, the default look) with its light companion Daylight. The source of truth for the visual design is the design canvas:
Design canvas: https://claude.ai/artifact/EbUJGUthCwaCc33u4b24LZ (boards: themes and components, icon set, pod icon, pod as a button, app icon, splash, phone layouts for Pod, Programs and Simulate)
When a change needs a new look, design it on the canvas first, then build it with the tokens below.
All colours, spacing and radii are CSS custom properties in src/app/theme.css. Never write a
colour in a component's CSS; use a token, so both themes work. The dark values are Midnight, the
light values Daylight (prefers-color-scheme).
| Token | Midnight | Daylight | Use |
|---|---|---|---|
--bg |
#0b1426 |
#eef3fb |
page background, header |
--surface |
#122039 |
#ffffff |
cards, sections, sheets |
--surface-2 |
#1a2c4d |
#e2eaf6 |
inputs, rows inside cards, segmented controls |
--border |
#26395e |
#c9d5e8 |
card and input borders |
--text |
#e7eefa |
#0b1630 |
text |
--text-muted |
#93a5c6 |
#4a5c7e |
secondary text, inactive icons |
--accent |
#5b9bff |
#1e5bd8 |
the one accent: primary buttons, links, active tab |
--accent-contrast |
#06122b |
#ffffff |
text on --accent
|
--accent-soft |
#1b3566 |
#dce7fc |
active tab pill, selected states |
--ok / --warn / --error
|
#34d399 / #fbbf4b / #ff6b81
|
#11804a / #a85a00 / #c21e3a
|
status |
--floating-* |
the floating tab bar (translucent background, border, shadow) | ||
--pod-* |
same in both | the pod puck (it is the dark device in both themes) | |
--led-* |
same in both | LED colours of the firmware, only where they mean LED colours |
Contrast: text at least 4.5:1 against its background in both themes. Colours that must be told apart also differ in lightness, not only in hue.
-
--font-display(Barlow Semi Condensed 600/700): page titles (26 px), pod names, big numbers such as reaction times. -
--font(Inter 400/500/600): everything else; body 16 px, labels 13–14 px. -
--font-mono: paths, expressions, block ids.
Both fonts are bundled (@fontsource, latin subset, imported in src/main.tsx) so the app works offline.
- Lucide icons with one thick stroke:
svg.lucide { stroke-width: var(--icon-stroke) }(2.5) intheme.css, so a plain<Icon size={20} aria-hidden />is already right. Don't passstrokeWidth. - Pick glyphs with few strokes; 20–24 px in lists and buttons, 24 px in the tab bar.
-
The pod icon is
PodIcon(src/components/PodIcon.tsx, canvas "C2 · back rim"): a puck whose back rim glows. Use it everywhere a pod, the set or the connection to a pod is meant; never Lucide'sRadioor similar. The glow colour comes from--pod-glow(default green); a container sets--pod-glow: currentColorto switch the glow off (inactive tabs do).
A pod is drawn as a raised puck (LedRing in src/components/LedRing.tsx): one cap with a
drop edge, the 18 LEDs as light segments on the cap rim. Use it for every pod and every LED
pattern, never a flat ring.
- Optional text inside the cap:
title(pod name, or the pod count in lists) andsubtitle(state, only on big pucks). No labels under the puck. - When the pod can be pressed (Simulate), the whole puck is the button;
pressedmoves the cap down. Size by pod count: 140 px for 1–2 pods, 116 px for 3–4, 96 px for more. - Small pucks (lists): 56–64 px, the pod count inside.
- Mobile first: touch targets ≥ 44 px, everything works without drag and drop, nothing cut off at 360 px.
- Phone: header (page title in the display font, connection chip, settings) and a floating tab
bar with at most five tabs (Pod, Programs, Editor, Simulate, Results). It floats 12 px above
the bottom edge;
.mainkeeps room for it. Fixed elements (the + button) sit above it, toasts at the top. The program menu is linked from the Pod page. - From 900 px: side rail with all destinations, no tab bar.
- Cards:
--surface, 1 px--border, radius--radius-m–--radius-l. No coloured stripes on the left edge; mark a type with an icon tile instead. - One primary button per view (filled
--accent); the rest are outlined or plain.
- App icon and favicon: the six-segment ring, 4 blue "ready" segments and 2 green "go" segments,
white button in the middle. Generated by
npm run icons(scripts/make-icons.mjs→public/icons/); change the script, not the files. - Splash: static HTML and CSS in
index.html(a big puck with "ReactPod" in the cap, the LED segments chasing in the icon's colours, the cap pressing down). React replaces it when it mounts. The animation stops underprefers-reduced-motion.
npm run build, npm run preview, then screenshots with playwright-core
(scripts/screenshots.mjs) at 360 px and 1200 px, in both colour schemes. Look at the screenshots.
For users and coaches
Repository and workflow
Firmware
- Firmware Overview
- Firmware Architecture
- Firmware Link Protocol
- Firmware Config API
- Firmware Programs
- Firmware Testing
- Firmware Timing
- Firmware Host Syntax Check
Config App
Community platform (on hold)
Decisions (ADRs)
- Decisions
- ADR 0001 Repo Layout and Workflow
- ADR 0002 Versions and Firmware Delivery
- ADR 0003 Community Platform
- ADR 0004 Platform Architecture
- ADR 0005 Live Results over BLE
- ADR 0006 No OTA
- ADR 0007 Platform on Hold
Archive