Communitygithub.com

产品演示视频制作

这个技能用于将静态的产品截图或设计稿转换为精美的动画演示视频,涵盖设备/浏览器框架、动画光标与点击波纹、区域缩放、标注说明、步骤节奏、画面过渡和功能字幕等。

产品演示视频制作 是什么?

这个技能(Product Demo Video)专为将静态截图或设计稿转变为专业、可复现的动画演示视频而设计,适用于SaaS演示、功能介绍、新手指引等场景。它基于 Remotion 框架,通过代码驱动动画,确保每一帧都是帧号的纯函数,从而避免传统屏幕录制中光标抖动、UI版本漂移、重录成本高的问题。主要功能包括:自动为截图添加浏览器或手机设备框架;使用缓动算法控制光标沿路径平滑移动并触发点击波纹;通过缩放(Ken Burns 效果)聚焦 UI 关键区域,并结合标注和功能字幕;支持多种画面过渡效果(推拉、交叉缩放、淡入淡出等)。该技能输出可复用渲染的 Remotion 工程,截图变化后仅需替换资源即可重新生成一致的 MP4 视频。

兼容平台~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/2233admin/design-pipeline/tree/HEAD/skill/references/iart-motion-skills/upstream/ecommerce-video-skills/skills/product-demo-video

在你喜欢的 AI 中提问

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

文档

产品演示视频

将静态的产品截图或设计稿转换为精美、动画化的演示——无需屏幕录制,没有抖动实时光标,没有UI版本漂移。为每个画面添加框架,让合成光标精确滑动到目标像素,触发点击波纹,然后放大到重要区域并添加功能说明。由于输入是静态的,运动由代码驱动,每个值都是确定性的,当截图变化时重新渲染结果一致。

何时使用

  • 应用/SaaS演示、功能介绍、新手指引(15–90秒)。
  • 展示仅拥有截图/设计稿的UI中的点击路径。
  • 突出密集仪表板的某个焦点区域(区域缩放+标注)。

为什么截图优于屏幕录制

屏幕录制截图驱动(此技能)
实时光标漂移、超调、抖动光标沿缓动路径精确到达目标
修复一步需重新录制整个片段替换一张PNG,重新渲染相同代码
录制过程中UI变化,光标混乱每张截图都是清晰的最终状态资源
难以放大而不像素化以2倍(DPR 2)导出截图 → 缩放依然清晰

以显示尺寸的两倍(retina / deviceScaleFactor: 2)捕获输入,这样2倍缩放仍保持清晰。请参阅 references/screenshot-demo.md 获取 Playwright 捕获脚本。

演示循环

每个演示都是相同的节奏,为每个功能重复。停留足够时间阅读,有目的地移动,完成点击,揭示结果。

拍节时长任务
停留在屏幕0.5–1秒让观看者在任何动作开始前先熟悉画面
光标移动至目标0.4–0.8秒缓动移动(缓入缓出),非线性
点击波纹 + 状态变化0.2–0.3秒触觉反馈;屏幕在同一帧做出反应
缩放到焦点区域1–2秒进入,保持2–4秒2倍是最佳效果——细节足够且保持上下文
添加功能字幕与缩放保持同时一个好处短语,例如“一键导出”

移动镜头或光标,但避免同时移动两者——两个同时进行的动作会分散注意力。

为截图添加框架

原始截图看起来像错误报告;有框架的截图看起来像产品。将每张屏幕放置在品牌背景上的浏览器或设备外壳中。

// 浏览器框架——放入截图,得到一个可信的窗口
const BrowserFrame = ({ url, children }) => (
  <div style={{ borderRadius: 12, overflow: "hidden", background: "#1e1e22",
                boxShadow: "0 40px 80px rgba(0,0,0,.35)" }}>
    <div style={{ height: 40, display: "flex", alignItems: "center", gap: 8, padding: "0 14px" }}>
      {["#ff5f57", "#febc2e", "#28c840"].map((c) => (
        <span key={c} style={{ width: 12, height: 12, borderRadius: "50%", background: c }} />
      ))}
      <div style={{ marginLeft: 12, flex: 1, height: 24, borderRadius: 6, background: "#2b2b30",
                    color: "#9aa", fontSize: 13, display: "flex", alignItems: "center", padding: "0 10px" }}>
        {url}
      </div>
    </div>
    <div style={{ background: "#fff" }}>{children}</div>
  </div>
);

