本地引入 motion-anything 后动效卡顿或不动,排查顺序通常比调参数更重要。先把渲染容器尺寸、初始化发生时机、浏览器当前能达到的帧率上限确认清楚,再去看缓动、时长、粒子数量这类动效参数。下面这套步骤适合本地静态页面或开发服务器,用最小骨架逐层排除;每一步都以控制台日志、页面行为和性能面板记录为准,不依赖猜测。
本地动效异常时,建议先按“容器可见且尺寸非零、初始化确实执行、浏览器合成与主线程没有持续长任务”三层判断。容器为零尺寸或 display:none 时,引擎可能仍在跑但画不出来;初始化顺序错误时,播放可能被覆盖。帧率目标要结合屏幕刷新率和设备性能实测,不能把某个固定 FPS 当合格线。先确认环境,再改动效参数,能减少把环境问题误判成参数问题。
在本地页面挂上 motion-anything 的最小动效骨架
目标不是做完整效果,而是确认 motion-anything 能在本地加载、初始化,并驱动一个可见变化。建议用本地静态服务器打开页面,避免 file:// 对 ES module 或包解析的限制。不同版本导出的初始化函数名可能不同,下面用 createMotion / mount / init 做候选检测,实际参数名需要按你安装的包替换。
<div id='motion-stage' style='width: 480px; height: 270px; position: relative;'></div>
<script type='module'>
import * as MotionAnything from 'motion-anything';
const stage = document.querySelector('#motion-stage');
const init = MotionAnything.createMotion
|| MotionAnything.mount
|| MotionAnything.init;
if (typeof init !== 'function') {
console.error('[motion] 没有找到初始化导出,检查包版本', Object.keys(MotionAnything));
} else {
const player = init({
container: stage, // 按实际参数名替换
autoplay: true, // 按实际参数名替换
width: stage.clientWidth,
height: stage.clientHeight,
pixelRatio: window.devicePixelRatio
});
window.__motionPlayer = player;
console.log('[motion] initialized', {
hasPlayer: !!player,
stageRect: stage.getBoundingClientRect(),
dpr: window.devicePixelRatio
});
}
</script>
替换项主要是包名、初始化导出名、参数名和容器选择器。初始化后看控制台:如果出现 initialized 日志,且 window.__motionPlayer 不是 undefined,说明调用链已经执行。再看容器里是否出现 canvas、svg 或子节点,页面上是否出现可见变化。只有日志没有画面,继续查容器尺寸;连日志都没有,先查模块是否加载成功和初始化条件是否被跳过。
量出容器宽高与像素比,排除零尺寸渲染
“动效没跑”和“跑了但画在零尺寸区域”表现不同。前者通常没有实例日志或没有子节点,后者可能有实例、有 canvas,但容器宽高为 0,页面上什么也看不到。建议在初始化前后都打印一次容器与 canvas 的尺寸,窗口尺寸变化后再打印一次。
const stage = document.querySelector('#motion-stage');
function logStage(tag) {
const rect = stage.getBoundingClientRect();
const canvas = stage.querySelector('canvas');
console.log(tag, {
client: [stage.clientWidth, stage.clientHeight],
rect: [rect.width, rect.height],
dpr: window.devicePixelRatio,
canvasAttr: canvas ? [canvas.width, canvas.height] : null,
canvasCss: canvas ? [canvas.clientWidth, canvas.clientHeight] : null
});
}
logStage('before-init');
window.addEventListener('resize', () => logStage('window-resize'));
new ResizeObserver(() => logStage('container-resize')).observe(stage);
改窗口尺寸后重新触发的验证步骤:拖动窗口宽度,或打开开发者工具的设备工具栏切换尺寸,观察控制台日志里 client 和 rect 是否跟着变;如果 canvas 的 width/height 属性没有跟着调整,检查是否需要调用播放器实例的 resize 方法,或在尺寸变化后重新初始化。零尺寸时常见表现是:容器高度为 0、display:none、父级 flex 未给高度、绝对定位元素没有撑开内容;页面上看不到动效,但日志显示实例存在。设备像素比方面,先读取 window.devicePixelRatio,再查看 canvas 后备宽高是否已经由库处理。不要在不了解库行为时自己重复乘 DPR,否则可能得到过大的绘制缓冲区,反而增加填充压力。
用浏览器性能面板记录帧率与长任务
需要判断卡顿来自渲染压力还是主线程逻辑。建议用 Chromium 系浏览器的性能面板录一段动效播放:打开开发者工具,切到 Performance,点击录制,让动效完整播放 3~5 秒,停止录制。录制时尽量关掉无关扩展和后台标签页,并记录是否插着外接显示器或开了省电模式,这些因素会影响帧率表现。
重点观察这些指标名称:Frames 轨道看帧率和掉帧;Main 轨道看长任务和脚本执行时间;Compositing Layers 或 Layers 面板看合成层变化;必要时打开 Rendering 里的 Layer borders、Paint flashing 辅助判断重绘区域。若 Main 轨道上出现与动画回调、业务计算同段的长任务,优先查 JS 逻辑;若 Main 相对空闲但 Frames 仍不稳、合成层频繁变化,再查绘制、布局和合成压力。
阈值必须自行测量,不要套用固定数值。先录一个静态页面的基线,再录同一容器里的动效,对比两次的帧间隔和长任务分布,结论才和你的机器、屏幕刷新率、浏览器版本相关。屏幕是 60Hz、90Hz 还是 120Hz,会直接影响“正常”帧率的上限判断。
一次只改一项:动效参数与渲染环境对照
参数问题和环境问题要拆开。每次只改一个变量,其他条件保持不变:同一浏览器窗口尺寸、同一 devicePixelRatio、同一电源模式、同一段播放时长。改完后硬刷新页面,重新录一次性能面板,并把观察结果填进表里。表格里的“结论”先写推断,再说明下一项要验证什么。
| 改动项 | 观察项 | 结论 |
|---|---|---|
| 容器高度从 auto 改为固定像素 | 初始化日志中的 rect 高度、canvas 属性宽高、页面是否出现画面 | 待记录 |
| 初始化顺序:先等 DOM 再初始化,或提前初始化 | 控制台是否出现 initialized、window.__motionPlayer 是否存在 | 待记录 |
| 动画持续时间或粒子数量减半 | Main 轨道长任务数量、Frames 掉帧位置 | 待记录 |
| devicePixelRatio 在设备模拟中改为 1 或 2 | canvas 后备宽高、绘制耗时、帧率变化 | 待记录 |
保证单一变量的做法:把环境信息写在纸上或 notes 文件里,每次只动一项;不要同时换浏览器、改容器尺寸、又调动画参数。若某一项改完结论不明显,先恢复原值,再改下一项。需要结合环境确认的结论,不要直接当成通用规律。
整理一份可复现的最小用例
排查结果要能自己复跑,也方便别人复现。最小用例的文件组织可以很简单:index.html 只保留一个容器和模块入口;src/main.js 放初始化、尺寸日志和播放触发;src/env.js 打印环境快照;package.json 或 importmap 锁定 motion-anything 的版本;notes.md 记录操作步骤、改动项和观察结果。不要塞入业务代码、路由和无关样式。
min-motion-case/
index.html
src/
main.js
env.js
package.json
notes.md
需要一并记录的环境信息包括:浏览器名称与版本、操作系统、屏幕刷新率、窗口尺寸、容器 client 与 rect 尺寸、window.devicePixelRatio、motion-anything 版本、是否开启省电或节能模式、是否外接显示器、录制性能时开发者工具是否打开。屏幕刷新率可以从系统显示设置读取,也可以用 requestAnimationFrame 在一段时间内估算,但估算时不要同时播放动效。把这些信息和最小用例放在一起,别人复跑时才有判断依据。
最后提醒一个边界:本地能跑不等于部署到其他环境也一致。容器尺寸、DPR、浏览器合成策略和电源模式都会变,所以这份用例用于定位“容器、初始化、帧率”三类问题,参数调优仍要在目标设备上重新确认。