Lottie 的本质是 After Effects 动画的 Web 播放器,其工作流程清晰简洁:
- 设计 → 设计师在 After Effects(AE) 中制作矢量动画
- 导出 → 通过 Bodymovin 插件将动画导出为轻量的
data.json文件 - 播放 → web 开发者使用
lottie-web库解析该 JSON,并在浏览器中实时渲染动画
若想深入理解 Lottie 的动画机制,从 JSON Schema 入手是一条清晰的路径。Lottie 是一个完全由数据驱动的动画系统,掌握其 JSON 结构,就等于握住了理解动画渲染逻辑的钥匙。当然,Lottie JSON 的配置项较为丰富,不必追求一次性全部记住。本文旨在帮助大家建立初步认知,为后续学习渲染引擎打下基础,做到"知其然,亦知其所以然"。
一、初识 data.json :动画数据的顶层结构
Lottie 动画的本质是一套由数据驱动的图形绘制指令集 ,而 data.json 文件正是这套指令的完整载体。其顶层结构 定义了动画的全局元信息,如同电影的"导演台本",设定了动画播放的画布尺寸、时间线与基础环境。理解这些字段,是后续深入解析图层、关键帧等复杂属性的根基。
顶层元数据:动画的全局定义
下表列出了 data.json 根对象(Root Object)中的核心元数据字段,它们共同框定了动画的时空属性与渲染基础。
| 字段 | 类型 | 描述 | 示例值 | 单位/备注 |
|---|---|---|---|---|
| v | string |
Bodymovin 插件版本:生成此 JSON 所用的插件版本号,不同版本可能支持不同的特性。 | "5.7.4" |
- |
| fr | number |
帧率(Frame Rate) :动画的播放速率,直接决定动画的流畅度与时间计算基准。 | 30, 60 |
帧/秒 (fps) |
| ip | number |
起始帧(In Point) :动画时间轴开始的绝对帧编号。 | 0 |
帧 |
| op | number |
结束帧(Out Point) :动画时间轴结束的绝对帧编号。动画总时长 = (op - ip) / fr 秒。 |
90 |
帧 |
| w | number |
画布宽度:动画合成(Composition)的逻辑宽度。 | 800 |
像素 (px) |
| h | number |
画布高度:动画合成的逻辑高度。 | 600 |
像素 (px) |
| nm | string |
合成名称(Name) :对应 After Effects 中合成的名称,便于识别。 | "元数据演示动画" |
- |
| ddd | integer |
3D 图层标识 :标识此合成中是否包含 3D 图层或摄像机 。0 代表否(默认),1 代表是。 |
0 |
- |
综合以上字段,一个定义了800x600画布、30fps、时长3秒的2D动画,其顶层结构示例如下:
json
{
"v": "5.7.4",
"fr": 30,
"ip": 0,
"op": 90,
"w": 800,
"h": 600,
"nm": "元数据演示动画",
"ddd": 0,
}
核心组成:图层、资源与字形
assets、chars 与 layers 是构成 Lottie 动画内容的三个核心数据数组。它们分别定义了可复用的素材、矢量字形以及图层的序列与属性,共同描述了动画的全部视觉信息与动态行为。
assets - 可复用资源库
assets 数组用于集中定义动画中可被多次引用的静态或动态资源。此设计实现了资源复用,有助于优化文件体积并保证引用的一致性。
| 资源类型 | 类型标识 (ty) |
内容描述 | 引用字段 | 主要用途 |
|---|---|---|---|---|
| 图像资源 | "img" |
包含图像ID、尺寸及文件路径或Base64编码数据。 | refId |
静态位图元素,如图标、背景。 |
| 预合成资源 | "precomp" |
一个完整的子合成,包含独立的图层(layers)与时间轴。 |
refId |
可重复使用的动画片段,如通用动效组件。 |
引用机制 :图层通过其 refId 属性与 assets 中对应ID的资源进行关联。渲染时,引擎据此查找并绘制相应资源。
chars - 矢量字形定义
chars 数组存储了将文字转换为矢量形状后的数据。当动画需要对文字进行路径变形、描边动画等超越普通文本渲染能力的操作时,会使用此数组。
- 产生条件:在After Effects中对文本图层执行"从文字创建形状",或在导出时启用"字符形状"选项。
- 数据结构 :每个项定义了字符、字体信息及其矢量路径(
data),该路径数据包含轮廓、描边与填充等属性。 - 核心用途:实现对文字字符的精细化控制,用于制作字形变形、笔画动画等效果。
layers - 动画图层序列
layers 是一个有序数组,定义了所有图层的叠加顺序、基本属性及关键帧动画。它是组织动画渲染逻辑的主体。
- 渲染顺序:数组索引从0开始,图层按索引升序从底层到顶层依次渲染。
- 核心属性:每个图层对象包含类型(如形状、图像、文本)、空间变换属性、蒙版以及关键帧动画数据。
- 关键作用 :
assets和chars中定义的资源需在此被引用,并通过图层的动画属性驱动,才能成为最终动画的一部分。
协作关系 :assets 和 chars 作为资源定义,为 layers 提供素材;layers 则负责组织这些素材,并通过其时间轴和属性控制动画的最终表现。一个完整的结构示例如下:
json
{
"v": "5.7.4",
"fr": 30,
"ip": 0,
"op": 90,
"w": 800,
"h": 600,
"nm": "元数据演示动画",
"ddd": 0,
"assets": [],
"layers": [],
"chars": []
}
二、图层系统 - 理解 Layers 结构⭐️
layers 数组是 Lottie JSON 中承载所有动画图层信息的主体。它定义了图层的堆叠顺序、属性及关键帧动画,是构成动画视觉呈现与动态行为的核心数据结构。Lottie 主要包含以下六种基础图层类型:
类型标识 (ty) |
图层类型 | 核心描述 |
|---|---|---|
| 0 | 预合成图层 (Precomp Layer) | 嵌套合成层,通过 refId 引用 assets 中定义的预合成资源,实现动画复用与模块化管理。 |
| 1 | 纯色图层 (Solid Layer) | 纯色填充层,定义固定颜色的矩形区域,常用作背景或遮罩。 |
| 2 | 图像图层 (Image Layer) | 静态图片层,通过 refId 引用 assets 中定义的图像资源。 |
| 3 | 空对象图层 (Null Layer) | 不可见辅助层,主要用于通过其 ks 属性(变换数据)驱动子图层动画,或作为动画控制器。 |
| 4 | 形状图层 (Shape Layer) | 矢量图形层,由路径、描边、填充等属性构成,是制作变形、路径动画的基础。 |
| 5 | 文本图层 (Text Layer) | 文字图层,可定义字体、颜色、段落样式,并支持逐字符动画。 |
所有图层共享一组基础属性,用于定义其在合成中的基本状态与时空关系。
以下属性为所有图层类型共有的基础属性:
| 属性 | 类型 | 必选 | 描述 | 示例值 | 默认值 |
|---|---|---|---|---|---|
ty |
number |
是 | 图层类型标识,决定图层的行为和数据结构(见上表) | 0-5 |
- |
nm |
string / number |
否 | 图层名称,在 After Effects 中设置,用于表达式和调试 | "按钮背景", "Layer 1" |
- |
ind |
number |
是 | 图层索引,在整个合成中唯一,用于父子关联和表达式引用 | 1, 2, 3 |
- |
ip |
number |
是 | 入点 (In Point),图层开始显示的帧数 | 0, 30 |
- |
op |
number |
是 | 出点 (Out Point),图层结束显示的帧数 | 90, 180 |
- |
st |
number |
是 | 起始时间 (Start Time),图层的时间偏移量 | 0, 10 |
- |
sr |
number |
否 | 时间拉伸 (Stretch),控制图层播放速度的系数 | 1 (正常), 0.5 (减速), 2 (加速) |
1 |
ks |
object |
是 | 变换属性 (Transform),包含位置、缩放、旋转、透明度等关键帧数据 | 见下方详解 | - |
ao |
number |
否 | 自动定向 (Auto-Orient),沿路径自动调整图层方向(布尔值:0/1) | 0 (关闭), 1 (开启) |
0 |
ddd |
number |
否 | 3D 图层标识,标记该图层是否为 3D 图层(布尔值:0/1) | 0 (2D), 1 (3D) |
0 |
parent |
number |
否 | 父图层索引 ,指向父图层的 ind 值,实现层级控制和联动变换 |
1, 5 |
- |
cl |
string |
否 | CSS 类名 (Class),在 SVG/HTML 渲染器中作为 HTML class | "background", "icon" |
- |
ln |
string |
否 | HTML ID,在 SVG/HTML 渲染器中作为 HTML id 属性 | "layer-bg", "main-icon" |
- |
以上13个通用属性中,有 3个 (ip、op、nm)与根对象中的概念完全一致 ,仅作用域不同。1个 (ddd)与根对象概念相似但有区别 :根对象的 ddd 表示合成"是否包含"3D元素,而图层的 ddd 表示其"本身是否为"3D图层。其余 9个 (ty, ind, st, sr, ks, ao, parent, cl, ln)则是图层专有的核心属性,它们共同定义了图层在时间与空间中的基本状态。
接下来,我们将首先深入解析其中最核心的 ks(变换属性) 对象,它是驱动所有图层运动与变化的关键。
三、变换属性 - 位置、旋转、缩放⭐️
ks 对象概览
ks(Transform)是所有图层的核心动画容器,它定义了图层在空间中的位置、大小、旋转、透明度等基础变换状态。其名称 ks 是 Keyable Styled Properties(可关键帧的样式化属性) 的缩写,这精准概括了其两大核心特性:
k(Keyable) :指这些属性可被设置为关键帧,是实现所有逐帧动画的基础。s(Styled) :指这些属性可被动态驱动或赋予样式,支持通过数据或表达式进行复杂控制。
因此,ks 对象不仅描述图层的静态空间状态,更是承载其所有运动与变换动画的数据载体。所有基础动画(如移动、缩放、旋转、淡入淡出)都通过在此对象内定义关键帧来实现。
ks 的完整属性表
| 属性 | 全称 | 默认值 | 作用 |
|---|---|---|---|
a |
Anchor Point | [0, 0, 0] |
锚点:图层变换的基准中心点(支点)。 |
p |
Position | [0, 0, 0] |
位置:图层在画布中的坐标。 |
s |
Scale | [100, 100, 100] |
缩放:图层的尺寸比例(以百分比表示)。 |
r |
Rotation | 0 |
旋转:图层的旋转角度(单位为度)。 |
o |
Opacity | 100 |
不透明度:图层的透明度(100为完全不透明,0为完全透明)。 |
sk |
Skew | 0 |
倾斜:图层的倾斜角度(单位为度)。 |
sa |
Skew Axis | 0 |
倾斜轴:定义倾斜操作所沿的轴向角度(单位为度)。 |
3D 图层特殊形式:当 ddd=1 时,p 可能被拆分为 px、py、pz 三个独立属性。
属性值的两种数据形态
每个变换属性的值均以统一的结构表示,分为 静态值 与 动画值 两种形态,通过 a 字段区分。
1. 静态值 (a: 0)
属性在整个时间轴上保持不变,结构简洁。
json
{
"r": {
"a": 0, // 静态标识
"k": 45 // 固定值:旋转45度
}
}
2. 动画值 (a: 1)
属性值随时间变化,通过关键帧数组 (k) 定义。
json
{
"r": {
"a": 1, // 动画标识
"k": [ // 关键帧数组
{
"t": 0, // 时间点(帧)
"s": [0], // 起始值
"e": [360] // 结束值
},
{
"t": 60, // 下一关键帧时间点
"s": [360] // 该帧的数值(结束时省略"e")
}
]
}
}
关键帧核心字段说明:
t(time) :关键帧所处的时间点(帧序号)。s(start value) :此关键帧的起始值。e(end value) :朝向下一关键帧的目标值。最后一个关键帧可省略。i/o:定义属性变化速率(缓动)的贝塞尔曲线控制点,将在后续章节详述。
此结构是 Lottie 实现所有基础运动(位移、缩放、旋转、淡入淡出)的通用数据范式。
🎨小试牛刀:动手验证核心概念
通过前面的学习,我们已经掌握了 Lottie JSON 的顶层结构和核心属性。现在,让我们通过一个具体的例子,动手验证如何配置一个基础的静态场景。
在本例中,我们将使用一张图片,创建一个静态的图片图层。您将在下图中看到(一个静态图,一个旋转图):

