mcpField
S
site-reels

site-reels

github.com/pedrojaques99创意与媒体8113 次安装2 天前更新
代码仓库

关于 site-reels

site-reels 用于录制本地运行网站中的脚本化场景,并生成视频素材或展示片,面向制作网站与产品视频的团队。它提供浏览器录制和确定性逐帧捕获两种流程。

主要功能

  1. 01脚本化浏览器场景录制
  2. 02可配置尺寸的 MP4 输出
  3. 03通过 snap.mjs 控制时间逐帧捕获
  4. 04场景准备与交互钩子
  5. 05Remotion 展示片合成指引
  6. 06视频与帧检查流程

适用场景

  1. 01录制网站品牌场景
  2. 02捕获产品操作流程制作展示片
  3. 03制作确定性 60fps 视频素材
  4. 04为 Figma Slides 准备视频封面

MCP 相关

README 提及使用 Figma MCP 工具(如 use_figma 和 upload_assets)创建幻灯片占位内容并上传封面图片;同时说明 MP4 不通过 MCP 上传。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/pedrojaques99/visant-skills-public --skill site-reels

安装后在 Claude Code 中输入/site-reels确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
cases.md
scripts/
deliver.example.sh
find-chrome.mjs
loop.sh
patch-timeweb.mjs
record.mjs
scenes.example.mjs
snap.mjs

详细介绍

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

要求

适用于要求检查
所有功能配备 GPU 和可见桌面的 Windows、macOS 或 Linux(Chrome 以有头模式运行)不适用
所有功能Node.js 18+node -v
所有功能PATH 中有 ffmpeg + ffprobe(或 FFMPEG=<full path>)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 <proj>-reels && cd <proj>-reels && npm init -y && npm i puppeteer-core puppeteer-screen-recorder
mkdir -p scripts && cp ~/.claude/skills/site-reels/scripts/{record,find-chrome}.mjs scripts/
cp ~/.claude/skills/site-reels/scripts/scenes.example.mjs scenes.mjs   # edit the scenes
# in the site repo: npx next build && npx next start -p 3100   (production build: smoother WebGL)
OUT="<output folder>/Videos" node scripts/record.mjs scenes.mjs [scene ...]

运行复制到项目中的脚本: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 会生成 720x900。

