Index of every page on this site: llms.txt
All skills
Run it yourself

Implement Lottie animations using dotLottie runtimes (@lottiefiles/dotlottie-web and @lottiefiles/dotlottie-react). Use when building, debugging, or optimizing dotLottie or Lottie animations in web projects, including vanilla JS, React, and Next.js. Covers package selection, Web Workers, state machines, theming, dynamic slot overriding, performance best practices, and common patterns.

Use this Skill: https://skilld.dev/gh/lottiefiles/dotlottie-web/dotlottie-web

Nothing lands on disk. Nothing to clean up.

Fork this Skill

Edit a local copy. It keeps the author and licence.

SKILL.md

≈101 tokens for metadata: the name and description. ≈3.3k when used: this file. ≈3307k more on demand in 187 files.

Description uses 5.0% of example budget

Before choosing a Skill, your Agent reads its name and description. All available Skills share that space.

  • A shorter description leaves more room for other Skills. This entry exceeds our 1% size suggestion.

In our Claude Code example, all Skill names and descriptions share 8,000 characters. This Skill uses ≈403 characters, or 5.0%.

The 1% threshold is a size suggestion. Longer descriptions can still fit.

Your model, settings, and other Skills decide how much text your Agent can read.

Example settings and source

The example uses a 200k-token context and default Claude Code settings. The count includes the name, description, separators, and when_to_use when present. Codex also counts local file paths.

Skit's source and limits: Codex 0.160.1, Claude Code 2.1.292.

dotLottie Implementation Guidelines

You are an expert at implementing Lottie animations using dotLottie runtimes. Follow these guidelines when working with dotLottie in web projects.

Package Selection

Use @lottiefiles/dotlottie-web when:

  • You need direct canvas control
  • Building framework-agnostic code
  • Maximum performance is critical
  • You want the smallest bundle

Use @lottiefiles/dotlottie-react when:

  • Building React applications
  • You want declarative component API
  • You need React lifecycle integration

Installation

# Web (vanilla JS, Vue, Svelte, etc.)
npm install @lottiefiles/dotlottie-web

# React
npm install @lottiefiles/dotlottie-react

Basic Implementation

Vanilla JavaScript

import { DotLottie } from '@lottiefiles/dotlottie-web';

const dotLottie = new DotLottie({
  canvas: document.getElementById('canvas') as HTMLCanvasElement,
  src: 'https://example.com/animation.lottie',
  autoplay: true,
  loop: true,
});

React

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

function Animation() {
  return (
    <DotLottieReact
      src="https://example.com/animation.lottie"
      autoplay
      loop
    />
  );
}

React with Instance Control

import { useRef } from 'react';
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
import type { DotLottie } from '@lottiefiles/dotlottie-web';

function Animation() {
  const dotLottieRef = useRef<DotLottie | null>(null);

  return (
    <DotLottieReact
      src="https://example.com/animation.lottie"
      dotLottieRefCallback={(dotLottie) => (dotLottieRef.current = dotLottie)}
    />
  );
}

.lottie vs .json

Always prefer .lottie format over .json:

  • Smaller file size (compressed)
  • Supports multiple animations in one file
  • Embedded assets (images, fonts)
  • State machines for interactivity
  • Theming with slots

Web Workers (Recommended for Performance)

Use DotLottieWorker to offload animation rendering to a Web Worker, keeping the main thread free for UI interactions:

Basic Worker Usage

import { DotLottieWorker } from '@lottiefiles/dotlottie-web';

const dotLottie = new DotLottieWorker({
  canvas: document.getElementById('canvas') as HTMLCanvasElement,
  src: 'https://example.com/animation.lottie',
  autoplay: true,
  loop: true,
});

Worker Grouping (Multiple Animations)

By default, all DotLottieWorker instances share the same worker. Group animations into separate workers using workerId:

// Hero animation in its own worker
const heroAnimation = new DotLottieWorker({
  canvas: heroCanvas,
  src: 'hero.lottie',
  workerId: 'hero-worker',
});

// UI animations share a different worker
const buttonAnimation = new DotLottieWorker({
  canvas: buttonCanvas,
  src: 'button.lottie',
  workerId: 'ui-worker',
});

When to Use Workers

  • Use DotLottieWorker for:

    • Multiple simultaneous animations
    • Complex animations with many layers
    • Animations running alongside heavy JS operations
    • Mobile devices where main thread performance is critical
  • Use regular DotLottie for:

    • Single simple animations
    • When you need synchronous frame access
    • SSR environments (workers not available)

React with Workers

import { DotLottieWorkerReact } from '@lottiefiles/dotlottie-react';

function Animation() {
  return (
    <DotLottieWorkerReact
      src="animation.lottie"
      autoplay
      loop
      workerId="my-worker" // Optional: dedicate to specific worker
    />
  );
}

