Command Palette

Search for a command to run...

Introduction to relottie

Discover relottie, a powerful ecosystem for developers to programmatically transform, analyze, and manipulate Lottie animations. Learn how to use ASTs and plugins to edit Lottie JSON.

Introduction to relottie

A unified, plugin-based ecosystem for programmatic Lottie animation processing.

relottie is an enterprise-grade toolkit for developers who need to programmatically analyze, transform, and manipulate Lottie animations at scale. Built on the robust unified.js processing engine, relottie transforms Lottie JSON files into Abstract Syntax Trees (ASTs), enabling reliable, structured manipulation through a composable plugin architecture.

What Problems Does relottie Solve?

Working with Lottie animations programmatically presents several challenges:

The Raw JSON Problem

Lottie files are complex, deeply nested JSON structures. Manual manipulation is:

  • Error-Prone: One typo can break the entire animation

  • Fragile: Changes to structure require updating all manipulation code

  • Difficult to Scale: Batch operations across hundreds of files become unwieldy

  • Hard to Validate: Ensuring modifications maintain Lottie spec compliance is complex

Common Scenarios relottie Addresses

  1. Batch Processing: Update brand colors across 500+ animation files

  2. Dynamic Theming: Programmatically adapt animations to user preferences

  3. Automated QA: Extract and validate animation metadata in CI/CD pipelines

  4. Feature Detection: Identify animations using unsupported features before deployment

  5. Performance Optimization: Analyze and optimize animations for specific platforms

  6. Custom Tooling: Build domain-specific Lottie editors and validators

  7. Integration Workflows: Prepare Lottie files for conversion to .lottie format or other systems

The relottie Solution

relottie solves these challenges by:

  • Structured Representation: Converting JSON to semantic ASTs with Lottie-specific node types

  • Plugin Ecosystem: Providing reusable, composable transformation units

  • Type Safety: Full TypeScript support for AST nodes and transformations

  • Validation: Ensuring transformations produce valid Lottie output

  • Extensibility: Easy creation of custom plugins for domain-specific needs

Core Concepts

Understanding three foundational concepts is essential to working with relottie:

1. Abstract Syntax Trees (ASTs)

An Abstract Syntax Tree is a tree representation of the structure of your Lottie JSON. Instead of working with raw text or generic JSON objects, relottie parses Lottie files into a semantic tree where each node has a specific type and meaning.

Why ASTs Matter:

  • Semantic Understanding: Nodes represent Lottie concepts (layers, transforms, colors) not just JSON keys

  • Reliable Navigation: Tree traversal utilities make finding and modifying content predictable

  • Transformation Safety: Changes to the tree structure are validated before output

  • Position Tracking: Every node knows its location in the original source for error reporting

2. LAST (Lottie Abstract Syntax Tree)

LAST is relottie's specific AST specification for representing Lottie animations. It extends the universal unist specification, making it compatible with the broader unified.js ecosystem of hundreds of utilities.

Key LAST Features:

  • Semantic title Property: Each node has a title describing its Lottie meaning (e.g., layer-image, transform-opacity, version)

  • Type Hierarchy: Nodes are typed as Root, Attribute, Primitive, Element, or JSON nodes

  • Position Information: Tracks source location (line, column, offset) for debugging

  • Expression Detection: Root node flags presence of potentially unsafe JavaScript expressions

  • TypeScript Types: Full type definitions in @lottiefiles/last package

Visualization: JSON to LAST Transformation

Lottie JSON                           LAST Tree
┌─────────────────────┐              ┌─────────────────────────────┐
│ {                   │              │ Root                        │
│   "v": "6.0.0",     │    ───>      │ ├─ Attribute (title: "version")│
│   "w": 512,         │              │ │  └─ Primitive ("6.0.0")   │
│   "h": 512,         │              │ ├─ Attribute (title: "width") │
│   "fr": 60          │              │ │  └─ Primitive (512)        │
│ }                   │              │ ├─ Attribute (title: "height")│
└─────────────────────┘              │ │  └─ Primitive (512)        │
                                      │ └─ Attribute (title: "framerate")│
                                      │    └─ Primitive (60)         │
                                      └─────────────────────────────┘

