Год Платите за год — и получите 2 месяца бесплатно на любом платном тарифе. Смотреть тарифы
Войти Начать бесплатно

Анимированные ролики-объяснения с озвучкой с помощью ToRun MCP и Remotion

Последнее обновление: 11 нояб. 2026

Что можно сделать

Агент для программирования, который выполняет команды на вашем компьютере, например Claude Code, opencode или Cursor, может сделать с ToRun короткий объясняющий ролик с закадровым голосом. Агент пишет сценарий, запрашивает у ToRun изображения для сцен, озвучку и фоновую музыку и рендерит видео на вашем компьютере с помощью Remotion — библиотеки, которая превращает компоненты React в видео.

Что понадобится

  • Инструмент для программирования, подключённый к MCP-серверу ToRun, который умеет выполнять команды и записывать файлы в папку: opencode, Claude Code или Cursor.
  • Node.js 18 или новее. При первом рендере загружается браузер, с помощью которого рендерит Remotion.
  • Лимит платного тарифа или баланс кошелька: вызовы API никогда не используют бесплатный лимит. См. как оплачиваются вызовы.

У Remotion своя лицензия: он бесплатен для частных лиц и очень маленьких компаний, а более крупным компаниям нужна корпоративная лицензия. Прежде чем использовать его в работе, ознакомьтесь с remotion.dev/license.

Стартовый проект

Четыре файла. Попросите агента создать их в пустой папке или скопируйте их сами, а затем выполните там npm install. Сгенерированные файлы складываются в папку public рядом с 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 описывает всё видео. У каждой сцены есть caption, показываемый на экране, текст озвучки say, prompt изображения, имена файлов её изображения и озвучки и её длительность в 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 воспроизводит сцены одну за другой. Каждое изображение медленно приближается, подпись выплывает снизу, озвучка сцены начинается вместе с ней, а музыка тихо звучит на протяжении всего видео:

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)}
  />
);

Как агент делает видео

  1. Сценарий. Агент записывает сцены в video.json: одна идея на сцену, подпись из нескольких слов, одно-два предложения для озвучки. Попросите его показать сценарий, прежде чем что-либо генерировать.

  2. Баланс. Он вызывает account_balance, чтобы узнать, сколько может потратить аккаунт. Этот вызов бесплатный.

  3. Изображения. Для каждой сцены он вызывает image_generate с prompt сцены и size 1792x1024 и сохраняет изображение как public/scene-1.png, public/scene-2.png и так далее. Если изображение не готово за время ожидания, инструмент возвращает id задания, и агент опрашивает job_status, пока изображение не будет готово.

  4. Озвучка. Для каждой сцены он вызывает tts_generate с текстом say сцены и голосом, например nova, и сохраняет аудио как public/scene-1.mp3 и так далее.

  5. Тайминг. Он задаёт seconds каждой сцены равным длительности её озвучки плюс примерно полсекунды. tts_generate возвращает эту длительность в duration_seconds, измеренную по аудиофайлу. Если в ответе также указано duration_estimated: true, длительность удалось лишь оценить по тексту, поэтому агент измеряет файл. Чтобы проверить файл самостоятельно:

    npx remotion ffprobe -v error -show_entries format=duration -of csv=p=0 public/scene-1.mp3
    
  6. Музыка (необязательно). Он вызывает music_generate с промптом вроде «calm instrumental background, soft piano», with_vocals со значением false и duration_seconds, близким к длительности видео. Инструмент возвращает id задания; агент опрашивает job_status, пока трек не будет готов, и сохраняет его как public/music.mp3. Если музыка не нужна, удалите строку music из video.json.

  7. Просмотр и рендер. npm run studio открывает предпросмотр в браузере. npm run render записывает out/explainer.mp4.

Каждая ссылка на файл, которую возвращает инструмент, скачивается без входа в аккаунт. Сохраняйте ссылку целиком, включая часть после вопросительного знака:

curl -L -o public/scene-1.png "<the image link>"

Попросите агента

Сделай 30-секундный объясняющий ролик о том, как работает синхронизация в нашем приложении, на основе стартового проекта Remotion с torun.ai/docs/mcp-motion-explainers. Четыре сцены. Сначала покажи мне сценарий в video.json. Затем сгенерируй по одному изображению на сцену без текста, озвучь каждую сцену голосом nova, добавь тихую инструментальную музыку, подгони длительность каждой сцены под её озвучку и отрендери.

Для вертикального видео укажите в video.json width 1080 и height 1920 и попросите изображения с size 1024x1792.

Сколько это стоит

  • image_generate, tts_generate и music_generate — платные вызовы, они списываются в Runs по тем же ценам, что и в приложении. Видео из четырёх сцен с музыкой — это четыре изображения, четыре озвучки и один трек.
  • account_balance и job_status бесплатны.
  • Рендер выполняется на вашем компьютере. Изменить подписи, тайминг или анимацию и отрендерить заново в ToRun ничего не стоит; повторная генерация изображения или озвучки — это новый платный вызов.
  • Если одна генерация стоила бы дороже порога ключа, инструмент сначала отвечает ценой, и агент спрашивает вас, прежде чем выполнить вызов.
  • Всё, что генерирует агент, также сохраняется в вашей библиотеке ToRun.

Советы

  • Просите изображения без текста. Слова несёт подпись, а модели изображений часто пишут текст с ошибками.
  • Ограничивайте каждую сцену одной идеей и одним-двумя предложениями озвучки.
  • Выберите один голос и используйте его во всём видео.
  • Держите громкость музыки между 0.1 и 0.15, чтобы озвучка оставалась разборчивой.
Застряли? На форуме обычно отвечают за несколько часов, поддержка — в течение 24 часов. Спросить на форуме Связаться с поддержкой