11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

動画編集ソフト使わずに動画制作する。Remotionで動画を"書く"という選択肢の話

11
Posted at

動画を作りたいけど、編集が億劫な人へ

自分はずっと、動画制作にコンプレックスがありました。

AI教育の発信をやってて、テキストの記事やXのポストは書ける。コードも書ける。でも「動画もやった方がいいよね」と思いつつ、Premiere Proを開くたびに「...うん、今日はいいか」ってなる。

あの感じ、わかる人いません?

タイムラインにクリップ並べて、テロップのフォントサイズ調整して、コードの表示タイミングを波形見ながら合わせて。1本作るのに4〜5時間。技術解説の動画って、内容を考える時間より編集の時間の方が長いんですよね。

エンジニアの本業はコードを書くことであって、動画編集ソフトのUIと格闘することじゃない。ずっとそう思ってました。

で、最近Remotionというライブラリに出会って、ちょっと世界が変わったんです。

「動画をコードで書く」って聞くと、は?って思いますよね。自分も最初はそうでした。でも実際に触ってみたら、これがもう、完全にエンジニアの発想で動画が作れる仕組みだった。

今日はその話を、コード多めで書きます。


Reactで動画を書くって、結局どういうことなのか

最初に自分がつまずいたのが、「Reactで動画を作る」という概念そのものでした。

Reactってブラウザ上のUIを作るものですよね。それで動画?意味がわからん、と。

でも触ってみて腑に落ちたのは、こういうことでした。

動画って、要するに 「1秒間に30枚の静止画を連続で表示してるもの」 なんですよね。パラパラ漫画と同じ。で、Remotionは「1枚目の静止画をReactでレンダリングして、2枚目もレンダリングして、3枚目も...」っていうのを全フレーム分繰り返して、最終的にMP4にまとめる。

言葉で説明するよりコード見た方が早いです。一番シンプルなRemotionの動画コンポーネントはこれ。

import { useCurrentFrame } from 'remotion';

export const MyFirstVideo: React.FC = () => {
  // 今、動画の何フレーム目にいるかを取得
  const frame = useCurrentFrame();

  // フレーム番号に応じて透明度を変える(0→1にフェードイン)
  const opacity = Math.min(1, frame / 30);

  return (
    <div style={{
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      display: 'flex',
      backgroundColor: '#111',
      opacity,
    }}>
      <h1 style={{ color: 'white', fontSize: 80 }}>
        Hello, Remotion
      </h1>
    </div>
  );
};

これだけで「1秒かけてフェードインするタイトル画面」の動画ができます。

useCurrentFrame() が返すのはただの数値。0, 1, 2, 3...と1フレームごとに増えていく。30fpsなら1秒で30まで。この数値を使ってスタイルを計算するだけ。

After Effectsのタイムラインで「ここにキーフレーム打って、イージングを...」ってやってた作業が、 Math.min(1, frame / 30) の一行で表現できるわけです。

これに気づいた瞬間、「あ、これエンジニアにとっての動画制作の正解かもしれん」と思いました。


じゃあ実際のプロジェクトはどうなってるのか

概念がわかったところで、Remotion-Fireshipテンプレートの実際のプロジェクト構造を見てみましょう。クローンするとこうなってます。

git clone https://github.com/wcandillon/remotion-fireship.git
cd remotion-fireship
src/
├── components/          # 動画パーツ(UIでいうButtonやCardに相当)
│   ├── CodeBlock.tsx    # コード表示コンポーネント
│   ├── FireshipTitle.tsx # タイトルスライド
│   ├── Terminal.tsx     # ターミナル風の表示
│   └── Typewriter.tsx   # タイピングアニメーション
├── compositions/        # 動画シーケンス(UIでいうページに相当)
│   ├── FireshipTutorial.tsx
│   └── SocialClip.tsx   # SNS用ショート動画
├── data/               # 中身のデータ(JSON)
│   └── tutorial.json
└── index.ts            # エントリポイント

