Skip to main content
skill CX Codex

lottie — Claude Code skill: fast Lottie animations on the web

A skill that steers your coding agent through Lottie work: dotLottie files, lazy loading, renderer choice and reduced-motion fallbacks.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add Mindrally/skills --skill lottie -a claude-code
Open on GitHub

What lottie does

This skill hands the agent a rulebook for Lottie animations. The first rule is format: ship .lottie (dotLottie) rather than .json, since assets and fonts travel inside one compressed bundle. A converter is available at lottiefiles.com.

Code samples cover React and plain JavaScript. React projects pull in @lottiefiles/dotlottie-react; vanilla ones use @lottiefiles/dotlottie-web. The agent will reach for IntersectionObserver to defer offscreen animations, pick between svg and canvas renderers, wire playback through dotLottieRefCallback, link frames to scroll position and split clips into segments. A reference table lists size and DOM-element targets for icons, UI animations, complex scenes and hero blocks.

Accessibility gets its own section: check prefers-reduced-motion, swap in a static image, and keep a fallback for load errors. The agent also reminds you to call destroy() when a component unmounts. None of the React samples compile without @lottiefiles/dotlottie-react installed, so add the package before asking for code.

What it helps with

  • migrate existing Lottie .json files to dotLottie
  • stop frame drops on an animation heavy with filters
  • defer loading until an animation scrolls into view
  • serve a static image to visitors who prefer reduced motion
  • drive playback and segments from UI buttons

Example prompts for the agent

  • Add the loading Lottie animation to this React component following the skill guidelines
  • Set up lazy loading for the animation with IntersectionObserver
  • Check prefers-reduced-motion and add a static fallback for this animation

How to install lottie

1Skills CLI (Vercel)

npx skills add Mindrally/skills --skill lottie -a claude-code

2Manually: put the files in place

~/.claude/skills/lottie/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/lottie/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about lottie

How do I install the lottie skill in Claude Code?

Run npx skills add Mindrally/skills --skill lottie -a claude-code. The skill lands at ~/.claude/skills/lottie/SKILL.md.

What does the lottie skill do?

It gives the agent guidelines for shipping Lottie animations: dotLottie format, lazy loading, renderer selection, file size limits and accessibility.

Why use dotLottie instead of plain JSON?

The .lottie format packs images and fonts into one compressed file, so it weighs less than .json with separate assets.

Source text

SKILL.md · Apache-2.0
---
name: lottie
description: Expert guidelines for implementing performant Lottie animations on the web
metadata:
  maintainer: Mindrally
  source: https://github.com/Mindrally/skills
---

# Lottie Animation Guidelines

You are an expert in Lottie animations, web performance, and JavaScript. Follow these guidelines when implementing Lottie animations.

## Core Principles

### Use dotLottie Format
- Prefer `.lottie` (dotLottie) format over `.json` - up to 90% smaller file size
- dotLottie bundles all assets (images, fonts) into a single compressed file
- Use the free dotLottie converter at lottiefiles.com

### Installation
```bash
# For React
npm install @lottiefiles/dotlottie-react

# For vanilla JS
npm install @lottiefiles/dotlottie-web
```

## React Implementation

### Basic Usage
```tsx
import { DotLottieReact } from "@lottiefiles/dotlottie-react";

function Animation() {
  return (
    <DotLottieReact
      src="/animations/loading.lottie"
      loop
      autoplay
    />
  );
}
```

### Control Animation Playback
```tsx
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
import { useState } from "react";

function ControlledAnimation() {
  const [dotLottie, setDotLottie] = useState(null);

  const dotLottieRefCallback = (dotLottie) => {
    setDotLottie(dotLottie);
  };

  return (
    <>
      <DotLottieReact
        src="/animation.lottie"
        dotLottieRefCallback={dotLottieRefCallback}
      />
      <button onClick={() => dotLottie?.play()}>Play</button>
      <button onClick={() => dotLottie?.pause()}>Pause</button>
      <button onClick={() => dotLottie?.stop()}>Stop</button>
    </>
  );
}
```

## Performance Optimization

### Lazy Loading
```tsx
import { useEffect, useRef, useState } from "react";
import { DotLottieReact } from "@lottiefiles/dotlottie-react";

function LazyLottie({ src }) {
  const [isVisible, setIsVisible] = useState(false);
  const containerRef = useRef(null);

  useEffect(() => {
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setIsVisible(true);
          observer.disconnect();
        }
      },
      { rootMargin: "100px" }
    );

    if (containerRef.current) {
      observer.observe(containerRef.current);
    }

    return () => observer.disconnect();
  }, []);

  return (
    <div ref={containerRef}>
      {isVisible && <DotLottieReact src={src} autoplay loop />}
    </div>
  );
}
```

