reanimate-video 是做什么的?
reanimate 拍摄一个实时页面,在你的代码中重建它,拍摄副本并与原版比较,一轮又一轮,直到数字匹配。它自身处理视频引用的路径是可行的,但首次真实运行(2026 年 11 月 6 日,一个免费倒计时素材)遇到了七个陷阱,每个都静默或缓慢。本工具包消除了这些陷阱,并添加了视频所需的测量功能,因为视频没有可供检查的页面。
需要 reanimate:npx skills add NiazMorshed2007/reanimate -g,然后运行 bash <reanimate>/scripts/setup.sh。
然后运行一次 rv setup(测量工具所需的 numpy 和 opencv,会安装在工具包自己的 Python 环境中:大多数 Mac 上的 python3 拒绝全局 pip 安装)。用 rv doctor 检查。(rv 是本技能中的 rv 文件。)
陷阱及工具包的处理方式
| 陷阱(reanimate 原版处理视频时) | 工具包的处理 | |
|---|---|---|
| 1 | 10 位视频(ProRes,大多数素材库)会变成 16 位 PNG,每帧 10 MB | rv ref 写入 8 位帧 |
| 2 | 样式表将每一帧内联到同一个页面,导致 1080p 帧超时 | 样式表来自 480 像素的副本 |
| 3 | 以 file:// 打开的副本无法加载其 ES 模块:reanimate 会记录一个空白页面而不发出任何提示 | rv serve + rv round 拒绝 file://,并且每个记录都会被检查:BLANK 或 FROZEN 会停止本轮 |
| 4 | 副本的第一帧在其第一个动画帧之前就被记录 | 模板在加载时绘制 |
| 5 | 以 1080p 比较 300 帧需要几分钟一轮 | 比较在半分辨率下进行,每轮采用相同方式,锐化和模糊 4 像素 |
| 6 | 视频没有元素轨道或关键帧可读取 | measure/:从像素中测量中心、浮动、旋转、弧线、淡出、大小、分段、字体 |
| 7 | 虚拟时钟以浮点数累加滴答,可能跳过某一帧的最后一个滴答:该帧会提前一个滴答(默认 60 Hz 时为 17 毫秒)显示页面 | 模板上的副本通过精确在 t = k / fps 时调用其 draw 来记录;其他页面以 240 Hz 滴答记录 |
| 8 | (工具包自有工具)numpy 和 opencv 无法通过 pip 安装到大多数 Mac 上现有的 python3(Homebrew 的,PEP 668) | rv setup 创建工具包自己的 Python(.venv);rv measure <tool> 使用此环境运行每个工具 |
tests/run.sh 会在原版 reanimate 上重现每个陷阱(红色),然后以工具包的方式运行(绿色);tests/e2e.sh 在一个小案例上运行完整路径(一个副本即引用的案例读取 0%;一个注入错误颜色的案例读取更差)。对工具包进行任何更改后,请同时运行这两个脚本。
在此之前:此视频可以被复制吗?
仅复制用户有权复制的视频的外观:用户自己的视频,或允许修改的免费许可(Videezy 标准许可:免费用于个人和商业用途,需注明“Videezy.com”;Mixkit 的免费许可;Pexels 和 Pixabay 的许可)。将许可证、来源链接和日期写入 <work>/LICENSE.md,并在所有展示视频的地方显示署名(<work>/film.json 中的 "credit")。游戏画面的复制仅限于其运动(reanimate 的默认行为):外观——文字、字体、颜色、艺术——仍然属于用户自己。
步骤
rv doctorrv ref <video> <work>(添加--start/--end截取片段,--crop x,y,w,h提取单个元素)。仔细阅读<work>/ref/sheets中的每一份样式表以及<work>/ref/sheets_full_rate中的全速率样式表。在测量之前,记录何时何物在运动。- 使用适合运动类型的工具测量每个运动元素(
measure/README.md;以rv measure <tool> ...运行),在<work>/ref/frames上进行。在使用每个工具之前,先在元素上验证其正确性(使用其--sheet,或另一个必须一致的帧)。 <work>/spec.md:每个元素的每个属性一行:开始、持续时间、从 -> 到、缓动函数或测量表,以及数字来源的文件。带有“?”的行表示未完成。- 构建:将
template/复制到项目中。animation.js导出draw(ctx, t)(时间的纯函数)和DURATION;将每个测量得到的数字放入一个模块中,并附带其来源文件。画布大小与参考帧相同(<work>/run.json)。 rv serve <copy dir>然后运行rv round 1 <work> --url http://127.0.0.1:8765/index.html。阅读<work>/compare-1/report.md及其样式表(compare-1/sheets):数字说明偏差有多大,样式表说明偏差在哪里。仅修正最大的差异,然后运行rv round 2 ...。最多进行 5 轮;仍然失败的将被报告其数字和原因。rv rounds <work>(表格)和rv film <work>(过程剪辑,1080x1920:原始视频、帧、每轮比较(红色标记差异及其数字)、数字下降趋势、最终同步结果)。- 报告:复制了什么以及保真度如何,文件列表,每轮比较表格,未匹配的部分及其原因。
从视频中能复制什么,不能复制什么
可通过测量良好复制:形状、文本、旋转的环和弧、点亮的刻度和分段、淡入淡出和闪烁、增长和滑动、所有元素的顺序和时机。使用 measure/ 工具测量它们,并以形状重建。
无法通过测量复制:3D 渲染场景、实拍镜头、随机放置的粒子、闪烁变化的背景。measure/spin.py 会通过其 AGREEMENT 值指出这一点(低于约 0.3 时,条带不仅仅是旋转)。2026 年 11 月 6 日,倒计时隧道读取的 AGREEMENT 为 0.16-0.6:副本的三轮比较使其成为一片模糊(76% -> 48% 的像素偏离),而其 HUD 则匹配。应对方法:复制前景元素,为用户提供自己的背景场景(游戏场景、页面场景),并且仅在元素所在位置进行比较,或者选择一个背景简单的参考。切勿将此类副本称为像素完美。
通过标准(reanimate 自身的标准,针对视频调整)
- 时间:每个事件(元素的 10/50/90% 上升和下降,
measure/curve.py)与参考的偏差在 0.08 秒内。 - 缓动:副本的测量曲线与参考的旅行距离平均绝对偏差在 5% 以内。
- 像素:对于像素级精确副本(仅在用户有权复制其外观的参考上,并且仅当背景是复制的一部分时),平均不匹配度最多 2%;同时报告锐化和模糊的数字。
- 每轮记录都通过了守卫检查(无空白或冻结帧)。
经验教训
- 为整个设计使用一个单一的浮动值是一种假设:在稳定任何东西(
stabilize.py)之前,先在原始帧上拟合每个环的中心(polar.py fit)。2026 年 11 月 6 日(Videezy 40314),第一次拟合锁定在亮度最高的环上,即白色环,该环漂移了 8.5 像素;319 处的环仅移动了 0.1 像素。前三轮整个 HUD 都在浮动,并在由错误图层稳定的帧上进行测量;第四轮仅让白色环浮动,并重新围绕静止中心测量所有内容,结果从 12.6% 降至 9.3%。 - 在花费一整轮之前,先在少量帧上尝试更改:
rv still <work> --url ... --frames 0,60,150并使用 compare.ts 将这些帧与上一轮的代码进行比较。11 月 6 日,三个候选更改中有两个有帮助(10.0 -> 9.5 -> 8.9%),一个使情况更糟(13.3%):它从未进入正式轮次。 measure/radial_diff.py显示一轮设计在半径上的哪里偏差;它只读取静止部分——浮动环会在其中位数中产生模糊,因此当它们与 compare.ts 不一致时,以 compare.ts 为准。- 静止的环在每个角度都是明亮的:角度上第 30 个百分位数可以保留它并丢弃运动部分——这是读取环的真实半径和宽度的方式。
rv film会裁剪到主体(film.json中的 "crop"):展示时主体会变大。- 从“最锐利的环”中找到的中心会在中间出现大的白色形状时发生偏移:在多个帧上使用一个小的明亮地标,并且仅在帧之间一致时才信任它(
measure/polar.py landmark)。 - 辉光会使每个边缘变厚:通过测量(
measure/fontmatch.py)选择字体,而不是凭肉眼。 - 测量的缩放或旋转在第二视角确认之前只是一个假设:11 月 6 日,一个对数极坐标相关报告了 3%/s 的缩放,但半径-时间条显示并不存在该缩放,因此副本为此收缩了隧道一整轮。
- 面积随尺寸的平方增长:一个数字的大小是其之前帧上方白色区域的平方根,或者其边界框。
- 免费素材通常是 4K ProRes,每个片段 1-2 GB:以 1920 宽度读取(
rv ref会这样做),保留原始文件作为记录,并留意磁盘空间。