Design system

One system, 12 themes

Every color, size and curve on this site comes from one set of tokens, and a theme is only a different set of values for them. This page renders the tokens with the same CSS the site uses, so it is always current. Change the theme from the knob in the header and watch it follow.

Principles

  1. Color means a byte role. In every theme, one hue is a status byte, one is data, one is meta. Decoration never borrows them.
  2. Hardware, sparingly. LEDs for what's on, keycaps that travel, a beat ruler at big breaks, a step grid behind the hero. Cues, never costume.
  3. Quiet until touched. Links and controls rest calm, answer on hover with a fine pointer, and always answer on press.
  4. Fast, honest motion. Under 300 ms, custom ease-out curves, nothing on keyboard shortcuts, no movement with reduced motion.

Themes

Each theme is a plain data file in src/themes/: colors for light, dark or both, three or four fonts, and a few type and shape settings. src/themes/registry.ts lists them. A first visit gets one at random from those with the visitor’s light or dark mode, and keeps it; the first, Field Guide, shows without JavaScript. Every theme and mode is tested for WCAG AA contrast (tests/themes.test.ts).

  • 01 Field Guide

    Warm paper and ink, with an ember status byte. A printed reference you can play.

    Archivo · Atkinson Hyperlegible Next · Atkinson Hyperlegible Mono

  • 02 Rhythm

    A drum machine at night: charcoal panel, condensed silkscreen, and red-orange-yellow step lights.

    Sofia Sans Condensed · Sofia Sans · JetBrains Mono

  • 03 Alloy

    Bead-blasted aluminum, black print and one orange key. A pocket synth’s industrial design.

    Instrument Sans · Martian Mono

  • 04 Score

    An engraved edition: ivory paper, serif type, oxblood markings, and staves for section breaks.

    Fraunces · Newsreader · IBM Plex Mono

  • 05 Phosphor

    A sequencer on an amber CRT: all monospace, amber phosphor, a faint glow on what’s lit.

    IBM Plex Mono

  • 06 Piano Roll

    A DAW at 2 a.m.: slate lanes, a bar ruler, lime notes and rounded clips.

    DM Sans · DM Mono

  • 07 Blueprint

    The spec as a technical drawing: drafting grid, condensed engineering type, square corners. Cyanotype in the dark.

    IBM Plex Sans · IBM Plex Mono

  • 08 Swiss

    International style: white, black and one red; a tight grotesk set big, flush left, square.

    Inter Tight · Inter · JetBrains Mono

  • 09 Riso

    A risograph zine: cream stock, blue and fluorescent-pink inks printed a touch off-register.

    Bricolage Grotesque · Space Mono

  • 10 Analog

    A 1970s synth panel: cream enamel, burnt orange and avocado, wide extended legends. Walnut at night.

    Jost · Red Hat Mono · Michroma

  • 11 After Hours

    The club at 3 a.m.: violet-black, magenta and cyan light, a wide rounded display face.

    Unbounded · Sora · JetBrains Mono

  • 12 Graphite

    A modern dev tool: cool neutrals, crisp hairlines, one electric blue. The quiet option.

    Geist · Geist Mono

Color

The semantic color tokens, as the current theme sets them. Components only use these names; a theme or a mode swaps the values.

Byte roles

  • 90

    Status

    Status bytes, links, the active section

    --accent

    --accent-soft

  • 3C

    Data

    Data bytes, success

    --data

    --data-soft

  • FF

    Meta

    Meta events, SysEx

    --meta

    --meta-soft

  • !

    Warn

    Cautions, unverified

    --warn

    --warn-soft

Surfaces

  • Sunken

    Inputs, code, readouts

    --surface-sunken

  • Page

    The paper everything sits on

    --bg

  • Raised

    Cards, panels, tables

    --surface

  • Floating

    Dialogs, selected segments

    --surface-raised

  • Fill

    Hover fills, quiet badges

    --surface-2

Ink and lines

  • Ink

    Headings and body

    --ink

  • Ink 2

    Secondary text

    --ink-2

  • Muted

    Meta, hints (4.5:1 on paper)

    --muted

  • Control

    Field borders (3:1)

    --control

  • Line strong

    Raised edges

    --line-strong

  • Line

    Hairlines and dividers

    --line

  • Focus

    Keyboard focus only

    --focus

  • Sky

    Chart series

    --sky

  • Olive

    Chart series

    --olive

Type

Each theme picks its own faces: one for display, one for text, a mono for bytes, and sometimes a fourth for the small uppercase labels. The theme cards above list them. Sizes are in rem so they follow the reader's text size. Tracking tightens as type grows (--tr-display −0.03em) and opens on uppercase labels (--tr-label 0.08em); leading tightens from 1.6 on body to 1.0 on display.

  • --t-display Home hero only

    The field guide

  • --t-3xl Page titles (h1)

    Message decoder

  • --t-2xl Section titles (h2)

    Running status

  • --t-xl Large numbers

    Pitch bend ±2 semitones

  • --t-lg Lede, h3

    A Note On is three bytes.

  • --t-base Body text

    Status bytes have the top bit set; data bytes never do.

  • --t-ui Buttons, nav, inputs

    Open a MIDI file

  • --t-md Card text, tables

    Header and track chunks, delta times, meta events.

  • --t-sm Hints, dense UI

    Paste or type bytes, e.g. B0 07 64

  • --t-xs Captions, badges, labels

    COMMERCIAL USE OK

  • --t-2xs Axis and key labels

    C4 C#4 D4

