Communitygithub.com

suxrobGM/jobpilot

为任何应用拍摄、剪辑并交付一条高质量的预告/演示视频:使用 Playwright 驱动真实 UI 进行录制,用 ffmpeg 进行后期编辑,支持分镜脚本、身份验证捕获、PII 审核、动画标题卡片,并输出 MP4 + GIF 格式。适用于“制作预告片”、“录制演示视频”、“产品发布视频”、“为 README 录制屏幕”等场景。

jobpilot 是什么?

这是一个 AI 代理技能,旨在将正在运行的应用自动录制并剪辑成一条发布级别的预告视频(约 30-45 秒)。其核心价值在于产出“产品视频”而非简单的屏幕录像——通过分镜、构图和节奏控制,让视频具有明确的导演意图和质感。用户仅需提供一个目标应用的 URL,AI 代理便会依序执行:先通过 Playwright 对候选页面进行侦察并拍摄截图,然后创建详细的分镜表;接着使用 Chrome DevTools Protocol (CDP) 的 screencast 功能进行无声、离屏的高速录制(约 100fps),由 Playwright 驱动操作,CDP 负责拍摄,互不干扰。之后,AI 会在应用的原生域内注入动画 HTML/CSS 来生成标题卡片,确保字体和配色风格统一。最后,通过 ffmpeg 对片段进行交叉淡入淡出剪辑,输出标准 MP4 和针对 README 优化的 GIF。该技能适用于 Claude Code、Cursor 等支持 Playwright 与 ffmpeg 的 AI 代理平台。它内置了严格的安全规则:用户必须逐项同意任何可能触发外部副作用的操作(如发送邮件、提交表单),并在拍摄前制定 PII 处理策略(通过取景裁剪、CSS 隐藏或使用种子演示账户来规避,绝不在拍摄后试图剪辑覆盖)。

兼容平台✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/suxrobGM/jobpilot/tree/main/.claude/skills/teaser-video

在你喜欢的 AI 中提问

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

文档

预告视频

为正在运行的应用制作一条发布级别的预告视频(约 30-45 秒):设计分镜脚本,通过驱动真实 UI 进行录制,使用 ffmpeg 进行剪辑,并最终交付 MP4 和用于 README 的 GIF。

输出结果必须看起来像产品视频,而不是屏幕录像。区别在于方向性——场景设计、构图和节奏——而不是分辨率。

参考实现在 reference/ 目录中;它们是可工作的 ESM 模块,不是伪代码。在临时目录中设置——绝不要在项目内部:

