lottie

Expert guidelines for implementing performant Lottie animations on the web

INSTALLATION
npx skills add https://github.com/mindrally/skills --skill lottie
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$27

React Implementation

Basic Usage

import { DotLottieReact } from "@lottiefiles/dotlottie-react";

function Animation() {

  return (

    <DotLottieReact

      src="/animations/loading.lottie"

      loop

      autoplay

    />

  );

}

Control Animation Playback

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

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 &#x26;&#x26; <DotLottieReact src={src} autoplay loop />}

    </div>

  );

}

Choose the Right Renderer

// 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

<DotLottieReact

  src="/hover-animation.lottie"

  playMode="hover"

/>

Scroll-Linked Animation

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

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

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

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

function AnimationWithPreloader() {

  const [isLoaded, setIsLoaded] = useState(false);

  return (

    <div className="animation-container">

      {!isLoaded &#x26;&#x26; (

        <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

useEffect(() => {

  return () => {

    dotLottie?.destroy();

  };

}, [dotLottie]);

Best Practices Summary

  • Use dotLottie format for smaller file sizes
  • Lazy load animations not in viewport
  • Use canvas renderer for complex animations
  • Avoid masks, blurs, and expressions
  • Compress and optimize image assets
  • Respect reduced motion preferences
  • Provide static fallbacks for errors
  • Clean up animations on unmount
  • Keep DOM element count low
  • Use preloaders for large animations
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card