short-editing について
short-editing は、撮影素材から完成した短尺動画を作るクリエイター向けスキルです。単一の仕様ファイルでローカルレンダラーを動かし、文字起こし、カット、モーション、字幕、音声ミックス、品質確認を行います。
主な機能
- 011 本の素材から短尺動画を作成
- 02音声を文字起こししてカット時刻を対応
- 03シーン、字幕、モーションを設定
- 04動画をレンダリングして音声をミックス
- 05静止画を生成して品質を確認
- 06動画、ポスター、字幕ファイルを出力
活用シーン
- 01撮影素材を短尺動画に編集
- 02無音や言い直しを取り除く
- 03字幕、音楽、効果音を追加
- 04縦型または正方形の動画を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ melvynx/ video-agent-skills --skill short-editingインストール後、Claude Code で/short-editingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/looks.jsonassets/icons/build-icons.mjsassets/music/tracks.jsonengine/camera.mjsaudio.mjschrome.mjsfaces.swiftimages.mjsengine/bin/darwin/faces.hashmatte.hashfacesmatteengine/lib/chill-synth.jschill.jscues.jsencode.jsplayer.jschill-styles.jsdsp.jsruntime-yt.jskit.jsruntime.jsscenes-crash.jsscenes-clean.jsscenes-faceless.jsscenes-master.jsscenes-story.jsscenes-life.jsscenes-meta.jsstyle.js詳細
翻訳後に原文が更新されています。最新の内容は原文をご確認ください。
ショート動画の編集
素材のワンテイクから、完成動画を1本作成します:video-agent/edits/<slug>/final.mp4。縦型ショート動画、またはYouTube向けの横型フル動画のいずれかです。
ツールは無料で、制作者のマシン上で動作します。
- Remotion(Reactで動画を作成)と、単語ごとのタイミング情報を含むローカル音声文字起こし機能(whisper.cpp)を搭載した公式TikTokテンプレート。
- チェックと音声処理にはffmpegを使用します。
見た目は固定でシンプルです:スタイル.md。描画コードはRemotionショート動画.mdにあります。
実行方法
- 実行前チェック:
node -v && ffmpeg -version && git --version。何かが不足している場合は、そこで止めて/studio-setup toolsに案内します。 - 制作者の言語で話します。インストール、文字起こし、レンダリングなど、時間のかかる各ステップの前に、何をするかと所要時間を1行で伝えます。
- 言語とアクセントカラーを確認するため、
video-agent/voice.mdを読みます。音声ファイルがない場合は両方を尋ねるか、英語と#FFD400を使用します。 - 名前付きスタイル(リクエスト内で
style <name>と指定され、/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)。次に実行するのは /publish <slug> です。
投稿文
動画の台本と voice.md をもとに、動画と同じ言語で post.md を作成します。
- タイトル(YouTube Shorts):60文字未満にし、最初の3語でトピックを示します。長尺動画では70文字未満にし、動画の内容に忠実な約束を伝えます。
- キャプション:最初の125文字だけでも意味が通るようにします(アプリでは「もっと見る」の前で切られます)。その後に短い行を1~2行と、voice.md にある依頼を1つ入れます。
- 検索ワード:視聴者が動画を見つけるために入力しそうな2~3語を、タイトルまたは最初の行に自然に記載します。
- ハッシュタグ:トピックに関連するものを最後に3~5個付けます。#fyp や #viral は使いません。
- 動画で述べていないことは書きません。新しい数字、主張、約束を加えないでください。
そのスキルがインストールされている場合は、studio-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 を使わない場合
自分の編集ソフトを好むクリエイターもいます。また、従業員が4人以上の企業が Remotion を使うには有料ライセンスが必要です。手順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)。