90 3C 64 Bytes are mono, bold, tabular, with a 0 that can't be mistaken for O.

Space

A 4px base. Layouts snap to these steps; one-off values are a bug.

  • --s-0
  • --s-1
  • --s-2
  • --s-3
  • --s-4
  • --s-5
  • --s-6
  • --s-7
  • --s-8
  • --s-9

Radii

Nested corners step down one size per level, so inner and outer curves stay concentric.

  • --r-2xs Keys, tiny marks
  • --r-xs Byte chips, badges, kbd
  • --r-sm Buttons, inputs, segments
  • --r-md Cards, tables, code
  • --r-lg Panels, dialogs
  • --r-pill Chips, search

Elevation

Five levels. Most themes use short shadows lit from above, with a highlight on the top edge, deeper in dark mode. Printed and drawn themes use rules or ink offsets instead.

  • Sunken

    A well you type or read into.

    --shadow-inset
  • Page

    Flat paper.

    none
  • Raised

    Resting cards and buttons.

    --shadow-1
  • Panel

    Tools; cards on hover.

    --shadow-2
  • Floating

    Search palette, dialogs.

    --shadow-3

Motion

Custom curves, because the CSS keywords are too weak, and never ease-in for UI. Press the buttons: each dot uses its curve at --d-slow, and you can reverse it mid-flight because these are transitions, not keyframes.

  • Ease out

    Anything entering or responding to input.

    --ease-out cubic-bezier(0.23, 1, 0.32, 1)

  • Ease in-out

    Something already on screen moving to a new place.

    --ease-in-out cubic-bezier(0.77, 0, 0.175, 1)

  • Drawer

    Menus and sheets sliding open.

    --ease-drawer cubic-bezier(0.32, 0.72, 0, 1)

TokenValueUse
--d-press100msPress feedback (scale 0.97)
--d-exit120msExits: faster than entrances
--d-fast140msHover and color changes
--d-base200msPopovers, toggles, chevrons
--d-slow280msDialogs, menus, theme change

Rules of thumb

  • Don't animate what people trigger from the keyboard dozens of times (the search palette opens instantly on ⌘K).
  • Hover effects only on devices with a fine pointer: @media (hover: hover) and (pointer: fine).
  • Things leave the way they came, and faster than they arrived: the same --ease-out at --d-exit.
  • With reduced motion, movement goes and color and opacity changes stay.

Focus

One ring for everything: --focus-width (2px, 3px with increased contrast) of --focus, offset --focus-offset from the edge, following the element's own radius. Text fields swap their border for the focus color and add a soft halo. Press Tab through the components below.

MIDI marks

A few hardware cues, kept small. Each theme recolors them, and none carries meaning on its own: an LED always sits next to a label or a state that says the same thing.

LED

.led, lit with .on. The MIDI IN light, the current section, the chosen theme. Color --led, bleed --led-blur.

Keycaps

Buttons have a lit top edge and a heavier lip; pressed, they travel down 1px and lose the lip.

Beat ruler

.rule-beats: a timeline's ticks for the big breaks between sections. Themes redraw it: step lights, staves, a heavy rule.

Texture

.textured draws the theme's --texture (a step grid, a piano roll, staves, dots) behind the hero, faded out from a focal point.

Icons

One set, drawn for this site in src/lib/icons.mjs: a 24px grid with a 2px safe area, one 2px stroke with round caps and joins, 2px corner radii, and solid fills only for the media glyphs and the star. Use <Icon name="…" /> in markup or iconSvg() in scripts; the favicons and social cards are generated from the same brand mark.

  • search
  • menu
  • close
  • sun
  • moon
  • code
  • upload
  • play
  • pause
  • stop
  • star
  • chevron-down
  • chevron-right
  • arrow-right
  • arrow-up-right
  • check
  • copy
  • plug
  • send
  • knob
  • shuffle
  • file
  • din
  • 2px safe area: nothing crosses it
  • Keylines: circle r 9, square 16, upright 14 × 18
  • Tall shapes (file, pause) use the upright keyline
  • Stroke 2 at 24px; scaled with the icon, so it is 1.33px at 16px

Components

Buttons

Heights --h-sm 32, --h-md 40, --h-lg 48; 44px minimum on touch screens. One primary per view.

Chips and segmented controls

Chips filter (any number on). A segmented control picks one of a few.

Fields

Inputs are sunken wells, so they never read as cards.

Marks

B00764F0 Commercial use OK Commercial use unclear Non-commercial Share-alike Archived ⌘ K

Callouts

Good to know

A Note On with velocity 0 is a Note Off.

Watch out

Free to use is not free to share.

Note

Running status lets a sender skip a status byte that repeats.

Cards and tables

StatusMessageData
8nNote Offnote, velocity
9nNote Onnote, velocity
BnControl Changecontroller, value

Panel

.widget

Interactive tools sit on a panel: --surface, --r-lg, --shadow-2.