Communitygithub.com

framewright

Crie vídeos curtos inteiramente a partir de código: um único arquivo HTML, cada quadro uma função pura de (frame, semente, largura). Funciona com Claude, Codex, Gemini e Cursor.

O que é framewright?

Framewright é uma habilidade para agentes de IA que transforma a criação de vídeos curtos em um processo determinístico e totalmente programático, semelhante à produção de uma gravura. O desenvolvedor escreve um único arquivo HTML contendo uma lista de 'placas' (cenas), onde cada quadro é uma função pura dos parâmetros (número do frame, semente, largura), garantindo reprodutibilidade. O agente renderiza os frames em um navegador headless (Chrome via Puppeteer) e os monta com ffmpeg, enquanto o som é sintetizado separadamente. A habilidade suporta múltiplas plataformas de agente (Claude Code, Codex, Gemini, Cursor) e impõe restrições rigorosas: sem arquivos de mídia externos, sem aleatoriedade, sem dependências de CDN. O fluxo de trabalho é altamente iterativo: cada cena é desenvolvida e verificada individualmente por meio da inspeção visual de frames renderizados, e a renderização completa só ocorre após a aprovação de uma folha de contato. A habilidade também gerencia a incorporação de ativos como fotos (convertidas em polígonos posterizados) e a sincronização de áudio gerado proceduralmente.

Funciona com✓Claude Code✓Codex CLI✓Cursor✓Gemini CLI
npx skills add smwbev/framewright

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

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

  1. 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, sem requestAnimationFrame como fonte de tempo. scripts/check.mjs prova isso antes de cada renderização completa.
  2. 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.
  3. Você verifica olhando para os quadros renderizados, nunca lendo o código e imaginando. Qualquer correção é confirmada com um quadro.
  4. Uma cena de cada vez. Escreva uma placa, filme três quadros, olhe, corrija, depois a próxima placa.
  5. As durações das cenas são múltiplos da batida do primeiro rascunho. O som vem por último.
  6. Renderização completa apenas depois que uma folha de contato de todo o vídeo parecer correta.
  7. Nunca commitar frames/, shots/, *.mp4, *.wav ou as fotos do usuário.
  8. 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

PassoO que acontecePonto de verificação com o usuário
0verificação do ambienteapenas se algo precisar ser instalado
1briefingquestionário, um bloco
2conceitostrês opções, escolha uma
3storyboard + esqueletoum "vai"
4cenas, uma por umafolha de contato a cada 2–3 cenas
5ativos (fotos, logotipos)pré-visualização do retrato traçado
6folha completa, renderizar, construirpré-visualização MP4
7somMP4 reconstruído
8entrega e variaçõesfinal

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:

  1. Mensagem: o que o espectador deve entender ou sentir, em uma frase. Nomes, datas, links, frases exatas que devem aparecer na tela.
  2. Onde será exibido e o formato: 16:9, 9:16, 1:1, 4:5.
  3. Duração: 10–15, 20–25, 30–40, 45–60 segundos.
  4. Tom: divertido, impassível, caloroso, épico, técnico, sombrio.
  5. Estilo: deixe você propor (padrão) ou uma família de references/styles.md.
  6. 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.
  7. Som: sintetizado, nenhum, ou espaço para a trilha do usuário (então pergunte o BPM dela).
  8. 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.i o quadro local, S.f o quadro global, S.g o contexto 2D em coordenadas lógicas (lado curto 1080). R é um gerador estável para toda a placa; S.b re-semeia a cada três quadros e dá uma linha viva; S.nz muda 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 para CUES e é lido com cue('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, camKey move uma câmera, title adiciona texto. Leia references/world.md antes do primeiro construtor.
  • Um filme de pintura (--painting) desenha uma pintura estática em três mídias. Suas placas todas chamam drawPainting(S); a vista vive no objeto SCENE e suas camadas entre /* ===== cena ===== */ e /* ===== fim da cena ===== */, e o kit de pintura acima dela permanece como está. Leia references/painting.md antes 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.md na raiz do projeto, não em .agents/. SKILL_DIR/scripts/ é copiado para scripts/.
  • O package.json do esqueleto tem puppeteer como 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)). CX e CY são as coordenadas do centro lógico do quadro.
  • R é um Math.random com 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.

Habilidades Relacionadas