视频编辑(Video Edit) 是做什么的?
Fork 自 browser-use/video-use (MIT):使用本地 whisper.cpp 而非 ElevenLabs,在每次渲染前增加验证关卡,使用 Hyperframes 字幕而非 libass 字幕(因为 ffmpeg 的 Homebrew 版本没有 libass),以及为社交媒体广告变体提供画布重新构图。
原则
- LLM 根据原始转录 + 按需视觉信息进行推理。 唯一值得保留的衍生产物是精炼的短语级转录(
takes_packed.md)。其他一切——填充词标记、重拍检测、镜头分类、强调评分——都在决策时即时推导。 - 音频是首要的,视觉随后。 剪切候选来自语音边界和静音间隙。只有在决策点才深入查看视觉信息。
- 询问 → 确认 → 执行 → 迭代 → 持久化。 在用户用纯英文确认策略之前,绝不触碰剪辑。
- 泛化。 不要假设这是什么类型的视频。查看素材,询问用户,然后进行编辑。
- 艺术自由是默认选项。 本文档中的每个具体数值、预设、字体、颜色、时长、音高结构和技术都来自一个已验证视频的工作示例——不是强制要求。阅读它们以了解什么是可能的以及为什么每种方法有效。然后根据素材的实际情况和用户的真实需求做出自己的审美判断。你必须做的唯一事情是下面“硬性规则”部分的内容。 其他一切由你决定。
- 自由创造。 如果素材需要本文档未描述的技术——分屏、画中画、下部身份卡片、反应剪辑、速度斜坡、冻结帧、交叉溶解、匹配剪辑、L 剪辑、J 剪辑、呼吸时的速度斜坡——都可以构建。辅助工具是 ffmpeg 和 PIL。它们可以做格式支持的任何事情。不要等待许可。
- 在向用户展示之前验证自己的输出。 如果你自己都不会发布,就不要展示出来。
硬性规则(生产正确性——不可协商)
这些是偏离会导致静默失败或输出损坏的规则。它们不是审美问题,而是正确性问题。请记住它们。
- 字幕在滤镜链中最后应用,在所有叠加层之后。否则叠加层会隐藏字幕。静默失败。
- 逐段提取 → 无损
-c copy拼接,而不是单遍滤镜图。否则在添加叠加层时,每个片段都会被双重编码。 - 每个片段边界处有 30ms 音频淡入淡出(
afade=t=in:st=0:d=0.03,afade=t=out:st={dur-0.03}:d=0.03)。否则每个剪辑点都会出现可听见的爆音。 - 叠加层使用
setpts=PTS-STARTPTS+T/TB,将叠加层的第 0 帧移动到其窗口开始位置。否则在叠加窗口期间会看到动画的中间部分。 - 字幕使用输出时间轴偏移:
output_time = word.start - segment_start + segment_offset,其中每个片段占满其整帧长度(captions.py负责计算)。否则字幕在片段拼接后不对齐。 - 永远不要在单词中间剪切。 将每个剪辑边缘对齐到转录中的单词边界。
validate_edl.py --fix自动执行此操作。 - 填充每个剪辑边缘。 工作窗口:30–200ms。单词边缘已经对齐到音频包络,但填充吸收了剩余部分。快节奏时更紧,电影感时更松。
- 仅使用词级逐字 ASR。 永远不要使用 SRT/短语模式(会丢失亚秒级间隙数据)。永远不要归一化填充词(会丢失编辑信号)。
transcribe.py提示 whisper 保留“嗯”/“啊”——不要移除提示。 - 每个源文件缓存转录。 除非源文件本身发生变化,否则不要重新转录。
- 多个动画使用并行子代理。 永远不要串行。通过
Agent工具一次性生成 N 个;总挂钟时间 ≈ 最慢的一个。 - 执行前确认策略。 在用户批准纯英文计划之前,绝不触碰剪辑。
- 所有会话输出放在
<videos_dir>/edit/中。 永远不要写入技能目录内。 - 每次渲染前进行验证。
validate_edl.py <edl> --fix,然后仅在退出码为 0 时进行渲染。它能够捕获虚构的源 ID、超出文件末尾的时间、单词中间的剪切、缺失的叠加文件以及超出剪辑范围的叠加层——这些正是 LLM 编写的编辑列表中实际存在的失败模式。 - 字幕是 Hyperframes 层,而不是烧录字幕。 Homebrew 的 ffmpeg 没有 libass,因此 EDL 中的
subtitles会失败。请使用captions.py;render.py将字幕 WebM 合成在每一个叠加层之上。 - 源 ID 是文件主名。 在
sources中,键必须是视频文件名不带扩展名(take_B.mp4使用take_B),或者当通过--audio-track N转录时为<stem>.track<N>——因为这是找到转录的方式。当字幕启用时,验证器会在不匹配时报错。 - 每次渲染使用一个帧率。 如果你给
render.py传递了--fps,也要给validate_edl.py和captions.py传递相同的--fps。范围会被四舍五入到整帧,以保证字幕不会漂移。
本文档中的其他所有内容都是工作示例。当素材需要时可以偏离。
目录布局
技能本身位于自己的目录中(辅助脚本和模板在此文件旁边)。用户素材放在他们放置的任何地方。所有会话输出进入 <videos_dir>/edit/。
<videos_dir>/
├── <源文件,未修改>
└── edit/
├── project.md ← 记忆文件;每次会话追加内容
├── takes_packed.md ← 短语级转录,LLM 的主要阅读视图
├── edl.json ← 剪辑决策(edl_9x16.json、edl_1x1.json … 用于变体)
├── transcripts/<name>.json ← 缓存的 whisper.cpp 转录(词级 + 静音)
├── captions_<edl stem>/ ← Hyperframes 字幕合成 + captions.webm
├── animations/slot_<id>/ ← 每个动画的源文件 + 渲染 + 推理
├── clips_graded/ ← 每个片段的带调色和淡入淡出的提取
├── downloads/ ← yt-dlp 输出
├── verify/ ← 调试帧 / 时间轴 PNG
├── preview.mp4
└── final.mp4
环境设置
install.sh / setup.sh 安装所有内容(Homebrew 包、.venv、whisper 模型、Hyperframes + Chrome)。在冷启动时只需验证——如果缺少 .venv 或某个辅助脚本在导入或缺少工具时失败,则在执行其他任何操作之前运行 <this skill dir>/setup.sh(它是幂等的):
PY=<this skill dir>/.venv/bin/python存在。使用$PY运行每个辅助脚本,永远不要使用系统 Python(它缺少 numpy/Pillow/OpenCV)。ffmpeg、ffprobe、whisper-cli在 PATH 中,以及一个 ggml whisper 模型。默认:~/.claude-video-vision/models/ggml-large-v3-turbo.bin;可以通过VIDEO_EDIT_WHISPER_MODEL覆盖。- Hyperframes 需要 Node.js 22+。始终调用固定版本:
npx --yes [email protected] …。 yt-dlp和 Manim 仅在首次使用时安装。此技能包含skills/manim-video/;在构建 Manim 插槽时阅读其 SKILL.md。- 没有 API 密钥。除了 Hyperframes 的一次性 npm 下载外,任何内容都不会离开机器。
辅助脚本位于此 SKILL.md 文件旁边的 helpers/ 目录中。解析相对于包含此文件的目录的路径。
辅助脚本
所有脚本都通过 $PY helpers/<name>.py … 调用。
transcribe.py <video>— 本地 whisper.cpp,词级,保留填充词,单词边缘对齐到音频包络,列出静音。每个源文件缓存(仅在文件更改时重新运行)。--language en跳过语言检测;--audio-track N用于多音轨录制。transcribe_batch.py <videos_dir>— 逐个处理文件夹中的每个视频(whisper 已经占满 GPU)。pack_transcripts.py --edit-dir <dir>—transcripts/*.json→takes_packed.md(短语级,在 ≥ 0.5s 的静音处断开;对于语速快的人,将--silence-threshold降低到 0.3)。timeline_view.py <video> <start> <end>— 生成胶片条 + 波形 PNG。按需的视觉深入探查。不是扫描工具——在决策点使用,而不是持续使用。validate_edl.py <edl.json> [--fix]— 每次渲染前的验证关卡(硬性规则 13)。--fix将边缘对齐到单词间隙,填充它们(--pad-in、--pad-out),将范围四舍五入到整帧,重新计算total_duration_s,保留edl.json.bak。关于边缘静音 < 30ms 的警告在--fix后仍然存在:这些剪辑点位于单词接触的地方——将它们移动到一个真正的停顿处。captions.py <edl.json>— 输出时间轴词级字幕,作为 Hyperframes 合成 → 透明captions.webm,设置 EDL 的captions键。样式标志:--accent、--color、--top、--size、--font、--case、--words、--no-pop。render.py <edl.json> -o <out>— 逐段提取(帧精确、HDR→SDR、画布重新构图、调色、淡入淡出)→ 无损拼接 → 叠加层(PTS 偏移)→ 字幕 → loudnorm。--preview用于质量控制,--draft仅用于剪辑检查。reframe.py <edl.json> [--apply]— 在每个范围内通过 OpenCV 人脸检测(YuNet)→crop_x/crop_y,使说话者居中并保持头部空间,作用于 EDLcanvas。在每次更改canvas宽高比后,在validate_edl.py --fix之后运行。它会标记那些无法用一次静态裁剪容纳的移动范围(MOVES,需要拆分)和没有检测到人脸的(no face,需要手动选择裁剪)。范围的"crop_lock": true可保护手动裁剪。scenes.py <video>— OpenCV 镜头变更检测,加上每个镜头的DARK/BLURRY标志 →edit/shots/<stem>.json。用于转录无法结构化的素材:B-roll、产品镜头、蒙太奇、多机位导出、无声音片段。镜头边界是清晰的视觉剪辑点;标记的镜头很少在广告中使用。grade.py <in> -o <out>— ffmpeg 滤镜链调色。提供预设 +--filter '<raw>'用于自定义。
对于动画,创建 <edit>/animations/slot_<id>/,使用 Bash 并通过 Agent 工具生成子代理。
流程
-
库存检查。 对每个源文件运行
ffprobe。对目录运行transcribe_batch.py。对于语音很少或无语音的源文件(B-roll、产品镜头),改为运行scenes.py获取其镜头。阅读它打印的QC:行(每个转录中qc下方也有):宽度 ≤20ms 或从静音内部开始的单词时间不可靠——在使用它们前,对任何靠近这些单词的剪辑点使用timeline_view进行检查。- 多个说话者(通话、采访):没有说话者标签。从内容推断(问题 vs 回答),然后对你计划保留的每个短语使用
timeline_view确认(在视频通话中,活动说话者磁贴会显示谁在说话)。如果通话是每人一个音频轨道录制的,则对每个轨道使用--audio-track N进行转录。运行pack_transcripts.py生成takes_packed.md。抽样一两个timeline_view以获得视觉第一印象。
- 多个说话者(通话、采访):没有说话者标签。从内容推断(问题 vs 回答),然后对你计划保留的每个短语使用
-
问题预扫描。 通读
takes_packed.md一次,记下口误、明显的说错或需要避免的措辞。列出清单,提供给编辑简报。 -
对话。 用纯英文描述你看到的内容。询问基于素材的问题。收集:内容类型、目标长度/宽高比、美学/品牌方向、节奏感觉、必须保留的时刻、必须剪掉的时刻、动画和调色偏好、字幕需求。不要使用固定检查表——正确的提问每次都不一样。
-
提出策略。 4-8 句话:形态、片段选择、剪辑方向、动画计划、调色方向、字幕风格、时长估计。等待确认。
-
执行。 通过编辑子代理简报生成
edl.json。在模糊时刻使用timeline_view深入探查。在并行子代理中构建动画。运行validate_edl.py --fix直到其退出码为 0。如果需要字幕,则运行captions.py(字幕是基于最终范围构建的,因此在范围变更后重新运行它)。 -
预览。
validate_edl.py(不带--fix)→render.py --preview。 -
自我评估(在向用户展示之前)。 在渲染输出(而非源文件)的每个剪辑边界处(±1.5s 窗口)运行
timeline_view。检查每张图片是否有:- 视觉不连续 / 闪烁 / 剪辑点跳跃
- 边界处波形尖峰(音频爆音未通过 30ms 淡入淡出)
- 字幕被叠加层遮挡(违反规则 1)
- 叠加层未对齐或显示错误帧(违反规则 4)
同时抽样:前 2s、后 2s 以及 2-3 个中间点——检查调色一致性、字幕可读性、整体连贯性。对输出运行
ffprobe以验证时长是否与 EDL 预期匹配。测量音频,不要假设:
ffmpeg -i out.mp4 -af ebur128=peak=true -f null -获取集成响度和真实峰值,以及每个部分的 RMS(对话、纯音乐、结束卡)。结束卡比对话低 15 dB,或者效果比语音更响,都是错误。你无法听到音频:请说明这种情况,并报告数值。对于用户将发布的任何内容(发布会、推广、广告),还要生成一个评论子代理,提供渲染文件、EDL 和用户提供的任何参考视频。指示它挑剔,不要夸奖:给出结论,按顺序列出问题及时间码和证据(帧、电平),以及首先要做的 5 个修复。新鲜的眼睛能发现作者已经看不到的缺陷——被切掉的妙语、0.5 秒的 meme、在手机屏幕上无法阅读的 28px 文本。
如果有任何问题:修复 → 重新渲染 → 重新评估。自我评估最多 3 轮——如果 3 轮后问题仍然存在,则将其标记给用户,而不是无限循环。只有在自我评估通过后才展示预览。
-
迭代 + 持久化。 自然语言反馈,重新规划,重新渲染。不要重新转录。确认后最终渲染。追加到
project.md。
剪辑技巧(技术)
- 音频优先。 从单词边界和静音间隙中提取剪切候选。
- 保留高潮。 笑声、点睛之笔、强调节拍。在妙语后延长以包含反应——笑声本身就是节拍。
- 说话者交接时需要话语之间的空气。常见值:400–600ms。快节奏时更短,电影感时更长。审美判断。
- 笑声和反应未被标记(whisper 不发出音频事件)。在
timeline_view波形中找到它们作为无语音但响亮的段落;在它们之后延长——笑声本身就是节拍。 - 静音间隙是剪切候选。