O que REEL-FROM-SCRIPT · v7 faz?
Uma skill para criar um reel 9:16 com aspecto art-direction e que não pode sair quebrado — a partir de um script que você não escreveu, uma referência que você precisa engenharia reversa, e um chat novo sem memória do anterior.
v5 forneceu layouts e codificou o design neles. v6 moveu todos os números para PARAMS.json e colocou um
validador antes da renderização. v7 é o que dois reels reais ensinaram ao v6 — o ciclo de seis campos de cor, o pôster
de capa, animação de cartão por cena, intervalos de cena contíguos, transições adaptativas, as armadilhas de áudio e um único
./build.sh + scripts/qc.py que se recusa a entregar um produto ruim.
A promessa: o único arquivo que um humano edita é
PARAMS.json. A única coisa autorizada a dizer não éprepare.py/qc.py. Todo o resto é gerado, e tudo que é gerado é reproduzível a partir de um único comando.
0 · Se você é novo aqui: os primeiros 10 minutos
export PATH=/home/user/node22/bin:$PATH # Node >= 22
cd <projeto> && ./build.sh --from render # ou siga §3 desde o início
Depois leia, nesta ordem: §1 (como o visual é construído) → §3 (o pipeline) → §6 (manual de design) → §9 (catálogo de falhas). Não invente um layout: o esqueleto é o design.
Nunca faça estas quatro coisas: digite uma duração (meça o VO), cole um hexadecimal ou um px em uma composição
(altere PARAMS.json), escreva index.html manualmente (gere-o), ou entregue sem olhar a folha de contato.
1 · Por que o resultado parece projetado (as sete leis)
Estas são as decisões reais por trás de cada bom quadro desta série. Elas são regras, não gosto.
1. Uma grade de ancoragem, fixa no fundo. Kicker → hero → corpo → chip → apresentador. A metade inferior nunca se move: o chip sempre está na mesma coordenada y, o apresentador é sempre cortado pelo quadro no mesmo lugar. Apenas a metade superior se recompoe. É por isso que nove cenas diferentes são lidas como um único filme.
2. O hero é uma palavra, não uma frase. 1–3 palavras, definido em uma fonte display condensada a ~17–25 % da largura do quadro, entrelinha apertada (0.88). A linha completa vai no chip (3–6 palavras, a coisa que um espectador sem áudio lê), o detalhe vai no cartão. Se não dá para dizer em 3 palavras, o beat são dois beats.
3. Cada beat tem um fundo diferente. Seis campos (creme / marrom-escuro / quase-preto / sálvia / marinho / lavanda)
ciclados para que dois vizinhos nunca coincidam. A mudança de cor é a outra metade da transição. prepare.py falha na
construção se duas cenas seguidas compartilharem um campo.
4. Prova, não decoração. Um cartão existe para mostrar a coisa: uma lista de arquivos, um diff, um navegador, um upload, um
medidor. Se um beat não tem artefato, ele é type-led e não tem cartão. Um cartão com duas linhas parece quebrado;
quatro a seis linhas parecem intencionais (ou um mockup ocupando ≥ 55 % do cartão).
5. O primeiro quadro é um pôster. A cena 1 é composta em t=0 (data-cover="1"): kicker, hero, cartão e
personagem já na tela, chip aterrissando em 0.65 s. Um reel que abre em um campo vazio perde a rolagem.
6. Movimento é apenas transformação, e termina cedo. Entradas são de 0.24–0.34 s, power2/3/4.out, e elas
terminam na primeira metade do beat. Nunca anime conteúdo de texto, nunca interpole um número, nunca deixe uma cena de 1.5 s
gastar 0.6 s em uma transição. Uma deriva lenta no hero mantém o último segundo vivo.
7. Som é pontuação, não papel de parede. ≤ 1 cue por segundo: um pop em cada corte, ticks de tecla na UI, um riser nas duas maiores reviravoltas, um chime na revelação, um notify/ping na CTA. Música de fundo a 0.15 abaixo de um VO a −16 LUFS; master a −14 LUFS / ≤ −1 dBTP.
2 · O contrato: o que é fixo, o que é seu
Invariante — validado, não editável por sensações
| Invariante | Imposto por |
|---|---|
| Todo par texto/fundo legível | WCAG ≥ 4.5:1 em 10 pares renderizados + 6 pares de campo |
| Hero é um hero e sempre cabe | ≥ 120 px, tamanho derivado, deve caber em --hero-lines dentro de --hero-band |
| Hero não sobrepõe o kicker, nunca toca o cartão | banda derivada + --gap, falha dura |
| Corpo legível em um telefone | ≥ 24 px e ≥ bodyMin |
| Nada escondido sob a UI da plataforma | fundo do chip ≤ fundo da zona segura, ≥ 55 % utilizável |
| Chip nunca pode colidir com o cartão | cardTop + cardHmax ≤ chipTop |
| Apresentador cortado pelo quadro, nunca sobre o chip | presenterTop + h > 1.0, presenterTop ≥ chipBottom |
| Duas cenas seguidas nunca compartilham um campo | data-field lido de cada composição |
| Quadro 0 é uma capa | data-cover + uma verificação de snapshot |
| Uma pose diferente em cada cena | um arquivo de pose por cena, verificado na revisão |
| Entregável é reproduzível e alto o suficiente | qc.py: resolução, fps, quadros, LUFS, pico verdadeiro, buracos silenciosos |
Variável — genuinamente seu: valores de paleta (6 campos + 4 tons de papel, com contraste permitido) · formato (9:16, 4:5, 1:1, 720p) · margens de zona segura · todas as proporções de grade e tipo dentro do piso · arquétipo por cena · contagem de cenas · palavras · duração · conjunto de poses · folha de cues · fontes no disco.
Se você quiser um layout que o validador não pode verificar, você altera o esqueleto e adiciona a verificação. Esse é o preço da liberdade, e é por isso que o resultado não pode ser ruim.
3 · O pipeline (a ordem não é negociável)
| # | Passo | Comando | Por que aqui |
|---|---|---|---|
| 0 | Engenharia reversa da referência | §4 | você não pode combinar um visual que não mediu |
| 1 | Fatos | — | uma alegação que chega tarde força uma regravação |
| 2 | Script → seções | assets/vo/sections.json | uma ideia por beat, 1.2–9 s |
| 3 | VO primeiro | python3 scripts/process_vo.py | timeline.json é o relógio; a imagem é cortada para ele |
| 4 | Visual | PARAMS.json | paleta, formato, grade, piso de tipo |
| 5 | Portão | python3 scripts/prepare.py | falha em contraste / tipo / colisão / ritmo de campo |
| 6 | Cenas | ./scenes.sh | uma chamada new_scene.py por beat, tokens injetados |
| 7 | Raiz | python3 scripts/build_index.py | intervalos contíguos, transições adaptativas, nenhum index.html digitado manualmente |
| 8 | Lint | npx --yes [email protected] lint | 0 erros é um portão |
| 9 | Olhe para ele | npx … snapshot --at "0,1.5,4,…" | o único passo que pega "correto mas feio" |
| 10 | Renderizar | npx … render --output renders/_raw.mp4 | ~1 m 45 s para 32 s a 1080×1920, GL de software |
| 11 | Mixar | python3 scripts/mix_audio.py | VO + música + cues → renders/master.wav (−14 LUFS) |
| 12 | Multiplexar + entregar | build.sh passo 6–7 | mp4 + .srt + thumbs, então qc.py |
./build.sh executa 3 → 12 de uma só vez. ./build.sh --from render pula o VO quando ele já está medido.
Passo 3 em detalhe — O VO é o relógio
# um clipe por seção, nomeado vo1.mp3 … voN.mp3 em assets/vo/
python3 scripts/process_vo.py
Ele corta silêncio, aplica atempo apenas se script_target estiver definido, normaliza o volume de cada take para
−16 LUFS, então escreve assets/vo/timeline.json: start/dur/end por seção + root_duration. Nada a jusante pode
saber uma duração que não esteja neste arquivo.
Escreva say em Devanagari com palavras técnicas em inglês em latim (resume, job description, ATS score, DM) — uma
voz hi-IN entende a prosódia corretamente e ainda diz as palavras em inglês. caption é o que o .srt mostra.
Passo 7 em detalhe — A raiz é mecânica
build_index.py encontra compositions/s*.html em ordem numérica, lê os intervalos medidos, os torna
contíguos (0 → corte → corte → … → raiz, para que nenhum buraco preto apareça onde o VO tem uma lacuna de 0.30 s), dispara uma
transição 0.36 s antes de cada corte na cor da cena que chega, e mantém a última cena através da cauda do áudio.
Uma transição é encurtada para 34–62 % da duração de uma cena curta — uma cena de 1.4 s não pode segurar uma transição de 0.62 s.
Passo 11 em detalhe — As duas armadilhas de áudio
alimitertemlevel=truepor padrão: ele automaticamente aumenta o nível de volta ao teto, então seu "limitador" se torna um compressor + ganho de compensação e o mix chega a −12.5 LUFS enquanto você mira −14. Semprelevel=false.loudnormem uma passagem linear ultrapassa. Meça comebur128, mova exatamentealvo − medido, então limite. Aritmética que você pode verificar vence um filtro que adivinha.
4 · Fase 0 — engenharia reversa de um vídeo de referência
Quando o briefing é "assista a isso e combine", meça. Dez minutos, cinco comandos:
ffprobe -v error -show_entries format=duration:stream=width,height,r_frame_rate,codec_type -of default=nw=1 ref.mp4
ffmpeg -i ref.mp4 -vf "fps=1,scale=400:-1,tile=6x6" -frames:v 1 sheet.jpg # o filme inteiro como uma imagem
python3 - <<'P' # a paleta de campo, por segundo
from PIL import Image; import glob
for f in sorted(glob.glob("frames/f_*.jpg"))[::2]:
im = Image.open(f).convert("RGB"); w,h = im.size
print(f[-7:-4], im.getpixel((3,3)), im.getpixel((w-4,3)))
P
ffmpeg -i ref.mp4 -vn -ac 1 -ar 16000 -c:a pcm_s16le audio.wav # para o script
Extraia disso: duração e ritmo de corte (quanto tempo dura cada beat), a paleta de campo (amostre cantos, não o meio), comportamento do tipo (maiúsculas condensadas? construções palavra por palavra? caixas de destaque?), layout (onde o personagem se senta, onde o bloco de texto se senta), artefatos de UI (quais mockups), som (densidade de cues). Esses seis números são toda a direção de arte.
Se o briefing lhe deu uma referência mas nenhum script, a referência é o script: transcreva o áudio
(faster-whisper, int8, modelo base → ~7 s para 32 s de Hinglish) e leia o texto na tela dos quadros.
Não reescreva o texto — uma série tem uma voz.
Traduza, não copie. A referência aqui era 1280×720; o entregável era 1080×1920. Mesma paleta, mesmo tipo, mesmos mockups — mas a banda do hero, a âncora do chip e o corte do apresentador foram re-derivados como proporções. Em 9:16 os blocos de 8–10 palavras da referência caem abaixo do piso de corpo de 24 px, então o texto é dividido de forma diferente: hero 1–3 palavras, chip a linha, cartão o detalhe.
5 · Arquivos
PARAMS.json o único arquivo de design
tokens.css recibo gerado (não edite)
index.html gerado por build_index.py (não edite)
SKILL.md · COMPONENTS.md · README.md
build.sh o pipeline inteiro
scenes.sh cada cena, reproduzivelmente
components/ 7 corpos de cartão que você pode passar com --card-body @…
compositions/
_scene-base.html.tmpl O esqueleto — zero hexadecimal literal, zero px literal
wipe.html a única transição
sN-*.html gerado por new_scene.py
_examples/ três cenas trabalhadas (não montadas: build_index só lê compositions/s*.html)
scripts/
process_vo.py VO → timeline.json
prepare.py o portão: piso + injeção de tokens
new_scene.py template base → uma cena correta
build_index.py timeline + cenas → raiz
mix_audio.py VO + música + cues → master.wav
make_deliverables.py .srt + thumbs
qc.py um comando, PASS/FAIL em 10 portões
cutout.py · gen_sfx.py assets
assets/{fonts,presenter,vo,sfx,music}/
6 · Manual de design (o que realmente escolher)
Beat → arquétipo. Prova → card-led. Um número → stat-led (odômetro, --digits). Uma afirmação, uma
transição, um cartão de marca → type-led. O gancho e a CTA são quase sempre card-led porque ambos precisam de um artefato
(a lista de arquivos que prova o problema; o fio de comentários que prova a CTA).
Beat → campo. Alterne quente e frio; nunca repita. Um ciclo prático para seis campos:
accent → ground → ink → secondary → tertiary → quaternary. Campos escuros (ink, tertiary) fazem o apresentador
desaparecer, então o halo vai para 0.20 → 0.42 lá (o esqueleto faz isso a partir de data-field); use-os para a revelação
da ferramenta e o beat "IA faz o trabalho", onde o drama ajuda.
Beat → pose. Mesmo personagem, mesma roupa, uma pose por cena, combinada com a emoção da linha:
ombros (uma pergunta) · facepalm (o problema) · apresentar (a oferta) · queixo (curioso) · memória (lembrança) ·
positivo (a vitória) · apontar (um passo) · ideia (o aha) · CTA (o pedido). Gere uma pose faltando a partir da imagem base
e mate com cutout.py; mantenha a regra do fundo branco e o corte na metade da coxa para que recortem limpo.
Palavras na tela. Hero: o verbo emocional ou o número (SAME RESUME?, CUSTOMIZE KARO, TAILOR,
ATS SCORE). Chip: a frase que um espectador sem áudio precisa (har company mein bhej rahe ho?). Título do cartão: o que
o artefato é (applied / 12 companies). Meta do cartão: um pequeno fato verdadeiro (this week, matched 3 of 7).
Quando um beat é muito curto para projetar (1–2 s). Mantenha a cena, remova a segunda camada: hero + chip + apresentador,
type-led, uma revelação. Não force um cartão e uma lista escalonada em 1.4 s — parece um glitch.
Quando um beat é longo (8–9 s, geralmente a CTA). Estágio três revelações com 1.8–2 s de intervalo (comentário → DM → link) e deixe uma deriva lenta carregar a cauda. Um quadro estático de 8 s é a causa única mais comum de "parece barato".
Transições. Uma transição, 0.34–0.62 s, cor = campo da cena que chega, direção alternada. Nenhum outro tipo de transição: consistência é o que faz oito cortes parecerem autorais.
O último segundo. O quadro final deve ser um quadro projetado com a alça e o site nele — o espectador que pausar ali deve ser capaz de agir.
7 · Manual de áudio
| Momento | Cue | Ganho |
|---|---|---|
| cada corte | pop | 0.50 |
| as duas maiores reviravoltas | riser 0.3 s antes do corte | 0.28–0.30 |
| um elemento de UI aterrissando | click, key | 0.38–0.45 |
| uma lista sendo preenchida | key ×N, 0.12 de intervalo | 0.40 |
| uma revelação / pontuação | chime | 0.36–0.42 |
| CTA | notify, então ping 1.7 s depois | 0.32–0.40 |
| erro / rejeitado | error (com moderação — soa como comédia apenas uma vez) | 0.30 |
Deslocamentos de cue são relativos à seção em assets/sfx/cues.json ("vo7+1.68"), então um VO regravado não
invalida o design. Nunca coloque uma cue na primeira sílaba de uma palavra; um tick pertence 20–60 ms
...
[truncado para tradução]