Community编程与开发github.com

piyush140104/screen-record-skills

Claude Code 技能:生成带 ElevenLabs 配音、背景音乐、点击音效和内置字幕的脚本化浏览器操作演示视频。

screen-record-skills 是什么?

这是一个专为 Claude Code 设计的技能,旨在帮助用户创建精心编排的浏览器操作演示视频。用户只需描述屏幕上需要展示的内容、光标操作以及旁白的大致内容,该技能便会自动生成脚本化的演示视频。 该技能的核心引擎 `engine.mjs` 能够:使用 ElevenLabs 生成同步的配音片段,利用 ffmpeg 创建背景音乐和点击音效,驱动无头 Chromium 浏览器录制 1920×1080 的高清画面,最终合成包含有声旁白、音乐和 ASS 格式内置字幕的 MP4/WebM 视频。 它非常适用于 LinkedIn、Twitter、销售演示、投资者更新或入门教程等场景。支持自定义场景脚本、配音语速、音乐风格以及字幕样式。用户需要提供 ElevenLabs API 密钥来启用配音功能。

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

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

在你喜欢的 AI 中提问

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

文档

/screen-record — 脚本化浏览器操作演示视频

使用时机

用户希望制作一个网站操作的精致视频,通常用于 LinkedIn、Twitter、销售演示、投资者更新或入门文档。用户描述屏幕上应显示的内容、光标操作以及旁白的大致内容。您编写脚本;引擎负责处理光标动画、通过 ElevenLabs 进行语音合成、背景音乐、点击音效和字幕嵌入。

不要将此技能用于:正在进行的实时屏幕录制(请使用 macOS 的屏幕截图或 QuickTime)、GIF(请使用 GIF 工具)或需要真人配音的视频(您仍可以编写脚本,然后让他们重新录制)。

工作原理

引擎位于 engine.mjs。它导出 runDemo(config),该函数:

  1. 使用 ElevenLabs 为每个提示生成一个 TTS 音频片段。
  2. 使用 ffmpeg 生成柔和的背景音乐和 UI 点击音效。
  3. 启动无头 Chromium,分辨率为 1920×1080,录制视频。
  4. 运行您的 scenes(helpers) 函数,该函数驱动浏览器操作。
  5. 混合音频(旁白响亮 + 音乐轻柔 + 点击声轻微),并烧录 ASS 格式字幕。
  6. 返回最终 .mp4、.webm、.srt、.ass 文件的路径。

工作流程

第一步 — 阅读用户的请求

确定以下内容:要录制的 URL、流程(光标应如何操作)、语调(正式/随意)、时长目标。如果缺少任何信息,请提出一个有针对性问题,而不是猜测。

第二步 — 检查 API 密钥

按以下顺序查找 ELEVENLABS_API_KEY:

  1. $CLAUDE_PLUGIN_ROOT/.env.local(或技能文件夹自身的 .env.local)
  2. 当前项目的 .env.local
  3. process.env

如果缺失,请告诉用户:

我需要一个 ElevenLabs API 密钥。请从 https://elevenlabs.io/app/settings/api-keys 免费获取一个(每月 10,000 个字符,足以录制约 15 个演示)。您可以将其粘贴到聊天中,我会将其保存到技能的 .env.local,或者您也可以自己添加。

如果密钥存在但引擎抛出 ApiKeyDeadError(HTTP 401/402/403),请告诉用户:

您的 ElevenLabs 密钥已被拒绝(已撤销、过期或配额不足)。请到 https://elevenlabs.io/app/settings/api-keys 轮换密钥,然后更新 .env.local。在您完成之前,我不会重试。

不要默默重试,除非用户明确要求,否则不要回退到 macOS 的 say 命令。

第三步 — 选择语音

默认是 Liam (TX3LPaxmHKxFdv7VOQHJ) — 充满活力的美国男性,现代风格。比 George(英国男性)和 Sarah(美国女性)更轻快。engine.mjs 中的 FREE_TIER_VOICES 下还有其他免费层级的语音。如果用户说“使用 X 语音”,请在目录中找到该语音。如果他们说的是“深沉/厚重/轻柔/温暖/女性”,请相应地选择。

库语音(Charlotte、Rachel、Adam 等)需要付费的 ElevenLabs 订阅。如果用户要求使用付费语音但他们是免费层级,您将收到 HTTP 402 错误 — 回退到最接近的免费层级语音并告知用户。

第四步 — 探查目标页面(仅在需要时)

如果您不了解页面的结构,请使用 Playwright 或 curl 检查 DOM 并找到选择器。不要猜测 — 选择器很重要,不明确的匹配会导致录制超时。

对于具有动态内容的 SPA,优先使用 aria-label、role 或文本选择器,而不是类名。使用 page.locator(s).first() 语义(引擎的助手已经这样做)。

第五步 — 编写场景文件

在 /tmp/screen-record-<name>.mjs 创建一个文件(不要污染用户的仓库),该文件导入引擎并调用 runDemo。模板如下:

import { runDemo } from '/Users/<you>/Desktop/Projects/skill/screen-record-skills/engine.mjs';
// 或者,如果通过符号链接安装:
// import { runDemo } from '/Users/<you>/.claude/skills/screen-record/engine.mjs';

