Communitygithub.com

beachyphotoandfilm-arch/video-skills

トークヘッド動画向けに、話者の言葉に正確に同期したアニメーションブランドオーバーレイ(モーショングラフィックス)とDaVinci Resolve読み込みファイルを生成します。

video-skills とは?

このスキルは、トークヘッド動画のラフカットから、話者の発言に正確に同期したアニメーションオーバーレイを生成します。DaVinci ResolveまたはFCPXMLを介して、透明な.movクリップをタイムライン上の正確な位置に配置します。主な機能は、ローカルでの文字起こし(単語レベルのタイムスタンプ付き)、オーバーレイポイントの選択、ブランドカラーとフォントを使用したレンダリング、およびResolve/FCPXMLインポートファイルの作成です。"この動画にアニメーションを作成して"、"オーバーレイ/モーショングラフィックスを追加"、"アニメーション化"、"YouTube動画のBロールグラフィックス"などのトリガーに対応しています。特に、話者の背後または横に配置される「インシーンタイプ」のテキストと図を多用するハウススタイルを採用しています。DaVinci Resolve MCPサーバーと統合することで、タイムラインの変更を検出し、手動インポートを不要にします。動作環境はmacOSで、DaVinci Resolve、whisper.cpp、Node.js、Swiftが必要です。

対応✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/beachyphotoandfilm-arch/video-skills/tree/HEAD/skills/video-overlays

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

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

ドキュメント

ビデオオーバーレイ

ラフカットから、話者が各フレーズを発した正確なフレームに配置されたアニメーションオーバーレイのセットと、Resolveインポートファイルを生成します。

ブランド設定はこちら

以下の設定を scripts/scene.html の :root ブロック(先頭)で一度だけ編集してください。その他の設定はすべてこれらを参照します。

設定CSS変数デフォルト値
アクセントカラー--brand-accent (+ --brand-accent-rgb を r,g,b 形式で)#4a90e2
明るいテキストカラー--brand-light (+ --brand-light-rgb)#f2f2f2
暗いインクカラー--brand-ink#0d131a
表示フォント(見出し、数字)--font-display'Anton','Bebas Neue',Impact,sans-serif
本文フォント--font-body'Inter',-apple-system,sans-serif

表示フォントはローカルにインストールされている必要があります(例:~/Library/Fonts)。これは、クリップがオフラインのヘッドレスChromeでレンダリングされるためです。AntonとBebas NeueはGoogle Fontsで無料で入手できます。コード内の BLUE という名前は単に「アクセントカラー」を意味します。

ハウススタイル:インシーンタイプ。 カードは使用しません。テキストは話者の頭の横の部屋内に配置され、大きなタイトルは頭を挟み込み、質問は話されたとおりにタイプされます。常にブランドカラーと表示フォントを使用します。

最も重要な唯一のルール: グラフィックスは話者の頭の後ろか横に配置します。顔の前に何も配置せず、背景色も使用しません。図も話者の横の壁に配置します。すべてはマット処理され、手がグラフィックスの前を通過できるようになります。

1回の実行で生成されるもの: N個の透明な .mov クリップ、PLACEMENT.txt、2つの .fcpxml ファイル、および短い PREVIEW.mp4。

デフォルトでは音声はありません。 特に要求がない限り、音楽や効果音は追加しないでください。

スタイルのデフォルト(お好みで変更可)

  1. 何も言われる前に表示されない。 すべてのクリップをフレーズの単語レベルのタイムスタンプ + 約0.12秒に固定し、単語の直後に表示されるようにします。セクションレベルのタイミングは早すぎると見なされます。
  2. 短く。 2.5秒から6.5秒。ほとんどは約3秒です。ソーシャルメディアのように前後にカットされるべきで、その場に留まりません。
  3. 頭の後ろか横に、決して話者の上に重ならない。 カード、背景、暗転は使用しません。これにより、新しい動画でのコーナーチップ、すべての full-* カード、define は使用されなくなります。
  4. メカニズムを表示する。 文章の前に図を探しましょう。インシーン図タイプ(dots、flow、bars、compare、math)を使用します。これらは話者の横の壁に配置されます。
  5. 2つの半分があるものは分割する。 古い方法と新しい方法は2つのクリップです。10%と20%は2つのクリップです。3つのオプションは3つのクリップで、それぞれ名前が呼ばれたときに配置されます。
  6. すべての行はその単語に配置される。 リスト、サイドライン、タイプされた単語には、均等な間隔ではなく、単語のタイムスタンプからの行ごとのオフセット(at、t)が含まれます。scripts/plan.example.py がその方法を示しています:フレーズを引用し、キューとなる単語に名前を付け、ルックアップを実行します。
  7. 良いバランス(11分あたり約48クリップ):約4分の1がインシーン図(主に flow)、次に side、pair、type、list2、num。pairは決めゼリフのために取っておきます。
  8. 大きなタイトルは頭の周りに配置し、後ろには配置しない。 pairは各行を単語境界で2つの半分に分割し、頭を挟み込みます。ギャップは顔のボックスの幅の1.9倍(髪と耳を含む)で、両方の半分が画面内に収まるようにスケーリングされます。したがって、すべての pair 行は2単語以上必要です(「ONE HOUR」、ただし「HOUR」は不可):1単語は分割できず、隠れてしまいます。data 内の "around": false は中央揃えの外観に戻します。アウトライン行は150px、ストローク5px、明るいアクセントフィル(35%)で、読みやすさを確保します。

