@spunto/design-systemla matière dont tout est fait

La matière
dont tout est fait.

Pas un projet annexe : c’est le paquet avec lequel s’affichent ce site, la console Spunto et Spunto Lite. C’est shadcn/ui restylé, pas un design system réécrit de zéro : des tokens oklch chaleureux, un rayon quasi carré de 4 px, et une vingtaine de primitives React sur Base UI, plus celles que shadcn n’a pas — un terminal xterm.js et une barre de pull d’image Docker. Tout ce qui suit est le vrai composant, rendu sur cette page, dans le thème où vous la lisez.

20+ primitivesReact + Base UItokens en oklchun terminal xterm
une commande · votre machine
$ npm i @spunto/design-system

les tokens tiennent en un import CSS ; les composants viennent avec

01 — Les tokens

Chaud, volontairement. Jamais de gris neutre.

Tout est en oklch : éclaircir une couleur ne change pas sa teinte, et le thème sombre est le thème clair avec la luminosité rééquilibrée plutôt qu’une seconde palette à maintenir. Les valeurs ci-dessous sont celles de la feuille de style du paquet — basculez le thème et elles changent avec les pastilles.

Marque

trois voisines chaudes — les tokens build, ship, run — plus la flamme qui a donné son nom à l’ensemble

--build
oklch(0.79 0.155 70)
Build — environnements de dev
--ship
oklch(0.72 0.185 52)
l’accent entre build et run
--run
oklch(0.66 0.205 42)
Run — logs et statistiques
--flame
oklch(0.64 0.205 41)
l’accent de la marque

Surface

crème chaud par défaut, anthracite chaud en sombre — jamais de gris neutre

--background
oklch(0.975 0.012 82)
la page
--card
oklch(0.995 0.006 86)
les surfaces surélevées
--muted
oklch(0.955 0.012 80)
les aplats discrets
--border
oklch(0.89 0.016 76)
chaque filet de ce site

Statut

vert : ça tourne ; ambre : regardez-moi ; rouge : c’est cassé

--success
oklch(0.62 0.145 152)
en marche · en ligne · terminé
--warning
oklch(0.74 0.16 68)
dégradé · demande de l’attention
--destructive
oklch(0.577 0.245 27.325)
échec · action destructrice
--info
oklch(0.58 0.13 245)
information neutre
rayon
0.25rem — tous les autres rayons en dérivent : rendre tout le système carré tient en une ligne
typo
Syne pour les titres, Geist Sans pour le texte, Geist Mono pour tout ce qu’a écrit une machine
ombres
aucune. L’app supprime chaque box-shadow exprès ; la profondeur vient des filets
sémantique
les accents sont des utilitaires (text-build, bg-ship/15) — pas des codes hex dans un composant
02 — Les primitives

shadcn/ui, sur Base UI

Petites, banales, cohérentes.

Les pièces sur lesquelles un produit passe vraiment ses journées. Rien ici ne cherche à être malin — l’intérêt, c’est que la console, le site et l’app auto-hébergée prennent tous le même bouton.

Presque toutes ont commencé comme composants shadcn/ui, copiés depuis sa variante Base UI et restylés pour cette palette. Le contrat des tokens, le helper cn et le motif des variantes sont aussi ceux de shadcn. À chacun son dû : shadcn-ui/ui (MIT) est la base de tout ce qui est sur cette page, et si vous ne tenez pas à notre style, utilisez-le directement.

Button — cinq variantes, quatre tailles

prêtv0.9.3arrêtéerreur

Badge — un statut d’un coup d’œil

SP

Spinner · Skeleton · Avatar

Input · Label

Switch · Checkbox · RadioGroup

Tabs — Base UI, indicateur glissant

Alert — le pendant persistant de toast()

shop-web
node:22 · 2 dépôts · ports 3000, 5432
Prête en 8,6 s sur fra-1.

Card

Quasi carré, à dessein

--radius: 0.25rem — toute l’échelle en dérive

Separator · le rayon de 4 px, partout

03 — Ceux qu’on ne trouve pas ailleurs sur npm

Un terminal et une barre de pull, en composants.

Terminal enveloppe xterm.js avec le thème, l’ajustement au redimensionnement et une API de recherche, et ne dépend d’aucun transport — alimentez-le depuis un WebSocket, un fichier de log ou un enregistrement. TerminalPanel en est le cadre : titre, statut, actions, et les états connexion/vide/erreur qu’on finit toujours par écrire deux fois.

ImagePull est l’autre : un docker pull dessiné en une seule barre segmentée, un bloc par couche. Purement visuel — donnez-lui un instantané, il le dessine.

Terminal
xterm.js + thème + fit + recherche, alimenté par un handle de ref
TerminalPanel
la barre, la surface et chaque état où peut se trouver une connexion
ImagePull
une barre segmentée par pull, un bloc par couche
overlays
Dialog, AlertDialog, Select, Tooltip et toast() sous un seul provider
shop-web-1

un vrai TerminalPanel, qui rejoue une vraie session

04 — S’en servir

Deux lignes pour tout adopter.

Les tokens tiennent en un fichier CSS : vous pouvez prendre la palette sans les composants, ou les composants et les restyler — ce sont des classes Tailwind sur Base UI, pas une boîte noire.

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>
  )
}

documenté deux fois

Une fois pour vous. Une fois pour l’agent.

Le showcase est piloté par les données : la même source alimente les pages visuelles et une surface en markdown brut qu’un LLM lit sans navigateur — un index à /llms.txt, un /<component>.md par primitive avec toute son API de props, les fondations, et /llms-full.txt pour tout d’un coup.

Ça compte plus qu’il n’y paraît : la plupart du code de cet écosystème est écrit par des agents, et un agent qui peut lire l’API de props cesse d’inventer une cinquième variante de bouton.

↳ aussi chez Spunto