西川和久の不定期コラム

撮影なし・生成AI動画なしでミュージックビデオ作成!AIにコードで動画を作らせる

イメージ

 10月に入り、街はすっかりハロウィンモード。そこで今回は、AIで“ハロウィンっぽい楽しいMV”を作ってみたい。

 といっても、今回は実写風の生成AI動画ではない。文字や図形、写真、動画を動かして見せる「モーショングラフィックス」を、Reactの「Remotion」とコードを使って作る話だ。Remotionは、Reactで書いた画面を1コマずつ描画し、MP4などの動画として書き出すツールだ。

モーショングラフィックスとは?

 モーショングラフィックスとは、文字/図形/アイコン/写真などを動かして見せる映像表現のことだ。ニュース番組のテロップ、CMで文字がポンッと飛び出す演出、YouTubeの解説動画で数字がカウントアップしていく場面……といえば、「ああ、あれか」と思い浮かぶのではないだろうか。

 つまり実写の撮影も、昨今話題の生成AI動画モデルも使わない。素材を“組み立てて動かす”タイプの動画となる。

 これをPCで簡単に実現できるのがRemotionだ。やり方は原始的?で、動くWebページを1コマずつ画像にし、ffmpegでつなげてMP4にするという、ある意味力技だったりする。手順は以下のような感じとなる。

  1. HTML/CSSと同じ感覚で書く(文字、色、位置、拡大縮小など)
  2. 「今、何コマ目か」という値(useCurrentFrame())が取れるので、その値で見た目を変えれば、アニメーションになる
  3. ブラウザ上のプレビュー画面(Remotion Studio)で、再生しながら確認
  4. 最後は1つのコマンドでMP4に書き出す

 プログラムで決めた通りに描くので、毎回同じ結果になり、生成AI動画のような“ガチャ”はない。さらに文字や数字を正確に出したい動画にはこちらの方が都合がいい。

 準備は以下の通り。

1. 空のフォルダを作って移動(フォルダは任意)
mkdir -p ~/Desktop/mg && cd ~/Desktop/mg
2. Blank テンプレートを生成(空のフォルダで一度だけ実行)
npx create-video@latest --yes --blank .
3. Remotion Studio(プレビュー画面)を起動 → http://localhost:3000
npm run dev

 これで空のRemotion Studioが起動する。いったんCtrl+Cで終了しよう。

空のRemotion Studioが起動

 以下、簡単な例を3つあげた。コードなので、何となく見れば分かる人も多いのではないだろうか?

例1: 文字がふわっと現れる

 まずは最初の一歩。「AIとは?」という文字が、下からせり上がりながら現れる。

 ポイントはinterpolate。「0~20コマ目の間に、透明度を0→1、位置を60px下→0に変える」と書いているだけだ。20コマ目以降はclampで止まるので、文字は表示されたまま動かない。

 実行は、src/Root.tsxを以下のように書き換える。

import {Composition} from 'remotion';
import {Title} from './Title';
export const RemotionRoot: React.FC = () => (
<>
<Composition id="Title" component={Title} durationInFrames={90} fps={30} width={1920} height={1080} />
</>
);

 それからnpm run devを実行する。

AIとは?が動いた

例2: 数字がカウントアップする

 次は、紹介動画でよく見る「利用者15,000人」のようなカウントアップ。

 springは、0から1へ“勢いよく近づいてなめらかに止まる”値を返してくれる便利な関数だ。それに15,000を掛けているだけで、数字が増えていくアニメーションになる。

 そしてsrc/Root.tsxのTitleと書かれた4カ所をCounterに書き換えてnpm run devを実行。

カウントアップ

例3: 写真や動画を取り込む

 ここまでは文字や数字だけだったが、Remotionは既存の写真や動画もそのまま使える。ここが実用上かなり大きい。商品写真、サイトのスクリーンショット、撮影済みの動画などを、public/フォルダに置いておくだけだ。ここではpublic/photo.jpgとpublic/clip.mp4の2つを置いている。

・写真: で表示。拡大・移動・透明度など、文字と同じようにアニメーション可能
・動画: <OffthreadVideo>で再生。画面の一部に小窓で重ねたり、背景にぼかして敷いたりもできる