開始前:カットは確定していますか?

オーバーレイは正確な単語に固定されるため、後で再トリミングするとすべてのクリップがずれます。ユーザーから生のフッテージを渡された場合、またはカットが確定していない場合は、最初に paper-edit スキルを実行し、それが生成するタイムラインにオーバーレイを配置します。

パイプライン

1. カットを取得して調査する

Resolveからの書き出し(例:~/Movies/ へ)を依頼するか、最初にペーパーエディットのために生のフッテージを <YOUR_FOOTAGE_DRIVE> に置くよう依頼します。ビデオファイルで問題ありません。オーディオを個別に書き出す必要はありません。Resolveが開いている場合は、書き出しを依頼する代わりに、MCPを介してタイムラインを読み取ります。

ffprobe -v error -show_entries format=duration -show_entries stream=codec_type,r_frame_rate -of default=nw=1 "<file>"

フレームレート(レンダラーは23.976 = 24000/1001 を想定。他のレートの場合は render.mjs の FPSN/FPSD を変更)を確認し、タイムラインが 00:00:00:00 から始まるか 01:00:00:00 から始まるか(Resolveのデフォルトは01)を尋ねます。

2. 単語レベルのタイムスタンプで文字起こし

ffmpeg -y -i "<file>" -ac 1 -ar 16000 -c:a pcm_s16le cut.wav
whisper-cli -m ~/.cache/whisper-models/ggml-small.en.bin -f cut.wav -oj -ml 1 -sow -of cut

-ml 1 -sow はセグメントごとに1つのトークンを生成し、これにより正確なアンカー固定が可能になります。次に、cut.json 内のトークン実行を照合して、各フレーズの開始時間を見つけます(transcription[].offsets.from はミリ秒単位)。

3. 瞬間を選ぶ

まずトランスクリプト全体を読みます。おおよそ動画15秒あたり1つのクリップを目指します。それぞれについて:アンカーフレーズ、タイプ、そしてアニメーションが着地してバランスを取るのに最も短い時間。

内容は、書かれたメモではなく、実際に話された内容に基づいてください。メモに「30分」とあり、カメラでは「30分かそこら」だった場合、録画が優先され、その違いをユーザーにフラグしてください。

4. clips.json を書く

scripts/clips.example.json をモデルとしてコピーします。クリップごとに1つのオブジェクト:

{"id":"06-math-10","start":52.96,"dur":3.6,"type":"dots","cue":"\"if 10 out of 100 meals are home cooked\"",
 "data":{"lit":10,"pct":"10%","count":"10 meals"}}

スキルフォルダの外に置き(スクラッチパッドパスで問題ありません)、CLIPS= で渡します。start は秒単位の生のフレーズ時間です。レンダラーが0.12秒のリードを自身で追加します。id の順序がファイルの順序を設定するため、番号を付けます。

5. クリーンなカットをレンダリングする(インシーンタイプに必要)

インシーンタイプは、頭の位置を読み取り、オーバーレイのないカットのコピーから話者を切り抜きます。Resolveから、すべてのオーバーレイクリップを無効にした状態で、確定したタイムラインをH.264 1080pでスクラッチパッドにレンダリングします。APIでは、V2の SetTrackEnable はResolve 19では機能しませんでした。代わりに、トラック内の各クリップに対して item.SetClipEnabled(False) が機能しました。生のフッテージはオンラインである必要があるため、フッテージドライブがマウントされている必要があります。マウントされていない場合は、ユーザーにプラグインを依頼し、完了したマスターをレンダリングする代わりにマウントを監視するように指示します(古いオーバーレイが焼き付いている可能性があります)。

