Community编程与开发github.com

VirtualPirate/create-product-demo-video-skill

Claude Code 技能:录制产品演示视频,通过 Playwright + ffmpeg 将真实的用户操作流程转录为 mp4/gif 格式。

create-product-demo-video-skill 是什么?

该技能专为 Claude Code 设计,用于自动录制 Web 应用的产品演示视频。其核心原则是“每一帧画面都必须源于真实 UI 的转录,而非凭空想象”,确保演示视频准确反映产品实际功能。技能支持将用户描述的操作流程映射到真实路由,读取每个页面的源代码并复制真实文案与组件,最终通过 Playwright 和 ffmpeg 生成 mp4 或 gif 格式的视频。输出的演示视频保存在新建的 demo/vN/ 目录下(每次递增版本号,不会覆盖),并包含字幕、背景音乐(可选)及播放引擎。此外,技能还提供详细的验证步骤,包括抽取关键帧检查布局、检测音频流和音量渐变,确保演示质量。该技能适用于任何需要为开发者工具、SaaS 产品或 Web 应用创建高质量、真实产品演示的场景,支持 macOS、Linux 和 Windows 平台。

兼容平台✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/VirtualPirate/create-product-demo-video-skill/tree/main/skills/create-product-demo-video

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

在你喜欢的 AI 中提问

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

文档

构建用户所述流程的演示视频。输出内容将放置在新的 demo/vN/ 文件夹中。

唯一重要的规则:每个屏幕都必须是真实 UI 的转录,而非印象。 编造布局、文案或组件的演示比没有演示更糟糕——它会让观看者认为存在一个不存在的产品。在编写任何标记之前,请先阅读每个屏幕的源代码。

输入

/create-product-demo-video <应该发生的操作> — 一个流程描述。如果描述模糊(例如“展示产品”),选择最窄的完整流程,以可感知的价值为终点,用一行说明选择了哪个流程,然后开始构建。不要因为提问而停滞。

步骤

  1. 将流程映射到路由。 将提示转换为用户会经过的真实路由的有序列表。首先找到路由器——routes/ 目录、app/ 树、<Routes> 块、路由清单——只列出存在的路径。如果流程需要先创建某个实体(例如项目)才能到达后面的屏幕(例如项目范围报表),要么包含该屏幕,要么选择不需要该实体的范围——不要静默跳过必需步骤。

  2. 读取每个屏幕的源代码。 对于每个路由:路由文件、其渲染的组件、应用的共享布局组件(外壳、页面标题、空状态)及其设计系统原语(components/ui/ 或它们所在的位置)。同时读取任何生成演示中显示的字符串的内容——预览助手、派生名称、后端渲染/模板服务。逐字复制字符串;不要转述产品文案。

  3. 搭建脚手架。 mkdir -p demo/vN(下一个未使用的 N——切勿覆盖现有的 vN),然后复制 assets/skeleton.html → demo/vN/index.html 和 assets/record.mjs → demo/vN/record.mjs。assets/ 位于此 SKILL.md 旁边,即技能安装的任何位置——插件缓存目录、~/.claude/skills/ 或项目的 .claude/skills/。从技能自身的目录解析它,绝不能从被演示的仓库解析。骨架携带占位外壳、标记尺度和播放引擎。 对于带评分的演示,还要从 assets/music/ 复制所选音轨 → demo/vN/music.mp3——参见音乐。复制进去(而不是引用技能文件夹)才能让 vN/ 在以后可重新录制,record.mjs 按版本复制也是出于同样的原因。

  4. 使骨架适应此产品。 所有标记为 REPLACE: 的都是占位符,必须在编写任何场景之前替换,因为每个屏幕都继承自它们:

    在 index.html 中替换为
    PRODUCT应用的名称、地址栏显示的主机名及其真实 logo svg
    NAV从真实导航栏转录的侧边栏——相同的部分、相同的顺序、相同的标签
    TOPBAR真实的顶部栏;删除应用没有的控件
    :root 标记应用样式表中的 :root 块,以使颜色/圆角/类型匹配
    ICONS应用实际使用的图标集中的路径数据
    删除流程不使用的可选 CSS 块(第三方屏幕、交付面板)。
  5. 编写场景。 每个屏幕一个 <section class="scene" data-scene="N">,按顺序排列。重用骨架的 CSS 类(.pagehead、.card、.btn、.seg、.opt、.chip、.scopeid、.statusbadge、.empty、.input、.pillbar、.toast)——它们被塑造成像 Tailwind/shadcn 样式系统的输出,因此对照实际组件的类进行检查并调整,而不是硬性假设。仅在骨架缺少某个组件时添加新 CSS,并从该组件的实际类派生。

  6. 编写 play()。 标题卡 → 屏幕 → 结尾。使用字幕命名每个步骤,并在脚本顶部设置 CAPTIONS——样式,以及 steps = 运行过程中 say() 调用的次数。交互通过指针助手进行,以便观看者能够跟随点击的轨迹。

  7. 录制。 node demo/vN/record.mjs → demo/vN/out/product-demo.mp4。添加 --gif 可生成 900px 的 gif。demo/vN/music.* 文件会被自动识别;--music <path> 指向其他位置的音轨,--music-db <n> 调整音量级别,--no-music 强制静音。

  8. 通过查看进行验证。 提取帧并阅读这些图像——这是不可选的,这是捕获布局错误的方式:

    for t in 5 12 20 28 36 44; do ffmpeg -y -loglevel error -ss $t \
      -i demo/vN/out/product-demo.mp4 -frames:v 1 /tmp/f$t.png; done
    

    检查:没有过大的图标,没有内容被裁剪,指针落在它声称要点击的元素上,文本没有被压缩成一行。修复并重新录制,直到干净为止。

    帧无法显示音频。 对于带评分的演示,还要检查音频流和音量渐变——volumedetect 在 info 级别记录日志,因此 -v error 会吞掉其输出:

    ffprobe -v error -select_streams a:0 -show_entries stream=codec_name,duration \
      -of default=nw=1 demo/vN/out/product-demo.mp4
    for w in "-ss 0 -t 0.25" "-ss 12 -t 0.5" "-sseof -0.25"; do \
      ffmpeg -hide_banner -nostats $w -i demo/vN/out/product-demo.mp4 \
        -af volumedetect -f null - 2>&1 | grep mean_volume; done
    

    期望一个 aac 流,持续时间与视频相差约 0.05 秒,max_volume 低于 0 dB,并且开头和结尾的平均音量远低于中间部分——这是表明渐隐生效的证据。

  9. 编写 demo/vN/README.md——包含路由的场景表格、源文件映射、持续时间、录制时使用的 CAPTIONS 样式和音轨,以及流程特意跳过的内容。更新 demo/README.md 以列出新版本。

