Vídeo com IA: Claude Code, Codex e ElevenLabs · Capítulo 5 de 25 · 27 min
Montar vídeo em React com Remotion e renderizar na sua máquina ou na AWS
Transforme um componente React em MP4 com props trocáveis e renderize no seu computador ou no AWS Lambda sabendo o custo e quando a licença passa a cobrar.
Este capítulo faz parte do curso gratuito Vídeo com IA: Claude Code, Codex e ElevenLabs.
Um vídeo feito em editor é um arquivo fechado: trocar o título de 20 versões exige 20 sessões de edição. O Remotion descreve o vídeo como uma aplicação React, em que cada quadro é o desenho de um componente num instante. Trocar o título vira trocar uma prop e renderizar de novo, sem abrir editor.
Sem esse modelo mental, o código que o Claude Code ou o Codex escrever em Remotion vira caixa-preta. Um pacote em versão diferente quebra o build, um vídeo fora da pasta certa sai preto, um render longo no Lambda estoura o timeout da função e cai. E há uma conta que pega de surpresa: o Remotion não é MIT, e a partir de quatro pessoas na empresa a licença cobra.
Nesta aula você cria o projeto do zero, escreve uma composição com props, vê a prévia no Studio, renderiza na sua máquina e no AWS Lambda e registra no projeto qual licença se aplica ao seu caso.
Entender composição, props e o que a licença cobra
Em 12/10/2026, a versão latest é a 4.0.535, publicada no mesmo dia; a 4.0.534, de 07/10/2026, trouxe o Chromium 157. A série 4.0.5xx sai quase todo dia, por isso a regra do curso é usar a versão vigente na data, conferida com npm view remotion version, e gravá-la igual em todos os pacotes. A 4.0.527 trouxe a ação de gerar legendas no Studio e a 4.0.530, a importação de SRT. O Remotion 5.0 ainda não foi lançado.
Dois conceitos sustentam tudo. Composição é a declaração de um vídeo (id, componente, largura, altura, fps e duração em quadros), como a ficha técnica de uma peça. Props são os valores que entram nela, como os campos de um formulário que gera o mesmo documento com dados diferentes. O Remotion não impõe limite de duração, resolução ou fps; quem limita é a composição, o renderizador e a licença.
O mesmo componente segue dois caminhos. No Studio e no @remotion/player, ele roda no navegador, sem FFmpeg. No render, um Chrome sem interface desenha cada quadro e o FFmpeg monta o MP4, na sua máquina ou na sua conta AWS. Os pacotes @remotion/renderer, @remotion/bundler e @remotion/cli só rodam no Node; nunca os importe dentro de um componente.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
A licença é gratuita para pessoas físicas, ONGs e empresas de até 3 pessoas, inclusive para uso comercial. A partir de 4 pessoas há três planos, e a infraestrutura da AWS nunca entra no preço. Em agência, contam os funcionários das duas empresas se o cliente opera o projeto; e embutir o @remotion/player num produto conta como automação.
Licença e custo de render do Remotion em 12/10/2026
scale Planos e custo de render
Planos da licença e custo de render do Remotion
| Situação | Plano ou custo | O que entra |
|---|---|---|
| Pessoa física, ONG ou empresa até 3 pessoas | Gratuito | Uso comercial incluído |
| Empresa a partir de 4 pessoas, quem escreve código | Creators: US$ 25 por pessoa por mês | Cada pessoa que escreve código Remotion |
| Empresa a partir de 4 pessoas, renders automáticos | Automators: US$ 0,01 por render, mínimo de US$ 100 por mês | Inclui o Player embutido em produto |
| Grande empresa | Enterprise: a partir de US$ 500 por mês | Contrato sob medida |
| Render no Lambda, 1 min de vídeo | US$ 0,017 a 0,021 | Só computação; sem S3, saída de dados nem licença |
| Render no Lambda, cerca de 10 min em HD | US$ 0,103 a 0,108 | Exemplo oficial com 2048 MB em us-east-1 |
Preços da licença de 12/10/2026, na FAQ de licença, reestruturada na 4.0.526, de 17/09/2026. Custos do Lambda do exemplo oficial com Remotion 4.0.381, página de 06/10/2026.
bookOpen O que diz a FAQ de licença

Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Escrever a composição com props
O projeto nasce do modelo oficial e todos os pacotes @remotion/* ficam na mesma versão exata; misturar versões é a causa mais comum de erro de build. Se a linha de npm install ou o package.json ainda são novidade, o curso de Node.js mostra npm e package.json desde o começo. As skills e o plugin que ensinam o Remotion ao agente entram em skills de vídeo no Claude Code; aqui você escreve à mão.
#!/usr/bin/env bash
# scripts/aula05_projeto.sh: cria o projeto Remotion, alinha as versões e prepara as pastas.
# Uso: bash scripts/aula05_projeto.sh (na raiz video-ia; o projeto nasce em composicoes/cozinha-remotion/)
set -euo pipefail
# 1) Projeto em branco com o modelo oficial. Sempre @latest: sem ele o npx pode
# reaproveitar um create-video antigo do cache e trazer um modelo velho.
cd composicoes
npx create-video@latest --yes --blank cozinha-remotion
cd cozinha-remotion # daqui em diante, a raiz video-ia fica em ../..
# 2) Todos os pacotes do Remotion na MESMA versão exata: a vigente na data, conferida com npm view
# (4.0.535 em 12/10/2026). Nunca a 4.0.531, que saiu quebrada e foi republicada como 4.0.532.
# --save-exact grava o número sem ^; versões misturadas são a causa mais comum de erro de build.
V=$(npm view remotion version) # ex.: 4.0.535
npm install remotion@$V @remotion/cli@$V @remotion/lambda@$V \
@remotion/captions@$V react react-dom --save-exact
grep -E '"(remotion|@remotion/[a-z-]+)"' package.json # todas as linhas com o mesmo número
# 3) Ponto de entrada que o Studio, a CLI e o Lambda carregam: só registra a raiz (Root.tsx)
cat > src/index.ts <<'TS'
import { registerRoot } from "remotion";
import { RemotionRoot } from "./Root";
registerRoot(RemotionRoot);
TS
# 4) public/ guarda a mídia que staticFile() lê. O b-roll é uma CÓPIA do bruto: midia/raw/ só é lido.
# Os MP4 vão para ../../renders/, que o .gitignore da raiz já deixa fora do git.
mkdir -p public
cp ../../midia/raw/broll_massa.mp4 public/broll_massa.mp4
# 5) Studio para a prévia (não conta como render na licença). Abre no navegador.
npm run devO componente abaixo é o cartão de abertura dos cortes: b-roll ao fundo, título com mola e cinco ingredientes entrando um a um. Três funções fazem a animação. useCurrentFrame() devolve o quadro que está sendo desenhado; interpolate() converte esse número em valor, como uma regra de três entre o quadro 0 e o quadro 15; spring() faz o movimento de mola. O <OffthreadVideo> lê o b-roll da pasta public/ por staticFile().
// src/Receita.tsx
// Cartão de receita: b-roll ao fundo, título com mola e ingredientes entrando um a um.
import React from "react";
import {
AbsoluteFill,
OffthreadVideo,
Sequence,
interpolate,
spring,
staticFile,
useCurrentFrame,
useVideoConfig,
} from "remotion";
// "type", não "interface": só um type alias satisfaz o Record<string, unknown>
// que o Remotion exige nas props de uma composição.
export type ReceitaProps = {
titulo: string; // ex.: "Bolo de rolo"
cidade: string; // ex.: "Recife"
ingredientes: string[]; // até 5 itens
broll: string; // nome do arquivo dentro de public/
};
export const Receita: React.FC<ReceitaProps> = ({ titulo, cidade, ingredientes, broll }) => {
const frame = useCurrentFrame(); // quadro atual, de 0 a durationInFrames - 1
const { fps, durationInFrames, width } = useVideoConfig(); // vêm da <Composition>
// Título: mola de 0 a 1 nos primeiros quadros e opacidade de 0 a 1 entre os quadros 0 e 15
const escala = spring({ frame, fps, config: { damping: 200 } });
const opacidade = interpolate(frame, [0, 15], [0, 1], { extrapolateRight: "clamp" });
// Fonte proporcional à largura: o mesmo componente serve ao 16:9 e ao 9:16
const base = width / 1080;
return (
<AbsoluteFill style={{ backgroundColor: "#1b0f0a" }}>
{/* b-roll mudo durante a composição inteira; OffthreadVideo extrai o quadro exato */}
<Sequence from={0} durationInFrames={durationInFrames}>
<OffthreadVideo
src={staticFile(broll)}
muted
style={{ objectFit: "cover", width: "100%", height: "100%" }}
/>
</Sequence>
{/* Escurece a metade de baixo para o texto ficar legível */}
<AbsoluteFill style={{ background: "linear-gradient(transparent 40%, rgba(0,0,0,0.85))" }} />
{/* 320 px de margem inferior: o texto fica fora da interface do Reels e do TikTok */}
<AbsoluteFill style={{ justifyContent: "flex-end", padding: `0 ${80 * base}px ${320 * base}px` }}>
<h1
style={{
color: "#fff",
fontSize: 110 * base,
margin: 0,
lineHeight: 1,
opacity: opacidade,
transform: `scale(${escala})`,
transformOrigin: "left bottom",
}}
>
{titulo}
</h1>
<p style={{ color: "#f5c16c", fontSize: 44 * base, margin: `${12 * base}px 0 ${32 * base}px` }}>
Cozinha da Rafa, {cidade}
</p>
{/* Cada ingrediente entra 10 quadros depois do anterior e leva 8 quadros para aparecer */}
{ingredientes.slice(0, 5).map((item, i) => {
const inicio = 30 + i * 10;
const faixa = [inicio, inicio + 8];
const op = interpolate(frame, faixa, [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
const dx = interpolate(frame, faixa, [-40, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
return (
<div
key={item}
style={{ color: "#fff", fontSize: 48 * base, opacity: op, transform: `translateX(${dx}px)`, marginBottom: 10 * base }}
>
{item}
</div>
);
})}
</AbsoluteFill>
</AbsoluteFill>
);
};Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
// src/Root.tsx
// A mesma cena registrada em dois formatos: só mudam width e height.
// 150 quadros a 30 fps = 5 segundos.
import React from "react";
import { Composition } from "remotion";
import { Receita, type ReceitaProps } from "./Receita";
const padrao: ReceitaProps = {
titulo: "Bolo de rolo",
cidade: "Recife",
ingredientes: ["Farinha de trigo", "Manteiga", "Açúcar", "Ovos", "Goiabada"],
broll: "broll_massa.mp4",
};
export const RemotionRoot: React.FC = () => (
<>
<Composition
id="Receita16x9" // nome que a CLI e o Lambda usam
component={Receita}
width={1920}
height={1080}
fps={30}
durationInFrames={150}
defaultProps={padrao} // valores da prévia; --props sobrescreve no render
/>
<Composition
id="Receita9x16"
component={Receita}
width={1080}
height={1920}
fps={30}
durationInFrames={150}
defaultProps={padrao}
/>
</>
);Renderizar na sua máquina e na AWS com custo conhecido
O render local usa o Chrome sem interface e o FFmpeg do seu computador e não consome token de modelo nenhum. O @remotion/lambda faz o mesmo na sua conta AWS: não é uma API hospedada pelo Remotion. Os limites são o tempo de execução da função, que a documentação recomenda manter em 120 segundos ou menos e que a AWS corta aos 15 minutos; a concorrência padrão de 1.000 funções por região; até 10 GB de memória e de disco; e nenhum AV1. Para vídeo longo, a documentação prefere aumentar a concorrência e o disco em vez do timeout. Pela estimativa do curso, como o Remotion divide o render em partes paralelas, isso cobre vídeos de até cerca de 80 minutos em Full HD; a página de limites não publica teto de duração nem de tamanho de saída. O @remotion/cloudrun existe, mas está em Alpha e sem desenvolvimento ativo; não use em produção.
Um detalhe pega no primeiro render. No Windows, em Mac Intel e em Linux mais antigo, o Remotion 4.0 captura cada quadro como JPEG, e sem --color-space=bt709 o MP4 sai em faixa de cor cheia, que o ffprobe lê como yuvj420p; o verificador da Aula 04 reprova o pix_fmt. A flag grava a cor em BT.709 com faixa limitada, e o ffprobe passa a mostrar yuv420p. Use a flag nos dois lugares para as saídas baterem. As duas abas trazem o mesmo render nos dois lugares, com as mesmas props.
O mesmo render em dois lugares
Na sua máquina
Rode da raiz video-ia: o script entra em composicoes/cozinha-remotion/, onde o Remotion precisa rodar, e grava o MP4 em renders/. O --props sobrescreve as defaultProps da composição, e o ffprobe compara a saída com o padrão de entrega do curso.
#!/usr/bin/env bash
# scripts/aula05_render_local.sh: render na sua máquina e conferência com ffprobe.
# Uso: bash scripts/aula05_render_local.sh (na raiz video-ia)
set -euo pipefail
cd composicoes/cozinha-remotion # o Remotion roda de dentro do projeto; a raiz fica em ../..
PROPS='{"titulo":"Bolo de rolo","cidade":"Recife","ingredientes":["Farinha de trigo","Manteiga","Açúcar","Ovos","Goiabada"],"broll":"broll_massa.mp4"}'
# 1) Render local: Chrome sem interface + FFmpeg na sua máquina. Não consome token de modelo.
# src/index.ts ponto de entrada
# Receita9x16 id da <Composition>
# --codec=h264 MP4 que todo celular toca
# --color-space=bt709 BT.709 em faixa limitada; sem ele, na captura por JPEG (Windows, Mac Intel),
# o ffprobe lê yuvj420p (faixa cheia) e o verificar_entrega.py reprova
# --props sobrescreve as defaultProps (texto JSON ou caminho de um arquivo .json)
npx remotion render src/index.ts Receita9x16 ../../renders/receita_9x16.mp4 --codec=h264 --color-space=bt709 --props="$PROPS"
# A CLI também aceita --width, --height, --fps e --duration (em quadros) para sobrescrever a composição.
# 2) Conferir contra o padrão do curso (Aula 04)
ffprobe -v error -show_entries stream=codec_name,width,height,r_frame_rate,pix_fmt \
-show_entries format=duration -of default=nw=1 ../../renders/receita_9x16.mp4
# esperado: h264 / 1080 / 1920 / yuv420p / 30/1 / duration perto de 5.0No AWS Lambda
Configure antes as credenciais e as permissões da AWS pela página do Remotion Lambda. O functions deploy cria a função, o sites create sobe o projeto empacotado para o S3 e o render usa o nome do site.
#!/usr/bin/env bash
# scripts/aula05_render_lambda.sh: o mesmo render na SUA conta AWS, com as mesmas props.
# Uso: bash scripts/aula05_render_lambda.sh (na raiz video-ia)
set -euo pipefail
cd composicoes/cozinha-remotion
PROPS='{"titulo":"Bolo de rolo","cidade":"Recife","ingredientes":["Farinha de trigo","Manteiga","Açúcar","Ovos","Goiabada"],"broll":"broll_massa.mp4"}'
# 1) Lambda: roda na SUA conta AWS, com as credenciais e permissões configuradas
# conforme a página do Remotion Lambda. A documentação recomenda timeout de até 120 s;
# para vídeo longo, prefira mais concorrência e disco. O teto da AWS é 15 min (--timeout abaixo de 900).
npx remotion lambda functions deploy # cria a função na região
npx remotion lambda sites create src/index.ts --site-name=cozinha-da-rafa # sobe o bundle para o S3
npx remotion lambda render cozinha-da-rafa Receita9x16 ../../renders/receita_9x16_lambda.mp4 \
--codec=h264 --color-space=bt709 --props="$PROPS"
# Referência oficial (Remotion 4.0.381, 2048 MB, us-east-1): 1 min de vídeo custa
# US$ 0,017 a 0,021 só de Lambda; S3, saída de dados, CloudWatch e licença ficam fora.
# 2) As duas saídas devem ser iguais em dimensões, fps, codec e duração
for f in ../../renders/receita_9x16.mp4 ../../renders/receita_9x16_lambda.mp4; do
ffprobe -v error -show_entries stream=width,height,r_frame_rate -show_entries format=duration -of csv=p=0 "$f"
doneDa pasta vazia ao MP4 no Lambda em oito passos
Siga na ordem; o passo 7 é decisão, não comando.
Passo 1: Crie o projeto dentro de composicoes/ com npx create-video@latest --yes --blank
Deu certo quando: A pasta composicoes/cozinha-remotion/ tem src/Root.tsx, src/index.ts e um package.json com remotion e @remotion/cli.
Erro comum: Rodar sem @latest e cair num modelo antigo guardado no cache do npx.
Passo 2: Fixe todos os pacotes @remotion/* na versão vigente com --save-exact
Deu certo quando: O grep no package.json mostra o mesmo número em todas as linhas do Remotion (4.0.535 em 12/10/2026).
Erro comum: @remotion/captions em outra versão; o Studio abre, mas o render falha com erro de módulo.
Passo 3: Escreva Receita.tsx e Root.tsx com as props tipadas
Deu certo quando: npm run dev abre o Studio e lista Receita16x9 e Receita9x16.
Erro comum: Props declaradas com interface em vez de type; o TypeScript recusa o componente na Composition.
Passo 4: Altere titulo e ingredientes no painel de props do Studio
Deu certo quando: O texto muda na prévia sem recarregar a página.
Erro comum: B-roll fora de public/; o staticFile não encontra o arquivo e o fundo fica preto.
Passo 5: Renderize Receita9x16 na sua máquina com --color-space=bt709
Deu certo quando: O ffprobe mostra h264, 1080x1920, 30/1, yuv420p e duração de 5 segundos.
Erro comum: Forçar o MP4 de renders/ para o git; MP4 acima de 5 MB não vai para o git, e renders/ fica no .gitignore da raiz.
Passo 6: Passe renders/receita_9x16.mp4 pelo scripts/verificar_entrega.py da Aula 04
Deu certo quando: Codec de vídeo, pix_fmt, fps e dimensões aparecem como OK; o item de áudio reprova porque o cartão é mudo e a voz entra na montagem.
Erro comum: Render sem --color-space=bt709 no Windows ou em Mac Intel sai em faixa cheia, o ffprobe lê yuvj420p e o pix_fmt reprova.
Passo 7: Registre a licença que vale para o seu caso
Conte as pessoas da empresa e quem escreve código Remotion.
Deu certo quando: O projeto tem anotado “gratuito, até 3 pessoas” ou o plano Creators ou Automators.
Erro comum: Embutir o @remotion/player em produto de empresa com 4 pessoas ou mais e tratá-lo como gratuito.
Passo 8: Renderize no Lambda com as mesmas props
Deu certo quando: O MP4 do Lambda tem as mesmas dimensões, fps e duração do local.
Erro comum: Render longo que estoura o tempo da função e cai no meio; aumente a concorrência ou recrie a função com timeout maior, abaixo dos 15 minutos da AWS. Acima de cerca de 80 minutos em Full HD, pela estimativa do curso, renderize na sua máquina.
No fim você tem: A composição Receita9x16 renderizada na sua máquina e no Lambda com o mesmo resultado no ffprobe, e a licença registrada no projeto.
Atualizar a versão sem quebrar o projeto
A versão fixa protege o projeto, mas uma hora você atualiza. Faça isso de propósito, num ramo separado: rode npm view remotion version, troque o número em todos os pacotes de uma vez, renderize Receita9x16 de novo e passe o MP4 pelo verificador da Aula 04. Se o número sugerido for o da 4.0.531, pule: ela saiu quebrada em 30/09/2026 e foi republicada no dia seguinte como 4.0.532. Está pronto quando o MP4 da versão nova passa no verificador com o mesmo resultado da anterior.
Duas mudanças do período mexem no comportamento depois de atualizar. Desde a 4.0.530, de 29/09/2026, a duração em quadros é calculada antes da velocidade de reprodução: um <OffthreadVideo> ou <Sequence> com playbackRate pode mudar de tamanho na linha do tempo, então confira a duração no ffprobe. Desde a 4.0.535, de 12/10/2026, cada componente pré-monta por 2 segundos antes de aparecer, e o b-roll chega carregado ao primeiro quadro. A mesma versão trouxe renderFramesOnLambda(), que devolve só a sequência de quadros, útil para a revisão visual pelo Claude sem baixar o MP4.
Na licença, quando o Remotion 5.0 sair, contratados passam a contar no tamanho da equipe e clientes Automators não poderão desligar a telemetria. Se a sua conta de 3 pessoas depende de um freelancer fixo, refaça a soma antes de atualizar para a 5.0.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Algumas decisões aparecem logo no primeiro projeto. Se você é pessoa física ou a empresa tem até 3 pessoas, siga sem custo de licença; com 4 ou mais, anote no projeto se o caso é Creators ou Automators antes de automatizar qualquer render. Se o vídeo tem até cerca de 80 minutos em Full HD e você já tem conta AWS, o Lambda custa centavos por minuto renderizado; se não quer AWS, renderize localmente. Se o render local começa a pesar na memória num lote grande, divida o lote em renders menores, um depois do outro. A escolha entre Remotion e HyperFrames para cada peça tem critério próprio em montar vídeo em HTML com HyperFrames.
Para o site, o @remotion/player toca o mesmo componente no navegador, sem FFmpeg nem Chromium, e exige cinco campos: component, durationInFrames, compositionWidth, compositionHeight e fps. A legenda palavra a palavra usa o pacote @remotion/captions com tempos por palavra, e um SRT de frases não basta; o caminho completo está em editar por transcrição e reenquadrar.
Na Cozinha da Rafa trabalham duas pessoas, a Rafa e um editor, então a licença é gratuita. O projeto composicoes/cozinha-remotion/ gera o cartão de abertura dos três vídeos da semana: Receita16x9 para o bolo de rolo longo e Receita9x16 para os dois cortes. A cada semana mudam só as props, e os três cartões de 5 segundos saem em menos de um minuto na máquina dela. Pelo exemplo oficial, os mesmos cartões no Lambda custariam frações de centavo de computação. Cada cartão entra antes do vídeo com o concat da Aula 04. Os custos que não aparecem na fatura do modelo, como armazenamento e saída de dados, estão no curso de FinOps, em os custos que não são token.
Glossário rápido
Remotion
Biblioteca que descreve um vídeo como aplicação React: cada quadro é o componente desenhado num instante.
composição
Declaração de um vídeo (id, componente, largura, altura, fps e duração em quadros), como a ficha técnica de uma peça.
props
Valores que entram na composição (título, ingredientes, arquivo de b-roll), como os campos de um formulário que gera o mesmo documento com dados diferentes.
useCurrentFrame
Função do Remotion que devolve o número do quadro que está sendo desenhado; toda animação é calculada a partir dele.
interpolate e spring
Funções que convertem o número do quadro em valor de animação: interpolate faz a regra de três, spring faz o movimento de mola.
Studio do Remotion
Prévia no navegador com painel de props; mostra o vídeo sem gerar arquivo e não conta como render na licença.
Remotion Lambda
Pacote @remotion/lambda, que renderiza na sua própria conta AWS, dividindo o vídeo em partes renderizadas em paralelo; cada função roda no máximo 15 minutos.
render (na licença do Remotion)
Cada geração bem-sucedida de vídeo, áudio, GIF, still ou PDF; prévia no Studio ou no Player não conta.
Guia prático: a duração do cartão segue a narração com calculateMetadata
Na aula, a composição tem 150 quadros fixos. Quando a voz entra, a duração precisa acompanhar o áudio, ou o cartão corta a última palavra ou sobra imagem muda. O calculateMetadata() do Remotion resolve isso: uma função que roda antes do render, lê o que precisar (aqui, a duração da narração) e devolve quadros, props e nome do arquivo de saída. Você sai com o Root.tsx ajustado e com as novidades das versões 4.0.529 a 4.0.535.
Funções, casos de uso e aplicações
Funções
O que entrou no Remotion e muda o projeto cozinha-remotion
| Função ou recurso | O que faz | Quando usar | Desde |
|---|---|---|---|
| calculateMetadata() | Calcula durationInFrames, fps, width, height e props antes do render; pode ser assíncrona | Duração que depende de um arquivo, de uma API ou de uma prop | Remotion 4; isRendering desde a 4.0.342 |
| defaultOutName | Nome padrão do arquivo de saída, sem extensão | Lote em que cada receita gera um MP4 com nome próprio | 4.0.268 |
| Leitura de metadados com Mediabunny | Lê duração, dimensões e fps de uma mídia; substitui getAudioDurationInSeconds(), depreciada | Medir a narração copiada para public/ | Na documentação em 12/10/2026 |
| separateAudioTo em renderMediaOnLambda() | Grava o áudio num arquivo à parte no render do Lambda | Mandar a voz para a transcrição sem extrair do MP4 | 12/10/2026 (4.0.535) |
| Chromium 157 e memória compartilhada entre Chrome e FFmpeg | Atualiza o navegador do render e usa codificação paralela com mais frequência | Ao atualizar, renderize de novo e passe o verificador da aula 04 | 07/10/2026 (4.0.534) |
| Copy context for agents, no Studio | Copia o contexto das sequências selecionadas para colar no agente | Pedir ao Claude Code uma mudança numa cena específica | 05/10/2026 (4.0.533) |
| @remotion/motion-blur com HTML-in-canvas | Motion blur reescrito sobre HTML-in-canvas | Título que cruza a tela rápido | 25/09/2026 (4.0.529) |
Casos de uso
Produtora de conteúdo de uma escola de culinária online em São Paulo que gera um cartão de abertura para cada aula
Educação, cursos livres
Dor
Cada aula tinha uma narração de abertura com duração diferente, e o editor ajustava o durationInFrames à mão antes de cada render.
Solução
Ela pediu ao agente o calculateMetadata lendo a narração com Mediabunny e o defaultOutName com o nome da aula.
Resultado
Conferir no ffprobe de cada cartão se a duração acompanha a da narração mais o respiro e se o ajuste manual sai da rotina do editor.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Coordenador de marketing de uma construtora em Florianópolis que anuncia cada lançamento com um vídeo curto
Marketing digital, mercado imobiliário
Dor
Os vídeos renderizados no Lambda precisavam de legenda, e a equipe baixava cada MP4 só para extrair o áudio e mandar transcrever.
Solução
Ele passou a renderizar com separateAudioTo, que entrega o áudio num arquivo próprio, e a etapa de transcrição lê esse arquivo.
Resultado
Acompanhar se a transcrição deixa de depender do download do MP4 e quanto tempo sai do ciclo de cada lançamento.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Na prática
No projeto composicoes/cozinha-remotion/, instale o leitor de mídia com npm install mediabunny --save-exact, acrescente narracao?: string ao ReceitaProps e copie a voz para public/ com cp ../../audio/voz_abertura.mp3 public/, como você fez com o b-roll. No Receita.tsx, toque a voz com <Audio src={staticFile(narracao)} /> (importado de remotion) quando a prop existir. O trecho abaixo troca os 150 quadros fixos pela duração da narração mais 0,4 segundo de respiro, folga que cabe na tolerância de 0,5 s do verificar_entrega.py.
// src/Root.tsx (trecho): a duração do cartão passa a seguir a narração.
import React from "react";
import { Composition, staticFile, type CalculateMetadataFunction } from "remotion";
import { Input, ALL_FORMATS, UrlSource } from "mediabunny";
import { Receita, type ReceitaProps } from "./Receita";
const FPS = 30;
const RESPIRO_S = 0.4; // folga depois da última palavra; cabe nos 0,5 s do verificador da aula 04
// Roda antes do Studio e do render: lê a narração em public/ e devolve quadros e nome.
const pelaNarracao: CalculateMetadataFunction<ReceitaProps> = async ({ props }) => {
if (!props.narracao) return { durationInFrames: 150 }; // sem voz, os 5 s da aula
const url = new URL(staticFile(props.narracao), window.location.href).href;
const entrada = new Input({ formats: ALL_FORMATS, source: new UrlSource(url) });
const segundos = await entrada.computeDuration();
// "Bolo de rolo" vira receita-bolo-de-rolo: nome de arquivo sem acento nem espaço
const slug = props.titulo.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/\s+/g, "-");
return { durationInFrames: Math.ceil((segundos + RESPIRO_S) * FPS), defaultOutName: `receita-${slug}` };
};
export const RemotionRoot: React.FC = () => (
<Composition
id="Receita9x16" // repita o calculateMetadata na Receita16x9
component={Receita}
width={1080}
height={1920}
fps={FPS}
durationInFrames={150} // valor provisório: o calculateMetadata sobrescreve
defaultProps={{
titulo: "Bolo de rolo",
cidade: "Recife",
ingredientes: ["Farinha de trigo", "Manteiga", "Açúcar", "Ovos", "Goiabada"],
broll: "broll_massa.mp4",
narracao: "voz_abertura.mp3", // cópia de ../../audio/ em public/
}}
calculateMetadata={pelaNarracao}
/>
);Da duração fixa à duração pela voz
Cinco passos dentro de composicoes/cozinha-remotion/, com a raiz video-ia em ../..
Passo 1: Instale o Mediabunny com versão exata
Deu certo quando: O package.json mostra mediabunny sem ^, e o Remotion segue com o mesmo número em todos os pacotes.
Erro comum: Rodar npm update junto e mudar a versão do Remotion sem querer.
Passo 2: Copie a narração para public/
Deu certo quando: O Studio toca a voz no cartão.
Erro comum: Apontar para ../../audio direto: o staticFile só lê o que está em public/.
Passo 3: Troque a duração fixa pelo calculateMetadata
Deu certo quando: No Studio, a Receita9x16 passa a durar o tempo da voz mais 0,4 s.
Erro comum: Apagar o durationInFrames provisório: a Composition continua exigindo o campo.
Passo 4: Renderize e passe o verificador da aula 04
npx remotion render src/index.ts Receita9x16 ../../renders/receita_9x16.mp4 --codec=h264 --color-space=bt709, depois python ../../scripts/verificar_entrega.py ../../renders/receita_9x16.mp4 ../../audio/voz_abertura.mp3 9:16
Deu certo quando: Os seis critérios dão OK, inclusive a duração contra audio/voz_abertura.mp3.
Erro comum: Esquecer o --color-space=bt709 e reprovar no pix_fmt.
Passo 5: Atualize de propósito, num ramo separado
Deu certo quando: O verificador dá o mesmo resultado antes e depois da 4.0.535.
Erro comum: Atualizar no meio do lote: o Chromium 157 e a pré-montagem de 2 s mudam o render.
No fim você tem: O cartão de abertura com a duração da voz, nome de arquivo sem acento e aprovado pelo mesmo verificador da aula 04.
Armadilhas
Metadado calculado, render previsível
Tudo o que o calculateMetadata devolve precisa ser JSON puro e chegar dentro do tempo do delayRender.
- Devolva só quadros, props, fps, tamanho ou nome: nada de funções
- Props devolvidas mantêm o mesmo formato das props de entrada
- Use o abortSignal para cancelar busca de rede velha no Studio
- getAudioDurationInSeconds() está depreciada; leia com Mediabunny
- Leitura por URL exige o arquivo acessível, sem bloqueio de CORS
O teste: Troque a narração por outra mais longa: o cartão cresce sem você tocar no Root.tsx.
alexandrecaramaschi.com/educacao/frontends-com-vibecoding
Troque as props para a sua próxima receita, renderize as duas composições e passe as duas pelo verificador. Está pronto quando Receita9x16 sai igual na sua máquina e no Lambda no ffprobe, o verificador devolve OK em codec de vídeo, pix_fmt, fps e dimensões, e o projeto tem a licença registrada por escrito.
Seu caderno neste capítulo
Abrir o caderno completoSelecione um trecho do capítulo para destacar ou anotar. Nos vídeos e áudios, use Anotar este momento. No teclado, selecione com Shift e as setas e use Alt+Shift+D para destacar ou Alt+Shift+N para anotar.
Salvo neste navegador. Entre na sua conta para levar o caderno a outros aparelhos.
Entre na sua conta para compartilhar o que aprendeu e convidar alguém para estudar com você.
Conexões deste capítulo
Veja o que estudar antes e para onde seguir depois, explore os conceitos e compare abordagens em outros cursos. Sugestões marcadas como “sugerido pelo grafo” vêm dos assuntos em comum, não do índice do curso.
Estude antes
- CursoClaude Code CLI: Programação com IA
- Veja o que o Claude Code faz antes de instalarsugerido pelo grafoApresenta o conceito “Claude Code”, usado em “Montar vídeo em React com Remotion e renderizar na sua máquina ou na AWS”.
- CursoAstra profundosugerido pelo grafoA quinta parte do Astra planeja o vídeo e edita o material bruto com o modelo dirigindo a ferramenta. O curso de vídeo com IA aprofunda esse trabalho com Claude Code, Codex e ElevenLabs, do roteiro à publicação. O grafo já sugeria esta ordem pela regra de entrada da trilha; com a ordem anterior curada, ela passa a ser declarada (Etapa 4, wave 3).
- CursoSetup Completo: do zero ao Claude Codesugerido pelo grafo7 capítulos de “Vídeo com IA: Claude Code, Codex e ElevenLabs” usam conceitos apresentados em “Setup Completo: do zero ao Claude Code”.
Depois, siga para
- Saber quem opera seus agentes, quanto custa e como trocarsugerido pelo grafoApresenta o conceito “AWS”, usado em “Saber quem opera seus agentes, quanto custa e como trocar”.
- Projetar movimento, assinatura e narrativas por rolagemsugerido pelo grafoApresenta o conceito “React”, usado em “Projetar movimento, assinatura e narrativas por rolagem”.
- Escolher a stack e projetar suas dependênciassugerido pelo grafoApresenta o conceito “React”, usado em “Escolher a stack e projetar suas dependências”.
- Escolher o modelo de cada etapa e calcular o custo por tarefasugerido pelo grafoApresenta o conceito “AWS”, usado em “Escolher o modelo de cada etapa e calcular o custo por tarefa”.
O mesmo assunto em outros cursos
Voltar ao capítulo anterior: Cortar, juntar, mixar e exportar vídeo com FFmpeg sem abrir editor
Leve uma ideia para a prática
Escolha uma atividade no painel e volte a este curso quando quiser.
Atividades e evolução ficam reunidas no painel da sua conta.
Laboratórios ao vivo deste curso
Cada laboratório monta a biblioteca real dentro da aula, com controles para você mexer e o código do exemplo para copiar. O texto de reserva descreve a demonstração para quem lê sem JavaScript. O link abre o capítulo já no ponto do laboratório.
MediaRecorder, Canvas 2D e Long Animation Frames (plataforma)
Grave a cena em tempo real e veja os quadros que se perdem
Suba as partículas, force um bloqueio de 300 ms e grave seis segundos; compare com o render quadro a quadro desta aula.
Pacote
Abrir no capítuloMontar vídeo em HTML com HyperFrames e escolher entre ele e o Remotionsem pacoteMotion
Ver agentes em paralelo trocando mensagens numa linha do tempo
Reproduza a cena, percorra o tempo pelo controle e compare o tempo de parede com a soma das barras de cada agente.
Pacote
Abrir no capítuloParalelizar cenas com subagentes sem estourar o limite das APIsmotionReact (sem dependência extra), com as APIs do Veo e do fal.ai
Prompt de vídeo em cinco camadas, pronto para a API
Escolha plano, câmera, luz, ação e áudio e copie o prompt e o JSON para o Veo ou para o fal.ai.
Pacote
Abrir no capítuloEscrever prompt de vídeo em cinco camadas e manter o personagem consistentereactReact (sem dependência extra), com o comando para o FFmpeg
Corte o vídeo apagando palavras da transcrição
Aperte as palavras para removê-las, ligue a remoção de pausas e copie o comando FFmpeg e a legenda SRT gerados.
Pacote
Abrir no capítuloRemover pausas e reenquadrar o vídeo de 16:9 para 9:16 com legenda por palavrareactReact (sem dependência extra)
Quanto custa cada etapa do seu pipeline de vídeo
Troque a ferramenta de cada etapa e o percentual de b-roll e veja qual etapa pesa no custo por minuto e por vídeo.
Pacote
Abrir no capítuloOrquestrar o pipeline com etapas idempotentes e teto de gastoreact
Capítulos vizinhos em Vídeo com IA: Claude Code, Codex e ElevenLabs
- 03Montar a bancada de vídeo com IA mesmo sem nunca ter usado o terminal
- 04Cortar, juntar, mixar e exportar vídeo com FFmpeg sem abrir editor
- 05Montar vídeo em React com Remotion e renderizar na sua máquina ou na AWS
- 06Montar vídeo em HTML com HyperFrames e escolher entre ele e o Remotion
- 07Estruturar o projeto de vídeo para o Claude Code operar sem improvisar