Each node in the LAST tree:

  • Has a type property (root, attribute, primitive, etc.)

  • Contains a semantic title derived from Lottie specification

  • May have children for nested structures

  • Includes position information for source mapping

Learn more: Guide: Working with LAST

3. The unified.js Pipeline

relottie is built on unified, a battle-tested content processing engine used by projects like remark (Markdown) and rehype (HTML).

The Processing Pipeline:

┌─────────┐      ┌─────────┐      ┌─────────────┐      ┌─────────┐
│ Lottie  │      │  LAST   │      │   LAST      │      │ Lottie  │
│  JSON   │ ───> │  Tree   │ ───> │   Tree      │ ───> │  JSON   │
│ (Input) │      │ (Parse) │      │ (Transform) │      │ (Output)│
└─────────┘      └─────────┘      └─────────────┘      └─────────┘
     │                │                   │                  │
     │                │                   │                  │
  relottie()    relottie-parse      Your Plugins      relottie-stringify
  processor                         (metadata,
                                   transforms,
                                   analysis)

Pipeline Stages:

  1. Parse: relottie-parse converts Lottie JSON → LAST tree

  2. Transform: Plugins traverse and modify the LAST tree (run sequentially)

  3. Stringify: relottie-stringify converts LAST tree → Lottie JSON

This architecture enables:

  • Composability: Chain multiple transformations

  • Reusability: Plugins work across projects

  • Isolation: Each plugin operates independently

  • Testability: Test plugins in isolation

Architecture Overview

┌─────────────────────────────────────────────────────────────────┐
│                      relottie Ecosystem                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                   │
│  ┌────────────────────────────────────────────────────────┐    │
│  │              @lottiefiles/relottie                     │    │
│  │              (Processor + Pipeline)                     │    │
│  └─────────────────┬──────────────────────────────────────┘    │
│                    │                                             │
│  ┌─────────────────┴──────────────────────────────────────┐    │
│  │                   unified.js                            │    │
│  │         (Core Processing Engine)                        │    │
│  └────────────────────────────────────────────────────────┘    │
│                                                                   │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │                   Core Plugins                            │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │  @lottiefiles/relottie-parse     (Parser)               │  │
│  │  @lottiefiles/relottie-stringify (Compiler)              │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                   │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │                 Utility Plugins                           │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │  @lottiefiles/relottie-metadata                          │  │
│  │  @lottiefiles/relottie-extract-features                  │  │
│  │  @lottiefiles/relottie-style (community)                 │  │
│  │  [Your Custom Plugins]                                    │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                   │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │                Support Packages                           │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │  @lottiefiles/last         (AST Types)                   │  │
│  │  @lottiefiles/last-builder (AST Construction)            │  │
│  │  @lottiefiles/relottie-cli (Command Line)                │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                   │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │              unist Ecosystem Utilities                    │  │
│  ├──────────────────────────────────────────────────────────┤  │
│  │  unist-util-visit   (Tree Traversal)                     │  │
│  │  unist-util-filter  (Tree Filtering)                     │  │
│  │  unist-util-map     (Tree Mapping)                       │  │
│  │  unist-util-select  (CSS-like Selection)                 │  │
│  │  + 100+ more utilities                                    │  │
│  └──────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘

Feature Matrix & Capabilities

FeatureCapabilityPackage
Parse Lottie JSONConvert JSON to LAST tree@lottiefiles/relottie-parse
Stringify to JSONConvert LAST tree to JSON@lottiefiles/relottie-stringify
Metadata ExtractionWidth, height, framerate, duration, colors@lottiefiles/relottie-metadata
Feature DetectionIdentify used Lottie features@lottiefiles/relottie-extract-features
Tree TraversalVisit, filter, map, select nodesunist-util-*
Custom TransformationsModify colors, properties, structureCustom plugins
Position TrackingSource maps for error reportingBuilt-in
Expression DetectionSecurity: Flag JS expressionsBuilt-in
TypeScript SupportFull type definitionsAll packages
CLI ToolCommand-line processing@lottiefiles/relottie-cli
AST BuildingProgrammatic AST construction@lottiefiles/last-builder
Batch ProcessingProcess multiple filesCustom implementation
Plugin DevelopmentCreate custom transformationsPlugin API