普通のReactプロジェクトと変わらないですよね。 components/ に部品があって、 compositions/ でそれを組み合わせる。React書いたことある人なら完全に既視感のある構造。

エントリポイントの index.ts はこう。

import { registerRoot } from 'remotion';
import { FireshipTutorial } from './compositions/FireshipTutorial';

registerRoot(FireshipTutorial);

で、コンポジション(=動画全体の定義)はこう。

import { Composition } from 'remotion';
import { TutorialSequence } from '../components/TutorialSequence';

export const FireshipTutorial: React.FC = () => {
  return (
    <Composition
      id="FireshipTutorial"
      component={TutorialSequence}
      durationInFrames={900}  // 30fps × 30秒 = 900フレーム
      fps={30}
      width={1920}
      height={1080}
      defaultProps={{
        title: 'React Server Components',
        codeExamples: []
      }}
    />
  );
};

<Composition> がRemotionの根幹。ここに動画のメタデータ(解像度、fps、長さ)と、実際に表示するコンポーネントを渡す。 defaultProps で動画の内容を外から注入できるのがポイントで、これが後で「JSONから動画を量産する」仕組みにつながります。


触ってみて驚いたこと——コードで「気持ちいい動き」が作れる

Remotionを触ってて一番「おお」ってなったのが、アニメーションの書き心地でした。

たとえば、タイトルがバウンドしながら登場する動き。After Effectsだとイージングカーブを手動で調整するんですけど、Remotionでは物理パラメータを指定するだけでいい。

import { useCurrentFrame, useVideoConfig, spring } from 'remotion';

export const BouncyTitle: React.FC<{ title: string }> = ({ title }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  // バネ物理でアニメーション値を計算
  // damping: 摩擦(低いとよく弾む) / mass: 質量(重いとゆっくり)
  const scale = spring({
    frame,
    fps,
    from: 0,
    to: 1,
    config: { damping: 8, mass: 0.6, stiffness: 200 }
  });

  // スプリングの値でtransformを動かす
  return (
    <div style={{
      display: 'flex',
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      background: 'linear-gradient(135deg, #0f0c29, #302b63, #24243e)',
      transform: `scale(${scale})`,
    }}>
      <h1 style={{
        fontSize: 100,
        color: 'white',
        fontFamily: 'SF Pro Display, sans-serif',
        fontWeight: 800,
      }}>
        {title}
      </h1>
    </div>
  );
};

spring()config を変えるだけで、動きの質感がガラッと変わる。dampingを下げればビヨンビヨン弾むし、massを上げればゆったり着地する。 パラメータで動きの感触をコントロールできる のが、エンジニアとしてはめちゃくちゃ気持ちいい。

「なんかいい感じの動き」をトライ&エラーで作るんじゃなくて、物理パラメータという 再現可能な数値 で管理できる。このアプローチ、好きな人多いんじゃないかなと。

で、もう一つ。フレーム番号を使ったもっと細かい制御もできます。 interpolate() という関数がそれ。

import { useCurrentFrame, interpolate } from 'remotion';

export const FadeSlide: React.FC<{ text: string }> = ({ text }) => {
  const frame = useCurrentFrame();

  // フレーム0〜20で透明度0→1にフェードイン
  const opacity = interpolate(frame, [0, 20], [0, 1], {
    extrapolateRight: 'clamp',  // 20フレーム以降は1のまま
  });

  // フレーム0〜30でY方向に50px→0pxにスライドアップ
  const translateY = interpolate(frame, [0, 30], [50, 0], {
    extrapolateRight: 'clamp',
  });

  return (
    <div style={{
      opacity,
      transform: `translateY(${translateY}px)`,
      fontSize: 60,
      color: 'white',
    }}>
      {text}
    </div>
  );
};