src/Media.tsx
import {AbsoluteFill, Img, OffthreadVideo, interpolate, spring, staticFile, useCurrentFrame, useVideoConfig} from 'remotion';
export const Media: React.FC = () => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
// 写真:大きく拡大しながら、斜めにパンして、少し回転する
const zoom = interpolate(frame, [0, 90], [1.1, 1.7]);
const panX = interpolate(frame, [0, 90], [-120, 120]);
const panY = interpolate(frame, [0, 90], [80, -80]);
const rotate = interpolate(frame, [0, 90], [-4, 4]);
// 動画の小窓:ぽんっと登場し、画面の中を円を描くように動き回る
const pop = spring({frame, fps, config: {damping: 8}});  // 勢いよく出て、弾んで止まる
const t = frame / 90 * Math.PI * 2;                      // 0~90コマで一周(2π)
const x = Math.cos(t) * 420;                             // 左右に ±420px
const y = Math.sin(t * 2) * 200;                         // 上下に ±200px(2倍速で8の字)
const tilt = Math.sin(t) * 10;                           // 動きに合わせて傾ける
return (
<AbsoluteFill style={{background: '#111'}}>
{/* 写真(public/photo.jpg)を背景に */}
<AbsoluteFill style={{overflow: 'hidden'}}>

</AbsoluteFill>
{/* 動画(public/clip.mp4)を、中央を基準に動き回る小窓で重ねる */}
<AbsoluteFill style={{justifyContent: 'center', alignItems: 'center'}}>
<OffthreadVideo src={staticFile('clip.mp4')} muted
style={{width: 800, borderRadius: 24, border: '8px solid #fff', transform: `translate(${x}px, ${y}px) rotate(${tilt}deg) scale(${pop})`}} />
</AbsoluteFill>
</AbsoluteFill>
);
};

 写真は背景で大きく拡大しながら斜めに動き、動画の小窓は画面の中を8の字に動き回る。小窓はspringでぽんっと弾んで登場する。ファイルはどちらもpublic/に入れたものをstaticFile()で指す。

 そしてsrc/Root.tsxのCounterと書かれた4箇所をMediaに書き換えてnpm run devを実行。

写真と動画が動き回る

 いかがだろうか?こんな感じで文字にエフェクトをかけたり動かしたり、写真や動画も扱え、うまく作ればいい雰囲気の動画が完成しそうだ。

 しかし、上記のコードからも分かるように、座標などを扱う関係上、人間業ではちょっと厳しい(笑)。そこでAIの登場となる。Remotionに関しては、割と知っているらしく、チャットするように指示するとうまく作ってくれる。

