
HyperFrames 中的 Anime.js v4 适配器编写可寻帧、确定性的动画合成【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes导读HyperFrames 是一套写 HTML、渲染视频、为 Agent 而生的开源框架它的核心模型是合成Composition拥有动画对象HyperFrames 拥有时钟clock。本文以skills/hyperframes-animation/adapters/animejs.md为主干结合packages/core/src/runtime/adapters/animejs.ts适配器源码、单元测试animejs.test.ts与 producer 端真实 fixturepackages/producer/tests/animejs-adapter/src/index.html完整讲解在 HyperFrames 合成中接入 Anime.js v4 的契约、加载方式、基础/时间线/模块三种写法、确定性保证、适用场景与雷区并给出 lint/validate 验证流程。读完你可以在 HyperFrames 中写出不会悄悄什么都不动的 Anime.js 动画。先决条件理解 HyperFrames 的运行时适配器机制HyperFrames 在初始化合成时init.ts会按固定顺序注册一组确定性适配器Anime.js 适配器位列其中state.deterministicAdapters [ createWaapiAdapter(), createCssAdapter({ ... }), createAnimeJsAdapter(), createLottieAdapter(), createThreeAdapter(), createMapboxAdapter(), // ... 以及 GSAP 等 ] as RuntimeDeterministicAdapter[];每个适配器实现 RuntimeDeterministicAdapter 接口核心是四个方法discover()探测并收集需要驱动的动画实例seek(ctx)把实例寻帧到指定时间ctx.time单位是秒pause()/play()暂停与恢复所有实例可选revert()回滚Anime.js 适配器刻意实现为空操作见下文。这就是合成拥有动画对象HyperFrames 拥有时钟这句话的落地形式时钟的每一次seek包括逐帧渲染时的onDeterministicSeek回调见 init.ts都会遍历全部适配器把同一时间点喂给每个已注册的实例。Anime.js 适配器的 seek 语义看 animejs.ts 的seek实现seek: (ctx) { const timeMs Math.max(0, (Number(ctx.time) || 0) * 1000); const instances (window as AnimeWindow).__hfAnime; if (!instances || instances.length 0) return; for (const instance of instances) { try { if (typeof instance.seek function) { instance.seek(timeMs); } } catch (err) { swallow(runtime.adapters.animejs.site2, err); } } },三个关键点单位换算HyperFrames 时间以秒为单位ctx.timeAnime.js 的seek()以毫秒为单位适配器统一乘以 1000 换算负值钳制为 0鸭子类型驱动适配器只要求实例暴露seek(timeMs)、pause()、play()三个方法不管它是由谁创建的——所以 UMD 全局、ESM import、甚至是你在合成里手工包了一层{ seek, pause, play }的代理对象都行producer 的分布式 fixture 就是这么干的见下文容错单个实例抛错不会影响其他实例继续 seek对应测试 animejs.test.ts 的 continues seeking remaining instances if one throws。单元测试还验证了秒到毫秒的精确换算time: 2→seek(2000)time: 0.5→seek(500)、负时间钳制、多实例同步 seek、空注册表不抛错等行为animejs.test.ts。v4 契约四条铁律使用 Anime.js 前必须先接受适配器的四条硬性契约同步创建在合成初始化期间同步创建动画或时间线不能放在定时器、Promise、事件处理器里也不能等异步资源加载完再建autoplay: false必须关闭 Anime.js 自己的时钟否则它会用自己的时间轴推进与 HyperFrames 的 seek 打架显式注册把每个返回的动画/时间线 push 到window.__hfAnime。v4 上没有可用的自动发现机制详见避坑一节有限时长与有限循环使用有限的 duration 和 loop 次数禁止无限循环。适配器会对每个已注册实例调用instance.seek(timeMs)ctx.time秒 × 1000同时调用pause()和play()。只要对象暴露这三个方法无论其来源都能被驱动。加载 v4全局是命名空间对象不是函数Anime.js v4 与 v3 是硬性断裂hard break。文档目标版本为v4示例锁定 4.5.0MIT 协议。v4 不再有可调用的anime()easing:改名ease:缓动名称去掉了ease前缀。凭记忆写 v3 语法产出的合成要么直接抛错要么静默地什么都不动。UMD 加载方式!-- UMD全局 anime 是命名空间对象NAMESPACE OBJECT不是函数 -- script srchttps://cdn.jsdelivr.net/npm/animejs4.5.0/dist/bundles/anime.umd.min.js/script加载后可用 API 为anime.animate(...)、anime.createTimeline(...)、anime.utils.*、anime.svg.*、anime.stagger(...)。调用anime(...)会直接抛 TypeError—— 无论加载哪个 v4 构建文件UMD 还是 IIFE全局变量都是命名空间对象v3 的anime({ targets })形式在 v4 下任何文件都无法工作。版本与路径的坑文档与源码双重印证本仓库的 producer fixture 锁定的是animejs4.0.2/lib/anime.iife.min.js见 animejs-adapter fixture 与 anime-boundary fixture该版本仍可解析但早于splitText/scrambleText/createSeededRandom/createLayout这些新 API而且 4.1 把构建产物移到了dist/bundles/所以升版本时路径也要跟着改。适配器源码的注释也明确提示了这一点animejs.ts。基础模式animate 显式注册script const anim anime.animate(.mark, { x: 280, // v4 中 translateX 的简写 rotate: 1turn, opacity: [0, 1], duration: 1200, ease: outExpo, // 注意不是 easing: easeOutExpo autoplay: false, }); window.__hfAnime window.__hfAnime || []; window.__hfAnime.push(anim); /script要点x/rotate是 v4 的变换简写opacity: [0, 1]表示从 0 到 1 的补间ease: outExpo—— v4 缓动名不带ease前缀参数也从easing改成了ease记得autoplay: false并且把返回值push进window.__hfAnime。时间线模式createTimelinev4 用anime.createTimeline(...)取代 v3 的anime.timeline且add()的签名是add(targets, parameters, position)——目标选择器作为第一个参数script const tl anime.createTimeline({ autoplay: false, defaults: { ease: outCubic }, // 时间线级默认参数不能写成裸的 easing }); tl.add(.title, { y: [40, 0], opacity: [0, 1], duration: 650 }); tl.add(.accent, { scaleX: [0, 1], duration: 450 }, 250); // 250 时间位置 window.__hfAnime window.__hfAnime || []; window.__hfAnime.push(tl); /scriptposition参数支持多种形式数字、标签label、相对位移250/-100、上一个动画的结束点以及上一个动画的开始点。仓库实测真实 fixture 中的 createTimeline 用法producer 的animejs-adapter测试合成是一个很好的实战参照index.htmlconst tl1 anime.createTimeline({ autoplay: false }); tl1 .add(#label, { opacity: [0, 1], translateY: [-30, 0], duration: 400, ease: out(4) }, 200) .add(#box-a, { opacity: [0, 1], scale: [0, 1], rotate: [-90, 0], duration: 500, ease: out(5) }, 500) .add(#box-b, { opacity: [0, 1], scale: [0, 1], rotate: [90, 0], duration: 500, ease: out(5) }, 700) .add(#box-c, { opacity: [0, 1], scale: [0, 1], translateY: [80, 0], duration: 500, ease: out(3) }, 900);这段代码展示了三个实战技巧链式 addcreateTimeline().add(...).add(...)依次编排多个入场数值型 position200、500、700、900分别是各片段在时间线上的起始毫秒位置构成标题先入、三个盒子依次跟进的节奏ease: out(4)这类带参数的缓动函数在 v4 中同样可用。同文件里的第二、第三条时间线还演示了 stagger 与长时长补间tl3中delay: anime.stagger(30, { grid: [8, 6], from: center })在 48 个点阵上做中心扩散的波动效果。需要注意的是该 fixture 用的是4.0.2的 IIFE 构建与文档推荐4.5.0的dist/bundles/路径不同二者 API 兼容但加载路径不一致。一个值得注意的 fixture 细节手动包装 seek 代理animejs-adapterfixture 并没有直接把三个时间线逐个 push 进__hfAnime而是推入了一个手动实现的代理对象window.__hfAnime [{ seek: function(globalTimeMs) { const t globalTimeMs / 1000; for (const s of scenes) { if (t s.start t s.end) { s.tl.seek((t - s.start) * 1000); } else if (t s.end) { s.tl.seek((s.end - s.start) * 1000); } else { s.tl.seek(0); } } }, pause: function() { for (const s of scenes) s.tl.pause(); }, play: function() { for (const s of scenes) s.tl.play(); }, }];这是对适配器鸭子类型契约的最直接印证适配器只认seek / pause / play三个方法。开发者可以用它实现分场景scene-based时间映射——把全局时间换算成各时间线的局部时间(t - s.start) * 1000实现0–3 秒跑 tl1、2–5 秒跑 tl2、3–6 秒跑 tl3这种重叠编排。分块chunk渲染场景下的anime-boundaryfixture 也用了同样的手法index.html只是更简单直接tl.seek(globalTimeMs)透传。模块ESM构建适配器不在乎实例是怎么创建的——只要求它暴露seek()、pause()、play()。因此也可以用 ESM 方式加载script typemodule import { animate } from https://cdn.jsdelivr.net/npm/animejs4.5.0/esm; const anim animate(.chip, { x: 18rem, duration: 900, autoplay: false }); window.__hfAnime window.__hfAnime || []; window.__hfAnime.push(anim); /script注册逻辑与 UMD 完全一致。确定性用 createSeededRandom 代替 Math.randomHyperFrames 的渲染要求同一帧每次渲染都相同参考hyperframes-core的非协商规则禁Math.random/Date.now/performance.now。v4 提供了createSeededRandom(seed)const rnd anime.createSeededRandom(1337); anime.animate(.dot, { y: () -40 * rnd(), duration: 800, autoplay: false });要点createSeededRandom是 v4 的新 API4.0.2 旧构建里还没有anime.utils.random()/randomPick()/shuffle()不是种子化的——它们会破坏帧间可复现性禁止在合成中使用函数值如y: () -40 * rnd()在每次动画求值时调用配合种子随机数散点/抖动效果才能逐帧稳定。适配器源码解剖discover / seek / pause / play / revert把 animejs.ts 完整拆开看适配器一共五个方法方法行为对应测试discover()检查window.anime.running是否存在v4 无此导出直接空转返回自动发现、去重、无全局、空数组animejs.test.tsseek(ctx)对__hfAnime中每个实例调用seek(timeMs)秒×1000、负值钳 0、逐实例容错毫秒换算、小数秒、负时间、多实例、单实例抛错不阻断L66-L120pause()对所有实例调用pause()逐实例容错L122-L137play()对所有实例调用play()L139-L147revert()空实现——不清空__hfAnime因为实例归合成所有L149-L154discover()的实现确认了v4 自动发现不可用的结论discover: () { try { const animeGlobal (window as AnimeWindow).anime; if (!animeGlobal || typeof animeGlobal.running undefined) return; // ... v3 时代的 running 数组扫描逻辑v4 永远走不到 } catch (err) { swallow(runtime.adapters.animejs.site1, err); } },running不在 v4.5.0 的导出列表里文档注明已对发布的 bundle 核实所以discover()遇到 v4 构建会立刻返回空任何没被你 push 的实例永远不会被 seek。显式注册不是可选项而是必须项。类型定义里也把running标注为 Legacy v3 registry retained for backward-compatible discoveryanimejs.ts。适用场景Good Uses与避坑Avoid推荐使用小而精的 SVG / DOM 点缀动画Anime.js 语法紧凑适合轻量 tween定位免费的splitText/scrambleTextMotion 把这些功能放在 Motion 付费档GSAP SplitText 是另一个免费选择svg.createDrawable/svg.morphTo/svg.createMotionPath描线绘制line-draw与路径动画多个相互独立的微动画推入同一个注册表一次 seek 全部同步。需要复杂场景编排时除非用户明确要求 Anime.js否则用 GSAP——GSAP 仍是 HyperFrames 的主创作路径对应 SKILL.md 的运行时选择表GSAP 覆盖 95% 的动效工作。必须避免的坑让autoplay保持默认值——Anime.js 默认自带时钟推进与 HyperFrames 的 seek 冲突依赖anime.running自动发现——v4 没有这个导出discover()直接空转不 push 就不被驱动autoplay: onScroll(...)——无头 seek 渲染里没有滚动动画永远不会推进必须改用合成时间驱动用waapi.animate()创建需要被 seek 的实例——适配器通过.seek()驱动WAAPI 后端实例是否尊重.seek()未经验证渲染用 JS 引擎animatewaapi是面向实时页面的非主线程优化路径createDraggable与任何指针驱动的createAnimatable循环——渲染时刻不存在输入事件无限循环——必须根据合成时长计算有限循环次数注意 v4 的loop计数的是重复次数loop: 1实际播放两遍在定时器、Promise、事件处理器或异步资源加载之后创建动画——违反同步初始化契约时序不确定。验证lint 与 validate编辑完使用 Anime.js 的合成后在项目目录执行npx hyperframes lint npx hyperframes validatelint用于校验合成中的常见错误CLI 描述见 lint.ts支持--json、--verbose也可指定目录如npx hyperframes lint ./my-videovalidate会在 headless Chrome 中加载合成并报告 console 错误含 WCAG 对比度审计默认开启支持--json、--timeout ms注意该命令已被标记为弃用deprecation notice建议优先使用lint及其后续替代命令validate.ts。总结在 HyperFrames 里用 Anime.js 的正确姿势可以浓缩为一条检查清单加载 v4 构建推荐 4.5.0 的dist/bundles/勿用 v3 语法同步创建autoplay: false每个实例都window.__hfAnime.push(...)有限 duration / 有限 loop随机数一律走createSeededRandom最后跑npx hyperframes lintvalidate兜底记住适配器契约实例只需暴露seek/pause/play。把握住合成拥有动画对象、HyperFrames 拥有时钟这一分工你就能在 HyperFrames 中写出既流畅又逐帧可复现的 Anime.js 动效。延伸阅读适配器源码packages/core/src/runtime/adapters/animejs.ts适配器单元测试packages/core/src/runtime/adapters/animejs.test.ts适配器注册点packages/core/src/runtime/init.ts生产端实测合成packages/producer/tests/animejs-adapter/src/index.html分块边界合成packages/producer/tests/distributed/anime-boundary/src/index.html动画技能总览与运行时选择skills/hyperframes-animation/SKILL.md运行时适配器接口定义packages/core/src/runtime/types.ts【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考