ナレーション同期アニメーション広告
基本原則
聞こえるもの=見えるもの。 ナレーションがタイミングを決定します。最初に録音し、Whisperが各単語の時間を割り出します。すべてのテキスト、シーン、通知、エフェクトは単語に合わせて配置されます。コード内にフレーム番号はありません。at: 'お客様' と書けば、時間は public/words.json から自動取得されます。新しい録音を追加したら npm run vo を実行するだけで、動画全体が自動で調整されます。
画面上のどの瞬間も静止させません。動きのない1秒=視聴者がスクロールして離れます。
絶対ルール
- あなたは音声を聴いてはいけません。 事業者が唯一の聴き手です。あなたによる音声チェックは数値ベースのみ(
silencedetect、ffprobe、再文字起こし)。出力を引用せずに「音声は正常です」と書くことは禁止です。 - まず無音を除去し、その後文字起こしを行います。 Whisperは無音付近でタイミングを誤ります。
prep-vo.shが正しい順序で両方を実行します。 - 音声を変更した後は、必ず
npm run voを再実行してください。 これを怠ると、すべての同期がずれます。 - 動画はナレーション終了+8フレームで終了します(
time.tsのDURATION)。render-all.shは各ファイルの長さをナレーションと比較して表示します。異なる場合は、どこかでクリッピングが発生しています。 - テキストは y=260 から y=1570 の間にのみ配置します。 それより上または下はInstagramによって隠されます。
validate()はテキストがこの範囲外、または幅1000pxを超える場合、説明とともにレンダリングを停止します。 - エフェクトは音声よりも小さくします。
Ad.tsxで固定:ナレーション1.15、音楽0.22、すべてのエフェクトはSFX = 0.38を乗算。「エフェクトが大きい」=この数値を変更します。 - フルレンダリング前にスチルを確認します。
npm run checkで10フレームがout/stillsにレンダリングされます。すべてを確認(PNGを読む)してからフルレンダリングを行います。 - 本物のコンテンツのみ。 顧客の数字、支払い、メッセージは実際に発生したものに限ります。名前は伏せても構いませんが、結果を捏造してはいけません。Metaのポリシーに加え、ユーザーは偽物を見抜きます。
- ヘブライ語: フォント(Rubik、Heebo、可変、OFL)はテンプレートに含まれており、
delayRenderで読み込まれます。ルートはdirection: rtl。ラベル内の数字はdirection: ltrを適用します。
プロジェクトの初回セットアップ
cp -R ~/.claude/skills/animated-voiceover-ad/template ~/ads/<広告名>
cd ~/ads/<広告名>
npm install
npm run setup # Mixkitからエフェクトと音楽を取得
必要なもの:Node 18+、ffmpeg、whisper-cli(brew install ffmpeg whisper-cpp)、およびWhisperモデル ~/.whisper/models/ggml-large-v3-turbo.bin(ない場合、words.mjs がダウンロードコマンドを表示します)。
パイプライン
| ステップ | 作業内容 |
|---|---|
| 1. スクリプト | references/script-formula.md に従います。各文は事前にシーンにマッピングされます。録音前に事業者に見せます。 |
| 2. 録音 | スマートフォンまたはQuickTimeで、1ファイル。間違えたら一時停止し、その文だけ最初からやり直します。後で悪いテイクを削除します(references/audio.md 参照)。 |
| 3. クリーニングと文字起こし | npm run vo -- recording.m4a。すべての単語をタイムスタンプ付きで表示します。文字起こしを事業者に見せ、Whisperが誤認識した単語を public/words.json で直接修正します(w のみ)。 |
| 4. ディレクション | src/Ad.tsx のみを編集:KTS(キネティックテキスト)、通知、SCENES。すべての時間は単語基準:['もう一つ', 2] は2回目の出現。コンポーネントの詳細は references/scenes.md を参照。 |
| 5. 確認 | npm run check(tsc + スチル)。すべてのスチルを確認。 |
| 6. レンダリング | npm run render。MUSICS(Root.tsx)内の各音楽は、out/ 内に個別ファイルとして出力され、A/Bテストが可能。 |
| 7. 修正 | 事業者からのコメントは、それぞれ1つの定数変更として対応:at 内の単語変更、音量、until。シーンを書き直す必要はありません。 |
広告用バリエーション
- 音楽: 組み込み済み、3つのコンポジション。
- 異なるイントロ: 最初の3秒が重要です。2~3種類の異なるフックを個別ファイルとして録音し、それぞれを
ffmpeg concatで本体と結合し、各結合に対してnpm run voを実行して個別のフォルダにレンダリングします。本体の単語が同じであれば、Ad.tsxはすべて同一のままです。 - フル字幕:
Ad.tsxでCAPTIONS = trueに設定。1行で、句読点で折り返します。広告の視聴の多くが無音であるため有用です。
既知の問題
| 問題 | 解決策 |
|---|---|
ナレーションに単語 "X" が見つかりません | メッセージは類似単語を提案します。ヘブライ語ではWhisperが接頭辞(ו/ה/ל/ב)を結合または分割します。words.json にある通りの単語を使用します。 |
| レンダリングに古いコードが表示される | $TMPDIR/remotion-webpack-bundle-* に古いバンドルがあります。render-all.sh がそれを削除します。 |
| TypeScript 7 がインストールされている | Remotionは [email protected] を必要とします。 |
delayRender がスタックする | --timeout=180000(render-all に既に含まれています)。 |
| スタンプが着地前に縮む | スプリングに overshootClamping: true を設定(既に実装済み)。 |
| 無音除去後に単語がくっつく | prep-vo.sh の stop_duration を0.35に上げます。 |
| 「退屈な」1秒がある | その単語にKT行、通知、またはエフェクトを追加します。イベントのない1秒を作らないでください。 |
テンプレートのデモ
テンプレートにはデモナレーション(TTS音声、public/vo.wav + public/words.json)と、それに同期した Ad.tsx が付属しており、録音前にすべてが動作することを確認できます:npm install && npm run setup && npm run check。実際の広告では、npm run vo -- recording.m4a でこれら両方を上書きし、その後スクリプトに従って Ad.tsx を最初から書き直します。