Opus 5.5の動画プロジェクトにナレーションと字幕を付ける方法
Opus 5.5のRemotionプロジェクトで、ナレーションと文単位の字幕のタイミングを合わせます。動作するMP4・WAV・SRT・ソースに加え、タイミングの確認方法とずれの直し方も紹介します。
Opus 5.5の動画にナレーションと字幕を付けるときは、音声のタイミングをプロジェクトのデータとして扱います。 ナレーションを作成または録音して長さを測り、各文をタイムラインに割り当ててから、音声と字幕を一緒にレンダリングします。実際のタイミングを渡さずに、モデルへ「字幕を同期させて」と頼むだけでは不十分です。
このチュートリアルでは、製品デモの作り方と同じ、実際のスクリーンショットを使ったプロジェクトを使います。その記事を先に終えていなくても、ダウンロード用ファイルから始められます。ここでの目標は、読みやすい文単位の字幕、編集可能なタイミングデータ、別ファイルのSRTを備えた、ナレーション付き30秒MP4を作ることです。新しいプロンプト集でも、検証されていない自動吹き替えの約束でもありません。
音声付きの例を見て確認する
英語の合成参考音声を使い、Remotionから実際に書き出した動画です。この音声はあくまでタイミング確認用で、プロのナレーション品質を示すものではありません。字幕は文単位で表示され、読むための保持時間を含みます。
プロジェクト一式、ナレーション付きMP4、参考用WAV、英語SRTをダウンロードできます。5言語の記事はこの英語の例を共有しています。言語ごとに5本の音声を制作したものとして示しているわけではありません。
実際のモデル呼び出しでは、ファーストパーティのClaude Codeでclaude-opus-5-5を使い、Remotionのコードを生成しました。渡したのはファイル名と文章によるシーン指示で、画像のピクセルや音声の録音は渡していません。その後、実際の元キャプチャを用意し、eSpeak NGで参考音声を生成し、コードを修正してローカルでレンダリングしました。この役割分担がこのチュートリアルの要点です。Opusはコードを書き、音声合成エンジンが音声を作り、Remotionが最終ファイルを作りました。
タイミングの進め方を選ぶ
出発点は主に2つあります。台本とシーンの長さにまだ融通が利くなら、承認済みの音声を先に録音または合成し、そのペースに映像を合わせます。承認済みの30秒枠に収める必要があるなら、先にシーンの区間を決め、自然に収まらない文を短くします。
この例は後者です。既存の5つのシーンと、5つの短い文があります。各音声区間は割り当てられた字幕の区間内に収まる必要があり、参考音声のスクリプトは終了時刻を超える区間をエラーにします。この確認によって、よくあるタイプの同期ミスをレンダリング前に見つけられます。
| 手元の素材 | 推奨する方法 | 主に確認するリスク |
|---|---|---|
| 承認済みの連続したナレーション | 長さの測定や文字起こしをしてから、実際の発話に合わせて映像と字幕を配置する | 単語数から文のタイミングを推測すること |
| 長さが固定された製品動画 | シーンごとに短い文を書き、録音ごとに長さを測る | 固定のカットに合わせるため、文を早口にしたり途中で切ったりすること |
| 音声付きの既存動画 | 実際の音声トラックからタイムスタンプを取得し、確認する | 自動文字起こしを検証済みの字幕ファイルとして扱うこと |
| 多言語版 | 言語ごとに録音し直し、タイミングを取り直す | 発話の長さが変わったのに、英語のタイミングを使い回すこと |
Remotionの字幕に関するドキュメントでは、字幕の読み込み、表示、書き出しを扱っています。このプロジェクトでは、タイミングが目に見えて確認しやすいように、あえて文単位の小さなJSONスケジュールを使っています。自動文字起こしや強制アラインメントは行っていません。
同梱の音声から始めて、差し替える
プロジェクトを実行する前に、Node.jsとnpmをインストールしてください。後述するターミナルでのメディア確認(任意)には、ffprobeを含むFFmpegを別途インストールする必要があります。npm ciではこのシェルコマンドはインストールされません。任意の確認コマンドを使わなくても、同梱のnpmスクリプトでレンダリングできます。
アーカイブを展開し、ルートフォルダーからプロジェクトを実行します。
npm ci
npm start
DemoNarratedを選びます。アーカイブにはすでにpublic/narration.wavが含まれているため、レンダリングのために音声合成エンジンをインストールしたり、音声サービスを購入したりする必要はありません。冒頭付近の最初の文、13秒付近のドキュメントの文、27秒付近の最後の文を確認してください。

