Tipografia Cinética
Crie vídeos onde as palavras são a própria imagem. Uma frase chega, preenche a tela, é atingida e substituída pela próxima, em ritmo. Deve parecer ousado, rápido e musical, como um pôster que se move.
Opções
| Opção | Padrão | Observações |
|---|---|---|
| formato | vertical 1080×1920 | ou paisagem 1920×1080, quadrado 1080×1080 |
| duração | 10–20 s | corresponder à narração ou à seção da música |
| tom | punchy | calmo (slides e fades de 0,4 s, menos inversões), punchy (padrão), caótico (todas maiúsculas, batidas, sacudidas, uma inversão a cada duas frases) |
| ritmo | tempo fixo | ou tempos da narração, ou batidas da música |
Briefing (responda antes de planejar)
- Qual é a única frase que o espectador deve lembrar?
- Divida o roteiro em frases de 1–4 palavras; marque uma palavra herói por frase.
- Onde está o pico de energia (a frase que recebe a inversão de cor)?
- Qual é o lockup final (título, call to action, handle)?
Folha de leitura (escreva com a lista de batidas)
Para cada batida, escreva a única coisa que o espectador deve entender ("o robô não pode voar", "a cache não acertou") e por quanto tempo ela fica legível. Uma leitura por vez. Pisos de texto: um rótulo fica pelo menos 0,8 s, uma frase cerca de 0,3 s por palavra depois de totalmente na tela. Se o texto não couber no tempo, corte palavras em vez de acelerar.
Disciplina de movimento
- Movimento é causal: todo movimento tem um motivo na tela (um clique, uma queda, um pacote chegando), e o próximo movimento segue dele.
- Escolha uma direção principal de deslocamento para todo o vídeo e mantenha-a. Use as outras direções para significado: para cima para sucesso ou conclusão, um zoom out para "aqui está a imagem completa".
- A saída de uma cena prepara a próxima entrada: mesmo eixo, mesma direção, velocidade semelhante. Carregue um objeto através da mudança em vez de fazer crossfade.
- Sem movimento de preenchimento ocioso (flutuação, respiração, oscilação) em diagramas, gráficos ou texto. Se nada deve se mover, fique parado; uma deriva deliberada da câmera é suficiente.
- Easing: ease-out suave para entradas (
power2.outapower4.out), ease-in mais rápido para saídas (cerca de 75% do tempo de entrada). Entradas no máximo 0,8 s. Stagger total para um grupo no máximo 0,5 s. Overshoot (back.out) apenas para pequenos pops; sem elastic ou bounce. - Uma coisa se move de cada vez quando importa; o olho só pode seguir uma.
- Adicione uma pausa de 0,3–0,75 s antes do payoff.
Regras de estilo (sempre)
Elas fazem este estilo; mantenha-as independentemente das cores ou palavras.
- O tipo preenche 50–80% da largura do quadro, porque texto pequeno é lido como legendas, não como visual.
- Uma ideia na tela por vez: 1–4 palavras, no máximo 3 linhas. Todo o resto já saiu.
- Cada palavra chega com um movimento (slam, slide, stretch, mask reveal, flip). Nada simplesmente aparece.
- As mudanças ocorrem em um ritmo: uma nova palavra ou movimento a cada 0,25–0,7 s, e palavras-chave na batida ou na sílaba tônica.
- O contraste é extremo: quase preto sobre off-white ou o inverso, mais uma cor de destaque apenas para a palavra-chave.
- Cada frase recebe uma palavra herói: a maior, com cor de destaque ou movendo-se de forma diferente das demais.
Padrões (mude à vontade)
Fontes, cores, palavras, tempo e fundo. Se o usuário fornecer fontes ou cores da marca, as deles vencem. Precedência: marca ou especificação do usuário, depois o pedido explícito, depois estes padrões.
- Fundo
#111111, texto#f4f1ea, destaque#ff4d2e. Inverta para claro-escuro ou escuro-claro por frase para dar energia. - Fonte de exibição: uma fonte condensada pesada (Anton, Bebas Neue ou Archivo Black), todas maiúsculas para palavras herói. Fonte de suporte: uma fonte sans pesada (Inter 800) para palavras de conexão pequenas.
- Tamanho: palavras herói 180–320 px em 9:16; palavras pequenas 60–90 px.
Configuração (uma vez)
node -v # precisa de 22+
ffmpeg -version
npx hyperframes init meu-video --non-interactive --resolution portrait && cd meu-video # landscape para 16:9
Dentro de uma pasta vazia existente, use npx hyperframes init . --non-interactive --resolution portrait, depois substitua o index.html gerado pelo modelo abaixo.
Decida antes de construir
Declare-os de volta ao usuário em uma linha antes de escrever o código.
- Proporção: 9:16 (1080×1920) ou 16:9 (1920×1080). O padrão é 9:16.
- Palavras e tempo: divida o roteiro em frases de 1–4 palavras. Com narração, use os tempos dos carimbos de data/hora das palavras (
npx hyperframes transcribe voice.wav). Sem narração, dê a cada frase 0,6–1,4 s e às palavras herói mais tempo. - Fonte do ritmo: voz (cair em sílabas tônicas), música (cair nas batidas;
npx hyperframes beats music.mp3) ou tempo fixo (ex.: 120 BPM = uma batida a cada 0,5 s). - Palavra herói por frase e qual movimento ela recebe.
| Necessidade | HyperFrames + GSAP (padrão) | Remotion |
|---|---|---|
| Movimentos de palavras e letras, máscaras, esticamentos | sim | sim |
| Tempo a partir de dados de voz ou batida | sim (rótulos) | sim (quadros) |
| Funciona apenas com Node e FFmpeg | sim | sim |
| Licença | gratuita | gratuita até 3 pessoas, paga acima |
Vocabulário de movimentos
| Movimento | Como (GSAP) | Use para |
|---|---|---|
| Slam | from {scale: 2.6, opacity: 0}, expo.out, 0,22 s, mais um tremor de tela de 6 px por 0,1 s | palavras herói |
| Slide stack | linhas from {yPercent: 110} dentro de máscaras overflow:hidden, stagger 0,06 s, power4.out 0,35 s | listas, frases de duas linhas |
| Stretch | scaleY: 1.6 → 1, transformOrigin: bottom, back.out(3) 0,3 s | ênfase, verbos |
| Letter cascade | letras from {y: -120, rotation: -20, opacity: 0}, stagger 0,025 s, back.out(2) | nomes, títulos |
| Flip swap | palavra antiga rotationX: 90 sai (0,12 s), palavra nova rotationX: -90 → 0 entra (0,18 s) | X se torna Y |
| Split | metades da palavra deslizam x: ±140 para revelar uma palavra menor no meio | contrastes |
| Exit | yPercent: -110 ou scale: 0.7, opacity: 0, 0,15 s, power2.in | toda frase saindo |
As saídas são rápidas (0,12–0,18 s) e as entradas são mais rápidas do que você pensa (0,18–0,35 s). Segure cada frase por pelo menos 0,35 s depois que ela pousar, para que possa ser lida.
Torne-o atraente
- Preencha o quadro. Dimensione as palavras à largura do quadro, não a um tamanho de fonte. Fontes condensadas com 250+ px são o visual.
- Inversões de cor: o fundo alterna entre escuro e claro (ou para o destaque) em 2–3 frases-chave, como um corte brusco na batida.
- Textura e profundidade: uma sobreposição de granulação sutil, uma sombra suave ou duplicata deslocada atrás das palavras herói (cor de destaque, deslocamento 10–14 px) e uma ocasional palavra gigante esmaecida no fundo.
- Energia da câmera: uma deriva de escala lenta de 2–4% em todo o palco, um punch-in (escala 1.06 por 0,1 s) nos hits herói e um tremor de 6–10 px nos slams.
- Formas com palavras: barras sublinhadas que se desenham, círculos que aparecem atrás de uma palavra, setas. Cor de destaque, plana.
- Termine em um lockup: o título ou call to action, totalmente composto, segurado por 1–1,5 s, correspondendo ao quadro inicial para que faça loop.
- Portão de qualidade: se qualquer snapshot mostrar texto pequeno centralizado em um fundo simples, não está pronto.
Construa: modelo
<!doctype html><html><head><meta charset="UTF-8">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Anton&family=Inter:wght@800&display=swap">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
<style>
html,body{margin:0;width:1080px;height:1920px;overflow:hidden;background:#111}
#root{width:100%;height:100%;position:relative;overflow:hidden}
#stage{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}
.phrase{position:absolute;left:60px;right:120px;top:270px;bottom:670px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:0}
.line{overflow:hidden;line-height:.92;padding:0 8px}
.w{display:inline-block;font-family:Anton,sans-serif;text-transform:uppercase;color:#f4f1ea;white-space:nowrap}
.hero{color:#ff4d2e}
.flip .w{color:#fff}.flip .hero{color:#111}
.small{font-family:Inter,system-ui,sans-serif;font-weight:800;text-transform:none}
#bg{position:absolute;inset:0;background:#111}
</style></head>
<body><div id="root" data-composition-id="main" data-start="0" data-duration="8" data-width="1080" data-height="1920">
<div id="bg"></div><div id="stage"></div></div>
<script>
// [time, lines, moveName, heroWordIndex, flipBackground?] -- edite esta lista; tempos em segundos
const PHRASES = [
[0.2, ["PALAVRAS"], "slam", 0],
[1.0, ["podem", "SE MOVER"], "stack", 1],
[2.0, ["COMO", "MÚSICA"], "stretch", 1, true],
[3.2, ["uma", "ideia"], "stack", 1],
[4.2, ["DE CADA", "VEZ"], "slam", 1],
[5.4, ["TIPO", "CINÉTICO"], "cascade", 1],
];
const END = 8, W = 1080 - 180;
// meça o texto apenas após carregar as fontes da web, depois construa e registre a timeline
document.fonts.ready.then(() => {
const tl = gsap.timeline({ paused: true });
const stage = document.getElementById("stage");
PHRASES.forEach(([t, lines, move, hero, flip], i) => {
const p = document.createElement("div"); p.className = "phrase" + (flip ? " flip" : ""); stage.appendChild(p);
const words = lines.map((txt, k) => {
const line = document.createElement("div"); line.className = "line";
const w = document.createElement("span"); w.className = "w" + (k === hero ? " hero" : "") + (txt === txt.toLowerCase() && k !== hero ? " small" : "");
w.textContent = txt; line.appendChild(w); p.appendChild(line);
w.style.fontSize = "100px"; const fit = Math.min(420, (100 * W) / w.getBoundingClientRect().width); // preenche a largura
w.style.fontSize = (w.classList.contains("small") ? Math.min(fit, 110) : fit) + "px";
return w;
});
gsap.set(p, { autoAlpha: 0 });
tl.set(p, { autoAlpha: 1 }, t);
if (move === "slam") tl.from(words, { scale: 2.6, opacity: 0, duration: 0.22, ease: "expo.out", stagger: 0.08 }, t)
.fromTo("#stage", { x: -10 }, { x: 10, duration: 0.04, yoyo: true, repeat: 3, ease: "none" }, t + 0.18).set("#stage", { x: 0 }, t + 0.34);
if (move === "stack") tl.from(words, { yPercent: 110, duration: 0.35, ease: "power4.out", stagger: 0.07 }, t);
if (move === "stretch") tl.from(words, { scaleY: 1.7, opacity: 0, transformOrigin: "50% 100%", duration: 0.3, ease: "back.out(3)", stagger: 0.08 }, t);
if (move === "cascade") words.forEach((w, k) => {
const letters = Array.from(w.textContent); w.textContent = "";
letters.forEach((c) => { const l = document.createElement("span"); l.style.display = "inline-block"; l.textContent = c; w.appendChild(l); });
tl.from(w.children, { y: -140, rotation: -20, opacity: 0, duration: 0.4, ease: "back.out(2)", stagger: 0.03 }, t + k * 0.15); });
const next = PHRASES[i + 1] ? PHRASES[i + 1][0] : null;
if (flip) tl.set("#bg", { background: "#ff4d2e" }, t).set("#bg", { background: "#111" }, next || END); // inversão de cor em uma frase-chave
if (next) tl.to(words, { yPercent: -110, opacity: 0, duration: 0.15, ease: "power2.in", stagger: 0.03 }, next - 0.17)
.set(p, { autoAlpha: 0 }, next);
});
tl.fromTo("#root", { scale: 1 }, { scale: 1.04, duration: END, ease: "none" }, 0); // deriva lenta
tl.set({}, {}, END);
window.__timelines["main"] = tl;
});
</script></body></html>
Edite PHRASES para alterar as palavras e os tempos. Adicione movimentos adicionando um ramo if (move === ...) do vocabulário de movimentos. Com narração, coloque o elemento <audio> na raiz e pegue os tempos das frases da transcrição.
Parâmetros a expor ao usuário
aspect · phrases (time, lines, move, hero) · fontDisplay · fontSupport · colors (bg, text, accent) · tempo or audio · flipPhrases (onde o fundo inverte) · endLockup.
Evite
- Fade-ins e derivações lentas como movimento principal. Parece uma apresentação de slides.
- Mais de 4 palavras ou 3 linhas na tela ao mesmo tempo.
- Várias cores de destaque. Um destaque, usado apenas em palavras herói.
- Pesos de fonte finos ou claros, ou fontes script para palavras herói.
- Texto na parte inferior 670 px ou superior 270 px de um quadro 9:16 (a UI da plataforma os cobre).
- Variação aleatória ou por renderização. Cada valor deve vir da timeline.
Modos de falha
| Parece | Causa | Correção |
|---|---|---|
| Uma apresentação de slides | fades, pausas longas, mesmo movimento toda vez | varie movimentos do vocabulário; entradas abaixo de 0,35 s; saídas 0,15 s |
| Legendas, não design | palavras muito pequenas, centralizadas em espaço vazio | dimensione palavras à largura do quadro; fonte condensada; 250+ px |
| Confuso, ilegível | muitas palavras ou movimentos de uma vez | uma frase na tela; uma palavra herói; segure 0,35 s após pousar |
| Fora do ritmo | tempos de frase estimados | use transcrição ou tempos de batida; acerte os hits 2–3 quadros antes |
| Palavras cortadas por máscaras | line-height muito apertado para a fonte | line-height 0.92–1.0 com padding em .line; verifique snapshots |
| Fonte errada na renderização | fonte não carregada | Google Fonts <link> no head; verifique se um snapshot mostra a face condensada |
Valide antes da renderização final
npx hyperframes check
npx hyperframes snapshot --at <um tempo por frase 0,3 s após pousar, mais um meio da saída>
npx hyperframes render -o renders/<nome>.mp4
ffprobe -v error -show_entries stream=width,height,r_frame_rate:format=duration -of csv=p=0 renders/<nome>.mp4
Olhe para cada snapshot e snapshots/contact-sheet.jpg, e confirme:
- cada frase preenche 50–80% da largura e é legível no tamanho de um telefone
- uma palavra herói por frase, na cor de destaque ou com um movimento diferente
- nenhuma duas frases se sobrepõem em nenhum quadro
- todo o texto dentro da área segura para a proporção
- o lockup final é segurado por pelo menos 1 s e corresponde ao inicial
- tamanho e duração correspondem ao pedido
Autocrítica antes da renderização final
Pontue a folha de snapshots de 1 a 10 em: gancho (primeiro segundo), legibilidade na largura do telefone, qualidade do movimento, composição, precisão e o "teste mudo" (um espectador consegue resumir em uma frase sem som?). Corrija apenas o que pontuar 7 ou menos, recapture o snapshot e repita até que tudo esteja 8 ou acima. Se possível, tenha uma passagem de leitura separada para fazer a pontuação, para não estar avaliando seu próprio trabalho.
| Não faça | Em vez disso |
|---|---|
| Crossfade entre dois layouts ocupados | saia do conteúdo antigo, depois traga o novo, ou carregue um objeto através |
| Faça várias coisas se moverem ao mesmo tempo | stagger, um foco |