promo-video — 从本地运行的SaaS到营销视频 是做什么的?
目标:用户在本地产品目录(或空目录)中打开Claude,描述想要展示的内容,最终获得一段展示真实产品(而非粗略模型)的精彩MP4视频。故事板在编码之前会与用户确认。屏幕上的一切动态元素都经过测量(捕捉坐标),一切声音都经过生成(零版权)。
该技能通过制作一段真实视频(Trkly,41秒,11次捕捉,配乐同步)构建而成,并编码了所有学到的经验:Remotion、Playwright、Lint的陷阱,以及如何让产品视频更具可信度。
技能文件
| 路径 | 作用 |
|---|---|
scripts/setup.mjs | 完整脚手架Remotion项目(依赖、Playwright、Remotion技能、模板、音乐) |
scripts/capture.mjs | 声明式捕捉真实页面(JSON计划 → PNG @2x + boxes.json) |
scripts/boxes-to-ts.mjs | boxes.json → 类型化的 src/story/boxes.ts |
scripts/make-music.mjs | 合成音乐 + SFX(可参数化设置的Drop和结尾音效) |
scripts/probe.mjs | 无需ffmpeg检查渲染的MP4(时长、轨道) |
templates/ | 组件(BrowserFrame、Cursor、Caption、Callout、DotGrid)、场景、brand.ts、示例捕捉计划、项目CLAUDE.md |
templates/examples/Demo.example.tsx | 完整的参考演示(28秒,11次捕捉,滚动,输入,弹出标签),在编写自己的演示前阅读 |
references/scenario.md | 剧本模板 + 字幕编写规则 |
references/pitfalls.md | 所有遇到的陷阱(Remotion、Playwright、Lint、音频、Windows) |
references/checklist.md | 交付前需要检查的内容 |
<skill> 下面 = 此SKILL.md所在的目录(~/.claude/skills/promo-video、.claude/skills/promo-video或插件缓存)。在运行脚本前用 ls 确认。
工作流程
0. 确定框架(5分钟)——并在编码前确认剧本
一次性向自己(或用户)提出以下问题:
- 产品:名称、一句话介绍、本地URL(
npm run dev在哪个端口?)或生产URL。是否存在登录/订阅墙?→ 需要找到一种方式来绕过以进行拍摄(应用内的演示标记、测试账户、cookies)。永远不要让自己输入密码:让用户在浏览器中登录,然后将cookies给你,或激活演示模式。 - 想要展示的内容:3到5个精确时刻(一个页面、一个筛选器、一次点击、一个结果)。每个时刻 = 一次捕捉 + 一次光标动作 + 一条字幕。
- 产品解决的痛点,用一句通俗的话概括(“你厌倦了…吗?”)。
- 格式:默认为16:9(X、LinkedIn、YouTube、落地页)。仅在明确要求时才使用9:16(TikTok/Reels)——模板为1920x1080设计。
- 最终CTA:URL、“简介中的链接”、“免费试用”……以及标语。
然后在聊天中编写剧本,使用 references/scenario.md 作为模板:8个场景、时长、屏幕文本、所见内容,并建议技术选择(推荐使用Playwright的真实捕捉)。等待用户的“开始”指令。如果用户说“你来处理”,即视为同意:不要重复提问,做出选择并记录下来。
将确认后的剧本写入视频项目根目录下的 SCENARIO.md:作为所有场景和后续修改的参考。
1. 搭建视频项目脚手架
始终为产品创建独立项目(兄弟目录 <product>-video):Remotion + Chromium 不应存在于SaaS的构建中,并且 next build 的 tsc 会包含视频文件。
node <skill>/scripts/setup.mjs ../monsaas-video --name "MonSaaS" --domain monsaas.app --base http://localhost:3000 --accent "#f97316" --desc "一句话"
脚本执行内容:create-video --blank(包含Tailwind v4),remotion add 相关包(transitions、google-fonts、media、zod,以及whisper-webgpu和video-matting,它们是Studio的可选依赖,缺少时会显示错误),Playwright 1.63 + Chromium,Remotion官方技能(npx skills add remotion-dev/skills),复制模板,项目 CLAUDE.md、launch.json(Studio在端口3012上——如果端口被占用请更改 --port),以及默认音乐。预计耗时3到5分钟。
之后:在任何修改之前,项目中的 npm run lint 必须通过(骨架使用占位框编译)。
2. 提取产品设计规范
打开产品的CSS(globals.css、tailwind.config、:root 变量),并填写 src/brand.ts:强调色、深色背景、文本、Google字体(更改 @remotion/google-fonts/<Font> 的导入)、logo(将PNG复制到 public/logo.png)、域名。不要猜测颜色:读取它们。所有组件都读取 brand,任何场景中都不应硬编码颜色。
3. 捕捉真实产品
产品必须正在运行(让用户启动服务器,或通过 preview_start 启动,切勿在Bash中启动)。如果内容被墙挡住,请提前处理(演示模式、计划中的cookies:"cookies": [...],或 "localStorage": {...})。
编写 capture-plan.json(模板:capture-plan.example.json,完整文档在 scripts/capture.mjs 头部):每个动作一个步骤。对于剧本中的每个时刻:
shot在动作之前的状态,click/type执行动作,settle稳定,shot在动作之后的状态;- 对光标将指向或高亮框将包围的每个元素添加
box(按钮、菜单选项、搜索字段、表格第一行、徽章、部分); - 对于长页面,使用
viewport高值(例如 1920x3400)并设置"group": "tall"——切勿在h-screen/可滚动面板布局上使用shotFull,它只捕捉视口; - AI生成结果:在加载过程中
shot,等待加载指示器消失waitGone(长超时),然后对结果shot。
node <skill>/scripts/capture.mjs capture-plan.json # PNG @2x + public/shots/boxes.json
node <skill>/scripts/boxes-to-ts.mjs # -> src/story/boxes.ts
在继续之前检查每张捕捉(使用Read工具):尴尬的内容(糟糕的测试数据、显示错误、用户名)、未正确打开的弹出窗口、未加载的页面。在计划侧修复(添加 wait、URL中的筛选器、用于隐藏元素的 css)并重新捕捉。如果你发现了产品的bug,记录下来用于交付——未经请求不要在产品中修复它。
4. 音乐
setup.mjs 已生成 public/audio/(音乐 + 点击/呼啸/爆裂/冲击效果)。音乐结构为:紧张的引子 → Drop → 律动 → 最终打击 → 尾部。让Drop与产品出现在屏幕上的时刻同步,最终打击与签名同步:
node <skill>/scripts/make-music.mjs --drop 8 --end 36 --total 42.5 [--bpm 120] [--transpose -2] [--seed 7]
120 BPM = 30 fps下每拍15帧:将场景对齐到15的倍数。如果用户提供了mp3,将其放入 public/audio/music.wav|mp3 并调整 Story.tsx——使用前检查许可。
5. 编写场景
完整阅读 templates/examples/Demo.example.tsx:这是我们所期望的模板(相机缩放至每个点击的元素、光标以弧线移动并点击、下一张捕捉淡入、高亮 + 标签、高捕捉的滚动、逐字键盘输入、弹出标签、每张字幕覆盖全屏、强切换时的白色闪烁、节拍上的脉动)。然后调整 Demo.tsx:SHOTS(捕捉和边界)、ZOOM(相机关键帧)、SCROLL、CURSOR(点击触发声音)、Callout、Caption。
场景设计规则:
- 每条字幕一个想法,3到6个单词 + 一个强调色组。永远不要同时显示两条字幕。
- 缩放到想要让用户阅读的内容(1.4到1.7),然后返回1:观众必须能够阅读真实的标签。未缩放的满屏捕捉无法阅读。
- 光标在点击前显示:它在点击前15到25帧到达,绝不瞬移。
- 一个动作 = 点击前状态 → 点击 → 点击后状态,使用
SHOTS的4帧淡入。 - 没有硬编码坐标:一切来自
boxes。如果缺少某个数字,向计划添加box。 - 复制和文本场景(Hook/Tension/Outro)通过
Story的属性传递 → 可在Studio中编辑。
逐步使用静态帧检查,不要在缩小的Studio中检查:
npx remotion still Demo out/check.png --frame=120 --scale=0.5
检查每张静态帧(使用Read工具)。检查:文本是否被窗口边缘裁剪、标签是否与正在阅读的元素重叠、光标是否在错误位置、捕捉是否尚未显示、字幕是否覆盖了操作。修复,重新渲染,直到每个关键时刻都正确。
6. 渲染和检查
npm run lint
npx remotion render Story out/<slug>-story.mp4
node <skill>/scripts/probe.mjs out/<slug>-story.mp4 # 时长、视频轨道、音频轨道
不要仅凭渲染结果就认为“没问题”:在最终版本的关键时刻渲染6到10张静态帧并检查它们。你无法听取混音:告诉用户这一点,并说明如何调整(Story.tsx 中的 volume,make-music.mjs 的参数)。
7. 交付
发送MP4文件(SendUserFile)和一份独立的摘要:文件位置、时长/格式、场景列表及其内容、已检查和未检查的内容(声音)、拍摄中发现的UI bug、如果UI更改如何重新捕捉(3条命令)、以及易于做的变体(9:16、15秒版本、其他语言 = Story的属性)。参见 references/checklist.md。
视频“令人震撼”的因素(按影响力排序)
- 真实产品在屏幕上,可读(缩放),光标执行真实操作。
- 音乐Drop与产品出现同步,切换时白色闪烁。
- 字幕:简短、通俗、每个想法一条、一个单词用强调色。
- 高亮恰好指向正在讨论的元素(实际价格徽章、按钮)。
- 节奏:不超过2秒没有事情发生;总时长不超过40秒。
- 微细节:捕捉之间的淡入、节拍上的脉动、弹出标签、点击SFX。
在编写任何Remotion代码之前加载 references/pitfalls.md,并在交付前重新阅读 references/checklist.md。