Communitygithub.com

cdesiles/design-system

Construisez un système de design sous la forme de deux fichiers CSS que d'autres applications peuvent copier — tokens.css (propriétés personnalisées) et components.css (classes construites sur celles-ci) — documentés par une page de spécimen. Lisez ceci avant de concevoir quoi que ce soit ayant plus d'un écran, et chaque fois que le projet n'a pas de système existant.

Qu'est-ce que design-system ?

Cette compétence permet de construire un système de design modulaire et réutilisable, produisant trois fichiers : `design/tokens.css` (propriétés CSS personnalisées), `design/components.css` (classes de composants), et `design/Design System.html` (spécimen de documentation). L'approche distingue clairement les tokens primitifs (valeurs brutes comme les couleurs en Oklch) des tokens sémantiques (noms de rôles fonctionnels pointant vers les primitifs), permettant un rebranding en une seule ligne. Les composants n'utilisent que des tokens sémantiques, garantissant une cohérence et une évolutivité. Les règles strictes incluent le préfixage systématique, l'utilisation de CSS pur sans préprocesseur, et la mesure du contraste plutôt que l'estimation visuelle. La compétence s'applique à tout projet web, indépendamment du framework, et facilite l'extension, le rebranding et la maintenance d'interfaces utilisateur cohérentes.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/cdesiles/opencode-kit/tree/HEAD/skills/design-system

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Système de design

Le système est l'artefact. Tout le reste en découle. Un livrable qui invente ses propres couleurs et espacements est une pièce unique ; un livrable construit sur des tokens peut être étendu, rebrandé et maintenu cohérent.

Livrables

Trois fichiers, et la séparation est l'essentiel :

  • design/tokens.css — les tokens, et rien d'autre. Des propriétés CSS personnalisées simples.
  • design/components.css — les composants, sous forme de classes construites uniquement à partir des tokens sémantiques.
  • design/Design System.html — le spécimen. Il <link> les deux fichiers et les documente. Documentation seulement : il ne déclare aucune valeur propre.

Les deux fichiers CSS sont le système : ce sont eux que les autres applications copient. Le spécimen reste dans le projet comme leur documentation.

Sections du spécimen, dans cet ordre :

  1. Intention — trois phrases : à qui cela s'adresse, ce que cela doit évoquer, ce que cela n'est explicitement pas.
  2. Couleur — chaque échantillon avec son nom de token, la valeur résolue et les appariements qui passent le contraste.
  3. Typographie — familles, graisses, l'échelle avec un rôle nommé pour chaque palier, et un échantillon de paragraphe à la taille du corps.
  4. Espace et forme — l'échelle d'espacement, les rayons, les ombres, les bordures.
  5. Composants — chacun rendu dans ses états réels, à côté du balisage qu'une application copie.
  6. Règles — les cinq ou six décisions que quelqu'un prendrait mal.
  7. Utilisation dans une application — la version, les deux fichiers à copier, l'ordre de chargement, la balise <link> de la police, la classe racine, et ce qui a changé depuis la dernière version.

Tokens

Deux couches. Les primitives contiennent les valeurs brutes ; les tokens sémantiques nomment un rôle et pointent vers une primitive. Les composants ne référencent que les tokens sémantiques — c'est ce qui permet un rebranding en une seule ligne.

Écrivez ceci dans design/tokens.css. C'est le seul fichier du projet où une valeur brute peut apparaître. acme représente le préfixe du système (voir Partage) :