interpolate(frame, [入力範囲], [出力範囲]) 。フレーム0のとき透明度0、フレーム20のとき透明度1。CSSのtransitionに似てるけど、フレーム単位で正確に制御できるのが違い。

この spring()interpolate() を組み合わせれば、Fireshipの動画で見るような、テンポの良いカットやスライドインが全部コードで書ける。しかも再利用可能なコンポーネントとして。


コードがタイピングされる演出——Fireshipの象徴的なアレ

Fireshipの動画でよく見る、コードが1文字ずつタイピングされるように表示される演出。あれもRemotionだとシンプルに実装できます。

import { useCurrentFrame } from 'remotion';

interface CodeBlockProps {
  code: string;
  startFrame: number;     // 何フレーム目からタイピング開始
  charsPerFrame: number;  // 1フレームあたり何文字表示するか
  language?: string;
}

export const CodeBlock: React.FC<CodeBlockProps> = ({
  code,
  startFrame,
  charsPerFrame,
  language = 'typescript'
}) => {
  const frame = useCurrentFrame();

  // 現在のフレームで何文字まで表示するか計算
  const elapsed = Math.max(0, frame - startFrame);
  const charactersShown = Math.floor(elapsed * charsPerFrame);
  const displayedCode = code.substring(0, charactersShown);

  // カーソルの点滅(15フレームごとにオンオフ)
  const showCursor = frame % 30 < 15;

  return (
    <div style={{
      background: '#1e1e1e',
      borderRadius: 12,
      padding: 40,
      margin: '0 auto',
      width: '80%',
      boxShadow: '0 20px 60px rgba(0, 0, 0, 0.5)',
    }}>
      {/* ウィンドウのドット(macOS風) */}
      <div style={{ display: 'flex', gap: 8, marginBottom: 20 }}>
        <div style={{ width: 12, height: 12, borderRadius: '50%', background: '#ff5f56' }} />
        <div style={{ width: 12, height: 12, borderRadius: '50%', background: '#ffbd2e' }} />
        <div style={{ width: 12, height: 12, borderRadius: '50%', background: '#27c93f' }} />
      </div>

      <pre style={{
        color: '#d4d4d4',
        fontSize: 22,
        fontFamily: "'Fira Code', 'JetBrains Mono', Monaco, monospace",
        lineHeight: 1.6,
        margin: 0,
        whiteSpace: 'pre-wrap',
      }}>
        <code>{displayedCode}</code>
        {showCursor && <span style={{ color: '#569cd6' }}></span>}
      </pre>
    </div>
  );
};

使い方はこう。

<CodeBlock
  code={`const greeting = "Hello, World";
console.log(greeting);

// 関数定義
function fibonacci(n: number): number {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}`}
  startFrame={30}       // 1秒後からタイピング開始
  charsPerFrame={1.5}   // 1フレームに1.5文字(わりと速め)
/>

原理はシンプルで、フレームが進むごとに substring で表示する文字数を増やしてるだけ。でもこれが動画になると、あの「ライブコーディング」の臨場感が出る。 charsPerFrame を変えるだけでタイピング速度を調整できるのも地味に便利。

ここで面白いのが、このコンポーネントは propsで内容を差し替えられる ということ。つまり同じコンポーネントで、異なるコードスニペットの動画を何本でも作れる。これが「動画のプログラマブルさ」の具体例です。


複数シーンを組み合わせる——Sequenceの使い方

実際の動画は、1つのコンポーネントだけじゃなくて、複数のシーンを時系列に並べて構成しますよね。RemotionではこれをSequenceで実現します。

import { Sequence } from 'remotion';
import { BouncyTitle } from './BouncyTitle';
import { CodeBlock } from './CodeBlock';
import { FadeSlide } from './FadeSlide';

