Annuel Payez à l'année et profitez de 2 mois offerts sur chaque offre payante. Voir les offres
Se connecter Commencer gratuitement

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

  1. 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.

  2. Solde. Il appelle account_balance pour voir ce que le compte peut dépenser. Cet appel est gratuit.

  3. Images. Pour chaque scène, il appelle image_generate avec le prompt de la scène et size 1792x1024, et enregistre l’image sous public/scene-1.png, public/scene-2.png et 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 interroge job_status jusqu’à ce que l’image soit prête.

  4. Narration. Pour chaque scène, il appelle tts_generate avec le texte say de la scène et une voix, par exemple nova, et enregistre l’audio sous public/scene-1.mp3 et ainsi de suite.

  5. Minutage. Il règle les seconds de chaque scène sur la durée de sa narration plus environ une demi-seconde. tts_generate renvoie cette durée dans duration_seconds, mesurée à partir du fichier audio. Si la réponse indique aussi duration_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.mp3
    
  6. Musique (facultatif). Il appelle music_generate avec un prompt comme « calm instrumental background, soft piano », with_vocals réglé sur false et duration_seconds proche de la durée de la vidéo. L’outil renvoie un identifiant de tâche ; l’agent interroge job_status jusqu’à ce que la piste soit prête et l’enregistre sous public/music.mp3. Sans musique, supprimez la ligne music de video.json.

  7. Aperçu et rendu. npm run studio ouvre un aperçu dans votre navigateur. npm run render écrit out/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_generate et music_generate sont 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_balance et job_status sont 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.1 et 0.15, pour que la narration reste claire.
Bloqué ? Le forum répond généralement en quelques heures ; le support sous 24 heures. Demander au forum Contacter le support