关于 video-edit
video-edit 是将原始录制转换为竖屏短视频或横屏 YouTube 视频的技能。它涵盖转录、剪辑选择、字幕、画面元素、质量检查、渲染及交付文件。
主要功能
- 01检查并准备源视频
- 02生成带词级时间的语音转录
- 03根据停顿和重录制作剪辑段
- 04添加字幕、开场卡片和标注
- 05渲染前检查静帧
- 06导出视频、字幕和发布文案
适用场景
- 01将单次录制剪成竖屏短视频
- 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
详细介绍
视频剪辑
输入一段原始拍摄素材,输出一段完成的视频:video-agent/edits/<slug>/final.mp4。可以是竖屏短视频,也可以是用于 YouTube 的完整横屏视频。
这些工具免费,并在创作者的机器上运行:
- Remotion(用 React 编写视频)及其官方 TikTok 模板,内置本地语音转文字功能和词级时间戳(whisper.cpp)。
- ffmpeg,用于检查和处理音频。
固定且简洁的视觉风格:references/style.md。绘制该风格的代码位于 references/remotion-short.md。
如何运行
- 运行前检查:
node -v && ffmpeg -version && git --version。缺少任何一项:停止并引导他们前往/video-setup tools。 - 使用创作者的语言交流。每个较长步骤(安装、转录、渲染)开始前,先用一行说明你要做什么,以及预计耗时。
- 阅读
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、“for YouTube”、“a reel”):按他们说的做。否则,根据拍摄素材选择,并用一行说明选择结果:
| 格式 | 构图 | 适用情况 | 默认设置 |
|---|---|---|---|
| 短视频 | Short,1080x1920 | 素材时长不足 90 秒,或他们想制作短视频、reel、TikTok 视频 | 开启字幕、添加开场卡片,每 8 到 10 秒添加一个提示标注 |
| 长视频 | Wide,1920x1080 | 横屏素材时长超过 90 秒、完整 YouTube 视频、教程、vlog | 开启字幕(询问:YouTube 观众通常更喜欢单独提供 .srt,设置 showCaptions: false)、除非他们需要,否则不添加开场卡片;最多每 30 到 60 秒添加一个提示标注;添加章节 |
- 横屏素材制作短视频:画面会裁切至中央。如果人物不在画面中央,提醒他们。
- 竖屏素材制作长视频:画面会被裁切成很窄的一条。不要这样做;建议制作短视频。
- 长视频:先说明耗时。使用
medium模型时,笔记本电脑上的转录速度约为实时速度(20 分钟的素材约需 20 分钟;small快 2 到 3 倍);渲染每秒视频需要 3 到 5 秒(15 分钟的剪辑约需 1 小时)。这两项任务都会在后台运行。
下文中的 <comp> 为 Short 或 Wide。
查找对应的脚本:在 video-agent/scripts/ 中找到匹配的脚本(slug 相同或首行相同)。没有脚本也没关系,剪辑将仅依据转录内容进行。
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:将src/Short/index.tsx和src/Root.tsx替换为当前版本的第 2 和第 3 节内容。 - 可选:从 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))'
第二条命令会打印所有超过 0.35 秒的间隔及其前一个词,随后列出带有 style.md 所述边距的保留 ranges。然后修正这些范围:
silencedetect未报告的间隔(呼吸声、轻声词语、音乐):将对应的两个范围合并。- 重录:逐行检查脚本。如果某一行(或开头 3 个词)出现多次,保留最后一次完整录制,并删除从第一次录制的第一个词到保留版本起始处的范围。
- 删除口误(如重说前的“呃”或半个词)、钩子之前的所有内容,以及偏离脚本的谈话。
长视频:规则相同,但间隔阈值使用 0.5 秒而非 0.35 秒(G=500):完整视频需要留出一些停顿,思考时的停顿可以保留。保留有价值的补充内容;删掉没有意义的旁枝内容。没有脚本时,连续说两遍的句子算作重录:保留最后一次。
渲染前,用几行展示结果:
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*标记,时长 2 至 3 秒。 - 标注:人物说出的数字、结果或工具名称,大约每 8 至 10 秒出现一次,间隔至少 4 秒(长视频:最多每 30 至 60 秒一次,只标注关键数字)。
atMs= JSON 中对应词的startMs。
写入 public/<slug>.edit.json(格式见 remotion-short.md 第 4 节)。
6. 质量检查,然后渲染
渲染 3 或 4 张静帧:钩子(第 30 帧)、一个标注、视频中段的一条字幕、最后一秒(长视频:在整个视频中均匀选取 6 至 8 张静帧)。仅短视频:将平台的安全区域叠加到每张图上:
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
笔记本电脑上,每秒视频约需 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:将台词调整到剪辑后的时间线上,每条字幕最多 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 秒。
然后说明视频时长、剪掉了什么、文件位置,并提出一项修改建议(“开场卡片再短一些?少几个提示?换个强调色?”)。修改方式:编辑 JSON,然后重新渲染(步骤 6 和 7)。下一步:/video-publish <slug>。
发布文案
post.md 根据脚本和 voice.md 编写,使用视频所用的语言:
- 标题(YouTube Shorts):少于 60 个字符,主题要出现在前 3 个词中。长视频:少于 70 个字符,体现视频承诺的内容,且与视频相符。
- 说明文字:前 125 个字符要能独立表达完整意思(应用会在此处截断,隐藏后续内容)。接着写 1 到 2 行简短文字,再提出一个请求,使用 voice.md 中的那个请求。
- 搜索词:观众会用来搜索该视频的 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
有些创作者更喜欢使用自己的编辑器;此外,对于超过 3 人的公司,Remotion 需要付费许可证。执行步骤 1 到 4,使用范围写入 public/<slug>.edit.json("hook": null、"callouts": []),跳过步骤 5 到 7,并提供 captions.srt(步骤 8)以及:
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)。