竖版视频动态图形剪辑
将原始竖版视频转换为完整的动态图形剪辑:
setup → analyze → 询问用户:风格(风格板)+ 准备选项 → 节拍表 → plan.json
→ 检查 + 预览循环 → 渲染叠加层 → 合成 → 验证 → 提供:字幕 + 额外选项
叠加层使用 HTML/GSAP 进行逐帧渲染,背景透明(assets/engine.html),因此波斯语字符形状、字体和渐变都能达到像素级完美。你无需手写动画代码:只需编写一个 plan.json,列出组件及其时间。引擎会在选定的 风格预设 中对其进行动画处理,该预设定义了外观、动画、转场和音效组合,并为每个组件分配默认音效。
使用用户的母语(通常是波斯语)进行交流。进度更新保持简短。
为何要让剪辑“恰到好处”而不是千篇一律
观众会注意到图形或声音有半秒的偏差,或者它们与所说内容毫无关系。这正是让剪辑显得业余的地方。以前的剪辑正是因此受到批评:装饰性徽章出现在说话者的脸上,却与他所说的内容不符。后来,用户还表示剪辑开始看起来重复。以下四个想法同时解决了这两个问题,并且工具强制执行了其中大部分:
- 锚定到单词。 任何重复语音的文字都使用单词锚点(
"t": "w:رایگان"),因此它会在音节上弹出,而不是在附近。仅对纯视觉事件使用手动输入的秒数。 - 锚定到画面。 点击、页面更改和布局缩放来自
motion.json事件("t": "m:m12")以及你自己阅读的带时间戳的联系表。没有可见点击的点击音效就是噪音。 - 保护面部。 在
plan.avoid中声明面部和画中画矩形。render.js check随后会标记任何覆盖它们的元素。在渲染之前修复所有COVERS警告。 - 让用户选择外观,然后在其中进行变化。 在设计之前(第 2 步)询问风格。然后不要每次都回到相同的模式:改变开场格式、承载想法的组件以及转场。
references/styles.md包含每种风格的操作手册和开场格式列表。
第 0 步 — 安装(首次在机器上运行)
python <skill>/scripts/setup.py
安装 faster-whisper、puppeteer-core 和 gsap 到 ~/.cache/reel-motion-edit/,合成音效库,并下载 Whisper 模型(large-v3-turbo,约 1.6 GB;如果 huggingface.co 被屏蔽或断开,它会恢复并回退到 hf-mirror.com)。这是“下载所需内容”的步骤,所以无需询问直接执行。用一行文字告诉用户正在下载什么。在后台运行:在慢速连接上模型可能需要一段时间。同时你可以使用 analyze.py --no-transcript 进行视觉分析,稍后再重新运行以获取转录。更新技能后重新运行 scripts/sfx.py ~/.cache/reel-motion-edit/sfx,以便新风格的声音存在。
如果你发现有用的额外素材(字体、图标集、免版税费音效或音乐轨道),将其下载到工作目录。在 <workdir>/CREDITS.txt 中注明其许可证。优先使用 OFL/CC0 来源(Google Fonts、Pixabay/Freesound CC0)。内置字体:Vazirmatn(正文)、Lalezar(显示)、Changa(科技感)、Lemonada(俏皮感)、Noto Kufi Arabic(正式)。用户本地安装的字体(例如 Morabba、IRANSansX、Yekan Bakh)可以通过 plan.fonts 添加,并且通常是最符合品牌的选择。查看 %LOCALAPPDATA%\Microsoft\Windows\Fonts 和 C:\Windows\Fonts。
品牌套件。 如果 ~/.config/reel-motion-edit/brand.json 存在,render.js 会自动应用它:style、theme(品牌颜色)、fonts、handle(@用户名水印)、handleCorner、logo。计划会覆盖它;"brand": false 为单个视频忽略它。当用户告诉你持久偏好(他们的用户名、他们总是想要的风格、品牌颜色)时,主动提出将其保存到那里。
第 1 步 — 分析
在视频旁边创建一个工作目录(<video dir>/<video name>_edit/)并运行:
python <skill>/scripts/analyze.py "<video>" "<workdir>" --lang fa
然后阅读 analysis/transcript.txt 和每张 analysis/sheets/sheet_*.jpg(每张 10 秒,每个单元格 0.5 秒,带有时间戳)。脚本打印的动作事件(m0 … mN、cut/change)是候选事件。对照联系表确认每个事件,因为滚动也会显示为“change”。
Whisper 有时会拼错波斯语或英语产品名称。记下更正(它们对字幕和单词锚点很重要:锚定到 Whisper 拼写单词的方式)。
第 2 步 — 询问用户:风格 + 准备选项(在设计任何内容之前)
不同的视频和受众需要不同的外观,并且用户想要选择。构建一个风格板:用所有 7 种预设渲染他们的视频的一个代表性帧,并带有标题、步骤芯片、贴纸和字幕行。首先编写一个最小的计划(视频 + 标题 + 一个关键词 + 如果视频有步骤则加上步骤),然后运行:
node <skill>/scripts/render.js "<workdir>/plan.json" styleboard <T> # → build/styleboard.jpg
选择帧是典型(非转场)的 T。将图像发送给用户(SendUserFile、display render),然后使用 AskUserQuestion 询问。如果品牌套件已经有 style,则跳过风格问题,除非用户要求不同的内容。
- Q1 — 风格(最多 4 个选项:首先推荐最适合此内容的那个,附上一行原因,再加上三个对比替代方案;其他的可以通过输入“Other”触发)。预设:
gradient现代渐变、bold大胆流行/Hormozi、neon霓虹科技/赛博、minimal简洁极简 Apple 风格、doodle手绘涂鸦、retro复古 VHS、news新闻播报。描述在assets/styles.json中(label、feel)。 - Q2 — 准备选项(多选),仅列出适用的选项:
- 修剪暂停(跳跃剪辑):
tighten.py移除超过 ~0.45 秒的静默。最适合讲话类视频。对于屏幕录制,警告静默部分可能是点击发生的地方。它会更改时间线,因此在分析之前运行:在收紧的文件上重新运行分析。 - 语音清理:
"voice": "enhance"(去噪、低频切除、临场感、轻度压缩)。推荐用于手机或房间录音。 - @用户名水印:如果品牌套件中没有,询问用户名。
- 背景音乐:仅当用户有曲目或希望你寻找 CC0 曲目时。它会自动在语音下进行闪避。
- 修剪暂停(跳跃剪辑):
如果用户只想要编辑而不在乎,为他们选择,说明选择了哪种风格以及原因,然后继续。
第 3 步 — 节拍表(设计前思考)
编写 <workdir>/beats.md:每个节拍一行,包括时间范围、说了什么、显示了什么以及布局(全脸 / 屏幕 + 画中画左下 / 手持屏幕 / …)。标记:
- 开场(前 1–3 秒):从
references/styles.md中选择一个开场格式,如果你知道,选择与上次不同的一个 - 演讲者解释的每个步骤/想法
- 高光时刻(显示结果:“已连接”、“完成”、数字)
- 结尾的CTA
- 布局变化(相机与屏幕之间的缩放):转场点
- 每种布局的安全区域:叠加层可以放置而不会遮挡面部、光标或正在演示的内容的位置
阅读 references/styles.md(所选风格的操作手册)和 references/creative-direction.md(节奏、位置、音效规则)。它们很短,是区分“杂乱”和“专业”的关键。
第 4 步 — plan.json
编写 <workdir>/plan.json。所有组件、其属性和默认音效都在 references/components.md 中。在编写计划前阅读它。最小形状:
{
"video": "D:/videos/vpn firefox.mp4",
"size": [1080, 1920], "fps": 30,
"style": "neon",
"voice": "enhance",
"handle": {"text": "@your_handle", "corner": "tl"},
"avoid": [{"name": "face", "from": 0, "to": 14.6, "rect": [200, 420, 680, 900]},
{"name": "pip", "from": 15, "to": 29.1, "rect": [0, 1300, 510, 620]}],
"elements": [
{"type": "title", "t": 0, "d": 3.8, "y": 90, "kicker": "آموزش ۶۰ ثانیهای", "lines": ["`VPN` *رایگان*"], "sub": "با سرورهای فایرفاکس"},
{"type": "transition", "t": "m:m3-0.1"},
{"type": "steps", "items": [{"t": "w:گوگل", "label": "جستجو در گوگل", "sub": "`vpn firefox github`"}], "hide": [[29.0, 34.1]]},
{"type": "keyword", "t": "w:رایگان", "x": 540, "y": 1640, "text": "رایگان", "emoji": "🎁"},
{"type": "success", "t": "w:وصل", "x": 405, "y": 678, "title": "وصل شدی!"},
{"type": "cta", "t": 57.4, "items": [{"text": "سیو کن", "icon": "save"}, {"text": "فالو کن", "icon": "follow"}]}
],
"camera": [{"t": "w:رایگان", "d": 1.2, "type": "punch", "scale": 1.12, "cx": 540, "cy": 700}],
"sfx": [{"t": 16.2, "name": "typing", "db": -8}],
"cover": {"lines": ["`VPN` *رایگان*"], "sub": "آموزش ۶۰ ثانیهای"}
}
让风格决定外观。 将视觉属性(theme 颜色、keyword style/rotate/from、transition kind、title anim、字幕样式)保持未设置,除非你有语义上的原因(错误用红色,品牌颜色)。预设会填充它们,这就是让风格感觉不同的原因。没有 kind 的转场会循环使用该风格的转场。计划中的 theme 仅覆盖预设(例如产品的品牌颜色)。
文本语法:*word* 或 *two words* = 高亮,`latin` = 隔离的从左到右运行(在 RTL 文本中保持“VPN”/URLs 不翻转)。
第 5 步 — 检查、预览、修复(循环)
node <skill>/scripts/render.js "<workdir>/plan.json" check
node <skill>/scripts/render.js "<workdir>/plan.json" preview 1 5.5 15.8 21.1 27.4 54
check 打印已解决的时间线并检查:
COVERS:元素覆盖了受保护区域OFFFRAMECLUTTER:同时超过 3 个叠加层SFXPILE:音效在 0.35 秒内堆叠ORDER:单词锚点命中了较早的出现,因此使用w:word#2
修复每个问题。然后查看 build/preview.jpg:为每个重要元素选择动画中间的帧,检查标注和涟漪是否恰好落在目标上。从全分辨率帧(ffmpeg -ss T -i video -frames:v 1 f.png)读取坐标,而不是从缩略图中猜测。迭代直到正确。预览成本低,完整渲染成本高。
第 6 步 — 渲染和合成
node <skill>/scripts/render.js "<workdir>/plan.json" full # build/overlay.mov(约 3–6 分钟 / 分钟视频)
python <skill>/scripts/compose.py "<workdir>/plan.json" --out "<video dir>/<name> - edit.mp4"
node <skill>/scripts/render.js "<workdir>/plan.json" cover <T> # build/cover.jpg — 帖子封面(模糊的帧 T + 标题)
在后台运行完整渲染。compose.py 执行以下操作:
- 仅对视频应用相机移动
- 叠加图形
- 如果设置了则应用
voice清理 - 在语音下混合音效层,如果设置了音乐则进行闪避:
"music": {"file": "...", "db": -20} - 标准化为 −14 LUFS
切勿覆盖源视频。写入一个新文件,并在重新渲染时使用版本后缀(- edit v2)。
第 7 步 — 验证
制作输出的联系表(ffmpeg -i out.mp4 -vf "fps=1/2,scale=216:-1,tile=10x3" sheet.jpg)并查看它。检查持续时间是否匹配且音频存在。诚实地报告你检查了什么(帧)以及你不能检查什么(你无法听到;音效时序已针对事件列表验证,而非通过耳朵)。
第 8 步 — 提供字幕和额外选项(始终在最后)
编辑交付后,使用 AskUserQuestion(适合时使用多选)询问。仅提供尚未完成的内容:
- 字幕:来自
references/caption-styles.md的 3–4 种样式,首先推荐所选风格的默认样式(在 styles.json 中的captions),并基于此视频给出原因。 - 封面图用于帖子(
render.js cover)。 - Instagram 帖子文案:从转录中编写
<workdir>/post.txt:一行吸引点,2–4 行简短价值点,CTA,演讲者提到的链接或评论关键词,以及 8–15 个相关的波斯语 + 英语话题标签。 - 保存到品牌套件:所选风格、用户名和颜色,以便下一个视频从此开始。
- 另一种风格版本:使用不同的
style重新渲染相同的计划,用于 A/B 测试(仅更改叠加层)。
对于字幕:
python <skill>/scripts/captions.py "<workdir>" --style karaoke --zones "0-14.6:1400,29.4-33.8:1400" --default-y 1170 --keywords "رایگان,VPN" --fix "غلط=درست,وی پی این=VPN"
校对打印的块。使用 --fix 修复 Whisper 拼写;多个单词源会合并 token。在计划中添加 "captions": {"file": "captions.json"}(样式默认为预设的;设置 "style" 以覆盖),运行 check(字幕也不能覆盖面部或贴纸),然后作为新版本再次渲染和合成。
注意事项
- 屏幕坐标中的元素(点击、高亮、标注箭头)如果相机移动缩放同一部分,则会错位。仅在讲话部分使用相机移动。
- Camtasia 风格的面部和屏幕之间的动画缩放持续约 0.5 秒。将转场元素放在缩放的开始处,并且不要在该窗口中将文字放在屏幕上。
steps.hide在全脸部分隐藏步骤芯片,之后重新显示。- Whisper 单词时间戳在暂停后的第一个单词上可能晚约 0.1 秒。对于硬冲击(标题结束),使用
-0.05进行微调。 - 非 1080×1920 的源(例如 608×1080 的手机导出)由合成和预览按计划大小进行放大/裁剪。计划坐标始终以计划大小的像素为单位,因此将从源帧读取的坐标乘以
1080 / source_width。 - 手持手机拍摄显示器:屏幕会漂移,因此屏幕固定的元素(点击、高亮、箭头)将无法保持在目标上。改用结构(步骤)、边距中单词锚定的贴纸以及全帧转场。
- 标题默认带有暗色顶部遮罩(
"scrim": false移除)。它使标题在亮色屏幕上保持可读。 - 保持演讲者自己的声音不变(除响度标准化外,无 EQ/压缩)