Communitygithub.com

site-reels: 网站场景录制与展示片制作

将网站或 Web 应用的最佳场景(WebGL 英雄区、3D 效果、滚动动效)录制为 1080p MP4 视频,上传至 Figma Slides,并使用 Remotion 打造品牌或产品展示片。使用 "record the site scenes"、"site video for the deck"、"showreel" 等指令。

site-reels: 网站场景录制与展示片制作 是什么?

**site-reels** 是一个面向开发者和设计师的高效自动化工具,用于从网站或 Web 应用中捕获关键视觉效果(如 WebGL 英雄区、3D 场景、滚动动效等),并将其直接集成到 Figma 演示文稿或 Remotion 展示片中。它通过 Puppeteer 和 CDP 屏幕录制技术,在可见桌面上以有头模式运行 Chrome,确保 WebGL 和 Canvas 渲染的流畅性,并自动检测 Chrome 环境。该工具支持两种录制模式:`record.mjs` 用于常规的 30fps 视频录制,适合大部分场景;`snap.mjs` 则使用虚拟时钟实现 60fps 的确定性帧捕获,特别适合需要精确节奏的 3D 或动画片段。录制的 MP4 视频可通过 Figma MCP 和相关的 Figma 技能(figma-use、figma-use-slides)上传至 Figma Slides,或作为“干净素材”导入 Remotion 项目,与品牌视觉元素(如字体、配色、动效)组合,制作完整的品牌或产品展示片。该工具还内置了质量控制脚本(如联系表生成、帧重复检测)、常见陷阱警告(如隐藏窗口冻结、CSS 重载丢失)以及详细的展示片制作指导(包括节奏、转场、音效归一化等),帮助用户避免常见错误,提升最终交付质量。

兼容平台~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/pedrojaques99/visant-skills-public/tree/HEAD/site-reels

在你喜欢的 AI 中提问

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

文档

Site Reels: 网站 → MP4 → 演示文稿

系统要求

用途需要什么检查方法
所有功能Windows、macOS 或 Linux,带 GPU 和可见桌面(Chrome 以有头模式运行)不适用
所有功能Node.js 18+node -v
所有功能ffmpeg + ffprobe 位于 PATH(或设置 FFMPEG=<完整路径>)ffmpeg -version
所有功能Chrome、Chromium 或 Edge(自动检测,见下文)node -e "import('./scripts/find-chrome.mjs').then(m=>console.log(m.findChrome()))"
record.mjspuppeteer-core + puppeteer-screen-recorder(npm,在项目中)npm ls puppeteer-core puppeteer-screen-recorder
snap.mjspuppeteer-core + timesnap(附带了 timeweb)npm ls timesnap
展示片Remotion 项目npx remotion --version
审计(可选)ImageMagickmagick -version
Figma 上传Figma MCP(use_figma、upload_assets)+ 技能 figma-use、figma-use-slidesMCP 工具列表

Chrome 检测(scripts/find-chrome.mjs,由 record.mjs 和 snap.mjs 使用):如果设置了 CHROME 环境变量则使用该值;否则检测已安装的 Chrome/Edge(Windows:Program Files 和 LocalAppData;macOS:/Applications 和 ~/Applications;Linux:PATH 中的 google-chrome、chromium、microsoft-edge);否则使用最新的 ms-playwright/chromium-<N>(或 PLAYWRIGHT_BROWSERS_PATH);否则停止并提示如何设置 CHROME 或运行 npx playwright install chromium。在 Windows 上会添加 --use-angle=d3d11;其他操作系统 Chrome 保持默认 GPU 后端。

功能描述

录制本地运行的网站的脚本化场景,并输出可直接用于 Figma 的 MP4 文件(1920×1080,30fps,x264 编码,< 100MB)。已验证的引擎:puppeteer-core + puppeteer-screen-recorder(CDP 屏幕录制 + ffmpeg)。无需系统屏幕录制。

运行

mkdir <项目名>-reels && cd <项目名>-reels && npm init -y && npm i puppeteer-core puppeteer-screen-recorder
mkdir -p scripts && cp <技能目录>/scripts/{record,find-chrome}.mjs scripts/
cp <技能目录>/scripts/scenes.example.mjs scenes.mjs   # 编辑场景配置
# 在网站仓库中:npx next build && npx next start -p 3100   (生产构建:更流畅的 WebGL)
OUT="<输出文件夹>/Videos" node scripts/record.mjs scenes.mjs [场景名 ...]

将脚本复制到项目中运行:ESM 模块解析从脚本所在文件夹查找 puppeteer-core,而非当前工作目录。

