O que teardown faz?
Uma máquina, uma página. O visitante vê a coisa funcionar, pressiona um botão e a parte que está trabalhando se abre enquanto os medidores ao redor mostram os números reais. Quando deixado sozinho, a página faz um tour automático com um cursor. O mesmo código grava um filme do tour, quadro a quadro, com uma trilha construída na mesma linha do tempo.
SKILL_DIR abaixo é a pasta onde este arquivo reside (para uma instalação no Cursor, geralmente ~/.cursor/skills/teardown, ~/.agents/skills/teardown ou .cursor/skills/teardown dentro de um projeto). As compilações e renderizações vão para ./teardown-out da pasta de onde você executa.
Primeira execução
cd "$SKILL_DIR" && npm install && npx playwright install chromium
As páginas não precisam de mais nada. O vídeo precisa do ffmpeg no PATH e a trilha precisa do Python 3 (apenas biblioteca padrão). Defina FFMPEG, PYTHON ou CHROMIUM para apontar para outros binários.
Os 3 exemplos
Construa um, abra o HTML, pressione botões. Copie o mais próximo ao começar uma nova máquina.
| A máquina | O que a impulsiona | Vale a pena roubar | |
|---|---|---|---|
v8-* | Um V8 cross-plane com camisas de vidro: a carga queima dentro do cilindro que você acompanha, válvulas sobem em seus cames, 8 pistões se movem a partir do exato mecanismo biela-manivela. | Ângulo do virabrequim. Ordem de ignição 1-8-4-3-6-5-7-2, um modelo de pressão na câmara para o diagrama indicador. | Modos de corte (vidro, seção, sólido), a ordem de ignição como um seletor de cilindros, gráficos ao vivo sincronizados com o virabrequim. |
cessna-* | O trem de pouso principal do Cessna 337 se recolhendo na fuselagem na decolagem e descendo no pouso. | Curso 0..1: uma cremalheira de 201 mm gira um pinhão de 32 dentes (módulo 4 mm) em exatos 180°. | Um grau de liberdade posando um mecanismo inteiro, fases de voo como funções do tempo, uma pista que rola sob o modelo. |
strandbeest-* | O Strandbeest de Theo Jansen, 20 pernas em um único virabrequim, andando de lado sobre a areia. | Vento. A velocidade do virabrequim é integrada a partir dele; cada articulação segue por interseção de círculos a partir dos 11 comprimentos de elos de Jansen. | Um solucionador de ligações exato em 67 linhas, tubos instanciados, traços dos pés, um gráfico de contato de todos os 20 pés. |
Cada um vem em 3 pastas: <nome>-shared/ contém a máquina, <nome>-film/ o tour gravado, <nome>-live/ a página que você dirige.
node "$SKILL_DIR/sims/build.mjs" v8-live # → teardown-out/dist/v8-live.html, offline, ~800 KB
node "$SKILL_DIR/sims/build.mjs" # todos os 6
Como uma máquina é construída
Uma pasta por máquina, dividida por função. Os exemplos seguem isto exatamente:
| Arquivo | Função |
|---|---|
kin.js / gear.js / jansen.js | A matemática. Dimensões reais em unidades reais, uma entrada (ângulo do virabrequim, curso, vento) e cada pose e leitura em função dela. Sem three.js aqui. |
engine.js / gear.js / beast.js | A geometria, construída a partir de código: peças torneadas, tubos, elos instanciados. update(input) a posiciona. |
stage.js | Estúdio, luzes, sombras, pós-processamento (GTAO, bloom). frame(state, cam) desenha um quadro. |
console.js | A sobreposição: layout CSS fixo de 1600 x 900 com painéis, gráficos, alternadores, chamadas com linhas guia. update(state) redesenha a partir do estado do quadro. |
film.js | Um SCRIPT de movimentos do operador (vistas, isolar, corte, acelerador) e render(t) como uma função pura do tempo. |
live.js | A mesma máquina em tempo real: botões, controles deslizantes, órbita, zoom, teclas. Sem entrada, executa o script de film.js como um tour automático com um cursor; qualquer clique, arrasto, roda ou tecla entrega o controle, 25 s de inatividade o devolvem. |
score.py | O som na linha do tempo do filme. |
Para uma máquina fora de SKILL_DIR, crie uma pasta com um main.js e importe o kit pelo nome: import {runSim} from 'teardown-kit/runtime.js'. Compile com node "$SKILL_DIR/sims/build.mjs" ./my-machine.
Regras que decidem se funciona
- Comece de uma referência, nunca da imaginação. Uma foto, um desenho em corte de um manual, um clipe da coisa real. Construa contra ela e compare quadro a quadro. Máquinas inventadas a partir de uma frase saem genéricas toda vez; o mesmo modelo reconstrói uma real de perto quando tem algo para corresponder.
- Números reais, uma fonte. Obtenha as dimensões reais primeiro (diâmetro do cilindro, curso, número de dentes, comprimentos dos elos). Cada medidor, gráfico e rótulo lê da mesma função que posiciona as peças, então nada na tela pode discordar do movimento. Verifique um manualmente: no Cessna, 32 dentes × módulo 4 mm é um diâmetro primitivo de 128 mm, e metade de sua circunferência é o curso de 201 mm.
- Uma entrada impulsiona tudo. Pose a partir do ângulo do virabrequim, do curso ou do vento. Nada é animado manualmente, então o filme, a página ao vivo e a trilha nunca divergem.
- A parte que está trabalhando se abre. Isole-a, corte-a, faça um raio-X. Uma câmera que entra por dentro vale mais do que dez órbitas.
- Estúdio de luz, um acento. Fundos claros são lidos em um feed; escuros perdem o primeiro segundo. O acento marca a coisa que está mudando. Cuidado com peças quase brancas em um fundo claro: dê a elas um contorno a tinta ou um solo mais escuro.
- Escolha a câmera para o mecanismo. Uma ligação planar vista de frente colapsa em uma treliça; uma vista 3/4 ao longo da espinha mantém cada perna legível.
- Corrija colisões com um número. Quando uma parte atravessa outra, escale ou mova-a no bloco de parâmetros. Nunca a esconda com a câmera.
Regras da página ao vivo
- Teste em uma GPU integrada. Uma página que roda a 60 fps em uma placa de desktop pode cair para 15 fps na placa integrada de um laptop. Os exemplos carregam níveis de qualidade (
TIERSemlive.js): sem AO, menor proporção de pixels, mapas de sombra menores, painéis redesenhados a cada dois quadros. Encontre o shader caro primeiro: um deslocamento computado 5 vezes por vértice custa mais do que todos os níveis juntos. - Aqueça os shaders.
kit/warm.jscompila cada programa em paralelo antes do primeiro quadro, para que a página nunca congele na primeira renderização. - Mantenha a página abaixo de 1 MB. Rastreadores de links (X, Slack) leem o cartão de compartilhamento do HTML e desistem de uma página de 15 MB. Modelos grandes vão como arquivos ao lado da página:
build.json→{"external": {"heavy.glb": "light.glb"}}.
Contrato render(t)
import {runSim} from '../kit/runtime.js';
const DEFAULTS = {duration: 20, fps: 60, hud: {enabled: false}, director: {enabled: false}};
runSim(DEFAULTS, async ({cfg, canvas, capture}) => {
// construir a cena, pré-computar qualquer coisa com estado
return {render(t) { /* desenhar quadro t do zero */ return {}; }, resize() {}};
});
render(t)é puro: semMath.random(userng(seed)dekit/util.jsna configuração), semDate, sem estado carregado entre quadros. A captura o chama em momentos arbitrários.- Qualquer coisa que se mova por suas próprias regras (agentes, partículas) é simulada uma vez no carregamento em arrays tipados;
renderapenas os lê. Uma quantidade integrada ao longo do tempo (o virabrequim do Strandbeest sob um vento variável) é integrada em forma fechada ou tabulada no carregamento. - Cada batida vai para
<nome>-film/timeline.jsonem segundos. A trilha lê o mesmo arquivo. - O quadro 0 é a miniatura. Ela já deve mostrar a máquina.
Comandos
node "$SKILL_DIR/sims/build.mjs" v8-film
node "$SKILL_DIR/sims/capture.mjs" v8-film --size 1600x900 --dpr 1.2 --stills beats --cols 4 --out teardown-out/v8-beats.png
node "$SKILL_DIR/sims/capture.mjs" v8-film --size 1600x900 --dpr 1.2 --still 12.5 --out teardown-out/v8-12.5.png
node "$SKILL_DIR/sims/capture.mjs" v8-film --size 1600x900 --dpr 1.2 --out teardown-out/v8-silent.mp4
python "$SKILL_DIR/run_sfx.py" "$SKILL_DIR/sims/v8-shared/score.py"
ffmpeg -y -i teardown-out/v8-silent.mp4 -i teardown-out/v8-score.wav -map 0:v -map 1:a -c:v copy -c:a aac -b:a 256k -shortest -movflags +faststart teardown-out/v8.mp4
node "$SKILL_DIR/wave.mjs" teardown-out/v8.mp4 --timeline "$SKILL_DIR/sims/v8-film/timeline.json"
--size é o layout CSS e --dpr o multiplica: 1600 x 900 a 1.2 dá 1920 x 1080. A captura imprime a GPU que obteve; um renderizador por software significa que as flags de GPU em paths.mjs não funcionaram.
Loop de revisão
Você não pode assistir ao vídeo; você pode olhar para quadros. Nunca relate uma máquina como concluída sem ler folhas da renderização atual.
--stills beats: um mosaico por batida da linha do tempo, 0,3 s após ela, cada um rotuladot=.- Leia cada mosaico contra a lista de verificação abaixo.
- Amplie:
--stills every:0.2 --from A --to Bpara uma transição,--still Tpara um quadro completo. - Corrija, reconstrua, volte ao passo 1. Pare quando uma passagem completa não encontrar nada.
- Final:
node "$SKILL_DIR/sheet.mjs" --video <final.mp4> --timeline <timeline.json>e leia também: mostra o que o codificador escreveu.
Lista de verificação:
- O mecanismo. Cada parte que deveria tocar toca; nada passa através de nada; os números nos painéis correspondem à pose.
- Composição. Um ponto focal por quadro. Nada importante a menos de 60 px de uma borda. Rótulos nunca cobrem a parte que nomeiam.
- Tipografia. Nada cortado. A leitura principal é legível na largura de um telefone.
- 3D. Bloom come detalhes: mantenha camadas emissivas abaixo de 1.0. Superfícies quase brancas estouram. Metal brilhante sob pouca luz cria estrias: aspereza ≥ 0.45 e envMapIntensity ≈ 0.5 em superfícies grandes.
- Tempo. Cada estado se mantém tempo suficiente para ser lido: 1 s para uma frase curta mais 0,25 s por palavra além de três.
Armadilhas do three.js que os exemplos já encontraram
smoothstep(a, b, x)coma > bretorna 0 no Windows (ANGLE/D3D). Escreva1.0 - smoothstep(b, a, x).- Um
ShadowMaterialou um decalque a uma fração de milímetro acima do chão perde o teste de profundidade dentro de um alvo de renderização de pós-processamento. Dê a elepolygonOffset. - Um quadrado colocado no chão com um mapeamento espelhado é descartado como face traseira. Use
DoubleSide. - Um pixel NaN escurece todo o quadro através do bloom. Aperte cada base de
pow()em um shader. - GTAO em um modelo cortado (cutaway) precisa dos mesmos planos de recorte em
gtao.normalMaterial, ou a metade cortada retorna como um fantasma pálido.
Som
sfx/ sintetiza cada som em Python puro (48 kHz, reproduzível) e lê a linha do tempo do filme, para que o som nunca saia de sincronia. python "$SKILL_DIR/run_sfx.py" --list mostra os geradores. sample() adiciona os sons CC0 gravados em sfx/samples/. sfx/score_kit.py tem as camadas e acentos que as 3 trilhas usam: uma camada de acorde, um baque suave por curso de potência, um motor, ar sob arrasto.
- Cada tempo vem da linha do tempo, nunca de um número digitado.
- A masterização é automática: −14 LUFS, pico verdadeiro ≤ −2 dBFS.
- Acento, nunca narre: movimento contínuo permanece em silêncio. Uma nota para cada som tonal.
Gosto, com números
- Suavização: entradas
cubic-bezier(0.16, 1, 0.3, 1), saídascubic-bezier(0.6, 0, 0.9, 0.35)com metade da duração da entrada, estado a estadocubic-bezier(0.65, 0, 0.35, 1). Linear apenas para movimento contínuo. - A máquina preenche 60-70% de sua viewport. Rótulos nunca abaixo de 34 px em uma tela de 1080.
- Um acento, e ele significa algo: a parte que está trabalhando agora.
- Nada parado: um elemento sempre vivo.
Créditos
Port para Cursor por bugeng777/teardown-cursor de elvarofficial/teardown (MIT). O kit, captura de quadros, motor de som e regras de revisão vêm de whaleyxbt/claude-motion (MIT). As amostras gravadas são CC0 do Freesound, editadas por Barty-Bart/motion-graphics (MIT); fontes em sfx/samples/SOURCES.md.