HyperFrames WAAPI与Anime.js适配完全指南:Seek帧的5个要点
【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
HyperFrames(HyperFrames)是一个"写 HTML、渲染视频"的开源项目,口号是Write HTML. Render video. Built for agents.。它的渲染引擎从不"播放"动画,而是逐帧seek(跳转)到指定时间点截图——因此,动画库能否被精确 seek,决定了你的 HTML 能否被确定性渲染成视频。
WAAPI(Web Animations API)和 Anime.js 正是两个相对小众但完全受支持的运行时。本文面向新手,用 5 个 Seek 要点讲透这两种 HyperFrames 动画适配的用法、常见坑位和选型建议,帮你在不依赖 GSAP 的情况下也能稳定产出可渲染的合成。
先理解原理:为什么"能 Seek"这么重要
HyperFrames 采用帧适配器(Frame Adapter)模式:渲染器不问"播放到哪了",而是反复问"第 N 帧画面长什么样"。官方概念文档 frame-adapters.mdx 描述了这条契约:
- 渲染器请求一帧 → 适配器把时间线跳到该时刻并稳定下来 → 捕获像素 → 下一帧;
- 支持前向、后向、任意顺序的 seek;
- 同一帧重复请求必须得到完全相同的状态(确定性渲染)。
对 GSAP 这是默认能力;而 WAAPI 和 Anime.js 需要通过各自的运行时适配器"接上时钟":
| 适配器 | 源码位置 | Seek 机制 |
|---|---|---|
| WAAPI | waapi.ts | 读取所有动画 → 写currentTime(毫秒)→pause() |
| Anime.js | animejs.ts | 对注册的每个实例调用instance.seek(timeMs) |
WAAPI 适配要点:让 element.animate() 可被逐帧定位
WAAPI 适合"CSS keyframes 太死板、又不想引入 GSAP"的轻量 DOM 动画。官方技能文档见 waapi.md。
要点 1:同步创建 + 有限时长 +fill: "both"
动画必须在合成初始化时同步创建,duration与iterations必须有界。fill: "both"保证 seek 到的状态会持续保持,不会闪回初始样式:
const animation = orb.animate( [ { transform: "translate3d(-160px, 0, 0)", opacity: 0 }, { transform: "translate3d(0, 0, 0)", opacity: 1, offset: 0.35 }, { transform: "translate3d(120px, 0, 0)", opacity: 1 }, ], { duration: 3000, delay: 2000, fill: "both", iterations: 1 }, ); animation.pause(); // 创建后立即暂停,交给 HyperFrames 时钟要点 2:适配器如何 seek——读document.getAnimations(),写currentTime
源码 waapi.ts 中,适配器会对每个跟踪到的动画执行animation.currentTime = 合成时间(毫秒)然后pause()。它还通过给Element.prototype.animate装钩子来追踪你之后创建的新动画——所以即使动画是延迟创建也能被发现,但渲染关键状态不要依赖回调和 Promise(如animation.finished),seek 渲染中它们不可靠。
要点 3:总时长会自动推断,但无限循环会打断它
WAAPI 合成没有 GSAP 那样的时间线对象来报告时长,运行时因此从每个动画的effect.getComputedTiming().endTime推断总时长(见 init.ts)。无限iterations没有有限的 endTime,无法自动推断——必须给根元素补data-duration="<秒>",否则npx hyperframes lint会报root_composition_missing_duration_source。
要点 4:clip 偏移用delay建模,别假设自动对齐
WAAPI 适配器 seek 的是文档级时间,不是某个 clip 的局部时间。想让动画在第 2 秒出场,就用delay: 2000显式表达偏移。
要点 5:避开"墙钟"陷阱
渲染时没有真实流逝的时间。避免requestAnimationFrame、setInterval、performance.now()这类独立时钟;能用transform和opacity表达的动效,就别动画化布局属性(layout 属性更贵且易抖动)。
Anime.js 适配要点:v4 必须显式注册,自动发现已失效
Anime.js 适配器文档在 animejs.md。它的分工很清晰:合成代码拥有动画对象,HyperFrames 拥有时钟——适配器对window.__hfAnime里每个实例调用seek(ctx.time × 1000)。
要点 1:autoplay: false,把播放权交出去
Anime.js 默认自己跑时钟,必须显式关掉,否则它会按墙钟前进,与渲染帧脱节:
const anim = anime.animate(".mark", { x: 280, rotate: "1turn", opacity: [0, 1], duration: 1200, ease: "outExpo", autoplay: false, }); window.__hfAnime = window.__hfAnime || []; window.__hfAnime.push(anim); // 显式注册,缺一不可要点 2:v4 全局anime是命名空间对象,不是函数
v4 对 v3 是硬断代:没有可调用的anime(),easing:改名为ease:,缓动名去掉了ease前缀。凭记忆写 v3 风格(anime({ targets }))会直接抛 TypeError,或"静默地什么都不动"——这是最常见的翻车点。
要点 3:显式注册是强制的,自动发现在 v4 上不工作
适配器保留了 v3 时代的anime.running自动发现逻辑,但v4 已不再导出running,发现永远返回空。凡是没push()到window.__hfAnime的实例,永远不会被 seek。
要点 4:随机性必须"播种"
需要散布/抖动的场景,用 v4 自带的anime.createSeededRandom(seed)代替Math.random(),保证每一遍渲染同一帧的画面完全一致;anime.utils.random()等工具是未播种的,会破坏帧级复现。
要点 5:时间线 API 换了签名
createTimeline()取代anime.timeline,add()的第一参数是目标元素:add(targets, parameters, position)。位置还能接受"+=250"、"<"这类相对写法。仓库自带一个完整可参考的测试合成 animejs-adapter/src/index.html,其中还演示了一个实用技巧:注册一个代理对象,按全局时间把 seek 映射到多条分场景时间线上。
两种运行时怎么选?一张表看懂
| 维度 | WAAPI | Anime.js v4 |
|---|---|---|
| 依赖 | 浏览器原生,零依赖 | 需引入 anime.js 脚本(固定版本) |
| 注册方式 | 自动发现(getAnimations+ animate 钩子) | 必须手动push到window.__hfAnime |
| 关键开关 | fill: "both"+pause() | autoplay: false+ 显式注册 |
| 时长来源 | 从endTime自动推断 | 由你自己/代理对象管理 |
| 随机性 | 避免Math.random() | 用createSeededRandom(seed) |
| 典型场景 | 数据驱动的轻量 DOM 动效 | 紧凑的 SVG/DOM 装饰、免费splitText |
💡 两者都是"小众补充"。GSAP 仍是 HyperFrames 的主力创作路径;除非有明确的存量 WAAPI 代码或想要 Anime.js 的紧凑语法/文本特效,否则默认让 GSAP 处理日常动效。
验证清单:改完后跑两条命令
编辑完任何使用这两种运行时的合成,用 CLI 检查:
npx hyperframes lint npx hyperframes checkAnime.js 合成则用npx hyperframes validate复核。lint 会抓住"根合成缺少时长来源"这类 WAAPI 高频问题。
延伸阅读
- 帧适配器契约与自定义适配器:frame-adapters.mdx
- 确定性渲染规则:determinism.mdx
- 运行时选型提示词指南:runtimes-and-3d.mdx
- WAAPI 适配器源码:waapi.ts
- Anime.js 适配器源码:animejs.ts
抓住"HyperFrames 拥有时钟,运行时只负责回答某一帧的状态"这一核心,WAAPI 的currentTime与 Anime.js 的seek(ms)就不再神秘——它们只是同一个 seek 契约在不同 API 上的落点。
【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考