/* Acme design system 1.0.0 — tokens. Copiez ce fichier tel quel ; modifiez-le dans son projet source. */
:root {
  /* primitives */
  --acme-ink-900: oklch(0.22 0.02 260);
  --acme-ink-600: oklch(0.48 0.02 260);
  --acme-paper-50: oklch(0.99 0.005 90);
  --acme-paper-100: oklch(0.96 0.008 90);
  --acme-line-200: oklch(0.90 0.006 90);
  --acme-accent-500: oklch(0.55 0.14 35);
  --acme-accent-600: oklch(0.45 0.15 35);
  --acme-accent-100: oklch(0.94 0.03 35);

  /* sémantique */
  --acme-text: var(--acme-ink-900);
  --acme-text-muted: var(--acme-ink-600);
  --acme-bg: var(--acme-paper-50);
  --acme-surface: var(--acme-paper-100);
  --acme-border: var(--acme-line-200);
  --acme-accent: var(--acme-accent-500);
  --acme-accent-hover: var(--acme-accent-600);
  --acme-accent-wash: var(--acme-accent-100);

  /* typographie */
  --acme-font-display: "Fraunces", Georgia, serif;
  --acme-font-text: "Public Sans", system-ui, sans-serif;
  --acme-step--1: 0.875rem;
  --acme-step-0: 1rem;
  --acme-step-1: 1.25rem;
  --acme-step-2: 1.5625rem;
  --acme-step-3: 1.953rem;
  --acme-step-4: 2.441rem;
  --acme-step-5: 3.052rem;

  /* espace, sur une base de 4px */
  --acme-s-1: 4px;  --acme-s-2: 8px;   --acme-s-3: 12px;  --acme-s-4: 16px;
  --acme-s-5: 24px; --acme-s-6: 32px;  --acme-s-7: 48px;  --acme-s-8: 64px;  --acme-s-9: 96px;

  /* forme et mouvement */
  --acme-radius-sm: 4px; --acme-radius: 8px; --acme-radius-lg: 16px;
  --acme-border-width: 1px; --acme-ring-width: 2px;
  --acme-shadow-1: 0 1px 2px oklch(0.2 0.02 260 / 0.06);
  --acme-shadow-2: 0 4px 16px oklch(0.2 0.02 260 / 0.08);
  --acme-ease: cubic-bezier(0.2, 0.7, 0.3, 1);
  --acme-dur: 160ms;
}

Ce bloc est un point de départ, pas un modèle à copier aveuglément. Modifiez la teinte d'accentuation, la paire typographique et la chaleur de l'encre pour correspondre au brief — mais gardez la structure.

Règles pour les tokens

  • Le contraste est mesuré, pas estimé visuellement. Texte du corps 4,5:1 par rapport à son fond réel ; grands textes et bordures UI 3:1. Chaque page d'échantillons indique ses appariements.
  • Oklch, pas de hex aléatoire. Des palettes avec des paliers de luminosité égaux évitent un rendu boueux. Gardez la chroma approximativement constante dans une famille de teintes.
  • Pas de tokens inutilisés. Si rien ne référence un token, supprimez-le.
  • Aucune valeur en dehors de ce fichier. Un hex, une valeur littérale oklch(), une taille en px ou une ombre ailleurs est un token qui n'a pas encore été nommé.
  • Deux familles typographiques. Une pour l'affichage, une pour le texte. Les piles de secours doivent être réelles, pas seulement sans-serif.
  • Échelle, pas d'improvisation. Si une valeur n'est pas sur l'échelle d'espacement ou de typographie, ajoutez-la délibérément ou utilisez la plus proche.
  • Mode sombre seulement si demandé — mais gardez les couleurs sémantiques pour que l'ajout ultérieur soit un échange de token, pas une réécriture.

Composants

Écrivez-les dans design/components.css, et représentez chacun dans le spécimen dans les états par défaut, survol, focus, actif et désactivé quand ils s'appliquent :

  • Bouton — primaire, secondaire, fantôme. Une seule taille suffit généralement.
  • Champ de texte et sélection, avec étiquette, texte d'aide et état d'erreur.
  • Carte, avec un exemple de contenu réel, pas « Lorem ipsum ».
  • Navigation, en version bureau et rétrécie.
  • Tableau ou ligne de liste avec un en-tête.
  • Badge et étiquette.
  • Modale ou dialogue.
  • État vide.
  • Toast ou notification en ligne.

Chaque composant utilise uniquement des tokens sémantiques. Si un composant a besoin d'une valeur qui n'a pas de token, c'est une lacune dans le système — ajoutez le token, ne codez pas la valeur en dur.

/* Acme design system 1.0.0 — components. Needs tokens.css from the same version, loaded first. */

.acme {
  font-family: var(--acme-font-text);
  font-size: var(--acme-step-0);
  color: var(--acme-text);
  background: var(--acme-bg);
}

.acme-button {
  font: inherit;
  padding: var(--acme-s-2) var(--acme-s-4);
  border: var(--acme-border-width) solid transparent;
  border-radius: var(--acme-radius);
  background: var(--acme-accent);
  color: var(--acme-bg);
  transition: background var(--acme-dur) var(--acme-ease);
}
.acme-button:hover { background: var(--acme-accent-hover); }
.acme-button:focus-visible { outline: var(--acme-ring-width) solid var(--acme-accent); outline-offset: var(--acme-ring-width); }
.acme-button--ghost { background: transparent; color: var(--acme-accent); border-color: var(--acme-border); }

