calesthio/lottie-animation-delivery
Production guidance for assessing, exporting, packaging, integrating, capturing, validating, and handing off Lottie vector animations. Use for Bodymovin/Lottie JSON, dotLottie archives, renderer and player compatibility, fonts and glyphs, image assets, markers and segments, deterministic video capture, responsive sizing, optimization, accessibility, and cross-platform QA; not for general After Effects animation craft or live-action/video delivery.
npx skills add https://github.com/calesthio/generative-media-skills --skill lottie-animation-delivery
Use this skill when a designed vector animation must move reliably from an authoring tool into web, mobile, application, or rendered-video players. The production problem is interchange: preserving intended motion, typography, assets, timing, accessibility, and control across implementations with different feature support.
Lottie is not a universal After Effects renderer. Treat the target-player matrix as an input before animation is finalized, not as a test performed only after export.
Facts were checked 2026-07-12. The official Lottie specification describes itself as a work in progress. Player feature support, exporter options, dotLottie versions, state machines, themes, and package APIs can change. Record exact exporter/player versions and re-check their current documentation.
Use Lottie when the deliverable benefits from:
Choose another format when:
Documented fact: the AE Feature Support section of the official lottie-web README says video, audio, and image sequences are not supported by its Bodymovin export/player path. Treat audio as a separately synchronized media asset in the host composition.
Record:
.lottie deliverables and required dotLottie version;Create one minimal feature fixture per risky capability and test it in every target before authoring many animations.
Documented facts: a Lottie document is JSON with an Animation object at the root. Animation data includes dimensions, frame rate, in/out points, layers, assets, and animated properties. Keyframes are ordered by frame and can use holds or cubic-bezier easing. Layers can be parented so child transforms compose with parent transforms.
This makes Lottie suitable for time-addressable vector motion, but a valid document does not prove identical rendering in every player. The specification covers an expanding subset of the ecosystem, and players may implement additional, missing, or different behavior.
Keep a compatibility ledger:
feature | source usage | web-svg | web-canvas | ios | android | dotlottie-player | fallback
Populate it with tested results for the pinned versions. Do not copy a generic support table into production approval.
Bodymovin/lottie-web commonly exports supported After Effects compositions to JSON. Before export:
Documented facts from lottie-web: Bodymovin supports common shapes, precompositions, solids, images, nulls, text, masks, and time remapping, with limitations. Its composition options include converting text to glyph shapes; including hidden/guided layers when referenced; exporting extra compositions; and preserving original raster-asset names. Hidden and guided layers increase output when included.
Use the exporter's report/preview plus target-player tests. A clean exporter preview is not cross-platform validation.
Choose glyph conversion when copy is fixed and exact visual shape matters. It removes runtime font loading as a rendering dependency, but increases vector data, loses normal text semantics/editability, and needs re-export for copy or localization changes.
Choose runtime text when localization or dynamic copy is required and the target player supports the needed text behavior. Package or preload licensed fonts before animation initialization; test shaping, line breaks, fallback, glyph coverage, right-to-left scripts, combining marks, and locale expansion in every player.
Do not assume a Latin fixture validates Arabic, Devanagari, CJK, or another script. Do not outline copy that must remain accessible or dynamically translated without providing an equivalent semantic text layer in the host.
Text decision record:
Inventory every non-shape feature. Test combinations, not only isolated features.
Mask and matte behavior can differ by renderer/player. Test edge quality, inverted/subtractive behavior, nesting, alpha, crop, and performance. If a target fails, simplify the construction, convert it to supported vector geometry, pre-render that element, or change the delivery format.
Do not assume AE effects or blend modes have portable equivalents. Use only the subset proven in the target matrix. Compare the result against reference frames over light, dark, transparent, and real host backgrounds.
Expressions add portability and determinism risk. lottie-web exposes a renderer setting that can disable expressions. Where expressions are required:
Raw Lottie JSON may reference image/font assets separately or embed some resources. It is simple and broadly understood but can produce multi-file custody problems.
Documented fact: dotLottie packages one or more Lottie JSON animations and resources into a Deflate-compressed ZIP archive with .lottie extension. In dotLottie v2, manifest.json and the a/ animations directory are required; i/, f/, t/, and s/ can contain images, fonts, themes, and state machines. The manifest requires a version and at least one animation entry.
Version choice matters. The official dotLottie documentation labels v2 as recommended for new projects and v1 as widely supported. Verify target-player support before choosing v2 features such as themes or state machines.
Package rules:
Do not hand-edit generated JSON or archives without recording the transformation and rerunning validation/reference comparisons.
Documented facts from lottie-web: animation instances support controls including play, pause, stop, speed, direction, goToAndStop, goToAndPlay, playSegments, setSubframe, getDuration, and destroy. Frame-based seeking is selected with the isFrame argument. setSubframe(false) respects the source composition fps; the default subframe mode updates with intermediate values.
Use markers as stable semantic edit/state names such as idle, focus, success, and reset. Verify exact names, start frames, durations, boundary semantics, and fallback behavior in each player. For dotLottie v2 state-machine segments, the specification says a missing marker falls back to the full animation range; treat that as a validation defect rather than a safe default.
Test:
destroy() or the target equivalent.If the same animationData object containing repeaters is loaded into lottie-web more than once, the official README advises deep-cloning it per load because internal mutation can affect instances.
For frame-rendered video, disable autoplay and seek explicitly after data, DOM, fonts, and images are ready.
Example lottie-web capture shape:
const animation = lottie.loadAnimation({
container,
renderer: "svg",
loop: false,
autoplay: false,
animationData,
});
await readyForCapture(animation, fonts, assets);
animation.setSubframe(false);
export function renderFrame(frame) {
animation.goToAndStop(frame, true);
}
The readiness helper is host-specific. Listen for and verify the relevant data/DOM/image readiness events and font promises; do not rely on a fixed delay.
Capture requirements:
Decide subframe behavior from the contract. Source-frame capture commonly uses setSubframe(false). If the host output fps differs and intermediate rendering is desired, test the chosen interpolation and frame mapping explicitly instead of assuming it preserves timing.
lottie-web renderer settings expose preserveAspectRatio behavior for SVG and Canvas. Decide whether each canvas should meet, slice, or use a separately authored composition.
meet preserves the whole artboard but may letterbox.slice fills the box but can crop essential content.For materially different aspect ratios, produce separate layouts or source comps when crop rules cannot preserve the message. Test line weight, small type, masks, filter bounds, and raster assets at final dimensions.
Optimize after visual correctness and target compatibility are established:
Measure package size, parse/load time, first rendered frame, steady playback, memory, and teardown. Test low-end target devices and multiple simultaneous instances if that is the product use.
For interactive surfaces:
(prefers-reduced-motion: reduce) by disabling autoplay, reducing movement, selecting a calm segment, or showing a static poster;lottie-web supports SVG renderer settings for a title and description, but this does not replace accessible host semantics or a fallback for Canvas/other players.
For prerecorded exports, render a reduced-motion variant if needed; CSS cannot change pixels already encoded in a video.
Documented fact: WCAG 2.2 SC 2.3.1 restricts flashing above three times in one second unless below threshold. Test loops while looping and at the largest intended view. SC 2.3.3 says non-essential interaction-triggered motion can be disabled unless essential.
lottie-web is MIT-licensed. That license does not clear source artwork, After Effects projects, fonts, logos, images, plugins, characters, or downloaded animation files. A file being technically editable or publicly viewable is not evidence of commercial rights.
Maintain:
Preserve required notices and escalate unclear marketplace, template, branded, likeness, or derivative rights.
Validate in layers:
Critical failures include missing assets, wrong copy/font, unsupported feature changing meaning, nondeterministic frame capture, broken segment/state fallback, unsafe flashing, no reduced-motion handling where required, or unverified rights.
Provide:
.lottie package;This is a complete example, not a mandatory formula.
Intent: deliver a three-state onboarding illustration (idle, scan, success) for web, iOS, and Android in six locales.
Constraints: dynamic localized label; no audio; 320x320 logical artboard; host button provides interaction semantics; reduced-motion mode; one small raster texture; offline use.
Workflow:
idle-poster and success-poster marker frames after export. Reduced-motion mode seeks directly to those frames and replaces the scan sweep with a short opacity change.Expected result: exact localized text, equivalent visual states, no inaccessible animation-only status, and no remote dependencies.
Likely failures: font initializes too late; one script shapes incorrectly; marker boundaries differ; mobile player drops a mask; the raster texture is missing offline; repeated loads share mutated data.
Variation: if cross-player runtime text cannot pass, export locale-specific glyph animations while keeping semantic label text in the host UI.
This is a complete example, not a mandatory formula.
Intent: use an approved eight-second vector route animation as a deterministic overlay in a 30 fps product video.
Constraints: transparent background; exact frame alignment to narration; SVG renderer in a pinned headless browser; no interaction; separate narration/music; final 1920x1080 and 1080x1920 versions.
Workflow:
goToAndStop(..., true); capture alpha through the host compositor.slice crops route labels.Expected result: repeated frame identity within the locked browser environment, correct alpha, exact narration cues, and equivalent horizontal/vertical message.
Likely failures: fixed-delay readiness misses an image; source/output fps mapping is off by one; autoplay advances before capture; remote font changes wrapping; vertical crop cuts labels; final loop frame duplicates the first.
Variation: when a target renderer cannot reproduce a required matte, pre-render the approved Lottie layer to a lossless alpha sequence and document that the interactive asset and video derivative have different delivery paths.
Official and authoritative sources checked 2026-07-12:
AE Feature Support, usage, and license: https://github.com/airbnb/lottie-web#ae-feature-supportprefers-reduced-motion: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motionTake calesthio/lottie-animation-delivery from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.