环境变量:BASE(默认 http://localhost:3100)、OUT、CHROME、FFMPEG、W、H、DPR、MOBILE=1(触摸仿真)、KEEP_UI=1(保留导航栏)、MIN_FPS(默认 24)。手机 4:5 比例:W=360 H=450 DPR=2 MOBILE=1 得到 720×900 分辨率。

每个场景 = { name, path, theme?, trim?, crf?, css?, prepare(page, ctx), act(page, ctx) }。prepare 在录制前运行(滚动到区域,等待 3D 加载);act 是录制的核心动作。ctx 包含 wait、scrollTo(page, y|selector, ms) 和 scrollThrough(page, selector|null, ms, from, to)(带缓动效果)。页面加载后立即运行的介绍:在 act 中使用 page.reload(),并通过 trim 裁切加载部分。

有效的品牌脚本结构:logo/英雄区介绍(浅色和深色模式)、英雄媒体切换、3D 区域(相机随滚动进入)、沉浸式路径浏览、页脚标志、一次完整页面滑动。5–7 个场景,每个 12–55 秒。

交付前审计(不要信任退出码)

  • 每个视频的联系表:ffmpeg -i x.mp4 -vf "fps=6/<时长>,scale=480:-1,tile=3x2" -frames:v 1 sheet.png 并仔细查看。
  • 19 秒的视频只有 1MB = 空白场景。> 100MB 的视频无法上传到 Figma(使用场景的 crf 参数修复;对于带颗粒和拖尾的场景可设为 24)。
  • 顶部条带(crop=1920:120:0:0)在不同时间点检查,以捕捉泄漏的导航栏。
  • LOW-FPS 且在开头/结尾有长时间停顿是误报(计数器统计的是静止帧);请检查联系表。

已知陷阱

  1. 隐藏窗口会冻结 rAF → 产生冻结帧。启动时已经传入了 --disable-backgrounding-occluded-windows --disable-renderer-backgrounding --disable-background-timer-throttling --disable-features=CalculateNativeWinOcclusion。有意使用 headless: false:headless 模式会回退到 SwiftShader,导致 WebGL 卡顿。
  2. 隐藏 UI 的 CSS 在重新加载和 React 水合清除 <head> 时会消失 → 脚本每 100ms 向 body 重新附加一个 <style id="reels-hide">。
  3. 一个无效的选择器会破坏整个规则:JS 模板字面量中的 \[ 变成 [,而 .z-[60] 会使 header, nav, .z-[60] 失效。每个有风险的选择器应单独写一条规则。
  4. 不要隐藏 [data-cursor]:网站将 3D Canvas 和轮播标记为此属性。应定位自定义光标元素(fixed + mix-blend + pointer-events-none)。
  5. 懒加载 3D(IntersectionObserver + 动态导入):到达该区域后等待 5–7 秒。如果没有 preserveDrawingBuffer,读取 WebGL Canvas 会返回空内容:使用固定等待或截图。
  6. 屏幕录制每秒传送约 32 个唯一帧 → 以 30fps 录制(60fps 会产生不规则的重复帧)。默认 trim 0.3 秒丢弃首帧缓存。
  7. 在负载高的机器上屏幕录制会卡顿(Photoshop 打开、并行渲染):MP4 显示“30fps”,但实际只有 9–18 个唯一帧/秒。record.mjs 会测量(mpdecimate=hi=64:lo=24:frac=0.05)并在低于 MIN_FPS(默认 24)时最多重新录制 2 次。对于 WebGL/3D 静态板,建议使用 snap.mjs。
  8. Cookie 横幅:在 prepare 中接受(通用点击“Accept/Aceitar/OK”)后再录制。
  9. 没有滚动操作的工具页面(生成器、效果编辑器)录制的视频会静止不动:场景必须进行交互(上传文件到 input[type=file],通过按钮文字点击预设)。自定义滑块不会响应合成的 input 事件。

60fps 锁定静态板:snap.mjs(确定性帧)

scripts/snap.mjs 注入 timeweb(timesnap 的虚拟时钟:rAF、performance.now、setTimeout 和 video),每帧前进 1/60 秒并截图。独立于机器负载。场景配置:{ name, path, theme, css, dur, wait(加载 3D 的真实毫秒数), pre(滚动前的虚拟毫秒数,默认 2000;**0 表示在加载时运行的介绍**), start(跳过的虚拟秒数), scroll: { sel, from, to, at, len } | { bottom: [from, to](屏幕高度倍数) }, frame(page, t)(例如鼠标移动) }。滚动是虚拟时间的函数。

npm i puppeteer-core timesnap && mkdir -p scripts
cp <技能目录>/scripts/{snap,find-chrome,patch-timeweb}.mjs scripts/
npm pkg set scripts.postinstall="node scripts/patch-timeweb.mjs" && npm run postinstall
FPS=60 OUT=... node scripts/snap.mjs scenes-snap.mjs [场景名]
  • 不要直接使用 timesnap():在 Next + R3F + Lenis 组合下,它会录到空白页面,并在 WebGL 英雄区留下冻结片段(rAF 未运行)。自定义循环(goTo + scrollTo + 截图)在所有场景下都有效:60/60 唯一帧。
  • 必须打 timeweb 补丁:它将 video.play() 替换为不返回 Promise 且没有 playing 事件的版本 → video.play().catch() 会抛出异常,页面变白。
  • 强制设置 preserveDrawingBuffer: true 到 getContext(可通过 preserve: false 关闭)。
  • 帧数据写入操作系统临时目录,绝不写入同步驱动器(数千张 jpg 同步会导致问题)。
  • 不要并行进行 GPU 密集型工作(Remotion 渲染、Photoshop):WebGL 会丢失上下文,录制出仅含背景的几秒内容。脚本会警告 FLASH(通过亮度检测帧闪烁);长段空白只有联系表能显示。请仔细查看。
  • 真正的流畅度审计:使用 magick compare -metric MAE 在全分辨率下比较相邻帧。0 = 重复帧。
  • 交付:scripts/deliver.example.sh(复制并重命名静态板;V= 必需)可制作展开效果、循环(loop.sh)和干净的 3D,最多将 crf 增加 3,直到文件 < 95MB。

上传至 Figma Slides(隐藏,不干扰团队)

MP4 不通过 MCP 直接上传:use_figma 没有网络功能,Plugin API 也无法从字节创建视频;upload_assets 只接受图片(≤ 10MB)。因此:

  1. 为每个视频制作封面图:ffmpeg -ss <时间点> -i x.mp4 -frames:v 1 -q:v 2 _capas/x.jpg。
  2. 使用 use_figma(技能 figma-use + figma-use-slides):在最终幻灯片前调用 createSlideRow(idx),设置 row.name = 'WIP · Motion (hidden)',并为每个视频调用一次 createSlide(idx, i),设置 isSkippedSlide = true,黑色背景,一个 1920×1080 的矩形,命名为 VIDEO · x.mp4,并在 speakerNotes 中添加操作说明。
  3. 使用 upload_assets 上传封面图到矩形的 nodeIds → 多部分 POST。
  4. 用户将 MP4 拖放到矩形上(封面被视频替换)。请明确说明这一点;切勿承诺自动插入视频。

getSlideGrid() 会省略被跳过的幻灯片:通过 SLIDE_GRID.children[i].children 检查结构。

品牌展示片(Remotion):静态板 + 设计场景

对于品牌展示片(Logo、颜色、字体、布局、理念、模型),只需从网站录制干净的静态板(无文字:每个场景的 CSS 隐藏标题/导航),其余部分在 Remotion 中合成(逐帧渲染,无抖动)。值得拥有的可复用构建块位于 src/fx.tsx:Mist、MistWords、Grain、KenBurns、Plate、nevoa()(迷雾)过渡效果,以及 brand.ts 中的品牌数据。

  • 视觉标识来自演示文稿,而非网站:在幻灯片中检查官方字体和调色板(网站可能偏离品牌手册)。
  • 有效的场景:开场短语在迷雾中、录制的展开效果、Logo 构建(evolvePath + 在 Logo 光栅上测量的辅助线)、理念短语逐句出现、带有可变 wght 轴的柱子、色带调色板、排版、分层图形、带 mix-blend-difference 标题的 3D、滚动布局列、1/2/3 列模型蒙太奇、产品与名称同步、以标志收尾。
  • 通过静帧审查(npx remotion still ... --frame=N + 蒙太奇)后再渲染。
  • 使用 --concurrency=3 渲染:并发数为 8 时,如果 Photoshop 打开,32GB 机器可能内存不足。
  • 循环:scripts/loop.sh 输入 输出 [开始] [时长] [交叉淡入]。使用 magick compare -metric RMSE 检查首尾帧接缝(< 0.5% = 不可见)。
  • 坏的静态板直接丢弃:旋转实体显示不了运动;为竖屏画布设计的相机镜头在 16:9 中看起来很小。
  • 快节奏展示片(经批准的节奏):25–35 秒,60fps,Series 在 120 BPM 网格(30 帧)上硬切,每 3–6 帧出现图像爆发,巨大 Logo 裁剪在网格上,字体粗细闪烁,调色板块重新排列,竖屏在圆形遮罩中,图形爆发,动态短语,一拍模型,最后 Logo 保持约 2.5 秒。零标签:文字仅作为图形。1 分 40 秒的慢节奏展示片已被拒绝。
  • 柔和/烟雾展示片:录制英雄烟雾效果时不带 Logo 或照片,黑色背景配纯白(场景中使用 storage 将参数存入 localStorage,以及 block: ['assets/logo.png'];空白 PNG 必须是透明的;不要阻塞视频:损坏的视频会冻结 timeweb)。将静态板作为 mix-blend-mode: multiply 叠加层:在场景开头出现,反转版本(ffmpeg -vf reverse)结尾;剪辑落在黑色上。过渡大约 1.1 秒(速率 2),或半个场景变黑。
  • Figma Slides 布局组装:克隆幻灯片(跳过),将每张卡片复制 3 份,只保留背景/Logo/文字可见,使用 download_assets(缩放 2)下载每个节点,然后删除克隆。Slides 不导出透明背景:先在黑色背景上导出 Logo/文字,再在白色背景上导出,通过差异提取 Alpha 通道(ImageMagick)。切勿通过 use_figma 返回 base64(会撑坏上下文)。

产品展示片(真实应用录制)

屏幕录制使用真实应用(Playwright + CDP 屏幕录制,2 倍速,步骤 goto/move/click/type/scroll/wait,光标轨迹保存为 <id>.cursor.json),光标在 Remotion 中重新绘制。

已被拒绝,请勿重复:

  • 将设计好的展示片与真实屏幕拼接(插画开头 + 录制中间 + 绘制的 CTA):两种语言,角色消失又出现,行为之间的黑色卡片中断节奏。每个视频只使用一种语言。
  • 在 16:9 窗口中显示小而加速的产品屏幕:Feed 和排名变得不可读。
  • 裁剪屏幕的缩放和覆盖在视频上的文字印章(巨大动词、01/07 计数器、渐变):侵入式设计。
  • 屏幕上的空白等待(“正在等待…”):直接切入动作。
  • 模糊的文案:必须清晰明了,使用受众的日常语言。

有效的形式: 每个动作,先显示纯文字,居中且简短(2 拍),然后展示整个屏幕,不裁剪,在屏幕中央以捕获比例显示在一个中心窗口中,背景干净。文字低调(粗细 700,逐词进入,带轻微模糊),无计数器,无渐变。在轨道网格上剪辑(14 帧 = 128.57 BPM)。最长 40 秒。

有效的技术:

  • 加速录制:使用 <OffthreadVideo trimBefore={开始时间} playbackRate={倍速}> 并重新计算点击帧 / 倍速(声音和光标环)。
  • 中途开始另一个合成:使用 <Sequence from={X}><Sequence from={-开始}><Comp/></Sequence></Sequence>。检查该段的第一个帧:共享元素“飞入”时可能显得松散。跳过几帧,重新放置落在前面的冲击音效。
  • 每个合成为一个语言,使用模块级时间线:globalThis 标志由自己的入口文件设置,在 Root 之前导入。
  • 跨剪辑的连续音轨:对背景音乐使用 trimBefore,使其从前一段停止处继续。
  • 响度:渲染,测量并使用 2 遍 loudnorm(-14 LUFS / -1 dBTP)归一化,同时复制视频。只在最后测量:Remotion 的原始混音会超过 0 dBFS。
  • 审计:为每个渲染制作带时间戳的联系表(fps=2,drawtext=%{pts\:hms},tile=8x6),并在每段交界处制作密集表(fps=6)。
  • 没有 git 的项目,另一个会话同时编辑:在新文件中进行新剪辑,编辑共享文件前备份 *.bak-*,并告知用户。

作品集卡片和工作室展示片

  • record.mjs 使用 KEEP_UI=1(卡片按原样显示网站)和上面的手机预设。
  • 场景从清单文件生成(仅限有实时 URL 的公开项目);无实时 URL = 使用截图进行 Ken Burns 效果。
  • 卡片包:从结尾到开头的交叉淡入循环,2 遍码率控制到 KB 上限,同时输出 VP9 WebM,WebP 海报为第一帧。
  • 带 Alpha 的 Logo 用于网页:-

…

[此处为截断内容]

相关技能