Communitygithub.com

huzaifa-hb/video-edit

実際の映像を会話で編集。完全ローカル。whisper.cppで文字起こし、トランスクリプトからテイクを選択、JSON編集リストの作成・検証、ffmpegでレンダリング、Hyperframesキャプションとオーバーレイの追加、9:16/1:1/16:9へのリフレーミング、そしてレンダリングの自己チェックを行います。

video-edit とは?

このスキルは、AIエージェント(Claude Codeなど)が実際の映像をローカルで編集するための強力なツールです。ユーザーとの会話を通じて編集戦略を決定し、whisper.cppによる高精度な文字起こし、JSON形式の編集リスト(EDL)の検証、ffmpegによるレンダリング、Hyperframesを使ったアニメーションキャプションの追加、そしてソーシャルメディア広告向けのアスペクト比変更(9:16、1:1、16:9)を自動化します。バーチャルアシスタントのような既存ツールとは異なり、完全にローカルで動作し、APIキーを必要としません。話し手の顔を追跡してフレーミングを調整するリフレーミング機能や、カット前後の自己検証プロセスを備えており、トークヘッド動画、UGC・ testimonial広告、ファウンダー動画、インタビュー、チュートリアルなどの制作に最適です。AIエージェントは、文字起こし、映像分析、編集判断、レンダリング、品質チェックを一貫して実行し、ユーザーが確認した戦略に基づいて高品質な動画を生成します。

対応✓Claude Code~Codex CLI~Cursor
npx skills add huzaifa-hb/video-edit

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Video Edit

browser-use/video-use (MIT) のフォーク: ElevenLabsの代わりにローカルのwhisper.cpp、レンダリング前の検証ゲート、libass字幕の代わりにHyperframesキャプション、ソーシャル広告バリエーション用のキャンバスリフレーミングを採用。

原則

  1. LLMは生のトランスクリプトとオンデマンドのビジュアルから推論する。 価値ある唯一の成果物は、フレーズレベルのパックされたトランスクリプト (takes_packed.md) です。その他(フィラータグ付け、撮り直し検出、ショット分類、強調スコアリング)は、判断時に動的に導出します。
  2. 音声が優先され、ビジュアルはそれに従う。 カット候補は発話境界と無音ギャップから生成されます。ビジュアルは判断ポイントでのみ掘り下げます。
  3. 質問 → 確認 → 実行 → 反復 → 永続化。 ユーザーが平易な英語で戦略を確認するまで、カットには決して触れません。
  4. 一般化する。 これがどのような種類の動画かを仮定しないでください。素材を見て、ユーザーに質問し、それから編集します。
  5. 芸術的自由がデフォルト。 このドキュメントに記載されているすべての具体的な値、プリセット、フォント、色、持続時間、ピッチ構造、およびテクニックは、実績のある1つの動画からの実例であり、強制ではありません。何が可能で、なぜそれぞれが機能したかを理解するためにそれらを読んでください。そして、素材が実際に何であるか、ユーザーが実際に何を望んでいるかに基づいて、独自のセンスで判断を下してください。以下の「ハードルール」セクションに記載されていることだけは必ず行わなければなりません。 それ以外はすべてあなたの自由です。
  6. 自由に発明する。 素材がここに記載されていないテクニック(分割画面、ピクチャーインピクチャー、ローワーサード ID カード、リアクションカット、スピードランプ、フリーズフレーム、クロスフェード、マッチカット、Lカット、Jカット、ブレスに合わせたスピードランプなど)を必要とする場合は、それを作成してください。ヘルパーは ffmpeg と PIL です。それらはフォーマットがサポートするすべてのことを実行できます。許可を待つ必要はありません。
  7. ユーザーに表示する前に、自分の出力を検証する。 出荷できないものは、提示しないでください。

ハードルール(プロダクションの正確さ — 交渉不可)

