Figuras TikZ interativas
Uma figura interativa é um desenho TikZ que o leitor pode modificar. A ideia é a mesma de uma figura estática em tikz-dl-visualizer (uma ideia, tornada óbvia), mas agora o leitor faz algo e vê a ideia responder: arrasta o ponto inicial e vê o momentum cancelar o zigue-zague, diminui a temperatura e vê o softmax colapsar em argmax.
Cada figura tem duas metades:
| arquivo | contém | compilado por |
|---|---|---|
figure.tex | tudo que nunca muda: eixos, contornos, grades, matrizes de valores fixos, rótulos, a equação e slots para o texto dinâmico | pdflatex, uma vez |
figure.js | tudo que muda: parâmetros, manipuladores, hotspots, um compute(state) puro e draw(d, state, c) | o navegador, a cada mudança |
scripts/build.py compila o .tex duas vezes (uma normal, uma com o texto dinâmico em cores de ID para recortar esses glifos), exporta o quadro de coordenadas TikZ e as caixas dos nós nomeados, executa a especificação sob node, e escreve:
figure.html: uma página autossuficiente (sem rede). Abra-a, coloque-a em iframe ou publique-a.figure.pngmaisfigure.<snapshot>.png: o estado padrão e cada instantâneo, renderizados sem navegador. É assim que você vê seu próprio trabalho.figure.svg: o estado padrão como SVG estático, para artigos e fallbacks.
Inclusos:
assets/dlviz.sty: a paleta e estilos TikZ (mesmo arquivo do tikz-dl-visualizer).assets/dllive.sty: lado TeX, as chavesexportelive=e\dlnum.assets/dllive.js: runtime: mapa de coordenadas, API de desenho, controles deslizantes, manipuladores, hotspots, reprodução.assets/examples/momentum/: parâmetros, um manipulador arrastável, um botão de reprodução, números dinâmicos, um rótulo móvel.assets/examples/attention/: células exportadas, hotspots de hover, um mapa de calor, 29 números dinâmicos, curvas.references/api.md: a API completa (chaves TeX, campos de especificação, chamadas de desenho). Leia antes de escrever sua primeira especificação em uma sessão.references/gotchas.md: problemas que enfrentamos e suas correções. Leia quando algo parecer estranho.
Para a linguagem visual em si (papéis das cores, notação, layout, anotações), siga tikz-dl-visualizer: seus references/visual-language.md e references/archetypes.md aplicam-se sem alterações. Leia-os se não os leu nesta sessão.
Fluxo de trabalho
1. Escreva a frase de interação
Antes de qualquer código, escreva uma frase no formato "o leitor faz X e vê Y, o que mostra Z":
- "Arraste o ponto inicial e mude β: o zigue-zague através do vale cancela enquanto o movimento ao longo dele acumula; β muito alto causa overshoot."
- "Passe o mouse sobre um token: sua linha de A é o conjunto de pesos, e sua linha de saída é a média ponderada das linhas de V. Reduza τ e os pesos colapsam em uma linha."
Se Y fosse igualmente claro em uma figura estática, faça uma estática (tikz-dl-visualizer). Use de um a três controles. Cada controle deve mudar algo que o olho possa seguir; um controle deslizante cujo efeito não é visível é ruído.
2. Separe o estático do dinâmico
Desenhe no papel o que muda. Todo o resto vai no .tex. Separações típicas:
- Estático: eixos, contornos, grades, contornos de células, matrizes fixas, rótulos de token, a equação, rótulos de leitura como
\(\beta = {}\), traços de legenda. - Dinâmico: caminhos, pontos, destaques, preenchimentos de mapa de calor, setas, escurecimento e números (como slots
\dlnum, para que permaneçam glifos TeX reais). - Um rótulo que precisa se mover (por exemplo, um preso a um manipulador) também é um nó
live=, movido comd.label(id, {from, to}).
3. Escreva figure.tex
Comece a partir do exemplo mais próximo. Necessário:
\documentclass[tikz,border=8pt]{standalone}
\usepackage[dark]{dlviz} % [light] para páginas brancas
\usepackage{dllive}
\begin{document}
\begin{tikzpicture}[x=1.15cm, y=1.15cm]
\useasboundingbox (xmin,ymin) rectangle (xmax,ymax); % SEMPRE: o desenho dinâmico deve caber dentro
...desenho estático...
\node[cell=coloraqua, export] (A-1-1) at (..) {}; % export: JS pode endereçar esta caixa
\node[fit=(Q-1-1)(Q-1-3), inner sep=0, export] (Qrow-1) {}; % caixa invisível para um hotspot
\node[anchor=base west, inner sep=0, text=coloraqua] (b) at (..) {\(\beta = {}\)};
\node[live=beta, anchor=base west, inner sep=0, text=coloraqua] at (b.base east) {\\(\dlnum\)};
\end{tikzpicture}
\end{document}
- Defina a escala com
x=/y=(nãoscale=), para que 1 unidade no JS seja 1 unidade no TikZ. - Um nó número dinâmico contém exatamente
\(\dlnum\). Defina sua cor comtext=e seu tamanho comfont=; comandos de cor dentro do nó quebram. - Coloque números em células de tabela com
anchor=mid westno centro da célula, entãod.number(id, v, {at: "cell"})os centraliza. Em um\matrixou qualquer lugar onde o layout importe, use\dlnumin{2em}para que o slot reserve apenas essa largura. - Se a figura só fizer sentido com algo selecionado, abra-a assim:
initial: {hover: "..."}maisstickyHover: true. - Nomeie as coisas para que o JS possa iterar sobre elas (
A-\i-\j,Qrow-\i). - Coloque um comentário
% Caption:no topo, como no tikz-dl-visualizer.
4. Escreva figure.js
DLLive.figure({
title: "...", caption: "...como interagir, uma ou duas frases...",
params: { beta: { label: "β", min: 0, max: 0.99, step: 0.01, value: 0.6 } },
handles: { w0: { value: [-4, 1.5], min: [-5.2, -1.85], max: [5.2, 1.85] } },
hotspots: /^Qrow-\d$/, // nós exportados que definem state.hover
play: { param: "t", ms: 110 }, // opcional: anima um parâmetro (oculto)
compute: (s) => ({ path: run(s.beta, s.w0) }), // matemática pura, memoizada
draw(d, s, c) { // unidades TikZ, cores dlviz
d.path(c.path, { color: "aqua", width: "thick", dots: true });
d.number("beta", s.beta, { digits: 2 });
},
snapshots: [{ name: "overshoot", beta: 0.95 }], // PNGs extras para verificar
tests: [{ name: "matches numpy", state: { beta: 0.4 }, check: (c) => Math.abs(c.path[30][0] - 1.036e-5) < 1e-8 || `got ${c.path[30]}` }],
});
- A matemática vive em
compute, e ela deve estar correta. Escreva uma referência em Python (numpy) primeiro, depois adicione uma entradatestsque compare o JS contra um número que você calculou em Python. Nunca confie em matemática escrita na sua cabeça. drawapenas desenha: nenhuma mudança de estado, nenhuma aleatoriedade (use um RNG com semente emcomputese precisar de ruído), e executa a cada quadro.- Use papéis de cores dlviz (
aqua,red,orange!55!bg...) e larguras TikZ (thin,thick,very thick), para que a sobreposição pareça com o esqueleto. - Adicione um instantâneo para cada estado importante: um extremo de cada controle deslizante, um hover, meio da animação. É aí que sobreposições se escondem.
5. Construa
uv run --with pymupdf python <caminho-do-skill>/scripts/build.py caminho/para/figure.tex
Isso imprime os nomes dos nós exportados e slots dinâmicos, quantos nós os hotspots corresponderam, PASS/FAIL para cada teste, e WARN para desenho fora da página ou texto TeX cortado em sua borda. Erros nomeiam o slot, nó ou parâmetro culpado. Após uma alteração apenas no .js, adicione --no-tex (cerca de 1 segundo).
6. Olhe, critique, itere
Abra cada PNG que escreveu (ferramenta de leitura) e verifique, como para uma figura estática:
- A parte dinâmica se alinha com o esqueleto (caminhos começam no ponto certo, números se sentam em suas células, destaques abraçam suas linhas)?
- Em cada instantâneo, algo se sobrepõe: um caminho através de uma leitura, uma curva sobre números, texto fora de sua célula, algo cortado na borda?
- Os extremos dos controles ainda são legíveis (β = 0.99, τ = 0.2, um manipulador num canto)?
- O olho consegue encontrar a ideia em três segundos no estado padrão? O estado padrão é o que uma miniatura e um leitor que folheia veem.
- As cores mantêm seus papéis tanto no esqueleto quanto na sobreposição.
Corrija e reconstrua. Duas ou três rodadas é normal.
Depois tente a página real se você tiver um navegador (o painel de navegador embutido): ele geralmente recusa file://, então sirva a pasta, por exemplo com uma entrada .claude/launch.json {"name": "fig", "runtimeExecutable": "python3", "runtimeArgs": ["-m", "http.server", "8800", "--directory", "<pasta>"], "port": 8800} e preview_start. Arraste, deslize, passe o mouse e reproduza; no console, DLLive.state() mostra o estado atual. Instantâneos não mostram traços ou cursores de hover.
7. Entregue
Dê ao usuário o PNG (estado padrão), o caminho para figure.html e um breve guia de leitura: o que tentar primeiro e o que observar ("Arraste w₀ na direção íngreme, depois aumente β..."). Se ele quiser um link compartilhável, publique o HTML como um Artefato; ele é autossuficiente, então não são necessários arquivos extras. Mencione o próximo controle ou figura natural em uma linha.
Incorporação
- Várias figuras em uma página, ou uma página com seu próprio tema claro/escuro (tikz-explorer-book faz isso através de seu
tools/fig.sh): construa com--themes dark,light --embed. Isso compila o esqueleto em ambos os temas e escrevefigure.live.html, um fragmento (<div class="dl-live">mais um<script>DLLive.load("name", ...)</script>). A página hospedeira incluiassets/dllive.jsuma vez antes dos fragmentos e as regras CSS marcadas como "live figure" emassets/template.html. Ela mostra o esqueleto para o tema atual com--show-d/--show-l. O runtime segue o tema da página (data-theme="dark|light"no<html>, ou a configuração do sistema) e recoloriza a sobreposição.-light.pngtambém é escrito. - Autônoma ou um Artefato:
figure.htmlcomo está. Com--themes dark,lightele segue o tema do visualizador; caso contrário, mantém o tema do.tex. - Slides: use
figure.png/figure.svgpara o slide estático e link para o HTML. - Artigo: use
figure.svgou o PDF do esqueleto em.dllive/; o estado padrão estático é uma figura completa por si só. Para figuras apenas para impressão, tikz-dl-visualizer é a ferramenta mais adequada.