# Guide to Analyzing Lottie Files
Learn how to analyze Lottie files using relottie. This guide covers using relottie-metadata and relottie-extract-features plugins to get insights into your animations.

# Guide: Analyzing Lottie Files

Beyond transforming Lottie files, relottie provides plugins specifically designed for analyzing their content and extracting useful information. This guide focuses on using the official `@lottiefiles/relottie-metadata` and `@lottiefiles/relottie-extract-features` plugins.

## Analyzing Metadata with `relottie-metadata`

This plugin extracts common metadata properties from a Lottie animation and attaches them to the `vfile.data.metadata` object during processing.

### 1. Installation

If you haven't already installed the core `relottie` package, do so first. Then, install the metadata plugin:

```bash
npm install @lottiefiles/relottie-metadata
# or
yarn add @lottiefiles/relottie-metadata
```

### 2. Usage

Include the plugin in your relottie pipeline using `.use()`. The extracted data will be available on the `data` property of the resulting VFile object.

```typescript
import { relottie } from "@lottiefiles/relottie";
import relottieMetadata, { type MetadataFileData, type Metadata } from "@lottiefiles/relottie-metadata";

// Example Lottie JSON (replace with your actual Lottie data)
const inputLottie = `{
  "v": "5.5.7",
  "fr": 60,
  "ip": 0,
  "op": 180,
  "w": 512,
  "h": 512,
  "nm": "Metadata Example",
  "ddd": 0,
  "assets": [],
  "layers": [
    {
      "ty": 4, "ks": { "c": { "k": [0.196, 0.314, 0.69, 1] } } // Shape layer with color #3250B0
    }
  ],
  "markers": [],
  "g": "Test Generator v1.0" // Custom field for generator in this example
}`;

async function extractMetadata() {
  try {
    const file = await relottie()
      .use(relottieMetadata) // Add the metadata plugin
      .process(inputLottie);

    // Type assertion for accessing the custom data
    const fileData = file.data as MetadataFileData;
    const metadata: Metadata | undefined = fileData.metadata; // Destructure for easier access

    if (metadata) {
      console.log("Extracted Metadata:");
      // console.log(metadata); // Log the whole metadata object if needed

      // Example: Accessing specific properties
      console.log(`\\nVersion: ${metadata.version}`);
      console.log(`Framerate: ${metadata.framerate}fps`);
      console.log(
        `Duration: ${metadata.outPoint - metadata.inPoint} frames (${
          (metadata.outPoint - metadata.inPoint) / metadata.framerate
        } seconds)`
      );
      console.log(`Dimensions: ${metadata.width}x${metadata.height}`);
      console.log(`Colors Used: ${Array.from(metadata.colors).join(", ")}`);
      console.log(`Generator: ${metadata.generator || "N/A"}`);
      if (metadata.fileSize) {
        console.log(`File Size: ${metadata.fileSize.formated.value} ${metadata.fileSize.formated.unit}`);
      }
    } else {
      console.log("No metadata found.");
    }
  } catch (error) {
    console.error("Error processing Lottie or extracting metadata:", error);
  }
}

extractMetadata();
```

### 3. Output (`vfile.data.metadata`)

The `metadata` object attached to `vfile.data` contains properties like:

- `colors`: A `Set` of unique hex color strings used.
- `fileSize`: Information about the Lottie JSON size (if processing a file, may require extra setup not shown in the basic plugin example).
- `framerate`: Animation framerate (frames per second).
- `frames`: Total number of frames (often same as `outPoint`).
- `generator`: The tool used to generate the Lottie (if specified in the JSON).
- `height`: Animation height.
- `width`: Animation width.
- `inPoint`: Starting frame (usually 0).
- `outPoint`: Ending frame (duration in frames).
- `version`: Lottie version string.

See the [API Reference for `relottie-metadata`](/docs/tools/relottie/api/relottie-metadata) for the full `MetadataFileData` interface.

### Understanding the `position` Property in LAST Nodes