说明 :上图的 GIF 展示了包含旋转动画的完整效果。而下面的 JSON 配置,我们将首先完成左侧静态图片 的搭建。这能让我们专注于已学的静态属性配置 (
a: 0)。右侧的旋转动画,将在我们学习了关键帧系统后,通过简单地修改r(旋转)属性即可实现。
以下是完整的 Lottie JSON 配置,已附上详尽的注释:
js
{
// ========== 顶层元数据:动画的全局定义 ==========
"v": "5.7.4", // Bodymovin 插件版本
"fr": 30, // 帧率:30fps
"ip": 0, // 起始帧:从第0帧开始
"op": 90, // 结束帧:到第90帧结束(总时长 = (90-0)/30 = 3秒)
"w": 800, // 画布宽度:800像素
"h": 600, // 画布高度:600像素
"nm": "变换属性演示", // 合成名称
"ddd": 0, // 3D标识:0表示不包含3D图层
// ========== Assets:可复用资源库 ==========
"assets": [
{
"id": "image_0", // 资源ID,供图层通过 refId 引用
"w": 500, // 图片原始宽度
"h": 500, // 图片原始高度
"u": "", // 图片URL基础路径(空表示使用完整路径)
"p": "https://img11.360buyimg.com/img/jfs/t1/383242/14/16667/276460/695dd5ccF565013e8/02761c81c82b92d4.png", // 图片完整URL
"e": 0 // 是否嵌入:0表示外部链接
}
],
// ========== Layers:图层序列(从下到上渲染) ==========
"layers": [
// ---------- 图层1:静态图片(展示静态值 a:0) ----------
{
"ddd": 0, // 该图层不是3D图层
"ind": 1, // 图层索引:1(唯一标识)
"ty": 2, // 图层类型:2 = Image Layer(图像图层)
"nm": "静态图片", // 图层名称
"refId": "image_0", // 引用 assets 中 id 为 "image_0" 的资源
"sr": 1, // 时间拉伸:1 = 正常速度
// ===== ks:变换属性(Transform)=====
"ks": {
// ----- o:不透明度(Opacity)-----
"o": {
"a": 0, // 静态值标识(a=0 表示不动画)
"k": 100 // 固定值:100%不透明
},
// ----- r:旋转(Rotation)-----
"r": {
"a": 0, // 静态值标识
"k": 45 // 固定值:旋转45度
},
// ----- p:位置(Position)-----
"p": {
"a": 0, // 静态值标识
"k": [250, 300, 0] // 固定位置:[x, y, z] = 左侧250px,顶部300px
},
// ----- a:锚点(Anchor Point)-----
"a": {
"a": 0, // 静态值标识
"k": [250, 250, 0] // 锚点在图片中心(500x500图片的中心点)
},
// ----- s:缩放(Scale)-----
"s": {
"a": 0, // 静态值标识
"k": [30, 30, 100] // 缩放到30%(显示为150x150)
}
},
"ao": 0, // 自动定向:关闭
"ip": 0, // 图层入点:第0帧开始显示
"op": 90, // 图层出点:第90帧结束显示
"st": 0, // 起始时间偏移:0(无偏移)
"bm": 0 // 混合模式:0 = Normal(正常)
}
],
// ========== Chars:矢量字形定义(本例未使用)==========
"chars": []
}
这个示例是一个"知识检查点",清晰地展示了:
- 顶层元数据 (
v,fr,w,h...) 定义了动画的舞台(3秒、800x600的画布)。 - 资源 (
assets) 定义了唯一可用的图片素材,并通过id标识。 - 图层 (
layers) 通过refId引用该资源,将其实例化到舞台上。 ks变换对象 决定了这个实例的最终状态:位于画布左侧,缩小至30%,并旋转了45度。所有属性均以静态值 (a: 0) 定义。
至此,您已经掌握了如何构建一个 Lottie 动画的静态骨架 ------定义舞台、准备素材、放置元素并设置其初始状态。在上方的预览图中,您也看到了动画的潜力:只需将 r(旋转)属性的 a 值从 0 改为 1,并配上关键帧数据,静态图片就能旋转起来。
那么,a: 1 模式下的 k 数组究竟如何定义?多个关键帧之间如何平滑过渡?动画的运动节奏又由什么控制?接下来,我们就将深入动画的核心,解析关键帧、插值与缓动的完整系统。
四、深入动画 - 关键帧、插值与缓动⭐️
在上一章的"小试牛刀"中,我们看到了静态图片与旋转图片的对比效果。右侧的旋转效果正是通过关键帧动画实现的。现在,让我们深入解析这个旋转动画的完整JSON配置,揭开Lottie动画系统的核心机制。