export const TutorialSequence: React.FC = () => {
  return (
    <div style={{ flex: 1, background: '#0a0a0a' }}>
      {/* 0〜60フレーム(0〜2秒):タイトル表示 */}
      <Sequence from={0} durationInFrames={60}>
        <BouncyTitle title="Remotionで動画を書く" />
      </Sequence>

      {/* 60〜180フレーム(2〜6秒):コードタイピング */}
      <Sequence from={60} durationInFrames={120}>
        <CodeBlock
          code={`import { useCurrentFrame } from 'remotion';

export const MyVideo = () => {
  const frame = useCurrentFrame();
  return <div>Frame: {frame}</div>;
};`}
          startFrame={0}
          charsPerFrame={1.2}
        />
      </Sequence>

      {/* 180〜240フレーム(6〜8秒):まとめスライド */}
      <Sequence from={180} durationInFrames={60}>
        <FadeSlide text="動画はコードで書く時代" />
      </Sequence>
    </div>
  );
};

<Sequence>from でシーンの開始フレームを、 durationInFrames で長さを指定。シーン内のコンポーネントでは useCurrentFrame() がそのシーンの先頭からの相対フレーム数を返してくれるので、各コンポーネントは自分がいつ再生されるかを気にしなくていい。

これ、React的に言えば「コンポーネントの関心の分離」がちゃんとできてるんですよね。各シーンは独立していて、並び替えても壊れない。UIコンポーネントの設計と同じ思想で動画が構成できる。


音声と映像を同期させる——地味にこれが一番嬉しかった

動画制作で一番面倒なのが、ナレーションとビジュアルの同期だと個人的に思ってるんですけど、Remotionではこれもコードで書けます。

import { Audio, useCurrentFrame, interpolate } from 'remotion';

export const NarratedScene: React.FC<{
  audioSrc: string;
  scenes: Array<{ text: string; startFrame: number; endFrame: number }>;
}> = ({ audioSrc, scenes }) => {
  const frame = useCurrentFrame();

  // 現在のフレームに対応するシーンを取得
  const currentScene = scenes.find(
    s => frame >= s.startFrame && frame < s.endFrame
  );

  const opacity = currentScene
    ? interpolate(
        frame,
        [currentScene.startFrame, currentScene.startFrame + 10],
        [0, 1],
        { extrapolateRight: 'clamp' }
      )
    : 0;

  return (
    <div style={{ flex: 1, background: '#111', position: 'relative' }}>
      {/* 音声ファイルの埋め込み */}
      <Audio src={audioSrc} />

      {/* テキスト表示 */}
      {currentScene && (
        <div style={{
          position: 'absolute',
          top: '50%',
          left: '50%',
          transform: 'translate(-50%, -50%)',
          opacity,
          fontSize: 48,
          color: 'white',
          textAlign: 'center',
          maxWidth: '80%',
        }}>
          {currentScene.text}
        </div>
      )}
    </div>
  );
};

使う側では、ナレーションの台本データを渡すだけ。

<NarratedScene
  audioSrc="/audio/narration.mp3"
  scenes={[
    { text: "Remotionとは何か", startFrame: 0, endFrame: 90 },
    { text: "Reactで動画を作るライブラリです", startFrame: 90, endFrame: 180 },
    { text: "コードがそのまま動画になる", startFrame: 180, endFrame: 270 },
  ]}
/>

ナレーション音声のどの部分でどのテキストを出すか、フレーム番号で指定するだけ。Premiere Proだとタイムライン上でテロップの位置をドラッグして合わせる作業が、ここでは データとして定義 できる。

さらに踏み込むと、 useAudioData() フックで音声の波形データを取得して、音量に応じてビジュアルを動かすこともできます。

import { Audio, useAudioData, useCurrentFrame } from 'remotion';