これらは、逸脱するとサイレント障害や出力の破損を引き起こすものです。センスの問題ではなく、正確さの問題です。暗記してください。

  1. 字幕はフィルターチェーンで最後に適用され、すべてのオーバーレイの後に適用されます。そうしないと、オーバーレイがキャプションを隠します。サイレント障害です。
  2. セグメントごとの抽出 → ロスレス -c copy での結合、シングルパスのフィルターグラフは使用しません。そうしないと、オーバーレイが追加されたときにすべてのセグメントが二重エンコードされます。
  3. すべてのセグメント境界で30msのオーディオフェード(afade=t=in:st=0:d=0.03,afade=t=out:st={dur-0.03}:d=0.03)。そうしないと、すべてのカットで可聴ポップノイズが発生します。
  4. オーバーレイは setpts=PTS-STARTPTS+T/TB を使用して、オーバーレイのフレーム0をそのウィンドウの開始位置にシフトします。そうしないと、オーバーレイウィンドウ中にアニメーションの途中が表示されます。
  5. キャプションは出力タイムラインオフセットを使用します: output_time = word.start - segment_start + segment_offset。ここで、各セグメントはその全フレーム長(captions.py がこれを行います)を持続します。そうしないと、セグメント結合後にキャプションがずれます。
  6. 単語の途中でカットしないでください。 すべてのカットエッジをトランスクリプトからの単語境界にスナップします。validate_edl.py --fix がこれを機械的に行います。
  7. すべてのカットエッジをパディングします。 作業ウィンドウ: 30~200ms。単語のエッジはすでにオーディオエンベロープにスナップされていますが、パディングは残りを吸収します。ペースの速いものではよりタイトに、映画的なものではよりルーズに。
  8. 単語レベルの逐語的ASRのみ。 SRT/フレーズモードは使用しないでください(サブ秒のギャップデータが失われます)。正規化されたフィラーは使用しないでください(編集シグナルが失われます)。transcribe.py は whisper に「um」/「uh」を保持するように指示します。プロンプトは削除しないでください。
  9. トランスクリプトはソースごとにキャッシュします。 ソースファイル自体が変更されない限り、再トランスクライブしないでください。
  10. 複数のアニメーションには並列サブエージェントを使用します。 決して順次実行しないでください。Agent ツールを介して一度にN個を起動します。総壁時計時間 ≈ 最も遅いものの時間です。
  11. 実行前に戦略を確認します。 ユーザーが平易な英語の計画を承認するまで、カットには決して触れません。
  12. すべてのセッション出力は <videos_dir>/edit/ に配置します。 スキルディレクトリ内には決して書き込まないでください。
  13. すべてのレンダリング前に検証します。 validate_edl.py <edl> --fix を実行し、終了コード0でのみレンダリングします。これにより、存在しないソースID、ファイルの終わりを超えた時間、単語途中のカット、欠落したオーバーレイファイル、カットを超えて実行されるオーバーレイなど、LLMが作成した編集リストが実際に持つ障害モードをキャッチします。
  14. キャプションは Hyperframes レイヤーであり、焼き込み字幕ではありません。 Homebrew の ffmpeg には libass がないため、EDL 内の subtitles は失敗します。captions.py を使用してください。render.py はすべてのオーバーレイの上にキャプション WebM を合成します。
  15. ソースIDはファイルのステムです。 sources 内で、キーは拡張子なしのビデオファイル名(take_B.mp4 の場合は take_B)、または --audio-track N で文字起こしされた場合は <stem>.track<N> でなければなりません。これがトランスクリプトの検索方法です。キャプションがオンの場合、バリデーターは不一致でエラーになります。
  16. レンダリングごとに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)を各範囲にわたって実行 → 話者を中央に保ち、EDL canvas 上にヘッドルームを確保する 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 ツールを介してサブエージェントを起動します。

プロセス

  1. インベントリ。 すべてのソースを 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 をサンプリングします。
  2. 問題の事前スキャン。 takes_packed.md を一度スキャンして、口の滑り、明らかな言い間違い、または避けるべき表現に注意します。プレーンなリストにして、エディターブリーフに供給します。

  3. 対話。 あなたが見ているものを平易な英語で説明します。素材に基づいて質問をします。収集するもの: コンテンツタイプ、ターットの長さ/アスペクト、美的/ブランドの方向性、ペース感、必須で保持する瞬間、必須でカットする瞬間、アニメーションとグレーディングの好み、字幕の必要性。固定のチェックリストは使用しないでください — 適切な質問は毎回異なります。

  4. 戦略を提案。 4~8文: 形状、テイクの選択、カットの方向性、アニメーションプラン、グレーディングの方向性、字幕スタイル、長さの見積もり。確認を待ちます。

  5. 実行。 エディターサブエージェントブリーフを介して edl.json を生成します。曖昧な瞬間には timeline_view を掘り下げます。並列サブエージェントでアニメーションを構築します。validate_edl.py --fix が終了コード0で終了するまで実行します。次に、キャプションが要求された場合は captions.py を実行します(キャプションは最終範囲から構築されるため、範囲変更後は再実行します)。

  6. プレビュー。 validate_edl.py(--fix なし)→ render.py --preview。

  7. 自己評価(ユーザーに表示する前)。 すべてのカット境界(±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回経過しても問題が残っている場合は、無限ループするのではなく、ユーザーにフラグを立てます。自己評価が合格した場合にのみプレビューを提示します。

  8. 反復 + 永続化。 自然言語フィードバック、再計画、再レンダリング。再トランスクライブは絶対に行わないでください。確認後に最終レンダリング。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 を使用して、話者の顔に基づいてクロップを自動調整します。

関連スキル