报告路径、持续时间和文件大小,然后打开 mp4 以便用户可以观看——macOS 上使用 open,Linux 上使用 xdg-open,Windows 上使用 start。

引擎 API

在 play() 内部可用:

调用效果
scene(n)淡入场景 n,根据 URLS 更新地址栏
tap(sel, ms)将指针移动到元素并点击(波纹效果 + 按下)
moveTo(sel, ms) / click(sel)拆分为两部分,当你需要在两者之间改变状态时使用
hideCursor() / place(x, y, 0)进入场景时重置指针
say(text, opts?) / hush()字幕进入/退出。{ at: sel } 锚定一个 coach 字幕;{ step: n } 强制指定索引
type(el, text, ms)逐字符输入到 <span> 中
wait(ms)等待
reveal(el)由 moveTo 自动调用——平滑滚动 .main 使折叠以外的目标可见

设置 window.__demoDone = true 在末尾(骨架已经这样做)——录制器等待它。

字幕设计

const CAPTIONS = { style: 'pill', steps: 6 } 与 URLS 一起放在引擎顶部。所有四种样式都随骨架提供;无论使用哪一种,say() 的调用方式都相同。根据视频选择:

style说明何时选择
pill (默认)墨色胶囊,底部居中任何简短且面向营销的内容。遮挡最少,每个字幕约 10 个词
lower-third左对齐块,带有步骤索引和进度条较长的流程,观看者应感受到顺序;在 gif 中最易读
rail窗口下 68px 的带状区域,章节圆点文档和支持片段,不能遮挡任何内容。会占用应用高度——见下文
coach锚定到播放元素的标注,其余部分变暗跟随式操作指南。每个字幕都需要 { at: sel };没有的则回退到 pill

steps 驱动索引、进度条和 rail 的圆点——统计 say() 调用的次数并设置它,否则运行结束时会显示 05 / 06。不确定哪种样式?在浏览器中打开 index.html 并切换 CAPTIONS.style——页面按 R 键重播,因此无需录制即可比较所有四种样式。

音乐

可选,并且仅在存在音轨时才开启。背景音乐在编码时混入——Playwright 完全不捕获音频,因此它不会影响演示页面或引擎。

node demo/vN/record.mjs                      # 使用 demo/vN/music.*(如果存在),不存在则静音
node demo/vN/record.mjs --music ~/beds/x.mp3  # 显式路径优先于同级文件
node demo/vN/record.mjs --music-db -4        # 更安静的背景音乐
node demo/vN/record.mjs --no-music           # 即使有同级音轨也保持静音
  • 捆绑音轨位于 assets/music/ 中,每行对应其 LICENSES.md 中的一个文件。没有音轨在没有可验证的 CC0/CC-BY 声明的情况下随附——未授权的 mp3 是所有安装此技能的人的问题,而不仅仅是你的。不确定?将其保留在仓库之外,并通过 --music <path> 指定。
  • 音量是归一化的,而非手动设置。 每个音轨都被驱动到 −18 LUFS,并带有 −1.5 dB 真实峰值上限,因此版本之间替换的背景音乐无需手动调整即可匹配。--music-db 改变这个目标;它不会在顶部增加增益。
  • 渐隐是自动的——1.5 秒渐入,2.5 秒渐出,渐出时间基于实际视频时长。
  • 选择比视频长的音轨。 更短的内容会被循环,接缝处可能被听到;当必须循环时,录制器会发出警告。60 秒以上可覆盖正常的 40–60 秒演示。
  • 不要有语音,不要有突兀的下降。 观看者同时正在阅读字幕和 UI 文案。
  • 音频只进入 mp4。 webm 是原始静默捕获,gif 根本没有音频轨道——纯音乐更改在 --gif 输出中不可见。

约定

  • 舞台是一个固定的 1280×800 模拟浏览器;其中 44px 是浏览器边框,剩余 1280×756 用于应用。骨架附带了一个 48

相关技能