sizzle-reel-de-video
Gera um sizzle reel ou hype video de alta energia a partir de ativos de marca e mensagens-chave. Pipeline: Composição HTML HyperFrames (linhas do tempo GSAP) → Chromium headless → FFmpeg H.264 MP4. Sem Runway. Sem Pika. Sem APIs de vídeo com IA. Custo de runtime zero além do Node.js + FFmpeg.
Diferenciação do vid-product-launch:
vid-product-launchconta uma história narrativa — uma revelação merecida, cinco seções, arco de tensãovid-sizzle-reelcria energia e empolgação — cortes rápidos, música em primeiro lugar, sem um único momento de história
Regras Críticas (leia antes de cada geração)
-
Escreva as mensagens-chave você mesmo — ou peça para o usuário escrevê-las. Estas são as frases exatas que aparecem na tela. "A IA vai descobrir" produz conteúdo genérico. 3-5 linhas afiadas são todo o conteúdo de um sizzle reel.
-
O nome da marca aparece APENAS na seção Aterrissagem. A Abertura Fria e a Construção criam tensão sem nomear a marca. A seção Aterrissagem é a recompensa.
-
Declare o padrão rítmico em um comentário no topo do script antes de escrever qualquer HTML. Formato:
// RITMO: sequencia-flash | Fria[0-5s]: stat | Construcao[5-40s]: msg(1.5s)|flash|... | Pico[40-55s]: ... | Aterrissagem[55-60s]: logo+CTA. Cada decisão de tempo é verificada em relação a este padrão. -
Construa o layout de estado final em CSS primeiro — ainda sem GSAP. Posicione cada elemento em seu momento mais visível em CSS estático. Em seguida, adicione entradas GSAP com
gsap.from()e saídas comgsap.to(). Nunca posicione no estado inicial animado. -
class="clip"em cada elemento temporizado. Obrigatório pelo HyperFrames. Sem isso, o elemento fica invisível para o player. -
data-start,data-duration,data-track-indexem cada clip. Sem exceções. Clips no mesmo track não podem se sobrepor — use índices de track diferentes. -
Sem
Math.random(). O HyperFrames exige composições determinísticas. Use PRNG com semente (mulberry32) para quaisquer valores pseudo-aleatórios. -
Todas as linhas do tempo GSAP começam
{ paused: true }e são registradas emwindow.__timelines["comp-id"]. O player HyperFrames controla a reprodução — nunca chametl.play(). -
Nunca use
position: absoluteem contêineres.scene-content. Usewidth:100%; height:100%; padding:Npx; display:flex. Reserveposition:absoluteapenas para elementos decorativos. -
Música: elemento
<audio>separado comdata-track-index. O vídeo deve termuted playsinline. Nunca coloque áudio em um elemento<video>. -
Leia
references/cut-patterns.mdEreferences/tone-presets.mdantes de gerar qualquer HTML. -
Nunca despeje HTML no chat. Salve em arquivo. Mostre apenas o resumo.
Passo 1: Coleta de Informações
Obrigatório:
mensagens_chave— 3-5 linhas impactantes para exibir na tela (o usuário deve escrevê-las)
Parâmetros opcionais e valores padrão:
| Parâmetro | Padrão | Descrição |
|---|---|---|
| ativos_marca | nenhum | URL/caminho do logotipo, cores da marca (hex), capturas de tela principais |
| tom | energético | energético / cinematográfico / emocional / profissional |
| musica | nenhum | Caminho do arquivo ou string BPM/gênero (ex.: "128bpm eletronica") |
| duracao | 60 | 30 / 60 / 90 segundos |
| proporcao_tela | 9:16 | 9:16 (1080x1920) / 16:9 (1920x1080) |
| estilo_corte | auto | rápido (1-2s) / cinematográfico (3-5s) — auto deriva do tom |
| cartao_final | auto | Logotipo + slogan + URL CTA para a seção Aterrissagem |
estilo_corte auto-padrão: energético → rápido; profissional → rápido (2s); cinematográfico → cinematográfico; emocional → misto
Se mensagens_chave estiver faltando, pergunte exatamente:
"Para gerar o sizzle reel, preciso das suas mensagens-chave — as frases exatas que aparecerão na tela. Me dê 3-5 linhas impactantes. Estas são a coisa mais importante que você está escrevendo para este vídeo.
Exemplos: 'Usado por mais de 500 equipes de crescimento' / 'De dias para minutos' / 'Funciona com Claude, Codex, Gemini'
Também é útil: tom (energético/cinematográfico/emocional/profissional), duração (30/60/90s), quaisquer cores da marca ou URL do logotipo."
Se as mensagens_chave estiverem presentes → vá para o Passo 2 imediatamente.
Passo 2: Instalar HyperFrames
Instale as skills HyperFrames (apenas na primeira vez — pule se já instalado):
npx skills add heygen-com/hyperframes
Verifique o ambiente:
node --version # deve ser >= 22
ffmpeg -version # deve estar presente
Inicialize o projeto:
npx hyperframes init sizzle-[slug] --example kinetic-type --non-interactive
cd sizzle-[slug]
Slug: kebab-case a partir do nome da marca do cartão_final ou da primeira mensagem_chave, máximo de 25 caracteres.
Passo 3: Arquitetura Interna (nunca mostrada ao usuário)
1. Derive o tempo dos cortes a partir da duracao + estilo_corte:
| Seção | 30s | 60s | 90s |
|---|---|---|---|
| Abertura Fria | 0-5s | 0-5s | 0-8s |
| Construção | 5-25s | 5-40s | 8-65s |
| Pico | 25-28s | 40-55s | 65-80s |
| Aterrissagem | 28-30s | 55-60s | 80-90s |
Converta cada limite para milissegundos. Calcule a duração por cena a partir do estilo_corte:
rápido: 1.2s-1.8s por mensagem (use 1.5s padrão)cinematográfico: 3.5s-5.0s por mensagem (use 4.0s padrão)misto: 2.0s-4.0s variando por energia da seção
2. Mapeie mensagens_chave para as cenas:
- Abertura Fria (1 cena): uma estatística ou pergunta de impacto — NENHUM nome de marca, constrói intriga
- Construção: uma cena por mensagem_chave
- Pico: repita a mensagem mais forte em escala dupla, ou combine 2 mensagens em flash rápido
- Aterrissagem: nome da marca + slogan + URL CTA
3. Detecte sincronização com a batida se a música for fornecida:
npx hyperframes tts --analyze-beats [arquivo-musica]
Se indisponível, calcule a partir do BPM: batida_ms = 60000 / BPM. Alinhe os cortes a cada 2ª batida.
4. Selecione a predefinição de tom — leia references/tone-presets.md para tokens CSS.
5. Declare o padrão rítmico — escreva comentário no topo do script:
// RITMO: sequencia-flash
// Abertura Fria [0-5000ms]: stat
// Construcao [5000-40000ms]: msg-1(1500ms)|flash|msg-2(1500ms)|flash|msg-3(1500ms)|flash|msg-4(1500ms)|flash|constr-acum(10000ms)
// Pico [40000-55000ms]: msg-mais-forte(1200ms)|flash|msg-2nd(1200ms)|flash|SEGURA(5600ms)
// Aterrissagem [55000-60000ms]: logo+slogan+cta
6. Determine as dimensões em pixels:
9:16→ L=1080, A=1920 (padrão — Instagram Reels, TikTok, YouTube Shorts)16:9→ L=1920, A=1080
Passo 4: Composição HTML HyperFrames
Leia references/cut-patterns.md e a skill HyperFrames (/hyperframes) antes de escrever qualquer código.
Estrutura HTML obrigatória:
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
[link CDN de fonte da predefinição de tom]
<style>
:root {
[todos os tokens CSS da predefinição de tom]
}
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
</style>
</head>
<body>
<div
data-composition-id="sizzle-[slug]"
data-width="[L]"
data-height="[A]"
style="position:relative;width:[L]px;height:[A]px;overflow:hidden;background:var(--bg)"
>
[se corte-flash: verdadeiro]
<div id="corte-flash"
style="position:absolute;inset:0;background:var(--corte-flash-bg);opacity:0;pointer-events:none;z-index:200"></div>
[fim se]
[se granulado-filme: verdadeiro]
<canvas id="sobreposicao-granulado"
width="240" height="135"
style="position:absolute;inset:0;width:[L]px;height:[A]px;pointer-events:none;opacity:0.022;mix-blend-mode:overlay;z-index:50"></canvas>
[fim se]
[se vinheta: verdadeiro]
<div id="sobreposicao-vinheta"
style="position:absolute;inset:0;background:radial-gradient(ellipse at center,transparent 35%,rgba(0,0,0,0.65) 100%);pointer-events:none;z-index:51"></div>
[fim se]
<!-- Cenas — uma div por cena -->
<div id="cena-fria"
class="clip"
data-start="0"
data-duration="5"
data-track-index="0"
style="position:absolute;inset:0;opacity:0"
>
<div class="conteudo-cena" style="width:100%;height:100%;padding:120px;display:flex;flex-direction:column;align-items:center;justify-content:center;box-sizing:border-box">
[conteúdo da abertura fria — uma estatística ou frase de impacto, sem nome de marca]
</div>
</div>
[uma div por cena da Construção, data-start incrementa pela duração do corte]
[cena(s) do Pico]
[cena da Aterrissagem — nome da marca + slogan + CTA]
[se música fornecida]
<audio id="musica"
class="clip"
data-start="0"
data-duration="[duracao_total]"
data-track-index="10"
data-volume="0.85"
src="[caminho_musica]"
></audio>
[fim se]
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
<script>
// ── DECLARAÇÃO DE RITMO ──────────────────────────────────────────────────────
// RITMO: [sequencia-flash | segurada-cinematografica | sincronia-batida | mista]
// Abertura Fria [0-Nms]: ...
// Construcao [N-Nms]: ...
// Pico [N-Nms]: ...
// Aterrissagem [N-Nms]: ...
// ── PRNG COM SEMENTE (apenas para granulado — nenhum outro valor aleatório) ───
function mulberry32(semente) {
return function() {
semente |= 0; semente = semente + 0x6D2B79F5 | 0;
let t = Math.imul(semente ^ semente >>> 15, 1 | semente);
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
return ((t ^ t >>> 14) >>> 0) / 4294967296;
};
}
[se granulado-filme: verdadeiro]
// ── GRANULADO DE FILME (apenas cinematográfico/emocional) ─────────────────────
const canvasGranulado = document.getElementById('sobreposicao-granulado');
const ctxGranulado = canvasGranulado ? canvasGranulado.getContext('2d') : null;
// Granulado atualizado pelo ticker GSAP (não por captura por quadro — HyperFrames lida com isso)
[fim se]
// ── LINHA DO TEMPO GSAP ───────────────────────────────────────────────────────
const tl = gsap.timeline({ paused: true });
// ── ABERTURA FRIA ───────────────────────────────────────────────────────────────
[animações de entrada e saída da abertura fria — veja cut-patterns.md para o padrão exato]
// ── SEÇÃO DE CONSTRUÇÃO ─────────────────────────────────────────────────────────
[animações por mensagem — sequencia-flash ou segurada-cinematográfica de cut-patterns.md]
// ── SEÇÃO DE PICO ───────────────────────────────────────────────────────────────
[animações do pico — mesmo padrão da construção, mas com tempo mais apertado]
// ── SEÇÃO DE ATERRISSAGEM ───────────────────────────────────────────────────────
[entradas da aterrissagem — logotipo, slogan, CTA. Sem saída — segura até o fim]
// ── REGISTRO DA LINHA DO TEMPO ──────────────────────────────────────────────────
window.__timelines = window.__timelines || {};
window.__timelines["sizzle-[slug]"] = tl;
</script>
</div>
</body>
</html>
Regras de qualidade de design:
- Estatística da abertura fria: tamanho de fonte ≥160px para 16:9, ≥100px para 9:16
- Mensagens-chave: tamanho de fonte ≥80px — legível rapidamente
- Nome da marca na seção Aterrissagem: ≥120px para 16:9
- Todas as cores das variáveis de token da predefinição — nenhum hex livre, exceto
var(--accent)literal hex dentro do canvasfillStyle conteudo-cenasempre usapadding + flex— nuncaposition:absoluteno contêiner de conteúdoclass="clip"em cada elemento comdata-start
Passo 5: Auto-QA (corrija todas as falhas antes do Passo 6)
Conteúdo:
-
mensagens_chave— cada frase aparece exatamente uma vez, sem duplicatas - Nome da marca aparece APENAS na seção Aterrissagem (não na abertura fria, nem na construção, nem no pico)
- Abertura fria não contém NENHUM nome de marca e NENHUM nome de produto — apenas estatística ou frase de impacto
- Seção Aterrissagem tem: nome da marca + slogan + URL CTA (três elementos no mínimo)
- URL CTA do cartão_final presente no quadro final
Contrato HyperFrames:
-
class="clip"em cada elemento comdata-start -
data-start,data-duration,data-track-indexem cada clip -
data-composition-idna div raiz da composição -
window.__timelines["sizzle-[slug]"] = tlregistrado - Todas as linhas do tempo começam
{ paused: true } - Sem
Math.random()— apenas PRNG com semente - Nenhuma chamada
tl.play()outl.resume()
GSAP / Layout:
-
gsap.from()para todas as entradas (FROM fora da tela TO posição CSS) -
gsap.to()para todas as saídas (FROM posição CSS TO fora da tela) - Sem
position:absoluteem contêineres.scene-content - Padrão rítmico declarado em comentário no topo do script
Tempo dos cortes:
- Tom
rápido: duração média do corte ≤ 2.0s - Tom
cinematográfico: duração média do corte ≥ 3.0s - Flash de corte dispara em cada limite de corte para tom
energético(60ms, opacidade 0→1→0) - Clips no mesmo track NÃO se sobrepõem (verifique todos os agrupamentos de
data-track-index)
Efeitos Sonoros:
-
window.__sfxTimelinepresente e colocado antes do registro da linha do tempo -
word-hitpor mensagem-chave -
whooshna transição Construção → Pico -
cta-chimeno início da Aterrissagem - Nenhum efeito sonoro dispara antes de 500ms
Passo 6: Lint, Renderizar, Saída
npx hyperframes lint
npx hyperframes inspect --json
Corrija todos os erros de lint. Corrija todos os erros de inspeção (estouro de texto, clips escapando de contêineres). Em seguida, renderize:
npx hyperframes render --output sizzle/[slug]/sizzle-reel.mp4
Saída:
## Sizzle Reel: [nome da marca do cartão_final]
Tom: [tom] | Duração: [N]s | Estilo de corte: [estilo_corte] | Proporção: [proporcao]
Ritmo: [padrão declarado]
Seções
Abertura Fria [0-Ns]: [estatística ou frase de impacto]
Construção [N-Ns]: [N mensagens-chave listadas]
Pico [N-Ns]: [mensagem mais forte em escala máxima]
Aterrissagem [N-Ns]: [nome da marca] + "[slogan]" + [URL CTA]
Arquivos
Fonte: sizzle/[slug]/index.html
Saída: sizzle/[slug]/sizzle-reel.mp4
Linha do Tempo de Efeitos Sonoros (embutida em cada composição)
O mesmo sistema de efeitos sonoros sintetizados por FFmpeg do vid-product-launch. Coloque window.__sfxTimeline imediatamente antes do registro da linha do tempo GSAP.
Referência de tipo de efeito sonoro para sizzle reel:
| Tipo | Som | Duração | Posicionamento |
|---|---|---|---|
word-hit | Soco sub (50Hz) + clique transitório (2.2kHz) + ruído burst | 180ms | Um por início de cena de mensagem_chave |
whoosh | Varredura de ruído de duas bandas (corpo 1.1kHz + ar 4-8kHz) | 700ms | No limite Construção → Pico |
cta-chime | Acorde A maior (440+554+659+880Hz) + brilho de sino aecho | 1.2s | Exatamente no início da Aterrissagem |
window.__sfxTimeline = [
// um word-hit por mensagem_chave (calculado a partir dos tempos de início da cena)
{ ms: MSG_1_INICIO_MS, sfx: 'word-hit', vol: 0.50 },
{ ms: MSG_2_INICIO_MS, sfx: 'word-hit', vol: 0.50 },
{ ms: MSG_3_INICIO_MS, sfx: 'word-hit', vol: 0.50 },
// ... repita para cada mensagem
{ ms: PICO_INICIO_MS - 700, sfx: 'whoosh', vol: 0.55 },
{ ms: ATERRISSAGEM_INICIO_MS, sfx: 'cta-chime', vol: 0.65 },
];
Calcule todos os valores de ms a partir das seções declaradas...