plugins/bundles/animation-components/skills/lottie-animations/SKILL.md
After Effects animation rendering for web and React applications. Use this skill when implementing Lottie animations, JSON vector animations, interactive animated icons, micro-interactions, or loading animations. Triggers on tasks involving Lottie, lottie-web, lottie-react, dotLottie, After Effects JSON export, bodymovin, animated SVG alternatives, or designer-created animations. Complements GSAP ScrollTrigger and Framer Motion for scroll-driven and interactive animations.
npx skillsauth add freshtechbro/claudedesignskills lottie-animationsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Lottie is a library for rendering After Effects animations in real-time on web, iOS, Android, and React Native. Created by Airbnb, it allows designers to ship animations as easily as shipping static assets. Animations are exported from After Effects as JSON files using the Bodymovin plugin, then rendered natively with minimal performance overhead.
When to use Lottie:
Key advantages:
1. JSON Lottie (.json)
2. dotLottie (.lottie)
lottie-web (original library):
import lottie from 'lottie-web';
lottie.loadAnimation({
container: document.getElementById('lottie-container'),
renderer: 'svg', // or 'canvas', 'html'
loop: true,
autoplay: true,
path: 'animation.json' // or animationData: jsonData
});
@lottiefiles/dotlottie-web (modern, recommended):
import { DotLottie } from '@lottiefiles/dotlottie-web';
new DotLottie({
canvas: document.getElementById('canvas'),
src: 'animation.lottie',
autoplay: true,
loop: true
});
@lottiefiles/dotlottie-react (React integration):
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
<DotLottieReact
src="animation.lottie"
loop
autoplay
style={{ height: 300 }}
/>
lottie-react (alternative React wrapper):
import Lottie from 'lottie-react';
import animationData from './animation.json';
<Lottie animationData={animationData} loop={true} />
1. LottieFiles (lottie.host)
2. Local JSON/dotLottie files
3. After Effects export
<!DOCTYPE html>
<html>
<head>
<style>
#canvas {
width: 400px;
height: 400px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="module">
import { DotLottie } from 'https://cdn.jsdelivr.net/npm/@lottiefiles/dotlottie-web/+esm';
new DotLottie({
canvas: document.getElementById('canvas'),
src: 'https://lottie.host/4db68bbd-31f6-4cd8-84eb-189de081159a/IGmMCqhzpt.lottie',
autoplay: true,
loop: true
});
</script>
</body>
</html>
import React from 'react';
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
const AnimatedButton = () => {
const [dotLottie, setDotLottie] = React.useState(null);
const handlePlay = () => dotLottie?.play();
const handlePause = () => dotLottie?.pause();
const handleStop = () => dotLottie?.stop();
const handleSeek = (frame) => dotLottie?.setFrame(frame);
return (
<div>
<DotLottieReact
src="button-animation.lottie"
loop
autoplay={false}
dotLottieRefCallback={setDotLottie}
style={{ height: 200 }}
/>
<div>
<button onClick={handlePlay}>Play</button>
<button onClick={handlePause}>Pause</button>
<button onClick={handleStop}>Stop</button>
<button onClick={() => handleSeek(30)}>Seek to frame 30</button>
</div>
</div>
);
};
import React, { useEffect } from 'react';
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
const EventDrivenAnimation = () => {
const [dotLottie, setDotLottie] = React.useState(null);
useEffect(() => {
if (!dotLottie) return;
const onLoad = () => console.log('Animation loaded');
const onPlay = () => console.log('Animation started');
const onPause = () => console.log('Animation paused');
const onComplete = () => console.log('Animation completed');
const onFrame = ({ currentFrame }) => console.log('Frame:', currentFrame);
dotLottie.addEventListener('load', onLoad);
dotLottie.addEventListener('play', onPlay);
dotLottie.addEventListener('pause', onPause);
dotLottie.addEventListener('complete', onComplete);
dotLottie.addEventListener('frame', onFrame);
return () => {
dotLottie.removeEventListener('load', onLoad);
dotLottie.removeEventListener('play', onPlay);
dotLottie.removeEventListener('pause', onPause);
dotLottie.removeEventListener('complete', onComplete);
dotLottie.removeEventListener('frame', onFrame);
};
}, [dotLottie]);
return (
<DotLottieReact
src="animation.lottie"
loop
autoplay
dotLottieRefCallback={setDotLottie}
/>
);
};
import Lottie from 'lottie-react';
import robotAnimation from './robot.json';
const ScrollAnimation = () => {
const interactivity = {
mode: 'scroll',
actions: [
{
visibility: [0, 0.2],
type: 'stop',
frames: [0]
},
{
visibility: [0.2, 0.45],
type: 'seek',
frames: [0, 45]
},
{
visibility: [0.45, 1.0],
type: 'loop',
frames: [45, 60]
}
]
};
return (
<Lottie
animationData={robotAnimation}
style={{ height: 300 }}
interactivity={interactivity}
/>
);
};
import { useLottie, useLottieInteractivity } from 'lottie-react';
import likeButton from './like-button.json';
const HoverAnimation = () => {
const lottieObj = useLottie({
animationData: likeButton
});
const Animation = useLottieInteractivity({
lottieObj,
mode: 'cursor',
actions: [
{
position: { x: [0, 1], y: [0, 1] },
type: 'loop',
frames: [45, 60]
},
{
position: { x: -1, y: -1 },
type: 'stop',
frames: [45]
}
]
});
return <div style={{ height: 300, border: '2px solid black' }}>{Animation}</div>;
};
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
import React, { useState, useEffect } from 'react';
const ThemedAnimation = () => {
const [dotLottie, setDotLottie] = useState(null);
const [animations, setAnimations] = useState([]);
const [themes, setThemes] = useState([]);
const [currentAnimationId, setCurrentAnimationId] = useState('');
const [currentThemeId, setCurrentThemeId] = useState('');
useEffect(() => {
if (!dotLottie) return;
const onLoad = () => {
setAnimations(dotLottie.manifest.animations || []);
setThemes(dotLottie.manifest.themes || []);
setCurrentAnimationId(dotLottie.activeAnimationId);
setCurrentThemeId(dotLottie.activeThemeId);
};
dotLottie.addEventListener('load', onLoad);
return () => dotLottie.removeEventListener('load', onLoad);
}, [dotLottie]);
return (
<div>
<DotLottieReact
src="multi-animation.lottie"
dotLottieRefCallback={setDotLottie}
animationId={currentAnimationId}
themeId={currentThemeId}
/>
{themes.length > 0 && (
<select value={currentThemeId} onChange={(e) => setCurrentThemeId(e.target.value)}>
{themes.map((theme) => (
<option key={theme.id} value={theme.id}>{theme.id}</option>
))}
</select>
)}
{animations.length > 0 && (
<select value={currentAnimationId} onChange={(e) => setCurrentAnimationId(e.target.value)}>
{animations.map((anim) => (
<option key={anim.id} value={anim.id}>{anim.id}</option>
))}
</select>
)}
</div>
);
};
import { DotLottieWorker } from '@lottiefiles/dotlottie-web';
// Offload animation rendering to a web worker
new DotLottieWorker({
canvas: document.getElementById('canvas'),
src: 'heavy-animation.lottie',
autoplay: true,
loop: true,
workerId: 'worker-1' // Group multiple animations by worker
});
// Multiple animations in separate workers
new DotLottieWorker({
canvas: document.getElementById('canvas-2'),
src: 'animation-2.lottie',
autoplay: true,
loop: true,
workerId: 'worker-2'
});
import Lottie from 'lottie-react';
import gsap from 'gsap';
import ScrollTrigger from 'gsap/ScrollTrigger';
import animationData from './animation.json';
gsap.registerPlugin(ScrollTrigger);
const GSAPLottieIntegration = () => {
const lottieRef = React.useRef();
React.useEffect(() => {
const anim = lottieRef.current;
if (!anim) return;
// Sync Lottie with scroll
gsap.to(anim, {
scrollTrigger: {
trigger: '#animation-section',
start: 'top center',
end: 'bottom center',
scrub: 1,
onUpdate: (self) => {
const frame = Math.floor(self.progress * (anim.totalFrames - 1));
anim.goToAndStop(frame, true);
}
}
});
}, []);
return (
<div id="animation-section" style={{ height: '200vh' }}>
<Lottie
lottieRef={lottieRef}
animationData={animationData}
autoplay={false}
loop={false}
/>
</div>
);
};
import { motion } from 'framer-motion';
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
const MotionLottie = () => {
return (
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.6 }}
>
<DotLottieReact
src="animation.lottie"
loop
autoplay
style={{ height: 400 }}
/>
</motion.div>
);
};
<script setup>
import { DotLottieVue } from '@lottiefiles/dotlottie-vue';
</script>
<template>
<DotLottieVue
style="height: 500px; width: 500px"
autoplay
loop
src="https://path-to-animation.lottie"
/>
</template>
<script lang="ts">
import { DotLottieSvelte } from '@lottiefiles/dotlottie-svelte';
import type { DotLottie } from '@lottiefiles/dotlottie-svelte';
let dotLottie: DotLottie | null = null;
function play() {
dotLottie?.play();
}
</script>
<DotLottieSvelte
src="animation.lottie"
loop={true}
autoplay={true}
dotLottieRefCallback={(ref) => dotLottie = ref}
/>
<button on:click={play}>Play</button>
1. Export Settings in After Effects:
2. Compression:
3. Lazy Loading:
const LazyLottie = () => {
const [shouldLoad, setShouldLoad] = React.useState(false);
React.useEffect(() => {
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
setShouldLoad(true);
}
});
observer.observe(document.getElementById('lottie-trigger'));
return () => observer.disconnect();
}, []);
return (
<div id="lottie-trigger">
{shouldLoad && <DotLottieReact src="animation.lottie" loop autoplay />}
</div>
);
};
1. Renderer Selection:
// SVG: Best quality, slower for complex animations
// Canvas: Better performance, rasterized
// HTML: Limited support, use only for simple animations
// For complex animations, prefer canvas
new DotLottie({
canvas: document.getElementById('canvas'),
src: 'animation.lottie',
autoplay: true,
loop: true,
renderConfig: {
devicePixelRatio: window.devicePixelRatio || 1
}
});
2. Web Workers:
// Offload to worker for heavy animations
import { DotLottieWorker } from '@lottiefiles/dotlottie-web';
new DotLottieWorker({
canvas: document.getElementById('canvas'),
src: 'heavy-animation.lottie',
autoplay: true,
loop: true
});
3. Mobile Optimization:
// Reduce quality on mobile
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
new DotLottie({
canvas: document.getElementById('canvas'),
src: isMobile ? 'animation-low.lottie' : 'animation-high.lottie',
autoplay: true,
loop: true,
renderConfig: {
devicePixelRatio: isMobile ? 1 : window.devicePixelRatio
}
});
Problem: Not destroying Lottie instances when components unmount.
Solution:
const SafeAnimation = () => {
const [dotLottie, setDotLottie] = React.useState(null);
React.useEffect(() => {
return () => {
// Always destroy instance on unmount
dotLottie?.destroy();
};
}, [dotLottie]);
return <DotLottieReact src="animation.lottie" dotLottieRefCallback={setDotLottie} />;
};
Problem: Event listeners not removed, causing multiple handlers.
Solution:
useEffect(() => {
if (!dotLottie) return;
const handleComplete = () => console.log('Complete');
dotLottie.addEventListener('complete', handleComplete);
// MUST return cleanup function
return () => {
dotLottie.removeEventListener('complete', handleComplete);
};
}, [dotLottie]);
Problem: Exported JSON files are 500KB+ for simple animations.
Solutions:
Problem: Animation stutters or drops frames.
Solutions:
DotLottieWorker for web worker renderingProblem: Animation doesn't load due to CORS or incorrect paths.
Solution:
// Use animationData for local imports (best for bundled apps)
import animationData from './animation.json';
<Lottie animationData={animationData} />
// OR use path for external URLs (requires CORS headers)
<DotLottieReact src="https://example.com/animation.lottie" />
// For Next.js, place in public/ folder
<DotLottieReact src="/animations/animation.lottie" />
Problem: Some After Effects features don't export to Lottie.
Unsupported features:
Solution:
This skill includes:
generate_lottie_component.py - Generate React/Vue/Svelte Lottie component boilerplateoptimize_lottie.py - Optimize Lottie JSON file sizeapi_reference.md - Complete API documentation for lottie-web, lottie-react, and dotlottie-webafter_effects_export.md - Guide for exporting animations from After Effectsperformance_guide.md - Detailed performance optimization strategiesstarter_lottie/ - Complete React + Vite starter template with Lottie examplesexamples/ - Real-world Lottie animation patterns and use casesdevelopment
Meta-skill for combining Three.js, GSAP ScrollTrigger, React Three Fiber, Motion, and React Spring for complex 3D web experiences. Use when building applications that integrate multiple 3D and animation libraries, requiring architecture patterns, state management, and performance optimization across the stack. Triggers on tasks involving library integration, multi-library architectures, scroll-driven 3D experiences, physics-based 3D animations, or complex interactive 3D applications.
development
Comprehensive skill for Three.js 3D web development. Use this skill when building interactive 3D scenes, WebGL/WebGPU applications, product configurators, 3D visualizations, or immersive web experiences. Triggers on tasks involving Three.js, 3D rendering, scenes, cameras, meshes, materials, lights, animations, textures, or WebGL/WebGPU rendering.
tools
Comprehensive skill for Adobe Substance 3D Painter texturing and material creation workflow. Use this skill when creating PBR materials, exporting textures for web/game engines, optimizing 3D assets for real-time rendering, or automating texture workflows. Triggers on tasks involving Substance 3D Painter, PBR texturing, material creation, texture export for Three.js, Babylon.js, Unity, Unreal, glTF optimization, or Python API automation. Creates optimized textures for threejs-webgl, react-three-fiber, and babylonjs-engine materials.
tools
Browser-based 3D design tool with visual editor, animation, and web export. Use this skill when creating 3D scenes without code, designing interactive web experiences, prototyping 3D UI, exporting to React/web, or building designer-friendly 3D content. Triggers on tasks involving Spline, no-code 3D, visual 3D editor, 3D animation, state-based interactions, React Spline integration, or scene export. Alternative to Three.js for designers who prefer visual tools over code.