在地址栏中放入真实URL(增加可信度),添加柔和的阴影和渐变色背景。对于移动端,切换到带刘海屏和圆角的手机框架。将所有框架样式保持在一个主题对象中,以确保每张屏幕一致。

动画光标 + 点击波纹(核心动作)

根据当前帧驱动位置,绝不要依赖CSS过渡或墙上时钟——视频渲染器需要每一帧都成为帧号的纯函数,否则光标会不同步并闪烁。

import { useCurrentFrame, interpolate, spring, useVideoConfig } from "remotion";

// 缓动从 `from` 到 `to` 的移动,发生在 startFrame 和 startFrame+dur 之间
const useCursor = (from, to, startFrame, dur) => {
  const frame = useCurrentFrame();
  const t = interpolate(frame, [startFrame, startFrame + dur], [0, 1],
    { extrapolateLeft: "clamp", extrapolateRight: "clamp", easing: (x) => x * x * (3 - 2 * x) }); // smoothstep
  return { x: from.x + (to.x - from.x) * t, y: from.y + (to.y - from.y) * t };
};

export const Cursor = ({ from, to, startFrame, dur, clickAt }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const { x, y } = useCursor(from, to, startFrame, dur);

  // 波纹在点击帧扩展一次
  const since = frame - clickAt;
  const showRipple = since >= 0 && since < 18;
  const r = spring({ frame: since, fps, config: { damping: 18 }, durationInFrames: 18 });

  return (
    <>
      {showRipple && (
        <div style={{ position: "absolute", left: x, top: y, transform: "translate(-50%,-50%)",
          width: 12 + r * 60, height: 12 + r * 60, borderRadius: "50%",
          border: "2px solid rgba(80,140,255,.9)", opacity: 1 - r }} />
      )}
      <svg width="28" height="28" viewBox="0 0 28 28"
           style={{ position: "absolute", left: x, top: y, filter: "drop-shadow(0 2px 3px rgba(0,0,0,.4))" }}>
        <path d="M3 2 L3 21 L9 15 L13 24 L16 23 L12 14 L20 14 Z" fill="#fff" stroke="#222" strokeWidth="1.4" />
      </svg>
    </>
  );
};

光标使用 smoothstep 缓动,使其从静止加速并减速到目标(线性光标读起来像机器人)。在相同的 clickAt 帧触发波纹和屏幕状态变化,使因果对齐。请参阅 references/screenshot-demo.md 获取完整的合成示例,包含跨多张屏幕的多次点击。

缩放到区域(UI的肯·伯恩斯效果)

要放大到焦点元素,缩放屏幕并将 transform-origin 设置为该元素的中心,使缩放集中于该元素而不是画面中心。

const ZoomToRegion = ({ target, scale = 2, startFrame, dur, children }) => {
  const frame = useCurrentFrame();
  const s = interpolate(frame, [startFrame, startFrame + dur], [1, scale],
    { extrapolateLeft: "clamp", extrapolateRight: "clamp", easing: (x) => 1 - Math.pow(1 - x, 3) }); // easeOutCubic
  return (
    <div style={{ transform: `scale(${s})`, transformOrigin: `${target.x}px ${target.y}px`,
                  willChange: "transform" }}>
      {children}
    </div>
  );
};

缩放限制在2倍左右(超过3倍会失去上下文并使人迷失方向)。保持缩放状态2–4秒——足够长以阅读细节——然后在移动到下一张屏幕前缓出。将缩放与标注结合使用,绝不要单独使用。

标注说明与功能字幕

注释关键点,然后让其消失。标注由标签 + 连接线(箭头、圆圈或下划线)组成,指向焦点元素。

  • 使用柔和的光圈或变暗周围来突出元素(box-shadow: 0 0 0 9999px rgba(0,0,0,.45) 可以切出一个聚光灯孔)。
  • 每拍节字幕一个好处——简短的名词短语(“实时分析”),而不是一个句子。在缩放时进入,在下一步之前退出。
  • 将字幕保持在下三分之一 并在标题安全区域内,以便在裁剪为9:16时不受影响。

请参阅 references/annotation-and-transitions.md 获取聚光遮罩、箭头连接器和带打字效果的字母轨道。

画面间过渡

在步骤之间,使用一种一致的语言移动画面。选择一种并坚持下去:

