MÓDULO 3.2

🔊 Narração local & composição

A voz e a montagem: TTS Kokoro local gratuito, geração dos WAVs a partir do steps.json, medição automática das durações e o build-demo.mjs que sincroniza áudio e animação pelo mesmo array de tempos.

7
Tópicos
30
Minutos
Avançado
Nível
Leitura
Tipo
steps.json narration + ctaNarration Kokoro TTS pf_dora txt/sN.txt → audio/sN.wav ffprobe mede WAVs durações reais AUDIO[] → S[] LEAD 0.5 · TAIL 0.7 · FADE 0.4 start · dur · audioStart · end timeline GSAP + audio tracks leem o MESMO S[] index.html áudio ↔ animação batidos + CTA
1

🎙️ TTS Kokoro local (voz pf_dora)

Narração em PT-BR gerada 100% na máquina, gratuita e sem chave de API — o que mantém a skill auto-contida.

💡Conceito Principal

Kokoro é um TTS ONNX que roda local (pip install kokoro-onnx soundfile), com a voz pf_dora (PT-BR) e --speed 0.98. A primeira execução baixa ~340MB do modelo; depois é offline. Nenhuma chave de API, nenhum custo por minuto.

geração de um WAV
npx -y hyperframes tts "assets/txt/s1.txt" \
  --voice pf_dora \
  --speed 0.98 \
  --output "assets/audio/s1.wav"
Expanda números e siglas na fala

"512" → "quinhentos e doze"; "URL" → soletre; "automationsai.net" → "inema ponto club". O TTS lê literal — escrever por extenso evita leituras estranhas.

🚨
Você não escuta o áudio no render

A voz é boa, mas sem atuação. Sempre peça ao usuário para validar a locução — ele é quem ouve antes do render final.

2

📝 Gerar os WAVs a partir do steps.json

O narration-template.sh extrai as falas do steps.json e gera um WAV por passo + CTA.

narration-template.sh — trecho
# extrai steps[].narration + ctaNarration -> assets/txt/sN.txt
node -e '
const d=JSON.parse(fs.readFileSync("steps.json","utf8"));
const lines=d.steps.map(s=>s.narration||"");
lines.push(d.ctaNarration);
lines.forEach((t,i)=>fs.writeFileSync(`assets/txt/s${i+1}.txt`, t));
'
# gera 1 WAV por txt (passos + CTA)
for i in $(seq 1 "$N"); do
  npx -y hyperframes tts "assets/txt/s$i.txt" \
    --voice pf_dora --speed 0.98 \
    --output "assets/audio/s$i.wav"
done
FAZER
  • Escrever as falas no próprio steps.json
  • Garantir 1 narração por passo + a ctaNarration
  • Rodar na raiz do projeto (onde está steps.json e assets/)
NÃO FAZER
  • Manter o texto da fala separado do steps.json (vira divergência)
  • Esquecer a CTA — ela é o último WAV
  • Numerar errado: os WAVs precisam ser s1..sN na ordem dos passos
3

📏 Medir a duração real dos WAVs

O timing é fonte única: o gerador mede cada WAV com ffprobe — não há array de tempos digitado à mão.

build-demo.mjs — medição automática
const NA = STEPS.length + 1;   // +1 da CTA
const AUDIO = [];
for (let i = 1; i <= NA; i++) {
  const d = parseFloat(execSync(
    `ffprobe -v error -show_entries format=duration \
     -of default=noprint_wrappers=1:nokey=1 \
     "assets/audio/s${i}.wav"`).toString().trim());
  AUDIO.push(d);   // duração REAL, não estimada
}
📊
Por que medir em vez de estimar

Uma fala de "10 segundos" raramente dura exatos 10s. Medir o WAV real e derivar o tempo das cenas dali é o que garante que a animação termine junto com a voz, sem ajuste manual.

ffmpeg/ffprobe no Windows/git-bash

Em ambientes git-bash, use ffmpeg -nostdin nas chamadas para extrair frames — sem a flag o processo pode travar lendo stdin interativo.

4

⚙️ A composição: build-demo.mjs

O gerador central: lê o steps.json, mede os WAVs e produz o index.html com moldura, cursor, destaque, zoom e CTA prontos.

1. lê steps.json

Carrega viewport, window, os passos (shot + target + caption + narration) e a ctaNarration.

2. mede WAVs + calcula geometria

Monta AUDIO[] com ffprobe e mapeia cada bbox do espaço do screenshot para o canvas (mapBox, center).

3. escreve index.html (16:9)

Cenas (1 por passo) + CTA, moldura, cursor global, destaques, zoom e timeline GSAP — tudo num único HTML renderizável.

um comando
node build-demo.mjs     # -> index.html (16:9), pronto para lint/render
🚨
index.html é gerado — não editar à mão

Qualquer ajuste vai no steps.json ou no build-demo.mjs, depois rode de novo. Editar o HTML direto se perde no próximo build.

5

🔗 Sincronizar áudio ↔ animação pelo S[]

A timeline e os áudios leem o mesmo array de tempos derivado de AUDIO[] — sincronia por construção.

build-demo.mjs — cálculo de S[]
const LEAD = 0.5, TAIL = 0.7, FADE = 0.4;
let t = 0;
const S = AUDIO.map((a, i) => {
  const dur = LEAD + a + TAIL;
  const o = { i: i+1, start: t, dur,
    audioStart: t + LEAD, audioDur: a, end: t + dur };
  t += dur; return o;
});
▶️
start
início da cena
dur
LEAD+áudio+TAIL
🔉
audioStart
start + LEAD
⏹️
end
start + dur
📊
Tracks alternados anti-overlap

Cenas e captions ficam em tracks alternados (1/3 e 2/4): um track termina enquanto o outro já prepara o próximo áudio, evitando sobreposição nas transições com FADE.

6

💬 Captions no rodapé

Cada passo tem um caption que vira legenda translúcida sincronizada com a cena.

💡Conceito Principal

O caption de cada passo (escrito no steps.json) é renderizado no rodapé com Inter 600 sobre fundo translúcido, entrando e saindo junto com a cena, em track alternado em relação às cenas.

📊
Caption ≠ narração

A narração é o que a voz fala (pode ter números por extenso); o caption é o texto curto na tela. Os dois vivem no mesmo passo do steps.json, mas servem a propósitos diferentes — feeds mudos leem o caption.

Caption curto

Mantenha o caption em uma frase. Texto longo no rodapé compete com a moldura e o resultado — a legenda reforça, não substitui a fala.

7

📣 A CTA final do AutomationsAI

A última cena é a chamada de marca — já vem pronta no template, com narração padrão.

💡Cena final padrão

"CONTINUA EM" + AutomationsAI (AutomationsAI creme, .CLUB âmbar com glow) + 🌐 automationsai.net. Narração padrão: "Isso é conteúdo do AutomationsAI ponto CLUB. Acesse: inema ponto club." Na CTA, o cursor some (opacity:0).

steps.json — ctaNarration
"ctaNarration": "Isso é conteúdo do AutomationsAI ponto CLUB. Acesse: inema ponto club."

🎯 O que você aprendeu

  • Kokoro gera a narração PT-BR local, grátis, voz pf_dora --speed 0.98
  • O narration-template.sh tira as falas do steps.json (passos + CTA)
  • O build-demo.mjs mede os WAVs com ffprobe — timing fonte única
  • S[] (start/dur/audioStart/end) sincroniza áudio e animação
  • Captions e a CTA do AutomationsAI já vêm prontos

Próximo: Módulo 3.3 — montar o projeto HyperFrames, validar com lint/inspect e renderizar o MP4 final.