export const AudioReactiveBar: React.FC<{ audioSrc: string }> = ({ audioSrc }) => {
  const frame = useCurrentFrame();
  const audioData = useAudioData(audioSrc);

  // 現在フレームの音量を取得(0〜1の値)
  const amplitude = audioData
    ? (audioData.frameData[frame]?.amplitude ?? 0)
    : 0;

  // 音量に応じてバーの高さを変える
  const barHeight = 50 + amplitude * 200;

  return (
    <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#000' }}>
      <Audio src={audioSrc} />
      <div style={{
        width: 60,
        height: barHeight,
        background: `hsl(${amplitude * 120}, 80%, 60%)`,
        borderRadius: 8,
        transition: 'height 0.05s',
      }} />
    </div>
  );
};

音が大きいとバーが伸びて色が変わる。ミュージックビジュアライザー的なことが数十行で書ける。こういう「音に反応するビジュアル」って、従来のエディタだとプラグイン入れて設定いじって...ってかなり手間だったんですよね。


JSONから動画を量産する——ここが本当の革命

ここまでのコード例を見てきて気づいた人もいるかもしれないですけど、全てのコンポーネントがpropsでデータを受け取る設計になっています。

これが意味するのは、 JSONファイルで動画の内容を定義して、プログラマティックに大量の動画を生成できる ということ。

たとえば、こういうJSONを用意する。

{
  "episodes": [
    {
      "id": "ep001",
      "title": "変数とは",
      "subtitle": "JavaScript基礎 第1回",
      "code": "let name = 'あきら';\nlet age = 34;\nconsole.log(`${name}は${age}歳`);",
      "explanation": "変数は値を入れる箱のようなもの",
      "duration": 90
    },
    {
      "id": "ep002",
      "title": "関数とは",
      "subtitle": "JavaScript基礎 第2回",
      "code": "function greet(name) {\n  return `こんにちは、${name}さん`;\n}\n\nconsole.log(greet('太郎'));",
      "explanation": "関数は処理をまとめて再利用できる仕組み",
      "duration": 120
    },
    {
      "id": "ep003",
      "title": "配列とは",
      "subtitle": "JavaScript基礎 第3回",
      "code": "const fruits = ['りんご', 'バナナ', 'みかん'];\n\nfruits.forEach(fruit => {\n  console.log(fruit);\n});",
      "explanation": "配列は複数の値をまとめて管理できるデータ構造",
      "duration": 100
    }
  ]
}

で、このJSONを読み込んでコンポジションを生成するコードを書く。

import { Composition } from 'remotion';
import { TutorialEpisode } from './components/TutorialEpisode';
import episodes from './data/episodes.json';

export const RemotionRoot: React.FC = () => {
  return (
    <>
      {episodes.episodes.map(ep => (
        <Composition
          key={ep.id}
          id={ep.id}
          component={TutorialEpisode}
          durationInFrames={ep.duration * 30}  // 秒→フレーム変換
          fps={30}
          width={1920}
          height={1080}
          defaultProps={{
            title: ep.title,
            subtitle: ep.subtitle,
            code: ep.code,
            explanation: ep.explanation,
          }}
        />
      ))}
    </>
  );
};

そしてレンダリング用のスクリプト。

#!/bin/bash
# render-all.sh — 全エピソードを一括レンダリング

EPISODES=("ep001" "ep002" "ep003")

for EP in "${EPISODES[@]}"; do
  echo "Rendering ${EP}..."
  npx remotion render src/index.ts "$EP" "out/${EP}.mp4"
  echo "${EP} done."
done

echo "All episodes rendered."
chmod +x render-all.sh
./render-all.sh

これで3本の教育動画が自動生成される。JSONにエピソードを追加するだけで、いくらでもスケールする。

自分がAI教育のコンテンツを作るときに、これがどれだけ効率化になるか考えると、正直ワクワクが止まらないんですよね。


GitHub Actionsで毎日自動レンダリングする

もう一歩踏み込んで、CI/CDに載せてみましょう。

Notionに毎日の「Today I Learned」を書いて、それをGitHub Actionsで拾って、30秒の縦型動画を自動生成する。この流れを実際に組むとこうなります。

まず、Notionからデータを取得するスクリプト。