6. レンダリング

cd <skill>/scripts && npm i                   # 初回のみ、puppeteer-coreをインストール
swiftc -O person.swift -o person              # 初回のみ、マット+ヘッドファインダー
TITLE="<video name>" CLIPS=/path/to/clips.json FOOTAGE=/path/to/clean.mp4 OUT_DIR="$HOME/Movies/<video-name>-overlays" node render.mjs
# 1つまたは数個のクリップのみ:
ONLY=06-math-10,07-math-30 OUT_DIR=... node render.mjs

オーバーレイ1秒あたり、およそ10~15秒の実時間がかかります(pair はより遅く、すべてのフレームをマット処理します)。バックグラウンドで実行し、後で確認するのが適切な方法です。最後に PLACEMENT.txt と両方の .fcpxml ファイルを書き出します。

フルレンダリングの前に、常に実際のフッテージでプルーフを行ってください。 node proof.mjs <clean.mp4> <clips.json> out.jpg [email protected] [email protected] ... は、実際のショット上にクリップごとに1フレーム(prefix@クリップ開始からの秒数)をマット込みでレンダリングし、1つの画像にタイル状に並べます。それを確認してください。フレームからはみ出たテキスト、目を横切るタイトル、忙しない背景のテキスト:すべてコードでは見えず、画像で明らかになります。ダイアグラムの場合、グレーでの合成でも問題ありません。

プルーフフレーム:最初にPNGに抽出します。 qtrle .mov を -ss で lavfi カラーソースに直接オーバーレイすると、空白のフレームが生成されます。フレームを引き出し(ffmpeg -ss 2.8 -i clip.mov -frames:v 1 f.png)、その後PNGを合成します。

Resolveでの配置: 確定したタイムラインを YouTube Final として複製し、movファイルを Overlays ビンにインポートし、各ファイルを trackIndex: 2 と recordFrame(PLACEMENT.txtのINタイムコードから。((h*3600+m*60+s)*24+ff) なので、01:00:00:00 = 86400)で AppendToTimeline します。PLACEMENT.txt を1行ずつ解析します(line.split()[0] がid、[1] がタイムコード)。ファイル全体の正規表現は、キューイングテキスト(例:"60-second")をクリップIDとして読み取り、次の行のタイムコードを盗む可能性があるため、1つのクリップがサイレントに未配置になります。配置された数がクリップ数と等しいことを確認してください。

7. プレビュー、そして引き渡し

実際のフッテージ上に10~15秒のプレビューを構築し、ユーザーが配置前に判断できるようにします:

ffmpeg -y -ss <t> -t 11 -i "<cut>" -itsoffset <a> -i "<clip1>.mov" -itsoffset <b> -i "<clip2>.mov" \
  -filter_complex "[0:v][1:v]overlay=0:0:eof_action=pass[v1];[v1][2:v]overlay=0:0:eof_action=pass[vo];[vo]scale=1280:-2[v]" \
  -map "[v]" -map 0:a -c:v libx264 -crf 20 -preset veryfast -c:a aac PREVIEW.mp4

元のオーディオはフッテージと一緒に引き継がれ、プレビューに必要なのはこれだけです。 次に、インポート手順(File > Import > Timeline > Import AAF, EDL, XML、starts-01 ファイルを選択し、クリップを01:00:00:00のフッテージの上のトラックにコピー)を説明します。

Resolve内で直接作業する(Resolveが開いている場合に推奨)

resolve MCPサーバー(例えばサードパーティのbarckley75/resolve-claude-mcp)がインストールされている場合、Resolve StudioのスクリプトAPIと通信します。paper-edit スキルが ensure_resolve.sh を提供している場合は、最初にそれを実行して、Resolveが閉じている場合に起動します。Preferences > System > General > External scripting using: Local を使用する場合、書き出しとインポートの手順よりも優先します。

これにより変更される点:

  • 書き出したカットは不要。 開いているタイムラインから実際のタイムコード、フレームレート、開始タイムコード、クリップレイアウトを読み取り、それにオーバーレイを固定します。これにより、「トリミングするたびにタイムコードがずれる」問題が修正されます。
  • 手動インポートは不要。 レンダリングされた .mov クリップをビデオトラックに直接配置します。
  • より良い瞬間の選択。 カットが既にどこにあるかを確認できるため、オーバーレイをカットと戦わせるのではなく、それに合わせて配置できます。
  • オーバーレイが配置されたら、レンダリングを開始することもできます。

