lottie-animation

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Lottie Animation

Lottie动画

The bridge from After Effects to product: vector animation shipped as JSON (or zipped
.lottie
), tiny and resolution-independent, played by a runtime on web, iOS, Android, and React Native. This skill covers integrating, controlling, and exporting Lottie.
连接After Effects与产品的桥梁:以JSON(或压缩的.lottie格式)交付的矢量动画,体积小巧且与分辨率无关,可通过运行时在网页、iOS、Android和React Native上播放。本技能涵盖Lottie的集成、控制与导出。

When to use

适用场景

  • Ship a designer's AE animation to web/iOS/Android/React Native
  • Looping illustrations, onboarding, empty states, animated icons
  • Scroll-driven or interaction-driven vector playback (hover, click, cursor)
  • Runtime theming/recoloring instead of re-exporting per brand
  • 将设计师制作的AE动画交付至网页/iOS/Android/React Native
  • 循环插图、引导页、空状态、动画图标
  • 滚动驱动或交互驱动的矢量播放(悬停、点击、光标跟随)
  • 运行时主题化/重新着色,无需针对每个品牌重新导出

Formats: .json vs .lottie

格式对比:.json vs .lottie

  • .json
    — the raw Bodymovin output. Human-readable, larger.
  • .lottie
    — a zipped container (often 60–80% smaller) that can bundle multiple animations, images, and theming. Preferred for shipping. Player:
    @lottiefiles/dotlottie-web
    (modern, canvas + WASM) supersedes the older
    lottie-web
    .
Prefer the dotLottie runtime for new work; use
lottie-web
only for legacy
.json
+ SVG renderer needs.
  • .json
    — Bodymovin的原始输出,人类可读,体积较大。
  • .lottie
    — 压缩容器(通常比.json小60–80%),可捆绑多个动画、图片和主题配置。是交付时的首选格式。播放器:
    @lottiefiles/dotlottie-web
    (基于canvas + WASM的现代版本)已取代旧版
    lottie-web
新项目优先使用dotLottie运行时;仅在需要兼容旧版.json + SVG渲染器时使用
lottie-web

Core workflow (web, dotLottie)

核心工作流(网页端,dotLottie)

bash
npm i @lottiefiles/dotlottie-web        # vanilla
npm i @lottiefiles/dotlottie-react      # React wrapper
Vanilla:
js
import { DotLottie } from "@lottiefiles/dotlottie-web";

const dotLottie = new DotLottie({
  canvas: document.querySelector("#lottie"),  // a <canvas> element
  src: "/hero.lottie",                         // or .json
  loop: true,
  autoplay: true,
  // speed: 1, mode: "forward" | "reverse" | "bounce", renderConfig: { autoResize: true }
});
React:
jsx
import { DotLottieReact } from "@lottiefiles/dotlottie-react";

function Hero() {
  return <DotLottieReact src="/hero.lottie" loop autoplay style={{ width: 320 }} />;
}
Capture the instance to control it:
jsx
const [dl, setDl] = useState(null);
<DotLottieReact src="/icon.lottie" dotLottieRefCallback={setDl} />;
// dl?.play(); dl?.pause(); dl?.setSpeed(2);
bash
npm i @lottiefiles/dotlottie-web        # 原生JS
npm i @lottiefiles/dotlottie-react      # React封装
原生JS示例:
js
import { DotLottie } from "@lottiefiles/dotlottie-web";

const dotLottie = new DotLottie({
  canvas: document.querySelector("#lottie"),  // 一个<canvas>元素
  src: "/hero.lottie",                         // 也可使用.json格式
  loop: true,
  autoplay: true,
  // speed: 1, mode: "forward" | "reverse" | "bounce", renderConfig: { autoResize: true }
});
React示例:
jsx
import { DotLottieReact } from "@lottiefiles/dotlottie-react";

function Hero() {
  return <DotLottieReact src="/hero.lottie" loop autoplay style={{ width: 320 }} />;
}
捕获实例以进行控制:
jsx
const [dl, setDl] = useState(null);
<DotLottieReact src="/icon.lottie" dotLottieRefCallback={setDl} />;
// dl?.play(); dl?.pause(); dl?.setSpeed(2);

Playback control

播放控制

