Remotion (Vídeo Programático)
O Remotion renderiza componentes React quadro a quadro. Cada quadro é uma função pura do número do quadro, portanto a animação é determinística e re-renderizável.
A API do Remotion muda entre versões principais. Leia a versão instalada (
npm ls remotion) e a documentação oficial em remotion.dev antes de usar uma API sobre a qual você não tem certeza. Verifique os termos de licença do Remotion para uso comercial por empresas.
Configuração
npx create-video@latest # escolha o template em branco (TypeScript)
cd my-video && npm install
npx remotion studio # pré-visualização ao vivo
npx remotion render MyComp out/video.mp4
npx remotion still MyComp out/thumb.png --frame=45
O modelo mental
useCurrentFrame()retorna o quadro atual, começando em 0.useVideoConfig()retornafps,width,height,durationInFrames.- Nada anima por si só. Você calcula o estilo a partir do quadro.
- Nunca use transições CSS,
setTimeout,Math.random()ouDate.now()para animação. Eles quebram a determinismo da renderização. Userandom('semente')do remotion.
Composição
// src/Root.tsx
import {Composition} from 'remotion';
import {Explainer} from './Explainer';
export const RemotionRoot = () => (
<Composition
id="Explainer"
component={Explainer}
durationInFrames={30 * 20} // 20 s a 30 fps
fps={30}
width={1920}
height={1080}
defaultProps={{title: 'Olá'}}
/>
);
Primitivas de animação
import {AbsoluteFill, Sequence, interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
export const Titulo: React.FC<{texto: string}> = ({texto}) => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
const opacity = interpolate(frame, [0, 15], [0, 1], {extrapolateRight: 'clamp'});
const escala = spring({frame, fps, config: {damping: 200}}); // suave, sem bounce
return (
<AbsoluteFill style={{justifyContent: 'center', alignItems: 'center'}}>
<h1 style={{opacity, transform: `scale(${0.9 + 0.1 * escala})`, fontSize: 96}}>{texto}</h1>
</AbsoluteFill>
);
};
export const Explainer = () => (
<AbsoluteFill style={{backgroundColor: '#0b1020', color: 'white'}}>
<Sequence from={0} durationInFrames={90}><Titulo texto="Introdução" /></Sequence>
<Sequence from={90} durationInFrames={120}><Titulo texto="Ponto principal" /></Sequence>
</AbsoluteFill>
);
Sempre passe extrapolateLeft/Right: 'clamp' para interpolate a menos que você queira que os valores ultrapassem o intervalo.
Mídia
import {staticFile, Audio, OffthreadVideo, Img} from 'remotion';
<Audio src={staticFile('voz.mp3')} />
<Audio src={staticFile('musica.mp3')} volume={0.12} />
<OffthreadVideo src={staticFile('demo.mp4')} />
<Img src={staticFile('logo.png')} />
Coloque os assets em public/ e referencie-os com staticFile(). Use <Img> em vez de <img> para que a renderização aguarde a imagem. Versões recentes do Remotion fornecem componentes de mídia atualizados; consulte a documentação para a versão instalada.
Sincronizar cenas com narração
Não codifique durações de cenas. Derive-as do áudio.
- Gere arquivos de narração por cena (
voiceover-tts skill). - Meça cada duração com
ffprobee escrevascenes.jsoncom{id, audio, seconds}. - Na composição, converta com
Math.ceil((seconds + 0.5) * fps)e organize<Sequence>pelo deslocamento cumulativo. - Use
calculateMetadatano<Composition>para definir odurationInFramestotal a partir desses dados.
Se a voz for regravada, o vídeo se reajusta automaticamente.
Transições
Instale @remotion/transitions e use TransitionSeries com fade(), slide(), wipe(). Uma transição sobrepõe suas duas cenas, portanto o comprimento total diminui pela duração da transição. Mantenha as transições entre 12 e 20 quadros a 30 fps.
Fontes e marca
Carregue fontes com @remotion/google-fonts ou @remotion/fonts para que estejam prontas antes do primeiro quadro. Mantenha cores, fontes e logotipo em um único brand.ts para que uma reformulação da marca seja uma alteração em um único arquivo.
Desempenho e renderização
- Visualize no estúdio; renderize a partir da CLI.
--concurrency=50%limita o uso da CPU.--codec=h264é o padrão; use--codec=prorespara entrega de edição.- Desfoque pesado, sombras e grandes filtros SVG são lentos. Prefira assets pré-renderizados para esses casos.
- Use
<OffthreadVideo>em vez de<video>para obter extração quadro a quadro precisa. - Para rascunhos rápidos:
--scale=0.5e um intervalo--frames=0-90.
Erros comuns
| Erro | Correção |
|---|---|
| Cintilação ou imagem ausente na renderização | Use <Img>, staticFile e delayRender para dados assíncronos |
| Animação diferente entre pré-visualização e renderização | Remova código não determinístico (tempo, aleatório) |
| Texto transborda em diferentes localidades | Defina larguras explícitas; teste a string mais longa |
| Vídeo muito longo após adicionar transições | Subtraia os quadros da transição do total |
| Áudio silencioso na renderização | Verifique o caminho do arquivo e se o <Audio> está dentro de um <Sequence> ativo |
Combine com motion-design-craft para escolhas de tempo e easing.