Vídeos explicativos animados y narrados con ToRun MCP y Remotion
Última actualización: 11 nov 2026
Lo que puedes crear
Un agente de programación que ejecuta comandos en tu ordenador, como Claude Code, opencode o Cursor, puede crear con ToRun un vídeo explicativo corto y narrado. El agente escribe el guion, pide a ToRun las imágenes de las escenas, la narración y la música de fondo, y renderiza el vídeo en tu ordenador con Remotion, una biblioteca que convierte componentes de React en vídeo.
Lo que necesitas
- Una herramienta de programación conectada al servidor MCP de ToRun que pueda ejecutar comandos y escribir archivos en una carpeta: opencode, Claude Code o Cursor.
- Node.js 18 o posterior. El primer renderizado descarga el navegador con el que renderiza Remotion.
- La asignación de un plan de pago o saldo en el monedero: las llamadas a la API nunca usan la asignación gratuita. Consulta cómo se pagan las llamadas.
Remotion tiene su propia licencia: es gratuita para particulares y empresas muy pequeñas, y las empresas más grandes necesitan una licencia de empresa. Consulta remotion.dev/license antes de usarlo para trabajar.
El proyecto inicial
Cuatro archivos. Pide a tu agente que los cree en una carpeta vacía, o cópialos tú mismo, y después ejecuta npm install en ella. Los archivos generados van en una carpeta public junto a 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 contiene todo el vídeo. Cada escena tiene un caption que se muestra en pantalla, el texto de narración say, el prompt de la imagen, los nombres de archivo de su imagen y su narración, y su duración en 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 reproduce las escenas una tras otra. Cada imagen se acerca lentamente, el subtítulo aparece subiendo, la narración de la escena empieza con él y la música suena bajita durante todo el 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)}
/>
);
Cómo crea el agente el vídeo
Guion. El agente escribe las escenas en
video.json: una idea por escena, un subtítulo de pocas palabras y una o dos frases para decir. Pídele que te enseñe el guion antes de generar nada.Saldo. Llama a
account_balancepara ver lo que puede gastar la cuenta. Esta llamada es gratuita.Imágenes. Para cada escena llama a
image_generatecon elpromptde la escena ysize1792x1024, y guarda la imagen comopublic/scene-1.png,public/scene-2.png, etc. Si una imagen no está lista dentro del tiempo de espera, la herramienta devuelve un id de trabajo, y el agente consultajob_statushasta que la imagen esté lista.Narración. Para cada escena llama a
tts_generatecon el textosayde la escena y una voz, por ejemplonova, y guarda el audio comopublic/scene-1.mp3, etc.Tiempos. Ajusta los
secondsde cada escena a la duración de su narración más medio segundo aproximadamente.tts_generatedevuelve esa duración comoduration_seconds, medida a partir del archivo de audio. Si la respuesta también diceduration_estimated: true, la duración solo pudo estimarse a partir del texto, así que el agente mide el archivo. Para comprobar un archivo tú mismo:npx remotion ffprobe -v error -show_entries format=duration -of csv=p=0 public/scene-1.mp3Música (opcional). Llama a
music_generatecon un prompt como «calm instrumental background, soft piano»,with_vocalsenfalseyduration_secondscerca de la duración del vídeo. La herramienta devuelve un id de trabajo; el agente consultajob_statushasta que la pista está lista y la guarda comopublic/music.mp3. Sin música, quita la líneamusicdevideo.json.Vista previa y renderizado.
npm run studioabre una vista previa en tu navegador.npm run renderescribeout/explainer.mp4.
Todos los enlaces a archivos que devuelve una herramienta se descargan sin iniciar sesión. Conserva el enlace completo, incluida la parte que va después del signo de interrogación:
curl -L -o public/scene-1.png "<the image link>"
Pídeselo a tu agente
Crea un vídeo explicativo de 30 segundos sobre cómo funciona la sincronización de nuestra app, con el proyecto inicial de Remotion de torun.ai/docs/mcp-motion-explainers. Cuatro escenas. Enséñame primero el guion en video.json. Después genera una imagen por escena sin texto, narra cada escena con la voz nova, añade música instrumental suave, ajusta el tiempo de cada escena a su narración y renderiza.
Para un vídeo vertical, pide width 1080 y height 1920 en video.json, e imágenes con size 1024x1792.
Cuánto cuesta
image_generate,tts_generateymusic_generateson llamadas de pago y se cobran en Runs a los mismos precios que en la app. Un vídeo con cuatro escenas y música son cuatro imágenes, cuatro narraciones y una pista.account_balanceyjob_statusson gratuitas.- El renderizado se hace en tu ordenador. Cambiar los subtítulos, los tiempos o el movimiento y volver a renderizar no cuesta nada en ToRun; volver a generar una imagen o una narración es una nueva llamada de pago.
- Cuando una sola generación costaría más que el umbral de la clave, la herramienta responde primero con el precio, y tu agente te pregunta antes de ejecutar la llamada.
- Todo lo que genera el agente también se guarda en tu biblioteca de ToRun.
Consejos
- Pide imágenes sin texto. El subtítulo lleva las palabras, y los modelos de imagen suelen escribir mal el texto.
- Limita cada escena a una idea y a una o dos frases de narración.
- Elige una voz y mantenla durante todo el vídeo.
- Mantén el volumen de la música entre
0.1y0.15, para que la narración se oiga con claridad.