Folio
Uma placa Folio explica uma ideia da mesma forma que um museu de história natural explica um espécime. Há um objeto sobre um suporte, uma chave numerada ao lado e textos de parede que ensinam como observá-lo. O objeto aqui é um instrumento que você inventa, como um banco, uma balança, um tear ou um alambique, cujas partes funcionais executam a ideia. Os leitores podem interagir com ele, e cada leitura nele é calculada.
Três compromissos
- Mecanismo, não metáfora. O instrumento deve executar a ideia, não apenas ilustrá-la. Antes de desenhar, escreva uma linha: "Quando o leitor faz X, a parte Y se move, e esse movimento representa Z na ideia."
- Uma única fonte de números. Um modelo puro e enxuto calcula tudo: ângulos das agulhas, níveis de fluido, a leitura, a chave, as tabelas. A página exibe apenas o que o modelo retorna, para que nenhum lugar possa discordar de outro.
- Uma leitura guiada. Um bom desenho ainda precisa de um guia. Cada placa vem com uma chave, uma leitura termo a termo, o funcionamento completo e um relato honesto do que foi simplificado.
Primeiros passos
- Três placas de referência acompanham o repositório. Placa I (
examples/attention/, atenção como um banco de ensaio) é o modelo para ideias compostas por etapas discretas e uma fórmula. Placa II (examples/heart/, o coração humano como uma bomba dupla) é o modelo para qualquer coisa que funciona no tempo: uma simulação integrada a cada quadro, fluxo contínuo, fases e gráficos redesenhados após cada ciclo. Placa III (examples/grid/, uma rede elétrica em miniatura) é o modelo para eletricidade, magnetismo e fluxos de energia, e para um banco construído com máquinas independentes em vez de faixas: uma turbina, um gerador com rotor giratório, transformadores, postes e uma cidade. Placa IV (examples/hashmap/, um mapa hash como uma agência de triagem) é o modelo para algoritmos e estruturas de dados, onde a ideia é uma sequência de operações discretas: cada operação (inserir, buscar, redimensionar) se expande em uma lista curta de ações cronometradas (levantar, carregar, mergulhar para comparar, voar cada cartão para um novo lugar), executadas uma após a outra, para que o leitor veja o algoritmo dar cada passo. Abra primeiro a mais próxima. - O início mais rápido é copiar uma placa de referência:
node scripts/new-plate.mjs <nome>criaexamples/<nome>/a partir da Placa I. Em seguida, substitua seu modelo, cena e textos. Construir a partir de uma placa funcional é mais rápido e seguro do que começar do zero. - Os estilos de exposição compartilhados ficam em
kit/folio-page.css; opage.htmlde uma placa coloca/*CSS*/dentro de sua<style>e adiciona apenas suas próprias regras. node scripts/build-site.mjsconstrói cada placa mais a página de capa (site/index.html) emdocs/, um site pronto para GitHub Pages. Para adicionar uma placa, adicione seu nome aPLATESlá e um cartão à capa.- Construa qualquer placa em um único arquivo independente com
node scripts/build.mjs examples/<nome> dist/<nome>.html. - Se apenas este arquivo estiver instalado (sem o repositório), o apêndice no final contém a biblioteca de desenho; salve-a como
folio-kit.js.
Uma placa é composta por cinco arquivos:
| Arquivo | Função |
|---|---|
folio-kit.js | a biblioteca de desenho (compartilhada, nunca editada por placa) |
folio-live.js | as três vistas: palco, camada de luz, órbita, alternador de vista (compartilhado) |
model.js | o modelo puro; coloca um objeto em window |
plate.js | o instrumento: geometria estática, encaixes vivos, entrada |
page.js | chave, controles, textos de parede, diário; escuta a placa |
page.html | o suporte e os estilos, com placeholders /*KIT*/ /*MODEL*/ /*PLATE*/ /*PAGE*/ |
Fase A: o briefing (sem desenho ainda)
A1. Escopo. Informe ao usuário qual destes ele está recebendo e aproximadamente quanto tempo levará, antes de começar:
| Escopo | Conteúdo | Tempo típico |
|---|---|---|
| Esboço | instrumento + chave + leitura, sem textos de parede | menos de uma hora |
| Placa | a página de exposição completa (o padrão para "explique X") | uma hora e meia a três horas |
| Série | várias placas em um único banco compartilhado, escala e paleta | combine a lista primeiro, depois uma placa de cada vez |
A2. O modelo. Escreva model.js antes de qualquer coisa visual. Reúna a fórmula real, unidades e magnitudes. Retorne objetos simples: entradas fornecidas, todas as quantidades que a página mostrará como saída. Execute-o no Node e imprima alguns casos. Procure por casos de contorno agora (um conjunto vazio, uma linha mascarada, um valor no limite). Se algo for inventado, como pesos fictícios ou dados de amostra, anote para o texto de parede "Sobre este espécime".
A2b. Modelos que funcionam no tempo. Quando a ideia é um processo (um batimento cardíaco, uma fila sendo esvaziada, uma curva de aprendizado), escreva-o como estado mais uma função step(s, dt) e um read(s) que retorna tudo que é mostrado. Ajuste parâmetros com valores conhecidos no Node antes de desenhar, como a Placa II faz para um adulto em repouso (cerca de 115/80 mmHg, 70 mL por batimento, 5 L/min). Mantenha a simulação funcionando enquanto o desenho estiver fora da tela e pule apenas a pintura; caso contrário, alterar um controle mais abaixo na página congela os números.
A3. O instrumento e sua tabela de correspondência. Procure um instrumento do mundo dos laboratórios, oficinas, observatórios ou gráficas. Em seguida, escreva a tabela que liga cada termo a uma parte:
| Termo na ideia | Parte do instrumento | O que o leitor pode ver |
|---|---|---|
| consulta | um carrinho em um trilho aéreo | ele estaciona acima da palavra que está perguntando |
| pontuação escalada | um mostrador por palavra | posição da agulha |
| softmax | um reservatório selado | as colunas só podem dividir o que ele contém |
| máscara | torneiras com tampas | palavras posteriores são fechadas |
| soma ponderada | uma bandeja de camada depositada | o comprimento de cada camada é um peso |
Cada linha precisa de uma parte, e cada parte importante precisa de uma linha. Alguns mapeamentos confiáveis: um total fixo torna-se um reservatório, uma bolsa ou um saco de pesos. Comparação torna-se um mostrador, uma balança ou um paquímetro. Seleção torna-se uma válvula, uma chave ou uma alavanca de agulha. Acumulação torna-se camadas, uma pilha ou um contador. Ordenação torna-se um trilho, uma estante ou uma calha.
Fase B: o banco
B1. Inventário. Liste as partes antes de posicioná-las. Mire entre 30 e 60. Agrupe-as por propósito: partes de termos (da tabela, repetidas por item), partes de suporte (plinto, pés, postes, trilhos, anéis, suportes), partes de controle (seletores, botões serrilhados, alavancas) e detalhes de montagem (placa de catálogo, etiquetas gravadas, tiras de escala, parafusos). Exatamente uma quantidade, aquela sobre a qual a ideia trata, recebe a cor vermelha.
B2. Faixas. Use coordenadas mundiais com x ao longo do banco, y em direção ao observador e z para cima. Divida o banco em faixas de profundidade, de trás para frente, e dê a cada faixa um tipo de parte. A Placa I usa: trilho, colunas, torneiras, manifold, mostradores, bandeja. Deixe folga entre as faixas em unidades mundiais, porque uma parte que invade a faixa seguinte será pintada na ordem errada. Dentro de uma faixa, desenhe de longe para perto. Configure a câmera (az perto de -24 para um banco longo, el 30) e ajuste aos cantos com Folio.fit.
B3. Strings estáticas, encaixes vivos. Percorra as faixas uma vez e empurre strings SVG para uma lista ordenada. Onde algo se move, empurre um encaixe nomeado. No momento da montagem, a lista se torna um SVG com um <g> vazio por encaixe. Cada quadro de animação redesenha apenas os encaixes, a partir de valores suavizados que perseguem os alvos do modelo. O desenho para quando todo valor tiver chegado.
B4. Pinos. Coloque de 6 a 10 pinos numerados diretamente nas partes que carregam a ideia, numerados na ordem que um novato deveria observá-los. Os pinos são as únicas marcas colocadas sobre o desenho. Todo outro texto é gravado em uma superfície: nomes nas frentes das bases, números nas escalas, uma placa de catálogo no plinto.
Fase C: o suporte
A página faz parte da explicação. Construa-a a partir destes blocos, de cima para baixo:
- Cabeçalho. A série à esquerda, a marca d'água centralizada, o número da placa à direita.
- Bloco de título. Um título de destaque que nomeia a ideia como o instrumento ("Atenção, como um banco de ensaio."), três frases sobre o que acontece e uma pequena lista de catálogo: Objeto, Ideia, Modelo, Catálogo.
- A placa montada. Um suporte de papel com uma moldura fina embutida. Seus cantos carregam o número da placa, uma legenda curta, a dica de interação e uma leitura ao vivo.
- A chave. Uma entrada por pino, dando o nome da parte e uma linha sobre o que ela calcula, com a matemática em mono. Passar o mouse sobre uma entrada destaca seu pino, e passar o mouse sobre um pino destaca sua entrada.
- No banco. Botões e controles deslizantes comuns que fazem o que os próprios botões do instrumento fariam.
- Texto de parede I: lendo a placa. Uma coluna para cada termo, na ordem em que a fórmula é escrita: um numeral romano, um verbo, o termo, duas frases que se referem aos pinos por número e uma caixa com números atuais.
- Texto de parede II: o diário. O funcionamento completo para o estado atual, uma linha por item. Clicar em uma linha seleciona aquele item.
- Texto de parede III: a visão mais ampla. O que o instrumento mostra uma fatia (a matriz completa, a sequência inteira, cada balde) e as variantes que o seletor escolhe.
- Texto de parede IV: sobre este espécime. Três notas: o que é calculado exatamente, o que foi escolhido manualmente e o que foi omitido. Sempre inclua-o.
- Colofão. Quem fez a placa e quais tipografias ela usa.
Os controles respondem ao ponteiro e ao teclado: clique em uma estação, setas avançam, dígitos escolhem uma variante, colchetes giram um botão, uma letra alterna uma chave. Quando ninguém está interagindo, a placa lentamente se demonstra sozinha. Ela pausa ao passar o mouse ou focar, descansa quando a página é rolada para longe e mostra um quadro fixo sob movimento reduzido. A leitura usa aria-live.
Fase C2: três vistas
Cada placa oferece o mesmo instrumento de três maneiras, escolhidas a partir de um pequeno seletor no canto superior do suporte (SVG · WebGL · 3D). O modelo, a chave e os textos de parede não mudam entre as vistas; apenas a forma como o banco é mostrado.
SVG é o desenho gravado descrito acima. É a vista padrão e a única que deve sempre funcionar.
WebGL projeta luz sobre o desenho sem redesenhar. A luz vive em um canvas sobre o SVG, e sabe o que está visível através de uma máscara renderizada a partir do próprio desenho: light() clona o SVG, recoloriza cada superfície por função (vermelho para o chão, verde para vasos e tubos, azul para vidro, preto para todo o resto), mantém a ordem do pintor e envia o resultado como textura. Qualquer coisa que o desenho esconda, a luz não pode tocar, portanto não é necessária lógica separada de oclusão. Dê a cada superfície sua função com uma classe (floor no plinto, pad em receptores elevados, pipe ou as classes de sangue em vasos) e passe as regras de cor como maskCss.
Dentro do shader, onPlane(vb, z) transforma um pixel de volta em um ponto mundial em um plano horizontal, project() vai no sentido contrário e fall() encontra onde a luz através de uma parte cai no chão (a lâmpada fica atrás do banco, então poças caem na frente das partes, onde o leitor pode vê-las). Use a luz para a quantidade do assunto apenas:
- Placa I: o fluido de cada coluna brilha com seu peso, um feixe de luz ondulado corre de cada coluna através do banco e pulsos correm ao longo do manifold, mais rápido enquanto os pesos estão se deslocando.
- Placa II: pulsos viajam ao longo de cada vaso no fluxo verdadeiro (o mesmo volume acumulado que move as marcas de fluxo SVG), cada câmara projeta luz da cor de seu sangue e os ventrículos brilham enquanto se contraem.
Acumule luz como cor pré-multiplicada (addLight) e escolha cores por tema: realces claros e poças saturadas sobre papel (mesclagem normal), brilhos mais intensos sobre o fundo escuro (mesclagem de tela, definida pelo token --light-blend). Renderize apenas enquanto a vista estiver ligada e a placa estiver na tela, limite a proporção de pixels a 1,5 e desenhe um quadro fixo sob movimento reduzido.
3D gira o banco completamente. Como toda a cena é uma função da câmera, stage.mount(az, el) simplesmente a constrói novamente a partir do novo ângulo: cada face é re-sombreada por seu viés, cada parte redonda re-silhuetada, cada hachura reespaçada e cada etiqueta gravada re-projetada. A ordem do pintor tem que valer de todos os lados, então nunca codifique "de trás para frente":
- Envolva cada faixa de profundidade como
{ y, draw }e passe a lista paraapi.bands(list); ela as ordena de longe para perto para a câmera atual. Por trás, a faixa da frente é desenhada primeiro. - Dentro de uma faixa, ou para um banco de máquinas separadas, dê a cada unidade uma posição mundial e use
api.units(list)com{ at: [x, y, z], draw }. A Placa III é construída inteiramente assim. - Paredes de um vaso aberto (uma bandeja, um tanque) são ordenadas com
api.backIsFareapi.leftIsFar. - Qualquer coisa montada em uma face do plinto (uma placa de catálogo em latão, um came de temporização em um painel frontal) é desenhada apenas quando aquela face olha na direção do leitor: verifique o sinal de
cam.viewprimeiro.faceTextjá se auto-seleciona.
orbit({ wrap: true }) permite que o azimute ultrapasse 360°, stage reajusta a escala em cada ângulo (limitada por orbitScale, para que o banco nunca mude de tamanho), clique duplo retorna à vista padrão e Shift com as setas o gira a partir do teclado. Verifique com uma grade de ângulos a cada 45° em duas elevações. Uma reconstrução completa da Placa II leva cerca de 27 ms, o que é suave o suficiente para arrastar; se uma placa for muito mais pesada, memorize a última saída de cada encaixe e repinte apenas o que mudou, como a Placa III faz.
Sair do 3D retorna a câmera à vista padrão, para que a luz WebGL (que a assume) sempre se alinhe.
Fase C2b: partes internas em movimento
Uma placa nunca deve ser uma imagem parada com números ao lado. Encontre as partes que realmente se moveriam e mova-as a partir do modelo, a uma taxa que o olho possa acompanhar:
- Coisas que giram. Uma roda de fluxo em um visor de nível gira no fluxo verdadeiro (manifold da Placa I), cames de temporização giram uma vez por ciclo e mostram qual fase está ativa (Placa II), e o rotor de um gerador, uma roda d'água e um regulador centrífugo giram com a velocidade da máquina (Placa III). Acumule o ângulo a partir do modelo (
rot += ω·dt) em vez do relógio, para que uma máquina desacelerando desacelere visivelmente. - Coisas que se deslocam. Níveis, pistões, folhetos de válvulas, agulhas, as esferas de um regulador voando para fora conforme a velocidade aumenta, uma lâmina de disjuntor levantando.
- Coisas que interagem. O movimento de uma parte altera o que outra mostra (como um pistão que move um fio que move uma agulha).
- Coisas que pulsam, brilham ou tremem. Luz e vibração como dicas de atividade, não como informação principal.
Para cada parte móvel, decida se ela tem uma posição de repouso e se move apenas quando o leitor a toca, ou se ela sempre dança enquanto a simulação está rodando. Mova a maioria delas o tempo todo; poupe apenas as que distrairiam (como um parafuso que não precisa girar).
Fase D: a página
D1. Layout da página. Use um layout de largura fixa centrado (cerca de 1200px) com tipografia grande e arejada. O suporte da placa é um retângulo de papel com uma moldura fina; tudo dentro da moldura é o desenho. Abaixo, use uma grade de duas colunas para a chave e os controles. Os textos de parede formam uma única coluna larga abaixo.
D2. Responsividade. Em telas estreitas, empilhe as colunas verticalmente. O suporte encolhe proporcionalmente. A tipografia usa clamp() para tamanhos de fonte. Os controles permanecem utilizáveis com toque.
D3. Acessibilidade. Use aria-live para o visor principal. Todos os pinos têm aria-label. A chave é uma <dl> estruturada. O hover destaca tanto a entrada da chave quanto o pino no desenho. A navegação por teclado é completa: Tab entre os controles, Enter e Espaço ativam botões, setas ajustam valores.
D4. Performance. O desenho SVG é estático, exceto pelos encaixes. Os encaixes são leves (< 100 elementos DOM). A animação usa requestAnimationFrame e para quando a página está oculta. O WebGL renderiza em um canvas separado com baixa resolução (máx. 1,5x de proporção de pixels). O 3D reconstrói a cena a cada quadro, mas cada reconstrução é rápida (~30ms). Desenhe um quadro fixo sob prefers-reduced-motion: reduce.
Apêndice: folio-kit.js
(A biblioteca de desenho completa está incluída neste arquivo. Veja o código-fonte para detalhes da API.)