Communitygithub.com

digitalsamba/synthetic-ui-demo

无需屏幕录制即可制作产品演示和版本发布视频。通过从源代码重建应用的静态 React 界面,并使用脚本化光标和摄像机在 Remotion 中驱动它们。

synthetic-ui-demo 是什么?

该技能是一种 AI 驱动的视频生成方法,用于制作产品演示、功能演示、版本发布说明或更新日志视频,且无需任何屏幕录制。它通过让 AI 读取产品的源代码,仅重建场景所需的静态 React 屏幕,然后在 Remotion 中通过脚本化的光标和摄像机实现操作流程。每个点击都对应一个帧编号,因此场景可以完全一致地重新渲染,无需种子账户或实时环境,并且当产品变化时只需编辑代码即可更新。该技能提供了一组构建块(如 Stage、Cursor、cursorAt),用于创建包含浏览器 chrome、摄像机移动和光标操作的视频帧。它特别适合与 Playwright 录制(/record-demo)相比的场景:当你能访问应用源代码、需要制作每次发布都要重做的版本说明或功能导览、或者流程需要你无法获得的数据(如完整的通话、其他用户、管理视图)时,使用该技能。方法涉及通过子代理从应用仓库中提取视觉规范(主题、字符串、图标、布局),仅重建场景所需的屏幕(基于固定画布的绝对定位),先录制语音再根据旁白确定帧时间,以及一系列质量控制步骤(如渲染联系表、标准化响度、检查对比度)。关键注意事项包括:避免使用已过时的本地分支、使用 `brightness(0) invert(1)` 处理深色背景上的单色 SVG 徽标、确保菜单和对话框位于画布内部,以及使用基于旁白的提示系统以便在语音变动时自动调整动画时间轴。

兼容平台✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/digitalsamba/claude-code-video-toolkit/tree/HEAD/.claude/skills/synthetic-ui-demo

在你喜欢的 AI 中提问

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

文档

Synthetic UI Demos

没有任何内容是屏幕录制的。Claude Code 读取产品的仓库,仅重建场景显示的那些屏幕作为静态 React,然后在 Remotion 中由脚本化的光标和摄像机执行流程。每个点击都是一个帧编号,因此场景可以完全一致地重新渲染,永远不需要种子账户或实时环境,并且当产品变化时,通过编辑代码即可更新。

参考构建(与此技能一起阅读;两者都在没有产品仓库的情况下构建):

  • examples/ds-free-schedule-demo:一个 26 秒的流程(安排通话),带有一个旁白块。最简单的完整用例。它的 src/Demo.tsx 是一个单一时间线,包含每个光标关键帧、点击和摄像机移动。
  • examples/ds-release-649:一个 80 秒的版本发布说明视频,涵盖三个应用的八个场景。templates/ds-release-notes 是其可复用的形状(作为版本 650 发布)。src/Release.tsx 编排场景,src/scenes/ 中每个发布项对应一个文件,src/room/ 和 src/ac/ 是屏幕套件。

何时使用此技能 vs. Playwright

Synthetic(此技能)Playwright 录制(/record-demo)
你可以读取应用的源代码你只有正在运行的应用
每次发布都需要重做的版本说明和功能导览一次性捕获真实行为或真实数据
流程需要你没有的数据(完整通话、其他用户、管理视图)真实场景易于访问且看起来已经很合适
摄像机移动、精确的点击时机、语音变更后重新渲染长时间、复杂的交互,重建成本过高

构建块(lib/components)

import { Stage, typed, cursorAt, near } from '../../../../lib/components';

<Stage
  url="app.example.com/settings"             // 地址栏;主机部分颜色更深,路径部分颜色更浅
  camera={CAMERA}                             // [{ f, z, x, y }] 画布像素坐标,缓动,限制在窗口内
  path={PATH}                                 // [{ f, x, y }] 画布像素坐标下的光标关键帧
  clicks={CLICKS}                             // 压扁光标并抛出波纹的帧
  aiNote                                      // "显示的为 AI 生成"(或传递你自己的文本)
  canvasWidth={1440} canvasHeight={810}       // 默认值
>
  <SettingsScreen field={typed(frame, 'Q4 Product Review', 128)} />
</Stage>
  • Stage 在固定大小的应用画布周围绘制浏览器 chrome,应用摄像机,并将光标放在 zIndex 100 的顶层。在缩放 1 时,窗口适配(fit)为帧宽度的 0.8625 倍。关键帧重复一个值以保持该状态。
  • Cursor 和 cursorAt 可以单独用于非浏览器场景;near(cursor, target) 驱动悬停状态。
  • 产品特定的屏幕套件(主题、图标、布局)保留在项目中。它们不属于库内容。