cp -r <skill>/reference/* "$SCRATCH/" && cd "$SCRATCH" && npm install
export TEASER_BASE_URL="https://the-app.example.com"

reference/package.json 声明了 "type": "module" 和三个依赖项。每个脚本都读取 TEASER_BASE_URL,因此没有任何内容硬编码到特定应用。

在任何其他操作之前:两条硬性规则

1. 未经明确的逐项同意,切勿触发真实世界副作用。

拍摄真实应用意味着点击真实按钮。其中一些按钮会发送电子邮件、公开发布内容、扣费或向第三方提交表单。在接触应用之前:

  • 列举你的分镜脚本中每一个会离开机器的操作。
  • 向用户明确告知每个操作的具体作用及执行次数,然后获得用户对次数的同意。
  • 优先选择一种在不可逆步骤前停止的模式(预览、试运行、可拍摄然后拒绝的确认门)。

对实时系统不存在所谓的只读探测。一个“诊断性”点击如果落在已经运行的会话中,就会真实触发。如果你正在调试为什么某个操作没有生效,请假设你的下一次点击会生效,并做好准备。

如果发生了你无意触发的事件:立即从源头停止该进程(终止会话/工作进程,而不仅仅是 UI 按钮——UI 按钮可能不起作用),通过回读验证停止状态,并在你的最终消息中明确告知用户——包括触发次数。

2. 假设每一帧都是公开的且充满 PII。

真实账户携带姓名、电子邮件、地址和文档。需提前与用户商定策略:

  • 通过取景规避(默认) ——构图时排除身份信息。在 ffmpeg 阶段裁剪掉持久的 Chrome 边栏(侧边栏、头像、账户菜单)。
  • 录制前隐藏 ——在录制开始前,使用 page.evaluate 对违规卡片设置 visibility: hidden。切勿先拍摄再试图剪辑绕过。
  • 使用种子演示账户 ——当存在演示账户时是最干净的做法。

在交付前,以完整分辨率检查最终剪辑的每一帧。不是查看缩略图联系表,而是查看每一帧。

工作流程

1. 侦察与分镜

首先使用 reference/scout.js 对每个候选屏幕进行经身份验证的截图。查看它们。然后编写一个分镜表:场景节拍、镜头、观众应该感受什么、以及时长。没有分配任务的镜头会在拍摄前被剪掉。

效果良好的叙事弧:紧张(问题)→ 揭示(产品)→ 证明(它确实能做事)→ 规模(成果)→ 信任(运行环境)→ 结束。

在分镜表中注明哪些屏幕包含 PII,哪些是安全的。

2. 布置场景

在录制前策划,切勿在之后:

  • 选择数据看起来最佳的视图——满的图表、活跃的列表、可识别的名称、非零计数。切勿拍摄加载动画、空状态或半渲染的图表。
  • 通过初始化脚本中的 localStorage 或拍摄前的 page.evaluate 有意识地设置 UI 状态(面板宽度、折叠/展开、过滤器、滚动位置)。
  • 在镜头外隐藏 Toast 通知、横幅和 Cookie 栏。
  • 等待数据稳定:networkidle 再加上几秒钟。

3. 拍摄

使用 CDP screencast(Page.startScreencast),而不是屏幕录制。它在屏幕外以约 100fps 捕获页面内容,因此用户正在做的任何事情都不会出现在画面中,机器仍然可用。Playwright 负责驱动;CDP 负责拍摄。reference/rig.js 实现了它。

  • 每个镜头一个主题。拍摄对象本身,而不是“整个应用”。
  • 相机移动来自页面内脚本化的缓动滚动(cameraScroll),绝不能使用滤镜。参见下面的 zoompan 警告。
  • 光标是一位演员:使用注入的 SVG 光标(cursorClick),它以缓动方式滑动并在按下时下移,或者隐藏它。不要有无目的的漂移。
  • 对每个镜头进行预演,提取帧,查看它们,调整,然后正式拍摄。

拍摄外部窗口(应用自身打开的浏览器、桌面应用)需要使用操作系统级捕获——gdigrab/x11grab/avfoundation(rig 中的 recordDesktop)。这会捕获屏幕上的所有内容,包括用户自己的工作。警告用户,请他们离开,然后逐帧审查结果;如果捕获到任何隐私内容则将其删除。

4. 标题卡片

使用在浏览器中拍摄的动画 HTML/CSS,而不是静态图片。将卡片标记注入到应用自身源域上的空白页面中,以便其网页字体和调色板生效,然后进行 screencast 录制。从实时页面上提取真实的显示字体(getComputedStyle),并固定一个已知良好的等宽字体栈,而不是去嗅探一个。

匹配应用的动效语言(其自身的缓动曲线和时长)。如果项目没有已建立的卡片样式,请在设计前加载 frontend-design 技能。

5. 剪辑

reference/build.js 将每个片段标准化为统一的尺寸/帧率,然后将整个链进行交叉淡入淡出。保持剪辑间隔约 2.5-4 秒。为高潮时刻留出正常速度的空间,同时压缩其周围的例行操作。

6. 审查,然后交付

  • 生成联系表以及每秒的完整分辨率帧。
  • 检查帧中是否有 PII、裁剪到面板边缘以及不可读的文本。
  • 使用探测器验证时长和尺寸。
  • 交付 MP4,对于 README,交付一个经过调色板优化的 GIF(GitHub 不会内联播放提交的 MP4)。保持 GIF 在约 10 MB 以下。
  • 除非要求,否则保持静音;你无法为音乐授权。说明这一点。

来之不易的具体细节

切勿使用 zoompan 进行推近镜头。 它会逐帧重新计算缩放并将裁剪窗口四舍五入到整数像素,导致图像来回跳动——看起来像地震。使用固定机位配合真实的页内滚动。如果必须使用推近镜头,首先将源素材放大 4 倍,并使用帧差值测量(reference/jitter.js)进行验证:一个固定的静态镜头平均差值应远低于 1.0;可见的抖动测量结果为 3 以上。

当动画稳定时,Screencast 会停止发送帧。 一个在 1.2 秒后结束动画的卡片会产生一个 1.2 秒的片段。使用 tpad=stop_mode=clone:stop_duration=N 填充,并使用 -t 剪辑到你想要的长度。

组装带有时间戳的帧,而不是固定帧率。 Screencast 帧带有 metadata.timestamp;编写一个带有实际每帧持续时间的 ffmpeg concat 列表,然后重新采样为恒定的 60fps。假设固定间隔会产生抖动。

ffmpeg-static 作为开发依赖项,通过模块路径解析。切勿依赖系统 PATH 中的 ffmpeg。(ffprobe 不在该包中——改为解析 ffmpeg -i 的 stderr。)

身份验证捕获: 在有头模式下登录一次,保存 storageState,在每次拍摄时重复使用(reference/login.js)。会话会过期——在同一天完成拍摄或重新运行。同时在那里植入任何 localStorage 的 UI 偏好设置。

部署源站访问 Localhost 会被 Chrome 的本地网络访问策略阻止。 如果页面必须访问本地服务,请使用 --disable-features=LocalNetworkAccessChecks,PrivateNetworkAccessChecks,BlockInsecurePrivateNetworkRequests 启动。

在固定偏移处裁剪掉持久的 Chrome 边栏。 以视口宽度 1920 + railWidth 拍摄,然后使用 crop=1920:1080:railWidth:0 裁掉侧边栏并精确落在 1080p 上。

交付物

报告路径、时长和尺寸;明确指出用户还需要什么(音乐、GitHub 原生视频上传);并披露拍摄过程中发生的任何用户可能想知道的事情。

相关技能