wisp-diagram : produire des diagrammes de style Wisp
Objectif : produire des diagrammes cohérents, thématisables et portables. Fichiers sources (.excalidraw / .drawio) + *.wisp.svg généré : le même SVG suit le thème du site lorsqu'il est intégré dans un site Wisp, et suit la préférence système (clair/sombre) lorsqu'il est utilisé comme <img> dans un README GitHub ou un autre blog.
Ce répertoire de compétence est autonome et peut être copié dans n'importe quel projet (~/.claude/skills/ ou <projet>/.claude/skills/). Les scripts sont en Python, exécutés avec uv : le point d'entrée scripts/wisp_diagram.py déclare ses dépendances via PEP 723 en en-tête, et uv run crée automatiquement un environnement isolé – pas besoin de npm / pip install.
SKILL.md
palette.json la palette (source unique de couleurs)
reference/ style-guide.md excalidraw-skeleton.md drawio-cheatsheet.md ml-patterns.md
assets/ wisp.excalidrawlib wisp-drawio-library.xml drawio-config.json drawio-colors.txt
scripts/ wisp_diagram.py (point d'entrée unique) wisp_diagram_lib/ (implémentation) tests/ (pytest)
Préparation unique
Les commandes ci-dessous s'exécutent toutes à la racine du projet, $W représente le script d'entrée du skill (ajustez le chemin selon l'emplacement réel du skill) :
W="uv run skills/wisp-diagram/scripts/wisp_diagram.py" # par ex. .claude/skills/wisp-diagram/... ou ~/.claude/skills/wisp-diagram/...
uv run --with playwright==1.64.1 playwright install chromium # navigateur headless pour l'export (ignorer si déjà installé)
$W probe # vérifier la disponibilité de Chromium, Excalidraw, draw.io (cli / docker / browser)
Le premier lancement télécharge et met en cache (ensuite utilisable hors ligne) :
| Contenu | Source | Taille |
|---|---|---|
| Dépendances Python playwright 1.64.1, fonttools | PyPI (géré par uv, dans le cache de uv) | ≈ 55 Mo |
| Chromium (seulement s'il n'est pas installé) | playwright install chromium, dans ~/.cache/ms-playwright/ | plusieurs centaines de Mo |
| @excalidraw/excalidraw 0.18.1 et ses dépendances (≈110 modules ES) | jsDelivr, version verrouillée | ≈ 1,6 Mo |
| svgo 4.1.0 (build navigateur, pour la minification SVG, exécuté dans Chromium) | jsDelivr | 0,8 Mo |
| Polices : Excalifont, Inter 5.3.0, Noto Sans SC 5.3.1 (découpées par unicode-range, téléchargement à la demande) | jsDelivr | Total ≈ 4,5 Mo |
| draw.io viewer (uniquement en mode d'export browser) | viewer.diagrams.net | ≈ 4,7 Mo |
À l'exception des dépendances Python et de Chromium, le cache se trouve dans ~/.cache/wisp-diagram/ (variable WISP_DIAGRAM_CACHE pour changer l'emplacement). Utilisez $W cache status pour voir l'état, $W cache clear pour vider.
Utilisation hors ligne : exécutez d'abord $W cache warm dans un environnement connecté (télécharge toutes les ressources frontend du tableau ci-dessus, ≈ 11 Mo), puis définissez WISP_DIAGRAM_OFFLINE=1 pour être complètement hors ligne ; si un fichier est manquant, une erreur sera levée avec une suggestion de préchauffage, sans connexion silencieuse. Vous pouvez également utiliser WISP_EXCALIDRAW_BUNDLE=<fichier JS local> pour spécifier votre propre build Excalidraw (une IIFE définissant window.__wisp, ou un module ES exportant des fonctions comme exportToSvg), et WISP_DRAWIO_VIEWER=<fichier local> pour le viewer draw.io.
L'export draw.io utilise un mécanisme de repli automatique : cli → docker → browser. Les commandes new, build, export nécessitent Chromium (l'export Excalidraw et la minification svgo s'exécutent dans le navigateur headless) ; lint, normalize, check n'en ont pas besoin.
1. Choisir l'outil
| Scénario | Choix | Fichier source |
|---|---|---|
| Diagrammes structurés : organigrammes, séquences, états, classes, relations entre nœuds | Mermaid (le plus simple, directement dans des blocs ```mermaid dans le texte ; le site Wisp les rend à la construction) | Aucun fichier séparé |
| Diagrammes conceptuels, illustrations intuitives, style manuscrit, flux de données ML | Excalidraw | nom.excalidraw (JSON) |
| Schémas de modèles alignés avec précision, architectures en couches, lignes brisées à angle droit, plusieurs pages | draw.io | nom.drawio (XML non compressé) |
| Démonstrations pas à pas, interactives | Hors du périmètre de ce skill (composants React) | — |
Principe : si Mermaid suffit à expliquer clairement, évitez de dessiner ; le style manuscrit ne dépasse pas environ 12 nœuds ; gardez un style cohérent dans un même article.
2. Workflow (5 étapes)
L'exemple ci-dessous utilise diagrams/attention, adaptez les chemins à votre situation.
① Déterminer le type (voir tableau ci-dessus). Une fois choisi, lisez la référence correspondante : Excalidraw → reference/excalidraw-skeleton.md ; draw.io → reference/drawio-cheatsheet.md. Les motifs de diagrammes ML courants peuvent être copiés directement depuis reference/ml-patterns.md et modifiés. Les principes de disposition se trouvent dans reference/style-guide.md.
② Générer le fichier source
- Excalidraw : écrivez un squelette JSON (position, dimensions, label, nom de couleur sémantique, ID de début/fin de flèche), puis convertissez. Interdiction d'écrire manuellement un élément Excalidraw complet (les champs seed, boundElements, version sont très sujets aux erreurs).
Le fichier squelette peut être supprimé après conversion ou conservé comme script de génération ; ensuite, c'est le fichier$W new diagrams/attention.skeleton.json -o diagrams/attention.excalidraw.excalidrawqui fait foi. - draw.io : écrivez directement le XML mxGraph non compressé, en utilisant uniquement les chaînes de style prédéfinies dans
reference/drawio-cheatsheet.md. Si vous obtenez un fichier.drawiocompressé, décompressez-le d'abord avec$W normalize diagrams/file.drawio. - Pour dessiner manuellement dans un éditeur : importez
assets/wisp.excalidrawlib(Excalidraw : Library → Open dans le panneau de droite) ouassets/wisp-drawio-library.xml(draw.io : File → Open Library from → Device), puis configurez la palette selonassets/drawio-colors.txt.
③ Lint (réparez d'abord) puis build
$W lint diagrams/attention.excalidraw --fix # attire les couleurs hors palette vers le jeton le plus proche ; celles qui ne peuvent pas être corrigées automatiquement sont listées
$W lint diagrams/attention.excalidraw --strict # aucun error/warn n'est accepté
$W build diagrams/attention.excalidraw # génère diagrams/attention.wisp.svg
Paramètres courants de build : --embed-fonts (incorpore un sous-ensemble de polices, à utiliser pour la publication sur des plateformes externes), --fix, --title T --desc D (remplace le texte d'accessibilité, fichier unique seulement), --drawio cli|docker|browser, --out-dir DIR, --strict. Pour un drawio multipage, la page 2 et suivantes sont générées sous la forme nom.page-2.wisp.svg.
④ Auto-vérification : exportez les aperçus clair et sombre, visualisez avec l'outil de lecture
$W export diagrams/attention.wisp.svg --theme light -o /tmp/attention.light.png
$W export diagrams/attention.wisp.svg --theme dark -o /tmp/attention.dark.png
Vérifiez : texte qui se chevauche, flèches traversant des nœuds, étiquettes écrasant la tête de flèche, éléments illisibles en mode sombre, texte chinois tronqué. Si un problème est détecté, modifiez le fichier source et revenez à l'étape ③ pour un nouveau build. Placez les PNG d'aperçu dans un répertoire temporaire, ne les commitez pas.
⑤ Référencez et écrivez le texte alt : voir la section « Utilisation des artefacts » ci-dessous. Fournissez impérativement un texte alt pertinent (décrivant la conclusion que le diagramme illustre, pas « figure 1 »).
3. Palette de couleurs
Les couleurs doivent uniquement provenir de palette.json. Pendant le dessin, utilisez exclusivement les valeurs claires (valeurs de gauche dans le tableau ci-dessous) ; le build les mappe en var(--wd-*) (les valeurs sombres sont automatiquement commutées par le SVG). Ne choisissez pas manuellement les valeurs sombres, n'utilisez aucune couleur en dehors de la palette (lint génère une erreur, --fix attire vers le jeton le plus proche).
| Teinte | stroke (trait, texte) clair / sombre | fill (remplissage) clair / sombre | Nom sémantique |
|---|---|---|---|
blue | #1d4ed8 / #60a5fa | #dbeafe / #1b2740 | q, active |
amber | #b45309 / #fbbf24 | #fef3c7 / #38290c | k, highlight |
green | #15803d / #4ade80 | #dcfce7 / #122d1c | v, done |
rose | #be123c / #fb7185 | #ffe4e6 / #3a1620 | grad, error |
violet | #7c3aed / #a78bfa | #ede9fe / #272040 | weight |
teal | #0f766e / #2dd4bf | #ccfbf1 / #0f2c29 | activation |
orange | #c2410c / #fb923c | #ffedd5 / #3a2010 | bias |
slate | #475569 / #94a3b8 | #e2e8f0 / #222831 | mask, visited |
Couleurs de base : texte principal fg #1d1d1f (le noir par défaut d'Excalidraw #000000/#1e1e1e est également considéré comme fg), secondaire muted #5c6067, surface surface #f4f4f2, bordure border #e2e2dd, toile blanche #ffffff (le build retire l'arrière-plan).
Couleurs sémantiques (cohérentes dans tous les articles et diagrammes)
| Nom sémantique | Signification | Teinte |
|---|---|---|
q | Query | blue |
k | Key | amber |
v | Value | green |
weight | Poids, paramètres | violet |
activation | Activation, softmax | teal |
grad | Gradient | rose |
bias | Biais | orange |
mask | Masque, entrée | slate |
highlight | Mise en évidence | amber |
visited | Déjà visité | slate |
active | Actif/en cours | blue |
done | Terminé | green |
error | Erreur, perte | rose |
Le champ color du squelette peut directement contenir le nom sémantique ("color": "q") ou le nom de la teinte ; dans draw.io, consultez le tableau pour choisir le fill/stroke correspondant à la teinte.
4. Règles strictes de style
| Élément | Règle |
|---|---|
| Grille | Tous les x/y/largeur/hauteur des éléments doivent être des multiples de 8 px |
| Taille de police | Utilisez uniquement 12 (note) / 14 (étiquette) / 18 (titre) ; tolérance lint ±1 |
| Épaisseur de trait | 1,5 (normal), 2,5 (accentué, une ou deux occurrences par diagramme) ; trait fin 1 réservé aux séparateurs |
| Coins arrondis | Coins des rectangles/conteneurs : Excalidraw round, draw.io rounded=1;arcSize=8 |
| Remplissage | Remplissage uni, utilisez la couleur fill de la teinte ; pas de dégradé |
| Ombres | Interdites |
| Police | Excalidraw utilise Excalifont (chinois : Noto Sans SC, pas Xiaolai); draw.io utilise Inter |
| Dessin à main levée | roughness: 1 ; draw.io n'utilisez pas sketch=1 |
| Arrière-plan | Ne dessinez pas de rectangle d'arrière-plan, gardez la transparence |
| Fichier source | .excalidraw est du JSON ; .drawio est du XML non compressé ; les images intégrées gonflent le fichier (avertissement >2 Mo) |
5. Liste de vérification automatique
- lint
--strictréussi : pas de couleur hors palette, pas d'ombre/dégradé, tailles de police conformes, éléments sur la grille 8 px - Couleurs sémantiques correctes : Q bleu, K ambre, V vert, poids violet, activation cyan, gradient/perte rose, biais orange, masque/entrée gris
- Un seul sujet par diagramme, nœuds ≤ 12 (style manuscrit)
- Les lignes ne traversent pas les nœuds, ne se croisent pas ; pas d'étiquette sur les lignes courtes (espacement < 96 px)
- Étiquettes chinoises : ≤ 8–10 caractères par ligne, pas de troncature
- Un titre (texte avec
size: "title"/ nom de page draw.io) et une note sont présents - Les aperçus PNG clair et sombre ont été visualisés avec l'outil de lecture
- Le fichier
.wisp.svga été généré, et un nouveau build a été effectué après modification du fichier source - Le texte alt est pertinent
6. Utilisation des artefacts
Dans un site Wisp (optionnel)
Les commandes pnpm diagram build|check|lint [--fix], pnpm diagram new <skeleton.json> --build, pnpm diagram export <fichier> --png --theme dark du site sont une mince surcouche de ce skill (elles appellent uv run skills/wisp-diagram/scripts/wisp_diagram.py avec --root <dépôt> --manifest scripts/diagram/manifest.json pour une construction incrémentale).
Placez les fichiers sources avec l'article (dans le répertoire diagrams/), le .wisp.svg doit également être committé. Dans le MDX/Markdown, référencez le fichier source avec la syntaxe d'image standard (le site intégrera le .wisp.svg correspondant et fournira un lien de téléchargement du fichier source) :


Le texte alt est écrit dans le <title> du SVG, et la description entre guillemets devient la légende de la figure ; #page=<nom de page> permet de sélectionner une page du dessin draw.io. pnpm diagram check ne vérifie que le hachage du contenu, pas besoin de navigateur dans la CI (mais uv est nécessaire).
D'autres projets peuvent également utiliser ce « mode projet » : $W build --root . --manifest diagrams.manifest.json ne reconstruit que les fichiers sources modifiés (en scannant <root>/src/content/**/diagrams/), et $W check --root . --manifest diagrams.manifest.json vérifie les hachages dans la CI.
Ailleurs (README GitHub, autres blogs, aperçu IDE)
Référencez directement le fichier *.wisp.svg généré : il contient son propre <style>, et lorsqu'il est utilisé comme <img>, il suit la préférence système (clair/sombre) via prefers-color-scheme ; les rendus ne supportant pas les variables CSS utiliseront les valeurs claires en fallback.

- Avant de publier sur une plateforme externe, utilisez
$W build <fichier> --embed-fontspour incorporer des sous-ensembles de polices (quelques dizaines de Ko par diagramme) et éviter le fallback de police. - Pour les plateformes qui ne supportent pas SVG (WeChat Official Accounts, Zhihu, etc.) :
$W export <fichier> --theme light --scale 2 -o out.png(--transparentpour un arrière-plan transparent ; les polices sont incorporées par défaut). - Conservez les fichiers sources dans le dépôt pour des modifications ultérieures ;
.excalidrawpeut être ouvert sur excalidraw.com,.drawiosur app.diagrams.net.
7. Erreurs courantes
| Erreur | Comment l'éviter |
|---|---|
| Écrire manuellement un élément Excalidraw complet | Écrivez uniquement le squelette, utilisez $W new pour la conversion |
| Utiliser une couleur hors palette dans l'éditeur (pipette, couleur par défaut) | Utilisez la bibliothèque de composants ; lint --fix attire vers la couleur la plus proche ; si l'erreur persiste, modifiez le fichier source |
| Choisir manuellement des valeurs sombres pendant le dessin | Utilisez uniquement les valeurs claires ; les valeurs sombres sont automatiquement gérées par le SVG |
| La flèche du squelette traverse un troisième nœud | Les flèches sont des lignes droites sur la ligne centrale ; ajustez la disposition ou passez aux lignes brisées de draw.io |
| Étiquette sur une ligne courte qui écrase la tête de flèche | N'ajoutez une étiquette que si l'espacement entre les nœuds est ≥ 96 px ; sinon, supprimez l'étiquette |
| Coordonnées non alignées sur la grille 8 px | Toutes les valeurs doivent être des multiples de 8 |
Le fichier .drawio committé est compressé | Utilisez $W normalize pour décompresser ; décochez la case Compressed dans File → Properties |
Le & dans les étiquettes draw.io n'est pas échappé | En mode html=1, écrivez &, pour un saut de ligne, utilisez <br> |
| Étiquette chinoise trop longue et tronquée | Limitez chaque ligne à 8–10 caractères, utilisez \n / <br> pour les retours à la ligne, et élargissez le nœud |
| Modification du fichier source sans rebuild | Relancez $W build après modification (dans le site, pnpm diagram check détectera une incohérence de hachage) |
| Livraison sans avoir vérifié l'aperçu sombre | L'aperçu sombre de l'étape ④ est obligatoire |
| Texte alt vide (« Figure 1 », « diagram ») | Le texte alt doit décrire la conclusion illustrée par le diagramme |
| Utiliser l'outil de diagrammes pour des graphiques de données | Les graphiques en courbes, barres, etc., ne font pas partie de ce skill |
8. Dépannage
uv: command not found: installez uv (curl -LsSf https://astral.sh/uv/install.sh | sh). Python ≥ 3.11 est requis, uv le télécharge automatiquement si nécessaire.Impossible de lancer Chromium:uv run --with playwright==1.64.1 playwright install chromium(la version doit correspondre à celle verrouillée par le script).Échec du téléchargement/N fichiers manquants dans le cache en mode hors ligne: exécutez une fois$W cache warmen ligne ; la localisation du cache est visible avec$W cache status.- Échec de l'export draw.io :
$W probepour voir quelle méthode est disponible ; utilisez--drawio browser|cli|dockerpour forcer celle-ci. - Pour voir les erreurs dans le navigateur : définissez
WISP_DIAGRAM_DEBUG=1. - Lint signale
unrecognised colour: la couleur n'est pas en hexadécimal (par exemple, une valeur spéciale commergb()autre que les couleurs de la palette). Remplacez-la manuellement par la valeur claire correspondante de la palette.