Plugin Ecosystem Overview

Official Plugins

Core (Bundled with relottie):

  • @lottiefiles/relottie-parse: Parses Lottie JSON into LAST tree

    • Based on Momoa JSON parser

    • Provides semantic Lottie node titles

    • Configurable position tracking

  • @lottiefiles/relottie-stringify: Converts LAST tree back to Lottie JSON

    • Produces valid, formatted output

    • Configurable indentation and spacing

    • Preserves or updates structure

Utilities:

  • @lottiefiles/relottie-metadata: Extracts animation metadata

    • Dimensions (width, height)

    • Timing (framerate, duration, in/out points)

    • Colors used in animation

    • Layer counts and types

    • Attaches to vfile.data

  • @lottiefiles/relottie-extract-features: Analyzes feature usage

    • Identifies all Lottie features used

    • Useful for compatibility checking

    • Generates feature report

    • Attaches to vfile.data

Community Plugins

  • @lottiefiles/relottie-style: Style inspection and transformation

  • Custom Plugins: See Ecosystem: Plugins

Creating Custom Plugins

Plugins are functions that return transformers. A minimal plugin:

import type { Plugin } from "unified";
import type { Root } from "@lottiefiles/last";
import { visit } from "unist-util-visit";

const myPlugin: Plugin<[], Root> = () => {
  return (tree, file) => {
    // Transform the tree
    visit(tree, "attribute", (node) => {
      // Your logic here
    });
  };
};

See: Guide: Creating Plugins

Quick Start

Installation

npm install @lottiefiles/relottie @lottiefiles/last unist-util-visit

Basic Usage: Update Animation Version

import { relottie } from "@lottiefiles/relottie";
import { TITLES } from "@lottiefiles/last";
import type { Root, Attribute } from "@lottiefiles/last";
import type { Plugin } from "unified";
import { visit, EXIT } from "unist-util-visit";

// Define a plugin to update version
const updateVersion: Plugin<[{ version: string }], Root> = (options) => {
  return (tree, file) => {
    visit(tree, "attribute", (node: Attribute) => {
      // Find the version attribute
      if (node.title !== TITLES.string.version) return;

      // Update the primitive value
      const primitiveNode = node.children[0];
      if (primitiveNode && primitiveNode.type === "primitive") {
        primitiveNode.value = options.version;
      }

      return EXIT; // Stop after finding version
    });
  };
};

// Process a Lottie file
const lottieJson = '{"v":"5.5.2","w":512,"h":512,"fr":60,"ip":0,"op":60,"layers":[]}';

const processor = relottie().use(updateVersion, { version: "6.0.0" });

const result = await processor.process(lottieJson);

console.log(String(result));
// Output: {"v":"6.0.0","w":512,"h":512,"fr":60,"ip":0,"op":60,"layers":[]}

Extract Metadata

import { relottie } from "@lottiefiles/relottie";
import relottieMetadata from "@lottiefiles/relottie-metadata";

const processor = relottie().use(relottieMetadata);
const result = await processor.process(lottieJson);

console.log(result.data.lottieMetadata);
// Output:
// {
//   width: 512,
//   height: 512,
//   framerate: 60,
//   inPoint: 0,
//   outPoint: 60,
//   duration: 1.0,
//   colors: [...],
//   ...
// }

Detect Features

import { relottie } from "@lottiefiles/relottie";
import relottieExtractFeatures from "@lottiefiles/relottie-extract-features";

const processor = relottie().use(relottieExtractFeatures);
const result = await processor.process(lottieJson);

