Community编程与开发github.com

AppLoidx/record-demo

一个与启动或产品演示视频相关的智能体技能/项目:AppLoidx/record-demo

record-demo 是什么?

这是一个专为开发者和AI智能体设计的技能,用于自动化录制产品演示视频。它基于Playwright引擎,允许开发者编写自包含的剧本来录制高质量的产品演示,无需将剧集添加到应用仓库中。技能支持多种输出格式(16:9、1:1、9:16)、视频和GIF生成,以及通过Remotion Studio进行后期编辑。它包含一个强大的DSL,提供zoomTo、spotlight、caption等高级工具,确保视频具有专业水准的镜头移动和剪辑节奏。技能还内置了运动评分和验证工具,帮助用户确保输出质量。该技能在Claude Code、Cursor等支持自定义技能的智能体平台上运行,需要Node >= 22.18、ffmpeg、Xvfb等依赖。

兼容平台✓Claude Code~Codex CLI✓Cursor
npx skills add AppLoidx/record-demo

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

录制演示视频

编写一个临时的 Playwright 分镜脚本,然后从任何工作目录运行自包含引擎。 除非用户明确要求,否则不要将分镜脚本添加到应用仓库中。 保持分镜脚本自包含;运行器会在 Playwright 加载之前将该文件暂存到引擎内部,因此不要使用分镜脚本相对路径的帮助导入。 <skill-dir> 表示克隆此仓库的目录,例如 ~/.claude/skills/record-demo。

编写分镜脚本

使用以下可移植导入来引入 DSL:

import { demo } from "record-demo/storyboard";

运行器在暂存时会将此说明符重写为引擎的实际路径,因此分镜脚本文件可以位于任何位置。 编辑器对 record-demo/storyboard 的类型解析来自 engine/tsconfig.json 中的 paths——在仓库外部,请将 record-demo/storyboard 映射到你的 tsconfig paths 中的绝对 <skill-dir>/engine/lib/storyboard.ts 路径,或者将文件放在 engine/scripts/ 中。

使用 engine/scripts/example-site.demo.ts 作为参考。优先使用 getByRole 选择器,使用 d.click(locator) 而不是 locator.click(),使用 d.hold(...) 来控制动作节奏,并断言或等待最终状态。

demo("storyboard-title", async (d) => {
  await d.seed(async (page) => {
    await page.getByRole("heading", { name: "Example Domain" }).waitFor();
  });

  await d.step("Read the page", async (page) => {
    const heading = page.getByRole("heading", { name: "Example Domain" });
    await d.zoomTo(heading, { padding: 48 });
    await d.hold(2_000);
    d.zoomOut();
    await heading.waitFor({ state: "visible" });
  });
});

引擎会使用 --name 或脚本的基本名称覆盖时间轴名称,因此传递给 demo(...) 的字符串不必与输出别名匹配。

预检(在任何捕获之前)

当针对本地服务的检出进行录制时:在服务的检出目录中运行 git fetch origin 并断言 HEAD == origin/main(或用户指定的分支)——过时的检出差错会录制过时的设计。如果过时,请先重建/重启服务器。将服务的 SHA 打印到录制笔记中,以便每个录制都可追溯。

录制

需要 Node >= 22.18(使用 nvm 或系统),ffmpeg,Xvfb,和 xdpyinfo。在 engine/ 内部使用 pnpm install 安装一次依赖。

node <skill-dir>/engine/record.mjs \
  --script /absolute/or/cwd-relative/demo.demo.ts \
  --url https://example.org \
  [--name output-slug] [--formats 16x9,1x1,9x16] \
  [--chrome none|macos|browser] [--storage-state <path>] [--raw]

使用 --formats 选择一个或多个构图预设(默认为 16x9),使用 --chrome 选择渲染的窗口框架(默认为 none)。格式按请求顺序渲染,第一个格式将用于编码 GIF。 9x16 格式是一种激进的中心裁剪(在广角镜头中,页面宽度约有 44% 可见),因此在为竖屏创作时请保持动作居中。

使用 --raw 在干净捕获后停止。不使用该标志,预期会得到以下交付物:

  • engine/out/<name>-raw.mp4
  • 每个请求格式的 engine/out/<name>-<format>.mp4
  • 从主要格式编码的 engine/out/<name>.gif

运行器在完成时会打印绝对交付物路径。将现场站点可重现性视为目标站点的责任,并且绝不要在分镜脚本中嵌入真实凭据。

认证站点

仅使用临时或测试账户录制已认证的流程;切勿使用生产凭据。智能体应首先使用自己的工具,通过一个无头 Playwright 脚本登录一次。如果登录需要通过电子邮件发送的 OTP 或魔法链接,首选途径是智能体自己的邮件访问——Claude Code 上的连接 Gmail 连接器/MCP,或其他运行时的邮件 CLI——以便它自己读取验证码;否则请用户粘贴。登录后,使用 await context.storageState({ path: storageStatePath }) 保存会话,其中 storageStatePath 是一个一次性临时路径,创建为 storageStatePath="$(mktemp -d)/<account>.storage-state.json"。然后使用 --storage-state "$storageStatePath" 运行录制命令。