Remotionのパーツ集を用意

 本格的なMVを作る前に、Remotionのパーツ集を用意した。上記のような動きを毎回一品物としてAIに作らせると、コストがかかるためだ。コードが長くなるので時間もかかるし、トークンも使う。直す度に、細かい動きや見た目が変わって、安定しないのも困りものだ。

 そこで、文字の置き方、文字の動き、背景、強調の飾り、アイコン、全体の雰囲気……といった「部品」を、あらかじめ作っておき(=パーツ集)、AIには、お題から「どの部品を、どの順で、どう組み合わせるか」を決めてもらうだけにする。部品が決まれば、描画はプログラムが、決めた通りに、毎回同じ結果で描いてくれる。

 部品は、次のようなものが入っている。

  • 文字の配置(30種): 中央に大きく、左寄せ、縦書き、斜め、左右に分ける、写真を傾いたカードで見せる、スマホの枠で動画を再生する、文字を散らす、波に沿わせる、左右に振る……。配置ごとに「1行は何文字まで」の上限があり、はみ出しを防げる
  • 文字の動き(20種): 波打つ、弾む、回る、下から浮かぶ、ぷるんと現れる……。動きの種類が多いと、単調にならない
  • 背景(28種): 星、泡、回路、ドット、縞、グラデーション……。写真や動画を、画面いっぱいに敷く背景もある
  • 写真そのものの動き(11種): ゆっくり寄る、引く、横や斜めに流れる、ゆらりと傾く、拍ごとに弾む、呼吸のように拡大縮小する……(写真の中身は動かないが、写真全体を動かして、動きを出す)
  • 強調の飾り(18種): 蛍光ペン、判子、紙吹雪、きらめき……
  • アイコン(約490個): Lucideというアイコン集から、題材に合うものを選べる。ハロウィン用に、おばけ、ドクロ、キャンディなども入れた
  • 雰囲気(11種): 配色、書体、場面転換、動きの強さ、BGMの曲調を、まとめて切り替える。ポップ、落ち着いた、夜、ハロウィンなど。文字と背景のコントラスト比を計算してあり、読めない配色にならない

 組み合わせるだけで、配置×動き×背景×飾りで、30万通り以上になる(アイコンも選ぶと、1億通りを超える)。コードを書かなくても、AIが「選ぶ」だけで、見た目が変わり、コストを抑え、安定させることもできる。

 加えて、MVを作るために、次の部品も足してある。

  • 写真や動画を、場面ごとに指定して使える(大きく敷く、傾いたカード、コラージュなど)
  • 文字のない場面(写真だけを見せる)と、文字の縦位置(人物の顔に文字がかからない)
  • 歌詞を、場面とは別に、時刻つきで重ねる。1文字ずつ、行ごとに違う踊り方で出て、拍に合わせて跳ねる
  • 曲のBPM(テンポ)を指定でき、場面の長さは、書いた秒数がそのまま効く。曲の拍に合わせて、画像を切り替えられる
  • 場面ごとに、文字を崩す(散らす・波に沿わせる・左右に振る配置と、文字全体の傾き・拡大・ずらし)。整った配置ばかりが続くと、単調になるため
  • 拍に合わせて弾けるアイコン(最大24個。位置・大きさ・色はばらばら)。アップテンポな曲に、漂うだけでは合わなかったため。人物の顔に重ならないよう、顔の位置を伝えて避けさせる指定もつけた
  • 黒からの入りと、黒への出(フェード)。曲が、フェードアウトで終わるため

 ほかに、素材づくりの道具も、おまけでつけた(どれも任意)。曲のテンポと拍を調べる道具(librosa、mlx-whisper)、ComfyUIで画像を作る道具(ComfyUIのAPIをNode.jsから呼ぶ)、文字が顔にかかっていないかを調べる道具(macOSのVisionフレームワークで顔と文字を検出。Swift使用)だ。

 使い方は簡単。AIに、パーツの説明書(PARTS.md)を読ませて、お題を伝える。すると、AIが、お題に合わせて、台本(scenario.json)を書く。台本は、たとえばこんな形だ。

{
"bpm": 112.36,
"hold": 0,
"fadeIn": 0.4,
"fadeOut": 1.5,
"lyrics": [
{"start": 0.1, "end": 3.0, "text": "鏡の前で仮面をつけて", "fx": "bounce"},
{"start": 16.7, "end": 21.0, "text": "Trick or Love", "big": true, "fx": "wave"}
],
"scenes": [
{"tech": "compose", "lines": [], "sec": 3.2,
"layers": {"layout": "none", "bg": "photofull", "pick": [1]}},
{"tech": "compose", "lines": ["仮面の", "下"], "sec": 4.3,
"layers": {"layout": "left", "motion": "slide", "bg": "photofull", "pick": [2]}}
]
}
※ 実際の台本の一部。場面ごとに、配置、動き、背景、使う写真の番号などを書く

 あとは、次のコマンドで動画が書き出される。曲は、重ねて書き出すだけ。

node scripts/render.mjs お題.md --name mv --bgm-file 曲.mp3

 また台本には「検査」がついている。文字数のはみ出し、存在しない部品の名前、素材の番号の間違い、といったミスは、動画を作る前に、理由つきで止めてくれる。AIは、その理由を読んで直すだけ。1回の書き出しは、約30秒から1分半(場面や、アイコンの数による)。