Partage

Les autres applications prennent le système en copiant tokens.css et components.css. Les règles ci-dessous permettent à une copie de fonctionner n'importe où.

  • Préfixez tout. Choisissez un nom court pour le système avant le premier token et mettez-le sur chaque propriété personnalisée et chaque classe : --acme-accent, .acme-button. Les copies se placent ensuite à côté du CSS de l'application sans collisions. Le préfixe fait partie de l'API ; ne le changez jamais.
  • CSS pur dans les deux fichiers. Pas de directives Tailwind, pas de syntaxe de préprocesseur, pas d'imbrication, pas d'exigence @layer, pas de @import entre eux. Une application React, une page statique ou un autre outil de design doit obtenir des résultats identiques à partir d'une copie directe.
  • Tout est résolu à l'exécution. Pas de calcul de couleur au moment de la construction, pas de sortie compilée.
  • Rien de global dans components.css. Pas de réinitialisations, pas de sélecteurs d'élément, rien sur html ou body : déposer le fichier dans une application ne doit pas la restyler. Les styles de texte de base vivent sur la classe racine .acme, qu'une application ajoute là où elle les souhaite.
  • Les états proviennent du balisage. Stylisez :hover, :focus-visible, :disabled, [aria-invalid="true"], [aria-current] et [aria-expanded] plutôt que des classes d'état qu'une application devrait basculer, afin que les composants fonctionnent avec n'importe quel HTML frameworké.
  • Facile à surcharger. Une classe par règle si possible, pas d'ID, pas de !important.
  • Une version pour les deux fichiers. La première ligne de chacun nomme le système et sa version ; incrémentez-la à chaque changement, dans les deux. Correctif pour une valeur modifiée, mineure pour un nouveau token ou composant, majeure pour une suppression. Renommez en ajoutant le nouveau token et en conservant l'ancien comme alias, --acme-old: var(--acme-new);, jusqu'à ce que les applications aient migré ; la suppression de l'alias est la version majeure.
  • Les choses spécifiques au projet restent dans le spécimen. Les balises <link> de polices, les largeurs de conteneur et les chemins d'actifs ne sont pas des tokens. Le spécimen montre la balise <link> de la police pour qu'une application puisse la copier avec les fichiers.

Si le projet cible a déjà un fichier de tokens, adaptez-vous à sa dénomination avant d'inventer la vôtre. Un vocabulaire partagé vaut mieux qu'un meilleur nom.

Page de spécimen

Le spécimen est une documentation pour les humains, pas une galerie de composants à admirer. Montrez le nom du token à côté de l'échantillon. Montrez chaque composant avec le balisage qu'une application copie. Notez les états difficiles à voir (anneaux de focus, désactivé).

Liez les deux fichiers, d'abord les tokens, et mettez la classe racine sur <body>. Utilisez la propre typographie et l'espacement du système pour disposer le spécimen — c'est la première preuve que le système fonctionne.

Lisez les valeurs du fichier au lieu de les taper, afin que la documentation ne puisse pas dériver :

<link rel="stylesheet" href="tokens.css">
<link rel="stylesheet" href="components.css">
…
<body class="acme">
<figure class="swatch" data-token="--acme-accent-500"></figure>
…
<script>
  for (const el of document.querySelectorAll('[data-token]')) {
    const name = el.dataset.token;
    const value = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
    el.dataset.value = value;                // affiché par CSS
    el.style.setProperty('--swatch', value); // peint par CSS
  }
</script>

L'échantillon se peint lui-même à partir du token et affiche la valeur résolue par le navigateur. Un hex tapé à la main est un futur mensonge.

Finalisation

Exécutez design-verify sur le spécimen. Il liste toute occurrence de couleur littérale dans le spécimen ou dans components.css ; il ne devrait y en avoir aucune. Vérifiez que chaque étiquette d'échantillon est lisible, que chaque composant est aligné sur la même grille de base, et qu'aucun texte échantillon ne déborde de son conteneur à 1024 px de large.

Lorsque le système va dans une autre application, celle-ci copie tokens.css et components.css inchangés, ainsi que la balise <link> de la police depuis le spécimen — pas le spécimen lui-même. Exportez une copie autonome du spécimen uniquement si elle doit être lue dans un endroit sans le dossier.

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

Skills associés