过渡感觉用途
推动/滑动向前移动的“下一步”线性引导
交叉缩放动感,像应用跳转到详细视图
交叉淡入淡出平静,中性切换上下文(设置 → 仪表板)
共享元素上的匹配剪切无缝同一卡片跨屏保留

保持当前画面直到其点击解析完成,然后进行过渡——绝不要在运动过程中剪切。请参阅 references/annotation-and-transitions.md。

输出检查清单

  • 输入以2倍(DPR 2)捕获;2倍缩放保持清晰。
  • 每个光标/缩放值都是 useCurrentFrame() 的纯函数——动画状态不使用CSS过渡。
  • 光标沿缓动路径(smoothstep)移动;波纹和状态变化在同一点击帧触发。
  • 每张屏幕都添加了框架(浏览器/设备),包含真实URL和一致的主题。
  • 一次只做一个动作(镜头或光标);缩放 ≤ 2倍,保持2–4秒。
  • 每拍节一个好处字幕,位于标题安全的下三分之一;过渡使用一种一致的语言。

交付与验证(渲染静帧 → MP4)

打包的助手脚本(scripts/):使用 scripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png 平铺你的静帧,然后使用 scripts/probe-mp4.sh out.mp4 [WxH] [fps] 验证编码。参见 scripts/README.md。

这是重型任务:交付物是MP4,而不是实时页面。演示使用用户资源——截图/设计稿、可选 Logo——因此验证主要是正确的图片是否实际加载并落在画面中。

输出约定:

  • 一个 Remotion 工程,注册了合成(<Composition> + zod schema + defaultProps);每个光标/缩放/过渡值都是 useCurrentFrame() 的纯函数(没有CSS过渡、定时器、Date.now())。
  • 截图通过 staticFile() 加载,并使用 delayRender/continueRender 门控,确保在帧渲染之前2倍 PNG(和任何 Web 字体)已存在——否则屏幕会在演示过程中空白弹出。
  • 交付物 = 渲染后的 out/*.mp4 加上工程(截图变化时重新渲染)。

验证循环——渲染静帧 → 检查 → 编码。 先跑便宜的PNG,只有确认正确后再生成视频。

# 使用实际将要交付的参数(真实截图路径)而非 defaultProps 输出帧精确静帧
npx remotion still ProductDemo out/f-settle.png --frame=15  --props=demo.json   # 画面已加框架,移动前
npx remotion still ProductDemo out/f-click.png  --frame=90  --props=demo.json   # 光标在目标上 + 波纹
npx remotion still ProductDemo out/f-zoom.png   --frame=150 --props=demo.json   # 缩放到焦点区域 + 字幕
# 结束帧 = durationInFrames - 1(npx remotion compositions 读取)

检查每个PNG的保真度(正确的截图已加载;光标在精确像素上;点击波纹和状态变化在同一帧;字幕文字正确)和伪影(图片空白/未加载,屏幕出画布,缩放像素化或超出画面,字幕超出标题安全下三分之一,宽高比错误/黑边)。

# 仅在静帧干净后:
npx remotion render ProductDemo out/demo.mp4 --props=demo.json
npx remotion render ProductDemo out/demo.gif --props=demo.json --codec=gif   # README 首屏证明

批量处理(一个模板,多个产品): 当为每个产品重新定制演示时,先通过静帧验证一个代表性产品的参数,然后再批量渲染整个目录——一次捕获空白图片或出画布的错误,而不是N次。

完成前:

  1. 静帧在停留/点击/结束时渲染清晰——无错误,截图实际已加载(非空白)。
  2. 光标落在精确目标上;波纹+状态变化在同一帧;字幕文字正确且在标题安全下三分之一。
  3. 所有运动由帧驱动——没有CSS过渡/定时器/Date.now()/Math.random()。
  4. 实际交付的参数(真实截图路径)正确渲染,而不仅仅是 defaultProps。
  5. 完整MP4已编码并可播放;(可选)为README渲染了GIF。

参考文件

  • references/screenshot-demo.md —— 一个完整可运行的 Remotion 演示:使用 Playwright 以2倍捕获截图、浏览器/手机框架组件、跨多张屏幕移动光标并带有点击波纹的多步合成、以及渲染命令。
  • references/annotation-and-transitions.md —— 聚光遮罩、箭头/圆圈标注连接器、带打字效果的功能字幕轨道、以及四种画面间过渡的帧驱动实现和多宽高比(16:9 / 9:16)安全区域说明。

Individual skills in this repo

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

相关技能