Video Edit
browser-use/video-use (MIT) のフォーク: ElevenLabsの代わりにローカルのwhisper.cpp、レンダリング前の検証ゲート、libass字幕の代わりにHyperframesキャプション、ソーシャル広告バリエーション用のキャンバスリフレーミングを採用。
原則
- LLMは生のトランスクリプトとオンデマンドのビジュアルから推論する。 価値ある唯一の成果物は、フレーズレベルのパックされたトランスクリプト (
takes_packed.md) です。その他(フィラータグ付け、撮り直し検出、ショット分類、強調スコアリング)は、判断時に動的に導出します。 - 音声が優先され、ビジュアルはそれに従う。 カット候補は発話境界と無音ギャップから生成されます。ビジュアルは判断ポイントでのみ掘り下げます。
- 質問 → 確認 → 実行 → 反復 → 永続化。 ユーザーが平易な英語で戦略を確認するまで、カットには決して触れません。
- 一般化する。 これがどのような種類の動画かを仮定しないでください。素材を見て、ユーザーに質問し、それから編集します。
- 芸術的自由がデフォルト。 このドキュメントに記載されているすべての具体的な値、プリセット、フォント、色、持続時間、ピッチ構造、およびテクニックは、実績のある1つの動画からの実例であり、強制ではありません。何が可能で、なぜそれぞれが機能したかを理解するためにそれらを読んでください。そして、素材が実際に何であるか、ユーザーが実際に何を望んでいるかに基づいて、独自のセンスで判断を下してください。以下の「ハードルール」セクションに記載されていることだけは必ず行わなければなりません。 それ以外はすべてあなたの自由です。
- 自由に発明する。 素材がここに記載されていないテクニック(分割画面、ピクチャーインピクチャー、ローワーサード ID カード、リアクションカット、スピードランプ、フリーズフレーム、クロスフェード、マッチカット、Lカット、Jカット、ブレスに合わせたスピードランプなど)を必要とする場合は、それを作成してください。ヘルパーは ffmpeg と PIL です。それらはフォーマットがサポートするすべてのことを実行できます。許可を待つ必要はありません。
- ユーザーに表示する前に、自分の出力を検証する。 出荷できないものは、提示しないでください。
ハードルール(プロダクションの正確さ — 交渉不可)
これらは、逸脱するとサイレント障害や出力の破損を引き起こすものです。センスの問題ではなく、正確さの問題です。暗記してください。
- 字幕はフィルターチェーンで最後に適用され、すべてのオーバーレイの後に適用されます。そうしないと、オーバーレイがキャプションを隠します。サイレント障害です。
- セグメントごとの抽出 → ロスレス
-c copyでの結合、シングルパスのフィルターグラフは使用しません。そうしないと、オーバーレイが追加されたときにすべてのセグメントが二重エンコードされます。 - すべてのセグメント境界で30msのオーディオフェード(
afade=t=in:st=0:d=0.03,afade=t=out:st={dur-0.03}:d=0.03)。そうしないと、すべてのカットで可聴ポップノイズが発生します。 - オーバーレイは
setpts=PTS-STARTPTS+T/TBを使用して、オーバーレイのフレーム0をそのウィンドウの開始位置にシフトします。そうしないと、オーバーレイウィンドウ中にアニメーションの途中が表示されます。 - キャプションは出力タイムラインオフセットを使用します:
output_time = word.start - segment_start + segment_offset。ここで、各セグメントはその全フレーム長(captions.pyがこれを行います)を持続します。そうしないと、セグメント結合後にキャプションがずれます。 - 単語の途中でカットしないでください。 すべてのカットエッジをトランスクリプトからの単語境界にスナップします。
validate_edl.py --fixがこれを機械的に行います。 - すべてのカットエッジをパディングします。 作業ウィンドウ: 30~200ms。単語のエッジはすでにオーディオエンベロープにスナップされていますが、パディングは残りを吸収します。ペースの速いものではよりタイトに、映画的なものではよりルーズに。
- 単語レベルの逐語的ASRのみ。 SRT/フレーズモードは使用しないでください(サブ秒のギャップデータが失われます)。正規化されたフィラーは使用しないでください(編集シグナルが失われます)。
transcribe.pyは whisper に「um」/「uh」を保持するように指示します。プロンプトは削除しないでください。 - トランスクリプトはソースごとにキャッシュします。 ソースファイル自体が変更されない限り、再トランスクライブしないでください。
- 複数のアニメーションには並列サブエージェントを使用します。 決して順次実行しないでください。
Agentツールを介して一度にN個を起動します。総壁時計時間 ≈ 最も遅いものの時間です。 - 実行前に戦略を確認します。 ユーザーが平易な英語の計画を承認するまで、カットには決して触れません。
- すべてのセッション出力は
<videos_dir>/edit/に配置します。 スキルディレクトリ内には決して書き込まないでください。 - すべてのレンダリング前に検証します。
validate_edl.py <edl> --fixを実行し、終了コード0でのみレンダリングします。これにより、存在しないソースID、ファイルの終わりを超えた時間、単語途中のカット、欠落したオーバーレイファイル、カットを超えて実行されるオーバーレイなど、LLMが作成した編集リストが実際に持つ障害モードをキャッチします。 - キャプションは Hyperframes レイヤーであり、焼き込み字幕ではありません。 Homebrew の ffmpeg には libass がないため、EDL 内の
subtitlesは失敗します。captions.pyを使用してください。render.pyはすべてのオーバーレイの上にキャプション WebM を合成します。 - ソースIDはファイルのステムです。
sources内で、キーは拡張子なしのビデオファイル名(take_B.mp4の場合はtake_B)、または--audio-track Nで文字起こしされた場合は<stem>.track<N>でなければなりません。これがトランスクリプトの検索方法です。キャプションがオンの場合、バリデーターは不一致でエラーになります。 - レンダリングごとに1つのフレームレート。
--fpsをrender.pyに渡す場合は、同じ--fpsをvalidate_edl.pyとcaptions.pyにも渡します。範囲はキャプションがドリフトしないように整数フレームに丸められます。
このドキュメントの他のすべては実例です。素材が必要とするときはいつでも逸脱してください。
ディレクトリレイアウト
スキルは独自のディレクトリ(このファイルの隣にあるヘルパー+テンプレート)にあります。ユーザーの映像はユーザーが配置した場所にあります。すべてのセッション出力は <videos_dir>/edit/ に配置されます。
<videos_dir>/
├── <ソースファイル、未編集>
└── edit/
├── project.md ← メモリ; セッションごとに追記
├── takes_packed.md ← フレーズレベルのトランスクリプト、LLMの主要な読み取りビュー
├── edl.json ← カット決定(バリアント用に edl_9x16.json、edl_1x1.json …)
├── transcripts/<name>.json ← キャッシュされたwhisper.cppトランスクリプト(単語レベル+無音)
├── captions_<edl stem>/ ← Hyperframesキャプション合成 + captions.webm
├── animations/slot_<id>/ ← アニメーションごとのソース + レンダリング + 推論
├── clips_graded/ ← グレーディングとフェードを含むセグメントごとの抽出
├── downloads/ ← yt-dlp出力
├── verify/ ← デバッグフレーム / タイムラインPNG
├── preview.mp4
└── final.mp4
セットアップ
install.sh / setup.sh ですべてをインストールします(Homebrewパッケージ、.venv、whisperモデル、Hyperframes + Chrome)。コールドスタート時は単に確認するだけです。そして、.venv がない場合、またはヘルパーがインポートや欠落したツールで失敗した場合は、他の何よりも先に <this skill dir>/setup.sh(冪等です)を実行してください:
PY=<this skill dir>/.venv/bin/pythonが存在する。すべてのヘルパーを$PYで実行し、システムのpythonは決して使用しないでください(numpy/Pillow/OpenCVがありません)。ffmpeg、ffprobe、whisper-cliがPATHにあり、ggml whisperモデルがある。デフォルト:~/.claude-video-vision/models/ggml-large-v3-turbo.bin;VIDEO_EDIT_WHISPER_MODELでオーバーライド。- Hyperframes用のNode.js 22+。常に固定バージョンを呼び出します:
npx --yes [email protected] …。 yt-dlpと Manim は最初の使用時のみ。このスキルはskills/manim-video/をベンダーします; Manimスロットを構築するときはその SKILL.md を読んでください。- APIキーは不要です。一度限りのnpmダウンロードのHyperframesを除き、マシンから何も出て行きません。
ヘルパーはこの SKILL.md の隣の helpers/ にあります。このファイルを含むディレクトリからの相対パスで解決してください。
ヘルパー
すべて $PY helpers/<name>.py … で実行します。
transcribe.py <video>— ローカルwhisper.cpp、単語レベル、フィラー保持、単語エッジはオーディオエンベロープにスナップ、無音をリスト化。ソースごとにキャッシュされます(ファイルが変更された場合のみ再実行)。--language enは検出をスキップします; マルチトラック録音には--audio-track N。transcribe_batch.py <videos_dir>— フォルダ内のすべての動画を一度に1つずつ処理します(whisperはすでにGPUを飽和させます)。pack_transcripts.py --edit-dir <dir>—transcripts/*.json→takes_packed.md(フレーズレベル、無音 ≥ 0.5秒で区切る; 早口の話者には--silence-thresholdを0.3に下げる)。timeline_view.py <video> <start> <end>— フィルムストリップ + 波形PNG。オンデマンドのビジュアルドリルダウン。スキャンツールではありません — 常にではなく、判断ポイントで使用します。validate_edl.py <edl.json> [--fix]— すべてのレンダリング前のゲート(ハードルール13)。--fixはエッジを単語ギャップにスナップし、パディングし(--pad-in、--pad-out)、範囲を整数フレームに丸め、total_duration_sを再計算し、edl.json.bakを保持します。30ms未満の無音しかないエッジに関する警告は--fix後も残ります: それらのカットは単語が接触している場所にあります — 実際の一時停止に移動してください。captions.py <edl.json>— 出力タイムラインの単語キャプションをHyperframesコンポジションとして → 透明なcaptions.webm、EDLのcaptionsキーを設定。スタイルフラグ:--accent、--color、--top、--size、--font、--case、--words、--no-pop。render.py <edl.json> -o <out>— セグメントごとの抽出(フレーム正確、HDR→SDR、キャンバスリフレーミング、グレーディング、フェード)→ ロスレス結合 → オーバーレイ(PTSシフト)→ キャプション → loudnorm。--previewはQC用、--draftはカットチェックのみ。reframe.py <edl.json> [--apply]— OpenCV顔検出(YuNet)を各範囲にわたって実行 → 話者を中央に保ち、EDLcanvas上にヘッドルームを確保するcrop_x/crop_y。canvasがアスペクト比を変更するたびに、validate_edl.py --fixの後に実行します。顔が1つの静的クロップに対してMOVESしすぎる範囲(分割する)とno faceの範囲(自分でクロップを選択する)にフラグを立てます。範囲の"crop_lock": trueは手動クロップを保護します。scenes.py <video>— OpenCVショット変更検出とショットごとのDARK/BLURRYフラグ →edit/shots/<stem>.json。トランスクリプトが構造化できない映像(Bロール、プロダクトショット、モンタージュ、マルチカム書き出し、無音クリップ)に使用します。ショット境界はクリーンなビジュアルカットポイントです; フラグが立てられたショットは広告で使用できることはほとんどありません。grade.py <in> -o <out>— ffmpegフィルターチェーングレーディング。プリセット + カスタム用--filter '<raw>'。
アニメーションについては、<edit>/animations/slot_<id>/ を Bash で作成し、Agent ツールを介してサブエージェントを起動します。
プロセス
-
インベントリ。 すべてのソースを
ffprobeします。ディレクトリに対してtranscribe_batch.pyを実行します。発話がほとんどまたはまったくないソース(Bロール、プロダクトショット)の場合は、代わりにscenes.pyを実行してショットを取得します。それが出力するQC:行(各トランスクリプトのqcの下にもあります)を読んでください: ≤20msに圧縮された単語、または無音の中で始まる単語は、信頼できない時間を持ちます — それを使用する前に、timeline_viewでそれらの近くのカットを確認してください。- 複数の話者(通話、インタビュー): 話者ラベルはありません。内容(質問と回答)から話者交代を推測し、次に
timeline_viewで保持する予定の各フレーズを確認します(ビデオ通話では、アクティブスピーカータイルが誰が話しているかを示します)。通話が1人あたり1オーディオトラックで録音された場合は、代わりに--audio-track Nで各トラックを文字起こしします。pack_transcripts.pyでtakes_packed.mdを生成します。視覚的な第一印象を得るために、1つか2つのtimeline_viewをサンプリングします。
- 複数の話者(通話、インタビュー): 話者ラベルはありません。内容(質問と回答)から話者交代を推測し、次に
-
問題の事前スキャン。
takes_packed.mdを一度スキャンして、口の滑り、明らかな言い間違い、または避けるべき表現に注意します。プレーンなリストにして、エディターブリーフに供給します。 -
対話。 あなたが見ているものを平易な英語で説明します。素材に基づいて質問をします。収集するもの: コンテンツタイプ、ターットの長さ/アスペクト、美的/ブランドの方向性、ペース感、必須で保持する瞬間、必須でカットする瞬間、アニメーションとグレーディングの好み、字幕の必要性。固定のチェックリストは使用しないでください — 適切な質問は毎回異なります。
-
戦略を提案。 4~8文: 形状、テイクの選択、カットの方向性、アニメーションプラン、グレーディングの方向性、字幕スタイル、長さの見積もり。確認を待ちます。
-
実行。 エディターサブエージェントブリーフを介して
edl.jsonを生成します。曖昧な瞬間にはtimeline_viewを掘り下げます。並列サブエージェントでアニメーションを構築します。validate_edl.py --fixが終了コード0で終了するまで実行します。次に、キャプションが要求された場合はcaptions.pyを実行します(キャプションは最終範囲から構築されるため、範囲変更後は再実行します)。 -
プレビュー。
validate_edl.py(--fixなし)→render.py --preview。 -
自己評価(ユーザーに表示する前)。 すべてのカット境界(±1.5秒ウィンドウ)でレンダリングされた出力(ソースではなく)に対して
timeline_viewを実行します。各画像を確認:- カット部分での視覚的な不連続性 / フラッシュ / ジャンプ
- 境界での波形スパイク(30msフェードをすり抜けたオーディオポップ)
- オーバーレイの後ろに隠れた字幕(ルール1違反)
- オーバーレイの位置ずれまたは間違ったフレームの表示(ルール4違反)
またサンプリング: 最初の2秒、最後の2秒、中間点の2~3箇所 — グレーディングの一貫性、字幕の読みやすさ、全体的なコヒーレンスを確認します。
ffprobeを出力に対して実行し、長さがEDLの期待値と一致することを確認します。音声を測定し、推測しないでください:
ffmpeg -i out.mp4 -af ebur128=peak=true -f null -で統合ラウドネスとトゥルーピーク、さらにセクションごとのRMS(ダイアログ、音楽のみ、エンドカード)を取得します。ダイアログより15dB低いエンドカード、または音声より大きいエフェクトはバグです。あなたは聞くことができません: そのように述べ、数値を報告してください。ユーザーが公開するもの(ローンチ、プロモ、広告)については、レンダリングされたファイル、EDL、およびユーザーが提供した任意の参照動画を使用して、1つの批評家サブエージェントも起動します。賞賛ではなく、酷評するようにブリーフします: 評決、タイムコードとエビデンス(フレーム、レベル)のあるランク付けされた問題、および最初に行うべき5つの修正。新鮮な目は、作成者が見えなくなったものをキャッチします — 途切れた決めゼリフ、0.5秒のミーム、電話サイズで読めない28pxテキスト。
何かが失敗した場合: 修正 → 再レンダリング → 再評価。自己評価のパスは最大3回に制限します — 3回経過しても問題が残っている場合は、無限ループするのではなく、ユーザーにフラグを立てます。自己評価が合格した場合にのみプレビューを提示します。
-
反復 + 永続化。 自然言語フィードバック、再計画、再レンダリング。再トランスクライブは絶対に行わないでください。確認後に最終レンダリング。
project.mdに追記します。
カットクラフト(テクニック)
- 音声ファースト。 単語境界と無音ギャップからのカット候補。
- ピークを保存。 笑い、決めゼリフ、強調ビート。決めゼリフの後にはリアクションが含まれるように延長します — 笑いがビートそのものです。
- 話者交代は発話間の空気から利益を得ます。一般的な値: 400~600ms。ペースが速い場合は短く、映画的な場合は長く。センスの問題です。
- 笑いとリアクションはタグ付けされません(whisperはオーディオイベントを出力しません)。
timeline_viewの波形で、発話はないが大きなストレッチとして見つけてください; それらを越えて延長します — 笑いがビートそのものです。 - 無音ギャップはカット候補です。 500msの無音はほぼ常にカット可能を意味します。300ms未満のギャップは、話者が単に息継ぎをしているのであれば、スペースがきついことを意味します。
- トランジション。
%3$s。しかし、まず視覚的に試してみてください: 話者が効果を強調するために仕草をする場合、ハードカットはそれに続きます。話者が単に静止している場合、クロスフェードはトランジションを滑らかにします。 - バラエティを保つ。 3つ以上の連続したハードカットは、目が慣れてしまうことを意味します。短いBロールクリップ、リアクションショット、またはピクチャーインピクチャーで区切ります。
- エンドカードは行き過ぎないでください。 ショットを保持するか、徐々にフェードアウトします。ズーム/スライド/分割は安っぽく感じられます。
エディターブリーフ(EDL生成用)
編集リストを生成するときは、以下の手順に従ってください。
1. 入力
takes:<videos_dir>/edit/takes_packed.mdからのフレーズの配列。sources:<videos_dir>内の動画ファイルのマップ(キー = 拡張子なしのファイル名、値 = パス + ffprobeメタデータ)。shots: トランスクリプトベースでないソースについては、<videos_dir>/edit/shots/*。jsonから利用可能。canvas: ターゲットのアスペクト比と解像度 (例: 9:16 1080x1920)。
2. 戦略
以下の配列を生成します:
[
{
"start": 12.34,
"end": 45.67,
"source": "take_A"
},
...
]
各範囲について:
startとendは元のソースファイル内の時間です (秒単位、浮動小数点)。sourceはソースファイルのステム (拡張子なしの名前) です。- オプションのキー:
grade(プリセット名)、overlays(ファイルパスの配列)、crop_lock(リフレーミングを無効にする場合)。
3. 制約
- 範囲はカットエッジ以外では重複してはなりません。
- カットエッジは単語の境界上になければなりません (ハードルール6)。
- 連続する範囲の間にギャップがあってはなりません。
endは次のstartと正確に同じでなければなりません。 - 各範囲は少なくとも 0.5 秒の長さが必要です。
- オーバーレイは EDL の全範囲内に収まらなければなりません。
4. 出力
<videos_dir>/edit/edl.json に書き込みます。
よくある質問
Q: 音声駆動のカットを行うにはどうすればよいですか?
A: 各無音ギャップに候補カットポイントがあります。takes_packed.md には、0.5秒以上の無音で区切られた各フレーズが表示されます。希望する編集を形成するフレーズのシーケンスを選択してください。
Q: 話者がカメラの外を向いたり、ぼやけたりした場合はどうなりますか?
A: timeline_view を使用して、カットを選択する前に問題のある領域を確認します。必要に応じて、問題のないショットのBロールやリアクションショットで覆います。
Q: 複数の話者を処理するにはどうすればよいですか?
A: 話者ラベルがない場合、発言から話者を推測します。timeline_view を使用して、各フレーズが期待する話者からのものであることを確認します。各話者が個別のオーディオトラックに録音されている場合は、--audio-track N で文字起こしします。
Q: カットポイントをどれだけ正確に調整できますか?
A: validate_edl.py --fix は、エッジを最も近い単語境界と最小30msの無音ギャップにスナップします。より細かい制御が必要な場合は、--pad-in と --pad-out を調整します。
Q: より複雑なアニメーションを追加するにはどうすればよいですか?
A: 各アニメーションスロット (<edit>/animations/slot_<id>/) にサブエージェントを作成します。Agent ツールを使用して並行して実行します。
Q: 特定の映像にキャプションスタイルを適応させるにはどうすればよいですか?
A: captions.py のフラグ (--accent, --color, --size, --font など) を使用して、テイストに合わせて調整します。動画の審美的な方向性に合わせてスタイルを選択します。
Q: whisper.cpp のモデルを変更するにはどうすればよいですか?
A: VIDEO_EDIT_WHISPER_MODEL 環境変数を設定して、別の ggml モデルファイルを指定します。
Q: このスキルはどのプラットフォームで動作しますか?
A: macOS (Homebrew が必要)。Linux でも動作する可能性がありますが、セットアップスクリプトは macOS 向けに調整されています。
Q: なぜ字幕に libass ではなく Hyperframes を使用するのですか?
A: Homebrew の ffmpeg は libass なしでコンパイルされています。Hyperframes はブラウザベースのレンダリングを使用してアニメーションキャプションを作成し、それを ffmpeg で合成できます。
Q: レンダリングが遅すぎる場合はどうすればよいですか?
A: render.py --draft を使用して、品質を犠牲にして高速なプレビューを行います。アニメーションを並列化します。または、レンダリングの解像度を下げます。
Q: 複数のアスペクト比のバリアントを作成するにはどうすればよいですか?
A: 各バリアントの EDL (例: edl_9x16.json, edl_1x1.json) を別々に作成し、適切なキャンバスでレンダリングします。reframe.py を使用して、話者の顔に基づいてクロップを自動調整します。