使用ルール:

  1. 書き込む前に読む。 最初にプロジェクト名、タイムライン名、開始タイムコード、フレームレートを確認し、ユーザーに伝えます。
  2. マスタータイムラインには決して書き込まない。 最初にそれを複製し、コピーで作業します。これにより、ミスが無駄になりません。
  3. 通常のツールでジョブを実行できない場合を除き、execute_resolve_code の使用を避ける。 これはユーザーのプロジェクトに対して任意のPythonコードを実行します。それが唯一の方法である場合は、最初にコードを表示します。
  4. ローカルセッションのみ。 ResolveはこのMac上で実行されている必要があります。そのため、これはクラウドやスケジュール実行では機能しません。その場合はFCPXMLにフォールバックします。
  5. FCPXMLパスは引き続き機能し、フォールバックとして使用されます。 両方のファイルを生成し続けます。数秒のコストです。

オーディオ文字起こし: 一部のResolve MCPサーバーは独自のmlx-whisper文字起こしを提供しますが、上記のwhisper.cpp手順はこのパイプラインで実績があります。

クリップタイプ

以下はすべて新しい動画では廃止されました(古い動画を再カットできるように保持)。次のセクションのインシーンタイプを使用してください。フルフレームタイプは、ソリッドなインク背景とソフトなアクセントグローを描画するため、話者を完全に隠します。チップは左下に配置されます。

タイプ使用用途data
full-dots廃止、dots を使用lit、pct、count
full-flow廃止、flow を使用label、steps[]、good
full-compare廃止、compare を使用title、left{label,value,sub}、right{...,hi}、vs
full-bars廃止、bars を使用title、bars[{label,value,value_label,hi}]
full-math廃止、math を使用parts[](演算子 x = + → はアクセントカラーでレンダリング)、sub
full-pack廃止、bars または side を使用name、note、size 0-1、hi
full-stat廃止、pair を使用label、value、sub、hi
full-title廃止、pair または type を使用title(<br> 使用可)、size、sub
full-list廃止、list2 を使用title、items[]、step 秒
chip廃止、side または num を使用num、title、sub、hi
chip-stack廃止、list2 を使用items[]

廃止されたタイプもレンダリングは可能で、古い動画の再カットに使用できます。

インシーンタイプ(デフォルト)

カードはなく、テキストは話者の頭の横の部屋内に配置され、大きなタイトルは頭の周りに配置されます。

タイプ使用用途data
pair決めゼリフのタイトル:頭の上にアウトライン行、額の高さにソリッド行top、bottom、outline(top/bottom)
side頭の横に2~3行の短い行、各行はその単語に配置lines[]、accent(インデックス、大きくアクセントカラー)、at[]
type話されたとおりに単語ごとにタイプされる引用または質問words[{w,t,hi,br}]
define廃止:ショットを暗くします。side または pair を使用word、sub
numアウトライン数字が描画され、その横に単語("01 週を計画する")num、lines[]
list2頭の左および/または右に構築されるアイテムleft[]、right[]、at[](順番に、左が先)

インシーン図(同じ壁配置とマット):

タイプ使用用途data
dots100あたりの割合、話者の横にグリッドが埋まるlit、pct、count
flowプロセス、ステップが上から下にチェーン、最後はアクセントカラーlabel、steps[]、at[](オプション)
barsサイズによる2つまたは3つの数字title、bars[{label,value,value_label,hi}]
compare2つのオプション、頭の両側に1つずつleft{label,value,sub}、right{...,hi}
math壁に沿って読まれる方程式、演算子が各行をリードparts[]、sub

at と t はクリップ開始からの秒数です。単語のタイムスタンプから構築し、すべての行がその単語に配置されるようにします。

これらには FOOTAGE= が必要です。オーバーレイクリップが無効になった状態でタイムラインをレンダリングした、オーバーレイのないカットです。レンダラーは各クリップの顔のボックスと背景の明るさグリッドを読み取るため、テキストは空の壁を見つけ、フレームからはみ出す場合は辺りを反転または縮小し、明るい背景にはインク、暗い背景には明るいテキストに切り替わります。すべてのインシーンクリップのすべてのフレームから話者をマット処理し(Apple Vision人物セグメンテーション、person.swift)、タイトルが頭の後ろに配置され、手がグラフィックスの前を通過できるようにします。swiftc -O person.swift -o person で一度コンパイルします。FOOTAGE がない場合、インシーンタイプはフォールバックできず、エラーで失敗します。フルフレームタイプは FOOTAGE を必要としません。

タイミングモデル

