Design tokens
Every colour, type, space, corner, shadow and motion token a page uses.
The tokens of the design system, as Tailwind utilities. A page gets them from the theme, once in its CSS: @import "@0x1audio/design-system/theme.css". A custom page shows the setup.
Colour
Use these as Tailwind utilities (bg-card, text-muted-foreground, border-border). They follow light and dark on their own.
| Need | Use | Not |
|---|---|---|
| The page | bg-background | |
| A raised surface: a card, a group of settings | bg-card with border-border | a shadow at rest |
| Something floating: a menu, a dialog, a toast | bg-popover with shadow-lg (the components do this) | |
| Text | text-foreground; text-muted-foreground for secondary text; text-subtle-foreground for hints, counts and column headers | a grey below 4.5:1 contrast for anything people must read |
| Lines | border-border, a hairline; border-border-strong for outline buttons and chips | a border where space already separates |
| Hover, pressed, selected | bg-hover, bg-pressed, bg-selected | a different colour for each state |
| Fields | bg-field, hover:bg-field-hover | |
| Status | text-destructive, text-success, text-warning-foreground | status colours as decoration |
| Focus | the ring every component shows on :focus-visible | removing outlines; a coloured ring |
| A waveform's resting bars | bg-wave or fill-wave; the part already played is ink (text-foreground) | a grey from the text scale; colour in a waveform |
| Behind a dialog | bg-scrim | |
| Your accent | accent in app.json, and <AppHero accent="#20b4c4" /> | your accent on buttons, text or backgrounds below the hero |
Tints are derived, not new colours. A status wash is the status token at a fixed opacity: bg-success/8, bg-warning/8 and bg-destructive/6 for fills, border-success/25 and the like for lines. Callout with a tone does this for you.
bg-chrome and lit belong to Mixel's own window frame and its live indicators, so apps don't use them.
Type
Figtree, included with the theme. Seven sizes, each with its own line height and tracking:
| Token | Size / line | Use |
|---|---|---|
text-display | 32 / 36 | One hero line, and rarely in an app |
text-title | 22 / 28 | The page title (PageHeader, AppHero) |
text-heading | 15 / 22 | Section titles, dialog titles, empty-state titles |
text-body | 14 / 20 | Rows, buttons, paragraphs |
text-small | 13 / 18 | Secondary text, menu items, labels, facts lines |
text-caption | 12 / 16 | Meta lines and counts |
text-micro | 11 / 14 | Column headers, menu labels, shortcuts |
- Weights: 400 for body text, 500 for labels and row titles, 600 for headings.
- Numbers that change or line up get
tabular-nums: lengths, BPM, counts, percentages. - Sentence case everywhere, and no all-caps labels.
- Tailwind's own sizes (
text-sm,text-lg) and fixed sizes liketext-[13px]are off the scale.
Space
A 4 px grid, which is Tailwind's spacing scale. The rhythm that repeats:
- The page:
px-8at the sides.PageHeaderbrings its own space above and below; aPageSectionispy-4, withgap-2between its title and its content. - Rows: 40 px (
min-h-10) for a list of sounds or files,gap-pxapart. Hover fills separate rows, not dividers. - Toolbars: every control
h-8, withgap-2between them.
Shared widths and grids are tokens, not fixed values: max-w-dialog, max-w-settings, max-w-page, and grid-cols-(--grid-tiles), grid-cols-(--grid-cards), grid-cols-(--grid-label-value). Never w-[26rem].
Corners
Crisp corners, to sit with Mixel's pixel mark.
| Token | Size | Use |
|---|---|---|
rounded-sm | 4 px | Kbd, tiny chips |
rounded-md | 6 px | Rows, small buttons, menu items |
rounded-lg | 8 px | Buttons, fields, tiles, toolbar controls |
rounded-xl | 12 px | Cards, dialogs, popovers, the hero |
rounded-full | Round play buttons, avatars, switches | |
rounded-icon | 22% | App icons only |
Never more than rounded-xl on a container.
Elevation
| Token | Use |
|---|---|
| none | Everything at rest on the page. A hairline border is enough. |
shadow-xs | Filled buttons, app icons |
shadow-sm | The active tab of a segmented control; a card lifting on hover, one step only |
shadow-md | A popover close to what opened it |
shadow-lg | Menus, dialogs, toasts |
No coloured shadows, no glows, and no blur as decoration.
Motion
| Token | Value | Use |
|---|---|---|
--duration-fast | 120 ms | Colour, background, border and press. Built into every component. |
--duration | 180 ms | Entering, cross-fades, menus opening |
--duration-slow | 280 ms | Dialogs, progress bars, larger moves |
--ease-out | Everything entering or responding | |
--ease-in-out | Something moving between two places | |
--ease-spring | A dialog scaling in, once |
- New content enters with
animate-enter. A list cascades withstaggeron the list andstyle={{ "--i": index }}on each item. - Buttons press to
active:scale-98. Nothing grows on hover. - Menus and dialogs open from what opened them, and close faster than they open. The components do this.
- Only live work loops: an indeterminate
Progress, aSkeleton. Nothing loops for decoration. - Reduced motion is handled by the theme.