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-metadata2. 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: ASetof 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 asoutPoint).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
positionobject on a LAST node details the node's location in the original Lottie JSON source string. It usually contains:start: An object withline,column, andoffsetfor the beginning of the node.end: An object withline,column, andoffsetfor 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
positioninformation 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
positioncan 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-visitin a custom plugin), you can accessnode.positionon most nodes. Therelottie-parseplugin 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-features2. 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: AMapwhere keys are the featuretitlestrings (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: AMapdetailing 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
Learn how to make changes based on analysis in the Modifying Lottie Files Guide.
Explore the structure you are analyzing in the Working with LAST Guide.