让我们对比一下 demo 中两个图层的配置,看看静态图片是如何"动"起来的:
静态图片(左侧):
json
"r": {
"a": 0, // 静态值标识
"k": 45 // 固定值:旋转45度
}
旋转图片(右侧):
json
"r": {
"a": 1, // 动画值标识(a=1 表示有关键帧动画)
"k": [ // 关键帧数组
{
"i": { "x": [0.667], "y": [1] }, // 入缓动
"o": { "x": [0.333], "y": [0] }, // 出缓动
"t": 0, // 时间点:第0帧
"s": [0] // 起始值:0度
},
{
"t": 90, // 时间点:第90帧
"s": [360] // 结束值:360度
}
]
}
核心差异总结:
| 特征 | 静态值 (a: 0) |
动画值 (a: 1) |
|---|---|---|
k 的类型 |
单个数值或数组 | 关键帧对象数组 |
| 时间轴 | 无时间概念,始终保持固定值 | 在时间轴上定义多个状态点 |
| 缓动控制 | 无 | 通过 i 和 o 控制运动节奏 |
| 适用场景 | 静态属性(如固定位置、固定角度) | 需要随时间变化的属性(移动、旋转、缩放等) |
关键帧数组结构解析
当属性设置为动画值(a: 1)时,k 字段不再是一个简单值,而是一个关键帧对象数组。每个关键帧对象定义了动画在特定时间点的状态。
核心字段说明
| 字段 | 类型 | 必选 | 描述 |
|---|---|---|---|
t |
number |
是 | 时间点(Time):该关键帧在时间轴上的位置,单位为帧。 |
s |
array |
是 | 起始值(Start Value) :该关键帧的属性值。对于旋转是 [角度],位置是 [x, y, z]。 |
e |
array |
否 | 结束值(End Value) :从当前关键帧到下一关键帧的目标值。通常省略 ,渲染器会自动使用下一关键帧的 s 值。 |
i |
object |
否 | 入缓动(In Tangent) :定义进入当前关键帧时的速度变化曲线(贝塞尔控制点)。 |
o |
object |
否 | 出缓动(Out Tangent) :定义离开当前关键帧时的速度变化曲线(贝塞尔控制点)。 |
h |
number |
否 | 保持帧(Hold) :值为 1 时,表示该关键帧到下一关键帧之间不插值,保持当前值(阶跃动画)。 |
说明:
s的数据类型 :虽然官方 schema 中定义为number,但在实际使用中,s通常是数组 (如[0]表示旋转 0 度,[100, 200, 0]表示位置)。这是为了统一处理单维和多维属性。e字段的实际使用 :在大多数情况下,e字段会被省略,渲染器会自动从下一个关键帧的s值推断目标值。只有在需要显式控制插值目标时才会使用。- 最后一帧 :最后一个关键帧通常只有
t和s,不需要i、o、e(因为没有下一个关键帧)。
缓动控制点的结构
i 和 o 对象定义了贝塞尔曲线的控制点,用于控制动画的加速度:
json
{
"i": {
"x": [0.667], // 入缓动的 X 轴控制点(时间维度,范围 0-1)
"y": [1] // 入缓动的 Y 轴控制点(数值维度,通常 0-1,但可超出)
},
"o": {
"x": [0.333], // 出缓动的 X 轴控制点
"y": [0] // 出缓动的 Y 轴控制点
}
}
x数组 :控制时间进度的变化率(水平方向)y数组 :控制数值变化的速率(垂直方向)- 数组长度 :对于单维属性(如旋转
r),数组长度为 1;对于多维属性(如位置p),数组长度对应维度数(如[0.5, 0.3]表示 X、Y 两个维度的独立控制)
前端知识关联 :
i与o定义的贝塞尔曲线,其作用与 CSS 中的transition-timing-function或animation-timing-function完全一致,用于创造非匀速的动画效果。区别在于,CSS 使用一个二维的cubic-bezier(x1, y1, x2, y2),而 Lottie 的i和o允许为每个属性维度单独定义控制点,控制更为精细。工具推荐 :如果您需要直观地创建或理解贝塞尔曲线,强烈推荐使用在线工具 cubic-bezier.com 。您可以在那里调整曲线并获取对应的
cubic-bezier()值,其原理与 Lottie 的i/o控制点相通,是理解和调试动画缓动的绝佳助手。
关键帧的工作流程
以 demo 中的旋转动画为例,让我们逐步拆解渲染器如何处理关键帧:
第 1 步:解析关键帧数组
json
"k": [
{
"t": 0, // 第0帧
"s": [0], // 旋转角度 0°
"i": { "x": [0.667], "y": [1] },
"o": { "x": [0.333], "y": [0] }
},
{
"t": 90, // 第90帧
"s": [360] // 旋转角度 360°
}
]
渲染器识别出:
- 动画从第 0 帧开始,到第 90 帧结束
- 起始角度 0°,结束角度 360°
- 需要在这 90 帧之间进行插值计算
第 2 步:插值计算(以第 45 帧为例)
当播放到第 45 帧时,渲染器需要计算此时的旋转角度:
- 计算时间进度 :
progress = (45 - 0) / (90 - 0) = 0.5(已完成 50%) - 应用缓动函数 :根据
i和o的贝塞尔控制点,将线性进度0.5转换为缓动后的进度(假设为0.55) - 计算属性值 :
angle = 0 + (360 - 0) × 0.55 = 198°
第 3 步:渲染当前帧
渲染器将计算出的 198° 应用到图层的旋转属性,完成该帧的绘制。
关键帧的连续性
在多个关键帧的场景中,渲染器会:
- 定位当前区间:找到当前时间点所在的关键帧区间(如第 30 帧位于第 0 帧和第 90 帧之间)
- 使用对应缓动 :应用该区间起始关键帧的
o(出缓动)和结束关键帧的i(入缓动) - 独立插值 :对于多维属性(如位置
[x, y, z]),每个维度独立进行插值计算
本章小结
至此,我们已经掌握了 Lottie 动画系统的"动力源":关键帧、插值与缓动。
- 静态与动画的开关 :通过
a字段 (0或1) 切换属性的静态与动态模式,是理解 Lottie 动画逻辑的第一课。 - 关键帧定义状态 :
k数组中的每个关键帧对象,通过t(时间) 和s(数值) 在时间轴上锚定了动画的各个"关键时刻"。 - 缓动赋予灵魂 :
i(入缓动) 与o(出缓动) 所定义的贝塞尔曲线,控制了数值变化的速率与节奏,是让动画摆脱机械感、获得生命力的关键。 - 渲染器执行插值 :在关键帧之间,Lottie 渲染器会依据缓动曲线,为每一帧实时计算出精确的属性值,从而创造出平滑的动画效果。
您已经了解了从定义到渲染的完整链条。关于贝塞尔曲线的数学原理 、多维属性的独立插值策略 以及更复杂的表达式动画,都属于更深入的话题。掌握了本章的核心数据模型,您已经具备了自行解析绝大多数 Lottie 动画、并理解其运动逻辑的能力。
五、形状系统 - 矢量图形
在 Lottie 的六种基础图层中,形状图层(Shape Layer,ty: 4) 占据着独特而核心的地位。其他图层类型------如空对象图层(用于控制)、预合成图层(用于嵌套)、图像图层(静态位图)和文本图层(字形动画)------虽然在特定场景下不可或缺,但它们在数据结构和动画能力上相对简单。
形状图层(ty: 4)是 Lottie 实现复杂矢量动画的核心。与其他图层类型相比,它拥有最丰富的专有属性和最强的动画表现力。
形状图层的结构:ty: 4 与 shapes 数组
当一个图层的 ty 值为 4 时,它就是一个形状图层。其核心数据容器是 shapes 数组(在早期的 Lottie 版本中可能标记为 it)。该数组是一个有序的列表,定义了构成最终矢量图形的所有基础元素,例如路径、描边、填充等。
- 有序渲染与叠加 :
shapes数组中的元素严格遵循数组索引顺序(从0到n-1)进行渲染 。在视觉上,这意味着索引值更大的元素(后渲染)会叠加在索引值更小的元素(先渲染)之上 。例如,shapes[2]会覆盖在shapes[0]和shapes[1]之上。这一规则是组织复杂图形层级的基础。 - 元素类型 :每个元素都是一个独立的对象,并通过
ty字段来声明自己的类型(如gr表示组,sh表示路径等)。
四种基础形状类型速览
shapes 数组中可以包含多种图形元素,其中基础形状主要有以下四种:
类型标识 (ty) |
名称 | 描述 | 核心动画属性 |
|---|---|---|---|
rc |
矩形 | 定义矩形或圆角矩形。 | p (位置), s (尺寸), r (圆角半径) |
el |
椭圆 | 定义圆形或椭圆形。 | p (中心点), s (半径/尺寸) |
sr |
星形/多边形 | 定义星形或多边形,可控制角数、内外径等。 | p (中心点), ir/or (内/外半径), pt (角数) |
sh |
自由路径 | 由贝塞尔曲线构成的任意形状路径,是矢量图形的基础。 | ks (路径数据,包含顶点与贝塞尔控制点) |
说明 :
rc,el,sr本质上是参数化形状,它们会在导出时被转换为最终的sh(路径)数据。但在 JSON 中,它们作为逻辑元素存在,便于理解和编辑。
自由路径的核心:顶点与贝塞尔控制点
自由路径(ty: 'sh')是最基础、最灵活的形状元素。其核心数据存储在 ks 属性中,它定义了一系列顶点(Vertex) 以及连接这些顶点的贝塞尔曲线。
一个路径的关键帧数据通常包含以下字段:
json
{
"a": 1, // 表示路径数据是动画的
"k": {
"i": [[0, 0]], // 入控制点 (In Tangent)
"o": [[0, 0]], // 出控制点 (Out Tangent)
"v": [[50, 50]], // 顶点 (Vertex)
"c": true // 路径是否闭合 (Closed)
}
}
v(顶点) :一个二维数组,定义了路径在空间中经过的关键点坐标[x, y]。i(入控制点) :定义曲线进入当前顶点时的方向与张力。o(出控制点) :定义曲线离开当前顶点时的方向与张力。c(闭合) :布尔值,true表示路径的首尾顶点应连接,形成封闭图形。
工作原理 :v 定义了"骨架",i 和 o 则定义了连接骨架的"肌肉"曲线。通过为这些数据添加关键帧,即可实现路径的形变、绘制等复杂动画。
知识关联:两种贝塞尔曲线
您可能已经发现,这里的
i和o与第四章关键帧缓动 中的i和o字段同名,且都代表贝塞尔曲线的控制点。这是 Lottie 中贝塞尔曲线的两种核心应用:
维度 空间贝塞尔曲线 (本章) 时间贝塞尔曲线 (第四章) 作用 定义空间中 的图形形状。 定义时间上 的属性变化速率(缓动)。 控制点 ( i/o)控制顶点处曲线的方向与曲率,决定路径形态。 控制关键帧处动画速度的快慢,决定运动节奏。 坐标空间 位于画布的二维/三维空间 (如 [x, y])。位于时间-进度二维空间,X轴是时间(0-1),Y轴是进度(0-1)。 直观感受 拖拽控制柄,改变的是线的弯曲程度。 拖拽控制柄,改变的是动画的先快后慢。 底层一致性 :尽管应用不同,但两者都基于三次贝塞尔曲线 的数学模型。理解这一点后,无论是调整路径平滑度还是动画缓动,您操作的都是同一种"控制点"逻辑。这也解释了为何可视化工具 cubic-bezier.com 对理解两者都有帮助:虽然它主要用于缓动(时间),但其对曲线形态的直观展示,同样有助于您想象空间路径中控制点对形状的影响。
形状组(gr):嵌套与组织
为了管理复杂的图形,Lottie 引入了 形状组(ty: 'gr') 。组可以将多个形状元素(包括其他组)打包为一个逻辑整体。
-
it数组:组的核心属性,是一个数组,用于包含其子元素(如路径、填充、描边或其他组)。 -
作用:
- 层次化管理:像文件夹一样组织图形,使结构清晰。
- 统一变换 :组可以拥有自己的
ks(变换)属性。对该组应用的变换(如移动、缩放)会同时影响其内部所有子元素。 - 动画复用:通过控制组的变换,可以轻松实现整个图形模块的动画。
六、形状样式 - 填充与描边
在上一章中,我们探索了形状图层如何通过路径、椭圆、矩形等元素定义图形的几何骨架 。然而,只有几何形状是"不可见"的。要让图形真正被渲染出来,就需要为其赋予样式。
本章将介绍形状系统中负责视觉呈现的两大核心样式元素:填充(Fill) 与描边(Stroke) 。它们为形状的内部 和轮廓提供颜色、渐变和不透明度等视觉效果,是矢量图形从"线框"变为"画面"的关键。
6.1 样式的作用:让形状可见
在 shapes 数组中,样式元素(如 fl、st)与形状元素(如 sh、el)地位平等,通过渲染顺序相互结合。
- 堆叠规则 :
it数组中的元素按索引顺序依次绘制 。这意味着索引更大的元素(后绘制的)会叠加在索引更小的元素(先绘制的)之上。在图形构建中,通常先定义"形状"元素(如el,sh),再定义为其着色的"样式"元素(如fl,st)。 - 独立性与组合性:样式元素是独立的,可以自由组合。一个形状可以同时拥有填充和描边,也可以只有其中一种。它们共同附着于其上方最近且未闭合的图形元素或组。
填充(Fill):纯色与渐变
填充用于为形状的内部区域着色。Lottie 支持两种填充类型。
纯色填充(ty: 'fl')
这是最基础的填充类型,使用单一颜色。
json
{
"ty": "fl", // 类型:Fill (纯色填充)
"c": { // Color (颜色)
"a": 0,
"k": [0.2, 0.6, 1, 1] // RGBA 数组,值范围 0-1
},
"o": { ... } // Opacity (不透明度)
}
渐变填充(ty: 'gf')
Lottie 支持线性渐变和径向渐变,为填充带来丰富的色彩过渡。
json
{
"ty": "gf", // 类型:Gradient Fill (渐变填充)
"t": 1, // 渐变类型:1-线性,2-径向
"g": {
"p": 2,
"k": {
"a": 0,
"k": [0, 0.2, 0.6, 1, 1, 1, 0, 1, 0, 1]
}
}
"s": { ... }, // 起点 (线性) / 起始点 (径向)
"e": { ... } // 终点 (线性) / 结束点 (径向)
}
g对象 :是渐变的核心。p定义色标数量,k是一个扁平的数组,每 5 个数字为一组,表示一个色标的[位置, R, G, B, A]。所有色标数据按顺序连接。
描边(Stroke):轮廓与样式
描边用于绘制形状的轮廓线。它拥有比填充更丰富的属性来控制线条的视觉表现。
纯色描边(ty: 'st')
json
{
"ty": "st", // 类型:Stroke (描边)
"c": { ... }, // 颜色,同填充
"w": { // Width (线宽)
"a": 0,
"k": 5 // 线宽为5像素
},
"lc": 2, // Line Cap (线帽): 1-平头, 2-圆头, 3-方头
"lj": 2, // Line Join (连接): 1-斜接, 2-圆角, 3-斜面
"ml": 10, // Miter Limit (斜接限制)
"o": { ... } // 不透明度
}
w(Width) :描边的粗细,支持动画。lc(Line Cap) :定义线段端点的样式。lj(Line Join) :定义线段转折处的连接样式。ml(Miter Limit) :当lj为 1 (斜接) 时,控制斜接长度与线宽的比例上限,防止尖角过长。
渐变描边(ty: 'gs')
渐变描边的数据结构与渐变填充 (gf) 高度相似,包含 t (类型)、g (渐变数据) 等属性,区别在于它应用于轮廓线而非填充区域。
样式的通用属性
填充和描边共享一些控制其最终呈现效果的通用属性:
| 属性 | 类型 | 描述 |
|---|---|---|
o |
object |
不透明度 (Opacity) 。通过 a 和 k 控制,值范围为 0 到 100(100 为完全不透明)。这与 CSS 中 0-1 的范围不同,请注意区分。 |
bm |
number |
混合模式 (Blend Mode) 。定义当前样式如何与下方已有的像素进行混合。常见值:0 (正常)、1 (相乘)、2 (屏幕) 等,对应 After Effects 中的混合模式。 |
🎨小试牛刀:画个圆
现在,让我们综合运用以上概念,创建一个最简单的形状:一个蓝色的实心圆 。我们将通过 JSON 配置,清晰地展示形状图层的 shapes 数组是如何组织起来的。

