wisp-diagram: Produce diagramas en estilo Wisp
Objetivo: generar diagramas consistentes en estilo, tematizables y portátiles. Archivos fuente (.excalidraw / .drawio) + SVG generado *.wisp.svg: el mismo SVG se integra con el tema del sitio Wisp cuando se incrusta, y cuando se usa como <img> en GitHub README / otros blogs, sigue el modo claro/oscuro del sistema.
Este directorio del skill es autocontenido y se puede copiar completo a cualquier proyecto (~/.claude/skills/ o <proyecto>/.claude/skills/). Los scripts están en Python y se ejecutan con uv: el punto de entrada scripts/wisp_diagram.py declara las dependencias en su cabecera con PEP 723 (playwright, fonttools), y uv run crea automáticamente un entorno aislado, sin necesidad de npm / pip install.
SKILL.md
palette.json Paleta de colores (única fuente de color)
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 (punto de entrada unificado) wisp_diagram_lib/ (implementación) tests/ (pytest)
Preparación única
Los comandos siguientes se ejecutan en la raíz del proyecto. $W representa el script de entrada del skill (ajusta la ruta según la ubicación real del skill):
W="uv run skills/wisp-diagram/scripts/wisp_diagram.py" # Ej.: .claude/skills/wisp-diagram/... o ~/.claude/skills/wisp-diagram/...
uv run --with playwright==1.64.1 playwright install chromium # Navegador sin cabeza para exportación (omitir si ya está instalado)
$W probe # Verificar si Chromium, Excalidraw y draw.io están disponibles (cli / docker / browser)
La primera ejecución descarga y almacena en caché (después funciona sin conexión):
| Contenido | Origen | Tamaño |
|---|---|---|
| Dependencias Python: playwright 1.64.1, fonttools | PyPI (gestionado por uv, almacenado en su propia caché) | ≈ 55 MB |
| Chromium (solo si no está instalado) | playwright install chromium, guardado en ~/.cache/ms-playwright/ | Cientos de MB |
| @excalidraw/excalidraw 0.18.1 y sus dependencias (≈110 módulos ES) | jsDelivr, versión bloqueada | ≈ 1.6 MB |
| svgo 4.1.0 build para navegador (optimización SVG, se ejecuta en Chromium) | jsDelivr | 0.8 MB |
| Fuentes: Excalifont, Inter 5.3.0, Noto Sans SC 5.3.1 (divididas por unicode-range, se descargan según se necesiten) | jsDelivr | Total ≈ 4.5 MB |
| Visor de draw.io (solo en modo de exportación por navegador) | viewer.diagrams.net | ≈ 4.7 MB |
Excepto las dependencias Python y Chromium, la caché está en ~/.cache/wisp-diagram/ (se puede cambiar con WISP_DIAGRAM_CACHE). $W cache status para ver el estado, $W cache clear para vaciarla.
Uso sin conexión: ejecuta primero $W cache warm en un entorno con conexión (descarga todos los recursos frontend de la tabla anterior, ≈ 11 MB), luego establece WISP_DIAGRAM_OFFLINE=1 para trabajar completamente sin conexión; si faltan archivos en caché, mostrará un error y sugerirá calentar la caché, sin conectarse silenciosamente. También puedes usar WISP_EXCALIDRAW_BUNDLE=<JS local> para especificar tu propia compilación de Excalidraw (un IIFE que define window.__wisp, o un módulo ES que exporte funciones como exportToSvg), y WISP_DRAWIO_VIEWER=<archivo local> para el visor de draw.io.
La exportación de draw.io retrocede automáticamente en el orden cli → docker → browser. Los comandos new, build y export necesitan Chromium (la exportación de Excalidraw y la optimización svgo se ejecutan en el navegador sin cabeza); lint, normalize y check no lo necesitan.
1. Elige la herramienta primero
| Escenario | Elección | Archivo fuente |
|---|---|---|
| Diagramas estructurados: flujo, secuencia, estados, clases, etc. (principalmente relaciones entre nodos) | Mermaid (lo más sencillo, se escribe directamente en bloques ```mermaid dentro del texto; el sitio Wisp lo renderiza durante la compilación) | Sin archivo independiente |
| Diagramas conceptuales, bocetos intuitivos, estilo dibujado a mano, flujos de datos de operadores de ML | Excalidraw | nombre.excalidraw (JSON) |
| Diagramas de estructura de modelos con alineación precisa, arquitecturas en capas, líneas ortogonales y múltiples páginas | draw.io | nombre.drawio (XML sin comprimir) |
| Demostraciones paso a paso, interactivas | No pertenece a este skill (componente React) | — |
Principio: si Mermaid puede explicarlo claramente, no dibujes un gráfico; los bocetos a mano no deben tener más de ≈12 nodos; mantén un estilo uniforme en todo el artículo.
2. Flujo de trabajo (5 pasos)
A continuación, usamos diagrams/attention como ejemplo; ajusta las rutas según la ubicación real.
① Determina el tipo (ver tabla anterior). Una vez elegido, lee la referencia correspondiente: Excalidraw → reference/excalidraw-skeleton.md; draw.io → reference/drawio-cheatsheet.md; los patrones de diagramas de ML comunes se copian y modifican directamente de reference/ml-patterns.md. Los principios de diseño están en reference/style-guide.md.
② Genera el archivo fuente
- Excalidraw: Escribe un esqueleto JSON (posición, tamaño, etiqueta, nombre de color semántico, ID de inicio/fin de flecha), luego conviértelo. Prohibido escribir elementos completos de Excalidraw a mano (campos como seed, boundElements, version son muy propensos a errores).
El archivo esqueleto se puede eliminar después de la conversión o conservar como script de generación; a partir de entonces, el archivo$W new diagrams/attention.skeleton.json -o diagrams/attention.excalidraw.excalidrawes la referencia. - draw.io: Escribe directamente el XML mxGraph sin comprimir, usando solo las cadenas de estilo predefinidas de
reference/drawio-cheatsheet.md. Si obtienes un.drawiocomprimido, primero descomprímelo con$W normalize diagrams/file.drawio. - Dibuja manualmente en el editor: importa
assets/wisp.excalidrawlib(Excalidraw: Library → Open en la derecha) oassets/wisp-drawio-library.xml(draw.io: File → Open Library from → Device) y configura la paleta segúnassets/drawio-colors.txt.
③ Lint (primero corregir) y luego build
$W lint diagrams/attention.excalidraw --fix # Atrae colores fuera de la paleta al token más cercano; los que no se puedan corregir automáticamente se listan
$W lint diagrams/attention.excalidraw --strict # No debe tener ningún error/advertencia para pasar
$W build diagrams/attention.excalidraw # Genera diagrams/attention.wisp.svg
Parámetros comunes de build: --embed-fonts (incrusta subconjuntos de fuentes, útil para publicar en plataformas externas), --fix, --title T --desc D (sobrescribe el texto de accesibilidad, solo para un solo archivo), --drawio cli|docker|browser, --out-dir DIR, --strict. Para draw.io de varias páginas, a partir de la página 2 se generan como nombre.page-2.wisp.svg.
④ Autocomprobación: exporta vistas previas en claro y oscuro, revísalas con la herramienta Read
$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
Verifica: texto superpuesto, flechas que atraviesan nodos, etiquetas que tapan cabezas de flecha, ilegibilidad en modo oscuro, texto chino truncado. Si encuentras problemas, corrige el archivo fuente y vuelve al paso ③ para reconstruir. Las vistas previas PNG van en un directorio temporal, no las confirmes.
⑤ Cita y escribe el alt: consulta «Uso del producto» más abajo. Debes proporcionar un texto alt significativo (que describa la conclusión que ilustra el diagrama, no «Figura 1»).
3. Paleta de colores
Los colores solo pueden provenir de palette.json. Al dibujar, usa solo los valores claros (valores izquierdos de la tabla siguiente); el build los mapeará a var(--wd-*) (los valores oscuros los cambia el SVG automáticamente). No selecciones valores oscuros manualmente, no uses ningún color fuera de la paleta (lint dará error, --fix lo atraerá al token más cercano).
| Hue | Stroke (línea, texto) claro / oscuro | Fill (relleno) claro / oscuro | Nombre semántico |
|---|---|---|---|
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 |
Colores base: texto fg #1d1d1f (el negro por defecto de Excalidraw #000000/#1e1e1e también se considera fg), secundario muted #5c6067, superficie surface #f4f4f2, borde border #e2e2dd, fondo blanco #ffffff (el build eliminará el fondo).
Colores semánticos (consistentes en todos los artículos y diagramas)
| Nombre semántico | Significado | Hue |
|---|---|---|
q | Query | blue |
k | Key | amber |
v | Value | green |
weight | Pesos, parámetros | violet |
activation | Activación, softmax | teal |
grad | Gradiente | rose |
bias | Sesgo | orange |
mask | Máscara, entrada | slate |
highlight | Resaltado | amber |
visited | Visitado | slate |
active | Actual/en curso | blue |
done | Completado | green |
error | Error, pérdida | rose |
El campo color del esqueleto puede contener directamente el nombre semántico ("color": "q") o el nombre del hue; en draw.io, consulta la tabla para obtener el fill/stroke correspondiente al hue.
4. Reglas estrictas de estilo
| Elemento | Regla |
|---|---|
| Cuadrícula | Todas las coordenadas x/y y dimensiones deben ser múltiplos de 8px |
| Tamaño de fuente | Usa solo 12 (notas) / 14 (etiquetas) / 18 (títulos); tolerancia de lint ±1 |
| Grosor de línea | 1.5 (normal), 2.5 (énfasis, una o dos veces por diagrama); línea fina 1 solo para separadores |
| Esquinas redondeadas | Rectángulos/contenedores: Excalidraw round, draw.io rounded=1;arcSize=8 |
| Relleno | Relleno sólido, usando el fill del hue; prohibidos degradados |
| Sombra | Prohibida |
| Fuente | Excalidraw usa Excalifont (chino: Noto Sans SC, no usar Xiaolai); draw.io usa Inter |
| Dibujo a mano | roughness: 1; draw.io no usar sketch=1 |
| Fondo | No dibujar rectángulo de fondo, mantener transparente |
| Archivo fuente | .excalidraw es JSON; .drawio es XML sin comprimir; las imágenes incrustadas inflan el archivo (advertencia si >2 MB) |
5. Lista de autocomprobación
- Lint
--strictsuperado: sin colores fuera de paleta, sin sombras/degradados, tamaño de fuente conforme, elementos en cuadrícula de 8px - Colores semánticos bien usados: Q azul, K ámbar, V verde, pesos violeta, activación cian, gradiente/pérdida rosa, sesgo naranja, máscara/entrada gris
- Un diagrama trata un solo tema, nodos ≤ 12 (boceto a mano)
- Las líneas no atraviesan nodos ni se cruzan; las líneas cortas (espacio < 96px) no tienen etiquetas
- Etiquetas en chino: cada línea ≤ 8–10 caracteres, sin truncamiento
- Tiene título (texto con
size: "title"/ nombre de página en draw.io) y una nota - Vistas previas en PNG claro y oscuro revisadas con Read
- Se ha generado
.wisp.svgy se ha reconstruido después de modificar el archivo fuente - El texto alt tiene significado
6. Uso del producto
En un sitio Wisp (opcional)
Los comandos del sitio pnpm diagram build|check|lint [--fix], pnpm diagram new <skeleton.json> --build, pnpm diagram export <archivo> --png --theme dark son envoltorios ligeros de este skill (redirigen a uv run skills/wisp-diagram/scripts/wisp_diagram.py con --root <repo> --manifest scripts/diagram/manifest.json para compilación incremental).
Los archivos fuente se colocan junto con el artículo (directorio diagrams/), y .wisp.svg también debe confirmarse. En MDX/Markdown, cita el archivo fuente con la sintaxis estándar de imagen (el sitio incrustará el .wisp.svg correspondiente y adjuntará un enlace de descarga del archivo fuente):


El alt se escribe en el <title> del SVG, y la explicación entre comillas se convierte en la nota de la figura; #page=<nombre_página> selecciona la página en draw.io. pnpm diagram check solo verifica el hash del contenido; en CI no necesita navegador (pero sí uv).
Otros proyectos también pueden usar el mismo «modo proyecto»: $W build --root . --manifest diagrams.manifest.json reconstruye solo los archivos fuente modificados (escanea <root>/src/content/**/diagrams/), $W check --root . --manifest diagrams.manifest.json verifica los hashes en CI.
En otros lugares (GitHub README, otros blogs, vista previa en IDE)
Referencia directa al *.wisp.svg generado: contiene un <style> que, cuando se usa como <img>, sigue el modo del sistema a través de prefers-color-scheme; los renderizadores que no admiten variables CSS usarán el fallback claro en el atributo.

- Antes de publicar en plataformas externas, usa
$W build <archivo> --embed-fontspara incrustar subconjuntos de fuentes (normalmente docenas de KB por imagen) y evitar que se usen fuentes de respaldo. - Para plataformas que no admiten SVG (WeChat, Zhihu, etc.):
$W export <archivo> --theme light --scale 2 -o out.png(--transparentpara fondo transparente; por defecto incrusta fuentes). - Guarda los archivos fuente en el repositorio para modificaciones futuras;
.excalidrawse puede abrir en excalidraw.com,.drawioen app.diagrams.net.
7. Errores comunes
| Error | Cómo evitarlo |
|---|---|
| Escribir elementos completos de Excalidraw a mano | Escribe solo el esqueleto, usa $W new para convertir |
| Usar colores fuera de la paleta en el editor (cuentagotas, colores por defecto) | Usa la biblioteca de recursos; lint --fix atrae; si sigue dando error, corrige el archivo fuente |
| Seleccionar valores oscuros manualmente al dibujar | Usa solo valores claros, el SVG cambia automáticamente a oscuro |
| Flecha del esqueleto atraviesa un tercer nodo | Las flechas son líneas rectas en la línea central; ajusta el diseño o usa líneas poligonales en draw.io |
| Etiqueta en línea corta que tapa la cabeza de la flecha | Solo añade etiqueta si la distancia entre nodos ≥ 96px; si no, quítala |
| Coordenadas no en cuadrícula de 8px | Todos los valores numéricos deben ser múltiplos de 8 |
Confirmar .drawio en formato comprimido | $W normalize descomprime; en File → Properties desmarca Compressed |
No escapar & en etiquetas de draw.io | Con html=1, escribe &amp;; salto de línea: <br> |
| Etiqueta china demasiado larga y truncada | Máximo 8–10 caracteres por línea, usa \n / <br> para saltos, ensancha el nodo |
| Modificar archivo fuente y olvidar reconstruir | Después de modificar, vuelve a ejecutar $W build (en el sitio, pnpm diagram check detectará hash diferente) |
| Entregar sin revisar vista previa oscura | La vista previa oscura del paso ④ es obligatoria |
| Alt vacío («Figura 1», «diagram») | El alt debe describir la conclusión que ilustra el diagrama |
| Usar herramientas de diagramas para gráficos de datos | Los gráficos de líneas/barras/etc. no pertenecen a este skill |
8. Resolución de problemas
uv: command not found: instala uv (curl -LsSf https://astral.sh/uv/install.sh | sh). Necesita Python ≥ 3.11; uv descargará la versión necesaria automáticamente.No se puede iniciar Chromium:uv run --with playwright==1.64.1 playwright install chromium(la versión debe coincidir con la que fija el script).Error de descarga/Modo sin conexión: faltan N archivos en caché: ejecuta$W cache warmuna vez con conexión; la ubicación de la caché se ve con$W cache status.- Error de exportación de draw.io:
$W probemuestra qué método está disponible; usa--drawio browser|cli|dockerpara forzar uno. - Para ver errores en el navegador: establece
WISP_DIAGRAM_DEBUG=1. - Lint reporta
unrecognised colour: el color no es hexadecimal (por ejemplo, valores especiales comorgb()); cámbialo manualmente a un valor claro de la paleta.