WAV音声トラックを含むプロジェクトの実際のプレビューです。波形が見えることで、プロジェクトに音声が含まれていることは確認できます。ただし、発音の品質や単語単位の同期を示すものではありません。
参考音声を再現するには、お使いのシステム向けの公式手順でeSpeak NGをインストールし、次を実行します。
python3 scripts/make_audio.py
npm run render:narrated
使用したのはeSpeak NG 1.52.0、en-usの音声で、速度は毎分190語に設定しました。このフォルマント方式の音声は、意図的に合成音らしいままにしています。最終的なナレーションを決める前にタイムラインを検証するのに役立ちます。この数値はツールの設定値であり、すべての文がまったく同じ速さで話されることを保証するものではありません。
実際に公開するキャンペーンでは、公開の許可を得た録音や音声出力を使ってください。製品名、略語、句読点での間、各文の最後の単語を聞いて確認します。文字起こしが正しくても、声が自然に聞こえるかどうかは分かりません。この記事で測定・確認したのは長さ、配置、表示される字幕であり、人による発音や演技の評価ではありません。
WAV、字幕、SRTに1つのスケジュールを使う
scripts/make_audio.pyを開きます。その中のLINES配列が参照元で、各項目に開始時刻、字幕の終了時刻、テキストがあります。スクリプトを実行すると、30秒のWAV、src/captions.json、public/captions.en.srt、audio-timing.jsonが生成されます。コンポジションは生成されたJSONを読み込むため、動画コードの中に手作業で編集する字幕リストを別に持つ必要がありません。
参考音声の各区間の測定値は次のとおりです。表の英文は、5言語の記事で共通して使っている英語の音声トラックで実際に話されている文なので、翻訳せずにそのまま載せています。
| 文 | 開始 | WAV区間の長さ | 区間の終了 | 字幕の終了 |
|---|---|---|---|---|
| A clear product video starts with a clear brief. | 0.35秒 | 2.664秒 | 3.014秒 | 3.60秒 |
| Show the real interface. Here, we begin with the model catalog. | 4.35秒 | 3.681秒 | 8.031秒 | 9.80秒 |
| Then show where a viewer can find the documentation. | 11.35秒 | 2.917秒 | 14.267秒 | 16.80秒 |
| Connect each scene to an actual page, such as this API reference. | 18.35秒 | 3.743秒 | 22.093秒 | 23.80秒 |
| Keep the message simple. Plan, build, and verify. | 25.35秒 | 3.537秒 | 28.887秒 | 29.50秒 |
これらの長さには、生成された区間の末尾のサンプルも含まれています。個々の音素を測定した値ではありません。字幕は意図的に、発話が終わったあとも表示し続けます。たとえばドキュメントの文では、WAV区間のあとに約2.53秒の読むための時間があります。字幕のタイミングをもっと詰めたい場合は、実際のナレーションを確認したうえでこの保持時間を短くしてください。
スクリプトは各区間の前後に無音を入れ、表に示した絶対開始時刻に音声を配置します。長すぎる文を区間に収めるために再生速度を上げることはしません。修正した文が収まらなくなった場合は明示的なエラーが出るので、レンダリング前に文を短くするか、終了時刻を動かしてください。
連続した差し替え用の録音を使う場合は、準備の手順が異なります。全長のpublic/narration.wavを1つ書き出し、src/captions.jsonとSRTを実際の録音に合わせて編集します。その録音を参考音声で上書きするつもりがない限り、そのあとでmake_audio.pyを実行しないでください。元の録音と生成した例は、別々のバージョンとして保存しておきます。
秒をフレームに慎重に変換する
コンポジションは30 fpsです。11.35秒に始まる字幕は、動画のフレームとフレームの間に当たります。最終コードでは最初に表示するフレームをMath.floor(start * fps)で求めるため、この文はフレーム340(約11.333秒)で表示されます。音声が始まるわずかに前です。最初に話される単語を隠してしまうフェードインはありません。最後の6フレームで短いフェードアウトが入ります。
const first = Math.floor(caption.start * fps);
const last = Math.round(caption.end * fps);
const visible = frame >= first && frame < last;
これは最終的な表示ルールを示したもので、完全なコンポーネントではテキストのレイアウトや終了時のフェードも設定しています。フレームの丸めは想定どおりの挙動です。30 fpsの映像タイムラインをもとに、サンプル単位で正確な音声同期を主張してはいけません。
同梱のRemotion 4.0.424プロジェクトでは、remotionからAudioをインポートし、staticFileでWAVを参照しています。現在のRemotionのドキュメントでは、この旧来のHTML5コンポーネントをHtml5Audioとして説明しており、新たに音声を組み込む場合は新しいメディアコンポーネントを推奨しています。このアーカイブを再現するときは、固定されたバージョンのまま使ってください。最新ドキュメントでのAPI変更と、理由の説明できないパッケージのアップグレードを混ぜてはいけません。
単語を隠さずに字幕を読みやすく保つ
横長のコンポジションでは、スクリーンショットとは別の暗い帯に字幕を置いています。ドキュメントとAPIのシーンでは、シーンのタイトルが左、文の字幕が右に配置されます。縦型版では画像と字幕を縦に積み重ねています。その配置は縦型動画のチュートリアルを参照してください。
英語の字幕の文字サイズは、横長で28ピクセル、縦型で30ピクセルです。これはこのプロジェクトで決めた値であり、SNSプラットフォーム共通のルールではありません。今回の文の長さは、確認したレイアウトに収まっています。翻訳で文が長くなると、収まらない可能性があります。
モデルの初期コードでは、CSSのline-clampで文字を2行に制限していました。編集後に3行目が気づかないうちに隠れるおそれがあるため、この指定は削除しました。長すぎる字幕への正しい対処は、文を分けるか言い換える、スペースを広げる、レイアウトを見直すことです。欠けた単語を見えなくすることではありません。
テキストを変更したら、最初の字幕、最も長い字幕、最後の字幕を、想定する表示サイズで確認します。システムフォントの代替によって改行位置が変わることがあり、アーカイブはすべてのOSで同じ組版になることを保証しません。ブランドフォントを固定したい場合は、適切なライセンスのフォントを同梱してレンダリング前に読み込み、これらの確認をやり直してください。
範囲を限定したタイミング修正をOpusに依頼する
この調整用プロンプトは、自分のナレーションを測定したあとに使うと役立ちます。プレースホルダーは実際の時刻に置き換えてください。これは追加のモデルテストとして実行したものではありません。
既存のDemoNarratedコンポジションだけを更新してください。
承認済みのスクリーンショット、30 fps、現在のシーン順は維持すること。
差し替えるナレーションは public/narration.wav です。
以下は測定済みの文ごとの区間です(秒):
[開始、終了、実際に話されるテキストを貼り付け]
字幕のデータソースは1つにすること。話される単語はすべて残すこと。
各文は最初に話される単語と同時かそれより前に表示し、フレームの丸めについて説明すること。
単語ごとのタイムスタンプや自動文字起こしの結果を捏造しないこと。
読むための保持時間は、私が明示的に指定した箇所にだけ設けること。
はみ出しを隠すためにline-clampを使わないこと。
文がシーンのカットをまたぐ場合は、音声を黙って切り詰めず、その文を指摘すること。
変更したファイル、タイミングの前提、確認すべきフレームを返すこと。
変更後は、テキストをナレーションと照合してから映像を確認します。カタログが画面に映っている間にAPIページの説明が流れるなら、それぞれのファイルは単体では正しくても、組み合わせたストーリーは間違っています。共通のシーンスケジュールか録音を修正してください。字幕のオフセットを調整するだけでは、ナレーションと映像の食い違いは直りません。
実際のファイルを書き出して診断する
npm run render:narrated
ffprobe -v error -show_entries stream=codec_name,codec_type,duration,sample_rate \
-show_entries format=duration -of json out/narrated.mp4
レンダリングした例には、H.264の映像ストリームとAACの音声ストリームがあります。映像のタイムラインは30秒ですが、圧縮音声ではエンコーダーのパディングにより、ストリームやコンテナの長さがわずかに異なって報告されることがあります。参考用WAVはちょうど30秒です。AACの短い末尾をシーンの長さのエラーと解釈せず、実際に聞こえる内容と同期を確認してください。
| 症状 | 確認すべき箇所 | 変更する内容 |
|---|---|---|
| MP4全体が無音 | コンポジション、ミュートフラグ、WAVのパス、ストリームのメタデータ | render:narratedを使い、音声素材を確認し、ミュート状態でレンダリングしていないことを確かめる。 |
| すべての文が同じだけ遅れる | 冒頭の無音、または共通の開始オフセット | その1つのオフセットを修正し、最初と最後の文を再確認する。 |
| 動画が進むにつれてずれが大きくなる | 長さの前提、音声の速度、元のタイムラインの誤り | 実際の録音を測定する。推測した単語数をもとに字幕を1つずつ直さない。 |
| 1つの文がカットをまたぐ | その文の長さとシーンの境界 | 文を短くするか録音し直す。または、シーンとそれに依存するすべてのタイミングを延ばす。 |
| 画面上で単語が欠ける | テキストの折り返しと固定サイズの字幕ボックス | 文を分けるかレイアウトのサイズを変える。はみ出しを隠さない。 |
| プレビューでは音が出るが、最終書き出しでは出ない | 最終ファイルとレンダリングコマンド | Studioの波形だけでなく、MP4の音声ストリームを確認する。 |
| SRTと焼き込み字幕の内容が違う | 最後に編集したソースと再生成の順序 | 同じスケジュールから再生成する。差し替え録音の場合は両方を意図的に更新する。 |
納品前に、書き出したファイル全体を音声付きで再生し、各文の開始と終了を確認してください。公開先のプラットフォームにアップロードしたバージョンも確認します。焼き込み字幕は映像のピクセルとして常に表示されますが、別ファイルのSRTはプラットフォームが対応し、有効になっているかどうかに左右されます。この例では両方を用意していますが、どちらもSNSにアップロードしたとは主張していません。
音声作業とモデルへのアクセスを分けて考える
Opus 5.5のモデルページは、このコーディングワークフローに関係するモデルを示すページです。この例は、OfoxでTTSが使えることや、動画レンダリングが課金対象になることを示すものではありません。記録したモデル呼び出しにはファーストパーティのClaude Codeを使い、音声はローカルで作成しました。
制作全体の流れはOpus動画のメインガイド、素材の選び方はスクリーンショットを使ったデモのチュートリアルを参照してください。モバイル中心の形式で公開する前には縦型への調整をご覧ください。確実な引き継ぎには、最終MP4、WAV、対応する字幕ファイル、そしてそれらを生成したプロジェクトの正確なバージョンをそろえておく必要があります。
よくある質問
- ナレーションはOpus 5.5が生成したのですか?
- いいえ。Opusが生成したのは動画プロジェクトのコードです。この例では、合成音声であることを明示したeSpeak NGの参考用音声を使い、RemotionがそのWAVを映像と合成しています。
- 単語単位で同期した字幕ですか?
- いいえ。この例では、あらかじめタイミングを決めた5つの文単位の字幕を使い、各音声区間のあとに読むための時間を余分に取っています。単語単位のハイライトには、実際の単語タイムスタンプと別途の検証が必要です。
- 動画のデザインを作り直さずに音声だけ差し替えられますか?
- はい。承認済みの映像はそのままに、音声を差し替えて字幕のタイミングを合わせてください。新しいナレーションがシーンやプロジェクトの長さを超える場合は、書き出す前に共通のタイムラインを修正します。


