課題: ボトムアップで作ると階層が混ざる
初期の実装では「とりあえず動く」ものを先に作るボトムアップのアプローチを取った。結果として起きたのは責務の混在だった。
- チャートコンポーネントが自分の配置位置を知っている
- 背景・コンテンツ・字幕が同一の層に混在している
- シーンごとの構造が微妙に異なり、量産ができない
AI にこの状態のコードを渡して「別のシーンを追加して」と頼むと、混乱した構造を踏襲した新しいコードが生成される。---
解決策: 6 階層をトップダウンで定義する
解決策は単純だった。大きい枠組みから小さい枠組みへ、一方向に下ろしていく設計に切り替えることだ。
montage の設計哲学は次の 6 階層で表現できる。
Video
└─ Scene(1シーン = 1画面)
└─ Layer(レイヤーの重ね合わせ: 背景 → コンテンツ → オーバーレイ → UI)
└─ Layout(空間分割: fullscreen / side-by-side / grid ...)
└─ Slot(分割された各エリア)
└─ ContentBlock(最小描画単位: chart / text / metric ...)
この階層は、人間が動画を制作するときの思考順序と一致させている。
- まずシーンのレイアウトを決める(1 分割?2 分割?左右比率は?)
- 各エリアに何を配置するか決める(左にグラフ、右にテキスト)
- 必要なら重ね合わせを使う(フルスクリーンチャートの上に半透明マスク)
- 最後に各コンテンツの詳細を調整する
各階層の責務と決定の流れ
| 階層 | 責務 | 主な決定事項 |
|---|---|---|
| Video | 全体構成・メタ情報 | テーマ・フォーマット(長尺/ショート)・総尺・チャプター分割 |
| Scene | 1 画面の意図と時間 | 伝えたいこと(intent)・尺(duration)・ナレーション |
| Layer | z 軸の重ね合わせ | 背景 / コンテンツ / オーバーレイ / UI の 4 種を積み上げ |
| Layout | 平面の空間分割 | fullscreen / side-by-side / dashboard / header-content 等 |
| Slot | 分割された各エリア | スロット ID(primary / secondary / header / content 等) |
| ContentBlock | 最小描画単位 | bar-chart / line-chart / text-block / metric-card / title-card 等 |
ある階層の変更が他の階層に影響しないよう、各責務を厳密に分離している。たとえば Layout を side-by-side から fullscreen に変更しても、ContentBlock の内部実装は一切変わらない。スロットへの割り当てを更新するだけだ。
AI 生成とレビュー、型定義との相性
AI 生成との相性が良いという点が最も大きい。
montage の Composer エージェント(Claude Code 上で動作)が動画を生成する際、この階層構造に沿って上から順に決定を下す。まず Scene の intent を決め、Layer 構成を決め、Layout を選択し、各 Slot に ContentBlock を割り当てる。各ステップが局所的な判断であり、前後の文脈に過度に依存しない。
人間のレビューも容易になる。 「このシーンのレイアウトが変だ」と思ったとき、Layout だけを変更すればよい。字幕がずれているなら UI 層のみを修正する。問題の影響範囲が階層によって自然に限定される。
型定義との相性も強力だ。VideoSpec → Chapter → Scene → Layer → SlotAssignment → ContentBlock の型の入れ子は Zod でバリデーション可能であり、AI が生成した JSON の構造不正を即座に検出できる。
運用してわかった効果と落とし穴
効果
量産速度が上がった。 6 階層の定義が安定したあとは、Composer エージェントが同じスキーマに従って新しいシーンを生成できるようになった。人間が毎回構造を指定しなくても、パイプラインが自律的に動く。
変更への耐性が高まった。 テーマカラーを変えたい場合は Video レベルの Theme を差し替えれば全シーンに反映される。特定のシーンだけ変えたければ Scene レベルの style override を使う。この仕組みは「ハードコード禁止」原則(config 駆動設計の記事参照)と連動している。
落とし穴と対策
最初の型定義が甘いと後で詰まる。 ContentBlock の data フィールドを Record<string, unknown> のままにしていた時期があり、AI が任意の構造を入れてしまう問題が発生した。現在は各 ContentBlock タイプに対応した Zod スキーマを定義し、Composer 出力を全件バリデーションしている。バリデーション失敗時は Composer に理由を伝えて再実行させる仕組みで、出力の一貫性を確保している。
Layer の種類を増やしすぎない。 background / content / overlay / ui の 4 種に絞っているのには理由がある。自由度を上げるとコンポーザーの判断が分散し、一貫性が失われる。制約が創造性を支える典型例だ。
まとめ
トップダウン設計の本質は「決定の順序を固定すること」だ。大きい枠組みが決まってから小さい枠組みを決める。上位層の決定が下位層を拘束する。この一方向の流れが、AI エージェントと人間の両方にとって扱いやすい構造を生む。
montage の 6 階層(Video → Scene → Layer → Layout → Slot → ContentBlock)は、この原則を動画生成という具体的なドメインに適用した結果だ。同じ考え方はウェブサイトのコンポーネント設計にも、エージェントの責務分離(3 層分離の記事参照)にも、あらゆる階層的なシステム設計に応用できる。
「大きい枠組みから小さい枠組みへ」。シンプルだが、AI 時代の設計原則として有効だと感じている。
八雲が取り組む AI 駆動開発の全体像はこちらの記事で解説している。