console.log(result.data.lottieFeatures);
// Output: ['layers', 'shapes', 'transforms', ...]

Common Use Cases

1. Batch Color Replacement

Replace all instances of a specific color across animations:

import { visit } from "unist-util-visit";
import type { Plugin } from "unified";
import type { Root, Primitive } from "@lottiefiles/last";

interface ColorOptions {
  from: [number, number, number, number]; // RGBA
  to: [number, number, number, number];
}

const replaceColor: Plugin<[ColorOptions], Root> = (options) => {
  return (tree) => {
    visit(tree, "element", (node) => {
      // Check if this is a color array [r, g, b, a]
      if (node.children.length === 4 && node.children.every((child) => child.type === "primitive")) {
        const values = node.children.map((child) => (child as Primitive).value);

        // Compare colors
        if (colorsMatch(values, options.from)) {
          // Replace with new color
          node.children.forEach((child, i) => {
            (child as Primitive).value = options.to[i];
          });
        }
      }
    });
  };
};

function colorsMatch(a: any[], b: number[]): boolean {
  return a.length === 4 && a.every((val, i) => Math.abs(val - b[i]) < 0.01);
}

// Usage
const processor = relottie().use(replaceColor, {
  from: [1, 0, 0, 1], // Red
  to: [0, 0, 1, 1], // Blue
});

2. Remove Expressions for Security

Strip potentially unsafe JavaScript expressions:

const removeExpressions: Plugin<[], Root> = () => {
  return (tree, file) => {
    let removed = 0;

    visit(tree, "attribute", (node, index, parent) => {
      if (node.title === "expression") {
        // Remove expression node
        if (parent && index !== undefined) {
          parent.children.splice(index, 1);
          removed++;
          return index; // Continue from current index
        }
      }
    });

    file.message(`Removed ${removed} expressions`, tree);
  };
};

3. Optimize Animation Size

Remove unused or redundant properties:

const optimizeSize: Plugin<[], Root> = () => {
  return (tree) => {
    visit(tree, "attribute", (node, index, parent) => {
      // Remove attributes with default values
      if (node.title === "autoOrient" && node.children[0]?.type === "primitive" && node.children[0].value === 0) {
        // Remove default autoOrient
        if (parent && index !== undefined) {
          parent.children.splice(index, 1);
          return index;
        }
      }
    });
  };
};

4. Validate Animation Properties

Ensure animations meet specific requirements:

const validateAnimation: Plugin<[], Root> = () => {
  return (tree, file) => {
    let width: number | undefined;
    let height: number | undefined;
    let framerate: number | undefined;

    visit(tree, "attribute", (node) => {
      if (node.title === TITLES.number.width) {
        width = node.children[0]?.value;
      } else if (node.title === TITLES.number.height) {
        height = node.children[0]?.value;
      } else if (node.title === TITLES.number.framerate) {
        framerate = node.children[0]?.value;
      }
    });

    // Validate
    if (!width || !height) {
      file.fail("Animation must have width and height", tree);
    }
    if (width && width > 2048) {
      file.message("Width exceeds recommended maximum (2048px)", tree);
    }
    if (framerate && framerate > 60) {
      file.message("Framerate exceeds 60fps", tree);
    }
  };
};

5. Extract Layer Information

Build an inventory of all layers:

interface LayerInfo {
  type: string;
  name?: string;
  index: number;
}

const extractLayers: Plugin<[], Root> = () => {
  return (tree, file) => {
    const layers: LayerInfo[] = [];

    visit(tree, "attribute", (node) => {
      if (node.title === "layer-type") {
        const typeNode = node.children[0];
        if (typeNode?.type === "primitive") {
          layers.push({
            type: String(typeNode.value),
            index: layers.length,
          });
        }
      }
    });

    file.data.layers = layers;
  };
};

Tool Comparison

relottie vs dotlottie-js vs Manual Editing

