关于 frames
Frames 是用于评估网页交互流畅度的技能,通过限速录制、帧预算分析和修复前后追踪,帮助开发者定位性能原因并用数据验证改动。
主要功能
- 014× CPU 限速交互录制
- 02帧与响应时间预算检查
- 03长帧原因分析
- 04修复前后数据验证
- 05按严重程度整理报告
适用场景
- 01诊断动画期间的掉帧
- 02排查超过 200ms 的交互
- 03在相同条件下验证性能修复
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ playful-design/ router --skill frames安装后在 Claude Code 中输入/frames确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSEobserve.jsagents/openai.yaml详细介绍
帧
此技能用于衡量交互是否流畅。它会在限速 CPU 上录制交互,追踪每个卡顿帧的原因,并通过第二次录制验证修复效果。
追踪数据,而非感觉
预算是精确的。每一帧都必须在一个刷新间隔内完成;在 60Hz 下为 16.7ms,并且动画进行时,不得有任何帧超过 50ms。每次交互都必须在 200ms 内绘制出响应。没有数字支撑的“感觉很流畅”不算结论。
关于动效应采用哪些数值,请参阅 motion。逐帧拆解动效,请参阅 deconstruct。查看运行结果,请参阅 verify。
1. 明确交互
写明路由、操作步骤和关键时刻,例如“打开命令面板并输入三个字母”。通过浏览器的模拟调用将 CPU 限速 4×,模拟中端手机。在未限速的笔记本上进行追踪属于 frames-throttle-the-cpu。
2. 录制
通过浏览器的 evaluate 调用运行 observe.js。调用 window.__frames.start(),将交互执行三次,然后调用 window.__frames.stop()。如果某个长帧没有对应的脚本名称,也要录制完整的性能分析数据。没有录制就报告流畅度,属于 frames-trace-not-feel。
3. 检查预算
将录制结果与预算进行比较。动画进行时出现丢帧或长动画帧,属于 frames-hold-the-budget。交互的 duration 超过 200ms,属于 frames-answer-in-200ms。指出时间花在输入延迟、处理还是呈现上。
4. 找出原因
查看每个长帧中的脚本及其强制布局耗时,然后检查这些脚本指向的代码。
在大型子树上为布局属性制作动画,会导致每一帧都重新布局。对整页面板使用 top 或 width 动画,属于 frames-compositor-properties。改用 transform 和 opacity。
写入样式后读取布局,会迫使浏览器在帧中途重新布局。在设置 style.height 的循环中读取 offsetHeight,属于 frames-no-forced-layout。先读取所有值,再写入。
每帧都更新状态,会导致每帧都重新渲染组件树。在 requestAnimationFrame 循环或滚动处理程序中调用 setState,属于 frames-animate-outside-render。通过 motion value、CSS 变量或 ref 驱动该值。
每帧都重绘大型区域,成本可能高于动效带来的价值。对移动的全屏图层使用 backdrop-filter,属于 frames-small-paint。缩小重绘区域,或淡入淡出静态副本。
5. 追踪修复效果
使用相同的步骤和限速设置再次录制。并排报告两次录制结果。“现在应该更快了”属于 frames-before-and-after。完成后,清除 CPU 限速。
成对对照
每项检查都要成对对照:出错的代码行旁边要列出替代它的代码行。
| 规则 | 错误做法 | 替代做法 |
|---|---|---|
frames-throttle-the-cpu | 在未限速的笔记本上追踪 | 在 4× CPU 限速下追踪 |
frames-trace-not-feel | “抽屉感觉很流畅” | “打开抽屉:0 帧丢失,最差间隔为 17ms,限速 4×” |
frames-hold-the-budget | 抽屉打开时丢失 14 帧 | 丢帧 0 次,没有动画帧超过 50ms |
frames-answer-in-200ms | 按键后 340ms 才绘制,其中 280ms 用于处理 | 90ms,并将筛选操作移出按键处理 |
frames-compositor-properties | 对整页侧边栏使用 animate={{ width: 320 }} | 固定宽度,使用 animate={{ x: 0 }} |
frames-no-forced-layout | 在遍历行的循环中执行 el.style.height = el.scrollHeight + "px" | 先读取所有高度,再统一写入 |
frames-animate-outside-render | 每帧调用一次 setProgress(p) | 在 motion value 上调用 progress.set(p) |
frames-small-paint | 对移动的全屏图层使用 backdrop-filter: blur(20px) | 在静态背景上应用模糊效果,让面板在其上方移动 |
frames-before-and-after | “现在应该更快了” | 修复前丢失 14 帧,修复后丢帧 0 次;限速 4×,步骤相同 |
报告
严重性。 在限速条件下,交互耗时超过 200ms,或未提供录制记录却报告页面流畅,属于 HIGH。动画期间出现丢帧、大型子树上有动画布局属性、强制布局或每帧更新一次状态,属于 MEDIUM。未启用限速进行的跟踪也属于此类。大范围重绘但仍在预算范围内,或报告修复却未进行第二次录制,属于 LOW。
格式。 每个根本原因列出一条发现,并附上测量数值:
1. file:line - [rule-id] what is wrong (dropped, worst gap, duration)
然后提供 Rule | Count | Severity 汇总。只要仍有任何 HIGH,就标记为 Block;否则标记为 Approve。对于不支持长动画帧的浏览器,脚本归因标记为 Not verified。