Vuosittain Maksa vuosittain ja saat 2 kuukautta ilmaiseksi jokaiseen maksulliseen tilaukseen. Katso tilaukset
Kirjaudu sisään Aloita ilmaiseksi

Animoidut selitysvideot kertojanäänellä ToRun MCP:n ja Remotionin avulla

Viimeksi päivitetty 11 marrask. 2026

Mitä voit tehdä

Koodausagentti, joka ajaa komentoja tietokoneellasi, kuten Claude Code, opencode tai Cursor, voi tehdä ToRunilla lyhyen selitysvideon, jossa on kertojanääni. Agentti kirjoittaa käsikirjoituksen, pyytää ToRunilta kohtausten kuvat, kertojanäänen ja taustamusiikin ja renderöi videon tietokoneellasi Remotionilla, kirjastolla, joka muuttaa React-komponentit videoksi.

Mitä tarvitset

  • ToRunin MCP-palvelimeen yhdistetyn koodaustyökalun, joka voi ajaa komentoja ja kirjoittaa tiedostoja kansioon: opencode, Claude Code tai Cursor.
  • Node.js 18:n tai uudemman. Ensimmäinen renderöinti lataa selaimen, jolla Remotion renderöi.
  • Maksullisen tilauksen kiintiön tai lompakon saldon: API-kutsut eivät koskaan käytä ilmaista kiintiötä. Katso miten kutsut maksetaan.

Remotionilla on oma lisenssinsä: se on ilmainen yksityishenkilöille ja hyvin pienille yrityksille, ja suuremmat yritykset tarvitsevat yrityslisenssin. Tarkista remotion.dev/license ennen kuin käytät sitä työssä.

Aloitusprojekti

Neljä tiedostoa. Pyydä agenttia luomaan ne tyhjään kansioon tai kopioi ne itse ja aja sitten siellä npm install. Luodut tiedostot menevät package.json-tiedoston viereen kansioon 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 sisältää koko videon. Jokaisella kohtauksella on näytöllä näkyvä caption, kertojanäänen teksti say, kuvan prompt, sen kuvan ja kertojanäänen tiedostonimet sekä sen pituus kentässä 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 toistaa kohtaukset peräkkäin. Jokainen kuva lähenee hitaasti, teksti nousee alhaalta, kohtauksen kertojanääni alkaa samaan aikaan, ja musiikki soi hiljaa koko videon ajan:

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

Miten agentti tekee videon

  1. Käsikirjoitus. Agentti kirjoittaa kohtaukset tiedostoon video.json: yksi ajatus kohtausta kohden, muutaman sanan teksti, yksi tai kaksi lausetta sanottavaksi. Pyydä sitä näyttämään käsikirjoitus ennen kuin se luo mitään.

  2. Saldo. Se kutsuu account_balance-työkalua nähdäkseen, paljonko tili voi käyttää. Tämä kutsu on maksuton.

  3. Kuvat. Jokaiselle kohtaukselle se kutsuu image_generate-työkalua kohtauksen prompt-arvolla ja size-arvolla 1792x1024 ja tallentaa kuvan nimellä public/scene-1.png, public/scene-2.png ja niin edelleen. Jos kuva ei ole valmis odotusajan kuluessa, työkalu palauttaa työn tunnisteen, ja agentti kysyy job_status-työkalulta, kunnes kuva on valmis.

  4. Kertojanääni. Jokaiselle kohtaukselle se kutsuu tts_generate-työkalua kohtauksen say-tekstillä ja äänellä, esimerkiksi nova, ja tallentaa äänen nimellä public/scene-1.mp3 ja niin edelleen.

  5. Ajoitus. Se asettaa kunkin kohtauksen seconds-arvoksi sen kertojanäänen pituuden plus noin puoli sekuntia. tts_generate palauttaa tämän pituuden arvona duration_seconds, mitattuna äänitiedostosta. Jos vastauksessa lukee myös duration_estimated: true, pituus voitiin vain arvioida tekstistä, joten agentti mittaa tiedoston. Tarkistaaksesi tiedoston itse:

    npx remotion ffprobe -v error -show_entries format=duration -of csv=p=0 public/scene-1.mp3
    
  6. Musiikki (valinnainen). Se kutsuu music_generate-työkalua kehotteella, kuten ”calm instrumental background, soft piano”, with_vocals-arvolla false ja videon pituutta lähellä olevalla duration_seconds-arvolla. Työkalu palauttaa työn tunnisteen; agentti kysyy job_status-työkalulta, kunnes kappale on valmis, ja tallentaa sen nimellä public/music.mp3. Jos et halua musiikkia, poista music-rivi tiedostosta video.json.

  7. Esikatselu ja renderöinti. npm run studio avaa esikatselun selaimeesi. npm run render kirjoittaa tiedoston out/explainer.mp4.

Jokainen työkalun palauttama tiedostolinkki latautuu ilman kirjautumista. Säilytä koko linkki, myös kysymysmerkin jälkeinen osa:

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

Pyydä agenttiasi

Tee 30 sekunnin selitysvideo siitä, miten sovelluksemme synkronointi toimii, Remotionin aloitusprojektilla osoitteesta torun.ai/docs/mcp-motion-explainers. Neljä kohtausta. Näytä ensin käsikirjoitus tiedostossa video.json. Luo sitten jokaiselle kohtaukselle yksi kuva ilman tekstiä, lisää jokaiseen kohtaukseen kertojanääni äänellä nova, lisää hiljainen instrumentaalimusiikki, sovita kunkin kohtauksen pituus sen kertojanääneen ja renderöi.

Pystyvideota varten pyydä video.json-tiedostoon width 1080 ja height 1920 sekä kuvia size-arvolla 1024x1792.

Mitä se maksaa

  • image_generate, tts_generate ja music_generate ovat maksullisia kutsuja, jotka veloitetaan Runs-yksiköinä samoilla hinnoilla kuin sovelluksessa. Neljän kohtauksen video musiikilla tarkoittaa neljää kuvaa, neljää kertojanääntä ja yhtä kappaletta.
  • account_balance ja job_status ovat maksuttomia.
  • Renderöinti tapahtuu tietokoneellasi. Tekstien, ajoituksen tai liikkeen muuttaminen ja uudelleenrenderöinti ei maksa ToRunissa mitään; kuvan tai kertojanäänen luominen uudelleen on uusi maksullinen kutsu.
  • Kun yksittäinen luonti maksaisi enemmän kuin avaimen kynnys, työkalu vastaa ensin hinnalla, ja agenttisi kysyy sinulta ennen kuin se suorittaa kutsun.
  • Kaikki, mitä agentti luo, tallentuu myös ToRun-kirjastoosi.

Vinkkejä

  • Pyydä kuvia ilman tekstiä. Sanat kulkevat tekstityksessä, ja kuvamallit kirjoittavat tekstin usein väärin.
  • Rajaa jokainen kohtaus yhteen ajatukseen ja yhteen tai kahteen lauseeseen kertojanääntä.
  • Valitse yksi ääni ja pidä se koko videon ajan.
  • Pidä musiikin äänenvoimakkuus välillä 0.1–0.15, jotta kertojanääni pysyy selkeänä.
Jumissa? Foorumilla vastataan yleensä muutamassa tunnissa, tuessa 24 tunnin sisällä. Kysy foorumilla Ota yhteyttä tukeen