While not directly part of the `relottie-metadata` output, it's important to understand that nodes in the [LAST (Lottie Abstract Syntax Tree)](/docs/tools/relottie/guides/working-with-last) generated by `relottie-parse` (and thus used by `relottie-metadata`) typically include a `position` property. This property is inherited from the underlying `unist` specification.

- **What it is:** The `position` object on a LAST node details the node's location in the original Lottie JSON source string. It usually contains:
  - `start`: An object with `line`, `column`, and `offset` for the beginning of the node.
  - `end`: An object with `line`, `column`, and `offset` for the end of the node.
- **Why it's needed:**
  - **Error Reporting:** If a plugin encounters an issue with a specific part of the Lottie structure, it can use the `position` information to provide precise error messages, pointing the user to the exact location in the source JSON.
  - **Source Mapping:** Tools that need to correlate the AST back to the original text (e.g., linters, advanced editors) can use `position`.
  - **Debugging:** When developing plugins, inspecting the `position` can help understand how the parser mapped JSON segments to AST nodes.
- **How to use it:** When you traverse the LAST tree (e.g., using `unist-util-visit` in a custom plugin), you can access `node.position` on most nodes. The `relottie-parse` plugin includes this by default, but it can be disabled via parser options if not needed, which can slightly reduce the AST's memory footprint.

## Analyzing Feature Usage with `relottie-extract-features`

This plugin inspects the Lottie AST to determine which features (represented by their `title` in the [LAST specification](/docs/tools/relottie/guides/working-with-last)) are actually used in the animation. It stores this information, including counts, in `vfile.data['extract-features']`.

### 1. Installation

```bash
npm install @lottiefiles/relottie-extract-features
# or
yarn add @lottiefiles/relottie-extract-features
```

### 2. Usage

Add the plugin to your pipeline. The analysis results are attached to the VFile's data.

```typescript
import { relottie } from "@lottiefiles/relottie";
import relottieExtractFeatures, {
  type ExtractFeaturesFileData,
  type UsedFeature, // Assuming UsedFeature is the type for Map values
} from "@lottiefiles/relottie-extract-features";
import { TITLES } from "@lottiefiles/last"; // Import TITLES

// Example Lottie JSON with an image layer and a shape layer
const inputLottie = `{
    "v":"5.5.7",
    "fr": 30,
    "ip": 0,
    "op": 60,
    "w": 200,
    "h": 200,
    "layers": [
      { "ty": 2, "ddd": 0, "ind": 1, "refId": "image_0", "nm": "ImageLayer" },
      {
        "ty": 4, "ddd": 0, "ind": 2, "nm": "ShapeLayer",
        "shapes": [
          { "ty": "gr", "it": [{ "ty": "rc", "s": [100,100], "p": [0,0], "r": 0, "nm": "Rectangle" }], "nm": "Group" }
        ]
      }
    ],
    "assets": [
      { "id": "image_0", "w": 50, "h": 50, "u": "images/", "p": "img_0.png", "e": 0 }
    ]
  }`;

async function extractFeatures() {
  try {
    const file = await relottie()
      .use(relottieExtractFeatures) // Add the feature extraction plugin
      .process(inputLottie);

    // Type assertion to access the data
    const fileData = file.data as ExtractFeaturesFileData;
    const featureData = fileData["extract-features"];

    if (featureData && featureData.used) {
      console.log("Extracted Feature Usage:");
      // The 'used' property is a Map
      for (const [featureTitle, usageInfo] of featureData.used.entries()) {
        console.log(`- Feature '${featureTitle}':`);
        console.log(`    Used Count (y): ${usageInfo.y}`);
        console.log(`    Unused Count (n): ${usageInfo.n}`);
        if (usageInfo.parents && usageInfo.parents.size > 0) {
          console.log("    Parents (Context of Use):");
          for (const [parentTitle, parentUsage] of usageInfo.parents.entries()) {
            console.log(`      - In '${parentTitle}': Used: ${parentUsage.y}, Unused: ${parentUsage.n}`);
          }
        }
      }

      // Example: Check usage of a specific feature title from TITLES
      const shapeRectangleUsage = featureData.used.get(TITLES.object["shape-rect"]); // Using TITLES
      if (shapeRectangleUsage) {
        console.log(`\\nSpecific Check - Rectangle Shape (shape-rect) Usage:`);
        console.log(`  - Used count: ${shapeRectangleUsage.y}`);
      }
    } else {
      console.log("No feature usage data found.");
    }
  } catch (error) {
    console.error("Error processing Lottie or extracting features:", error);
  }
}

extractFeatures();
```

