Communitygithub.com

产品演示视频

将静态产品截图或设计转换为精美的动画演示——无需录屏,无需抖动光标。支持设备/浏览器框架、动画光标+点击波纹、缩放/平移至焦点UI、标注说明、步骤节奏、屏幕间过渡和功能说明文字。

产品演示视频 是什么?

该技能是一个基于 Remotion 的框架,用于从静态截图创建高保真、声明式的产品演示视频。与传统的屏幕录制不同,它通过编码的缓动曲线驱动合成光标、点击波纹和摄像机运动(Ken Burns 风格缩放),确保帧精确的可复现性。它专为展示 SaaS 点击路径、功能公告和产品导览而设计,能拆解 UI 变更导致的重录问题。该技能支持浏览器和移动设备框架、带连接线的标注说明、以及四种一致的屏幕间过渡(滑动/交叉缩放/淡入淡出/匹配剪辑),并提供全面的验证工作流,包括逐帧检查静态图片、编码 MP4 及批量渲染。它需要用户提供 2 倍分辨率截图以支持清晰的 2 倍缩放,所有动画值都是帧号的纯函数,无 CSS 过渡或计时器,确保每次截图变更时输出完全一致。

兼容平台~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/playlikeboy/videos-skill/tree/HEAD/.claude/skills/product-demo-video

在你喜欢的 AI 中提问

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

文档

产品演示视频 是做什么的?

将静态的产品截图或设计转化为精美的动画演示——无需录屏软件,无需抖动的真实光标,不受 UI 版本偏差影响。为每一屏放上框架,让合成光标沿着缓动路径滑到精确的像素位置,触发点击波纹,然后缩放到关键区域并配上功能说明。因为输入是静态的,动画通过代码驱动,所以每个值都是确定性的,截图更改后重新渲染结果完全一致。

使用时机

  • 应用 / SaaS 演示、功能发布公告、入门引导操作演示(15–90 秒)。
  • 展示你只有截图或设计的 UI 的点击路径。
  • 高亮显示密集仪表盘中的某个焦点区域(区域缩放 + 标注说明)。

为什么截图优于录屏

屏幕录制截图驱动(本技能)
真实光标会漂移、超调、抖动光标沿缓动路径精确到达目标
修复一步需要重新录制全部内容替换一张 PNG,重新渲染相同代码即可
录制中途 UI 变化,鼠标需要重新定位每张截图都是清晰的最终状态资源
缩放容易产生像素化以 2 倍(DPR 2)导出截图 → 缩放清晰

以两倍显示尺寸(视网膜 / deviceScaleFactor: 2)捕获输入,这样 2 倍缩放也能保持清晰。请参见 references/screenshot-demo.md 获取 Playwright 截图脚本。

演示流程

每个演示都以相同的节奏重复每个功能。保持足够长的停顿供用户阅读,有意图地移动,精准落点击,然后展示效果。

节拍时长预算任务
停驻在屏幕上0.5–1 秒让观众在动画开始前先定位
光标移动到目标0.4–0.8 秒缓动移动(ease-in-out),非直线
点击波纹 + 状态变化0.2–0.3 秒触觉反馈;屏幕在同一帧做出反应
缩放至焦点区域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 的 Ken Burns 效果)

要缩放至焦点元素,将屏幕进行缩放并将 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 6 individual skills — each has its own dedicated page.

animated-infographic

This skill should be used when the user asks to "make an animated infographic", "create an infographic video", "build an infographic animation", "animate an explainer infographic", "do a sequenced reveal of icons and stats", "animate icons with key numbers and connectors", or "lay out a designed infographic that animates in sequence". Covers infographic layout & visual hierarchy, staggered element reveals, animating icons/pictograms, key-number counters, connectors/flow, and section pacing. For heavy charting (bar chart race, charts from a CSV) use the chart-animation skill instead.

brand-motion-guidelines

This skill should be used when the user asks to "write motion guidelines", "create a brand motion system", "define easing and timing tokens", "document our animation principles", "build a motion language like Slack/IBM/Klarna", "set up entrance/exit/transition rules", or "add a reduced-motion / accessibility section". It outputs a fill-in-ready brand motion guidelines document.

explainer-video

This skill should be used when the user asks to "make an explainer video", "turn this into a short explainer", "write a script and storyboard for a product video", "produce a how-it-works/onboarding video", "sync narration and captions", or "build a 30–90s animated explainer". Covers script→storyboard→scene build→narration/caption sync→edit→polish.

presentation-video

This skill should be used when the user asks to "make an animated presentation", "turn a pitch deck into a video", "convert slides/a deck to video", "make a presentation video", "build a deck video", "narrate a slide deck as a video", or "auto-advance slides synced to a voiceover". Covers rebuilding slides as motion graphics with staggered build reveals, slide-to-slide transitions, and timing locked to per-slide narration.

shot-composition

This skill should be used when the user asks to "compose a frame", "set up a grid", "plan shot composition", "place the focal point", "decide where elements enter and exit", "add a parallax/camera move", "adapt a layout for 16:9 / 9:16 / 1:1", or "keep content inside safe areas". Covers grids, safe areas, focal hierarchy, and 2D/3D camera framing.

whiteboard-animation

This skill should be used when the user asks to "make a whiteboard animation", "draw-on explainer", "VideoScribe style", "hand-drawn explainer video", "animate a sketch being drawn", "do a doodle/scribe video", "show a hand drawing the illustration", or "animate handwriting appearing on a whiteboard". Covers SVG stroke draw-on, a marker hand that follows the path tip, staggered reveal, erase/wipe transitions, and narrated export.

相关技能