# 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`](https://github.com/syntax-tree/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](#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`](https://github.com/syntax-tree/unist-util-visit)).
- **Learn More:** Refer to the [unist Glossary](https://github.com/syntax-tree/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`.
  ```typescript
  // 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.
  ```typescript
  // 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.

  ```typescript
  // 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](https://lottiefiles.github.io/lottie-docs/expressions/#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](/docs/tools/relottie/ecosystem/security) for more details.

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

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

  ```typescript
  // 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`).

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

  ```typescript
  // 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).

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

  ```typescript
  // 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).
  ```typescript
  // 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](https://lottiefiles.github.io/lottie-docs/).

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

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

A simplified representation of its LAST tree might look like:

```json
{
  "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`](/docs/tools/relottie/api/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](/docs/tools/relottie/api/last-builder) for details on these functions.

## Further Reference

- For the complete definition of all node types and their properties, consult the [**LAST Specification (`@lottiefiles/last`)**](/docs/tools/relottie/guides/working-with-last).
- To see how to traverse and change nodes, refer back to the [Modifying Lottie Files Guide](/docs/tools/relottie/guides/modifying-lottie-files).
