freecut
原则
- 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 帧移动到窗口起始位置。否则在叠加窗口期间会看到动画的中间部分。 - 主 SRT 文件使用输出时间线偏移量:
output_time = word.start - segment_start + segment_offset。否则在片段拼接后,字幕会错位。 - 绝不在单词中间进行剪辑。 每个剪辑边缘都必须对齐到转录文本中的单词边界。
- 在每个剪辑边缘添加填充。 工作窗口:30–200ms。ASR 时间戳有 50–100ms 的漂移——填充可以吸收这种漂移。快节奏视频使用更紧的填充,电影感视频使用更松的填充。
- 仅使用词级别的、逐字的 ASR 文本。 绝不要使用 SRT/短语模式(会丢失亚秒级间隙数据)。也不要使用标准化的填充词(会丢失编辑信号)。
- 按源文件缓存转录。 除非源文件本身发生变化,否则绝不重新转录。
- 并行子 Agent 处理多个动画。 绝不要串行处理。通过
Agent工具一次性生成 N 个;总耗时为最慢的那个。 - 执行前确认策略。 在用户批准清晰的自然语言计划之前,绝不触碰剪辑。
- 所有会话输出都在
<videos_dir>/edit/目录下。 绝不要写入freecut/项目目录内。
本文档中的其他所有内容都是实例。当素材需要时,可以随时偏离。
目录布局
技能文件位于 freecut/ 中。用户素材存放在他们指定的任何位置。所有会话输出都进入 <videos_dir>/edit/。
<videos_dir>/
├── <源文件, 保持原样>
└── edit/
├── project.md ← 记忆;每个会话追加
├── takes_packed.md ← 短语级转录,LLM 的主要阅读视图
├── edl.json ← 剪辑决策
├── transcripts/<name>.json ← 缓存的规范化 ASR JSON
├── animations/slot_<id>/ ← 每个动画的源文件 + 渲染 + 推理
├── clips_graded/ ← 逐段提取的片段(含调色和淡入淡出)
├── master.srt ← 输出时间线字幕
├── downloads/ ← yt-dlp 输出
├── verify/ ← 调试帧 / 时间线 PNG
├── preview.mp4
└── final.mp4
设置
首次安装存在于 install.md(克隆、依赖、ffmpeg、技能注册、API 密钥)。不要在每次会话时都重新运行;冷启动时只需验证:
- 转录后端可用。默认是
whisper(免费、本地)——检查mlx-whisper(Apple Silicon)或faster-whisper是否可以导入。如果两者都未安装,告诉用户pip install mlx-whisper(或faster-whisper),而不是静默地回退到付费后端。对于可选的vibevoice/elevenlabs后端,在 freecut 仓库根目录的环境变量或.env文件中检查VIBEVOICE_ASR_URL/ELEVENLABS_API_KEY。 ffmpeg+ffprobe在 PATH 中。- Python 依赖已安装(在仓库内执行
uv sync或pip install -e .)。 - 如果会话需要 HyperFrames 或 Remotion 插槽,Node.js + npm 需可用。HyperFrames 目前需要 Node.js 22+。
yt-dlp、HyperFrames、Remotion、Manim 仅在首次使用时安装。- 首次使用的动画设置应在插槽目录内进行,绝不能在 freecut 仓库根目录。HyperFrames 可以通过
npx --yes hyperframes ...调用;Remotion 可以使用npx create-video@latest搭建,或者在本地项目中作为依赖安装后再使用其remotion render命令。 - 此技能包含了
skills/manim-video/。在构建 Manim 插槽时,请阅读其 SKILL.md。
辅助脚本(helpers/transcribe.py、helpers/render.py 等)与此 SKILL.md 文件位于同一目录。根据包含此文件的目录解析它们的路径——该技能通常被符号链接到 ~/.claude/skills/freecut/ 或 ~/.codex/skills/freecut/。
辅助脚本
transcribe.py <video>— 单文件转录。通过--backend {whisper,vibevoice,elevenlabs}可选择后端(默认whisper,本地 + 免费,单说话人)。vibevoice使用VIBEVOICE_ASR_URL实现实时说话人日志;elevenlabs使用ELEVENLABS_API_KEY并支持--num-speakers。结果会被缓存。transcribe_batch.py <videos_dir>— 4 工作线程并行转录。使用相同的--backend标志。适用于多段素材。pack_transcripts.py --edit-dir <dir>—transcripts/*.json→takes_packed.md(短语级别,静音 ≥ 0.5s 或说话人变化时断句)。由于 JSON 形状已规范化,此功能在所有后端上工作方式相同。timeline_view.py <video> <start> <end>— 生成胶片条 + 波形 PNG。按需的视觉深入检查。不是扫描工具——在决策点使用,而不是持续使用。render.py <edl.json> -o <out>— 逐段提取 → 拼接 → 叠加层(PTS 偏移) → 最后是字幕。--preview用于快速生成 720p 预览。--build-subtitles用于内联生成 master.srt。grade.py <in> -o <out>— ffmpeg 滤镜链调色。包含预设 +--filter '<raw>'用于自定义。
对于动画,创建 <edit>/animations/slot_<id>/ 目录,使用 Bash 工具,并通过 Agent 工具生成一个子 Agent。
工作流程
-
清点素材。 使用
ffprobe检查每个源文件。对目录运行transcribe_batch.py。运行pack_transcripts.py生成takes_packed.md。对一两个片段运行timeline_view以获得视觉第一印象。 -
预扫描问题。 快速浏览一遍
takes_packed.md,记录口头失误、明显的用词不当或需要避免的措辞。形成一个简单列表,作为编辑简报的输入。 -
对话。 用清晰的自然语言描述你所看到的。根据素材本身提出针对性问题。收集:内容类型、目标长度/宽高比、美学/品牌方向、节奏感、必须保留的时刻、必须剪掉的时刻、动画和调色偏好、字幕需求。不要使用固定的检查清单——每次的合适问题都不同。
-
提出策略。 4–8 句话:结构形态、片段选择、剪辑方向、动画计划、调色方向、字幕风格、预估时长。等待确认。
-
执行。 通过编辑子 Agent 简报生成
edl.json。在存在歧义的时刻深入检查timeline_view。在并行的子 Agent 中构建动画。对每个提取的片段应用调色。通过render.py合成最终视频。 -
预览。 运行
render.py --preview。 -
自我评估(在展示给用户之前)。 对渲染后的输出(而非源文件)在每一个剪辑边界处运行
timeline_view(±1.5s 窗口)。检查每张图片是否存在以下问题:- 剪辑点处的视觉不连贯/闪烁/跳跃
- 边界处的波形尖峰(漏掉 30ms 淡入淡出的音频爆音)
- 字幕被叠加层遮挡(违反规则 1)
- 叠加层未对齐或显示错误帧(违反规则 4)
同时抽样检查:前 2s、最后 2s 以及中间 2–3 个点——检查调色一致性、字幕可读性、整体连贯性。对输出运行
ffprobe,验证时长与 EDL 预期一致。如果任何一项失败:修复 → 重新渲染 → 重新评估。自我评估最多进行 3 轮——如果 3 轮后问题依然存在,向用户标记这些问题,而不是无限循环。只有在自我评估通过后才展示预览。
-
迭代 + 持久化。 接收自然语言反馈,重新计划,重新渲染。绝不重新转录。用户确认后生成最终渲染版本。将结果追加到
project.md。
剪辑技巧
- 音频优先。 从单词边界和静音间隙中寻找候选剪辑点。
- 保留峰值时刻。 笑声、笑点、强调的节拍。剪辑点应延伸到笑点之后以包含反应——笑声本身就是节拍。
- 说话人交接 时,在两次发言之间保留一定的时间间隔。常用值:400–600ms。快节奏视频更短,电影感视频更长。这是一个品味判断。
- 音频事件作为信号。
(laughs)、(sighs)、(applause)标记了节拍。剪辑点应延长以包含它们。 - 静音间隙是剪辑候选。 长度 ≥ 400ms 的静音通常是最干净的。150–400ms 的短语边界在视觉检查后可用。长度 < 150ms 不安全(可能位于短语中间)。
- 剪辑填充示例(此技能发布的演示视频使用):在第一个保留单词前填充 50ms,在最后一个保留单词后填充 80ms。混剪节奏更紧,纪录片更松。保持在 30–200ms 的工作窗口内(硬性规则 7)。
- 绝不要独立地推理音频和视频。 每个剪辑点都必须同时作用于两个轨道。
打包的转录文件(主要阅读视图)
pack_transcripts.py 读取所有 transcripts/*.json 文件,并生成一个 markdown 文件,其中每个片段(take)都是一个由短语级行组成的列表,每行以其 [起始-结束] 时间范围作为前缀。短语在静音 ≥ 0.5s 或说话人变化时断开。这是编辑器子 Agent 用来选择剪辑点的工件——它通过纯文本提供了单词级别的精度,而所需的 tokens 仅为原始 JSON 的十分之一。
示例行:
## C0103 (持续时间: 43.0s, 8 个短语)
[002.52-005.36] S0 一个 Web Agent 所做的百分之九十的工作都是完全浪费的。
[006.08-006.74] S0 我们解决了这个问题。
编辑器子 Agent 简报(用于多片段选择)
当任务是“从多个片段中,为每个节拍选择最佳的一个”时,生成一个专门的子 Agent,并附带一个如下形状的简报。结构是承载核心逻辑的;音调形状示例仅供参考。
你正在编辑一个 <类型> 视频。为每个节拍选择最佳的一个片段,并按节拍的逻辑顺序排列,而不是按源文件的顺序。
输入:
- takes_packed.md(所有片段的时间标注短语级转录)
- 产品/叙事背景:<来自用户的 2 句话描述>
- 说话人:<姓名、角色、表达风格说明>
- 预期结构:<选择一个原型,或自行创造>
- 需要避免的口头失误:<来自预扫描步骤的列表>
- 目标时长:<秒>
常见的结构原型(选择一个,或者改编/创造):
- 科技产品发布/演示: 钩子 → 问题 → 解决方案 → 好处 → 示例 → 行动号召
- 教程: 介绍 → 准备 → 步骤 → 陷阱 → 总结
- 采访: (问题 → 回答 → 追问)循环
- 旅行/活动: 到达 → 亮点 → 安静时刻 → 离开
- 纪录片: 论点 → 证据 → 反方观点 → 结论
- 音乐/表演: 前奏 → 主歌 → 副歌 → 桥段 → 尾奏
- 或者创造你自己的。
规则:
- 起始/结束时间必须落在转录文本的单词边界上。
- 在剪辑边界添加填充(工作窗口 30-200ms)。
- 优先选择 ≥ 400ms 的静音作为剪辑目标。
- 如果没有更好的片段,可以保留不可避免的口误。在“原因”中注明。
- 如果超过预算,进行修改:删除一个节拍或修剪尾部。报告总时长并自我修正。
输出(JSON 数组,不要包含说明文字):
[{"source": "C0103", "start": 2.42, "end": 6.85, "beat": "钩子",
"quote": "...", "reason": "..."}, ...]
返回最终的 EDL 和一行总时长检查结果。
调色(当用户要求时)
你的工作是推理图像,而不是应用某个预设。查看一帧画面(通过 timeline_view),决定哪里有问题,调整一项,再次查看。
心理模型是 ASC CDL。每个通道:out = (in * slope + offset) ** power,然后是全局饱和度。slope → 高光,offset → 阴影,power → 中间调。
示例滤镜链(grade.py 的 --list-presets 可以列出预设;将它们作为起点或混合使用):
warm_cinematic— 复古/技术感,微妙的青橙色调分离,低饱和度。在真实的发布视频中使用过。对口播视频安全。neutral_punch— 最小化的校正:对比度提升 + 温和的 S 形曲线。无色相偏移。none— 直接复制。用户未提出要求时的默认选项。
对于其他任何情况——肖像、自然、产品、音乐视频、纪录片——创造你自己的滤镜链。grade.py --filter '<raw ffmpeg>' 接受任何滤镜字符串。
硬性规则:在提取过程中逐段应用(不要在拼接后应用,后者会导致二次编码)。在没有检查肤色之前,绝不要使用激进的调色。
字幕(当用户要求时)
字幕有三个值得考虑的维度:分块(每行 1/2/3 个词或一个句子)、大小写(全大写/首字母大写/自然写法)和位置(距离底部边缘的距离)。正确的组合取决于内容。
已实践的风格——选择一个,改编它,或根据内容创造新的:
- 全大写 / 每行 1 词 / 底部 3% 边距 — 非常适合活泼的快节奏促销视频。
- 首字母大写 / 每行 2 词 / 底部 5% — 干净的科技教程。
- 自然写法 / 每句一行 / 底部 5% — 反光/文档风格。
- 自然写法 / 混合(2-3 词为主,关键句用整句)/ 底部 4% — 视频播客/对话风格。
实现细节:撰写者会在 project.md 中生成一个分块的“燃烧列表”。render.py 的 --build-subtitles 命令将其转换为带时间偏移量的 SRT 文件。单行中的溢出由 ffmpeg 的 subtitles 滤镜自动换行处理——皮质损伤并不意味着你需要强制预换行。
在部署之前通过 timeline_view 验证最终字幕。
叠加动画(按需)
::: important 并行化
始终同时启动所有动画插槽。不要串行构建。使用 Agent 工具并行生成 N 个子 Agent。总墙钟时间 ≈ 最慢的那个。
:::
每个动画都是一个 slot_<id>/ 目录,包含:
source.gif/source.mov/source.png/source_<frame>.png— 动画资产,由子 Agent 生成render.sh— 一个 shell 脚本,在操作完成后输出slot_<id>_final.mov(或.png序列)到 slot 目录。使用 ffmpeg 渲染到-c prores_ks -profile:v 3 -pix_fmt yuv422p10le以保留颜色精度;最后的合成阶段会根据需要转换为 H.264/5。reasoning.md— 关于为什么选择此动画及其结构的简短说明。
子 Agent 会收到此 SKILL.md 中它们所需的部分(特别是关于叠加层和 setpts 偏移的规则),以及任何特定的用户偏好。它们可以使用 HyperFrames、Remotion、Manim(通过 skills/manim-video/ 子技能)、PIL、ffmpeg(如 drawtext、movie 滤镜)或你认为合适的任何方法。没有任何限制。
当子 Agent 完成其动画仓库后,它会返回其 slot_<id>/ 目录的路径。主 Agent 收集这些路径,将它们填充到 EDL 的 "effects": [{"type": "overlay", "path": ".../slot_<id>/", ...}] 中,然后传递到 render.py,后者会处理偏移、持续时间、alpha 通道和最终的合成。
额外创建模式
如果用户想要一些与当前编辑不直接相关的额外内容、风格或技术解释——例如,一个展示镜头如何工作的演示动画,或一个在开始时介绍说话人身份的卡片——自由地创建一个新的动画插槽并并行启动一个子 Agent。像常规叠加动画一样处理时间和合成。
构图方法
对于引导视觉注意力的静态叠加层——例如,在相机设置教程中将当前设置居中并淡化其余部分的圆形遮罩——使用 PIL 生成矢量风格的遮罩,使用 center: (radius, softness, opacity...) 符号。像常规动画一样在 slot_<id>/ 中设置它。
平台集成
- 此技能依赖于
Agent工具进行子 Agent 通信(从主技能上下文向上生成)。在 Claude Code 中,这是Codex或Bash工具。在 Cursor 中,它是@Codex或Agent的等效调用。如果你所在的平台不支持子 Agent,需要手动运行Bash命令直到工具完成。 - 时间线查看器使用
matplotlib(由transcribe.py或timeline_view.py触发)。这在无头环境中可以工作,但会保存 PNG 而不是显示窗口。 - Sub-agent 编排在缺少
Agent工具的平台上会自动降级为串行 Bash 调用。这对于最终视频来说仍然是正确的,只是更慢。
参考
- 此技能附带了
skills/manim-video/。在构建 Manim 插槽时读取其 SKILL.md。 - HyperFrames 文档:https://github.com/superloach/hyperframes (注意:可以在没有项目文件的情况下使用
npx --yes hyperframes调用) - Remotion 文档:https://remotion.dev