wisp-diagram: Produzir Diagramas no Estilo Wisp
Objetivo: Produzir diagramas consistentes em estilo, temáticos e portáteis. Arquivos fonte (.excalidraw / .drawio) + SVG gerado *.wisp.svg: o mesmo SVG segue o tema do site quando embutido no Wisp, e segue o modo claro/escuro do sistema quando usado como <img> no README do GitHub / outros blogs.
Este diretório de skill é autocontido e pode ser copiado para qualquer projeto (~/.claude/skills/ ou <projeto>/.claude/skills/). Os scripts são em Python, executados com uv: a entrada scripts/wisp_diagram.py declara dependências no cabeçalho via PEP 723, e uv run cria automaticamente um ambiente isolado – não precisa de npm / pip install.
SKILL.md
palette.json Paleta de cores (única fonte de cores)
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 (entrada unificada) wisp_diagram_lib/ (implementação) tests/ (pytest)
Preparação Única
Os comandos abaixo são executados na raiz do projeto, $W representa o script de entrada da skill (ajuste o caminho conforme a localização real da skill):
W="uv run skills/wisp-diagram/scripts/wisp_diagram.py" # ex.: .claude/skills/wisp-diagram/... ou ~/.claude/skills/wisp-diagram/...
uv run --with playwright==1.64.1 playwright install chromium # Navegador headless para exportação (pule se já instalado)
$W probe # Verificar se Chromium, Excalidraw, draw.io estão disponíveis (cli / docker / browser)
Na primeira execução, faz o download e cache (depois funciona offline):
| Conteúdo | Origem | Tamanho |
|---|---|---|
| Dependências Python playwright 1.64.1, fonttools | PyPI (gerenciado pelo uv, no cache do uv) | ≈ 55 MB |
| Chromium (apenas se não instalado) | playwright install chromium, em ~/.cache/ms-playwright/ | Centenas de MB |
| @excalidraw/excalidraw 0.18.1 e suas dependências (≈110 módulos ES) | jsDelivr, versão fixada | ≈ 1.6 MB |
| svgo 4.1.0 build para navegador (otimização SVG, executado no Chromium) | jsDelivr | 0.8 MB |
| Fontes: Excalifont, Inter 5.3.0, Noto Sans SC 5.3.1 (divididas por unicode-range, baixa apenas as partes usadas) | jsDelivr | Total ≈ 4.5 MB |
| draw.io viewer (apenas no modo de exportação browser) | viewer.diagrams.net | ≈ 4.7 MB |
Exceto pelas dependências Python e Chromium, o cache fica em ~/.cache/wisp-diagram/ (pode ser alterado com WISP_DIAGRAM_CACHE). Use $W cache status para ver, $W cache clear para limpar.
Uso offline: Execute $W cache warm uma vez em ambiente com rede (baixa todos os recursos frontend da tabela acima, ≈ 11 MB). Depois defina WISP_DIAGRAM_OFFLINE=1 para funcionar completamente offline; se faltar arquivos em cache, um erro será emitido pedindo para aquecer, sem acessar a rede silenciosamente. Você também pode usar WISP_EXCALIDRAW_BUNDLE=<JS local> para especificar sua própria build do Excalidraw (IIFE que define window.__wisp, ou módulo ES que exporta funções como exportToSvg), e WISP_DRAWIO_VIEWER=<arquivo local> para o viewer do draw.io.
A exportação do draw.io faz fallback automático na ordem cli → docker → browser. new, build, export precisam de Chromium (exportação Excalidraw, otimização svgo rodam no navegador headless); lint, normalize, check não precisam.
1. Escolha a Ferramenta
| Cenário | Escolha | Arquivo Fonte |
|---|---|---|
| Diagramas estruturados como fluxogramas, sequências, estados, classes, com foco em relações entre nós | Mermaid (mais simples, escreva direto no bloco ```mermaid do texto; o site Wisp renderiza na build) | Nenhum arquivo separado |
| Diagramas conceituais, esboços intuitivos, estilo hand-drawn, fluxo de dados de operadores ML | Excalidraw | nome.excalidraw (JSON) |
| Diagramas de modelo com alinhamento preciso, arquiteturas em camadas, que precisam de linhas com cantos retos e múltiplas páginas | draw.io | nome.drawio (XML não compactado) |
| Demonstrações passo a passo, interativas | Não faz parte desta skill (componente React) | — |
Princípio: se Mermaid explica bem, nem desenhe; estilo hand-drawn com no máximo ≈12 nós; mantenha o estilo consistente no mesmo artigo.
2. Fluxo de Trabalho (5 Passos)
Abaixo, usando diagrams/attention como exemplo; ajuste os caminhos conforme a localização real.
① Determine o tipo (veja tabela acima). Depois leia a referência correspondente: Excalidraw → reference/excalidraw-skeleton.md; draw.io → reference/drawio-cheatsheet.md; padrões de diagramas de modelo comuns copie e modifique de reference/ml-patterns.md. Princípios de layout em reference/style-guide.md.
② Gere o arquivo fonte
- Excalidraw: Escreva o esqueleto JSON (posição, dimensões, label, nome da cor semântica, IDs de início/fim de seta), depois converta. É proibido escrever elementos Excalidraw completos à mão (campos como seed, boundElements, version são muito propensos a erros).
O arquivo esqueleto pode ser deletado após a conversão ou mantido como script gerador; a partir de então, o$W new diagrams/attention.skeleton.json -o diagrams/attention.excalidraw.excalidrawé a referência. - draw.io: Escreva diretamente o XML mxGraph não compactado, usando apenas as strings de estilo predefinidas em
reference/drawio-cheatsheet.md. Se receber um.drawiocompactado, primeiro execute$W normalize diagrams/file.drawiopara descompactar. - Desenhe manualmente no editor: Importe
assets/wisp.excalidrawlib(Excalidraw: Library à direita → Open) ouassets/wisp-drawio-library.xml(draw.io: File → Open Library from → Device) e configure a paleta conformeassets/drawio-colors.txt.
③ Lint (corrija primeiro) depois build
$W lint diagrams/attention.excalidraw --fix # Aproxima cores fora da paleta para o token mais próximo; lista as que não puderem ser corrigidas automaticamente
$W lint diagrams/attention.excalidraw --strict # Só passa se não houver nenhum erro/aviso
$W build diagrams/attention.excalidraw # Gera diagrams/attention.wisp.svg
Parâmetros comuns do build: --embed-fonts (embute subconjuntos de fontes, use ao publicar em plataformas externas), --fix, --title T --desc D (substitui texto de acessibilidade, apenas para arquivo único), --drawio cli|docker|browser, --out-dir DIR, --strict. Para draw.io com várias páginas, a partir da página 2 o output é nome.page-2.wisp.svg.
④ Auto-verificação: exporte previews claro e escuro, visualize com ferramenta 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
Verifique: sobreposição de texto, setas atravessando nós, rótulos cobrindo pontas de seta, ilegibilidade no modo escuro, texto chinês cortado. Se encontrar problemas, corrija o arquivo fonte e volte ao passo ③ para rebuild. As previews PNG ficam em diretório temporário, não as submeta.
⑤ Referencie e escreva o alt: veja a seção "Usando os Artefatos" abaixo. O texto alt deve ser significativo (descreva a conclusão que o diagrama ilustra, não "Figura 1").
3. Paleta de Cores
As cores só podem vir de palette.json. Ao desenhar, use apenas os valores de modo claro (valores à esquerda na tabela abaixo); o build os mapeia para var(--wd-*) (os valores de modo escuro são alternados automaticamente pelo SVG). Não selecione valores de modo escuro manualmente, não use nenhuma cor fora da paleta (lint reporta erro, --fix aproxima para o token mais próximo).
| Matiz | stroke (linha, texto) claro / escuro | fill (preenchimento) claro / escuro | Nome 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 |
Cores base: texto fg #1d1d1f (o preto padrão do Excalidraw #000000/#1e1e1e também é tratado como fg), secundário muted #5c6067, superfície surface #f4f4f2, borda border #e2e2dd, fundo da tela branco #ffffff (o build remove o fundo).
Cores Semânticas (consistentes em todos os artigos e diagramas)
| Nome Semântico | Significado | Matiz |
|---|---|---|
q | Consulta Query | blue |
k | Chave Key | amber |
v | Valor Value | green |
weight | Peso, parâmetro | violet |
activation | Ativação, softmax | teal |
grad | Gradiente | rose |
bias | Viés | orange |
mask | Máscara, entrada | slate |
highlight | Destaque | amber |
visited | Visitado | slate |
active | Atual/em andamento | blue |
done | Concluído | green |
error | Erro, perda | rose |
No esqueleto, o campo color pode receber diretamente o nome semântico ("color": "q") ou o nome do matiz; no draw.io, consulte a tabela para usar o fill/stroke correspondente ao matiz.
4. Regras Rígidas de Estilo
| Item | Regra |
|---|---|
| Grade | Todos os elementos x/y/largura/altura devem ser múltiplos de 8px |
| Tamanho da Fonte | Use apenas 12 (notas) / 14 (rótulos) / 18 (títulos); tolerância do lint ±1 |
| Espessura da Linha | 1.5 (normal), 2.5 (ênfase, uma ou duas por diagrama); linha fina 1 apenas para separadores |
| Cantos Arredondados | Retângulos/containers: Excalidraw round, draw.io rounded=1;arcSize=8 |
| Preenchimento | Preenchimento sólido, use o fill do matiz; proibido gradiente |
| Sombra | Proibida |
| Fonte | Excalidraw use Excalifont (chinês fallback Noto Sans SC, não use Xiaolai); draw.io use Inter |
| Hand-drawn | roughness: 1; draw.io não use sketch=1 |
| Fundo | Não desenhe retângulo de fundo, mantenha transparente |
| Arquivo Fonte | .excalidraw é JSON; .drawio é XML não compactado; imagens embutidas incham o arquivo (aviso >2MB) |
5. Lista de Auto-Verificação
- lint
--strictpassou: sem cores fora da paleta, sem sombra/gradiente, tamanhos de fonte dentro das regras, elementos na grade de 8px - Cores semânticas usadas corretamente: Q azul, K âmbar, V verde, peso violeta, ativação ciano, gradiente/perda rosa, viés laranja, máscara/entrada cinza
- Um diagrama conta uma coisa só, nós ≤ 12 (hand-drawn)
- Linhas não atravessam nós, não se cruzam; linhas curtas (distância < 96px) não têm rótulo
- Rótulos em chinês com ≤ 8–10 caracteres por linha, sem corte
- Tem título (texto com
size: "title"/ nome da página no draw.io) e uma nota - Previews PNG claro e escuro visualizados com Read
-
.wisp.svggerado, e rebuild após modificar o arquivo fonte - Texto alt significativo
6. Usando os Artefatos
Em um site Wisp (opcional)
Os comandos do site pnpm diagram build|check|lint [--fix], pnpm diagram new <skeleton.json> --build, pnpm diagram export <arquivo> --png --theme dark são wrappers finos desta skill (chamam uv run skills/wisp-diagram/scripts/wisp_diagram.py com --root <repositório> --manifest scripts/diagram/manifest.json para build incremental).
Arquivos fonte ficam junto com o artigo (diretório diagrams/), .wisp.svg também deve ser versionado. Em MDX/Markdown, use a sintaxe padrão de imagem referenciando o arquivo fonte (o site embelezará o .wisp.svg correspondente e fornecerá link de download do fonte):


O alt é escrito no <title> do SVG, e a explicação entre aspas vira legenda da figura; #page=<nome da página> seleciona a página no draw.io. pnpm diagram check verifica apenas o hash do conteúdo, não precisa de navegador no CI (mas precisa de uv).
Outros projetos também podem usar o mesmo "modo projeto": $W build --root . --manifest diagrams.manifest.json reconstrói apenas os arquivos fonte que mudaram (varre <root>/src/content/**/diagrams/), $W check --root . --manifest diagrams.manifest.json verifica hashes no CI.
Em outros lugares (GitHub README, outros blogs, preview do IDE)
Referencie diretamente o *.wisp.svg gerado: ele já vem com <style>, e quando usado como <img>, segue o modo claro/escuro do sistema via prefers-color-scheme. Em renderizadores que não suportam variáveis CSS, as cores claras em atributo servem como fallback.

- Antes de publicar em plataformas externas, use
$W build <arquivo> --embed-fontspara embutir subconjuntos de fontes (geralmente dezenas de KB por figura), evitando fallback de fonte. - Para plataformas que não suportam SVG (WeChat, Zhihu, etc.):
$W export <arquivo> --theme light --scale 2 -o out.png(--transparentpara fundo transparente; fontes embutidas por padrão). - Mantenha os arquivos fonte no repositório para edições futuras;
.excalidrawpode ser aberto em excalidraw.com,.drawioem app.diagrams.net.
7. Erros Comuns
| Erro | Como Evitar |
|---|---|
| Escrever elementos Excalidraw completos à mão | Escreva apenas o esqueleto, use $W new para converter |
| Usar cores fora da paleta no editor (conta-gotas, cores padrão) | Use a biblioteca de assets; lint --fix aproxima; se ainda der erro, corrija o fonte |
| Selecionar valores de modo escuro manualmente ao desenhar | Use apenas valores claros; o modo escuro é alternado automaticamente pelo SVG |
| Seta do esqueleto atravessa um terceiro nó | Setas são linhas retas no centro da conexão; ajuste o layout ou use linhas poligonais do draw.io |
| Rótulo em linha curta, rótulo cobre a ponta da seta | Distância entre nós ≥ 96px antes de adicionar rótulo; caso contrário, remova o rótulo |
| Coordenadas fora da grade de 8px | Todos os valores devem ser múltiplos de 8 |
| .drawio versionado em formato compactado | $W normalize descompacta; File → Properties desmarque Compressed |
& não escapado em rótulos do draw.io | Com html=1, escreva &amp;, quebra de linha <br> |
| Rótulo chinês muito longo, cortado | Máximo de 8–10 caracteres por linha, use \n / <br> para quebrar, aumente a largura do nó |
| Modificou o fonte e esqueceu de rebuild | Após modificar, execute $W build (no site, pnpm diagram check detectará hash inconsistente) |
| Entregou sem ver o preview escuro | O preview escuro do passo ④ é obrigatório |
| Alt vazio ("Figura 1", "diagram") | O alt deve descrever a conclusão que o diagrama ilustra |
| Usar ferramenta de diagramas para gráficos de dados | Gráficos de linha/barra não fazem parte desta skill |
8. Solução de Problemas
uv: command not found: Instale uv (curl -LsSf https://astral.sh/uv/install.sh | sh). Precisa de Python ≥ 3.11, o uv baixa automaticamente se necessário.Não foi possível iniciar o Chromium:uv run --with playwright==1.64.1 playwright install chromium(a versão deve corresponder à versão fixada do playwright no script).Download falhou/Modo offline: faltam N arquivos no cache: Execute$W cache warmuma vez em ambiente com rede; a localização do cache aparece em$W cache status.- Exportação do draw.io falhou:
$W probepara ver qual modo está disponível; use--drawio browser|cli|dockerpara forçar um modo específico. - Quer ver erros no navegador: Defina
WISP_DIAGRAM_DEBUG=1. - Lint reporta
unrecognised colour: Cor não é hexadecimal (ex.: valores especiais diferentes dergb()); troque manualmente por um valor claro da paleta.