Command Palette

Search for a command to run...

Guide to Working with LAST (Lottie Abstract Syntax Tree)

Learn how to work with LAST, the Lottie Abstract Syntax Tree used by relottie. Understand its unist base, key node types, the semantic title property, and how to build LAST trees.

Guide: Working with LAST

Understanding the LAST (Lottie Abstract Syntax Tree) is fundamental to analyzing or modifying Lottie files with relottie. LAST is the specific format relottie uses to represent the structure and content of Lottie JSON in a traversable tree.

Based on unist

LAST is built upon the unist (Universal Syntax Tree) specification. This means:

  • Standard Structure: LAST nodes follow the basic unist structure. Key properties include:

    • type: A string indicating the node's type (e.g., 'root', 'attribute', 'primitive').

    • children: An array of child nodes (for Parent nodes).

    • value: The literal value of the node (for Literal nodes).

    • position: (Optional) An object detailing the node's location (start and end points including line, column, and offset) in the original Lottie JSON source. This is invaluable for error reporting and source mapping. See more on the Position Property below.

  • Ecosystem Compatibility: You can use general-purpose unist utilities for traversing, inspecting, and manipulating LAST trees (e.g., unist-util-visit).

  • Learn More: Refer to the unist Glossary for common terminology like tree, node, parent, child, root, etc.

Key LAST Node Types

The @lottiefiles/last package defines the TypeScript interfaces for all nodes. Here are the essential types:

Abstract Base Interfaces (from unist)

These are foundational types that other LAST nodes extend:

  • Literal: Represents a node that contains a value.

    // Interface (simplified from unist)
    interface Literal extends Node {
      value: any;
    }
  • Parent: Represents a node that contains other nodes in a children array. In LAST, this interface is extended to also include a mandatory title property, which provides Lottie-specific semantic meaning.

    // Interface (simplified from unist & last)
    interface Parent extends Node {
      children: Node[];
      title: AnyTitle; // Lottie semantic title
    }

Core LAST Nodes

  • Root: The top-level node representing the entire Lottie animation object.

    // Simplified structure
    {
      type: "root",
      title: "animation", // Always "animation"
      hasExpressions: false, // Boolean flag
      children: [
        // Attribute, Element, or Collection nodes for global animation properties
      ]
      // position?: PositionData;
    }
    • The hasExpressions: boolean flag is a crucial security feature. If true, it indicates the Lottie animation may contain JavaScript expressions. Expressions can introduce security risks (like XSS) if the Lottie is rendered in an environment that executes them without sanitization. This flag helps identify such animations early for careful handling. See Security Considerations for more details.

  • Primitive: Represents a primitive JSON value (string, number, boolean, or null).

    // Simplified structure
    {
      type: "primitive",
      value: "5.5.7", // or 5.5.7, true, null
      valueType: "string" // or "number", "boolean", "null"
      // position?: PositionData;
    }
  • KeyNode: Represents the key (property name) in a JSON key-value pair.

    // Simplified structure
    {
      type: "key",
      value: "v" // The actual JSON key as a string
      // position?: PositionData;
    }
  • Member (Interface): Not a concrete node type, but a base TypeScript interface shared by Attribute, Element, and Collection. It defines common properties for nodes that represent JSON key-value pairs:

    • key: The JSON property name (a KeyNode or a string).

    • title: The Lottie semantic meaning for this member (e.g., 'version', 'layer-image'). This is critical for understanding the Lottie structure beyond plain JSON.

  • Attribute: A Member node whose value is a single Primitive or is empty (representing an implicit null or default value in some Lottie contexts, though typically it holds one Primitive).

    // Simplified structure for: "v": "5.5.7"
    {
      type: "attribute",
      key: "v", // Or a KeyNode
      title: "version", // Semantic title from TITLES
      children: [
        { type: "primitive", value: "5.5.7", valueType: "string" }
      ]
      // position?: PositionData;
    }
  • ObjectNode: Represents the value part of an Element (a JSON object). Its children are Attribute, Element, or Collection nodes.

    // Simplified structure for the value of: "meta": { "a": "LottieFiles" }
    {
      type: "object",
      title: "custom", // Or another ObjectTitle like "animation-settings"
      children: [
        {
          type: "attribute",
          key: "a",
          title: "author",
          children: [ { type: "primitive", value: "LottieFiles" } ]
        }
      ]
      // position?: PositionData;
    }
  • Element: A Member node whose value is a JSON object, represented by a child ObjectNode (or is empty).

    // Simplified structure for: "meta": { "a": "LottieFiles" }
    {
      type: "element",
      key: "meta",
      title: "metadata", // Semantic title from TITLES
      children: [
        // One ObjectNode (as shown above)
      ]
      // position?: PositionData;
    }
  • ArrayNode: Represents the value part of a Collection (a JSON array). Its children can be Primitive, ObjectNode, or other ArrayNode instances.

    // Simplified structure for the value of: "layers": [ { ...layer1... } ]
    {
      type: "array",
      title: "array", // Or another ArrayTitle
      children: [
        // ObjectNode representing layer1, etc.
      ]
      // position?: PositionData;
    }
  • Collection: A Member node whose value is a JSON array, represented by a child ArrayNode (or is empty).

    // Simplified structure for: "layers": [ { ... } ]
    {
      type: "collection",
      key: "layers",
      title: "composition-children", // Semantic title from TITLES
      children: [
        // One ArrayNode (as shown above)
      ]
      // position?: PositionData;
    }