js
dotLottie.play();
dotLottie.pause();
dotLottie.stop();
dotLottie.setSpeed(1.5);
dotLottie.setMode("bounce");        // forward | reverse | bounce | reverse-bounce
dotLottie.setFrame(42);             // jump to a frame
dotLottie.setSegment(30, 90);       // constrain playback to a frame range (e.g. a "loading" loop)
Events drive sequencing and UI:
js
dotLottie.addEventListener("load", () => { /* totalFrames now available */ });
dotLottie.addEventListener("complete", () => { /* non-looping playback finished */ });
dotLottie.addEventListener("frame", ({ currentFrame }) => { /* per-frame */ });
State-machine style (e.g. button that plays "checked" segment then idles): play a segment, listen for
complete
, then
setSegment
to the idle loop.
js
dotLottie.play();
dotLottie.pause();
dotLottie.stop();
dotLottie.setSpeed(1.5);
dotLottie.setMode("bounce");        // forward | reverse | bounce | reverse-bounce
dotLottie.setFrame(42);             // 跳转到指定帧
dotLottie.setSegment(30, 90);       // 将播放限制在指定帧范围内(例如“加载”循环)
通过事件驱动序列与UI:
js
dotLottie.addEventListener("load", () => { /* 此时可获取totalFrames */ });
dotLottie.addEventListener("complete", () => { /* 非循环播放已结束 */ });
dotLottie.addEventListener("frame", ({ currentFrame }) => { /* 逐帧触发 */ });
状态机模式(例如:按钮播放“选中”片段后进入 idle 状态):播放指定片段,监听
complete
事件,然后调用
setSegment
切换到idle循环。

Scroll-driven Lottie (no GSAP needed)

滚动驱动的Lottie(无需GSAP)

Map scroll progress (0–1) to a frame. Pause autoplay and drive frames yourself.
js
const dotLottie = new DotLottie({ canvas, src: "/scroll.lottie", autoplay: false });
let total = 0;
dotLottie.addEventListener("load", () => { total = dotLottie.totalFrames; });

window.addEventListener("scroll", () => {
  const el = canvas.closest(".scrolly");
  const rect = el.getBoundingClientRect();
  const p = clamp(-rect.top / (rect.height - window.innerHeight), 0, 1); // 0..1 through the section
  dotLottie.setFrame(p * (total - 1));
}, { passive: true });

const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
For richer interaction (hover-to-play, click toggles, cursor-follow) without writing the wiring, use
@lottiefiles/lottie-interactivity
, which maps
scroll
,
hover
,
click
,
play
, and
cursor
modes to frame ranges declaratively.
将滚动进度(0–1)映射到帧。暂停自动播放,自行驱动帧更新。
js
const dotLottie = new DotLottie({ canvas, src: "/scroll.lottie", autoplay: false });
let total = 0;
dotLottie.addEventListener("load", () => { total = dotLottie.totalFrames; });

window.addEventListener("scroll", () => {
  const el = canvas.closest(".scrolly");
  const rect = el.getBoundingClientRect();
  const p = clamp(-rect.top / (rect.height - window.innerHeight), 0, 1); // 滚动过该区域时的0..1进度
  dotLottie.setFrame(p * (total - 1));
}, { passive: true });

const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
若无需编写底层逻辑即可实现更丰富的交互(悬停播放、点击切换、光标跟随),可使用
@lottiefiles/lottie-interactivity
,它能以声明式方式将
scroll
hover
click
play
cursor
模式映射到帧范围。

Runtime theming / recoloring

运行时主题化 / 重新着色

Two paths:
  • dotLottie themes: a
    .lottie
    can embed named color themes; switch with
    dotLottie.setTheme("dark")
    /
    loadTheme(...)
    . Authored in LottieFiles tooling — no re-export to recolor.
  • Manual color override: load the JSON, walk
    layers[].shapes[]
    and patch
    c.k
    color arrays (normalized 0–1 RGBA), then init the player with the modified object. Brittle (depends on layer structure) — prefer themes or CSS-driven SVG-renderer (
    lottie-web
    rendererSettings
    ) when you must restyle by class.
两种实现方式:
  • dotLottie主题:.lottie文件可嵌入命名颜色主题;通过
    dotLottie.setTheme("dark")
    /
    loadTheme(...)
    切换。使用LottieFiles工具创建——无需重新导出即可更改颜色。
  • 手动颜色覆盖:加载JSON文件,遍历
    layers[].shapes[]
    并修改
    c.k
    颜色数组(归一化0–1的RGBA值),然后使用修改后的对象初始化播放器。这种方式较为脆弱(依赖图层结构)——必须通过类重新样式化时,优先使用主题或CSS驱动的SVG渲染器(
    lottie-web
    rendererSettings
    )。

Mobile runtimes (parity)

