Réglages

Apparence

Thème

Couleurs

Primary — tonique
Neutre — gris / slate

Typographie

Titres
Corps

1 · Primitives

Le catalogue brut. Aucune sémantique, aucune référence. Jamais modifié par projet.

Fichier généré. tokens/primitives/color.json est produit par npm run ramps:write — ne l'édite pas à la main, il serait écrasé.

Les rampes de couleur

Chaque palette est définie par une teinte + un pic de chroma. Ses 11 crans sont calculés en OKLCH sur une courbe de luminosité commune à toutes les palettes.

2550100200300400500600700800900
α5α10
gray
25
50
100
200
300
400
500
600
700
800
900
5%
10%
blue
25
50
100
200
300
400
500
600
700
800
900
5%
10%
red
25
50
100
200
300
400
500
600
700
800
900
5%
10%
green
25
50
100
200
300
400
500
600
700
800
900
5%
10%
orange
25
50
100
200
300
400
500
600
700
800
900
5%
10%
turquoise
25
50
100
200
300
400
500
600
700
800
900
5%
10%
slateBlue
25
50
100
200
300
400
500
600
700
800
900
5%
10%
slateViolet
25
50
100
200
300
400
500
600
700
800
900
5%
10%
violet
25
50
100
200
300
400
500
600
700
800
900
5%
10%

Survole un aplat pour son hex et sa luminosité perçue (L*).

Pourquoi une courbe commune. Des rampes dessinées à la main dérivent : le cran 500 valait 55 % de luminosité en gray et 89 % en turquoise (un néon). Un bouton primaire en turquoise donnait alors un contraste de 1,85:1 — illisible. Comme les rôles sont interchangeables, un rôle sémantique ne peut tenir sa promesse de contraste que si toutes les palettes partagent la même courbe. Après régénération : 4,60:1.

OKLCH et pas HSL : la luminosité HSL n'est pas perceptuelle — un jaune et un bleu à L=50 % n'ont rien à voir à l'œil. OKLCH, si.

Les voiles alpha

Chaque teinte expose un voile translucide à 5 % et 10 % (colonnes α ci-dessus, sur damier), calculé sur son cran 500. Ils servent aux fonds d'états : survol et état actif d'un bouton outlined ou ghost, ligne de tableau sélectionnée.

L'alpha vit DANS la palette, pas dans un groupe color.alpha.* séparé. Le rôle brand.primary alias la palette entière : changer la tonique emporte donc l'alpha avec elle. Un groupe séparé obligerait à swapper deux fois — et un oubli donnerait un bouton violet au survol turquoise.

Un voile se compose sur le fond qui est dessous : il s'adapte tout seul au thème sombre. Les tokens alpha sont donc identiques en light et dark.

Les échelles de taille

size.spacing

Échelle d'espacement brute. Sert aux paddings et aux gaps.

size.spacing.00
size.spacing.12px
size.spacing.24px
size.spacing.38px
size.spacing.412px
size.spacing.516px
size.spacing.620px
size.spacing.724px
size.spacing.832px
size.spacing.940px
size.spacing.1048px
size.spacing.1164px

size.radius

Échelle d'arrondi brute.

size.radius.none0
size.radius.sm4px
size.radius.md8px
size.radius.lg16px
size.radius.xl24px
size.radius.full9999px

size.border

Échelle d'épaisseur de bordure brute.

size.border.none0
size.border.sm1px
size.border.md2px
size.border.lg4px

size.container

Largeurs de conteneur borné (modale, panneau, feuille). Le consommateur les combine avec un min(…, Nvw) pour rester responsive : le token donne la largeur MAXIMALE, pas une largeur figée.

size.container.sm360px
size.container.md480px
size.container.lg640px
size.container.xl800px

size.breakpoint

Points de rupture. Une media query CSS ne peut pas lire une custom property : la valeur est inlinée par le build.

size.breakpoint.xs480px
size.breakpoint.sm640px
size.breakpoint.md768px
size.breakpoint.lg1024px
size.breakpoint.xl1280px

Les polices

Le catalogue typographique brut : piles de polices, graisses, interlignes, approches. Comme les couleurs, rien n'est choisi ici — c'est le brand qui désigne la pile qui joue heading, body et mono. C'est ici qu'un rôle typo trouve sa weight, sa lineHeight et son letterSpacing.

font.stack

Catalogue de piles de polices. AUCUNE n'est choisie ici : c'est la couche brand (`font.brand.*`) qui désigne celle qui joue le rôle sans / serif / mono. Ajouter une pile ici ne change rien tant que le brand ne la sélectionne pas.

font.stack.interInter, system-ui, -apple-system, sans-serif
font.stack.geistGeist, system-ui, -apple-system, sans-serif
font.stack.systemSanssystem-ui, -apple-system, 'Segoe UI', sans-serif
font.stack.georgiaGeorgia, 'Times New Roman', serif
font.stack.jetbrainsMono'JetBrains Mono', ui-monospace, 'SF Mono', monospace
font.stack.systemMonoui-monospace, 'SF Mono', Menlo, monospace

font.weight

font.weight.regular400
font.weight.medium500
font.weight.semibold600
font.weight.bold700

font.lineHeight

Sans unité : l'interligne se multiplie par le corps du texte, il suit donc la bascule mobile tout seul.

font.lineHeight.tight1.2
font.lineHeight.normal1.5
font.lineHeight.relaxed1.75

font.letterSpacing

En `em`, jamais en px : l'approche doit être PROPORTIONNELLE au corps, sinon un titre passé de 48px à 32px en mobile garderait un crénage calculé pour 48px. Le principe est optique — plus le texte est gros, plus on resserre ; plus il est petit ou capitalisé, plus on aère.

font.letterSpacing.tight-0.02em
font.letterSpacing.snug-0.01em
font.letterSpacing.normal0
font.letterSpacing.wide0.02em
font.letterSpacing.caps0.08em