パーツ集とAIでハロウィンのMVを作る

 やったことは単純。MVなのでまず音源がないと話にならない。これは「ACE-Step 1.5」を使った。歌詞はAI任せ「ハロウィンの歌をJ-pop風のアップテンポで」。以下、出力された歌詞 by DeepSeek V4 Flash。

[Verse 1]
鏡の前で仮面をつけて
借り物の顔で笑ってみせた

[Pre-Chorus - building energy]
甘いキャンディ溶けていく
君の名前呼べないまま

[Chorus - anthemic]
Trick or Love お菓子より君が欲しい
仮面の下覗かないでよ
Trick or Love 月が沈むまでに
本当のわたしを選んで

[Verse 2]
黒いマントが風に揺れて
君は吸血鬼のふりをした

[Pre-Chorus - building energy]
時計が鳴る十二時
魔法が解ける前にほら

[Chorus - anthemic]
Trick or Love お菓子より君が欲しい
仮面の下覗かないでよ
Trick or Love 月が沈むまでに
本当のわたしを選んで

[Bridge - whispered]
お化けになれば怖くないのに
好きだって言葉だけが怖い

[Chorus - powerful belting]
Trick or Love 仮面を脱いだこの顔でも
笑ってくれるそれだけ聞きたい
Trick or Love 夜が明けても隣にいて
本当のわたしを選んで

[Outro - dreamy]
Trick or Love...
カボチャの灯りが消えてく

[Fade Out]

 これを使ってACE-Step 1.5で音源を作る。プロンプトは“Female Vocals, happy ハロウィン, J-pop”、bpm: 110、C major、60s……など。

ACE-Step 1.5のWorkflow
できた音源(静止画動画)。尺を1分にしたので歌詞がかなり省略されている

 これができればあとは、先のパーツ集PARTS.md、お題「ハロウィンのMV。明るくアップテンポ、カラフルで賑やかな感じ」、音源はこれ(上記のMP3)、歌詞はこれ(上記の歌詞)……と渡せば、自動的に必要な台本や画像を作り動画(MP4)を出力する。

Claude Code(Sonnet 5.5)がZ-Imageを使って生成した画像群。これをベースに動かしたり文字を入れたりする

 もともとClaude Code(Sonnet 5.5)でパーツ集を作ったこともあり、そのままお題を実行。できたMVが以下となる。

Claude Code(Sonnet 5.5)が作ったハロウィンのMV

 ただこれだとある意味、自作自演なので、ほかのハーネス(DeepSeek V4 Flash)にもPARTS.mdを渡し、同じお題を与えたMVがこれだ。

DeepSeek V4 Flashが作ったハロウィンのMV

 やはりモデルによって個性があり、出来が結構変わる。Sonnet 5.5は硬い感じ、DeepSeek V4 Flashはちょっと弾けた感じだろうか。普段チャットで会話しているときと印象が同じだ(笑)。

 最後にちょっと注意事項。Remotionはご覧のようにかなり便利なのだが、ライセンスが少し変わっており、個人、従業員3人以下の営利団体、非営利団体なら、商用でも無料。4人以上の会社が業務で使う場合は、有償のライセンスが必要になる。


 文字や写真を動かすモーショングラフィックスは、Remotionを使えばコードで確実に作れる。そのコードをAIに書かせれば、「ハロウィンっぽい楽しい動画」のようなお題でも、曲、画像、動きまで含めてAIと一緒に作れた。

 ただ、全部の動きを毎回一品物としてAIに作らせると、コストがかかる。そこで、パーツ集を用意して、AIには「選ばせる」形にした。毎回コードを書かせるより、安定していて、直しやすい。困ったことをパーツに足していけば、次に使うAIが、同じところで困らなくなる。

 とはいえ、まだまだ課題は多い。歌詞のタイミングは「おおよそ」だし、顔に文字がかからないようにするには、人間(か別のAI)の目で見る必要がある。それでも、「こんな感じで」と伝えて、AIがMVを作れる時代になったと、改めて感じた次第。

 パーツは、足せるようにしてあるので、「こんな動きがほしい」「こんな背景がほしい」と思ったら、AIに作ってもらえばいい。興味のある人はぜひ試してほしい。