### 3. Output (`vfile.data['extract-features']`)

The `extract-features` object contains:

- `used`: A `Map` where keys are the feature `title` strings (from the LAST specification) and values are objects containing:
  - `y`: Total count of times the feature was used.
  - `n`: Total count of times the feature was present but considered unused (e.g., a property set to its default value).
  - `parents`: A `Map` detailing usage counts within specific parent node types.

This data can be useful for understanding animation complexity, identifying potentially unused elements for optimization, or ensuring compatibility.

See the [API Reference for `relottie-extract-features`](/docs/tools/relottie/api/relottie-extract-features) for the full `ExtractFeaturesFileData` interface.

## Combining Analysis Plugins

You can easily use both plugins in the same pipeline:

```typescript
import { relottie } from "@lottiefiles/relottie";
import relottieMetadata, { type MetadataFileData, type Metadata } from "@lottiefiles/relottie-metadata";
import relottieExtractFeatures, { type ExtractFeaturesFileData } from "@lottiefiles/relottie-extract-features";
import { TITLES } from "@lottiefiles/last";

// Use the same inputLottie from the extractFeatures example or define a new one
const combinedInputLottie = `{
    "v":"5.5.8", "fr": 24, "w": 300, "h": 300, "nm": "Combined Analysis",
    "layers": [
      { "ty": 4, "ks": { "c": { "k": [0,0,1,1] } }, "nm": "Blue Shape" }, // Blue color
      { "ty": 2, "refId": "img_1", "nm": "Another Image" }
    ],
    "assets": [ { "id": "img_1", "p": "image.png" } ]
  }`;

async function analyzeAll() {
  try {
    const file = await relottie().use(relottieMetadata).use(relottieExtractFeatures).process(combinedInputLottie);

    // Access metadata
    const metadata = (file.data as MetadataFileData).metadata;
    if (metadata) {
      console.log("\\n--- Combined Analysis: Metadata ---");
      console.log(`Animation: ${metadata.name || "Untitled"}`);
      console.log(`Dimensions: ${metadata.width}x${metadata.height}, Framerate: ${metadata.framerate}fps`);
      console.log(`Colors: ${Array.from(metadata.colors).join(", ")}`);
    } else {
      console.log("\\n--- Combined Analysis: No Metadata Found ---");
    }

    // Access feature usage
    const featuresData = (file.data as ExtractFeaturesFileData)["extract-features"];
    if (featuresData && featuresData.used) {
      console.log("\\n--- Combined Analysis: Feature Usage ---");
      const imageLayerUsage = featuresData.used.get(TITLES.object["layer-image"]);
      if (imageLayerUsage) {
        console.log(`Image Layers Used: ${imageLayerUsage.y}`);
      }
      const shapeLayerUsage = featuresData.used.get(TITLES.object["layer-shape"]);
      if (shapeLayerUsage) {
        console.log(`Shape Layers Used: ${shapeLayerUsage.y}`);
      }
      // You can iterate through all features as shown in the standalone example
    } else {
      console.log("\\n--- Combined Analysis: No Feature Data Found ---");
    }
  } catch (error) {
    console.error("Error during combined analysis:", error);
  }
}

analyzeAll();
```

This example demonstrates how data from multiple analysis plugins can be collected on the same `VFile` object after processing. The output would show metadata information first, followed by details about feature usage.

## Next Steps

- Learn how to make changes based on analysis in the [Modifying Lottie Files Guide](/docs/tools/relottie/guides/modifying-lottie-files).
- Explore the structure you are analyzing in the [Working with LAST Guide](/docs/tools/relottie/guides/working-with-last).
