🔢 AUDIO[] como fonte única do timing
O array AUDIO[] contém as durações REAIS (medidas com ffprobe) de cada narração WAV. Ele é a única variável que você precisa preencher para que todo o timing do vídeo — HTML, GSAP e áudio — fique sincronizado automaticamente.
O array de durações governa tudo. Nenhum número de tempo aparece em outro lugar do código. Altere um WAV, atualize a entrada correspondente em AUDIO[], rode o gerador — o vídeo inteiro recalibra automaticamente.
Isso é possível porque o gerador roda em Node.js e produz um HTML estático com todos os tempos já calculados. O browser recebe números prontos — não precisa calcular nada em runtime.
- ✓
data-startedata-durationde cada.scene.clip - ✓ Tempos absolutos de todos os tweens GSAP via
anim(i, s.start) - ✓
data-startdos elementos<audio>em track 20 - ✓
TOTALda composição e barra de progresso
- ✗ Kokoro gera durações diferentes conforme texto e velocidade (
--speed 0.98) - ✗ Estimativa errada = áudio e visual dessincronizados permanentemente
- ✗ O render headless não avisa — o vídeo simplesmente fica errado
- ✗ Nunca escreva durações de cabeça — use sempre
ffprobe
⏱️ O cálculo de S[] — a série de timing
A série S é gerada por um único AUDIO.map(). Cada objeto carrega todos os tempos necessários para cenas, captions, áudio e tweens — calculados uma vez, propagados em todo lugar.
Três constantes controlam toda a ritmicidade: LEAD=0.5 (visual entra antes da voz), TAIL=0.9 (visual segura após a voz) e FADE=0.45 (duração do fade-in/out do .scene-inner). Um acumulador t cresce a cada cena.
Fórmulas fundamentais: dur = LEAD + a + TAIL · audioStart = t + LEAD · end = t + dur.
Após gerar o HTML, o template exibe no console: OUT gerado · W×H · TOTAL = Xs · N cenas, seguido de uma linha por cena com start, dur, audio@ e audioDur. Verifique esses números antes de renderizar.
🎬 sceneN() e anim(i,t) por cena
Cada cena tem duas funções: sceneN() retorna o HTML interno do .scene-inner, e anim(i,t) gera strings de código GSAP que serão embutidas no <script> do HTML final. O fade do .scene-inner é sempre gerado pela parte comum de anim().
O gerador roda em Node.js mas o GSAP executa no browser (Chrome headless). anim() constrói strings JavaScript com os tempos absolutos já calculados — quando o browser carregar o HTML, essas strings executam com números exatos, sem recálculo. O fade do .scene-inner é comum a todas as cenas; o switch interno adiciona os tweens específicos de cada uma.
O HyperFrames força opacity:1 no clip ativo. Se você tentar animar o .clip ou o .scene, a animação de fade não funciona. O wrapper animável é sempre o filho .scene-inner. O template já gera os fades para ele — não remova essas linhas.
🧱 Montagem do HTML completo
Os quatro streams (scenesHTML, captionsHTML, audioHTML em track 20, animJS) são montados numa template string final com a timeline GSAP pausada registrada em window.__timelines["main"]. O ambiente (glow/grid) e a sentinela tl.set({},{},TOTAL) também fazem parte da montagem.
A montagem final é uma template string gigante que costura os quatro streams. As captions ficam em tracks alternados (2/4), o áudio em track 20 (especial). A timeline GSAP é criada pausada e registrada em window.__timelines["main"] — o HyperFrames player a controla externamente.
A sentinela tl.set({}, {}, TOTAL) estende a timeline até o fim da composição, garantindo que a barra de progresso chegue até o fim mesmo sem tweens após a última cena.
yoyo:true cobrindo todo o TOTAL. data-layout-ignore — não interfere no layout do HyperFrames.backgroundPositionY+=128 ao longo de todo o vídeo. Cria sensação de movimento.SKILL.md decorativo. Ambos com data-layout-ignore.📱 Overrides 9:16 via body.v e flag --vertical
O gerador suporta dois formatos: 16:9 (1920×1080) padrão e 9:16 (1080×1920) para Shorts. A flag --vertical troca W e H, adiciona a classe body.v no HTML gerado e aplica overrides CSS automáticos. O output é sempre index.html.
O mesmo build-index.mjs gera 16:9 e 9:16. A lógica de timing é idêntica — só as dimensões W/H mudam e o CSS do body.v ajusta fontes, padding e layout. Você renderiza duas vezes com a mesma fonte, obtendo dois formatos sincronizados.
Fluxo típico: node build-index.mjs → renderiza 16:9 → node build-index.mjs --vertical → renderiza 9:16. Ambos sobrescrevem index.html — nunca edite o HTML diretamente.
v no body. CSS padrão com fontes grandes para tela de 1080p.class="v" ao body. Overrides CSS ajustam fontes e layout para mobile.🏁 A CTA scene9() / case 9 — assinatura invariável
A cena 9 é a assinatura padrão de todos os vídeos INEMA.CLUB. Ela mostra "CONTINUA EM" + INEMA.CLUB com glow e a URL 🌐 inema.club. Nunca deve ser removida, reposicionada ou alterada — é parte da identidade do canal.
A cena 9 funciona como uma assinatura de marca: quem assiste qualquer vídeo INEMA.CLUB sempre vê o mesmo encerramento. Isso cria reconhecimento e direciona o espectador para o site. O template já inclui a narração de CTA (s9.wav) e o HTML — você só fornece a duração real no AUDIO[].
Regra: AUDIO[8] (índice 8, cena 9) sempre é a duração de assets/audio/s9.wav. Narração padrão: "Isso é conteúdo do INEMA ponto CLUB. Acesse: inema ponto club."
A CTA está na posição 9 de BODIES[] e no índice 8 de AUDIO[]. Remover ou reposicionar quebra o timing de todo o vídeo e elimina a assinatura do canal. Ao adaptar o template para um novo vídeo, mude apenas as cenas 1–8 e atualize as durações em AUDIO[0..7]. AUDIO[8] é sempre o WAV da CTA.
- ✓ Copie o template inteiro como
build-index.mjs - ✓ Preencha
AUDIO[0..7]com ffprobe — mantenhaAUDIO[8] - ✓ Escreva
scene1()–scene8()— mantenhascene9() - ✓ Codifique
case 1–case 8emanim()— mantenhacase 9 - ✓ Rode o gerador e verifique o log de timing antes de renderizar
- ✗ Remover
scene9()deBODIES[] - ✗ Remover
AUDIO[8]ou deixar o array com menos de 9 entradas - ✗ Substituir a cena 9 por conteúdo de outro vídeo
- ✗ Alterar as cores
.cta-inema/.cta-club
📋 Resumo do Módulo 3.3
- ✓
AUDIO[]governa 100% do timing — HTML, GSAP e áudio - ✓
S[] = AUDIO.map()com LEAD/TAIL/FADE calcula start, dur, audioStart, end - ✓
sceneN()retorna HTML;anim(i,t)gera strings GSAP com fade no.scene-inner - ✓ Quatro streams montados no HTML: scenesHTML, captionsHTML, audioHTML (track 20), animJS
- ✓ Timeline GSAP pausada em
window.__timelines["main"], sentinelatl.set({},{},TOTAL) - ✓ Flag
--verticaltroca W/H e adicionabody.v— output sempreindex.html - ✓
scene9()/case 9é a CTA INEMA.CLUB — nunca remover