Aspectrelottiedotlottie-jsManual JSON Editing
Primary PurposeProgrammatic analysis & transformationCreate .lottie bundlesQuick one-off edits
Use CaseBatch processing, automation, toolingPackage animations for distributionSimple value changes
Input FormatLottie JSONLottie JSON + assetsLottie JSON
Output FormatLottie JSON.lottie binary formatLottie JSON
TransformationFull AST-based manipulationLimited (bundling focus)Manual find/replace
Type SafetyFull TypeScript supportTypeScript APINone
ValidationAST structure validationFormat validationNone
ExtensibilityPlugin ecosystemFixed feature setN/A
ScaleHundreds/thousands of filesIndividual conversionsSingle files
Learning CurveModerate (AST concepts)LowVery low
PerformanceFast (optimized traversal)FastInstant (no processing)
Error HandlingDetailed position infoStandard errorsNo validation
Best ForAutomation, CI/CD, toolingDistribution, app bundlingQuick fixes

When to Use Each Tool

Use relottie when you need to:

  • Batch process multiple animations

  • Perform complex transformations

  • Build custom Lottie tooling

  • Analyze animation properties

  • Validate Lottie files in CI/CD

  • Create reusable transformation logic

  • Extract metadata programmatically

Use dotlottie-js when you need to:

  • Package animations with assets into .lottie format

  • Prepare animations for app distribution

  • Bundle multiple animations together

  • Optimize delivery size with compression

Use manual editing when:

  • Making a single quick change

  • Testing animation behavior

  • Learning Lottie format

  • No automation required

Combine tools:

  • Use relottie to prepare/transform Lottie JSON

  • Use dotlottie-js to package the result into .lottie format

  • Example: Optimize colors with relottie, bundle with dotlottie-js

When to Use relottie

Ideal Scenarios

Automation & Scale

  • Processing 100+ animation files

  • CI/CD integration for animation validation

  • Automated color/brand updates

Analysis & Reporting

  • Extract metadata from animation libraries

  • Feature compatibility checking

  • Performance analysis

Custom Tooling

  • Building Lottie-specific editors

  • Creating domain-specific validators

  • Developing animation optimization tools

Complex Transformations

  • Multi-step modifications

  • Conditional transformations based on content

  • Cross-file consistency enforcement

Consider Alternatives When

Simple, one-time changes - Manual editing may be faster

Need .lottie format output - Use dotlottie-js directly (or after relottie)

Runtime manipulation - Consider Lottie player APIs instead

No programming required - Use GUI tools like LottieFiles editor

Performance Characteristics

Processing Speed

  • Parsing: ~2-5ms for typical animations (< 1MB JSON)

  • Transformation: Depends on plugin complexity, typically < 10ms

  • Stringification: ~1-3ms for typical animations

  • Total Pipeline: ~5-20ms per file for standard workflows

Memory Usage

  • AST Overhead: ~2-3x source JSON size in memory

  • Streaming: Not currently supported (loads full tree)

  • Recommended: Process files individually for large batches

Optimization Tips

// ✅ Efficient: Single processor, reused
const processor = relottie().use(plugin1).use(plugin2);

for (const file of files) {
  await processor.process(file);
}

// ❌ Inefficient: Creating new processor each time
for (const file of files) {
  const processor = relottie().use(plugin1).use(plugin2);
  await processor.process(file);
}

Benchmarks

Typical performance on M1 MacBook Pro:

  • 100 small animations (< 50KB): ~1-2 seconds

  • 100 medium animations (< 500KB): ~5-10 seconds

  • 100 large animations (> 1MB): ~20-30 seconds

Note: Actual performance varies based on plugin complexity and animation structure.

Next Steps

Learn the Fundamentals

Start Building

Advanced Topics

API Reference

Community & Support

We're excited to see what you build with relottie! Whether you're automating animation workflows, building custom tooling, or analyzing animation libraries at scale, relottie provides the foundation for reliable, maintainable Lottie processing.

Last updated: April 10, 2026 at 9:12 AMEdit this page