Command Palette

Search for a command to run...

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:

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.

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 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) 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) are actually used in the animation. It stores this information, including counts, in vfile.data['extract-features'].

1. Installation

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.

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 for the full ExtractFeaturesFileData interface.

Combining Analysis Plugins

You can easily use both plugins in the same pipeline:

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

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