移动端运行时(功能对齐)

  • iOS —
    lottie-ios
    (
    LottieAnimationView
    ):
    .play()
    ,
    .currentProgress
    ,
    .play(fromFrame:toFrame:)
    .
  • Android —
    lottie-android
    (
    LottieAnimationView
    / Compose
    LottieAnimation
    ):
    setMinAndMaxFrame
    ,
    progress
    .
  • React Native —
    lottie-react-native
    (
    <LottieView source={...} progress={anim} />
    , drive
    progress
    with
    Animated
    ).
The same
.lottie
/
.json
plays across all; segments and progress concepts match the web API.
  • iOS —
    lottie-ios
    LottieAnimationView
    ):
    .play()
    .currentProgress
    .play(fromFrame:toFrame:)
  • Android —
    lottie-android
    LottieAnimationView
    / Compose
    LottieAnimation
    ):
    setMinAndMaxFrame
    progress
  • React Native —
    lottie-react-native
    <LottieView source={...} progress={anim} />
    ,通过
    Animated
    驱动
    progress
    )。
同一.lottie/.json文件可在所有平台播放;片段和进度概念与网页端API一致。

Optimization

优化建议

  • Ship
    .lottie
    (zipped) over raw
    .json
    ; lazy-load offscreen players and pause when not visible (
    IntersectionObserver
    play
    /
    pause
    ).
  • Prefer the canvas/WASM dotLottie renderer for many simultaneous animations; SVG renderer (lottie-web) is fine for one crisp icon but costs more DOM for complex files.
  • Keep AE comps small: fewer layers/keyframes, no large embedded rasters; flatten precomps where possible. File size tracks keyframe and path complexity, not duration.
  • Recolor at runtime (themes) instead of exporting a file per brand/theme.
  • 优先交付.lottie(压缩格式)而非原始.json;延迟加载屏幕外的播放器,当元素不可见时暂停播放(使用
    IntersectionObserver
    控制
    play
    /
    pause
    )。
  • 同时播放多个动画时,优先使用canvas/WASM版的dotLottie渲染器;SVG渲染器(lottie-web)适合单个清晰图标,但复杂文件会占用更多DOM资源。
  • 保持AE合成文件简洁:减少图层/关键帧数量,不嵌入大型光栅图;尽可能合并预合成。文件大小取决于关键帧和路径复杂度,而非时长。
  • 通过运行时主题化(主题)修改颜色,而非为每个品牌/主题导出单独文件。

Deliver & verify (standalone HTML)

交付与验证(独立HTML文件)

Packaged helper (
scripts/
):
scripts/seek-shot.sh anim.html 0 1.5 3
freezes the
?t=N
harness and screenshots each moment;
scripts/contact-sheet.sh sheet.png frame-*.png
tiles them for one-glance review. See
scripts/README.md
.
For a self-contained Lottie demo (looping illustration, animated icon, empty state) the deliverable is one HTML file that opens directly in a browser — the dotLottie/lottie-web runtime from CDN, a
<canvas>
, and your
.lottie
/
.json
(a relative file or a data URL). No build step. One file is the right tier for shipping a player; don't reach for a bundler.
Output contract:
  • One
    .html
    file: the runtime via CDN (
    @lottiefiles/dotlottie-web
    ), the canvas, and
    autoplay:false
    so the frame is yours to drive.
  • Include the seek harness so any frame can be frozen for a screenshot.
Seek harness — freeze an exact frame.
?t=N
jumps to a frame and holds it so a screenshot lands on a still, deterministic frame. Lottie's playhead is in frames, so stop on the frame directly:
html
<script>
  const dl = new DotLottie({ canvas, src: "/icon.lottie", autoplay: false });
  dl.addEventListener("load", () => {
    const t = new URLSearchParams(location.search).get("t");
    if (t !== null) dl.setFrame(parseFloat(t));      // freeze on frame N (lottie-web: anim.goToAndStop(N, true))
    else dl.play();
    console.log("totalFrames", dl.totalFrames);       // read for end-frame
    window.__ready = true;
  });
</script>
Verify loop — render → freeze → screenshot → check: open the file at first / mid / last frame (
?t=0
,
?t=<total/2>
,
?t=<total-1>
; read
totalFrames
from the console), screenshot each, and check fidelity (colors/theme correct, segment loops where intended) plus artifacts (canvas blurry from missing
autoResize
/DPR, clipped composition, FOUC before the file loads, jank). Any headless tool works:
bash
npx playwright screenshot --wait-for-timeout=600 "file://$PWD/lottie.html?t=42" frame-mid.png
Before you finish:
  1. Opens standalone — no console errors, CDN runtime and the
    .lottie
    /
    .json
    load.
  2. ?t=N
    (
    setFrame
    /
    goToAndStop
    ) freezes the correct, deterministic frame.
  3. Screenshotted at first / mid / last frame — matches the brief, sharp, no clipping.
  4. prefers-reduced-motion
    honored — don't
    autoplay
    a loop; show a static frame or offer a play control.
  5. Easing is intentional — playback speed/segment chosen on purpose, motion baked in AE reads as designed.