// scripts/fetch-notion.js
const { Client } = require('@notionhq/client');
const fs = require('fs');

const notion = new Client({ auth: process.env.NOTION_API_KEY });

async function fetchTodaysTip() {
  const today = new Date().toISOString().split('T')[0];

  const response = await notion.databases.query({
    database_id: process.env.NOTION_DB_ID,
    filter: {
      property: 'Date',
      date: { equals: today }
    }
  });

  if (response.results.length === 0) {
    console.log('No tip found for today. Skipping.');
    process.exit(0);
  }

  const page = response.results[0];
  const tip = {
    title: page.properties.Title.title[0].plain_text,
    code: page.properties.Code.rich_text[0]?.plain_text || '',
    category: page.properties.Category.select?.name || 'General',
  };

  fs.writeFileSync('src/data/daily-tip.json', JSON.stringify(tip, null, 2));
  console.log(`Fetched tip: ${tip.title}`);
}

fetchTodaysTip();

SNS用の縦型コンポジション(9:16)。

// src/compositions/DailyTip.tsx
import { Composition } from 'remotion';
import { DailyTipScene } from '../components/DailyTipScene';
import tipData from '../data/daily-tip.json';

export const DailyTip: React.FC = () => {
  return (
    <Composition
      id="DailyTip"
      component={DailyTipScene}
      durationInFrames={900}  // 30秒
      fps={30}
      width={1080}   // 縦型
      height={1920}  // 9:16
      defaultProps={tipData}
    />
  );
};

GitHub Actionsのワークフロー。

# .github/workflows/daily-video.yml
name: Daily TIL Video

on:
  schedule:
    - cron: '0 23 * * *'  # UTC 23:00 = JST 08:00
  workflow_dispatch:       # 手動実行もできるように

jobs:
  render:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'

      - name: Install FFmpeg
        run: sudo apt-get update && sudo apt-get install -y ffmpeg

      - name: Install dependencies
        run: npm ci

      - name: Fetch today's tip from Notion
        run: node scripts/fetch-notion.js
        env:
          NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}
          NOTION_DB_ID: ${{ secrets.NOTION_DB_ID }}

      - name: Render video
        run: npx remotion render src/index.ts DailyTip out/daily-tip.mp4

      - name: Upload to S3
        run: |
          aws s3 cp out/daily-tip.mp4 \
            s3://my-videos/daily/$(date +%Y%m%d).mp4
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

一度この仕組みを組んでしまえば、 毎日のコンテンツ投稿がNotionに1行書くだけ になる。

レンダリングもGitHub Actionsのランナーでやるので、自分のマシンリソースを使わない。寝てる間に動画ができてる世界。


セットアップの手順をちゃんと書いておく

ここまでコード例をたくさん出してきたので、実際に動かしたくなった人向けにセットアップ手順をまとめます。

前提条件

  • Node.js 16.8.0以降(18.x推奨)
  • npm 7以上
  • FFmpeg
# FFmpegの確認
ffmpeg -version

# 入ってなければインストール(macOS)
brew install ffmpeg

# Ubuntu/Debian
sudo apt-get update && sudo apt-get install ffmpeg

# Windows(Chocolatey)
choco install ffmpeg

Windowsの場合、FFmpegを手動インストールしたときにPATHが通ってないことがあります。 ffmpeg コマンドが認識されない場合は、環境変数のPATHにFFmpegのbinフォルダを追加してください。ここでハマる人、けっこう多いです。

クローン〜起動

git clone https://github.com/wcandillon/remotion-fireship.git
cd remotion-fireship
npm install
npm start

npm start するとブラウザにプレビューが立ち上がります。コンポーネントを編集するとホットリロードで即反映。ここまで、FFmpegが入ってる人なら10分くらい。

Remotionの設定

remotion.config.ts でグローバル設定をいじれます。

import { Config } from 'remotion';

