@spunto/design-systemthe material everything is made of

The material
everything is made of.

Not a side project — it’s the package this website, the Spunto console and Spunto Lite all render from. Warm oklch tokens, a quasi-square 4px radius, and twenty-odd React primitives on Base UI, including an xterm.js terminal and a Docker image-pull bar. Everything below is the real component, rendered on this page, in whichever theme you’re reading in.

20+ primitivesReact + Base UItokens in oklchan xterm terminal
one command · your machine
$ npm i @spunto/design-system

the tokens are one CSS import; the components come with it

01The tokens

Warm on purpose. Never neutral grey.

Everything is oklch, so lightening a colour doesn’t change its hue and the dark theme is the light one with the lightness rebalanced rather than a second palette to maintain. The values below are the ones in the package’s stylesheet — flip the theme and they change with the swatches.

Brand

Build → Ship → Run, plus the flame the whole thing is named after

--build
oklch(0.79 0.155 70)
Build — dev environments
--ship
oklch(0.72 0.185 52)
Ship — deployments
--run
oklch(0.66 0.205 42)
Run — logs and stats
--flame
oklch(0.64 0.205 41)
the brand accent

Surface

warm cream by default, warm charcoal in the dark — never neutral grey

--background
oklch(0.975 0.012 82)
the page
--card
oklch(0.995 0.006 86)
raised surfaces
--muted
oklch(0.955 0.012 80)
quiet fills
--border
oklch(0.89 0.016 76)
every hairline on this site

Status

green means running, amber means look at me, red means it broke

--success
oklch(0.62 0.145 152)
running · online · done
--warning
oklch(0.74 0.16 68)
degraded · needs attention
--destructive
oklch(0.577 0.245 27.325)
failed · destructive action
--info
oklch(0.58 0.13 245)
neutral information
radius
0.25rem — every other radius derives from it, so squaring the whole system is one line
type
Syne for display, Geist Sans for text, Geist Mono for anything a machine wrote
shadows
none. The app kills every box-shadow on purpose; depth comes from hairlines
semantics
Build / Ship / Run are utilities (text-build, bg-ship/15) — not hex codes in a component
02The primitives

on Base UI

Small, boring, consistent.

The parts a product actually spends its day on. Nothing here is trying to be clever — the value is that the console, the marketing site and the self-hosted app all reach for the same button.

Button — five variants, four sizes

readyv0.9.3stoppederror

Badge — status, at a glance

SP

Spinner · Skeleton · Avatar

Input · Label

Switch · Checkbox · RadioGroup

Tabs — Base UI, sliding indicator

Alert — the persistent counterpart to toast()

shop-web
node:22 · 2 repos · ports 3000, 5432
Ready in 8.6s on fra-1.

Card

Quasi-square by design

--radius: 0.25rem — the whole scale derives from it

Separator · the 4px radius, everywhere

03The ones you can't npm install elsewhere

A terminal and a pull bar, as components.

Terminal wraps xterm.js with the theme, fit-on-resize and a search API, and is transport-agnostic — feed it from a WebSocket, a log file or a recording. TerminalPanel is the frame around it: title, status, actions, and the connecting/empty/error states you always end up writing twice.

ImagePull is the other one: a Docker pull drawn as a single segmented bar, one block per layer. Purely presentational — hand it a snapshot, it draws it.

Terminal
xterm.js + theme + fit + search, fed through a ref handle
TerminalPanel
the bar, the surface, and every state a connection can be in
ImagePull
one segmented bar per pull, one block per layer
overlays
Dialog, AlertDialog, Select, Tooltip and toast() under one provider
shop-web-1

a real TerminalPanel, replaying a real session

04Using it

Two lines to adopt the whole thing.

The tokens ship as one CSS file, so you can take the palette without the components, or the components and restyle them — they’re Tailwind classes over Base UI, not a black box.

install
npm i @spunto/design-system
app/globals.css
/* one import for the tokens — light by default, .dark for the rest */
@import "@spunto/design-system/styles.css";
anywhere.tsx
import { Button, Badge, TerminalPanel } from "@spunto/design-system"

export function Deploy() {
  return (
    <div className="flex items-center gap-2">
      <Badge variant="secondary">v0.9.3</Badge>
      <Button size="sm">Deploy</Button>
    </div>
  )
}

documented twice

Once for you. Once for the agent.

The showcase is data-driven, so the same source feeds the visual pages and a plain-markdown surface an LLM can read without a browser: an index at /llms.txt, one /<component>.md per primitive with its full props API, the foundations, and /llms-full.txt for everything at once.

Which matters more than it sounds: most of the code in this ecosystem is written by agents, and an agent that can read the props API stops inventing a fifth button variant.

also from Spunto