{"course":{"slug":"motion-and-audio","title":"Motion, Sound and Music","url":"https://addaly.com/learn/motion-and-audio","level":"intermediate","track":"create"},"lesson":{"slug":"lottie-and-its-limits","title":"What Lottie carries and what it drops","url":"https://addaly.com/learn/motion-and-audio/lottie-and-its-limits","position":20,"of":72,"minutes":10,"answer":"A Lottie file is a list of shapes with keyframed properties, so anything that is not expressible that way (effects, most expressions, motion blur, cameras) does not survive the export.","keyIdea":"A Lottie file is a list of shapes with keyframed properties, so anything that is not expressible that way (effects, most expressions, motion blur, cameras) does not survive the export, and imported raster images are base64-inflated into the JSON rather than compressed."},"body":{"format":"markdown","text":"## What a Lottie file actually is\n\nA Lottie file is JSON. Open one in a text editor and you will find a list of layers, each with a set of animated properties, each property a list of keyframes with values and bezier handles. There are no pixels in it unless an image was imported, in which case that image sits inside the JSON as a base64 string and the file size jumps accordingly.\n\nIt is produced by exporting from After Effects with the **Bodymovin** plugin, or from Glaxnimate, Haiku, or any of several open-source writers. It is played back by a runtime: `lottie-web` in a browser, `lottie-ios`, `lottie-android`, and ports for Flutter, React Native and others. The runtime reads the keyframes and redraws the shapes every frame.\n\nThat is the whole idea, and it explains both its strengths and every one of its failures. The strengths: a 40KB file that renders crisply at any size, on any platform, with the same timing, and that a designer can replace without a developer. The failures: anything that is not expressible as \"shapes with animated properties\" does not survive the export.\n\n## What does not export\n\nThis is the list that costs people a day each time they rediscover it.\n\n- **Effects.** Almost all of them. Glow, drop shadow as an effect, blur, distortions, generate effects: gone, or approximated badly. Build glow with actual shapes and opacity.\n- **Expressions.** Newer runtimes support a limited subset, but an expression-driven rig is not portable. Bodymovin can bake expressions into keyframes on export, which works and produces a much larger file.\n- **Merge paths.** Supported in some renderers and not others, which is worse than unsupported because it works on your machine.\n- **Layer styles**, **3D layers** with real depth, **cameras**, **motion blur**, **time remapping**, **adjustment layers**, **track mattes beyond the simple cases**.\n- **Auto-orient**, **parenting past certain depths**, and most expression controls.\n\nThe rule the export gives you: **shape layers, solids, precomps, masks, simple track mattes, and transform properties**. Build inside that box and the file behaves everywhere.\n\n## The two renderers\n\n`lottie-web` can draw with SVG, canvas, or HTML. The choice matters more than most people realise.\n\n**SVG renderer** (the default) creates a DOM element for every shape, group and mask. Crisp at any scale, correct anti-aliasing, works with CSS. It also means a file with 400 shapes creates roughly 400 nodes that are re-laid-out every frame. Past a few hundred, this becomes visible main-thread work, and on a low-end phone it stutters.\n\n**Canvas renderer** draws to a single element. Far faster on complex files. You lose per-shape CSS control and you have to redraw on resize to keep it sharp, because the canvas is a fixed pixel buffer.\n\nThe practical test: render your file, open the DevTools performance panel, and look at the main thread during playback. If you see a solid block of scripting work at 16ms intervals, switch renderer.\n\n## The sizes and the traps\n\nA typical illustrated Lottie is 15 to 60KB. Two things blow that up:\n\n**Imported raster images.** They are base64-encoded into the JSON, which adds about 33 per cent to their size on top of losing all compression benefits. A Lottie with a photograph in it is not a vector file with a small extra; it is a badly packed image file with some vectors attached. Keep images external where the runtime supports it, or do not use them.\n\n**Baked expressions and very dense keyframes.** An expression sampled per frame for ten seconds at 60fps is 600 keyframes on that property. Reduce the frame rate of the export (24 or 30 is almost always enough) and the file halves.\n\n**dotLottie** (`.lottie`) is a zip containing the JSON plus any assets. It is typically 50 to 80 per cent smaller than the raw JSON for image-bearing files and has a cleaner story for multiple animations in one bundle. Support is now good across the official runtimes.\n\n## Controlling it\n\nThis is where Lottie beats a video. The runtime exposes the timeline:\n\n```js\nconst anim = lottie.loadAnimation({\n  container: el, renderer: 'svg', loop: false,\n  autoplay: false, path: '/motion/checkout.json'\n});\nanim.playSegments([0, 40], true);   // the \"loading\" portion\nanim.setSpeed(1.2);\nanim.goToAndStop(38, true);          // frame-accurate hold\n```\n\nMarking sections of a single file and playing segments is how you build a state-driven animation without a separate file per state. Name your frame ranges in the handover, because a developer cannot find them by looking.\n\n## Honouring reduced motion\n\nA looping Lottie is continuous motion and belongs inside the reduced-motion rules from the previous module. The runtime cannot know; you have to check the media query and either call `goToAndStop` on a representative frame or not load the animation at all. Shipping a static poster frame as an SVG for that case is a five-minute job that almost nobody does.\n\n## The free path\n\n- **Glaxnimate**: open source, authors and exports Lottie directly, no After Effects required.\n- **python-lottie**: a library that reads, writes and converts Lottie files, useful for batch edits and for stripping unsupported features.\n- **LottieFiles** has a free tier with a preview and optimiser; the file format itself is open and none of the tooling is mandatory.\n- **Blender** with grease pencil for authoring, exported through an SVG sequence, is a viable if awkward free route for frame-by-frame vector work.\n\n## The limitation\n\nLottie's compatibility story is not one thing. The web, iOS and Android runtimes have historically differed in exactly which features they implement, and a file that looks right in one can be subtly wrong in another: a mask that clips differently, a trim path that runs backwards, a gradient that bands. There is no conformance suite that settles it.\n\nSo the only safe process is to preview the exported file on every target platform before sign-off, not in the design tool. The design tool is not the renderer, and the difference between them is where the day goes."},"check":{"question":"A Lottie file is 1.4MB and stutters on a mid-range phone. The designer insists the composition is simple. What are the two most likely causes, given how the format works?","options":[{"text":"A raster image has been embedded as base64 inside the JSON, and the SVG renderer is creating a DOM node per shape that is re-laid-out every frame.","correct":true},{"text":"The animation was exported at 60fps instead of 24, which quadruples the rendering cost per second because the runtime must interpolate four times as many intermediate values.","correct":false,"tempting":"Export frame rate affects keyframe density and file size, but the runtime redraws at the display rate regardless of the authored frame rate."},{"text":"Expressions in the composition are being evaluated live by the runtime on every frame, which is the main source of per-frame cost in any Lottie file.","correct":false,"tempting":"Expressions are baked to keyframes at export or unsupported; they inflate the file rather than running live."},{"text":"The file is using the canvas renderer, which rasterises the entire composition at device pixel ratio on every frame and is therefore always slower than the SVG renderer for complex artwork.","correct":false,"tempting":"Inverts the two renderers: canvas is generally faster on complex files, and SVG is the one whose cost grows with node count."}]},"prev":{"slug":"which-technology","title":"Five ways to put motion on a screen","url":"https://addaly.com/learn/motion-and-audio/which-technology"},"next":{"slug":"svg-animation","title":"Animating a drawing that is also a document","url":"https://addaly.com/learn/motion-and-audio/svg-animation"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'What Lottie carries and what it drops', in Motion, Sound and Music. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/motion-and-audio/lottie-and-its-limits (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"What Lottie carries and what it drops","courseTitle":"Motion, Sound and Music","module":{"index":3,"slug":"shipping-the-motion","title":"Shipping the motion"},"answer":null,"keyIdea":"A Lottie file is a list of shapes with keyframed properties, so anything that is not expressible that way (effects, most expressions, motion blur, cameras) does not survive the export, and imported raster images are base64-inflated into the JSON rather than compressed.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"what-a-lottie-file-actually-is","runs":[{"text":"What a Lottie file actually is"}]},{"t":"p","runs":[{"text":"A Lottie file is JSON. Open one in a text editor and you will find a list of layers, each with a set of animated properties, each property a list of keyframes with values and bezier handles. There are no pixels in it unless an image was imported, in which case that image sits inside the JSON as a base64 string and the file size jumps accordingly."}]},{"t":"p","runs":[{"text":"It is produced by exporting from After Effects with the "},{"text":"Bodymovin","b":true},{"text":" plugin, or from Glaxnimate, Haiku, or any of several open-source writers. It is played back by a runtime: "},{"text":"lottie-web","code":true},{"text":" in a browser, "},{"text":"lottie-ios","code":true},{"text":", "},{"text":"lottie-android","code":true},{"text":", and ports for Flutter, React Native and others. The runtime reads the keyframes and redraws the shapes every frame."}]},{"t":"p","runs":[{"text":"That is the whole idea, and it explains both its strengths and every one of its failures. The strengths: a 40KB file that renders crisply at any size, on any platform, with the same timing, and that a designer can replace without a developer. The failures: anything that is not expressible as “shapes with animated properties” does not survive the export."}]},{"t":"h2","id":"what-does-not-export","runs":[{"text":"What does not export"}]},{"t":"p","runs":[{"text":"This is the list that costs people a day each time they rediscover it."}]},{"t":"ul","items":[[{"text":"Effects.","b":true},{"text":" Almost all of them. Glow, drop shadow as an effect, blur, distortions, generate effects: gone, or approximated badly. Build glow with actual shapes and opacity."}],[{"text":"Expressions.","b":true},{"text":" Newer runtimes support a limited subset, but an expression-driven rig is not portable. Bodymovin can bake expressions into keyframes on export, which works and produces a much larger file."}],[{"text":"Merge paths.","b":true},{"text":" Supported in some renderers and not others, which is worse than unsupported because it works on your machine."}],[{"text":"Layer styles","b":true},{"text":", "},{"text":"3D layers","b":true},{"text":" with real depth, "},{"text":"cameras","b":true},{"text":", "},{"text":"motion blur","b":true},{"text":", "},{"text":"time remapping","b":true},{"text":", "},{"text":"adjustment layers","b":true},{"text":", "},{"text":"track mattes beyond the simple cases","b":true},{"text":"."}],[{"text":"Auto-orient","b":true},{"text":", "},{"text":"parenting past certain depths","b":true},{"text":", and most expression controls."}]]},{"t":"p","runs":[{"text":"The rule the export gives you: "},{"text":"shape layers, solids, precomps, masks, simple track mattes, and transform properties","b":true},{"text":". Build inside that box and the file behaves everywhere."}]},{"t":"h2","id":"the-two-renderers","runs":[{"text":"The two renderers"}]},{"t":"p","runs":[{"text":"lottie-web","code":true},{"text":" can draw with SVG, canvas, or HTML. The choice matters more than most people realise."}]},{"t":"p","runs":[{"text":"SVG renderer","b":true},{"text":" (the default) creates a DOM element for every shape, group and mask. Crisp at any scale, correct anti-aliasing, works with CSS. It also means a file with 400 shapes creates roughly 400 nodes that are re-laid-out every frame. Past a few hundred, this becomes visible main-thread work, and on a low-end phone it stutters."}]},{"t":"p","runs":[{"text":"Canvas renderer","b":true},{"text":" draws to a single element. Far faster on complex files. You lose per-shape CSS control and you have to redraw on resize to keep it sharp, because the canvas is a fixed pixel buffer."}]},{"t":"p","runs":[{"text":"The practical test: render your file, open the DevTools performance panel, and look at the main thread during playback. If you see a solid block of scripting work at 16ms intervals, switch renderer."}]},{"t":"h2","id":"the-sizes-and-the-traps","runs":[{"text":"The sizes and the traps"}]},{"t":"p","runs":[{"text":"A typical illustrated Lottie is 15 to 60KB. Two things blow that up:"}]},{"t":"p","runs":[{"text":"Imported raster images.","b":true},{"text":" They are base64-encoded into the JSON, which adds about 33 per cent to their size on top of losing all compression benefits. A Lottie with a photograph in it is not a vector file with a small extra; it is a badly packed image file with some vectors attached. Keep images external where the runtime supports it, or do not use them."}]},{"t":"p","runs":[{"text":"Baked expressions and very dense keyframes.","b":true},{"text":" An expression sampled per frame for ten seconds at 60fps is 600 keyframes on that property. Reduce the frame rate of the export (24 or 30 is almost always enough) and the file halves."}]},{"t":"p","runs":[{"text":"dotLottie","b":true},{"text":" ("},{"text":".lottie","code":true},{"text":") is a zip containing the JSON plus any assets. It is typically 50 to 80 per cent smaller than the raw JSON for image-bearing files and has a cleaner story for multiple animations in one bundle. Support is now good across the official runtimes."}]},{"t":"h2","id":"controlling-it","runs":[{"text":"Controlling it"}]},{"t":"p","runs":[{"text":"This is where Lottie beats a video. The runtime exposes the timeline:"}]},{"t":"code","lang":"js","label":"JavaScript","text":"const anim = lottie.loadAnimation({\n  container: el, renderer: 'svg', loop: false,\n  autoplay: false, path: '/motion/checkout.json'\n});\nanim.playSegments([0, 40], true);   // the \"loading\" portion\nanim.setSpeed(1.2);\nanim.goToAndStop(38, true);          // frame-accurate hold"},{"t":"p","runs":[{"text":"Marking sections of a single file and playing segments is how you build a state-driven animation without a separate file per state. Name your frame ranges in the handover, because a developer cannot find them by looking."}]},{"t":"h2","id":"honouring-reduced-motion","runs":[{"text":"Honouring reduced motion"}]},{"t":"p","runs":[{"text":"A looping Lottie is continuous motion and belongs inside the reduced-motion rules from the previous module. The runtime cannot know; you have to check the media query and either call "},{"text":"goToAndStop","code":true},{"text":" on a representative frame or not load the animation at all. Shipping a static poster frame as an SVG for that case is a five-minute job that almost nobody does."}]},{"t":"h2","id":"the-free-path","runs":[{"text":"The free path"}],"role":"free"},{"t":"ul","items":[[{"text":"Glaxnimate","b":true},{"text":": open source, authors and exports Lottie directly, no After Effects required."}],[{"text":"python-lottie","b":true},{"text":": a library that reads, writes and converts Lottie files, useful for batch edits and for stripping unsupported features."}],[{"text":"LottieFiles","b":true},{"text":" has a free tier with a preview and optimiser; the file format itself is open and none of the tooling is mandatory."}],[{"text":"Blender","b":true},{"text":" with grease pencil for authoring, exported through an SVG sequence, is a viable if awkward free route for frame-by-frame vector work."}]]},{"t":"h2","id":"the-limitation","runs":[{"text":"The limitation"}],"role":"limit"},{"t":"p","runs":[{"text":"Lottie’s compatibility story is not one thing. The web, iOS and Android runtimes have historically differed in exactly which features they implement, and a file that looks right in one can be subtly wrong in another: a mask that clips differently, a trim path that runs backwards, a gradient that bands. There is no conformance suite that settles it."}]},{"t":"p","runs":[{"text":"So the only safe process is to preview the exported file on every target platform before sign-off, not in the design tool. The design tool is not the renderer, and the difference between them is where the day goes."}]}],"check":{"question":[{"text":"A Lottie file is 1.4MB and stutters on a mid-range phone. The designer insists the composition is simple. What are the two most likely causes, given how the format works?"}],"options":[{"text":[{"text":"A raster image has been embedded as base64 inside the JSON, and the SVG renderer is creating a DOM node per shape that is re-laid-out every frame."}],"correct":true,"tempting":null},{"text":[{"text":"The animation was exported at 60fps instead of 24, which quadruples the rendering cost per second because the runtime must interpolate four times as many intermediate values."}],"correct":false,"tempting":[{"text":"Export frame rate affects keyframe density and file size, but the runtime redraws at the display rate regardless of the authored frame rate."}]},{"text":[{"text":"Expressions in the composition are being evaluated live by the runtime on every frame, which is the main source of per-frame cost in any Lottie file."}],"correct":false,"tempting":[{"text":"Expressions are baked to keyframes at export or unsupported; they inflate the file rather than running live."}]},{"text":[{"text":"The file is using the canvas renderer, which rasterises the entire composition at device pixel ratio on every frame and is therefore always slower than the SVG renderer for complex artwork."}],"correct":false,"tempting":[{"text":"Inverts the two renderers: canvas is generally faster on complex files, and SVG is the one whose cost grows with node count."}]}],"order":[1,3,2,0],"why":null},"prev":{"slug":"which-technology","title":"Five ways to put motion on a screen","minutes":10},"next":{"slug":"svg-animation","title":"Animating a drawing that is also a document","minutes":10}}}