# 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](https://lottiefiles.com/what-is-lottie) animations at scale. Built on the robust [`unified.js`](https://unifiedjs.com/) 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`](https://github.com/syntax-tree/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](/docs/tools/relottie/guides/working-with-last)

### 3. The unified.js Pipeline

relottie is built on [`unified`](https://unifiedjs.com/), a battle-tested content processing engine used by projects like [remark](https://github.com/remarkjs/remark) (Markdown) and [rehype](https://github.com/rehypejs/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

| Feature                    | Capability                                 | Package                                  |
| -------------------------- | ------------------------------------------ | ---------------------------------------- |
| **Parse Lottie JSON**      | Convert JSON to LAST tree                  | `@lottiefiles/relottie-parse`            |
| **Stringify to JSON**      | Convert LAST tree to JSON                  | `@lottiefiles/relottie-stringify`        |
| **Metadata Extraction**    | Width, height, framerate, duration, colors | `@lottiefiles/relottie-metadata`         |
| **Feature Detection**      | Identify used Lottie features              | `@lottiefiles/relottie-extract-features` |
| **Tree Traversal**         | Visit, filter, map, select nodes           | `unist-util-*`                           |
| **Custom Transformations** | Modify colors, properties, structure       | Custom plugins                           |
| **Position Tracking**      | Source maps for error reporting            | Built-in                                 |
| **Expression Detection**   | Security: Flag JS expressions              | Built-in                                 |
| **TypeScript Support**     | Full type definitions                      | All packages                             |
| **CLI Tool**               | Command-line processing                    | `@lottiefiles/relottie-cli`              |
| **AST Building**           | Programmatic AST construction              | `@lottiefiles/last-builder`              |
| **Batch Processing**       | Process multiple files                     | Custom implementation                    |
| **Plugin Development**     | Create custom transformations              | Plugin API                               |

## Plugin Ecosystem Overview

### Official Plugins

**Core (Bundled with relottie):**

- **`@lottiefiles/relottie-parse`**: Parses Lottie JSON into LAST tree
  - Based on [Momoa](https://github.com/humanwhocodes/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](/docs/tools/relottie/ecosystem/plugins)

### Creating Custom Plugins

Plugins are functions that return transformers. A minimal plugin:

```typescript
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](/docs/tools/relottie/guides/creating-plugins)

## Quick Start

### Installation

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

### Basic Usage: Update Animation Version

```typescript
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

```typescript
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

```typescript
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:

```typescript
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:

```typescript
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:

```typescript
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:

```typescript
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:

```typescript
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

| Aspect              | relottie                               | dotlottie-js                        | Manual JSON Editing     |
| ------------------- | -------------------------------------- | ----------------------------------- | ----------------------- |
| **Primary Purpose** | Programmatic analysis & transformation | Create .lottie bundles              | Quick one-off edits     |
| **Use Case**        | Batch processing, automation, tooling  | Package animations for distribution | Simple value changes    |
| **Input Format**    | Lottie JSON                            | Lottie JSON + assets                | Lottie JSON             |
| **Output Format**   | Lottie JSON                            | .lottie binary format               | Lottie JSON             |
| **Transformation**  | Full AST-based manipulation            | Limited (bundling focus)            | Manual find/replace     |
| **Type Safety**     | Full TypeScript support                | TypeScript API                      | None                    |
| **Validation**      | AST structure validation               | Format validation                   | None                    |
| **Extensibility**   | Plugin ecosystem                       | Fixed feature set                   | N/A                     |
| **Scale**           | Hundreds/thousands of files            | Individual conversions              | Single files            |
| **Learning Curve**  | Moderate (AST concepts)                | Low                                 | Very low                |
| **Performance**     | Fast (optimized traversal)             | Fast                                | Instant (no processing) |
| **Error Handling**  | Detailed position info                 | Standard errors                     | No validation           |
| **Best For**        | Automation, CI/CD, tooling             | Distribution, app bundling          | Quick 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

```typescript
// ✅ 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

- **[Core Concepts](/docs/tools/relottie/getting-started/core-concepts)**: Deep dive into ASTs, LAST, and the processing pipeline
- **[What is relottie?](/docs/tools/relottie/getting-started/introduction)**: Understand the philosophy and architecture
- **[Why use relottie?](/docs/tools/relottie/getting-started/why-relottie)**: Explore use cases and benefits

### Start Building

- **[Quick Start](/docs/tools/relottie/getting-started/quick-start)**: Build your first transformation
- **[Usage Guide](/docs/tools/relottie/getting-started/usage-guide)**: Practical examples and patterns
- **[Using the CLI](/docs/tools/relottie/guides/using-the-cli)**: Command-line workflows

### Advanced Topics

- **[Working with LAST](/docs/tools/relottie/guides/working-with-last)**: Master the AST structure
- **[Creating Plugins](/docs/tools/relottie/guides/creating-plugins)**: Build custom transformations
- **[Modifying Lottie Files](/docs/tools/relottie/guides/modifying-lottie-files)**: Complex transformation patterns
- **[Analyzing Lottie Files](/docs/tools/relottie/guides/analyzing-lottie-files)**: Extract insights from animations

### API Reference

- **[Processor API](/docs/tools/relottie/api/relottie-processor)**: Core processor methods
- **[Parse Plugin](/docs/tools/relottie/api/relottie-parse)**: Parser configuration
- **[Stringify Plugin](/docs/tools/relottie/api/relottie-stringify)**: Output formatting
- **[Metadata Plugin](/docs/tools/relottie/api/relottie-metadata)**: Extract animation metadata
- **[Extract Features Plugin](/docs/tools/relottie/api/relottie-extract-features)**: Feature detection
- **[LAST Specification](/docs/tools/relottie/api/last-specification)**: Complete AST reference

### Community & Support

- **[GitHub Repository](https://github.com/LottieFiles/relottie)**: Source code and issue tracking
- **[Plugin Ecosystem](/docs/tools/relottie/ecosystem/plugins)**: Discover and share plugins
- **[Security Considerations](/docs/tools/relottie/ecosystem/security)**: Best practices for safe usage

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.