以下是实现该圆形的精简版 JSON 配置 ,我们省略了前面章节已详细讲解的通用图层属性(如 ks 变换),将焦点完全放在形状图层特有的 shapes 数组上:
js
{
"v": "5.7.4",
"fr": 30,
"ip": 0,
"op": 90,
"w": 800,
"h": 600,
"layers": [
{
"ty": 4, // ⭐️ 核心标识:这是一个形状图层
"nm": "带描边圆形",
"ind": 1,
// 🔽 此处省略了图层的 `ks` 变换属性(如 p, a, s, r, o)
// 在完整文件中,它们用于将整个图层定位在画布中心,例如:
// "ks": { "p": { "a": 0, "k": [400, 300, 0] }, ... }
"shapes": [ // ⭐️ 本章核心:形状与样式数组
{
"ty": "gr", // 类型:gr (Group),一个形状组
"nm": "圆形组",
"it": [ // 组内元素列表,按索引顺序 0→1→2→3 渲染
// 1. 形状定义:椭圆 (el) - 先绘制,定义几何轮廓
{
"ty": "el",
"nm": "椭圆路径",
"p": { "a": 0, "k": [0, 0] }, // 位置:相对于组的中心
"s": { "a": 0, "k": [100, 100] } // 尺寸:宽高100px,即圆形
},
// 2. 样式定义:填充 (fl) - 其次绘制,为形状内部着色
{
"ty": "fl",
"nm": "蓝色填充",
"c": {
"a": 0,
"k": [0.2, 0.6, 1, 1] // 颜色:RGBA,此为蓝色
},
"o": { "a": 0, "k": 100 } // 不透明度:100%
},
// 3. 样式定义:描边 (st) - 最后绘制,为形状轮廓添加边线
{
"ty": "st",
"nm": "白色描边",
"c": {
"a": 0,
"k": [1, 1, 1, 1] // 颜色:白色
},
"w": { "a": 0, "k": 5 }, // 线宽:5像素
"lc": 2, // 线帽:2 = 圆头
"lj": 2 // 连接:2 = 圆角
},
// 4. 必需的组变换 (tr) - 必须放在最后,控制整个组的变换
{
"ty": "tr",
"nm": "组变换"
// 其内部属性 (p, a, s, r, o) 通常保持默认值 [0, 0, 100, 0, 100]
}
]
}
]
}
]
}
七、形状修改器 - Trim、Repeater
在掌握了形状的构建与样式之后,我们迎来了形状系统的最后一块拼图:修改器(Modifiers) 。它们不是独立形状,而是附加在现有形状或组之上的"效果处理器",能够以非破坏性的方式动态改变图形的外观或行为,是实现复杂、程式化动画的关键。
修改器的概念:作用范围与顺序
修改器是一种特殊类型的元素,其 ty 值定义在 shapes 或 it 数组中。它们不直接渲染 ,而是像一个处理器,作用于排列在它之前的特定元素。
- 作用逻辑 :在
it数组中,修改器按照从前往后 的顺序执行,每个修改器会作用于它之前已定义 的特定元素。例如,Trim Path裁剪其之前的路径,Repeater重复其之前的整个形状组合。 - 顺序关键 :修改器的位置 决定了其作用范围和最终效果。例如,
[形状 → 样式 → Trim]会裁剪已着色的形状;而[形状 → Trim → 样式]会先裁剪路径,再为裁剪后的部分着色。
Trim Path(tm):路径裁剪动画
Trim Path(路径裁剪)是最常用的修改器之一,它通过控制路径的"起止点"来创造笔触绘制、擦除、扫描等动画效果。
核心属性:
json
{
"ty": "tm", // 类型:Trim Paths
"s": { // Start(起点百分比)
"a": 1,
"k": [{ "t":0, "s":[0] }, { "t":90, "s":[100] }] // 从0%到100%
},
"e": { // End(终点百分比)
"a": 1,
"k": [{ "t":0, "s":[100] }, { "t":90, "s":[100] }] // 保持100%
},
"o": { // Offset(偏移)
"a": 0,
"k": 0 // 范围0-360°,整体偏移裁剪区域
}
}
s(Start) :路径可见部分的起点,范围 0-100%。动画化此属性可实现"生长"动画。e(End) :路径可见部分的终点 ,范围 0-100%。通常e>=s。o(Offset) :裁剪区域的整体偏移量,范围 0-360°。它可以让裁剪的起止点沿路径循环移动,常用于创建"追逐"或"循环扫描"效果。
典型应用 :通过动画 s 和 e 属性,可以实现经典的"笔画书写"或"进度条填充"效果。
Repeater(rp):重复器
Repeater(重复器)能将它之前的所有图形元素 (包括形状、样式甚至其他修改器)复制多次,并对每个副本应用递增的变换,快速创建阵列、放射状、循环等复杂图案。
核心属性:
json
{
"ty": "rp", // 类型:Repeater
"c": { // Copies(副本数量)
"a": 0,
"k": 5 // 生成5个副本(包含原始图形)
},
"o": { // Offset(副本索引偏移)
"a": 0,
"k": 0 // 控制从哪个"虚拟副本"开始渲染,可用于动画
},
"m": 1, // Composite(合成模式):1=Above(后续副本在上方),2=Below(后续副本在下方)
"tr": { // Transform(每个副本的增量变换)
"p": { "a":0, "k":[20, 0] }, // 位置增量:每个副本右移20px
"s": { "a":0, "k":[90, 90] }, // 缩放增量:每个副本缩小至90%
"r": { "a":0, "k":[30] } // 旋转增量:每个副本旋转30度
}
}
c(Copies) :生成的副本总数(包含原始图形)。o(Offset) :控制从哪个"虚拟副本"开始渲染,可用于动画。m(Composite) :控制副本的堆叠顺序。1表示新副本叠在上方,2表示新副本叠在下方。tr(Transform) :定义每个新副本相对于前一个副本的变换增量,是创造规律性变化的关键。
其他修改器简介
除了上述两个,Lottie 还提供了其他实用的修改器来扩展图形能力:
类型标识 (ty) |
名称 | 核心作用 | 关键属性与备注 |
|---|---|---|---|
rd |
Round Corners (圆角) | 将路径的所有尖角转换为指定半径的圆角。 | r:圆角半径。 |
mm |
Merge Paths (合并路径) | 将多个路径合并为一个(类似布尔运算)。 | mm:合并模式(如相加、相减、交集等)。 ⚠️ 注意 :官方文档标注此功能目前不被支持,使用时需谨慎测试。 |
🎨小试牛刀:loading动画
让我们将学到的 Trim Path 知识应用到实践中,制作一个经典的 loading 动画。下面的示例将展示如何通过动画 o(偏移)属性来创建持续旋转的圆环进度效果。