### Choose the Right Renderer
```tsx
// SVG renderer - best quality, good for simple animations
<DotLottieReact src="/animation.lottie" renderer="svg" />

// Canvas renderer - better performance for complex animations
<DotLottieReact src="/animation.lottie" renderer="canvas" />

// Use canvas for:
// - Complex animations with many elements
// - Lower-powered devices
// - Animations with filters/effects
```

### Reduce DOM Elements
- Reuse identical graphic elements in After Effects
- Simplify paths and reduce keyframes
- Avoid unnecessary layers
- Target under 1000 DOM elements per animation

## Animation Design Best Practices

### Avoid Performance-Heavy Features
```
AVOID:
- Masks (use alpha matte sparingly)
- Complex blur effects
- 3D layers
- Expressions
- Uncompressed images
- Large image assets

PREFER:
- Simple shapes (fills, strokes)
- Transform animations (position, scale, rotation)
- Opacity changes
- Path animations
```

### Optimize Images in Animations
```
- Compress images to match display size
- If max display is 400x400, don't use 1000x1000 images
- Use vector graphics when possible
- Consider converting images to shapes
```

## Interactivity

### Cursor/Mouse Interaction
```tsx
<DotLottieReact
  src="/hover-animation.lottie"
  playMode="hover"
/>
```

### Scroll-Linked Animation
```tsx
import { useScroll, useTransform } from "motion/react";

function ScrollLottie() {
  const { scrollYProgress } = useScroll();
  const [dotLottie, setDotLottie] = useState(null);

  useEffect(() => {
    if (!dotLottie) return;

    const unsubscribe = scrollYProgress.on("change", (progress) => {
      dotLottie.setFrame(progress * dotLottie.totalFrames);
    });

    return unsubscribe;
  }, [dotLottie, scrollYProgress]);

  return (
    <DotLottieReact
      src="/scroll-animation.lottie"
      dotLottieRefCallback={setDotLottie}
      autoplay={false}
    />
  );
}
```

### Segment Playback
```tsx
function SegmentAnimation() {
  const [dotLottie, setDotLottie] = useState(null);

  const playSegment = (start, end) => {
    dotLottie?.setSegment(start, end);
    dotLottie?.play();
  };

  return (
    <>
      <DotLottieReact
        src="/multi-state.lottie"
        dotLottieRefCallback={setDotLottie}
        autoplay={false}
      />
      <button onClick={() => playSegment(0, 30)}>State 1</button>
      <button onClick={() => playSegment(30, 60)}>State 2</button>
    </>
  );
}
```

## Accessibility

### Respect Reduced Motion
```tsx
function AccessibleAnimation() {
  const prefersReducedMotion = window.matchMedia(
    "(prefers-reduced-motion: reduce)"
  ).matches;

  if (prefersReducedMotion) {
    return <img src="/static-fallback.svg" alt="Animation description" />;
  }

  return (
    <DotLottieReact
      src="/animation.lottie"
      autoplay
      loop
      aria-label="Decorative loading animation"
    />
  );
}
```

### Provide Fallbacks
```tsx
function AnimationWithFallback() {
  const [hasError, setHasError] = useState(false);

  if (hasError) {
    return <img src="/fallback.gif" alt="Animation" />;
  }

  return (
    <DotLottieReact
      src="/animation.lottie"
      autoplay
      onError={() => setHasError(true)}
    />
  );
}
```

## Loading Strategy

### Use Preloader for Large Animations
```tsx
function AnimationWithPreloader() {
  const [isLoaded, setIsLoaded] = useState(false);

  return (
    <div className="animation-container">
      {!isLoaded && (
        <img src="/first-frame.webp" alt="" className="preloader" />
      )}
      <DotLottieReact
        src="/large-animation.lottie"
        onLoad={() => setIsLoaded(true)}
        style={{ opacity: isLoaded ? 1 : 0 }}
        autoplay
      />
    </div>
  );
}
```

## File Size Guidelines

| Animation Complexity | Target Size | Max DOM Elements |
|---------------------|-------------|------------------|
| Simple icons        | < 10KB      | < 100           |
| UI animations       | < 50KB      | < 500           |
| Complex scenes      | < 150KB     | < 1500          |
| Hero animations     | < 300KB     | < 2500          |

## Cleanup

### Proper Cleanup in React
```tsx
useEffect(() => {
  return () => {
    dotLottie?.destroy();
  };
}, [dotLottie]);
```

## Best Practices Summary

1. Use dotLottie format for smaller file sizes
2. Lazy load animations not in viewport
3. Use canvas renderer for complex animations
4. Avoid masks, blurs, and expressions
5. Compress and optimize image assets
6. Respect reduced motion preferences
7. Provide static fallbacks for errors
8. Clean up animations on unmount
9. Keep DOM element count low
10. Use preloaders for large animations

© Mindrally · Apache-2.0 · Mindrally/skills

Similar skills

Everything for Frontend and UI →

From the same set236

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor