Guia Mestre Remotion — Criação Programática de Vídeos em React
Remotion permite a criação de vídeos cinematográficos com código React puro. Cada frame do vídeo é tratado como um estado determinístico (frame) => UI, gerando visuais perfeitos em 60 FPS sem travamentos ou queda de frames.
1. Arquitetura de Composição & Configuração Raiz
A. Ponto de Entrada Raiz (Root.tsx)
import { Composition } from 'remotion';
import { MainExplainer } from './compositions/MainExplainer';
import { VerticalShort } from './compositions/VerticalShort';
export const RemotionRoot: React.FC = () => {
return (
<>
{/* Explicativo Cinematográfico 16:9 */}
<Composition
id="MainExplainer-1080p"
component={MainExplainer}
durationInFrames={30 * 32} // 32 segundos @ 30 FPS = 960 frames
fps={30}
width={1920}
height={1080}
defaultProps={{
title: 'Mistério do Derretimento dos Picos de Gelo Mundiais',
author: 'NARA Studio',
themeColor: '#f97316',
}}
/>
{/* Vertical 9:16 para TikTok / Reels / Shorts */}
<Composition
id="VerticalShort-60fps"
component={VerticalShort}
durationInFrames={60 * 15} // 15 segundos @ 60 FPS = 900 frames
fps={60}
width={1080}
height={1920}
/>
</>
);
};
B. Regras de Duração e FPS
- 16:9 YouTube / Explicativo: Recomendação
30 fps(equilíbrio entre velocidade de renderização e suavidade de movimento) ou60 fpspara tipografia cinética ultra-nítida. - Duração em Frames: Sempre calcule
durationInFrames = Math.round(segundos * fps). - Zero Jitter: Não use
setIntervalousetTimeout. Sempre useuseCurrentFrame()euseVideoConfig().
2. Primitivas de Layout e Linha do Tempo
AbsoluteFill
Base de toda a camada de cena. Automaticamente position: absolute; inset: 0; width: 100%; height: 100%;:
import { AbsoluteFill } from 'remotion';
export const SceneBackground: React.FC = () => {
return (
<AbsoluteFill style={{ backgroundColor: '#090812', overflow: 'hidden' }}>
{/* Conteúdo visual */}
</AbsoluteFill>
);
};
Sequence vs Series
Sequence: Posiciona elementos em um tempo absoluto (fromedurationInFrames). Ideal para áudio de fundo, marcas d'água, sobreposições HUD ou elementos que se sobrepõem.Series: Organiza cenas sequencialmente de forma automática, sem necessidade de calcular offsets de frame manualmente.
import { Series, Sequence, Audio, staticFile } from 'remotion';
export const VideoStory: React.FC = () => {
return (
<AbsoluteFill>
{/* Áudio de Música de Fundo Durante Todo o Vídeo */}
<Audio src={staticFile('audio/ambient_score.mp3')} volume={0.35} />
{/* Sequência Automática de Cenas */}
<Series>
<Series.Sequence durationInFrames={120}>
<HookScene />
</Series.Sequence>
<Series.Sequence durationInFrames={180}>
<ProblemScene />
</Series.Sequence>
<Series.Sequence durationInFrames={240}>
<SolutionScene />
</Series.Sequence>
<Series.Sequence durationInFrames={150}>
<CallToActionScene />
</Series.Sequence>
</Series>
</AbsoluteFill>
);
};
3. Física de Animação: spring() e interpolate()
A. Fórmula de Mola Natural (spring())
Use spring() para gerar movimentos com física real (eliminando a rigidez de animações "PowerPoint"):
import { spring, useCurrentFrame, useVideoConfig } from 'remotion';
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// 1. Pop Repentino (Texto/Emblema Aparecendo com Impacto)
const popScale = spring({
frame,
fps,
config: { damping: 10, mass: 0.4, stiffness: 180 },
});
// 2. Deslizamento Suave (Câmera Deslizando Suavemente)
const smoothSlide = spring({
frame,
fps,
config: { damping: 20, mass: 1.2, stiffness: 60 },
});
// 3. Queda Elástica (Ícone/Partícula Caindo e Quicando)
const bounce = spring({
frame: frame - 10, // atraso de 10 frames
fps,
config: { damping: 8, mass: 0.6, stiffness: 140 },
});
B. Mapeamento Suave de Valores (interpolate())
import { interpolate, Easing } from 'remotion';
// Transição Alpha e Rotação com Easing Bezier
const opacity = interpolate(frame, [0, 20], [0, 1], {
extrapolateRight: 'clamp',
});
const rotateY = interpolate(frame, [0, 60], [-45, 0], {
easing: Easing.bezier(0.16, 1, 0.3, 1),
extrapolateRight: 'clamp',
});
4. Tipografia Cinética e Sincronização com Voiceover
A. Revelação de Palavras Escalonadas (Texto Aparecendo Palavra por Palavra)
import React from 'react';
import { useCurrentFrame, useVideoConfig, spring, interpolate } from 'remotion';
interface KineticTextProps {
sentence: string;
startFrame?: number;
wordDelay?: number;
}
export const KineticText: React.FC<KineticTextProps> = ({
sentence,
startFrame = 0,
wordDelay = 4, // 4 frames de intervalo entre palavras
}) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const words = sentence.split(' ');
return (
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '12px', justifyContent: 'center' }}>
{words.map((word, idx) => {
const wordStart = startFrame + idx * wordDelay;
const progress = spring({
frame: frame - wordStart,
fps,
config: { damping: 12, mass: 0.4, stiffness: 160 },
});
const translateY = interpolate(progress, [0, 1], [40, 0]);
const opacity = interpolate(progress, [0, 1], [0, 1]);
return (
<span
key={idx}
style={{
display: 'inline-block',
transform: `translateY(${translateY}px)`,
opacity,
fontSize: '48px',
fontWeight: 800,
color: idx === 0 ? '#f97316' : '#ffffff',
letterSpacing: '-1px',
fontFamily: "'JetBrains Mono', sans-serif",
}}
>
{word}
</span>
);
})}
</div>
);
};
B. Sincronização de Voiceover e Efeitos Sonoros
- Coloque os arquivos de áudio na pasta
public/audio/. - Use
staticFile('audio/file.mp3'). - Crie transições de fade in/fade out usando a propriedade
volume:
<Audio
src={staticFile('audio/naskah_vo.mp3')}
volume={(f) =>
interpolate(f, [0, 15, 880, 900], [0, 1, 1, 0], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
})
}
/>
5. Assets Assíncronos e Pré-carregamento (delayRender)
Quando o vídeo carrega fontes personalizadas, imagens externas ou dados de API, o Remotion DEVE ser informado para não renderizar frames vazios:
import { delayRender, continueRender } from 'remotion';
import { useEffect, useState } from 'react';
export const DynamicScene: React.FC = () => {
const [handle] = useState(() => delayRender('Carregando Fonte e Asset'));
useEffect(() => {
document.fonts.ready.then(() => {
continueRender(handle);
});
}, [handle]);
return <AbsoluteFill>...</AbsoluteFill>;
};
6. Template e Receitas de Motion Graphics NARA
Fórmula de 8 Etapas Cinematográficas (Anti-PPT)
- Cena 1: Gancho Inicial (00-03s) $ ightarrow$ Visual de mistério + Tipografia cinética grande.
- Cena 2: Problema Apresentado (04-07s) $ ightarrow$ Visual de gelo desabando / gráfico vermelho ardente.
- Cena 3: Mergulho em Dados (08-12s) $
ightarrow$ Números estatísticos contando para cima (
Math.floor). - Cena 4: Mudança de Escala Dinâmica (13-16s) $ ightarrow$ Transição de escala macro para micro.
- Cena 5: Impacto Humano (17-20s) $ ightarrow$ Personagem cartoon reagindo na tela.
- Cena 6: Revelação da Solução (21-25s) $ ightarrow$ Visual muda para cores verdes/laranja brilhantes.
- Cena 7: Etapas de Ação (26-29s) $ ightarrow$ 3 cartões flutuantes em 3D.
- Cena 8: Clímax e CTA (30-32s) $ ightarrow$ Logo do estúdio pulsando + efeito sonoro de whoosh.
7. Execução de Renderização via CLI e Aceleração de Hardware
A. Renderizar Vídeo Único (1080p 60fps)
npx remotion render src/remotion/index.ts MainExplainer-1080p out/output.mp4 --gl=angle
B. Renderização Rápida com Alta Concorrência
npx remotion render src/remotion/index.ts MainExplainer-1080p out/output.mp4 --concurrency=8 --gl=angle --jpeg-quality=90
C. Flags Importantes de Renderização
--gl=angle: Usa aceleração de GPU DirectX no Windows (muito mais rápido que o rasterizador por software).--gl=swiftshader: Fallback por software caso GPU não esteja disponível em container/CI.--concurrency=N: Número de núcleos de CPU usados para renderização paralela.--muted: Renderiza sem stream de áudio se apenas o visual for necessário.--props='{"title":"Novo"}': Passa parâmetros dinâmicos via JSON na linha de comando.
8. Guia de Solução de Problemas
- Tela Preta / Imagem Não Aparece: Certifique-se de que o asset está na pasta
public/e é chamado comstaticFile('nome_do_arquivo'). - Vídeo Trava Durante Renderização: Verifique se há um loop infinito em
useMemoou um componente React que não finalizoudelayRender. - Áudio Fora de Sincronia: Certifique-se de que o valor de
fpsda composição é exatamente igual ao cálculo dos segundos do voiceover (segundos = frames / fps).