js
{
"v": "5.7.4",
"fr": 30,
"ip": 0,
"op": 90,
"w": 800,
"h": 600,
"nm": "Trim Path演示",
"layers": [
{
"ty": 4,
"nm": "圆形绘制动画",
"ind": 1,
"ks": {
"p": { "a": 0, "k": [400, 300, 0] }
},
"shapes": [
{
"ty": "gr",
"nm": "圆形组",
"it": [
// 1. 圆形路径
{
"ty": "el",
"nm": "圆形路径",
"p": { "a": 0, "k": [0, 0] },
"s": { "a": 0, "k": [200, 200] }
},
// 2. 描边样式
{
"ty": "st",
"nm": "描边",
"c": { "a": 0, "k": [0.2, 0.8, 1, 1] },
"w": { "a": 0, "k": 12 },
"lc": 2,
"lj": 2
},
// 3. Trim Path 修改器 ⭐️
{
"ty": "tm",
"nm": "Trim Path",
"s": { // 起点百分比 (0-100)
"a": 1,
"k": [
{ "t": 0, "s": [0], "e": [100] },
{ "t": 90, "s": [100] }
]
},
"e": { // 终点百分比 (0-100)
"a": 0,
"k": 100
},
"o": { // 偏移角度 (0-360)
"a": 0,
"k": 0
}
},
// 4. 组变换
{ "ty": "tr" }
]
}
]
}
]
}
八、高级特性 - 蒙版、效果、表达式
本章将简要介绍 Lottie 中几个高级但常用的特性。理解这些概念有助于您阅读和分析更复杂的动画文件,但在实际创作中,请注意它们在不同平台和渲染器中的支持程度可能有所差异。
蒙版(Mask):masksProperties 数组
蒙版用于控制图层的显示区域,实现剪切、遮罩等效果。在图层对象中,通过 masksProperties 数组定义。
json
json
"masksProperties": [
{
"mode": "a", // 蒙版模式:a=相加,s=相减,i=相交等
"pt": { // 路径(Path),定义蒙版形状
"a": 0,
"k": { "v": [[0,0], [100,0], [100,100], [0,100]], "c": true }
},
"o": { "a": 0, "k": 100 }, // 不透明度(Opacity)
"inv": false, // 是否反转(Inverted)
"nm": "蒙版1" // 名称(Name)
}
]
关键属性:
-
mode:蒙版混合模式。除了常用的"a"(Add,相加)和"s"(Subtract,相减),Lottie Schema 还定义了其他模式,但并非所有都被完全支持。模式代码 名称 (英文) 作用效果 "n"None (无) 禁用蒙版 "a"Add (相加) 合并多个蒙版区域 "s"Subtract (相减) 从现有区域中减去 "i"Intersect (相交) 只保留蒙版重叠区域 "l"Lighten (变亮) 保留较亮区域 "d"Darken (变暗) 保留较暗区域 "f"Difference (差异) 显示颜色差异区域 -
pt:蒙版路径,其数据结构(含v,i,o)与形状图层中的自由路径(sh)完全相同。 -
o:蒙版的不透明度。 -
inv:布尔值,为true时反转蒙版区域。
效果(Effects):ef 数组
Lottie 支持部分 After Effects 内置效果,通过图层的 ef 数组定义。请注意,支持的效果非常有限,且并非所有AE效果都能被完美支持或渲染。
根据官方 Schema 文档,有明确定义的效果类型包括:
- 填充 (Fill):
ty: 21 - 描边 (Stroke):
ty: 22 - 色调 (Tint):
ty: 20 - 三色调/专业色阶 (Tritone/Pro Levels):
ty: 23
json
json
"ef": [{
"ty": 21, // 效果类型:21 = 填充 (Fill)
"nm": "颜色叠加",
"en": 1, // 启用 (Enabled)
"ef": [{
"ty": 10,
"nm": "颜色",
"v": { "a": 0, "k": [1, 0, 0, 1] } // 红色
}]
}]
重要说明 :"高斯模糊 (
ty: 29)"和"发光 (ty: 27)"等效果在公开的官方 Schema 文档中未有明确定义 。它们可能由 Bodymovin 插件导出,但不一定被所有 Lottie 渲染器支持,在实际使用前必须进行充分的兼容性测试。
表达式(Expression):x 字段
表达式是 After Effects 中用于创建属性间动态关联的脚本语言。在 Lottie 中,表达式可以存储在属性的 x 字段中。
json
css
"p": {
"a": 1,
"k": [{"t":0, "s":[0,0]}, {"t":30, "s":[100,100]}],
"x": "loopOut('cycle')" // 表达式:循环播放动画
}
表达式的作用与局限性:
- 作用 :可以创建循环 (
loopOut)、随机 (wiggle)、数学关联等复杂动画逻辑,无需大量关键帧。 - 局限性 :平台支持极不完整。仅有少数最基础的表达式可能在部分平台上被识别,复杂的表达式通常会被忽略或导致动画错误。在需要跨平台稳定播放的动画中,应尽量避免使用表达式。
混合模式(Blend Mode):bm 字段
混合模式控制当前图层如何与下层图层进行颜色混合。在图层(根对象)或形状样式元素(如 fl, st)中通过 bm 字段定义。
json
json
"bm": 3 // 叠加模式 (Overlay)
混合模式值速查表 (根据官方 /helpers/blendMode.json):
| 值 | 模式 (英文) | 值 | 模式 (英文) |
|---|---|---|---|
| 0 | Normal (正常) | 8 | Hard Light (强光) |
| 1 | Multiply (相乘) | 9 | Soft Light (柔光) |
| 2 | Screen (屏幕) | 10 | Difference (差值) |
| 3 | Overlay (叠加) | 11 | Exclusion (排除) |
| 4 | Darken (变暗) | 12 | Hue (色相) |
| 5 | Lighten (变亮) | 13 | Saturation (饱和度) |
| 6 | Color Dodge (颜色减淡) | 14 | Color (颜色) |
| 7 | Color Burn (颜色加深) | 15 | Luminosity (明度) |
注意:混合模式在 SVG/HTML 渲染器中支持较好,在其他渲染器(如 Canvas)或某些移动端平台中可能需要降级处理或不被支持。
九、结语
本文系统性地解析了 Lottie JSON 的核心数据结构。以下是全文知识要点的回顾与总结:
核心数据结构总览
| 模块 | 关键对象/字段 | 核心作用与要点 |
|---|---|---|
| 顶层结构 | v, fr, ip, op, w, h |
定义动画全局信息:版本、帧率、时间轴、画布尺寸。 |
assets, layers, chars |
三大数据支柱:可复用资源、图层序列、矢量字形。 | |
| 图层系统 | ty (0-5) |
标识六种图层类型:预合成、纯色、图像、空对象、形状、文本。 |
ind, parent, ip, op, st |
控制图层索引、父子关系、时间属性(入点、出点、起始时间)。 | |
ks |
变换属性容器 ,包含锚点(a)、位置(p)、缩放(s)、旋转(r)、透明度(o)等。 |
|
| 动画系统 | ks 下的 a 字段 |
属性动画开关:0为静态值,1为动画值(关键帧数组)。 |
关键帧 k 数组 |
定义动画轨迹,包含时间(t)、值(s/e)、缓动(i/o)。 |
|
| 形状系统 | shapes 数组 |
形状图层的核心容器,元素按索引顺序渲染叠加。 |
ty: el/rc/sr/sh |
基础图形:椭圆、矩形、星形、自由路径(贝塞尔曲线定义)。 | |
ty: gr (组) |
使用 it 数组组织子元素,实现层级管理与统一变换。 |
|
| 样式系统 | ty: fl (填充) |
定义形状填充色(纯色或渐变)。 |
ty: st (描边) |
定义轮廓线样式,包括线宽(w)、端点(lc)、连接(lj)。 |
|
| 修改器 | ty: tm (Trim) |
路径裁剪,通过动画起点(s)、终点(e)、偏移(o)实现绘制效果。 |
ty: rp (Repeater) |
图形重复器,通过副本数(c)和增量变换(tr)创建阵列。 |
|
| 高级特性 | masksProperties |
蒙版数组,通过路径(pt)和模式(mode)控制图层显示区域。 |
ef (效果), bm (混合模式) |
实现滤镜与图层混合,需注意平台支持度。 | |
x (表达式) |
支持简单表达式驱动属性,跨平台支持有限。 |
十、写在最后:笔者的思考💡
在整理 Lottie 的技术细节时,我反复思考一个核心问题:我们看到的这套 JSON 结构,到底是由什么决定的?
最直接的答案是"为了在网页上播放"。但这只是目的,并未解释其形态。我的思路分两步推进:第一,是 Web 的渲染能力(如 Canvas)限制了它的设计;第二,是否有更底层的蓝本在主导结构。
通过逐项对比,我找到了更关键的依据。Lottie JSON 的结构,本质上是对 After Effects 内部动画数据模型的直接翻译。 例如,JSON 中的 ks 对象精确对应了 AE 图层的"变换"属性组,shapes 数组则完全复现了 AE 形状层的堆叠逻辑。设计者的首要任务,是为 AE 的动画状态提供一个无损且精确的数据描述格式。
那么,Web 技术(如 Canvas/SVG)的作用是什么?我认为它主要扮演了 "支持度评估"与"性能优化"的角色。它并未改变数据描述的根本方式,而是基于实现难度与性能成本,划定了哪些 AE 高级功能可以(或不可以)被包含在这个格式中。例如,一些复杂的实时滤镜可能因性能考量而被排除。
这自然引向更深一层:AE 自身的这套强大模型又是如何建立的? 它并非凭空创造,而是对更早行业的数字化融合。其"合成"与"图层"概念源自电影工业 的胶片叠加流程;"关键帧"动画继承自传统手绘动画 的生产方式;而所有视觉变换的根基,则是计算机图形学提供的数学工具(如坐标变换、贝塞尔曲线)。
因此,学习 Lottie 最有效的方法,并非孤立记忆 JSON 字段,而是理解它作为"AE 模型的数据接口"这一定位 。掌握 AE 的核心概念,就能理解 Lottie 绝大部分的设计逻辑。这揭示了一种高效的学习路径:当面对一个出色的"技术转译层"时,直接研究它所转译的源系统,往往是理解其设计最快的方式。