HyperFrames Lottie 运行时适配器:在 HTML 合成中确定性渲染 lottie-web 与 dotLottie 动画
【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
HyperFrames 通过内置的lottie运行时适配器,支持对lottie-web与@lottiefiles/dotlottie-web两类播放器进行确定性时间寻址(seek),让 After Effects 导出的动画资产能在 HTML 合成中按帧渲染。本文基于 skills/hyperframes-animation/adapters/lottie.md 展开,结合 packages/core/src/runtime/adapters/lottie.ts 的源码实现与其测试用例,讲解注册契约、两种播放器的接入模式、多动画同步、时长自动推断与验证流程。读完本文,你将掌握在 HyperFrames 合成中正确接入 Lottie 资产、避免渲染期坑点并让导出结果确定性的完整方法。
为什么 Lottie 需要专属适配器
Lottie 动画(.json或.lottie)与 GSAP 等代码驱动的动画不同:它的时间线已经以帧率 + 总帧数的形式编码在资产本身。HyperFrames 的运行时并不需要"创建"这个时间线,它只需要拿到一个可被寻址的播放器对象,然后在渲染时把它拨到指定的时间点即可——这正是lottie适配器的职责。
从 skills/hyperframes-animation/SKILL.md 的运行时选型表可以看到,HyperFrames 共有七个运行时适配器(GSAP 为默认,另有 Lottie、Three.js、Anime.js、CSS keyframes、Web Animations API、TypeGPU),而选型原则是:当资产自带预制时间线(典型如 After Effects 导出)时,选择 Lottie。多个运行时可以在同一合成中共存,各自把实例注册到运行时专属的全局变量上,由 HyperFrames 一次性全部寻址。
接入契约(Contract)
任何 Lottie 合成都必须遵守 lottie.md 中定义的接入契约,共五条:
- 从本地项目文件加载资产,通常放在
assets/目录下; - 设置
autoplay: false——播放必须完全由运行时接管; - 优先
loop: false,除非用户明确要求循环; - 把每个返回的动画或播放器注册到
window.__hfLottie; - 用 CSS 保持 Lottie 容器尺寸稳定。
契约背后的原因可以从源码解释:适配器的seek遍历的正是window.__hfLottie数组(见 lottie.ts),未注册的实例不会被寻址;而autoplay/loop若为true,播放器会在页面加载后自行推进时间线,破坏确定性。全局注册点的类型声明位于 packages/core/src/runtime/window.d.ts,注释中同样写明:"Push your animation instance here after callinglottie.loadAnimation()"。
lottie-web 模式:经典 bodymovin 播放器
lottie-web(bodymovin)是最常见的 Lottie 运行时。接入方式如下:
<div id="logo-lottie" class="lottie-layer"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.12.2/lottie.min.js"></script> <script> const anim = lottie.loadAnimation({ container: document.getElementById("logo-lottie"), renderer: "svg", loop: false, autoplay: false, path: "assets/logo-reveal.json", }); window.__hfLottie = window.__hfLottie || []; window.__hfLottie.push(anim); </script>.lottie-layer { width: 100%; height: 100%; }要点说明:
renderer: "svg"是 HyperFrames 合成中最常用的渲染器,矢量保真且 DOM 可被截图;path指向本地assets/下的 JSON 文件,不要指向远程 URL(原因见下文"避免事项");- 返回的
anim对象(lottie-web 的AnimationItem)必须push进window.__hfLottie; - 容器必须显式设置宽高(通常为
100%),否则动画尺寸不稳定会影响合成布局。
从源码看,适配器对lottie-web的寻址方式是anim.goToAndStop(time * 1000, false):第一个参数为毫秒,第二个参数false表示按时间而非帧号寻址,以保证精度(见 lottie.ts)。时间会先经过Math.max(0, Number(ctx.time) || 0)归一化,负时间被钳制为 0。暂停时调用anim.pause()。
dotLottie 模式:canvas 播放器
@lottiefiles/dotlottie-web是面向.lottie文件格式的 canvas 播放器,接入方式如下:
<canvas id="product-lottie" class="lottie-canvas"></canvas> <script src="https://unpkg.com/@lottiefiles/dotlottie-web"></script> <script> const player = new DotLottie({ canvas: document.getElementById("product-lottie"), src: "assets/product-flow.lottie", autoplay: false, loop: false, }); window.__hfLottie = window.__hfLottie || []; window.__hfLottie.push(player); </script>.lottie-canvas { width: 100%; height: 100%; display: block; }dotLottie 播放器没有goToAndStop这样的统一寻址 API,因此适配器按播放器形态分派(见 lottie.ts):
- dotLottie-web v2+:调用
setCurrentRawFrameValue(frame)直接设置原始帧号,帧号由time * frameRate计算,并钳制到totalFrames - 1以内(避免超出末帧); - dotLottie-web v1:调用
seek(percentage),百分比由(time / duration) * 100计算并钳制到 100;当duration尚未就绪(为 0 或非有限值)时跳过寻址,等 duration 可用后下一个渲染周期自然生效。
测试 lottie.test.ts 对上述行为有完整覆盖,例如:seek({ time: 2 })对 lottie-web 断言调用goToAndStop(2000, false);对 v2 播放器断言setCurrentRawFrameValue(30)(time=1、fps=30);当frame = 300超过totalFrames = 60时断言钳制为59;对 v1 播放器断言duration = 2时seek依次收到[50], [0], [100]的百分比调用序列。
多动画同步:一个注册表,同一时间点
一个合成里可以同时出现多个 Lottie 动画(背景、图标、装饰粒子等),只需把每个实例都 push 进同一个window.__hfLottie数组:
window.__hfLottie = window.__hfLottie || []; window.__hfLottie.push(backgroundAnim); window.__hfLottie.push(iconAnim); window.__hfLottie.push(confettiAnim);适配器的seek会遍历整个注册表并把所有实例拨到同一个合成时间点(见 lottie.ts)。单实例的寻址失败会被swallow捕获并跳过,不会阻断其余实例——源码注释明确这是"keep going for other instances"的容错设计。
另外,适配器还提供**自动发现(auto-discovery)**能力:即使合成代码没有手动 push,只要页面上存在全局lottie对象(即加载了 lottie.min.js),适配器的discover()就会调用lottie.getRegisteredAnimations()读取所有已注册动画,并去重合并进window.__hfLottie(见 lottie.ts)。不过契约仍然推荐显式注册——自动发现只是兜底,显式注册不依赖库内部 API 的稳定性。
组合时长:data-duration为什么可以省略
GSAP 合成的时间线对象会自动上报总时长;而纯 Lottie 合成没有时间线对象,渲染引擎必须知道合成总长度才能正确推进。适配器通过getInferredDurationSeconds()从注册实例直接读取原生时长(见 lottie.ts):
- lottie-web:
totalFrames / frameRate(如 90 帧 @ 30fps → 3 秒); - dotLottie:优先使用播放器自身的
duration字段,缺失时回退到totalFrames / frameRate; - 多实例:取所有实例推断值的最大值(
Math.max),因为合成长度必须容纳最长的动画; - 未加载完成:若
totalFrames仍为 0(资产尚未加载完),返回null而非 0,避免把"仍在加载"误判为"真实时长为 0"。
运行时在 init.ts 的resolveAdapterDurationFloorSeconds()中汇总所有适配器的推断时长,再与媒体时长下限、data-duration组合取最大值作为安全时长(见 init.ts)。因此,只要每个动画都按契约注册到了window.__hfLottie,即使不写data-duration、甚至设置loop: true,运行时也能拿到有限时长来完成渲染——这正是原文档"data-duration对 Lottie 合成是可选的"这句话的底层依据。
适用场景(Good Uses)
- After Effects 导出且已在 lottie-web 中确认渲染正确的资产;
- Logo 揭示、图标循环、装饰点缀、产品 UI 动效;
- 把 Remotion 中的 Lottie 用法迁移为纯 HyperFrames HTML。
避免事项(Avoid)
原文档明确列出四类渲染期风险,务必规避:
- 渲染时依赖远程
pathURL——远程资源在渲染环境不可达会导致合成失败,资产必须随项目本地化; - 用
play()启动播放——播放行为会破坏确定性,一切由运行时 seek 接管; - 假设不受支持的 After Effects 效果能原样导出——先在本机浏览器中打开 JSON 或
.lottie文件实测确认; - 异步加载播放器并在 HyperFrames 校验完页面之后才注册——注册太晚会错过适配器的发现与验证时机,动画永远不会被寻址。
验证:lint 与 check
编辑完 Lottie 合成后,在项目根目录运行官方校验命令:
npx hyperframes lint npx hyperframes checklint用于静态检查合成结构(资产路径、注册模式等),check则进一步验证合成在渲染前的关键约束是否满足。两条命令的组合是提交或导出前的标准自检流程。
源码路径速查
- 适配器核心实现:packages/core/src/runtime/adapters/lottie.ts(
createLottieAdapter,含discover/seek/pause/getInferredDurationSeconds) - 时长自动推断的运行时折叠机制:packages/core/src/runtime/init.ts(
resolveAdapterDurationFloorSeconds) - 全局注册点与 lottie 全局对象的类型声明:packages/core/src/runtime/window.d.ts
- 适配器行为测试:packages/core/src/runtime/adapters/lottie.test.ts(寻址、钳制、时长推断、自动发现去重均有断言)
- 适配器选型总览:skills/hyperframes-animation/SKILL.md
外部库参考:lottie-web(Airbnb 的 bodymovin 库)的loadAnimation选项,以及 LottieFiles 官方 dotLottie web 播放器方法文档,均可在各自官方文档站查阅,本文不再赘述。
【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考