The title Property and TITLES

A crucial addition in LAST compared to a generic JSON AST is the title property on many nodes (especially Parent nodes: Root, Attribute, Element, Collection, ObjectNode, ArrayNode).

  • Semantic Meaning: This title provides the Lottie-specific meaning of the node within the animation's structure (e.g., version, layer-image, transform-anchor-point, shape-rectangle). These titles are defined in and exported as the TITLES object from the @lottiefiles/last package (e.g., TITLES.string.version, TITLES.object.layerImage, TITLES.number.transformAnchorPointX). Using these constants (e.g. const { string: ST, object: OT } = TITLES; ... if (node.title === ST.version)) is highly recommended for robustness when writing plugins, as it protects against typos and provides type safety with TypeScript.

  • Disambiguation: Titles help distinguish between JSON keys that might be ambiguous or have different meanings in different contexts (e.g., a "nm" key could be a layer name, shape name, or asset name; its title would clarify this).

  • Based on Lottie Docs: The semantic titles are derived from the official Lottie documentation.

The custom Title

The TITLES object also includes TITLES.custom (evaluating to the string 'custom'). Many title types in LAST (like AttributeTitle, ElementTitle, etc.) can also accept this 'custom' value. This allows LAST to represent:

  • Non-standard properties found in a Lottie JSON that are not part of the official specification.

  • User-defined data or metadata that plugins might want to attach to the tree. When a parser encounters a JSON property it doesn't have a predefined semantic title for, it may assign it the 'custom' title. When building nodes, you can also use TITLES.custom if you are adding properties not covered by the standard Lottie titles.

The position Property

As mentioned earlier, most nodes in a LAST tree generated by relottie-parse will have a position property (unless disabled in parser options). This property is part of the unist specification and is vital for tools that need to relate AST nodes back to their origin in the source Lottie JSON file.

  • Structure: The position object typically contains start and end points:

    interface Position {
      start: Point;
      end: Point;
      indent?: number[]; // (optional) line indents
    }
    interface Point {
      line: number; // 1-indexed line number
      column: number; // 1-indexed column number
      offset?: number; // 0-indexed character offset from start of file
    }
  • Use Cases:

    • Error Reporting: Pinpointing the exact location of an error in the input Lottie JSON.

    • Linters & Formatters: Applying rules or changes based on source location.

    • Source Mapping: In more complex toolchains, mapping from the AST back to the original text or even to a UI.

    • Plugin Development: Understanding how the parser segmented the input can be helpful for debugging plugins.

When traversing the tree, node.position can be accessed to get this information.

Example Tree Snippet

Consider this simple Lottie JSON:

{ "v": "5.5.7", "layers": [] }

A simplified representation of its LAST tree might look like:

{
  "type": "root",
  "title": "animation",
  "children": [
    {
      "type": "attribute",
      "key": "v",
      "title": "version",
      "children": [{ "type": "primitive", "value": "5.5.7", "valueType": "string" }]
    },
    {
      "type": "collection",
      "key": "layers",
      "title": "composition-children", // Semantic title for layers
      "children": [
        { "type": "array", "title": "array", "children": [] } // Empty array node
      ]
    }
  ]
}

(Note: Real nodes include position information by default, and keys might be KeyNode objects instead of raw strings, though builders often simplify this.)

Building LAST Trees Programmatically

Sometimes, you might need to create LAST nodes or entire trees from scratch, perhaps for generating Lottie files or complex manipulations. The @lottiefiles/last-builder package provides composable helper functions (like rt for root, at for attribute, el for element, pt for primitive) to make this process easier and less error-prone.

See the last-builder API reference for details on these functions.

Further Reference

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