explainer-video-pipeline (自動生成)
いつ使うか
ユーザーが科学、製品、技術などについて1〜3分のナレーション付き解説動画(MP4)を希望する場合。動画には音声、字幕、BGM、効果音が含まれます。
パラメータとデフォルト値
トピックだけを尋ね、それ以外はユーザーが明示的に指定しない限りデフォルト値を使用します。どの値を使用したかを1行で伝えてください。
| パラメータ | デフォルト | その他の値 |
|---|---|---|
topic | 必須 | — |
storyboard_model | claude-opus-5.5 が脚本・ナレーション・ストーリーボードを執筆 | kiro-cli chat --list-models で表示される任意のモデルID |
video_engine | opus-5.5: claude-opus-5.5 が各シーンの描画コードを執筆 | 別のコードモデル(例: claude-sonnet-5.5); seedance(BytePlus ModelArk API、ARK_API_KEY が必要); hybrid(コード描画シーン内に Seedance クリップを埋め込み) |
renderer | remotion(React/SVG、Remotion がヘッドレス Chromium を駆動) | html(Canvas 2D / SVG / GSAP / p5.js ページ、Playwright でキャプチャ); manim(Manim Community シーン、幾何学・グラフ・ベクトル・段階的導出に最適) |
seedance_model | seedance-1-5-pro-251215 | ユーザーのModelArkアカウントで有効な任意のSeedanceモデル |
tts | polly、ニューラル音声 Zhiyu、cmn-CN、us-east-1 | gtts(無料、キー不要、平坦な音声); その他の Polly 音声・言語 |
captions | オン: Whisper 単語タイミング、単語単位ハイライト付きで焼き込み | オフ |
whisper_model | small(CPU、int8、音声10秒に対し約5秒) | base(より高速)、medium(より正確なタイミング) |
music | synth(ffmpeg で生成するロイヤリティフリーの発振器BGM) | none; ユーザー所有の音楽ファイルのパス |
sfx | オン: scenes.json にリストされたイベントを合成し該当フレームに配置 | オフ: すべてのシーンから sfx を省略 |
language | 中国語(マンダリン)ナレーション | Polly と Whisper が両方サポートする任意の言語 |
size, fps | 1920×1080、30 fps | 縦向きの場合は 1080×1920 |
「Opus 5.5 で制作」とは、Opus 5.5 が作者であることを意味します。すなわち、脚本と描画コードを執筆し、レンダラーがそのコードをピクセルに変換します。テキストモデルが直接動画を出力することはありません。Seedance のみが動画を直接生成します。最初の返信でこのことを一度述べてください。
セッションがすでに claude-opus-5.5 上で動作している場合は、自分の力で執筆を行ってください。そうでない場合は、ストーリーボード(ステップ2)のために model="claude-opus-5.5" かつ keep=true のタスクを1つ起動し、シーンコード(ステップ5)のために同じ実行を spawn_continue で続け、その後自分でその出力を確認してください。
セットアップ(マシンごとに1回)
ツールは安定したキャッシュディレクトリ(例: ~/.cache/explainer-video/)に置き、セッション間で再利用される $KIROCREW_SCRATCH には決して置かないでください。
- ffmpeg:
aevalsrc、anoisesrc、tremolo、sidechaincompress、ass/libass を含む完全な静的ビルド。Remotion にバンドルされた ffmpeg にはこれらがありません。FFMPEG/FFPROBE環境変数でそれを指すように設定します。 - Python venv(
boto3 gTTS playwright faster-whisper pillow numpy)、その後その venv からpython -m playwright install chromium-headless-shellを実行します。 faster-whisper 1.2.x は PyAV 19 で壊れます(unexpected keyword argument 'metadata_errors')。av==16.1.0を固定してください。Whisper モデルが一度だけダウンロードされるようにHF_HOMEをキャッシュディレクトリに設定します。 - Manim(
renderer=manimの場合のみ): pip では aarch64 でビルドできません(pycairo、manimpango、moderngl の wheel がありません)。root 権限がない場合は micromamba を使用します:micromamba create -p <cache>/manim-env -c conda-forge python=3.12 manimText()はCJKフォントで動作します。MathTex/Texには LaTeX ディストリビューションとdvisvgmが必要です。conda-forge のtexlive-coreは aarch64 でlatex.fmtがないため、数式はそこで失敗します。数式はText()で書くか(Unicode: F = m·a, x², √, →)、システムの TeX Live をユーザーがインストールできる場所にインストールしてください。
手順
ヘルパーはこのスキルの scripts/ フォルダにあります。
- プロジェクト. ユーザーのワークスペース下にgitリポジトリとしてプロジェクトフォルダを作成します。
renderer=remotionの場合、package.json、tsconfig.json(resolveJsonModule: true)、src/index.ts、src/Root.tsxを手動で雛形作成し、npm i remotion @remotion/cli react react-domを実行します。 - 脚本とストーリーボード(
storyboard_modelが担当)。scenes.jsonを作成します。各シーンはid、narration(話す台詞)、visual(画面に表示される内容)、オプションのmanim(Scene クラス名)、オプションのsfx:[{"at": FRAME_IN_SCENE, "kind": "whoosh|hiss|pop|rise|thud|PATH"}]を含むオブジェクトです。タイトルシーンとエンドカードを含め、1つのアイデアにつき6〜10シーンを使用します。ウェブ検索で事実を確認し、README に出典を引用します。 - 参考画像. 動画に実在の物体が登場する場合、明確な写真を探すかユーザーに依頼し、
ref/に保存します。記憶だけで実在物体の形状を描かないでください。写真にエッジ検出を適用し、キーポイントを測定し、それらの点から形状を生成する小さなスクリプトをリポジトリに保存して使用します。 - ナレーションがタイミングを決定.
narrate.py scenes.json . --tts pollyを実行します。これによりdurations.json(実際の音声長さ+パディングから計算されたシーンごとのフレーム数)、narration.wav、audio/sNN.mp3が作成されます。シーンコードはdurations.jsonを読み込むため、各シーンは台詞の長さだけ継続します。 - シーンコード(
video_engineが担当)。remotion: シーンごとに1つのReactコンポーネントを作成し、useCurrentFrameとinterpolate/springを使用してシーンの開始を基準にアニメーションさせます。html: 1つのindex.htmlにwindow.seek = async (frame) => {...}関数を実装し、フレーム番号とdurations.json配列から正確にそのフレームを描画します。requestAnimationFrame、壁時計、シード指定のないMath.randomは使用禁止。durations.json配列を定数としてページ内に貼り付けます。file://で開かれたページはfetch()でローカルファイルを取得できず、失敗は黙って行われます。GSAP: 一時停止タイムライン +tl.seek(frame / fps)。p5.js:noLoop()+seek内でredraw()。manim: 1つのscenes.pyにシーンごとのSceneクラスを作成します。ターゲット長をos.environ["SCENE_SECONDS"]から読み取り、self.wait(max(0.04, secs - self.renderer.time))で終了します。長いアニメーションのサイズもsecsから決定します。フレームの下部15%を字幕用に空けておきます。seedance:ARK_API_KEYを設定してseedance_clips.py scenes.json .を実行します。clips/<id>.mp4をダウンロードします(URLは24時間で期限切れ)。
- フルレンダリング前に静止画を確認. キーシーンから4〜6フレームをレンダリングし、1枚の縮小コンタクトシートにまとめて、その1枚の画像を確認します。独立した確認のために、新しいレビューアーを起動してシートと
scenes.jsonだけを渡すこともできます。 - 音声. いずれかのシーンに
sfxがある場合、sfx.py scenes.json .を実行します。その後mix_bgm.py . --music <music>を実行します。これは音楽を音声の下にダッキングし、sfx.wavを追加し、narration_bgm.wavを書き出し、RMSレベルを表示します。音楽のみのリードインは約−20〜−30 dB にします。−55 dB 以下ではほぼ聞こえません。 - 字幕.
captions.py scenes.json . --size <WxH>は faster-whisper の単語タイムスタンプを使用して各行を書き起こし、それをスクリプトの文字にマッピングします(Whisper が同音異義語を誤認識するため、例えば「気体」を「漆体」と聞くことがあります)。captions.ass(各文字が話されたときにハイライト)とwords.json(文字ごとのタイミング、ステップ5で画面上の強調に使用可能)を書き出します。 - レンダリング(映像のみの無音動画)。
remotion:npx remotion render src/index.ts <Comp> out/silent.mp4html:capture_html.py index.html out/silent.mp4 --frames <durations.json の合計>manim:manim_scenes.py scenes.py . --manim <manim-env>/bin/manim --quality h。各クラスをレンダリングし、正確なフレーム数になるようにパディングまたはトリミングします。
- FFmpegで合成. 字幕あり:
ffmpeg -i silent.mp4 -i narration_bgm.wav -vf "ass=captions.ass" -c:v libx264 -crf 18 -pix_fmt yuv420p -c:a aac -b:a 192k -shortest final.mp4(字幕なしの場合は-c:v copyを使用し-vfを削除)。動画と音声の長さが約0.1秒以内で一致していることを確認し、最終的な MP4 から4〜5フレームを取得して確認します。特に文の途中で字幕のハイライトが正しいか確認します。 - 納品. フィーチャーブランチにコミットし、PRを作成します。マージ後、
gh api repos/<o>/<r>/git/trees/<base>?recursive=1でファイルが正しく配置されたことを確認します。
注意点
- SVGパスの
d=文字列内に/* */形式のコメントを入れないでください。Chromium は/で解析を停止します。6桁のHEXカラーを使用してください。 - ハードコードされた絶対フレーム番号を持つコードは、シーンのクライマックスがシーン終了後に発生する可能性があります。
- Manimでは、オブジェクトが移動した後にラベルや矢印を配置するか(あるいは
always_redraw/add_updaterでアタッチする)、そうしないと古い位置に留まります。DashedVMobjectは独自のポイントを持たないため、通常の図形から位置を取得してください。 - pip でインストールされた Playwright は、キャッシュされたものよりも新しい Chromium ビルドを必要とする場合があります。
- 複数の並列
strReplace呼び出しで1つのファイルを編集しないでください。編集が失われます。シェルのヒアドキュメントでコードを記述しないでください。ガードレールがブロックする可能性があります。 - Seedance 2.x モデルはアカウントのアクティベーションが必要で、実在の人間の顔を含む参照画像を拒否します。Seedance 1.5 pro のクリップは4〜12秒です。
- Remotion ライセンス: 個人および3人以下の企業は無料です。より大規模な企業は有料の Company License が必要です。
htmlとmanimはそれを回避します。