🪟 A moldura de navegador
Uma janela persistente envolve cada screenshot — é o que dá o ar de "navegador" e disfarça que o conteúdo é um print.
A janela #appwin vive na bg-layer com data-layout-ignore: borda, raio, sombra grande, barra de título com 3 pontinhos (vermelho/amarelo/verde) e uma pílula de URL mono com cadeado + window.urlLabel. Os screenshots (1 clip por cena) ficam dentro dela, em (WIN_L, SHOT_T) com tamanho VW×VH.
"window": {
"top": 96, // WIN_T — topo da janela no canvas
"titleH": 52, // altura da barra de título
"urlLabel": "localhost:8000"
}
// derivados no build-demo.mjs:
WIN_L = (1920 - VW) / 2 // centraliza horizontal
SHOT_T = WIN_T + TITLE_H // topo do screenshot
- ✓Marcar a moldura com
data-layout-ignore - ✓Usar a
urlLabelreal do app capturado - ✓Manter a janela persistente (não recriar por cena)
- ✗Desenhar o screenshot fora da área da janela
- ✗Carregar o site ao vivo dentro da moldura (render é determinístico)
- ✗Animar a moldura como se fosse cena
➡️ O cursor animado e o caminho até o alvo
Um único cursor global desliza pela timeline principal e cai exato no centro da bounding box real do controle.
A captura roda num viewport fixo (ex.: 1280×800) — toda bbox vem nesse espaço. Um ponto (sx, sy) do screenshot vira canvasX = WIN_L + sx, canvasY = SHOT_T + sy. O alvo do cursor é o centro da bbox mapeada.
// hotspot na ponta da seta ≈ (6,3) num SVG de 42px
const HOT = { x: 6, y: 3 };
// a PONTA cai no centro do alvo, não o canto
tl.to("#cursor", {
x: alvoX - HOT.x,
y: alvoY - HOT.y,
duration: 0.7,
ease: "power3.inOut"
}, s.start + 0.35); // deixa a cena aparecer antes
A bounding box vem de getBoundingClientRect() na captura — não de uma estimativa "no olho". É exatamente isso que faz o cursor parecer profissional: ele cai no pixel certo do botão ou campo.
👆 O clique e o efeito visual
Quando o cursor "clica", um pulse no próprio cursor e um ripple âmbar comunicam a ação ao espectador.
~start + 0.35scursor parteO cursor sai da posição anterior em direção ao alvo, deixando a cena aparecer primeiro.
~start + 1.05schega ao alvoA ponta pousa no centro da bbox; o destaque já está pulsando ao redor do controle.
~start + 1.15scliqueCursor faz scale:.82 em yoyo (pulse) e o #ripple (círculo âmbar) expande e some no centro do alvo.
Passos só de leitura (sem click:true) não disparam o ripple — bom para a tela inicial (intro:true), onde você só apresenta o app sem interagir.
🔍 Zoom e destaque na região ativa
O destaque foca o olhar no controle; o zoom dá um push-in cinematográfico no momento do resultado.
.hlbox (destaque)
Retângulo só com box-shadow (anel âmbar + glow) na bbox mapeada com ~6px de folga. Entra com back.out e pulsa o glow algumas vezes — foca sem cobrir nada.
zoom: true
No passo do resultado, o <img> recebe scale 1 → 1.12 ao longo da narração, com transformOrigin no centro do alvo (ex.: o painel de resultado).
{
"shot": "04-result.png",
"target": { "x": 668, "y": 128, "w": 484, "h": 324 },
"zoom": true,
"caption": "O resultado aparece pronto para baixar.",
"narration": "E pronto: o resultado já está disponível."
}
O último passo de conteúdo costuma ser o resultado com zoom:true — um leve "tcharam" que fecha o arco do walkthrough antes da CTA.
🎨 House style dark premium âmbar
Uma paleta fechada de 6 cores com o âmbar como único destaque dominante — a identidade visual de todos os vídeos.
UM accent dominante: o âmbar. Ele aparece no ripple do clique, no anel do destaque, no glow de fundo e na CTA. Fundo idêntico em todas as cenas — nunca chapado.
Camada de fundo persistente com data-layout-ignore: glow radial âmbar respirando, ghost text gigante driftando, grid hairline e grão. Escala grande: headline 64–172px, decorativos a 12–25% de opacidade.
🔤 As fontes embutidas
Sora, Inter e JetBrains Mono como .woff2 locais — nunca CDN, porque o render é offline e determinístico.
Sora 700–800Títulos e headlines (geométrica, impacto).
Inter 400–600Corpo e captions (alta legibilidade).
JetBrains MonoPílula de URL, valores e código.
O ambiente de render pode não ter internet. Fonte externa cai em fallback e quebra o visual. As fontes vêm de assets/fonts/ (subset latin cobre PT-BR); o build-demo.mjs injeta o fonts.css reescrevendo os caminhos.
⏱️ O timing de cada passo batendo com a narração
O cursor reage à fala: chega ao alvo antes da explicação e clica no momento certo, num ritmo definido por LEAD/TAIL/FADE.
LEAD 0.5s — a cena aparece antes da voz começar.
TAIL 0.7s — respiro depois do áudio terminar.
FADE 0.4s — transição entre cenas.
O cursor chega ao alvo ~0.7s antes da explicação principal; o clique cai perto de start + 1.15s.
Além disso o vídeo cansa e a captura/edição vira trabalho grande. 5–8 passos + CTA ≈ 35–50s — o tamanho ideal de um walkthrough.
🎯 O que você aprendeu
- ✓A moldura
#appwinenvolve o shot e dá o look de navegador - ✓O cursor global mira a bbox real com hotspot na ponta e easing curvo
- ✓O clique faz pulse + ripple âmbar; o zoom dá push-in no resultado
- ✓Paleta dark premium âmbar e fontes locais Sora/Inter/JetBrains
- ✓O timing LEAD/TAIL/FADE casa a animação com a narração
Próximo: Módulo 3.2 — como gerar a narração local com Kokoro e montar tudo com o build-demo.mjs.