How Lottie Turns JSON Into Smooth Web Animations: A Deep Dive
This article explains how Lottie uses JSON exported from Adobe After Effects via the Bodymovin plugin to render vector animations on the web, detailing the export workflow, JSON structure, renderer initialization, layer processing, and the requestAnimationFrame‑driven playback loop with code examples.
Introduction
Lottie enables complex frame‑based animations created in Adobe After Effects (AE) to be exported as a JSON file via the Bodymovin extension and rendered on web, Android, iOS, or React Native using the Lottie library.
1. Implementing a Lottie Animation
Designer creates the animation in AE.
Bodymovin exports the animation as a JSON file.
Developer loads lottie-web, provides the JSON data, and initializes the animation.
import lottie from 'lottie-web';
import animationJsonData from 'xxx-demo.json'; // exported JSON
const anim = lottie.loadAnimation({
container: document.getElementById('lottie'),
renderer: 'svg', // 'svg', 'canvas' or 'html'
loop: true,
autoplay: false,
animationData: animationJsonData,
});
// start playback
anim.play();Additional JSON animation templates can be found at https://lottiefiles.com/.
2. Decoding the JSON Data Format
The exported JSON contains global settings, assets, and layer definitions. w / h: canvas width and height (e.g., 200 × 200). v: Bodymovin version (e.g., 4.5.4). fr: frame rate (e.g., 30 fps). ip / op: start and end frames (e.g., 0 – 180 for a 6 s animation at 30 fps). assets: static resources such as images. layers: array of layer objects, each describing geometry, transformation, and animation data. ddd: 3‑D flag. comps: composition information.
2.1 Global Information
Lottie calculates animation time in frames, not milliseconds. For a 30 fps animation, 0 – 6 seconds corresponds to frames 0 – 180.
2.2 Layer‑Related Information
Each layer has a ty field that identifies its type (shape, image, text, etc.). In the demo there is a single shape layer ( ty = 4). Layer data is divided into three logical areas:
Content – size, position, corner radius, etc.
Transformation – anchor point, position, scale, rotation, opacity.
Keyframes – three keyframes (0, 90, 180) modify the scale property; at frame 90 the layer scales to 50 %.
2.3 Property‑Change Information
The ks object holds keyframe data. Important sub‑fields: t: keyframe time (in frames). s: start value (for 2‑D layers the third component is always 100). e: end value.
3. How Lottie Animates the JSON
3.1 Initializing the Renderer
lottie.loadAnimationcreates an AnimationItem instance, registers event listeners ( destroy, _active, _idle) and selects a renderer based on the renderer option.
function loadAnimation(params) {
var animItem = new AnimationItem();
setupAnimation(animItem, null);
animItem.setParams(params);
return animItem;
}
function setupAnimation(animItem, element) {
animItem.addEventListener('destroy', removeElement);
animItem.addEventListener('_active', addPlayingCount);
animItem.addEventListener('_idle', subtractPlayingCount);
registeredAnimations.push({ elem: element, animation: animItem });
}The chosen renderer (SVG in most cases) inherits from BaseRenderer and implements the actual drawing logic.
3.2 Loading Static Resources
configAnimationcomputes total frames, frame rate, and preloads assets (images, fonts) before drawing the first frame.
AnimationItem.prototype.configAnimation = function(animData) {
if (!this.renderer) { return; }
this.totalFrames = Math.floor(this.animationData.op - this.animationData.ip);
this.firstFrame = Math.round(this.animationData.ip);
this.renderer.configAnimation(animData);
this.frameRate = this.animationData.fr;
this.frameMult = this.animationData.fr / 1000;
this.trigger('config_ready');
this.preloadImages();
this.loadSegments();
this.updaFrameModifier();
this.waitForFontsLoaded();
};3.3 Drawing Initial Layers
initItemscalls buildAllItems, which creates a concrete element for each layer based on its ty value. The eight possible types are composition (0), solid (1), image (2), null (3), shape (4), text (5), audio (6), and camera (13).
BaseRenderer.prototype.createItem = function(layer) {
switch (layer.ty) {
case 0: return this.createComp(layer);
case 1: return this.createSolid(layer);
case 2: return this.createImage(layer);
case 3: return this.createNull(layer);
case 4: return this.createShape(layer);
case 5: return this.createText(layer);
case 6: return this.createAudio(layer);
case 13: return this.createCamera(layer);
}
return this.createNull(layer);
};In the demo the only layer is a shape, so only createShape runs.
3.4 Animation Playback
Calling play triggers the _active event, which starts a requestAnimationFrame loop.
AnimationItem.prototype.play = function(name) {
this.trigger('_active');
};
function activate() {
window.requestAnimationFrame(first);
}The first function records the start time and schedules resume on the next frame. resume calculates elapsed time, converts it to a frame increment using frameModifier = fr / 1000, updates the current raw frame, and renders the frame.
function resume(nowTime) {
var elapsed = nowTime - initTime;
var next = this.currentRawFrame + elapsed * this.frameModifier;
this.setCurrentRawFrameValue(next);
initTime = nowTime;
if (playingAnimationsNum && !_isFrozen) {
window.requestAnimationFrame(resume);
}
}
AnimationItem.prototype.setCurrentRawFrameValue = function(value) {
this.currentRawFrame = value;
this.renderFrame();
};During each render, TransformPropertyFactory interpolates keyframe values (scale, rotation, position, opacity) and produces a CSS matrix that is applied to the DOM element. Because requestAnimationFrame runs at ~60 fps, Lottie can compute sub‑frame values for a smoother 30 fps animation.
4. Advantages and Limitations
Designers work entirely in AE; developers render the exported JSON without recreating the animation.
SVG output scales without loss of quality.
JSON files are reusable across Web, Android, iOS, and React Native.
JSON size is typically much smaller than GIF or APNG, improving performance.
Lottie‑web library size is relatively large (≈513 KB uncompressed, 144 KB minified, 39 KB gzipped).
Exporting each frame as an image inflates the JSON size.
Some AE effects are unsupported or have performance constraints.
5. References
https://github.com/airbnb/lottie-web/
http://airbnb.io/lottie/#/
https://www.zhangxinxu.com/wordpress/2012/06/css3-transform-matrix-%E7%9F%A9%E9%98%B5/
https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
