Yearly Pay yearly and get 2 months free on every paid plan. See plans
登入 免費開始

用 ToRun MCP 和 Remotion 製作附旁白的動態解說影片

最後更新於 11 11月 2026

你可以做什麼

能在你的電腦上執行指令的程式開發代理,例如 Claude Code、opencode 或 Cursor,可以透過 ToRun 製作一段附旁白的簡短解說影片。代理會撰寫腳本,向 ToRun 要求場景圖片、旁白和背景音樂,然後用 Remotion 在你的電腦上渲染影片。Remotion 是一個把 React 元件變成影片的函式庫。

你需要什麼

  • 一個已連接 ToRun MCP 伺服器、能執行指令並在資料夾中寫入檔案的程式開發工具:opencode、Claude Code 或 Cursor。
  • Node.js 18 或更新版本。第一次渲染時會下載 Remotion 用來渲染的瀏覽器。
  • 付費方案的額度或錢包餘額:API 呼叫從不使用免費額度。請參閱呼叫如何付費。

Remotion 有自己的授權:對個人和非常小的公司免費,規模更大的公司需要公司授權。在工作中使用之前,請查看 remotion.dev/license。

入門專案

四個檔案。請你的代理在一個空資料夾中建立它們,或自己複製,然後在那裡執行 npm install。產生的檔案會放在 package.json 旁邊的 public 資料夾中。

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. 圖片。 對於每個場景,它以該場景的 prompt 和 size 1792x1024 呼叫 image_generate,並將圖片儲存為 public/scene-1.png、public/scene-2.png 等。如果圖片在等待時間內沒有完成,工具會回傳一個工作 ID,代理會持續查詢 job_status,直到圖片完成。

  4. 旁白。 對於每個場景,它以該場景的 say 文字和一個聲音(例如 nova)呼叫 tts_generate,並將音訊儲存為 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. 音樂(選用)。它以類似「calm instrumental background, soft piano」的提示詞、設為 false 的 with_vocals,以及接近影片長度的 duration_seconds 呼叫 music_generate。工具會回傳一個工作 ID;代理會查詢 job_status 直到音軌完成,並將它儲存為 public/music.mp3。如果不需要音樂,請從 video.json 中刪除 music 這一行。

  7. 預覽與渲染。 npm run studio 會在你的瀏覽器中開啟預覽。npm run render 會寫出 out/explainer.mp4。

工具回傳的每個檔案連結都不必登入即可下載。請保留完整連結,包括問號後面的部分:

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

請你的代理來做

使用 torun.ai/docs/mcp-motion-explainers 上的 Remotion 入門專案,製作一段 30 秒的解說影片,說明我們應用程式的同步如何運作。四個場景。先在 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 小時內回覆。 在論壇提問 聯絡支援