Playwright 的 storageState 仅恢复 cookies 和 localStorage。在 IndexedDB 或 sessionStorage 中保存认证的应用会静默录制到一个已登出的屏幕,因此在捕获之前验证已认证的页面。storage-state 文件是一个秘密:切勿打印或提交它。录制器在加载后会立即删除它;这是一次性交接,因此重新录制需要重新登录,并且磁盘上不会留下任何与认证相关的内容。一次性的登录辅助脚本也包含凭据:保持其临时性,切勿提交。

在 Remotion Studio 中编辑录制的演示

录制后导出一个自包含的项目,然后安装并打开 Studio:

node <skill-dir>/engine/scripts/export-project.mjs <name>
cd <skill-dir>/engine/out/<name>-project
pnpm install
pnpm studio

Studio 的时间轴面板显示编辑器风格轨道(屏幕底片,每个字幕一个命名片段,聚光灯,缩放移动,和片尾)——拖动播放头进行浏览,点击片段的行以查找其事件。使用属性面板或 fixtures/timeline.json 编辑字幕、缩放时间(保持缩放移动不低于 1650ms 的下限)、聚光灯时间和片尾标题。编辑 remotion/theme.ts 来设置颜色、排版、间距和运动。使用 pnpm render 渲染最终的 16:9 视频。

运动和分镜规则(是什么让一个片段可发布)

  • 每个场景一次相机移动,而不是每个字段。 放大到该区域一次,然后在其内部操作。每次输入的缩放读起来像生硬的剪辑。
  • 在页面过渡时保持广角,在内容稀疏的页面上保持广角。 在导航的点击之前调用 d.zoomOut();绝不要在几乎空白的页面上放大到一个状态药丸。
  • 靠近页面底部的部分: d.zoomTo([...locators], { scroll: "center", padding: 48 })——相机夹子无法居中页面边缘的矩形;滚动居中在根级别解决了这个问题。Locator[] 通过联合边界框框定整个部分。
  • d.spotlight([...locators]) = Apple 风格的焦点变暗(抠图 + 环)。使用慷慨的 holdMs,在步骤结束前显式调用 d.spotlightOff() + hold(600) 结束。聚光灯矩形必须适合视口(强制执行);缩放矩形可以自由溢出。
  • Seed 等待真实数据,而不仅仅是触发元素——否则视频在骨架屏上打开。等待一个已知的内容节点 + 约 600ms。
  • 在结果字幕之前调用 d.settle(locator)。 提交后重新获取数据的视图会短暂空白;简单的 waitFor 会在首次渲染时解析,结果字幕会在空白页面之上触发。
  • 字幕是祈使句,与光标动作相关联;在关闭场景上将结果字幕(d.caption(...) 在步骤后期)放置;修剪步骤字幕,以便祈使句永远不会悬停在已完成的操作上。
  • d.outro(title) 关闭可发布的片段,在最后一个场景之后以平静的结束画面结束。
  • 始终断言最终状态——没有它,管线会渲染出一个错误流程的精美视频。
  • 切勿发布带有 localhost URL、内部主机名、提供商名称或屏幕上真实凭据的片段。在 seed 中屏蔽仅用于演示的字符串(使用 window.open 补丁和 MutationObserver 输入重写)。

在报告完成前验证

  1. 在 engine/ 中运行 pnpm typecheck && pnpm test。
  2. node scripts/score-motion.mjs out/timeline.json——FAIL 阻塞;WARN 缩放速率约 0.78/s 是接受的稳定状态;任何不连续性判定都是相机错误;死区 WARN 意味着静态拉伸 >= 3.5 秒且光标移动少于 40px——重新调整速度或添加字幕。
  3. 引擎更改后运行 node scripts/prove-composition.mjs。
  4. 观看实际渲染:ffmpeg -i out/<name>-16x9.mp4 -vf fps=1 out/frames/%03d.png 并读取帧。缩放裁剪、字幕延迟、抠图不同步和屏幕上的开发 URL 在绿色测试运行中是不可见的。

注意事项

症状原因 / 修复
Invalid demo viewport ... 中止几何体偏移——修复启动标志,绝不要放宽断言。
光标垂直偏移约 174pxChrome 以选项卡模式运行,而不是 --app。
找不到场记板帧检测器容差为 64(外部捕获平均不纯);如果仍然错过,检查捕获是否为黑色(Chrome 在错误的 DISPLAY 上)。
字幕/光标在片段中漂移场记板同步——不要使用墙上时钟时间相减。
聚光灯抠图偏离目标矩形与平滑滚动竞速——measureTarget 的稳定性循环应能保持;如果复发,增加其超时时间。
裁剪边缘处单词被从中切掉对于模态框,使用 zoomTo(locator, { padding: 120 })。
缩放将内容裁剪出帧maximumScale 品味问题(1.45 有效),不是夹子错误。

验证引擎更改

从 engine/ 运行:

pnpm typecheck && pnpm test
node scripts/prove-composition.mjs

相关技能