Vidéos explicatives animées et narrées avec ToRun MCP et Remotion
Dernière mise à jour : 11 nov. 2026
Ce que vous pouvez créer
Un agent de code qui exécute des commandes sur votre ordinateur, comme Claude Code, opencode ou Cursor, peut créer avec ToRun une courte vidéo explicative narrée. L’agent écrit le script, demande à ToRun les images des scènes, la narration et la musique de fond, puis effectue le rendu de la vidéo sur votre ordinateur avec Remotion, une bibliothèque qui transforme des composants React en vidéo.
Ce dont vous avez besoin
- Un outil de code connecté au serveur MCP de ToRun, capable d’exécuter des commandes et d’écrire des fichiers dans un dossier : opencode, Claude Code ou Cursor.
- Node.js 18 ou une version ultérieure. Le premier rendu télécharge le navigateur avec lequel Remotion effectue le rendu.
- L’allocation d’un forfait payant ou un solde de portefeuille : les appels API n’utilisent jamais l’allocation gratuite. Voir comment les appels sont payés.
Remotion a sa propre licence : elle est gratuite pour les particuliers et les très petites entreprises, et les entreprises plus grandes ont besoin d’une licence entreprise. Consultez remotion.dev/license avant de l’utiliser dans un cadre professionnel.
Le projet de départ
Quatre fichiers. Demandez à votre agent de les créer dans un dossier vide, ou copiez-les vous-même, puis exécutez npm install dans ce dossier. Les fichiers générés vont dans un dossier public à côté 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 contient toute la vidéo. Chaque scène a une caption affichée à l’écran, le texte de narration say, le prompt de l’image, les noms de fichier de son image et de sa narration, et sa durée 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 joue les scènes l’une après l’autre. Chaque image zoome lentement, la légende apparaît en montant, la narration de la scène démarre avec elle, et la musique joue doucement sous toute la vidéo :
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)}
/>
);
Comment l’agent crée la vidéo
Script. L’agent écrit les scènes dans
video.json: une idée par scène, une légende de quelques mots, une ou deux phrases à dire. Demandez-lui de vous montrer le script avant de générer quoi que ce soit.Solde. Il appelle
account_balancepour voir ce que le compte peut dépenser. Cet appel est gratuit.Images. Pour chaque scène, il appelle
image_generateavec lepromptde la scène etsize1792x1024, et enregistre l’image souspublic/scene-1.png,public/scene-2.pnget ainsi de suite. Si une image n’est pas prête dans le délai d’attente, l’outil renvoie un identifiant de tâche, et l’agent interrogejob_statusjusqu’à ce que l’image soit prête.Narration. Pour chaque scène, il appelle
tts_generateavec le textesayde la scène et une voix, par exemplenova, et enregistre l’audio souspublic/scene-1.mp3et ainsi de suite.Minutage. Il règle les
secondsde chaque scène sur la durée de sa narration plus environ une demi-seconde.tts_generaterenvoie cette durée dansduration_seconds, mesurée à partir du fichier audio. Si la réponse indique aussiduration_estimated: true, la durée n’a pu être qu’estimée à partir du texte, et l’agent mesure donc le fichier. Pour vérifier un fichier vous-même :npx remotion ffprobe -v error -show_entries format=duration -of csv=p=0 public/scene-1.mp3Musique (facultatif). Il appelle
music_generateavec un prompt comme « calm instrumental background, soft piano »,with_vocalsréglé surfalseetduration_secondsproche de la durée de la vidéo. L’outil renvoie un identifiant de tâche ; l’agent interrogejob_statusjusqu’à ce que la piste soit prête et l’enregistre souspublic/music.mp3. Sans musique, supprimez la lignemusicdevideo.json.Aperçu et rendu.
npm run studioouvre un aperçu dans votre navigateur.npm run renderécritout/explainer.mp4.
Chaque lien de fichier renvoyé par un outil se télécharge sans connexion. Conservez le lien entier, y compris la partie après le point d’interrogation :
curl -L -o public/scene-1.png "<the image link>"
Demandez à votre agent
Crée une vidéo explicative de 30 secondes sur le fonctionnement de la synchronisation de notre application, avec le projet de départ Remotion de torun.ai/docs/mcp-motion-explainers. Quatre scènes. Montre-moi d’abord le script dans video.json. Génère ensuite une image par scène sans texte, narre chaque scène avec la voix nova, ajoute une musique instrumentale douce, cale chaque scène sur sa narration et fais le rendu.
Pour une vidéo verticale, demandez width 1080 et height 1920 dans video.json, et des images avec size 1024x1792.
Ce que cela coûte
image_generate,tts_generateetmusic_generatesont des appels payants, facturés en Runs aux mêmes prix que dans l’application. Une vidéo de quatre scènes avec musique correspond à quatre images, quatre narrations et une piste.account_balanceetjob_statussont gratuits.- Le rendu s’effectue sur votre ordinateur. Modifier les légendes, le minutage ou l’animation et refaire le rendu ne coûte rien sur ToRun ; générer à nouveau une image ou une narration est un nouvel appel payant.
- Quand une seule génération coûterait plus que le seuil de la clé, l’outil répond d’abord avec le prix, et votre agent vous demande votre accord avant de lancer l’appel.
- Tout ce que l’agent génère est aussi enregistré dans votre bibliothèque ToRun.
Conseils
- Demandez des images sans texte. La légende porte les mots, et les modèles d’image écrivent souvent le texte avec des fautes.
- Limitez chaque scène à une idée et à une ou deux phrases de narration.
- Choisissez une voix et gardez-la pour toute la vidéo.
- Gardez le volume de la musique entre
0.1et0.15, pour que la narration reste claire.