Vídeos explicativos animados e narrados com o ToRun MCP e o Remotion
Última atualização: 11 nov. 2026
O que você pode criar
Um agente de programação que executa comandos no seu computador, como o Claude Code, o opencode ou o Cursor, pode criar com o ToRun um vídeo explicativo curto e narrado. O agente escreve o roteiro, pede ao ToRun as imagens das cenas, a narração e a música de fundo, e renderiza o vídeo no seu computador com o Remotion, uma biblioteca que transforma componentes React em vídeo.
Do que você precisa
- Uma ferramenta de programação conectada ao servidor MCP do ToRun que consiga executar comandos e gravar arquivos em uma pasta: opencode, Claude Code ou Cursor.
- Node.js 18 ou mais recente. A primeira renderização baixa o navegador que o Remotion usa para renderizar.
- A cota de um plano pago ou saldo na carteira: chamadas de API nunca usam a cota gratuita. Veja como as chamadas são pagas.
O Remotion tem a própria licença: é gratuito para pessoas físicas e empresas muito pequenas, e empresas maiores precisam de uma licença empresarial. Consulte remotion.dev/license antes de usá-lo no trabalho.
O projeto inicial
Quatro arquivos. Peça ao seu agente para criá-los em uma pasta vazia, ou copie-os você mesmo, e depois execute npm install nessa pasta. Os arquivos gerados vão para uma pasta public ao lado de package.json.
package.json:
{
"name": "motion-explainer",
"private": true,
"scripts": {
"studio": "remotion studio src/index.ts",
"render": "remotion render src/index.ts Explainer out/explainer.mp4"
},
"dependencies": {
"@remotion/cli": "4.0.539",
"react": "18.3.1",
"react-dom": "18.3.1",
"remotion": "4.0.539"
}
}
video.json guarda o vídeo inteiro. Cada cena tem uma caption mostrada na tela, o texto de narração say, o prompt da imagem, os nomes dos arquivos da imagem e da narração, e a duração em seconds:
{
"width": 1920,
"height": 1080,
"fps": 30,
"music": { "file": "music.mp3", "volume": 0.12 },
"scenes": [
{
"caption": "Every team has a backlog.",
"say": "Every team has a backlog, and it only grows.",
"prompt": "flat illustration of a wall covered in sticky notes, soft morning light, no text",
"image": "scene-1.png",
"narration": "scene-1.mp3",
"seconds": 5.5
},
{
"caption": "Sort it by what users feel.",
"say": "Sort it by what your users feel, not by what is loudest.",
"prompt": "flat illustration of hands arranging cards into three columns on a desk, no text",
"image": "scene-2.png",
"narration": "scene-2.mp3",
"seconds": 6
},
{
"caption": "Ship the top one this week.",
"say": "Then ship the top one this week.",
"prompt": "flat illustration of a small paper boat leaving a harbour at sunrise, no text",
"image": "scene-3.png",
"narration": "scene-3.mp3",
"seconds": 5
}
]
}
src/index.ts:
import {registerRoot} from 'remotion';
import {Root} from './Root';
registerRoot(Root);
src/Root.tsx reproduz as cenas uma depois da outra. Cada imagem se aproxima devagar, a legenda surge subindo, a narração da cena começa junto e a música toca baixinho durante todo o vídeo:
import React from 'react';
import {AbsoluteFill, Composition, Html5Audio, Img, interpolate, Series, staticFile, useCurrentFrame} from 'remotion';
import data from '../video.json';
// "say" and "prompt" are the script: the narration text and the image prompt. Rendering reads the rest.
type Scene = {image: string; narration?: string; seconds: number; caption?: string; say?: string; prompt?: string};
type Video = {width: number; height: number; fps: number; music?: {file: string; volume: number}; scenes: Scene[]};
const video = data as Video;
const clamp = {extrapolateLeft: 'clamp', extrapolateRight: 'clamp'} as const;
const framesOf = (scene: Scene) => Math.round(scene.seconds * video.fps);
// One scene: the image slowly zooms in, the caption rises in, the narration plays from the scene's start.
const SceneView: React.FC<{scene: Scene; frames: number}> = ({scene, frames}) => {
const frame = useCurrentFrame();
const fade = interpolate(frame, [0, 10, frames - 10, frames], [0, 1, 1, 0], clamp);
const zoom = interpolate(frame, [0, frames], [1, 1.08]);
const rise = interpolate(frame, [8, 26], [40, 0], clamp);
return (
<AbsoluteFill style={{backgroundColor: 'black', opacity: fade}}>
<Img src={staticFile(scene.image)} style={{width: '100%', height: '100%', objectFit: 'cover', transform: `scale(${zoom})`}} />
{scene.caption ? (
<div
style={{
position: 'absolute', left: '6%', right: '6%', bottom: '8%', transform: `translateY(${rise}px)`,
color: 'white', fontFamily: 'Arial, sans-serif', fontSize: video.height / 18, fontWeight: 700,
textShadow: '0 2px 16px rgba(0,0,0,0.7)',
}}
>
{scene.caption}
</div>
) : null}
{scene.narration ? <Html5Audio src={staticFile(scene.narration)} /> : null}
</AbsoluteFill>
);
};
const Explainer: React.FC = () => (
<AbsoluteFill style={{backgroundColor: 'black'}}>
<Series>
{video.scenes.map((scene, i) => (
<Series.Sequence key={i} durationInFrames={framesOf(scene)}>
<SceneView scene={scene} frames={framesOf(scene)} />
</Series.Sequence>
))}
</Series>
{video.music ? <Html5Audio src={staticFile(video.music.file)} volume={video.music.volume} loop /> : null}
</AbsoluteFill>
);
export const Root: React.FC = () => (
<Composition
id="Explainer"
component={Explainer}
width={video.width}
height={video.height}
fps={video.fps}
durationInFrames={video.scenes.reduce((sum, scene) => sum + framesOf(scene), 0)}
/>
);
Como o agente cria o vídeo
Roteiro. O agente escreve as cenas em
video.json: uma ideia por cena, uma legenda de poucas palavras, uma ou duas frases para falar. Peça para ele mostrar o roteiro antes de gerar qualquer coisa.Saldo. Ele chama
account_balancepara ver quanto a conta pode gastar. Esta chamada é gratuita.Imagens. Para cada cena, ele chama
image_generatecom opromptda cena esize1792x1024, e salva a imagem comopublic/scene-1.png,public/scene-2.pnge assim por diante. Se uma imagem não ficar pronta dentro do tempo de espera, a ferramenta retorna um id de tarefa, e o agente consultajob_statusaté a imagem ficar pronta.Narração. Para cada cena, ele chama
tts_generatecom o textosayda cena e uma voz, por exemplonova, e salva o áudio comopublic/scene-1.mp3e assim por diante.Tempo. Ele define os
secondsde cada cena como a duração da narração mais cerca de meio segundo.tts_generateretorna essa duração comoduration_seconds, medida a partir do arquivo de áudio. Se a resposta também disserduration_estimated: true, a duração só pôde ser estimada pelo texto, então o agente mede o arquivo. Para conferir um arquivo você mesmo:npx remotion ffprobe -v error -show_entries format=duration -of csv=p=0 public/scene-1.mp3Música (opcional). Ele chama
music_generatecom um prompt como "calm instrumental background, soft piano",with_vocalsdefinido comofalseeduration_secondspróximo da duração do vídeo. A ferramenta retorna um id de tarefa; o agente consultajob_statusaté a faixa ficar pronta e a salva comopublic/music.mp3. Sem música, remova a linhamusicdevideo.json.Prévia e renderização.
npm run studioabre uma prévia no seu navegador.npm run rendergravaout/explainer.mp4.
Todo link de arquivo que uma ferramenta retorna pode ser baixado sem login. Mantenha o link inteiro, incluindo a parte depois do ponto de interrogação:
curl -L -o public/scene-1.png "<the image link>"
Peça ao seu agente
Crie um vídeo explicativo de 30 segundos sobre como funciona a sincronização do nosso app, com o projeto inicial do Remotion de torun.ai/docs/mcp-motion-explainers. Quatro cenas. Me mostre primeiro o roteiro em video.json. Depois gere uma imagem por cena sem texto, narre cada cena com a voz nova, adicione uma música instrumental suave, ajuste o tempo de cada cena à narração e renderize.
Para um vídeo vertical, peça width 1080 e height 1920 em video.json, e imagens com size 1024x1792.
Quanto custa
image_generate,tts_generateemusic_generatesão chamadas pagas, cobradas em Runs pelos mesmos preços do app. Um vídeo com quatro cenas e música são quatro imagens, quatro narrações e uma faixa.account_balanceejob_statussão gratuitas.- A renderização acontece no seu computador. Mudar as legendas, o tempo ou o movimento e renderizar de novo não custa nada no ToRun; gerar de novo uma imagem ou uma narração é uma nova chamada paga.
- Quando uma única geração custaria mais do que o limite de confirmação da chave, a ferramenta responde primeiro com o preço, e seu agente pergunta a você antes de executar a chamada.
- Tudo o que o agente gera também é salvo na sua biblioteca do ToRun.
Dicas
- Peça imagens sem texto. A legenda leva as palavras, e modelos de imagem costumam escrever texto errado.
- Limite cada cena a uma ideia e a uma ou duas frases de narração.
- Escolha uma voz e mantenha a mesma em todo o vídeo.
- Mantenha o volume da música entre
0.1e0.15, para que a narração fique clara.