State Machines (Interactivity)

State machines enable interactive animations without code. See the State Machine Guide for details.

const dotLottie = new DotLottie({
  canvas,
  src: 'interactive.lottie', // Contains state machine
  autoplay: true,
});

// Fire events to trigger state transitions
dotLottie.stateMachineFireEvent('click');
dotLottie.stateMachineFireEvent('hover');
dotLottie.stateMachineFireEvent('custom-event');

// Set numeric/boolean/string inputs for state conditions
// See: https://github.com/LottieFiles/dotlottie-web/wiki/dotLottie-State-Machine-Guide#working-with-inputs
dotLottie.stateMachineSetNumericInput('progress', 0.5);
dotLottie.stateMachineSetBooleanInput('isActive', true);
dotLottie.stateMachineSetStringInput('mode', 'dark');

State Machine Events

  • click - User click/tap
  • hover - Mouse enter
  • unhover - Mouse leave
  • complete - Animation finished
  • Custom events defined in the state machine

Theming with Slots

Slots allow runtime color/value customization. Themes follow the dotLottie 2.0 spec.

const dotLottie = new DotLottie({
  canvas,
  src: 'themed.lottie',
  themeId: 'dark-mode', // Use embedded theme by ID
});

// Or apply theme data directly (JSON string per dotLottie 2.0 spec)
// See: https://dotlottie.io/spec/2.0/#themes
dotLottie.setThemeData(JSON.stringify({
  rules: [
    { id: 'primary-color', value: [1, 0.34, 0.13] }, // RGB values 0-1
  ]
}));

Dynamic Slot Overriding

Slots enable runtime customization of animated properties using typed APIs. Available slot types: color, scalar, vector, gradient, text, image.

Key APIs: getSlotIds(), getSlotType(), setColorSlot(), setScalarSlot(), setVectorSlot(), setGradientSlot(), setTextSlot(), resetSlot(), clearSlots().

For complete API reference with code examples for each slot type, animated keyframes, resetting, bulk updates, common use cases (branding, dark mode, progress indicators), and React integration, see Dynamic Slots Reference.

Markers & Segments

Playing Specific Segments

// Play frames 0-60
dotLottie.setSegment(0, 60);
dotLottie.play();

// Play by marker name (defined in animation)
dotLottie.setMarker('intro');
dotLottie.play();

Getting Markers

const markers = dotLottie.markers();
// Returns: [{ name: 'intro', time: 0, duration: 60 }, ...]

Rendering a Specific Frame to an Image

Set autoplay: false so playback doesn't advance past your target, then call setFrame() after load. setFrame() renders synchronously, so the canvas and dotLottie.buffer (RGBA Uint8Array) hold that exact frame immediately after the call.

Browser

const dotLottie = new DotLottie({ canvas, src: 'animation.lottie', autoplay: false });

dotLottie.addEventListener('load', () => {
  dotLottie.setFrame(42);                        // render frame 42
  const dataUrl = canvas.toDataURL('image/png'); // or canvas.toBlob(cb, 'image/png')
});

Node.js (@napi-rs/canvas)

import fs from 'node:fs';
import { createCanvas } from '@napi-rs/canvas';

const canvas = createCanvas(200, 200);
const dotLottie = new DotLottie({
  canvas: canvas as unknown as HTMLCanvasElement,
  src: 'animation.lottie',
  autoplay: false,
});

dotLottie.addEventListener('load', async () => {
  dotLottie.setFrame(42);
  fs.writeFileSync('frame-42.png', await canvas.encode('png'));
  dotLottie.destroy();
});

For custom encoding, read raw RGBA pixels directly from dotLottie.buffer (length = width × height × 4).

Event Handling

dotLottie.addEventListener('load', () => {
  console.log('Animation loaded');
});

dotLottie.addEventListener('play', () => {
  console.log('Playing');
});

dotLottie.addEventListener('complete', () => {
  console.log('Animation completed');
});

dotLottie.addEventListener('frame', ({ currentFrame }) => {
  console.log('Frame:', currentFrame);
});

// Clean up
dotLottie.removeEventListener('load', handler);

Performance Best Practices

1. Use Web Workers for Complex Animations

import { DotLottieWorker } from '@lottiefiles/dotlottie-web';

// Offload rendering to worker thread
const dotLottie = new DotLottieWorker({
  canvas,
  src: 'complex-animation.lottie',
});

2. Lazy Load Animations

// Only load when visible
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      loadAnimation();
      observer.disconnect();
    }
  });
});
observer.observe(container);

3. Auto-Freeze is Enabled by Default

DotLottie automatically freezes animations when they're not visible (offscreen). To disable this behavior:

