Animação explicativa
Um vídeo é uma lista ordenada de cenas em src/timeline.ts. Três tipos:
intro: o cartão de gancho. Sua primeira linha é o gancho, exibido em grande, com as palavras iluminando conforme são faladas (funciona como sua própria legenda).anim: um componente de animação do catálogo, sincronizado com as linhas de narração da cena.outro: o cartão de encerramento com o distintivo da AGILabs,javieraguilar.aie o título do artigo vindo deSETTINGS.articleTitle.
Escrevendo a linha do tempo
import type { Cuts } from './types.ts';
import { L, anim, intro, outro, say, videos } from './narrate.ts';
const build = (): Cuts => ({
main: [
intro('hook', [say(0.4, 'EN hook line.', 'ES hook line.')]),
anim(
'result',
'BarCompare',
{ bars: [{ label: L('With the reason', 'Con el porqué'), value: 14, display: '14/20', highlight: true },
{ label: L('Without it', 'Sin él'), value: 4, display: '4/20' }], max: 20 },
[say(0.3, 'First line.', 'Primera línea.'), say(0, 'Second line.', 'Segunda línea.')],
{ min: 4 },
),
outro('outro', [say(0.4, 'More at javieraguilar.ai.', 'Más en javieraguilar.ai.')]),
],
});
export const VIDEOS = videos(build);
export const TIMELINE = VIDEOS.en.main;
say(at, en, es, spoken?): uma linha de narração.até o segundo mais cedo da cena em que pode começar; as linhas nunca se sobrepõem (intervalo de 0,35 s), e a cena dura até que sua última linha termine mais 0,8 s, oumin.spoken({ en?, es? }) é o que o TTS lê quando difere do texto da legenda (vejanarration).- Beats. O tempo de início de cada linha em uma cena é um beat. Os componentes reproduzem o passo i no beat i (a barra i cresce, o nó i aparece, o bloco i surge), portanto escreva uma linha por passo que deseja revelar. Antes do TTS, os beats vêm de uma estimativa de duração; após
npm run tts, eles vêm do áudio real, então verifique novamente os stills após narrar. L(en, es): um rótulo bilíngue na tela. Uma string simples é usada para ambos os idiomas.- Os IDs das cenas devem ser únicos: as chaves das linhas (
<scene>-01, ...) nomeiam os arquivos de áudio. opts.chapteremanimé armazenado na cena, mas ainda não é desenhado por nenhum componente.- Execute
npm run lintapós cada alteração: verifica duração contratargetSeconds(±20%), pistas de legenda com mais de 0,8 s ou mais de 17 caracteres/s, e nomes de componentes ausentes do catálogo.
Catálogo de componentes
Todos os componentes recebem t, beats, dur, lang e vertical da cena; as props abaixo vêm da linha do tempo. Números mostrados na tela usam a forma exata do artigo: prefira display / string value em vez de texto calculado sempre que o artigo escrever "14/20", "0,0018" ou "83%".
| Componente | Uso | Props |
|---|---|---|
Counter | Um número de destaque contando para cima, com rótulo abaixo | value: number, label: Label, prefix?, suffix?, decimals? (0-8), beat? (índice do beat em que a contagem começa, padrão 0) |
BarCompare | 2 a 5 barras horizontais crescendo uma por beat; a destacada em gradiente de acento | bars: { label: Label; value: number; display?: string; highlight?: boolean; at?: number }[], max? (topo da escala, padrão o maior valor), unit? (anexado quando não há display) |
FlowDiagram | Caixas e setas aparecendo em ordem; uma aresta broken é tracejada e suave, com um espaço | nodes: { id; label: Label; at?: number }[], edges: { from; to; label?: Label; broken?: boolean }[], `layout: 'vertical' |
KeyQuote | A frase-chave, palavra por palavra, palavras enfatizadas no acento com um sublinhado | text: Label, emphasis?: string[] (palavras ou frases, combinadas ignorando maiúsculas e pontuação), beat? |
StatGrid | 2 a 4 blocos de números surgindo um por beat | stats: { value: string; label: Label; at?: number }[] |
at em uma barra, nó ou bloco fixa-o a um segundo da cena em vez de seu próprio beat. Passos sem um beat ou at seguem 0,6 s após o anterior. Cada componente é ajustado para terminar no final da cena: o último quadro sempre mostra o estado final.
Para ver a biblioteca inteira: npm run studio e abra Gallery-vertical, ou renderize stills dela.
Adicionando um componente personalizado
Quando o roteiro sinalizar uma cena como "bespoke":
- Estado primeiro, com um teste. Escreva
src/anim/<Nome>.state.tscom o tipo das props e uma função puraframeState(props, t, beats, dur)que retorna números e strings simples. Sem imports de Remotion ou React ali. Construa-o emsrc/anim/steps.ts(sceneTime,stepTimes,fit,progress,beatAt,easeOutCubic) para que seja total: valores finitos em qualquert, campos de progresso dentro de [0, 1], nada visível antes de seu primeiro beat, estado final emt = dur. - Adicione um caso a
CASESemtest/anim.test.ts(e um teste de seu próprio comportamento), depois executenpm test. Isso verifica o estado emt < 0, em cada beat,dure além dedur, com beats ausentes, atrasados e muito curtos. - Desenhe-o em
src/anim/<Nome>.tsx: chameframeState, desenhe dentro de<Stage vertical={...}>, use os tokens da marca desrc/brand.ts(C,GRADIENT,alpha) e Inter. Sem novas cores ou fontes. - Registre-o em
ANIMSemsrc/anim/index.ts. MantenhaANIMScomo um objeto literal simples de nomes:npm run lintos lê da fonte. - Opcionalmente, adicione uma amostra a
src/Gallery.tsx. Se for reutilizável, pertence ao template do plugin.
Imagens geradas. A maioria das cenas deve ser desenhada em código (SVG e CSS dos tokens da marca). Se uma cena realmente precisar de uma imagem gerada (um fundo, uma imagem base, um momento texturizado), um modelo de imagem pode criá-la, por exemplo, a geração de imagens do Codex CLI. Salve-a em public/, carregue-a com staticFile(), mantenha-a dentro da paleta da marca e verifique o still.
Área segura vertical (1080x1920)
- A interface da plataforma cobre os ~220 px superiores e os ~380 px inferiores; mantenha 72 px nas laterais.
- As animações desenham apenas dentro do palco: de y = 280 (abaixo do distintivo da AGILabs) a y = 1280 (acima das duas linhas de legenda), 936 px de largura.
Stage/stageOf()fornecem essa caixa. - As legendas ficam abaixo do palco, no máximo duas linhas de ~32 caracteres, dentro de ~900 px.
Stills: observe-os
Renderize stills e Leia cada PNG antes de renderizar o vídeo. Um lint ou build limpo não mostra transbordamento, texto cortado ou número errado.
npx remotion still src/index.ts Main-EN-vertical out/stills/f0150.png --frame=150
Pegue um still por cena assim que seu último passo for reproduzido, mais um a cada ~3 s (a cada 90 quadros a 30 fps). Verifique: distintivo da AGILabs e nada mais como marca, nada fora da área segura, nenhum texto transbordando sua caixa, cada figura igual ao artigo, e a legenda na tela correspondendo ao que a animação mostra naquele momento.