方法

1. 通过子代理从应用仓库中提取视觉规范

为每个应用或区域并行发送一个子代理,让每个子代理返回一个紧凑的规范,而不是文件转储:

  • 主题: 调色板、字体栈、圆角、间距、阴影(来自主题文件或 CSS 变量)。
  • 字符串: 场景显示的每个标签、菜单项、对话框和提示的精确英文本地化字符串(public/locales/en/*.json、src/i18n/locales/en/*)。切勿意译 UI 文本。
  • 图标: 如果应用使用图标字体,其 icomoon/fontello selection.json 包含每个图标的 SVG 路径。将你需要的提取到一个小的 JSON 中,并渲染为 <svg><path d=...>。否则复制 SVG 组件。
  • 布局和行为: 所显示屏幕的组件树、工具栏顺序、默认值、每个控件的作用。

从远程读取默认分支(git show origin/main:path,或 git fetch 然后读取 origin/<default>)。本地检出通常已过时,会给你上个季度的 UI。

对于版本说明,将每个项追溯到首先发布它的提交和组件。这样可以让你获得确切的字符串和要显示的默认值。

2. 仅在固定画布上重建场景显示的内容

  • 将所有元素以绝对位置布局在固定画布上(1440x810 是一个好的默认值)。将重要的矩形导出为常量(SAVE_BTN = { x, y, w, h }),这样点击目标就是算术运算,而非猜测。
  • 只构建摄像机看到的内容。从未出现在镜头中的面板可以是一个纯色块。
  • 保持静态 React:没有状态,没有副作用。每个视觉变化都是 frame 的函数。
  • 将套件放在自己的文件夹中(src/ui/、src/room/),并包含一个用于常量的 theme.ts。

3. 先录制语音,再确定时间线帧

  • 每个场景写一行,按句子拆分(每个短语一个 .txt),并首先生成音频(voiceover.py --scene-dir ...)。录制三遍加上 tools/pick_takes.py 比单次录制加上 --max-wpm 更有效:克隆会复制其参考剪辑的节奏和平坦度,所以如果台词听起来仓促或单调,使用 tools/voice_prosody.py expand 修复剪辑,而不是拉伸输出(参见 CLAUDE.md 中的 "Clone Prosody")。读取测量到的时长,以及 tools/captions.py 用于单词时间。
  • 将每个场景的大小设置为你的台词加上一个节拍,并在文件顶部保留一个注释,列出每句台词的起始位置和长度。该注释是真理的唯一来源(参见 CLAUDE.md 中的 "Audio-Anchored Timelines")。
  • 场景文件顶部的一切都是帧常量:光标关键帧、CLICKS、摄像机关键帧、UI 状态切换(frame >= C.save 显示对话框)。导出点击帧,以便父级可以放置点击音效。
  • 通过旁白查找帧,不要手动设置。 voice()(lib/components/cues.ts;ds-release-notes 模板有一个副本)接收场景的短语及其 .captions.json 和起始帧,而 cue('save') 返回该单词开始的帧。将每个动作锚定到它说明的单词上,并带有一个偏移量,并将每个光标和摄像机关键帧锚定到这些锚点上:
    import line06a from '../../public/audio/scenes/06a_link.captions.json';
    export const LINK_VOICE = voice([{ file: '06a_link', at: 10, captions: line06a }, ...]);
    const { cue } = LINK_VOICE;
    const C = { field: cue('before', { offset: -3 }), save: cue('save') };
    const PATH = [{ f: C.field - 6, ...field }, { f: C.save - 24, ...saveBtn }];
    
    重新生成或重新调整短语的时间,点击、打字、光标和摄像机都会随之移动。一个其单词不再被说出的提示会在构建时失败,并指出是哪些单词。选项:offset、edge: 'end'、after(一个帧,用于重复的单词)、nth、in(一个短语)。父级从 LINK_VOICE.lines 放置音频,因此短语的起始帧只写入一次。templates/ds-release-notes/src/scenes/FreeCustomLink.tsx 是详细的示例。

4. 在停顿处拆分密集的列表行

列出多个事物的台词("日程安排、联系人、录音和抄本")一次拍摄太快。在停顿处将音频拆分为短语文件(07a、07b、...),给每个短语自己的镜头,并将每个短语放在自己的节拍上。ds-release-649 的 moreVo 字段实现了这一点。

5. 在完整渲染之前,通过联系表测量点击目标

猜测的坐标在摄像机缩放后通常偏差 20-50 像素。在每个点击帧及其前几帧渲染静态图片,将它们平铺,并检查光标尖端是否位于目标上:

i=1; for f in 46 78 122 212; do npx remotion still MyComp out/stills/s$i.png --frame=$f; i=$((i+1)); done
ffmpeg -start_number 1 -i out/stills/s%d.png -vf "scale=640:-1,tile=2x2" -frames:v 1 out/contact.png

修复常量,重新渲染静态图片,然后才渲染视频。

6. 标注屏幕上的 AI 生成人物

任何不是真实的人(方块中的 FLUX.2 肖像、头像、旁白)都要有可见的标签:Stage 上的 aiNote,或者旁白块上的 "AI" 徽章。姓名、联系人和通话数据也是虚构的,因此保持它们明显是虚构的。

7. 渲染,然后标准化

渲染前使用 tools/qc.py --project ...,然后使用 qc.py --render out/video.mp4 --fix 实现 -14 LUFS。使用 qc.py --project ... --layout 检查视频自身文本(字幕、卡片、AI 注释)的大小和对比度,并单独列出产品 UI。Stage 将其窗口标记为 data-qc="product";在外部构建的任何手机或平板模拟器上也放置相同的属性,否则其 UI 文本将被当作视频的一部分进行评判。

注意事项

  • 单色 SVG 徽标渲染为黑色。 logo_mono.svg 通常有黑色填充;在深色背景上使用 filter: brightness(0) invert(1)。
  • 已过时的本地分支。 读取 origin/<default>,而不是本地检出的任何分支。
  • rsync --exclude src 也会删除 node_modules/*/src。 复制项目或套件时,使用前导斜杠将排除项锚定到传输根目录:--exclude /src。
  • 摄像机会进行限制。 靠近画布边缘的摄像机中心会被拉回,以免窗口边缘显示到帧之外。如果缩放落到意外位置,就是这个原因;瞄准更靠内的点。
  • 菜单和对话框必须位于画布内部。 画布会裁剪其子元素。将菜单定位为向内打开,正如真实应用那样。
  • 悬停状态来自光标路径。 使用 near(cursorAt(frame, PATH), target) 而不是第二组帧常量,这样移动关键帧时悬停状态也会随之移动。
  • 更改的语音行会移动其后所有内容。 在提示场景中,点击、光标和摄像机会自动跟随,但场景长度和后面短语的 at 仍需要检查。在手动设置的场景中,需要重新测量每个帧。无论哪种方式,都要更新头注释和场景长度,然后重新检查点击静态图片。如果由组装语音音轨驱动的口型同步旁白受到影响,也需要重新生成它。
  • 套件比演示寿命更长。 重建的屏幕套件可以托管其他视频:ds-release-notes 房间变成了一个恶搞短片品牌版的舞台,其方块中有动画面孔,并且没有新的屏幕工作。将套件复制到新项目中,并将其逻辑画布缩放到帧(.claude/skills/parody-short/formats.md)。

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

digitalsamba/claude-code-video-toolkit

Python video composition with moviepy 2.x — overlaying deterministic text on AI-generated video (LTX-2, SadTalker), compositing clips, single-file build.py video projects. Use when adding labels/captions/lower-thirds to LTX-2 or SadTalker outputs, building short ad-style spots in pure Python without Remotion, or doing programmatic video composition. Triggers include text overlay on video, label LTX-2 clip, caption SadTalker output, lower third, build.py video, moviepy, Python video composition, sub-30s ad spot.

digitalsamba/claude-code-video-toolkit

Video and audio processing with FFmpeg. Use for format conversion, resizing, compression, audio extraction, and preparing assets for Remotion. Triggers include converting GIF to MP4, resizing video, extracting audio, compressing files, or any media transformation task.

digitalsamba/ideogram4

Prompting patterns for Ideogram 4 text-to-image — best-in-class in-image text rendering and exact color/layout control via structured JSON captions. Use when generating images that need legible on-image text (title cards, thumbnails, logos, signage, CTAs), precise brand colors, or controlled spatial layout. Triggers include title slide image, thumbnail with text, on-image text, legible text in image, brand color palette image, bounding-box layout, Ideogram.

digitalsamba/parody-short

Comedy shorts about a group's own life - a team's launch, quarter end, office move or leaving do; a club's season; a class's year; a family's Christmas - or about a shared topic everyone recognises (video calls, the return to the office), told in a borrowed genre (80s action intro, creature feature, Dickens Christmas ad, heist, nature documentary) and starring the group's real, animated photos or an invented cast. Covers mining the group's own context for in-jokes (chat, email, calendars,...

相关技能