Config.setVideoImageFormat('jpeg');  // jpegの方がレンダリング速い
Config.setOverwriteOutput(true);     // 上書き許可
Config.setConcurrency(8);            // 並列数(CPUコア数に合わせる)

レンダリング

# 基本的なレンダリング
npx remotion render src/index.ts FireshipTutorial out/video.mp4

# 4Kでレンダリング(RAM 16GB以上推奨)
npx remotion render src/index.ts FireshipTutorial out/video-4k.mp4 \
  --width=3840 --height=2160

1分の1080p動画で2〜5分。30分で「テンプレートを動かして最初の動画を書き出す」は、嘘じゃないです。


正直、万能じゃない。限界の話もしておく

ここまで良いことばかり書いてきたので、バランスを取ります。

コードが書けないと使えない。 React(少なくともJavaScript)が書けることが前提。「動画制作を民主化する」ツールではなくて、「エンジニアの動画制作を効率化する」ツール。この区別は大事。

実写映像の編集はできない。 Remotionはプログラマティックに生成されるグラフィック動画が得意であって、撮影した映像をカット編集するようなことは向いてない。Vlogやインタビュー動画は従来のエディタの領域。

日本語情報がまだまだ少ない。 2026年3月時点で、日本語のまとまった解説はほとんど見当たらない。公式ドキュメントは英語のみ。トラブったらGitHub IssuesかDiscordで英語で質問することになる。ただ、自分はこれをチャンスとも捉えてて、先に触って先に発信する。それはそのまま価値になるので。

ライセンスの確認は必須。 Remotionはカンパニーライセンスモデル。個人や小規模企業(年間売上100万ドル未満)は無料。大規模になるとライセンス購入が必要。商用利用する前に確認した方がいい。

長尺動画はコンポジション分割が必要。 10分以上の動画を1つのコンポジションで作るとメモリが辛い。分割してFFmpegで結合するのが現実的。


バイブコーディングの次は、バイブ動画制作かもしれない

最後に、ちょっと飛躍した話をさせてください。

自分は以前、バイブコーディングについて記事を書いたんですけど、あの記事で伝えたかったのは「コードを書く行為の抽象度が上がった」ということでした。

Remotionを触ってみて感じたのは、同じことが動画制作にも起きてるということ。

タイムラインを手動で操作する代わりに、コンポーネントを書く。キーフレームを打つ代わりに、 spring({ damping: 8 }) と書く。1本ずつ手作業する代わりに、JSONデータをforループで回す。

動画制作の抽象度が一段上がった んですよね。

で、ここからがさらに面白いんですけど。

Remotionのコードって、バイブコーディングと相性がめちゃくちゃ良いんです。コンポーネントの構造がシンプルだし、やりたいことを自然言語で伝えれば、AIがRemotionのコンポーネントを生成してくれる。

自然言語 → コード → 動画。

この流れが現実的に成立する時代に、もう入ってるんですよね。

"30秒のタイトル動画を作って。背景は紺色のグラデーションで、
テキストがバウンドしながら表示されて、最後にフェードアウト。"

→ AIがRemotionコンポーネントを生成
→ npx remotion render
→ MP4が完成

もちろん、全ての動画がこのアプローチで作れるわけじゃない。実写は実写。After EffectsはAfter Effects。適材適所は変わらない。

でも、技術解説動画、プロダクトデモ、教育コンテンツ。テンプレートベースで量産可能なコンテンツの領域では、コードで動画を書くアプローチが圧倒的に効率的です。

そしてこの領域って、まさにエンジニアが発信するコンテンツの中心。

なので、もし技術発信に興味があって、でも動画編集のハードルで立ち止まってた人がいたら。 npm start を一回叩いてみてください。30分後には最初の動画ができてます。

その体験をすると、動画に対する認識がちょっと変わるかもしれません。

動画はもう、編集するものじゃなくて、書くもの。

そう思える日が、もう来てるんだなと。


参考リンク

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?