打包工具
scripts/
目录):
scripts/seek-shot.sh anim.html 0 1.5 3
可冻结
?t=N
测试工具并截取每个时刻的截图;
scripts/contact-sheet.sh sheet.png frame-*.png
将截图拼接成一张预览图,方便快速查看。详见
scripts/README.md
对于独立的Lottie演示(循环插图、动画图标、空状态),交付物应为可直接在浏览器中打开的单个HTML文件——通过CDN引入dotLottie/lottie-web运行时、一个
<canvas>
元素,以及你的.lottie/.json文件(相对路径或data URL)。无需构建步骤。单个文件是交付播放器的最佳方式,无需使用打包工具。
输出规范:
  • 单个
    .html
    文件:通过CDN引入
    @lottiefiles/dotlottie-web
    运行时、canvas元素,并设置
    autoplay:false
    ,以便自行控制帧。
  • 包含帧定位工具,可冻结任意帧以截图。
帧定位工具——冻结精确帧
?t=N
可跳转到指定帧并保持静止,确保截图为确定的静态帧。Lottie的播放头以帧为单位,直接停在目标帧即可:
html
<script>
  const dl = new DotLottie({ canvas, src: "/icon.lottie", autoplay: false });
  dl.addEventListener("load", () => {
    const t = new URLSearchParams(location.search).get("t");
    if (t !== null) dl.setFrame(parseFloat(t));      // 冻结在第N帧(lottie-web:anim.goToAndStop(N, true))
    else dl.play();
    console.log("totalFrames", dl.totalFrames);       // 读取总帧数以获取结束帧
    window.__ready = true;
  });
</script>
验证循环——渲染→冻结→截图→检查:在第一帧/中间帧/最后帧打开文件(
?t=0
?t=<total/2>
?t=<total-1>
;从控制台读取
totalFrames
),分别截图,检查保真度(颜色/主题正确,片段按预期循环)以及** artifacts**(因缺少
autoResize
/DPR导致canvas模糊、合成内容被裁剪、文件加载前出现FOUC、播放卡顿)。任何无头工具均可完成此操作:
bash
npx playwright screenshot --wait-for-timeout=600 "file://$PWD/lottie.html?t=42" frame-mid.png
完成前检查:
  1. 可独立打开——无控制台错误,CDN运行时和.lottie/.json文件加载正常。
  2. ?t=N
    setFrame
    /
    goToAndStop
    )可冻结正确的确定帧。
  3. 在第一帧/中间帧/最后帧截图——符合需求,清晰无裁剪。
  4. 遵循
    prefers-reduced-motion
    设置——不要自动播放循环动画;显示静态帧或提供播放控件。
  5. 缓动效果符合预期——播放速度/片段选择合理,AE中制作的动效与设计一致。

Quick reference

快速参考

GoalCall
Play a range
setSegment(start, end)
Jump to frame
setFrame(n)
Reverse / bounce`setMode("reverse"
Scroll-drive
autoplay:false
+
setFrame(p*totalFrames)
Theme swap
setTheme("dark")
Know length
totalFrames
after
load
event
Declarative interactivity
@lottiefiles/lottie-interactivity
目标调用方法
播放指定范围
setSegment(start, end)
跳转到指定帧
setFrame(n)
反向播放 / 弹跳播放`setMode("reverse"
滚动驱动
autoplay:false
+
setFrame(p*totalFrames)
切换主题
setTheme("dark")
获取总帧数加载事件后读取
totalFrames
声明式交互
@lottiefiles/lottie-interactivity

Reference files

参考文件

  • references/integration-and-export.md
    — full dotLottie-web + React setup and event/segment control,
    lottie-interactivity
    mode configs, scroll/cursor patterns, runtime theming details, and the complete After Effects → Bodymovin export checklist with the list of unsupported AE features and how to work around them.
  • references/integration-and-export.md
    — 完整的dotLottie-web + React设置、事件/片段控制、
    lottie-interactivity
    模式配置、滚动/光标交互模式、运行时主题化细节,以及完整的After Effects → Bodymovin导出检查清单,包含不支持的AE功能列表及解决方法。