const dotLottie = new DotLottie({
  canvas,
  src: 'animation.lottie',
  renderConfig: {
    freezeOnOffscreen: false, // Disable auto-freeze (not recommended)
  },
});

4. Device Pixel Ratio

By default, devicePixelRatio is set to 75% of the actual value for better performance. For full retina quality (with higher performance cost):

const dotLottie = new DotLottie({
  canvas,
  src: 'animation.lottie',
  renderConfig: {
    devicePixelRatio: window.devicePixelRatio, // Full retina (higher CPU/GPU)
  },
});

5. Clean Up (Vanilla JS only)

// Always destroy when done (vanilla JS)
dotLottie.destroy();

Note: DotLottieReact handles cleanup automatically on unmount - no manual cleanup needed.

6. Frame Interpolation Control

const dotLottie = new DotLottie({
  canvas,
  src: 'animation.lottie',
  useFrameInterpolation: true,  // Smooth playback (default)
  // useFrameInterpolation: false, // Match original AE frame rate
});

Multi-Animation Files

A single .lottie file can contain multiple animations:

// Load specific animation by ID
dotLottie.loadAnimation('animation-2');

// Get all animation IDs
const animations = dotLottie.manifest?.animations;
// Returns: [{ id: 'animation-1' }, { id: 'animation-2' }]

Canvas Sizing

Set canvas size via CSS styles (recommended). DotLottie will automatically determine the optimal drawing area:

<canvas id="canvas" style="width: 400px; height: 400px;"></canvas>

Auto-Resize to Container

Use the autoResize render config to automatically resize when the container changes:

const dotLottie = new DotLottie({
  canvas,
  src: 'animation.lottie',
  renderConfig: {
    autoResize: true, // Canvas resizes to fit container
  },
});

Common Patterns

Play on Hover

canvas.addEventListener('mouseenter', () => dotLottie.play());
canvas.addEventListener('mouseleave', () => dotLottie.pause());

Play on Click (Once)

canvas.addEventListener('click', () => {
  dotLottie.setFrame(0);
  dotLottie.setLoop(false);
  dotLottie.play();
});

Scrub with Scroll

window.addEventListener('scroll', () => {
  const progress = window.scrollY / (document.body.scrollHeight - window.innerHeight);
  const frame = progress * dotLottie.totalFrames;
  dotLottie.setFrame(frame);
});

Loading States (React)

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

  return (
    <>
      {!isLoaded && <Skeleton />}
      <DotLottieReact
        src="animation.lottie"
        style={{ opacity: isLoaded ? 1 : 0 }}
        dotLottieRefCallback={(dotLottie) => {
          dotLottie.addEventListener('load', () => setIsLoaded(true));
        }}
      />
    </>
  );
}

Responsive Animation

function ResponsiveAnimation() {
  return (
    <DotLottieReact
      src="animation.lottie"
      autoplay
      loop
      style={{ width: '100%', maxWidth: '400px' }}
      renderConfig={{ autoResize: true }}
    />
  );
}

Debugging

// Check if loaded
console.log('Loaded:', dotLottie.isLoaded);

// Get animation info
console.log('Duration:', dotLottie.duration);
console.log('Total Frames:', dotLottie.totalFrames);
console.log('Current Frame:', dotLottie.currentFrame);
console.log('Is Playing:', dotLottie.isPlaying);
console.log('Loop:', dotLottie.loop);
console.log('Speed:', dotLottie.speed);

// Get manifest (for .lottie files)
console.log('Manifest:', dotLottie.manifest);

Error Handling

dotLottie.addEventListener('loadError', (error) => {
  console.error('Failed to load animation:', error);
  // Show fallback UI
});

SSR / Next.js Considerations

dotLottie requires browser APIs. For SSR frameworks:

import dynamic from 'next/dynamic';

const DotLottieReact = dynamic(
  () => import('@lottiefiles/dotlottie-react').then(mod => mod.DotLottieReact),
  { ssr: false }
);

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

Resources

Source: SKILL.md on GitHub

skilld matched fixed text patterns in SKILL.md and file names. Patterns miss obfuscated code.

skilld run checks every file with the same patterns. It asks for approval before it loads a Skill with a behavior marked Needs approval.

1 warning1mo3 checks · Risk SAFE
  • Gen Agent Trust Hub1mo

    Error: AI Analysis failed - API error after retries

  • Socket1mo

    2 alerts: gptAnomaly, gptSecurity

  • Snyk1mo

    Risk: LOW · No issues

Signed by skilld at d8a4e9e. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 weeks ago.

Activeupdated 4 months ago
Other metadata
metadata
{
  "author": "lottiefiles",
  "version": "1.0.0",
  "source": "https://github.com/LottieFiles/dotlottie-web"
}

README badge

README badge for lottiefiles/dotlottie-web