O que framewright faz?
Você vai fazer um vídeo curto do jeito que um gravurista faz uma gravura: um arquivo HTML com uma canvas, uma lista de cenas chamadas placas e uma função de quadro que desenha qualquer quadro sob demanda a partir de (número do quadro, semente, largura). Sem filmagens, sem arquivos de imagem, nada vindo de uma CDN. Os quadros são renderizados no Chrome headless e montados pelo ffmpeg. O som é sintetizado por último, de acordo com as durações fixas das cenas.
Fale com o usuário no idioma dele. Mantenha as regras abaixo mesmo quando o usuário estiver com pressa: cada atalho aqui custa mais do que economiza.
SKILL_DIR abaixo significa a pasta que contém este arquivo (no Claude Code é
${CLAUDE_SKILL_DIR}; em outros lugares é .agents/skills/framewright). Após o passo 3 os
scripts também residem na pasta scripts/ do próprio projeto.
Itens inegociáveis
- Um quadro depende apenas do número do quadro, da semente e da largura de saída. Sem
Math.random, sem relógio de parede, sem animação CSS, semrequestAnimationFramecomo fonte de tempo.scripts/check.mjsprova isso antes de cada renderização completa. - Sem arquivos de imagem, vídeo, fonte ou biblioteca, sem base64, sem CDN. Polígonos traçados a partir de uma foto por um script são dados e estão corretos. Fontes do sistema são suficientes.
- Você verifica olhando para os quadros renderizados, nunca lendo o código e imaginando. Qualquer correção é confirmada com um quadro.
- Uma cena de cada vez. Escreva uma placa, filme três quadros, olhe, corrija, depois a próxima placa.
- As durações das cenas são múltiplos da batida do primeiro rascunho. O som vem por último.
- Renderização completa apenas depois que uma folha de contato de todo o vídeo parecer correta.
- Nunca commitar
frames/,shots/,*.mp4,*.wavou as fotos do usuário. - Pergunte antes de instalar pacotes do sistema. Nunca publique a semelhança de uma pessoa real sem o usuário confirmar que tem o direito de usá-la.
Fluxo de trabalho em resumo
| Passo | O que acontece | Ponto de verificação com o usuário |
|---|---|---|
| 0 | verificação do ambiente | apenas se algo precisar ser instalado |
| 1 | briefing | questionário, um bloco |
| 2 | conceitos | três opções, escolha uma |
| 3 | storyboard + esqueleto | um "vai" |
| 4 | cenas, uma por uma | folha de contato a cada 2–3 cenas |
| 5 | ativos (fotos, logotipos) | pré-visualização do retrato traçado |
| 6 | folha completa, renderizar, construir | pré-visualização MP4 |
| 7 | som | MP4 reconstruído |
| 8 | entrega e variações | final |
Tempo real típico: briefing e conceitos 10 minutos, esqueleto 10, cada cena 10–20, renderização 2–4 minutos por minuto de vídeo 1080p, som 15.
Passo 0. Ambiente
bash SKILL_DIR/scripts/doctor.sh # relatório; adicione --json para um resumo legível por máquina
bash SKILL_DIR/scripts/doctor.sh --install # instala o que está faltando, pergunta antes de cada etapa
Requerido: Node 20+, npm, ffmpeg com libx264, Puppeteer com Chrome no projeto.
Opcional: Python 3 com numpy, scipy, Pillow, apenas quando uma foto for traçada. Se o doctor
relatar ferramentas faltando, informe ao usuário o que será instalado e onde, obtenha um sim, então execute
--install (adicione --yes quando o usuário já concordou). Não inicie o passo 3 com um doctor com falha.
Passo 1. O briefing
Execute o questionário de references/questionnaire.md. Use a ferramenta de perguntas estruturadas do harness
quando ela existir (Claude Code: AskUserQuestion, até quatro perguntas por chamada,
duas a quatro opções cada, coloque a opção recomendada primeiro e marque-a). Sem tal
ferramenta, imprima as perguntas como uma lista numerada com opções com letras e um padrão por pergunta, e
aceite respostas curtas como 1b 2a 3c. Sempre pergunte, nesta ordem:
- Mensagem: o que o espectador deve entender ou sentir, em uma frase. Nomes, datas, links, frases exatas que devem aparecer na tela.
- Onde será exibido e o formato: 16:9, 9:16, 1:1, 4:5.
- Duração: 10–15, 20–25, 30–40, 45–60 segundos.
- Tom: divertido, impassível, caloroso, épico, técnico, sombrio.
- Estilo: deixe você propor (padrão) ou uma família de
references/styles.md. - Ativos: fotos, logotipos, capturas de tela. Os arquivos devem ser colocados na pasta do projeto; uma imagem colada no chat não pode ser salva por você. Pergunte sobre os direitos de pessoas reais.
- Som: sintetizado, nenhum, ou espaço para a trilha do usuário (então pergunte o BPM dela).
- Entregáveis e qualidade: rascunho ou final, cortes extras (vertical, GIF, frame de pôster, variações de semente), uma capa como o primeiro quadro do MP4 (os feeds mostram-na como pré-visualização).
Se o usuário disser "você decide", use os padrões, diga quais você usou e continue.
Passo 2. Conceitos
Proponha exatamente três conceitos antes de qualquer código. Construa-os a partir de três ângulos: literal (mostre o
assunto), metáfora (um sistema visual que representa a situação: um cartão de teste de TV para
espera, um projeto para um plano, um terminal para um processo) e paródia de gênero (boletim de notícias,
modo de atração de arcade, cartão de segurança, previsão do tempo, teletexto). Para cada conceito dê: um nome,
uma logline de uma frase, o sistema visual e paleta, três a cinco cenas-chave em ordem, o
final, um esboço de som, por que se encaixa e seu principal risco. Apresente uma tabela compacta, recomende
um e peça ao usuário para escolher. O método e exemplos práticos estão em
references/questionnaire.md. Um conceito cuja logline é uma jornada sem cortes (uma linha que nunca
levanta, um voo de um detalhe para uma paisagem) é construído como um mundo contínuo
(references/world.md); diga isso em sua linha, porque muda como as cenas são construídas e alteradas.
Um conceito que é uma vista desenhada, pintada e trazida à vida (um desenho a lápis que se torna uma
pintura a óleo viva, estilos 13–16) é construído como um filme de pintura (references/painting.md); diga isso
em sua linha também: suas placas são capítulos de tempo sobre uma pintura, e a cena é o trabalho.
Passo 3. Storyboard e esqueleto
Preencha storyboard.md (modelo em assets/storyboard.md): uma linha por placa, durações em
compassos, a grade de batidas (30 fps, 120 BPM: batida 15 quadros, compasso 60), o segundo do evento principal,
o total. O total deve igualar a duração acordada; quando uma cena é adicionada depois, outra
cena cede um compasso. Mostre a tabela e peça um único "vai".
Então crie o esqueleto:
bash SKILL_DIR/scripts/init.sh # index.html, scripts/, audio.mjs, storyboard.md, package.json
bash SKILL_DIR/scripts/init.sh . --world # o mesmo, mas index.html é o esqueleto de um mundo (sem cortes)
bash SKILL_DIR/scripts/init.sh . --painting # o esqueleto de pintura; audio.mjs e nature.mjs criam som de natureza
npm install # puppeteer (Chrome vem do cache ou é baixado uma vez)
node scripts/look.mjs shot 0,30,60 1200 7
Abra os PNGs com sua ferramenta de visualização de imagens e olhe para eles. A placa de demonstração do esqueleto deve
renderizar antes de você tocá-la. Em seguida, substitua a placa de demonstração pela sua primeira cena. Em um filme de pintura,
o quadro 0 é papel em branco: filme 30,82,200 (o desenho, a cor chegando, a pintura viva)
em vez disso, e substitua o bloco de cena da demonstração enquanto o kit de pintura permanece como está.
Passo 4. Cenas
Leia references/guide.md uma vez antes da primeira cena. Os essenciais:
plate('nome', {len: 2*COMPASSO}, (S, R) => { ... }).S.té o progresso 0..1,S.io quadro local,S.fo quadro global,S.go contexto 2D em coordenadas lógicas (lado curto 1080).Ré um gerador estável para toda a placa;S.bre-semeia a cada três quadros e dá uma linha viva;S.nzmuda a cada quadro para ruído. As sementes derivam do nome da placa.- Toda geometria em unidades lógicas, centralizada através de
CX, CY. Mantenha o conteúdo importante dentro dos 92 % centrais do quadro; em 9:16 também fora dos 15 % superiores e dos 20 % inferiores, onde os botões e legendas da plataforma ficam. - Tempo dentro de uma placa em batidas:
Math.floor(S.i/BATIDA),span(S.i, a, b),ease.out(...). Nunca codifique números de quadro globais dentro de uma cena. Algo que continua através de cortes pega o tempo de outra placa pelo nome,at('placa', batidas); um momento que o som deve acertar vai paraCUESe é lido comcue('nome'). - Os helpers ficam acima do bloco de placas, nunca entre placas.
- As transições são desenhadas pelo motor nas bordas das placas (flags
cutIn/cutOut); as cenas não sabem sobre elas. - Um filme mundo (
--world) não tem cortes. As placas são construtores,build(W, {pen, b, R}), que acrescentam a uma linha do tempo:b(x)é a batida x da placa, a caneta continua a linha de onde a placa anterior a deixou,camKeymove uma câmera,titleadiciona texto. Leiareferences/world.mdantes do primeiro construtor. - Um filme de pintura (
--painting) desenha uma pintura estática em três mídias. Suas placas todas chamamdrawPainting(S); a vista vive no objetoSCENEe suas camadas entre/* ===== cena ===== */e/* ===== fim da cena ===== */, e o kit de pintura acima dela permanece como está. Leiareferences/painting.mdantes da primeira camada. Revise o desenho sozinho primeiro, depois a revelação, depois a vida (references/painting.md, seção 13).
Por cena: escreva-a, filme o primeiro quadro, um no meio, um cinco quadros antes do fim, olhe, corrija, olhe novamente. Após cada duas ou três cenas:
node scripts/look.mjs sheet 24 480 7 shots/sheet.png
FROM=240 TO=480 node scripts/look.mjs sheet 12 480 7 shots/sheet-b.png # uma seção, mais densa
Lista de verificação para a folha, cada item com seus olhos: cada cela se lê como um still em 1,5 segundos; nenhum texto está cortado; linhas e painéis vizinhos não se tocam; duas celas adjacentes de uma placa nunca parecem idênticas; os cortes caem onde planejado e não comem o primeiro quadro de uma cena; nada importante está nos 8 % externos; a cor não está turva; linhas finas não desmoronam; o evento principal está no segundo planejado; o último quadro parece um final; nenhum título compartilha a tela no mesmo lugar. Uma cena que falha em "1,5 segundos" é redesenhada, não decorada. Uma cena vazia ganha um objeto maior ou uma câmera mais próxima, nunca mais detalhe; um close-up ocupado tem sua decoração escurecida ao redor do assunto. Em um filme mundo, também filme o último quadro de cada placa ao lado do primeiro quadro da próxima: nada pode pular.
Envie a folha para o usuário nestes pontos com duas frases de status. Não narre código.
Passo 5. Ativos
Fotos se tornam polígonos posterizados, nunca pixels:
bash scripts/portrait.sh photo.jpg --levels 0.14,0.28,0.42,0.56,0.70,0.84 --height 900
node scripts/look.mjs shot <quadro na cena do retrato> 1200 7
Olhe para shots/portrait_preview.png e para o quadro renderizado. Ajuste níveis, desfoque, corte e
limiar de fundo conforme references/photo.md. Enquanto o arquivo ainda não está na pasta, construa
a cena no placeholder sintético que vem no esqueleto e diga isso.
Passo 6. Folha completa, renderizar, construir
node scripts/look.mjs sheet 24 480 7 shots/sheet.png # olhe para ela, corrija, repita
node scripts/check.mjs # determinismo e autocontenção, deve dizer OK
node scripts/render.mjs frames 7 1920 5 # dir, seed, width (omitido: 1920 landscape, 1080 portrait), tabs
bash scripts/build.sh out.mp4 # frames (+ track.wav) -> mp4
A verificação renderiza cinco quadros de cada placa em sete ordens (primeiro quadro de uma nova aba,
para frente, para trás, embaralhado, logo após o quadro anterior, após outra largura, após uma
varredura sobre o filme da mesma forma que uma aba de renderização o percorre) e exige pixels idênticos. Ela também verifica
a fonte em busca de Math.random, Date e performance.now, falha quando a página solicita qualquer
arquivo e imprime a grade de batidas e o tempo de renderização esperado. Corrija cada FAIL antes de renderizar;
make.sh executa a verificação e para em uma falha. Um quadro que muda com a ordem de renderização aponta para
um estado que sobrevive a um quadro: uma canvas agrupada desenhada sem limpar, um global que uma placa muda, uma
chave de cache sem todas as suas entradas.
Verifique a partir do arquivo, não dos quadros: a contagem de quadros do ffprobe iguala o total de
look.mjs info, a duração iguala quadros divididos por 30, e um mosaico feito do MP4 corresponde
à folha:
ffmpeg -i out.mp4 -vf "select='not(mod(n\,50))',scale=480:-1,tile=6x4" -frames:v 1 shots/out_sheet.png
Envie o primeiro MP4 para o usuário assim que ele existir, mesmo com placeholders, e diga o que é um placeholder.
Passo 7. Som
scripts/export-curves.mjs escreve curves.json a partir da página: inícios das placas, as cues, e para
cada quadro em um filme mundo a velocidade e posição na tela da cabeça da linha, em um filme de pintura
as parcelas reveladas, vida, gust e zoom. audio.mjs pega sua linha do tempo dele, então nunca
se desvia da imagem (uma página sem RISO.curves() precisa dos inícios de look.mjs info
copiados para T manualmente). Escreva um bloco de eventos por placa usando o mapa de cues em
references/audio.md; acertos em algo que a imagem marca pegam seu tempo das cues da página,
cue('nome') (CUES, ou W.cues em um filme mundo), não de números de batida copiados de uma placa;
em um filme mundo dê à linha ou ao personagem uma voz que segue as curvas (follow(),
references/audio.md, seção 7). Uma pintura ou uma paisagem ganha ambiência de natureza em vez de
batidas: vento, água, farfalhar e pássaros de nature.mjs, cronometrados às cues e ao gust da página
pelo audio.mjs que --painting copia de assets/audio-nature.mjs (references/audio.md,
seção 8, Ambiência de natureza). Então:
node scripts/export-curves.mjs curves.json
node audio.mjs track.wav
ffmpeg -i track.wav -filter_complex "showwavespic=s=1800x300:split_channels=1" -frames:v 1 shots/wave.png
bash scripts/build.sh out.mp4
Você não pode ouvir, então leia a forma de onda: sem silêncio acidental dentro de cenas ativas, sem cena presa ao teto. Sempre que uma duração de cena mudar, regenere a trilha.
Passo 8. Entrega
Entregue out.mp4 (1920×1080, H.264, AAC, ~0,7 MB por segundo em estilos ruidosos) e diga como
reconstruir: bash scripts/make.sh [photo.jpg] [semente] [largura]. Ofereça, não imponha:
outra semente (uma impressão diferente das mesmas placas), um corte vertical
(AR=9:16 node scripts/render.mjs frames-v 7 1080 5, então verifique uma folha com AR=9:16; os
títulos inferiores ficam a 70 % da altura lá, TITLE_Y, livres dos botões da plataforma; um
pôster (--poster em render.mjs, o quadro do meio na largura total, colorido e legível em miniatura: um
fundo limpo e um contorno amplo; ffmpeg pode extraí-lo, mas o poster explicitamente desenhado é melhor).
Um MP4 com a faixa de som do usuário em vez da sintetizada, os mesmos comandos, largura de semente e
taxa de quadros.
Se o usuário pedir variações, forneça-as em shots/variations/: uma imagem de 1080×1080 com
os nomes dos arquivos como rótulos. Inclua o comando de renderização e o atalho em cada arquivo.
Comandos de resumo
bash scripts/doctor.sh [--install] # ambiente
bash SKILL_DIR/scripts/init.sh [--world|--painting] # esqueleto
node scripts/look.mjs shot <quadros> <largura> <seed> # filmar quadros (shot) ou uma folha (sheet)
node scripts/look.mjs sheet <cols> <largura thumb> <seed> [caminho]
FROM=240 TO=480 node scripts/look.mjs sheet … # uma seção
AR=9:16 node scripts/look.mjs … # formato alternativo
node scripts/check.mjs # verificação de determinismo + autocontenção
node scripts/render.mjs <pasta> <seed> <largura> [<tabs>] # renderizar todos os quadros
AR=9:16 node scripts/render.mjs … # corte vertical (padrão landscape)
node scripts/render.mjs … --poster # extrair poster
bash scripts/build.sh <saída>.mp4 # construir mp4 a partir de quadros + track.wav
bash scripts/make.sh [foto] [seed] [largura] # reconstrução completa (doctor → check → render → build)
node scripts/export-curves.mjs <curves.json> # exportar curvas para áudio
node audio.mjs <track.wav> # sintetizar trilha de áudio
Notas
- O esqueleto coloca
scripts/,audio.mjs,storyboard.mdna raiz do projeto, não em.agents/.SKILL_DIR/scripts/é copiado parascripts/. - O
package.jsondo esqueleto tempuppeteercomo uma dependência de desenvolvimento e um script"postinstall": "npx puppeteer browsers install chrome". S.gé o contexto de desenho 2D (CanvasRenderingContext2D), com uma transformação aplicada para que a geometria da cena esteja em coordenadas lógicas (1080 unidades no lado curto, centrado em (0,0)).CXeCYsão as coordenadas do centro lógico do quadro.Ré umMath.randomcom semente (seedrandom) estável para toda a placa;S.b(seedrandom) é re-semeada a cada três quadros para variação viva;S.nzé um gerador de ruído Perlin/simplex que muda a cada quadro para efeitos atmosféricos.