1. はじめに
個人開発で、さまざまなテーマの「ゆっくり解説動画」を、台本作成から動画レンダリングまで自動生成できるシステムを作りました。
システムの特徴:
- 汎用的な設計: マスター台本形式により、あらゆるテーマの解説動画に対応
- 高度な自動化: LLMによる台本生成 → 音声合成 → 動画レンダリング(人間による最終確認あり)
- 拡張可能: 新しいコンテンツタイプを追加しやすい設計
現在の実装例:
- GitHub 人気リポジトリ解説動画
- 今後の展開
- 技術記事解説、プロダクトレビュ、ニュース解説など
この記事では、システムの中核となるマスター台本システムと、その具体的な活用例としてGitHub 人気リポジトリ解説動画の自動生成を紹介します。
生成された動画例
このシステムを使うと、こちらのような動画を生成できます。
2. システム全体像
汎用的な動画生成パイプライン
なお、動画生成パイプラインは、一括で実行できますが、ステップごとでの実行や途中のステップから再実行することも可能です。
| ステップ | 技術 | 役割 | 拡張性 |
|---|---|---|---|
| データ収集 | 任意 | コンテンツソースからデータ取得 | 各種API、スクレイピング、手動入力など |
| 分析・整形 | Claude Agent Skills | データ構造化、要点抽出 | 任意のドメイン知識に対応 |
| マスター台本生成 | Gemini 2.5 Flash | マスター台本JSON生成 | キャラクターの追加、テーマに応じたプロンプト設計 |
| 音声ファイル生成 | AquesTalk10 | ゆっくりボイス生成 | VOICEVOX等の音声合成エンジンにも対応可能 |
| 台本ファイルへ変換 | 変換プログラム | 各セリフの発話時間などを元に 動画タイムラインでの表示制御 |
さまざまな表示オブジェクト(グラフなど)の追加 |
| 動画レンダリング | Remotion | React → MP4変換 | コンポーネントで画面要素を拡張 |
重要な設計方針:
- マスター台本 = 中間形式: データソースに依存しない汎用的な台本形式
- コンテンツタイプごとにデータ収集・分析を切り替え: 動画生成パイプラインは共通
- React コンポーネントで画面要素を追加: カード、グラフ、スライドショーなど
3. マスター台本システム
なぜ中間形式が必要か
動画を自動生成する際、次のような問題があります。
問題: 音声の長さは生成してみないと分からない
同じセリフでも、音声合成エンジンの設定次第で長さが変わります。
- 「今日はおもしろいリポジトリを紹介するぜ!」
- 通常速度: 3.2秒
- 速い速度: 2.5秒
- ゆっくり速度: 4.0秒
Remotionで動画を作る場合、「このセリフは何フレーム表示するか」を事前に決める必要があります(例: 30fps × 3.2秒 = 96フレーム)。しかし、音声ファイルを生成する前は、この長さが分かりません。
解決策: マスター台本という中間形式
そこで、以下の2段階で処理するようにしました。
1. LLM → マスター台本(セリフテキストのみ、音声の長さは不明)
2. マスター台本 → 音声生成 → 台本ファイル(各セリフの長さを含む)
3. 台本ファイル → Remotion(フレーム数が確定、動画生成可能)
マスター台本では「何を喋るか」だけを定義し、音声生成後に「何秒喋るか」が確定してから、Remotionで表示するフレーム数を計算します。この2段階の仕組みにより、音声の長さに応じた正確なタイミング制御が可能になります。
マスター台本の構造
各要素の説明:
| 要素 | 説明 |
|---|---|
| MasterScript | マスター台本のトップレベル構造。動画全体の情報を保持 |
| Metadata | 動画のタイトルやIDなど、動画を識別するための情報 |
| Settings | 動画全体に適用される設定。BGM、音声エンジン、デフォルトのタイミングなど |
| Section | 番組の構成単位。導入、本編、まとめなど、テーマごとにセリフをまとめる |
| Line | セリフ・シーン動画・BGM制御の共通インターフェイス |
| DialogueLine | キャラクターのセリフ1行分。テキスト、感情、表示コンポーネント(リポジトリカード、スター推移グラフなど)を含む |
| SceneVideo | オープニング、インターバル、エンディングなどの動画を挿入する行 |
| BgmControl | BGMの開始・停止・変更・音量変更を制御する行 |
ポイント:
-
sectionsで番組構成を表現(introduction, main, conclusion など) -
linesにセリフのみを格納(表示コンポーネントは後から挿入) - 動画ID、BGM ID などは設定ファイルで別途定義することで、再利用しやすくしている
- JSONなので人間もLLMもレビュ・修正しやすい
事後処理で画面要素を挿入
LLMにはセリフだけを生成させ、カード・グラフ・スクリーンショットなどの表示設定は、事後処理でセクションに応じて自動挿入します。
function enrichSections(masterScript, repoData, analysisData) {
for (const section of masterScript.sections) {
switch (section.name) {
case 'introduction':
// 最初のセリフにリポジトリカードを追加
section.lines[0].repositoryCard = {
name: repoData.fullName,
stars: repoData.stars,
// ...
};
break;
case 'star_growth':
// スター推移グラフを追加
targetLine.starHistoryChart = { /* ... */ };
break;
}
}
}
なぜこの設計か:
- LLMに「画面要素を意識させない」ことで出力が安定
- 番組のセクションに応じて機械的に挿入できる
- 画面レイアウトの変更がLLMの再生成なしで可能
表示コンポーネントの拡張性
表示コンポーネントはReactコンポーネントとして実装されており、動画のパターンに応じて自由に追加・拡張できます。
現在利用可能な表示コンポーネント
| コンポーネント | 用途 | 表示内容 |
|---|---|---|
| RepositoryCard | リポジトリ紹介 | 名前、説明、スター数、言語、ライセンス |
| RepositoryFeatureCard | リポジトリの特徴 | 主要機能を箇条書きで表示 |
| ProductCard | プロダクト紹介 | 名前、説明、価格、カテゴリ |
| ProductFeatureCard | プロダクトの特徴 | 主要機能を箇条書きで表示 |
| StarHistoryChart | スター推移 | 時系列グラフ(recharts) |
| ScreenshotsGrid | スクリーンショット | 最大4枚のグリッド表示 |
| ScreenshotsSlideshow | スクリーンショット | 複数枚のスライドショー |
RepositoryCard
リポジトリの基本情報(名前、説明、スター数、言語、ライセンス)を表示するカードです。
RepositoryFeatureCard
リポジトリの主要機能を箇条書きで表示するカードです。
StarHistoryChart
リポジトリのスター数の推移を時系列グラフで表示できます。
新しいコンポーネントの追加方法
新しいテーマの動画を作る場合、専用の表示コンポーネントを簡単に追加できます。
例: 技術解説動画用のコードブロックコンポーネント
// src/components/CodeBlock.tsx
export const CodeBlock: React.FC<{
code: string;
language: string;
highlightLines?: number[];
}> = ({ code, language, highlightLines }) => {
return (
<div className="code-block">
<SyntaxHighlighter language={language}>
{code}
</SyntaxHighlighter>
</div>
);
};
マスター台本に codeBlock フィールドを追加するだけで、動画内でコードを表示できます。
拡張例:
- 技術解説動画: コードブロック、ターミナル出力、アーキテクチャ図
- プロダクトレビュ: 価格比較表、機能チェックリスト、スクリーンキャスト
- ニュース解説: 関連記事カード、引用文、タイムライン
- チュートリアル動画: ステップバイステップガイド、完成イメージ、注意点ボックス
このように、Reactコンポーネントの追加だけで、新しい動画パターンに対応できます。
4. LLMで台本を自動生成する際のポイント
🔍 A. Agent Skills でリポジトリを深く分析する
台本を生成する前に、何を解説するかを決める必要があります。GitHub 人気リポジトリ解説動画では、リポジトリのREADMEから特徴や見どころを抽出します。
従来の方法の問題点:
単純にREADMEを要約するだけでは、以下のような問題がありました。
- ✗ 表面的な情報しか取得できない(「〜するツールです」程度)
- ✗ 技術的な深掘りができない(どんなアーキテクチャか、どんな技術が使われているか)
- ✗ 番組で取り上げるべきポイントが不明瞭
解決策: Claude Agent Skills で段階的に分析
Agent Skills を使うことで、以下のような段階的な分析が可能になりました。
// skills/analyze-repository/skill.ts
const analysisResult = await analyzeRepository({
repositoryUrl: repoUrl,
readme: readmeContent,
// Agent Skills が以下を自動実行:
// 1. READMEの構造を理解
// 2. 技術スタックを特定
// 3. 主要機能を抽出
// 4. ユースケースを分析
// 5. 番組で取り上げるべきポイントを提案
});
効果:
- ✓ 深い分析: 技術的な背景やアーキテクチャまで理解できる
- ✓ 構造化されたデータ: 特徴、ユースケース、技術スタックなどを項目別に抽出
- ✓ 番組構成のヒント: 「どのセクションで何を説明すべきか」が明確になる
- ✓ 台本生成の精度向上: 分析結果を台本生成のプロンプトに含めることで、より的確な解説が可能
分析結果の活用例:
{
"repositoryType": "framework",
"techStack": ["TypeScript", "React", "Vite"],
"features": [
"高速なビルド",
"ゼロコンフィグ",
"プラグインエコシステム"
],
"useCases": [
"モダンなWebアプリ開発",
"プロトタイピング"
],
"highlights": [
"Viteの革新的なホットリロード機構",
"従来のWebpack比で10倍高速"
]
}
この分析結果を基に、台本生成時に「どの特徴を強調すべきか」「どんな順序で説明すべきか」が明確になります。
📝 B. 生成するマスター台本を構造化出力させる
LLMに台本を生成させる際、最初は「JSONフォーマットで出力してください」とプロンプトで指示していました。しかし、この方法には問題がありました。
従来の方法の問題点:
あなた: 「以下の形式でJSONを出力してください: { "metadata": { ... }, "sections": [...] }」
LLM: 「承知しました。JSONを出力します。```json { ... } ``` 」
- ✗ JSONが壊れることがある(カンマ抜け、括弧の不一致など)
- ✗ パースエラーで失敗する
- ✗ フィールドの型が間違っている(numberのはずがstringなど)
- ✗ 必須フィールドが欠けていても気づかない
解決策: Vercel AI SDK の generateObject
generateObject を使うと、Zodスキーマに従った構造化JSONを直接取得できます。
import { generateObject } from 'ai';
import { MasterScriptSchemaForLLM } from '@/schemas/masterScript';
const result = await generateObject({
model: google('gemini-2.5-flash'),
prompt,
schema: MasterScriptSchemaForLLM, // ← Zodスキーマで構造を定義
mode: 'auto',
});
メリット:
- ✓ JSONパースエラーが起きない(LLMが直接オブジェクトを返す)
- ✓ 型安全(TypeScriptの型定義と完全に一致)
- ✓ スキーマ検証(必須フィールドや型の制約を自動チェック)
- ✓ 再試行ロジック(失敗時は自動的にリトライ)
🔧 C. Zodスキーマで構造を教える
Zodスキーマは、LLMに「どんな構造のJSONを出力すべきか」を教える設計図です。
// schemas/masterScript.ts
export const MasterScriptSchemaForLLM = z.object({
metadata: z.object({
title: z.string(),
videoId: z.string(),
// ...
}),
settings: z.object({
bgm: z.object({
id: z.string(),
volume: z.number().optional(),
}),
// ...
}),
sections: z.array(
z.object({
name: z.string(),
lines: z.array(/* ... */),
})
),
});
このスキーマにより、LLMは正確な構造のJSONを生成でき、開発者は型安全にデータを扱えます。
💡 D. プロンプト設計のポイント
構造化出力でJSONの形式は保証できますが、セリフの内容の質はプロンプト設計で決まります。
👤 1. キャラクター設定の厳格化
なぜ必要か: LLMは同じキャラクターでも、生成のたびに口調が変わることがあります。視聴者は一貫性のないキャラクターに違和感を覚えるため、厳格なルールが必要です。
プロンプト例:
**魔理沙(marisa)の役割:**
- 解説役・突っ込み役
- **必ず語尾に「だぜ」をつける**(例外なし)
- 例: 「すごいんだぜ」「知ってるか?」「そうなんだぜ」
**霊夢(reimu)の役割:**
- 質問役・ボケ役、知識が少ない
- 驚きや感嘆のリアクション
- 例: 「へぇ〜」「それってどういうこと?」「そうなんだ!」
効果: 口調サンプルを明示することで、キャラクターのブレを防ぎ、動画全体で一貫した個性を保てます。
🚫 2. 画面要素への言及を禁止
なぜ必要か: LLMが「このグラフを見てください」と言及しても、実際にグラフが表示されるかは事後処理で決まります。言及と実際の表示がズレると、視聴者が混乱します。
プロンプト例:
**画面要素への言及を絶対にしないでください**
- **禁止**: 「カード」「グラフ」「スクリーンショット」などへの言及
- **禁止**: 「〜を見てくれ」「〜を表示します」などのメタ的な表現
- **推奨**: 内容を直接説明する(「このリポジトリは〜」「スター数は〜」)
効果: セリフと画面要素を分離することで、LLMの出力が安定し、事後処理で柔軟に画面を調整できます。
📖 3. 音声合成用の句読点ルール
なぜ必要か: 音声合成エンジンは句読点の位置で間(ポーズ)を入れます。適切な位置に読点がないと、一気に読み上げられて聞き取りにくくなります。
プロンプト例:
- 読点(、)は8〜15文字ごとに入れる
- 文節の区切りに読点を入れる
**悪い例(読みにくい)**:
「このフレームワークを使えば開発者はAIエージェント同士の連携を効率的に実装できるんだ」
**良い例(読みやすい)**:
「このフレームワークを使えば、開発者は、AIエージェント同士の連携を、効率的に実装できるんだ」
効果: AquesTalkでの読み上げが自然になり、視聴者が聞き取りやすくなります。
⚙️ 4. コンテンツ固有のプロンプト
テーマに応じて、以下をカスタマイズします。
- 動画の長さ: セクションごとの行数指定で調整(例: introduction 4-5行、main 15-18行)
- 構成: テーマに応じた番組構成を定義(例: GitHub解説動画では「導入 → 実例 → 本編 → まとめ」)
- データ参照: 分析結果を参照しながら台本を生成(例: リポジトリのREADMEから特徴を抽出)
効果: 同じシステムで、さまざまなテーマの動画を生成できます。
5. Remotionで動画をレンダリング
コンポーネント構成
YukkuriComposition(メイン)
└── Scene(1セリフ単位)
├── Character × 2(霊夢・魔理沙)
├── Subtitle(字幕)
├── RepositoryCard / StarHistoryChart(画面要素)
└── Audio(音声)
- YukkuriComposition: セクション・セリフを時系列に配置
- Scene: 2人のキャラクターを常時表示、話者を強調
- Character: body/face/eye の3レイヤー構成
フレームベースのタイミング制御
const durationInFrames = Math.ceil(
(paddingBefore + audioDuration + paddingAfter) * fps
);
音声の長さ(秒)× fps = フレーム数で、各セリフの表示時間を計算します。
6. 具体例: GitHub 人気リポジトリ解説動画
自動化フロー
ここまで説明した汎用的なシステムを使って、GitHub リポジトリ解説動画を生成しています。
重要: データ収集から音声生成まではほぼ自動化されていますが、音声生成後に人間が台本をレビュ・調整します。これにより、品質を保ちながら効率的に動画を生成できます。
7. まとめ
システムの特徴と成果
このシステムは、マスター台本という中間形式を中心に、LLMと人間の協働で高品質な解説動画を効率的に生成します。
主要な技術的工夫:
-
🔍 Agent Skills による深い分析
- 単純な要約ではなく、技術的背景やアーキテクチャまで理解
- 番組で取り上げるべきポイントを自動抽出
-
📝 構造化出力による信頼性
- Vercel AI SDK の
generateObject+ Zod スキーマ - JSONパースエラーなし、型安全、スキーマ検証
- Vercel AI SDK の
-
💡 プロンプト設計のノウハウ
- キャラクター設定の厳格化で一貫性を確保
- 画面要素への言及を禁止し、セリフと画面を分離
- 音声合成用の句読点ルールで聞きやすさを向上
-
🎨 表示コンポーネントの拡張性
- Reactコンポーネントで画面要素を追加
- 新しい動画パターンへの対応が容易
-
👤 人間による品質管理
- 音声生成後に台本をレビュ・調整
- 用語の追加や微調整で品質を担保
得られたメリット:
- 高度な自動化: データ収集から音声生成まで自動化、人間はレビュに集中
- 品質の安定: マスター台本 + 事後処理の分離でLLM出力が安定
- さまざまなテーマに対応: データソースを切り替えるだけで、さまざまな解説動画を生成可能
現在の実装:
- GitHub リポジトリ解説動画を効率的に生成
- 6つのカテゴリに対応
今後の展開:
- 技術記事解説動画(Qiita 人気記事解説)
- プロダクトレビュ動画(新しいツールやサービスの紹介)
- ニュース解説動画(技術ニュースの要約と解説)
- チュートリアル動画(プログラミング学習コンテンツ)
マスター台本形式を共通化することで、新しいコンテンツタイプの追加が容易になります。
技術スタック
| カテゴリ | 技術 | 用途 |
|---|---|---|
| データ収集 | GitHub API | Trendingリポジトリ取得 |
| 分析 | Claude Agent Skills | 深い分析、ポイント抽出 |
| 画像生成 | Gemini 2.5 Flash + nanobanana | ユースケース画像生成 |
| スクリーンショット | MCP Playwright Server | リポジトリページ撮影 |
| 台本生成 | Vercel AI SDK + Gemini 2.5 Flash | 構造化JSON生成 |
| 型定義 | Zod | スキーマ検証 |
| 音声合成 | AquesTalk10 | ゆっくりボイス生成 |
| 動画レンダリング | Remotion | React → MP4変換 |