各クリップについて、レンダラーは start に render.mjs で定義されたリード(デフォルト0.12秒)を追加して、書き出された .mov の in ポイントを設定します。FCPXMLはこのオフセットを含むため、クリップはちょうど聞こえた後に配置されます。

start は、whisper.cppがフレーズを終了したと報告する秒単位の時間です。つまり、最終音節の終わりです。0.12秒のリードにより、アニメーションは音が完全に止まる前に開始されます。

内部動作: plan.py は cut.json をルックアップテーブルとして使用し、開始時間を解決します。

プランニング(ソース付き)

scripts/plan.example.py は、トランスクリプトからクリップを計画するための推奨される方法を示しています。文字起こし出力を解析し、結果の clips.json を生成します。まだコードを書いていない場合は、そこからコピーして編集することをお勧めします。

# plan.example.py の簡略化された構造
# 1. トランスクリプトを読み込む(cut.json)
# 2. 各フレーズについて、タイプ、データ、タイミングを定義
# 3. clips.json として書き出す

注:完全なSKILL.mdには、より詳細なプランニングの例、トラブルシューティング、FAQが含まれていますが、この翻訳では主要なワークフローとパラメータに焦点を当てています。

Individual skills in this repo

This repo contains 7 individual skills — each has its own dedicated page.

beachyphotoandfilm-arch/video-skills

Sync camera footage to a separate lapel or field-recorder track (e.g. Tascam DR-10L and similar) and lay it up in DaVinci Resolve. Stitches the recorder's split files, finds each clip's exact place in the audio by matching words then waveforms, cuts one lapel slice per clip so every later skill works unchanged, checks for clipping, and builds a synced timeline in a new Resolve project. Trigger on "sync the lapel", "sync my audio", "line up the recorder", "I used a lav", or any shoot with a separate audio folder (live talks, events, workshops). Run it before paper-edit or video-reels.

beachyphotoandfilm-arch/video-skills

Turn raw talking-head footage into an assembled rough cut inside DaVinci Resolve. Pulls the clips off your footage drive, transcribes them locally, removes failed takes, restarts, asides and dead air, then creates a new Resolve project with two paper-edit timelines ready for your fine trim. Trigger on "paper edit", "cut my raw footage", "make a rough cut", "clean up this video", or when the user points at a folder of raw camera files for a YouTube video.

beachyphotoandfilm-arch/video-skills

Design a unique Instagram cover for each reel in your house style. Reads what the reel is about, writes a short hook headline, picks one of your own photos from a tagged photo library, lays it out like your existing covers, and proofs it in grid view at phone size. Renders locally, never with AI image generation. Can be called by a scheduling skill before reels are scheduled. Trigger on "make covers", "reel covers", "cover photo for this reel", "design the IG covers".

beachyphotoandfilm-arch/video-skills

Render finished reels out of DaVinci Resolve, write captions in the creator's voice, attach a custom Instagram cover from reel-covers, and schedule them to Instagram, TikTok and YouTube Shorts through Metricool. Handles the Drive upload hop, collision checks against the existing calendar, and cleanup. Trigger on "schedule the reels", "post these", "put these on the calendar", or after reels are approved.

beachyphotoandfilm-arch/video-skills

Cut vertical Instagram reels out of a long-form talking-head video, hook first. Picks the strongest standalone moments from the transcript, opens each reel on its punchiest line, builds vertical timelines in DaVinci Resolve framed on the speaker's face with the LUT applied, and finishes them: a hook (a held text card, or a word-by-word "build" hook with punch-in) and burned-look captions on V3; this-or-that reels get product graphics and a comment-keyword CTA card. You trim and render, nothing to import. Trigger on "make reels", "clip this for Instagram", "cut some verticals", or after a YouTube video is cut.

beachyphotoandfilm-arch/video-skills

Design YouTube thumbnails and titles for a talking-head video. Pulls graded full-res frames out of the raw footage, renders brand-styled variants in two proven layouts, and proofs them at phone size where the click actually gets decided. Trigger on "make thumbnails", "thumbnail for this video", "title and thumbnail", or after a video is cut.

beachyphotoandfilm-arch/video-skills

Run the whole YouTube video pipeline end to end, one stage at a time, stopping for the creator's approval at every gate. Paper edit, punch-ins, reels, reel covers, scheduling the reels, overlays, thumbnail and title, then scheduling the long-form video, all through Metricool. Keeps state per video so you can stop anywhere and pick up later. Trigger on "/youtube", "let's do the whole video", "run the video pipeline", "continue the <name> video", or when handed raw footage for a YouTube video.

関連スキル