ショートフォーム編集 — 素材を投稿可能なショート動画にカットする
あなたは編集室の技術者です。 誰かが本物の映像(トーキングヘッドのテイク、スクリーン録画、ナレーション、Bロールなど)を差し出し、あなたはそれをポスト可能な縦型ショート動画に仕上げます。無音を除去し、カットは高速に、字幕は単語単位で焼き込み、モーションはビートに合わせて、規定通りの出力を行います。あなたはピクセルとタイミングをエンコードします。言葉を書いたりフックを選んだりはしません。
厳格基準は検証可能なファイルです:焼き込み字幕入りの1080x1920 H.264 MP4で、ffprobeで確認できること。さらには中間成果物(カットリスト、.ass/.srt、ビートグリッド)も含みます。ffprobeで結果を確認し、仕様を満たしていなければ完了ではありません。
スコープ:3つのスキルが「縦型動画」に関わる — 自分の役割を理解せよ
| 依頼内容 | 担当先 | 成果物 |
|---|---|---|
| 脚本、フック、ビート、画面上のキャプションテキスト、編集決定シートを作成する | ../video-shorts/SKILL.md | .md 脚本ファイル |
| 実映像をカット/キャプション/出力する(ツール非依存) | ここ | 編集済み .mp4 + キャプション/カットファイル |
Remotion React コンポジションプロジェクト(<TransitionSeries>、ヘッドレスレンダリング)を構築する | ../remotion-video/SKILL.md | .tsx プロジェクト |
ワンライナーのルーティング:映像入力 → カット、キャプション、出力 → このスキル。 言葉や計画 → video-shorts。Reactコードベース → remotion-video。この3つの中でツールポータブルなのはあなただけです。
最初にルートを選べ
ツールを選ぶ前にカットを始めてはいけません。選択は「誰が実行するか」と「再現性が必要か」に依存します。
| 状況 | ルート | 理由 |
|---|---|---|
| 再現可能 / バッチ / CI / 「これを40クリップに適用」 | ffmpeg + WhisperX | スクリプト可能、決定論的、GUI不要 — 同じ入力、同じ出力 |
| リポジトリがすでにRemotionプロジェクト | @remotion/captions | 既存のコンポジショングラフを再利用;シェルアウトしない |
| 人間が1本の動画を手作業で仕上げる | CapCut クリックパス | 単一の手動パスで最速、自動キャプション+自動ビートマーカー機能付き |
このスキルの残りの部分はffmpeg + WhisperX パイプライン(再現可能なパス)であり、RemotionとCapCutのルートは違いがある箇所で注記します。長いコマンドブロックは references/ffmpeg-pipeline.md に、キャプションの詳細は references/captions.md にあります。
再現可能なパイプライン(順序通り)
これが骨子です。上から下に実行し、各ステップが次のステップにデータを渡します。
1. 文字起こし用にクリーンなモノラル16kHzオーディオトラックを抽出する。
ffmpeg -i in.mp4 -vn -ac 1 -ar 16000 a.wav
理由:モノラル16kHzはWhisperモデルが期待する形式です。ステレオ48kHzを入力すると時間を浪費し、精度に変化はありません。
2. 単語レベルのタイムスタンプで文字起こしする。 セグメントのタイムスタンプだけでは不十分です。単語ごとのキャプションには単語ごとのタイミングが必要です。
whisperx a.wav --model large-v3 --output_format json --highlight_words True
WhisperX(v3.8.5)はfaster-whisperにwav2vec2の強制アライメントを組み合わせ、100ミリ秒未満の精度で単語タイミングを提供します。これはカラオケハイライトの最低限の精度です。faster-whisper単体でも word_timestamps=True で動作しますが(約10%のオーバーヘッド)、単語境界のズレが大きくなります。理由:強制アライメントが必要な理由 — Whisperのネイティブ単語タイムスタンプは補間されておりジッターが発生しますが、強制アライメントは各単語を音声に正確に固定します。 インストール方法とJSONの構造については references/captions.md を参照してください。
3. 無音を検出し、ビデオとオーディオを一緒にカットする。 これが多くの人が間違えるステップです。
# パス1:無音範囲を検出する(発話しきい値)
ffmpeg -i in.mp4 -af silencedetect=noise=-25dB:d=0.3 -f null - 2> silence.log
silenceremove を単体で使うとオーディオのみのフィルターであり、ビデオが非同期になります — 決してワンショットで使わないでください。silence.log から silence_start / silence_end の行を解析し、保持範囲に反転させ、両方のストリームから同じ範囲を削除する select + aselect フィルター(または trim+concat グラフ)を構築します。しきい値:発話 noise=-25dB:d=0.3;音楽 noise=-40dB:d=1。フィルター生成のスニペットは references/ffmpeg-pipeline.md にあります。
4. ビートグリッドを構築する(音楽に合わせてカットする場合のみ)。
python -c "import librosa; y,sr=librosa.load('music.wav'); \
_,b=librosa.beat.beat_track(y=y,sr=sr,units='time'); print(*b,sep='\n')" > beats.txt
beats.txt はビート時間(秒)のリストです。CapCutはこれらのマーカーを波形に自動的に配置します。librosa(またはaubio)はスクリプトで同じグリッドを提供します。
5. カットポイントとズームキーフレームを最も近いビートにスナップする。 各カット時刻を beats.txt 内の最も近い値に丸めます。ビートに合わせたズームパンチはエネルギーを感じさせます。ビート同期の「使用すべきでない場合」については後述します。
6. カラオケ .ass キャプションを焼き込む。
ffmpeg -i tightened.mp4 -vf "ass=captions.ass" -c:a copy captioned.mp4
.ass は、ステップ2の単語タイムスタンプとセーフゾーンマージンから構築された単語ごとの \k タイミングを保持します。生成の詳細とテンプレートは「カラオケキャプション」セクションにあります。
7. プラットフォームマスターをエクスポートする(「出力仕様」を参照)。
カラオケキャプション
単語ごとのキャプションが特徴的なルックです。セグメントタイムスタンプではなく、単語タイムスタンプから構築してください。
- タイミング。 各単語の画面上のハイライトは、強制アライメントによる開始/終了時刻から来ます。
.assでは、\k<センチ秒>タグが単語ごとにカラオケフィルを進めます。セグメントタイミングから単語ごとに作成するとジッターが発生し、間違った単語にハイライトが当たります — 常にステップ2の単語ごとのタイムスタンプを使用してください。 - 無音視聴での可読性。 大きく太いサンセリフ体、太い輪郭/ストローク、必要に応じてドロップシャドウ。人々はミュートで見ています:一目で読めない場合、スマホでは失敗です。画面上で一度に2行以内 / 約6単語以内に抑えてください。
- セーフゾーン — 見落としがちな点。 キャプションは縦方向の中央帯に配置し、下部には配置しないでください。プラットフォームのUI(右側のアイコン、下部のキャプション/CTA/プロフィール)は、下部の約15~20%と右端を覆います。キャプションとキーテキストは、
1080x1920フレームの中央約80%に収めてください。下部に焼き込まれたキャプションはTikTokのボタンの後ろに隠れます — これが「キャプションが壊れている」という最も多い原因です。
最小限の .ass スタイルブロック(完全なテンプレートは references/captions.md にあります):
[V4+ Styles]
Style: Karaoke,Montserrat,64,&H00FFFFFF,&H0000FFFF,&H00000000,&H64000000,-1,0,0,0,100,100,0,0,1,5,2,5,80,80,640,1
末尾の 640 が行を中央帯に持ち上げます。太い Outline(5)はどんな背景でも可読性を保ちます。
Remotion ルート: Remotionプロジェクト内であれば、@remotion/captions — createTikTokStyleCaptions({ captions, combineTokensWithinMilliseconds }) を使用してトークンをページ分割します。低い値(200~500 ms)は単語ごとのポップ、高い値(1200~2000 ms)はフレーズ単位のページになります。 durationMs はv4.0.261で追加されました。 CapCut ルート: テキスト → 自動キャプション → 生成、その後スタイル変更。
ビート同期
ビートグリッド(ステップ4)は秒のリストです。カットポイントとズームキーフレームを最も近いビートにスナップして、モーションが音楽に合うようにします。
- 悪い → 良い。 単語の途中でカットをビートに正確に合わせると、ミスと認識されます → カットを、発話境界も尊重する最も近いビートに微調整してください。ビートよりも言葉を優先してください。
- ビートカットをすべきでない場合。 言葉が価値を伝えるトーキングヘッドの説明動画では、明瞭さがリズムに勝ります。人の話の途中でビートカットすると、その人の話し方が途切れます。ビート同期はBロールのモンタージュ、トランジション、音楽主導のセグメントにのみ使用してください。
- トランジションは安く、速く。 ハードカットがデフォルトです。ビートに合わせてのみ、ウィップパンやズームパンチを使用します。30秒のショート動画で1秒のクロスフェードは避けてください — ペースを殺します。ショートは高速なハードカットで成り立っています。
出力仕様
ユニバーサルな縦型マスター — 3つのプラットフォームすべてでクリーンに再生される1つのファイル:
ffmpeg -i captioned.mp4 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2,setsar=1" \
-c:v libx264 -profile:v high -pix_fmt yuv420p -r 30 \
-c:a aac -b:a 192k -ar 48000 -ac 2 \
-movflags +faststart out.mp4
yuv420p(広範な再生互換性)、+faststart(Webストリーミングで完全ダウンロード前に再生開始)、AAC-LC 48kHz。30fpsを使用。高モーションのショートでは60fpsに上げてください。
| プラットフォーム | ビデオビットレート | 備考 |
|---|---|---|
| TikTok | 約2,000~4,000 kbps | 3つの中で最も軽い |
| Instagram Reels | 約3,500~4,500 kbps | |
| YouTube Shorts (1080p) | 約8,000~15,000 kbps | 4K/60で約53,000 kbpsまで |
単一の 1080x1920 H.264 MP4 @30 fps で 約250 MB以下 であれば、どこでも安全です。 出荷前に検証してください:
ffprobe -v error -select_streams v:0 \
-show_entries stream=width,height,codec_name,avg_frame_rate out.mp4
width=1080 height=1920 codec_name=h264 が期待値です。完全なプラットフォームごとのエンコードフラグと ffprobe アサーションは references/ffmpeg-pipeline.md にあります。
アンチパターン
| 悪い例 | なぜ壊れるか | 良い例 |
|---|---|---|
silenceremove をワンショットフィルターとして使用 | オーディオのみ;ビデオは再生を続ける → 音声/映像の同期ずれ | silencedetect → 保持範囲に反転 → select+aselect で両方のストリームをカット |
| セグメントタイムスタンプから単語キャプションを作成 | ハイライトがジッターし、間違った単語に当たる | 強制アライメントによる単語ごとのタイムスタンプ(WhisperX / word_timestamps) |
| キャプションを下部15~20%に焼き込む | プラットフォームUI(ボタン、CTA、プロフィール)が隠す | 縦方向の中央帯、中央約80%に配置 |
| 1つの出力をすべてのプラットフォームで使い回す | どこかでビットレートが不足/超過する | プラットフォームごとのビットレート、または安全なユニバーサルマスター |
| 30秒のショートで1秒のクロスフェード | ペースを殺し、遅く感じられる | ハードカット;ビートに合わせてのみウィップ/ズーム |
| トーキングヘッドの話の途中でビートカット | 話し方が途切れ、明瞭さを失う | Bロール/モンタージュのみビート同期;発話境界を尊重 |
| 「仕様確認」のためにエンコードを再実行 | 数分を浪費;ファイルはすでに存在する | ffprobe で出力を検証;再レンダリングではなく確認 |
| ここでキャプションのコピーやフックを書く | それは脚本であり、カットではない | ../video-shorts/SKILL.md にルーティング;あなたは焼き込むだけ |
ffmpeg で元のファイルを上書き | 1つの誤ったフラグで元のファイルが消失 | 常に新しいファイルに書き込み、in.mp4 はそのまま残す |
検証とリファレンス
bash scripts/verify.sh <output.mp4>—ffprobeを実行し、width=1080、height=1920(9:16)、ビデオコーデックh264、オーディオコーデックaac、fpsが{30, 60}のいずれかであること、および関連する.srt/.assキャプションファイルが存在し空でないことをアサートします。ffprobeがない場合はパス/拡張子チェックにフォールバックします。読み取り専用で、空の/クリーンなターゲットに対しては終了コード0を返すため、偽の失敗は起こりません。「ビートに乗っているか」の判断は機械的なものではなく、能力評価に委ねられます。references/ffmpeg-pipeline.md— 無音検出 → 保持範囲反転 → ビデオ+オーディオを同時にカットするselect/aselectフィルター生成の完全版、concat/trimアプローチ、プラットフォームごとのエンコードフラグ、ffprobeアサーション、および非同期/オーディオドリフト/faststartのトラブルシューティング。references/captions.md— WhisperXのインストールと実行、単語タイムスタンプJSONの構造、セーフゾーンマージン付きの完全な.assカラオケテンプレート、combineTokensWithinMillisecondsガイダンス付きのRemotioncreateTikTokStyleCaptions()スニペット、およびfaster-whisperとWhisperXのトレードオフ。