每个场景 = { 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/<dur>,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:无头模式会回退到 SwiftShader,导致 WebGL 卡顿。
  2. 隐藏 UI 的 CSS 会消失,页面重新加载时以及 React hydration 清空 <head> 时都会如此 → 脚本每 100ms 将 <style id="reels-hide"> 重新附加到 body。
  3. 一个无效选择器会导致整条规则失效:JS 模板字面量中的 \[ 会变成 [,而 .z-[60] 会使 header, nav, .z-[60] 失效。每个风险选择器单独写一条规则。
  4. 不要隐藏 [data-cursor]:网站会给 3D 画布和轮播图添加此属性。应定位自定义光标元素(fixed + mix-blend + pointer-events-none)。
  5. 延迟加载的 3D 内容(IntersectionObserver + dynamic import):到达相应区域后等待 5–7 秒。没有 preserveDrawingBuffer 时,读取 WebGL 画布会得到空内容:使用固定等待时间或截图。
  6. 屏幕录制每秒约输出 32 个不重复帧 → 以 30fps 录制(60fps 会产生不规则的重复帧)。默认的 trim 0.3s 会丢弃首个缓存帧。
  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 中接受 Cookie(通用方式点击“Accept/Aceitar/OK”)。
  9. 不需要滚动的工具页面(生成器、效果编辑器)录制出来会是静止画面:场景必须有交互(向 input[type=file] 上传文件、按按钮文本点击预设)。自定义滑块不会响应合成的 input 事件。

60fps 锁定片段:snap.mjs(确定性)

scripts/snap.mjs 注入 timeweb(timesnap 的虚拟时钟:rAF、performance.now、 setTimeout 和 video),每帧前进 1/60s 并截图,不受机器负载影响。 场景配置:{ name, path, theme, css, dur, wait (等待 3D 加载的实际毫秒数), pre (滚动前的虚拟毫秒数,2000;对于加载时即播放的片头,设为 **0**), start (跳过的虚拟秒数), scroll: { sel, from, to, at, len } | { bottom: [from, to] in screen heights }, frame(page, t) (例如鼠标) }。滚动由虚拟时间驱动。

npm i puppeteer-core timesnap && mkdir -p scripts
cp ~/.claude/skills/site-reels/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 [scene]
  • 不要直接使用 timesnap():使用 Next + R3F + Lenis 时,它录下的是空白页面,WebGL 主视觉区域也有一段段冻结画面(rAF 不会运行)。自定义循环(goTo + scrollTo + screenshot)在所有场景中都有效:60 帧中有 60 个不重复帧。
  • 必须应用 timeweb 补丁:它会将 video.play() 替换为不返回 Promise 且不触发 playing 事件的版本 → video.play().catch() 会抛出错误,导致页面变成空白。
  • 在 getContext 上强制启用 preserveDrawingBuffer: true(使用 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 <t> -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、黑色背景、一个命名为 VIDEO · x.mp4 的 1920×1080 矩形,以及写入 speakerNotes 的说明。
  3. 将矩形的 nodeIds 传给 upload_assets → 通过 multipart 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 渲染:在 Photoshop 开启时,32GB 内存的机器使用并发数 8 会耗尽内存。
  • 循环视频:scripts/loop.sh in out [start] [dur] [crossfade]。使用 magick compare -metric RMSE 比较首尾帧,检查衔接处(< 0.5% = 不可见)。
  • 不合格的素材底片应直接舍弃:旋转的旋转体看不出运动;为竖屏画布构图的镜头放在 16:9 画面中会显得很小。
  • 急促风格的视频(获批节奏):25–35s、60fps,使用 Series,按 120 BPM 网格(30 帧)进行硬切;每 3–6 帧出现一组图像;网格上叠加巨幅 logo 裁切图、闪变的字体粗细、重新排列的色块、圆形蒙版中的肖像、图形爆发、动态短句、持续一拍的样机镜头,并以停留约 2.5s 的 logo 收尾。零标签:文字只能作为图形出现。节奏缓慢的 1:40 展示视频未获通过。
  • 柔和/烟雾风格的视频:录制主视觉烟雾时不要出现 logo 或照片,使用纯白背景上的黑色烟雾(带 storage = localStorage 中的参数,以及 block: ['assets/logo.png'] 的场景;空白 PNG 必须透明;不要屏蔽视频:视频出错会导致 timeweb 卡住)。将素材底片用作 mix-blend-mode: multiply 叠加层:场景开始时淡入,倒放版本(ffmpeg -vf reverse)在结尾淡出;切点落在黑帧上。约 1.1s 时转场(速率 2),否则半个场景会变黑。
  • 拼装 Figma Slides 布局:克隆幻灯片(设为跳过),将每张卡片各复制 3 次,每份只显示背景 / logo / 文字;使用 download_assets 下载每个节点(缩放 2 倍),然后删除克隆。Slides 不会导出透明度:将幻灯片设为黑色和白色,分别导出 logo/文字,再通过差值提取 alpha(ImageMagick)。绝不要通过 use_figma 返回 base64(会撑爆上下文)。

产品展示视频(真实应用实拍)

使用 Playwright + CDP screencast 以 2 倍速真实录制屏幕,步骤为 goto/move/click/type/scroll/wait,指针轨迹保存为 <id>.cursor.json,然后在其上方用 Remotion 重绘光标。

已否决,请勿重蹈覆辙:

  • 将设计好的视频片段拼接到真实屏幕画面上(插画开场 + 实拍中段 + 绘制的 CTA): 两种语言混用,角色消失后又出现,幕间的黑色卡片打断节奏。 每个视频只用一种语言。
  • 缩小并加速的产品屏幕画面放在 16:9 窗口中:动态信息流和排名变成难以辨认的一片。
  • 裁切屏幕的缩放画面和叠加在视频上的文字(巨大的动词、01/07 计数器、 渐变):喧宾夺主。
  • 屏幕上空等(“等待中……”):直接切入操作。
  • 文案含糊:必须清楚易懂,使用受众日常说的话。

有效的形式:每项操作先单独显示文字,居中且简短(2 拍),然后显示完整屏幕,不裁切,置于干净背景上的居中窗口中,窗口保持录制画面的宽高比。 文字低调(字重 700,逐词入场并带轻微模糊),不加计数器,不加渐变。按音乐轨道网格切换(14 帧 = 128.57 BPM)。最长 40 秒。

实践证明有效的技巧:

  • 加速录制画面:使用 <OffthreadVideo trimBefore={from} playbackRate={rate}>,并将点击帧重新计算为 / rate(声音和光标圆环也要同步)。
  • 从中途开始另一个合成:<Sequence from={X}><Sequence from={-start}><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-*,并告知用户。

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

  • 使用 KEEP_UI=1 运行 record.mjs(卡片显示网站的实际样子),并使用上面的手机预设。
  • 根据清单文件生成场景(仅包含公开且有可用 URL 的项目);没有可用 URL 时,对截图应用 Ken Burns 效果。
  • 卡片交付包:首尾交叉淡入淡出循环、2 遍编码以满足 KB 上限、同时提供 VP9 WebM,以及第 1 帧的 WebP 海报图。
  • 用于网页的透明 Logo:--codec=vp9 --pixel-format=yuva420p(Safari 无法播放)+ 用于编辑的 ProRes 4444;Config.setVideoImageFormat("png") 可保留透明度。
  • Remotion 中的剪纸/定格动画效果:时间按 2 帧量化(24 fps,每 2 帧一个姿势);每个姿势应用 SVG 滤镜(边缘使用 feTurbulence + feDisplacementMap、奶油色边框使用 feMorphology、硬偏移阴影),并循环使用 3 个种子(“boil”);纸张纹理设为正片叠底。通过 DOMParser 按 id 读取设计师 SVG 中的吉祥物部件,因此更换品牌版本时无需改代码。
  • CC0 音乐:Free Music Archive(CC0 专辑)。可选用 Python 中的 librosa.beat.beat_track + 分段 RMS 分析节奏和最饱满的片段。

项目起源故事、参考项目和特定机器的技巧:references/cases.md。

评论

支持 Markdown