Visual Guide Video
動画を分析し、タイムラインファイル1つ(timeline.py) を作成すれば、エンジンがすべての演出・音楽・効果音をコードでレンダリングします。外部の編集ツールや音声ファイルは使いません。
SKILL_DIR = この SKILL.md があるフォルダ。スクリプトは python "$SKILL_DIR/scripts/<name>.py" で実行します。
0. 準備
pip install -r "$SKILL_DIR/requirements.txt" # opencv-python imageio-ffmpeg numpy scipy pillow edge-tts
ffmpeg は imageio-ffmpeg バンドルを使用します。日本語・絵文字フォントはOSのデフォルトを自動検出します(VGUIDE_FONT_BOLD/REGULAR/EMOJI で指定可能)。
作業フォルダは動画と同じ場所に置きます: project/timeline.py、成果物 project/build/、project/output/
1. 動画タイプの判別 → プロファイルの選択
python "$SKILL_DIR/scripts/analyze.py" VIDEO --out build/analysis
コンソールの タイプ推定 と build/analysis/sheets/*.jpg を Read で直接確認 してタイプを決定します。PROFILE 1つでデフォルト値が変更され、timeline.py に記述した値が常に優先されます。
| PROFILE | 対象 | デフォルト値 | コア演出 |
|---|---|---|---|
screen | 画面録画・チュートリアル・デモ | pop音楽、元の音声オフ、進行バー | SHOTSズーム、CLICKS、LINKS、HIGHLIGHTS、CARDS、HUD、FLOW |
game | ゲームプレイ・ボス戦・ハイライト | epic音楽(小音量)、元の音声オン、シネマティックカラーティング、30fps | MAGNIFY、IMPACTS、SPEED/FREEZE、POPS、CALLOUTS(@トラック)、ゲージ分析 |
vlog | 日常・旅行・レビュー | chill音楽、元の音声オン、warmカラーティング | CALLOUTS、STICKERS、SPEED(早送り移動)、字幕、GRADES |
anim | アニメーション・キャラクター動画 | cute音楽、vividカラーティング | POPS(funny)、STICKERS、CALLOUTS、FREEZE |
promo | 広告・プロモーション・旅行・ブランドフィルム | epic音楽(大音量)、元の音声オフ、30fps | TYPE(広告タイポ・印)、CLEANUP(元の文字消去)、INK切り替え、GLOWS、LETTERBOX、季節パーティクル、zen音楽arc |
タイプごとに 何を説明するか が異なります:
- screen: 「今どこを押して、何が変わるか」→ クリックポイントズーム、変更されたパネル矢印、ステータスカード
- game: 「何が起こったか(攻撃・防御・被弾・回復・ボスパターン)」+ 面白さ → ヒット感、リアクションポップアップ、遠くの対象拡大鏡、決定的瞬間停止解説、退屈な移動区間早送り
- vlog: 「どこで何をしているか」+ 感情 → 説明より雰囲気。イベント(誕生日・旅行・卒業)のクライマックスをスローモーション・パーティクルで盛り上げ、揺れる移動区間は早送り、写真を撮る瞬間は停止+ポラロイド、最後は写真コラージュアウトロ
- anim: キャラクターリアクション強調 → キュートなポップアップ、ステッカー、決定的表情停止
- promo: 「見ている人が行きたくなり、買いたくなるように」→ 字幕の代わりに 短い広告コピー(オープニング2行 → ヒーロータイトル → シーン別チャプター → エンドカード)、大きな場面転換時に墨汁にじみのようなシグネチャートランジション、音楽エネルギーカーブ(静か → 盛り上がり → 絶頂 → 余韻 → フィナーレ)。元の動画に別言語の文字が埋め込まれている場合は消去し、対象言語に置き換え(国際版)
共通編集原則(ユーザーが最も好んだ部分): 不要な区間(移動・ローディング・カメラが揺れている区間)は 早送り、重要な瞬間は 停止(フリーズ) して説明や装飾を入れます。分析段階で各区間を「核 / 接続 / 不要」に分類して開始します。
2. 分析 — いつどこで何が
events.json のイベント種類:
- 共通:
cut(シーン切り替え)、flash(閃光)、loud(音声ピーク = 打撃音・爆発)、motion(動きピーク) - screen:
switch(クリック・タップ切り替え候補)、big-change、scroll - ゲージ(
--bar):bar-drop/bar-big-drop(被弾)、bar-low(危険)、bar-empty(死亡)、bar-rise(回復)
ゲームはHPゲージを必ず測定します。被弾・回復・死亡時点がフレーム単位で正確に出ます。
python "$SKILL_DIR/scripts/crops.py" VIDEO --t 10,30 --box 200,940,500,100 --step 25 --out build/hp.jpg # ゲージ座標測定
python "$SKILL_DIR/scripts/analyze.py" VIDEO --out build/analysis --bar player:337,982,626,988 --bar boss:1015,911,1590,915
- ゲージボックスは バーの内側1ライン(高さ4~8px) で設定します。白ゲージはデフォルト
light、色ゲージは:any bar_<名前>.png(カイモグラフ: 縦=時間)をReadで見てイベントが正しいか確認します。被弾瞬間にゲージが赤く光ったり、演出でHUDが消えると誤検出が発生するため、graph.pngとシートでクロスチェックします- シートは2秒間隔です。戦闘区間は0.3~0.6秒間隔でフレームをさらに抽出し、どんな動作か(攻撃/回避/被弾/変身) を直接解釈します
正確な座標: 必ず目盛りクロップで測定します。
python "$SKILL_DIR/scripts/crops.py" VIDEO --t 7.4,13.5 --box 0,760,420,240 --out build/crops.jpg # 領域、50px 目盛り
python "$SKILL_DIR/scripts/crops.py" VIDEO --t 12 --full --out build/grid.jpg # 全体、100px グリッド
3. timeline.py の作成
レシピから始めます。 タイプに合ったレシピを timeline.py にコピーし、[1. 埋める値](核となる瞬間の時間・座標・フレーズ)だけを埋めれば、検証済みの演出構造が自動で作成されます。その後、プレビューを見ながら動画に合わせて項目を追加・修正します。
| レシピ | 対象 | 埋める値 |
|---|---|---|
recipes/screen_walkthrough.py | 画面録画チュートリアル・デモ | クリック(時間・座標・フレーズ・変更箇所・カード)、強調領域、字幕 |
recipes/game_boss_fight.py | ゲーム戦闘ハイライト | HPゲージ位置、被弾(時間・残りHP)、自分の攻撃、ボスダウン、回復、死亡/撃破、移動区間、解説字幕 |
recipes/event_vlog.py | 誕生日・記念日・パーティーVlog | クライマックス時間と対象、揺れている区間、写真カウントダウン・停止フレーム、ゲスト登場、最後のシーン |
recipes/promo_shorts.py | 30秒縦型ショート(広告モンタージュ) | 区間リスト(元の区間・出力長)、シーン別パンニング、季節単語・チャプターフレーズ、トランジション種類 |
recipes/promo_film.py | 広告・プロモーション・旅行フィルム | オープニングコピー、ヒーロー・エンドカード、シーン(区間・速度・チャプターフレーズ・印・カメラ・パーティクル・エネルギー・背景音)、墨切り替え時間、光る対象、消す文字 |
レシピのデフォルト値は実際の動画で検証された値のため、そのままにしておけばサンプルのように動作します(他の動画では必ず再度測定してください)。レシピにない項目は templates/timeline_template.py の全スキーマを参照して追加します。適切なレシピがない場合はテンプレートから開始します。
作業した動画の timeline.py はその動画のフォルダに置きます。スキルリポジトリには特定の動画のタイムライン(人名・個人シーン・作業内容)は入れません — 一般化できるパターンはレシピとこのドキュメントに移します。
ルール: 時間は常に '元の動画の時間'、座標は '元のピクセル'。SPEED・FREEZE で出力長が変わってもエンジンが自動変換します。
停止区間内の時間は (元の時間, 出力オフセット秒) で記述します: (49.45, 1.6) = 49.45秒で停止が開始され、1.6秒後。停止中にポップアップ・ポラロイド・アウトロを順に表示する際に使用します。
汎用要素(すべてのプロファイル)
| 項目 | 用途 |
|---|---|
TRIM, SPEED, FREEZE | 区間カット、速度・スローモーション(ラベルバッジ、ラベル None ならバッジなし)、停止画面(look desat=解説用 / photo=シャッターフラッシュのみ)。早送りは自動モーションブラー(SPEED_BLEND) |
TRACKS | 動く対象のキーフレーム。auto=True(OpenCV追跡: 人・動物) / auto="match"(テンプレートマッチング: ケーキ・看板など形状固定物体、until までキー1つで追跡) / follow="親"(親トラックに付随する対象、例: ケーキの上のろうそく)。他の項目で "@名前"、"@名前:top" として参照 |
PARTICLES | パーティクル confetti/hearts/sparkle/bokeh/notes/stars/snow/petals/leaves/fireflies(palette=[6] のように色指定)。トラック・座標から burst(一度にパッ)または rate(継続)、画面全体(at="screen") |
PHOTOS | 元のフレームをポラロイドとして表示(キャプション・角度・落ちる登場)。停止画面・アウトロコラージュ用 |
SHOTS | カメラ: 座標ズーム / "full" / "fill"(レターボックスなしで画面いっぱい) / "@トラック" 追跡ズーム |
MAGNIFY | 拡大鏡レンズ: 遠くの対象を円形に拡大 + 接続線 + ラベル |
CALLOUTS | 対象を指す吹き出し(トラックに沿って移動) |
POPS | ポップアップテキストスタイル impact/danger/cool/info/funny/small/party/sweet/count(カウントダウン数字) |
STICKERS | 絵文字ステッカー(bob/pulse) |
IMPACTS | ヒット感 hit/heavy/crit/damage/block/parry: 振動+フラッシュ+ズームパンチ+色収差(+効果音自動) |
SHAKE, FLASH | 手動振動・閃光 |
GRADE, GRADES | カラーティング cinematic/warm/cool/vivid/mono/sepia/danger/dream/night(区間別切り替え) |
SFX, SFX_VOLUME | 効果音ライブラリ: hit boom clang pop ding scratch sad_trombone heartbeat shutter slowmo crash whoosh riser party_horn twinkle confetti / stamp temple_bell ink gliss gliss_down / 長さを受け取る背景音 "waves:8" "wind:6" "water:6" "birds:5" |
SOURCE_AUDIO | 元の音声(スローモーション区間はピッチ下降、停止区間は無音、早送り区間は fast_gain 分だけ低減) |
MUSIC | style pop/epic/chill/cute/zen、arc(zen: シーン別エネルギー)、start(この時間から音楽)、drop、end(+end_fx scratch/fade/cut)、volume |
MASTER_GAIN_DB | 最終ミックスゲイン(リミッター前)。スマートフォン動画は元の音が小さいため +3~5 dB |
CUSTOM_LAYERS, CUSTOM_FRAME_FX, CUSTOM_SFX | 指示された新しい効果 を timeline.py 内の関数として追加(以下参照) |
OUTPUT_SIZE, FPS, QUALITY | 出力解像度(例: 720p (1280, 720))、fps、CRF |
CANVAS, BACKDROP | デザインキャンバス。縦型ショートは CANVAS = (1080, 1920) + OUTPUT_SIZE = (1080, 1920)。横長の元動画は中央の帯として入り、余白は BACKDROP("black"、"blur"、dict(kind="blur", tint=(r,g,b), amount=0.5))。画面をいっぱいにするには SHOTS 倍率 ≈ 3.16 (= 1920 / 607.5) でズームし、x でパンニング |
SPEED_RAMP | 速度区間を隙間なく連結する場合(ショートモンタージュ): 区間間で1倍速に戻らず、この秒数だけスムーズに移行する |
広告・プロモーション要素(scripts/promo.py、すべてのプロファイルで使用可能)
| 項目 | 用途 |
|---|---|
CLEANUP | 元の動画に埋め込まれた文字・印・ロゴの消去 (t0, t1, (x0,y0,x1,y1), dict(plate=(ta, tb), ref=t))。plate = 同じシーンで文字が ない フレーム → 背景をそのまま復元(シーンがパンニング・ズームする場合は位相相関で自動移動補正)。mask="box" はボックス全体を置換(静止背景)、plate がない場合はインペイント(NS + 紙目)、live=True は動く文字(例: スライドして入ってくるラベル、ink="light") |
TYPE | 広告タイポ。"line"(単語ごとに浮かび上がるコピー)、"hero"(文字間が詰まって登場する大型タイトル + サブタイトル + 印)、"chapter"(印が押され、キッカー・罫線・タイトルが続けて登場、veil で背後に霞のベール)。座標は1920x1080キャンバス、色 color、可読性 halo |
GLOWS | 太陽・月・照明の光のにじみ + レンズフレア(ストリーク・ゴースト) — トラックに沿う |
INK | 墨汁にじみトランジション (t, dict(dur, at)): t で画面を最も覆い、中央から消えていく(効果音自動) |
TYPE "slam" | ショート用: 大きな単語がビートに合わせて「ドン」 — 墨汁の上に描かれ、画面が覆われた瞬間にも見える(over_ink)。印 seal |
LETTERBOX | シネマレターボックス dict(ratio=2.39, range=(t0, t1)) — 入りと出の際にスムーズに。パーティクルも帯の下に隠れる |
新しい効果を指示された場合 — カスタムフック
エンジンを修正せずに、timeline.py に関数を記述します。ctx には t(出力時間)、ts(元の動画時間)、raw(元のフレーム)、frame(現在のキャンバス BGR)、view、cv(オーバーレイキャンバス)、tl、gfx、fx、W、H、screen("@boss")、window(t0, t1)(元の動画時間区間 → (alpha, 進捗度))があります。
def speed_lines(ctx): # CUSTOM_LAYERS: オーバーレイ描画(戻り値なし、または新しい frame)
w = ctx.window(57.2, 58.4)
if w:
x, y = ctx.screen("@boss")
for k in range(12):
a = k / 12 * 6.283
ctx.fx.draw_line(ctx.cv, (x + 300 * math.cos(a), y + 300 * math.sin(a)),
(x + 700 * math.cos(a), y + 700 * math.sin(a)), (255, 255, 255), 3, w[0] * 0.6)
CUSTOM_LAYERS = [speed_lines]
def red_pulse(ctx): # CUSTOM_FRAME_FX: フレーム変形 → 新しい frame を返す
return ctx.fx._tint(ctx.frame, (255, 0, 0), 0.15) if ctx.window(76, 78) else None
CUSTOM_FRAME_FX = [red_pulse]
def boss_roar(a): # CUSTOM_SFX: a = dict(buf, add, lib, tl, SR)
a["add"](a["buf"], a["lib"]["boom"]() , a["tl"].out(14.4), 0.8)
CUSTOM_SFX = [boss_roar]
頻繁に使う効果は後で fx.py に移して正式な項目にします。
レイアウト規則(実際に遭遇した問題から生まれたもの)
共通
- 絵文字はカラーでレンダリングされます。ただし
▸ ✓ ✕などの記号は □ のように崩れるので、絵文字(✅ ✖️ 👉 ⏩ ⏸)や• → ·を使用します。 - 字幕は1行40文字前後。キーワードは
[大括弧]で強調。停止画面の解説字幕は(tf, tf, "...")のように停止時間を開始=終了とすると、停止中のみ表示されます。 - 同じ瞬間にポップアップ・吹き出し・ステッカーを3つ以上重ねないこと。ポップアップは0.8~1.2秒で十分です。
screen
- カードとハイライトが重ならないように時間を分割します(カード → ハイライト)。カードは次のクリックズーム前に終了させます。
- ズーム状態でハイライトが画面外に出ると切れる → 倍率1.15~1.3。
- ラベル配置
"right"(矢印)、"above-right"(表の行)、"below"(上部要素)。HUD はズーム1.12倍以上でミニモード(左側100px)。
game
- ウルトラワイド(21:9)は16:9キャンバスにレターボックスで収まります。上下の帯に速度バッジ・字幕が入り、アクションを隠しません。画面いっぱいにするには
SHOTSに"fill"。 - ゲージハイライトは
"above|nodim"— 画面を暗くするとアクションが見えなくなります。 - ズームは1.3~1.5倍まで。アクションが速く、過剰だと対象が画面外に出ます。拡大が必要な場合は
MAGNIFYを使用します。 - 停止(FREEZE)は1~2秒、1つの動画に3~4回で十分です。停止中は CALLOUTS で「誰が何を」指します。
- 移動・ローディング区間は SPEED 2~3倍で短縮します。スローモーション0.3~0.4倍は被弾・決定打の0.5~1秒のみ。
- トラックキーフレームは対象が大きく動くたびに打ち、シーンが変わる箇所(カット)では同じ値を2回(直前・直後)記述して補間が飛ばないようにします。
python "$SKILL_DIR/scripts/tracks.py" timeline.pyでシートを作成して確認します。 - HPイベントで被弾時点を特定し、
IMPACTSをフレーム精度で合わせます。被弾 =damage/crit、自分の攻撃ヒット =hit/heavy。 - 元のゲーム音を生かし、BGM は小さく(volume 0.3~0.45)。死亡時点で
MUSIC["end"]+end_fx="scratch"で音楽を切り、sad_tromboneなどの効果音で笑いポイントを作ります。
promo(広告・プロモーション・国際版)
- 元の文字消去: 文字が現れる0.4秒以上前/消えた後のフレームを plate に選びます。フェード中のフレームには薄い文字が残っています → コントラストを上げたクロップ(背景ぼかしを除いて ×4)で確認。消去後は
--preview元の解像度クロップで残像・継ぎ目を確認します。 - 霧・水しぶきのように形が絶えず変わる背景は plate が合いません(灰色のムラ) → plate なしでインペイントし、その場所にチャプタータイポを
veilとともに乗せます。 - 赤い印の検出は濃い赤のみを捉えます(夕日・朱色の空は除外)。空が朱色の場合、ボックス全体が変わって色の帯ができないか確認します。
- コピーは短く: オープニング2~4単語 × 2行、チャプタータイトル2~5単語、エンドカードブランド + 1行。実際の機関・ブランドの公式スローガンは使いません。
- タイポはレターボックス内側(上部140px・下部140pxを除く)に配置。元の文字があった場所は大抵「空けてある空」なので、チャプターを置くのに適しています。
- 音楽: zen は
arcでシーン別エネルギーを設定します。墨切り替え時間が小節境界(80 BPM = 3秒)に合うように シーン速度を調整すると、切り替え・太鼓・印がビートに合います(tl.loadで出力時間を出力 → 速度修正)。段階別音量は calm −20 / peak −12 dB 程度の差があると絶頂が生きてきます。 - 決定的シーン(展開する屏風・日の出)は0.75~1倍、ゆっくりした風景は1.5~2.4倍。大きな章(季節・地域)の切り替えにのみ墨を使い、同じ章の中では元のトランジションを生かします。
- 縦型ショート(30秒) (
recipes/promo_shorts.py): 96 BPM(1小節2.5秒)に1シーンずつ。SEGMENTS = [(元の開始, 終了, 出力長)]で連結し、Remapで速度を逆算するとトランジションが正確に小節に合います。元のトランジション(クロスフェード)は0.2秒に圧縮し、墨・フラッシュの下に隠します。- 最初の1秒がフック: コピー1行 → 小節1にブランドタイトル + 音楽打撃。オープニング・フィナーレは帯レイアウト(中央に元動画 + 上下にタイポ)、本編は画面いっぱいの縦クロップ + 被写体側パンニング(太陽・滝・月は中央、広い風景は左→右)。
- 早送り区間では元の秒が短くなるため、タイポの時間は
(TRIM[0], 出力秒)のように 出力基準 で記述します。チャプターはpace=0.55で早めに登場。 - パーティクルは
clip=Trueでカットとともに切ります(花びらが次の季節に渡らないように)。ショートUIを避けてタイポは上部260px・下部420pxの内側に。
vlog(家族・イベント動画)
- スマートフォン動画は揺れが多いです。揺れる移動区間は3~4倍早送り(モーションブラーが自動入りで滑らか)、元の音声は自動で小さくなります。
- クライマックス(ろうそく消し・乾杯・ゴールイン)は0.4倍スローモーション + フラッシュ + confetti burst + party_horn。音楽はその瞬間から開始(
MUSIC["start"]) — その前は元の音声(誕生日の歌・会話)を生かします。 - 写真を撮るシーンはシャッターが押された直後の ぶれていないフレーム で停止(
look="photo")し、ポラロイドを表示します。停止フレームはプレビューで鮮明か必ず確認します(カメラが動いているフレームはぼやけています)。 - ステッカー・ポップアップ・ハートを 顔の上に置かない こと。顔の座標を測定して、横や上の空いているスペースに配置します。表情(舌出し・ウインク)を指す場合は、ステッカーの代わりに CALLOUTS(
ring=False)で横から指します。 - カウントダウンが画面に表示されている場合(スマホタイマー)は、
countポップアップ3・2・1 をその時間に合わせ、pop効果音を付けます。 - アウトロは停止画面の上にポラロイド2~3枚コラージュ + 短いお祝いメッセージ(
OUTROのtopで上に上げ、stats=[])。 - 字幕・ナレーションがなくてもストーリーが伝わるように: イントロタイトル + シーンごとに短いポップアップ1行で十分です。
4. プレビューの繰り返し
python "$SKILL_DIR/scripts/build.py" timeline.py --preview 3.5,7.4,26 # 元の動画時間
python "$SKILL_DIR/scripts/build.py" timeline.py --preview-out 16.6,36.2 # 出力時間(停止・スローモーション中間確認)
build/preview/sheet*.jpg を Read で確認 し、重なり・切れ・隠れ・座標誤差・文字化けを修正します。ラベル src ↔ out で時間変換も確認できます。停止区間は元の動画時間では確認できないため、--preview-out を使用します。
5. オーディオ
- BGM
MUSIC["style"]: pop(126BPM エレクトロポップ)、epic(96BPM 太鼓・スタッカート弦・ブラス・合唱)、chill(82BPM ローファイ)、cute(132BPM マリンバ・ピチカート)、zen(80BPM 伽耶琴・大笒・杖鼓・太鼓・合唱、MUSIC["arc"] = [(元の動画時間, "calm|flow|pulse|build|peak|hush|finale")])。zen 以外はすべて intro → A → B → build → drop → outro 構造で、drop秒にハイライトが発生します。 - 元の音声: game/vlog/anim はデフォルトでオン。ナレーターが話すと一緒にダッキングされます(
SOURCE_AUDIO["duck"])。 - レベルチェック: ゲームは元の音声が主役です。区間別RMSを測定し、音楽が元の音声より3~5dB小さく、効果音は打撃瞬間のみ聞こえるように調整します。
import tl, music, build; t = tl.load("timeline.py"); m = music.build_music(t)[0] * t.music["volume"]; s = build.source_audio(t, m.shape[1]) - ナレーター(オプション)
NARRATION = [(t, "文章")](ない場合は字幕を読み上げます)。--voice edge(Microsoft ニューラルネットワーク、オンライン — 文章が Microsoft に送信されることを通知します)/--voice sapi(Windows オフライン)。build/voice_report.jsonで rate が +15% を超えたり overflow がある場合は文章を短くします(日本語 ≈ 7音節/秒)。
6. 最終レンダリングと検証
python "$SKILL_DIR/scripts/build.py" timeline.py [--voice edge] [--workers 8]
フレームを分割して複数プロセスで並列レンダリングした後、連結します(1分 1080p ≈ 2~3分、8 workers)。バックグラウンドで実行します。
完了前の確認事項
- 最終行
[done] ... Ns (expected Ns), N MBで長さが一致しているか、ログに Traceback がないかを確認します。 - 出力から数フレームを抽出して確認します:
ffmpeg -ss T -i out.mp4 -frames:v 1 f.png - 音楽・効果音は直接聴けないため、区間RMSで確認し、ユーザーに直接聴いてみるよう伝えます。
ファイル構成
| ファイル | 役割 |
|---|---|
scripts/analyze.py | メタ・タイプ推定・シーン切り替え・音声ピーク・ゲージイベント・グラフ・シート |
scripts/crops.py | 元の座標目盛りクロップ |
scripts/tracks.py | 対象追跡(キーフレーム補間・OpenCV)、検証シート |
scripts/remap.py | 時間リマッピング(TRIM・SPEED・FREEZE) |
scripts/build.py | プレビュー / オーディオミックス(元の音声リマッピング・リミッター) / 並列レンダリング / SRT |
scripts/tl.py | timeline.py ローダー、プロファイルデフォルト値、座標・時間変換 |
scripts/render.py | カメラ(追跡・振動)・画面録画レイヤー・カスタムフック |
scripts/fx.py | 汎用効果: カラーティング、ヒット感、拡大鏡、吹き出し、ポップアップ、ステッカー、バッジ、 |
…