video-edit について
video-editは、録画素材を縦型ショート動画または横型のYouTube動画に仕上げるスキルです。文字起こし、カット選定、字幕や画面要素の追加、品質確認、レンダリング、納品までを案内します。
主な機能
- 01元動画の確認と準備
- 02単語ごとの時刻付き文字起こし
- 03無音や撮り直しに基づくカット作成
- 04字幕、フックカード、コールアウトの追加
- 05レンダリング前の静止画確認
- 06動画、字幕、投稿文の書き出し
活用シーン
- 011回の録画から縦型ショートを作成
- 02横型のYouTube動画を制作
- 03別の編集ソフト向けにSRT字幕を作成
- 04保存済みの編集データを使って動画を修正
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ melvynx/ video-agent-skills --skill video-editインストール後、Claude Code で/video-editを入力して読み込まれたか確認します。
同梱ファイルreferences/remotion-short.mdreferences/style.md
詳細
動画編集
未編集のテイクを1つ用意すると、完成動画が1本書き出されます:video-agent/edits/<slug>/final.mp4。縦型ショート、またはYouTube向けの横型フル動画のどちらかです。
ツールは無料で、クリエイターのマシン上で実行されます。
- Remotion(Reactで動画を作成)と、単語ごとのタイミング情報付きのローカル音声テキスト変換機能(whisper.cpp)を備えた公式TikTokテンプレート。
- チェックと音声には ffmpeg を使用します。
ルックは固定でシンプルです:references/style.md。描画するコードはreferences/remotion-short.mdにあります。
実行方法
- 事前確認:
node -v && ffmpeg -version && git --version。何かが見つからない場合は停止し、/video-setup toolsに案内します。 - クリエイターの言語で話します。長い各工程(インストール、文字起こし、レンダリング)の前に、何をするかと所要時間を1行で伝えます。
- 言語とアクセントカラーは
video-agent/voice.mdで確認します。音声ファイルがない場合は両方を尋ねるか、英語と#FFD400を使います。 - 名前付きスタイル(依頼に
style <name>とあり、/video-stealで作成されたもの)がある場合は、video-agent/styles/<name>.mdを読み、style.mdに重ねて適用します。そちらの値を優先し、記載されたとおりに効果音、ステッカー、カラーグレーディングを編集に反映します。名前のない項目はすべてstyle.mdの設定のままにします。 <slug>:小文字、ハイフン区切りで、ドットやスペースは使いません(文字起こしツールは最初のドットでファイル名を切り詰めます)。- 手順1と2はプロジェクトのルートから実行します。手順3以降のコマンドはすべて
video-agent/studio/で実行し、パスはそのディレクトリからの相対パスです。
1. テイクと形式
指定されたファイルを使います。指定がなければ、video-agent/takes/ 内の最新ファイルを使います。確認します:
ffprobe -v error -show_entries format=duration:stream=codec_type,codec_name,width,height,r_frame_rate,avg_frame_rate,color_transfer -of compact "<take>"
- 音声ストリームがない場合は停止して、その旨を伝えます。
color_transferがsmpte2084またはarib-std-b67の場合はHDRテイクです(iPhoneのデフォルト設定)。変換しないでください。レンダリング時にRemotionが通常の色にマッピングします。次回の撮影に備え、カメラ設定でHDRビデオをオフにするよう伝えます。- それ以外で、ファイルが
.webmの場合、または可変フレームレートの場合(r_frame_rateとavg_frame_rateが異なる)は変換します。Remotionとffmpegのカット処理はいずれも、これらのファイルではずれが生じます。以降は新しいファイルをテイクとして使います:ffmpeg -y -i "<take>" -vf fps=30 -c:v libx264 -crf 18 -preset veryfast -pix_fmt yuv420p -c:a aac -b:a 192k -ar 48000 "video-agent/takes/<slug>-30fps.mp4"
次に形式を決めます。形式が指定されている場合(short、long、「YouTube向け」、「リール」など)は、その指定に従います。指定がなければテイクを見て選び、どちらにしたかを1行で伝えます:
| 形式 | 構成 | 条件 | デフォルト |
|---|---|---|---|
| ショート | Short、1080x1920 | テイクが90秒未満、またはショート、リール、TikTokを希望している場合 | 字幕あり、フックカードあり、8〜10秒ごとにコールアウト |
| ロング | Wide、1920x1080 | 90秒を超える横型テイク、YouTube向けフル動画、チュートリアル、Vlogの場合 | 字幕あり(確認する:YouTube視聴者は.srtのみを好むことが多いため、showCaptions: false)、フックカードは希望がない限りなし、コールアウトは30〜60秒ごとを上限とし、チャプターあり |
- ショートで横型テイクを使う場合は、中央をクロップします。フレームの中央に映っていない場合は注意を伝えます。
- ロングで縦型テイクを使うと、細い帯状にクロップされます。これは避け、ショートを提案します。
- ロングの場合は、まず所要時間を伝えます。ノートPCで
mediumモデルを使うと、文字起こしには動画の長さとほぼ同じ時間がかかります(20分のテイクなら約20分、smallは2〜3倍速)。レンダリングには動画1秒あたり3〜5秒かかります(15分の動画なら約1時間)。どちらもバックグラウンドで実行されます。
以下の <comp> は Short または Wide です。
元になったスクリプトを探します:video-agent/scripts/ 内で一致するスクリプト(slugが同じか、1行目が同じもの)を使用します。スクリプトがなくても問題ありません。その場合、カットは文字起こしのみに基づいて行います。
2. スタジオ(初回のみ)
まず、パッケージに約1 GB、初回の文字起こし時に音声エンジンとそのモデルに0.5〜1.5 GB、さらにセットアップに数分かかることを伝えてください。
git clone --depth 1 https://github.com/remotion-dev/template-tiktok video-agent/studio
cd video-agent/studio
npm i
video-agent/studio/.gitを削除し、プロジェクト内の通常のフォルダーにします。whisper-config.mjsで言語を設定します。- 英語:
WHISPER_MODEL = "medium.en"とWHISPER_LANG = "en"のままにします。 - それ以外の言語:
WHISPER_MODEL = "medium"(低速なマシンでは"small"(466 MB))にし、WHISPER_LANGには言語コード("fr"、"es"、"de"、"pt"など)を設定します。
- 英語:
ShortとWideのコンポジション、およびフォントパッケージを追加します。references/remotion-short.md のセクション1〜3に従い、その後npx tsc --noEmitを実行します。Wideがまだ存在していなかった頃に作成したスタジオの場合は、現在のセクション2と3の内容でsrc/Short/index.tsxとsrc/Root.tsxを置き換えます。- 任意:Claude に Remotion コードを改善してもらうには、
npx skills add remotion-dev/skillsを実行します。
3. 文字起こし
cp "../takes/<take file>" public/<slug>.mp4
node sub.mjs public/<slug>.mp4
public/<slug>.json に、単語ごとのエントリ({ "text": " word", "startMs", "endMs", "confidence" })を書き込みます。JSON がすでに存在するファイルはスキップされます。再度文字起こしするには、JSON を削除してください。
聞き間違えた単語(名前、ブランド名、数字)はスクリプトを参照して修正します。変更するのは text のみで、時刻は変更しないでください。
4. カットリスト
実際の無音部分を検出してから、単語間の間隔を一覧表示します。
ffmpeg -nostats -i public/<slug>.mp4 -af silencedetect=noise=-35dB:d=0.3 -f null - 2>&1 | grep silence_
node -e 'const w=require("./public/<slug>.json"),G=350,B=100,A=150,s=(ms)=>(ms/1000).toFixed(2);let r=[{fromMs:Math.max(0,w[0].startMs-B)}];for(let i=1;i<w.length;i++){const g=w[i].startMs-w[i-1].endMs;if(g>G){console.error(`gap ${s(w[i-1].endMs)} -> ${s(w[i].startMs)} (${g} ms) after "${w[i-1].text.trim()}"`);r[r.length-1].toMs=w[i-1].endMs+A;r.push({fromMs:w[i].startMs-B})}}r[r.length-1].toMs=w[w.length-1].endMs+300;console.log(JSON.stringify(r))'
2つ目のコマンドは、0.35秒を超えるすべての間隔と、その直前の単語を出力し、続けて style.md のマージンを適用した維持対象の ranges を出力します。その後、ranges を修正します。
- silencedetect で検出されない間隔(息継ぎ、声の小さい単語、音楽)は、該当する2つの range を再び結合します。
- 撮り直し:スクリプトを1行ずつ確認します。行(または最初の3単語)が複数回登場する場合は、最後の完全なテイクを残し、最初のテイクの先頭の単語から、残すテイクの開始位置までの ranges を削除します。
- 言い直しの前にある言いよどみ(「えー」や途中までの単語)、フックより前の部分、台本にない会話を削除します。
長尺動画:ルールは同じですが、0.35秒ではなく0.5秒を超える間隔を使います(G=500)。長尺動画には適度な間が必要なので、考え込む間は残してもかまいません。内容のある補足は残し、話がそれるものはカットします。台本がない場合、撮り直しとは同じ文が連続して2回話されていることです。後の方を残します。
レンダリングの前に、結果を数行で表示します。
Take 1:42 → short 0:47 (-55 s)
- 38 pauses cut (41 s)
- 3 retakes dropped: line 2 (x2), line 7
- dropped "ok let me do that again" at 0:58
5. モーション
スクリプトのビジュアルメモを参考にします(メモがない場合は、自分で選びます)。
- フックカード:画面上に表示するフックは6語以内とし、
*accent*の単語を1つ含め、表示時間は2〜3秒にします。 - コールアウト:話者が口にする数字、結果、ツール名を表示します。8〜10秒ごとに1つを目安にし、4秒以内に2つ表示しないでください(長尺の場合は、重要な数字に限り、最大30〜60秒ごとに1つ)。
atMsは、JSON 内にある該当単語のstartMsです。
public/<slug>.edit.json を作成します(形式は remotion-short.md のセクション4を参照)。
6. QC を行ってからレンダリング
静止画を3〜4枚レンダリングします。フック(フレーム30)、コールアウト、動画中盤の字幕、最後の1秒を選びます(長尺の場合は、動画全体にわたって6〜8枚を選びます)。Short のみ:各画像にプラットフォームのセーフゾーンを重ねます。
npx remotion still <comp> out/<slug>-qc-30.png --frame=30 --props=public/<slug>.edit.json
ffmpeg -y -v error -i out/<slug>-qc-30.png -vf "drawbox=x=0:y=0:w=iw:h=230:[email protected]:t=fill,drawbox=x=0:y=1440:w=iw:h=480:[email protected]:t=fill,drawbox=x=850:y=900:w=230:h=540:[email protected]:t=fill" out/<slug>-qc-30-safe.png
各 -safe PNG を確認します(長尺の場合は各静止画)。赤いゾーン(アプリのボタン、名前、説明文で覆われる部分)にテキストがないこと、字幕が顔より下にあること、フックカードが読みやすいこと、コールアウトが目を覆っていないこと、アクセントカラーが適切であることを確認します。編集ファイルを修正してから、次を実行します。
npx remotion render <comp> out/<slug>.mp4 --props=public/<slug>.edit.json
ノートパソコンでは、動画1秒あたり約3〜5秒のレンダリング時間がかかります。バックグラウンドで実行し、所要時間を伝えてください。
7. 音声
音楽(依頼された場合のみ。YouTube Audio Library などのロイヤリティフリーのもの)は最初に追加し、音声より22 dB低くします。
ffmpeg -y -i out/<slug>.mp4 -stream_loop -1 -i "<music file>" -filter_complex "[1:a]volume=-22dB[m];[0:a][m]amix=inputs=2:duration=first:normalize=0[a]" -map 0:v -map "[a]" -c:v copy -c:a aac -b:a 192k out/<slug>-music.mp4
次に、レンダリング結果を音量調整します(音楽がある場合は out/<slug>-music.mp4)。Remotion は音声の音量を調整しません。また、単純な loudnorm の処理では、これほど短いクリップは目標より2〜3 LU小さくなります。まず測定します。
ffmpeg -nostats -i out/<slug>.mp4 -af ebur128=peak=true -f null - 2>&1 | grep -E "^\s+(I|Peak):"
ゲインは、-14 から I: の値を引いた値です(例:I = -17.0 → 3.0dB)。リミッターも適用します。
mkdir -p ../edits/<slug>
ffmpeg -y -i out/<slug>.mp4 -c:v copy -af "volume=<gain>dB,alimiter=limit=0.8:level=false" -c:a aac -b:a 192k -ar 48000 ../edits/<slug>/final.mp4
同じ方法で final.mp4 を測定します。I が -15〜-13、Peak が -1 dBFS 未満であれば適切です。
8. 納品
video-agent/edits/<slug>/ に次のファイルを用意します。
- 投稿できる状態の
final.mp4。 captions.srt:カット後のタイムラインに合わせた字幕です。1つのキューにつき最大7語とし、各文の後に新しいキューを作成します。プラットフォームではクローズドキャプションとして読み込まれます。node -e 'const e=require("./public/<slug>.edit.json"),w=require("./public/"+e.captions),F=30,fr=(ms)=>Math.round(ms/1000*F);let at=0;const p=e.ranges.map(r=>{const f=fr(r.fromMs),n=Math.max(1,fr(r.toMs)-f),q={...r,s:(at-f)/F*1000};at+=n;return q});const o=w.flatMap(x=>{const q=p.find(q=>x.startMs>=q.fromMs&&x.startMs<q.toMs);return q?[{t:x.text.trim(),a:x.startMs+q.s,b:Math.min(x.endMs,q.toMs)+q.s}]:[]});const ts=(ms)=>new Date(Math.max(0,Math.round(ms))).toISOString().slice(11,23).replace(".",",");let c=[],n=0,out="";const flush=()=>{if(c.length)out+=`${++n}\n${ts(c[0].a)} --> ${ts(c[c.length-1].b)}\n${c.map(x=>x.t).join(" ")}\n\n`;c=[]};for(const x of o){c.push(x);if(c.length===7||/[.?!]$/.test(x.t))flush()}flush();process.stdout.write(out)' > ../edits/<slug>/captions.srtedit.json:後から動画を作り直せるように、public/<slug>.edit.jsonのコピーを保存します。post.md:投稿時に貼り付けるテキストです(下記参照)。- 長尺動画のみ、
post.mdにYouTubeの説明欄用のチャプターを記載します。話題が変わる箇所に1〜3分ごとに設定し、時刻はカット後のタイムライン(captions.srtを参照)に合わせます。最初のチャプターは0:00とし、少なくとも3つ、それぞれ10秒以上にします。
次に、動画の長さ、カットした内容、ファイルの保存場所を伝え、変更案を1つ提示します(「フックカードを短くしますか? コールアウトを減らしますか? 別のアクセントカラーにしますか?」)。変更する場合は、JSONを編集して再レンダリングします(手順6と7)。次は /video-publish <slug> を実行します。
投稿文
動画のスクリプトと voice.md をもとに、動画と同じ言語で post.md を作成します。
- タイトル(YouTube Shorts):60文字未満にし、最初の3語にトピックを含めます。長尺動画の場合は70文字未満にし、動画の内容に忠実な、動画が約束する内容を表します。
- キャプション:最初の125文字だけでも意味が通るようにします(アプリでは「もっと見る」の前で省略されます)。続けて短い行を1〜2行と、
voice.mdにある依頼を1つ記載します。 - 検索語:視聴者がこの動画を見つけるために入力する2〜3語を、タイトルか最初の行に自然に含めます。
- ハッシュタグ:末尾に、トピックに関するものを3〜5個記載します。#fyp や #viral は使いません。
- 動画で述べていない内容は加えません。新たな数値、主張、約束は含めません。
このスキルがインストールされている場合は、video-script の humanize パス(references/humanize.md)を実行します。
Title: Your hook is too long
Caption: Nobody hears word 12 of your hook. Cut it to 12 words and put the result first.
Try it on your next three videos.
Follow for one script fix a day.
#shortformvideo #videohooks #contentcreator
CapCut、Premiere、またはRemotionを使わない場合
自分のエディターを使いたいクリエイターもいます。また、Remotionは従業員が3人を超える企業では有料ライセンスが必要です。手順1〜4を実行し、範囲を指定した public/<slug>.edit.json("hook": null、"callouts": [])を作成します。手順5〜7は省略し、手順8の captions.srt と、次のいずれかを渡します。
- 手作業でカットするための範囲を記載した
cuts.md:mkdir -p ../edits/<slug> node -e 'const e=require("./public/<slug>.edit.json"),t=(ms)=>new Date(ms).toISOString().slice(14,23);for(const r of e.ranges)console.log(t(r.fromMs)+" → "+t(r.toMs))' > ../edits/<slug>/cuts.md - または、ffmpegだけを使ったシンプルなカット:
SEL=$(node -e 'const e=require("./public/<slug>.edit.json");console.log(e.ranges.map(r=>`between(t,${r.fromMs/1000},${r.toMs/1000})`).join("+"))') ffmpeg -y -i public/<slug>.mp4 -vf "select='$SEL',setpts=N/FRAME_RATE/TB" -af "aselect='$SEL',asetpts=N/SR/TB" -c:v libx264 -crf 18 -c:a aac ../edits/<slug>/cut.mp4
制約事項
- whisper.cpp は名前や専門用語を聞き間違えます。スクリプトで修正し、数値は目視で確認してください。
- カットの精度は高いものの、完璧ではありません。息継ぎや語尾の小さな音が途切れることがあります。投稿前に一度、結果を確認してください。
- Claudeは収録音声を聞けず、タイミングと silencedetect を信頼します。音質の悪い音声(音楽、エコー、複数人の声)では、どちらの精度も下がります。
- セーフゾーンはTikTok、Reels、Shortsの中間に合わせたものです。各アプリではボタンの位置が少しずつ異なります。
- Remotionのライセンス:個人、従業員3人以下の企業、非営利団体は無料です。それを超える企業には企業向けライセンスが必要です(remotion.pro/license)。