await runDemo({
  baseUrl: 'http://localhost:3000',
  outputDir: './output/onboarding-demo',
  outputName: 'onboarding',

  splash: {
    label: '访问我们',
    url:   'www.yourapp.com',
    footer: 'YourApp — 入门流程',
  },

  cues: [
    { id: 'intro',   text: '欢迎使用 YourApp。让我带您看看。' },
    { id: 'signup',  text: '点击“注册”创建一个账户。' },
    { id: 'form',    text: '输入您的电子邮件和密码。' },
    { id: 'done',    text: '就这样 — 您已成功进入。' },
  ],

  // 可选:模拟后端,使演示具有确定性。
  routes: [
    { match: /\/api\/signup$/, fulfill: { status: 200, body: { ok: true } } },
  ],

  // 可选:预填充已认证用户,使演示跳过登录。
  // initialAuth: { id: 'u1', email: '[email protected]', name: 'Demo User' },

  scenes: async ({ page, baseUrl, sleep, speak, awaitCue,
                   clickAt, typeInto, moveCursorTo, hideSplash, typeSplashUrl,
                   configSwitch, showSwitch, hideSwitch, setAuth }) => {

    // 场景 0:URL 启动画面(引擎已在镜头外导航到 baseUrl)。
    speak('intro');
    await typeSplashUrl('www.yourapp.com');
    await awaitCue('intro');
    await hideSplash();
    await sleep(750); // 匹配启动画面的淡出

    // 场景 1:点击注册
    speak('signup');
    await clickAt('button:has-text("注册")');
    await awaitCue('signup');

    // 场景 2:填写表单
    speak('form');
    await typeInto('input[type="email"]', '[email protected]');
    await typeInto('input[type="password"]', 'CorrectHorseBattery');
    await awaitCue('form');

    // 场景 3:提交
    speak('done');
    await clickAt('button[type="submit"]');
    await sleep(1000);
    await awaitCue('done');
  },
});

第六步 — 运行它

cd /Users/<you>/Desktop/Projects/skill/screen-record-skills
# 仅第一次执行:
npm install --silent
# 每次执行:
node /tmp/screen-record-<name>.mjs

每次运行大约需要最终视频时长加上约 10 秒的额外时间。

第七步 — 汇报

告诉用户:

  • 最终 .mp4 文件的路径(已针对 LinkedIn 优化,1920×1080,H.264 + AAC)
  • .srt 文件的路径(LinkedIn 会自动将其作为隐藏式字幕导入)
  • 在 macOS 上提供使用 afplay <path> 播放的选项

助手参考(您的场景可以调用的内容)

助手功能
page原始的 Playwright Page 对象,如果您需要它
baseUrl配置的基础 URL
sleep(ms)await sleep(800)
moveCursorTo(x, y, durationMs?)平滑移动到坐标
moveToSelector(selector, durationMs?, offset?)平滑移动到元素中心
clickAt(selector, durationMs?)移动 + 脉冲 + 点击(记录点击时间用于音效)
typeInto(selector, text, perChar?)点击 + 清除 + 逐字符输入
recordClick()手动记录点击时间戳(用于音效)
speak(cueId)标记提示开始。结束时间为 start + audioDuration + 0.35s
awaitCue(cueId)休眠直到该提示的旁白播放完毕
typeSplashUrl(text, perChar?)在启动画面 URL 栏中动画打字
hideSplash()淡出启动画面(之后总是休眠约 750ms)
configSwitch({ fromInitial, fromLabel, toInitial, toLabel, title, sub })设置账户切换卡片的内容
showSwitch() / hideSwitch()切换账户切换覆盖层的显示
setAuth(user)将 localStorage[authStorageKey] 设置为新用户(与 showSwitch 配对用于账户交换演示)

节奏经验法则

  • 每个提示一句话。保持在约 12 个词以内。
  • 对于 UI 操作,在操作之前 speak(cue),以便在光标移动时播放旁白。
  • 对于打字密集的场景,打字时间比旁白时间长 — 使用 sleep 而不是 awaitCue 来控制节奏。
  • 视频总时长通常为 sum(audioDurations) + sum(sleeps)。对于 LinkedIn,目标时长为 30-75 秒。

常见易失效的选择器

  • 单独使用 text=Foo 可能匹配多个元素。使用 page.locator(...).first() 这也是引擎已经做的,或者使用 button:has-text("Foo") 将范围限定到特定标签。
  • Tailwind 类名很脆弱。优先使用 aria-label、role、语义标签 + 文本。
  • 模态框/对话框:在点击内部之前,等待 [role="dialog"] 或模态框的标题文本。

禁止事项

  • 不要将实际的旁白文本写入场景文件 — 将旁白保留在 cues[].text 中,以便字幕和音频保持同步。
  • 不要将光标烧录到页面 CSS 中 — 引擎会注入它。
  • 不要在场景中间 await page.screenshot() — 您会捕获到光标在不合适的位置;如果需要,事后使用 extractFrames。
  • 不要提交 .env.local(它在 .gitignore 中)。

技能说明结束。

相关技能