# Understanding the Scene
Learn how to access and traverse the Lottie Creator scene.

Lottie Creator organizes animation content in a hierarchy:

- Every Lottie Creator file can have one or more scene
- Scenes and elements in a scene are referred to as **nodes**

```mermaid
flowchart TD
  subgraph File
    Scene1[Scene]
    Scene2[Nestable scene]
  end

  Scene1 --> ShapeLayer[Shape layer]
  Scene1 --> Image[Image layer]
  Scene1 --> Text[Text layer]
  Scene1 --> SceneLayer[Scene layer]

  SceneLayer -.->|references| Scene2

  ShapeLayer --> Group
  ShapeLayer --> Shapes

  Group --> Group2[Group]
  Group --> Shapes
  Scene1 --> Null[Null layer]
  Scene1 --> Audio[Audio layer]
```

Okay, that's probably confusing at first glance, so let's go through this step-by-step:

## Node types

### Scenes

```mermaid
flowchart TD
  subgraph File
    Scene1[Scene]
    Scene2[Nestable scene]
  end

  Scene1 --> ShapeLayer[Shape layer]
  Scene1 --> Image[Image layer]
  Scene1 --> Text[Text layer]
  Scene1 --> SceneLayer[Scene layer]

  SceneLayer -.->|references| Scene2

  ShapeLayer --> Group
  ShapeLayer --> Shapes

  Group --> Group2[Group]
  Group --> Shapes
  Scene1 --> Null[Null layer]
  Scene1 --> Audio[Audio layer]

  style Scene1 fill:#E0F7F4,stroke:#00C1A2,stroke-width:4px
```

- Every Lottie Creator file can have one or more scene
- A scene defines the content of an animation. It has its own canvas, canvas size, framerate, duration, layers, etc.

### Nested scenes and scene layers

```mermaid
flowchart TD
  subgraph File
    Scene1[Scene]
    Scene2[Nestable scene]
  end

  Scene1 --> ShapeLayer[Shape layer]
  Scene1 --> Image[Image layer]
  Scene1 --> Text[Text layer]
  Scene1 --> SceneLayer[Scene layer]

  SceneLayer -.->|references| Scene2

  ShapeLayer --> Group
  ShapeLayer --> Shapes

  Group --> Group2[Group]
  Group --> Shapes
  Scene1 --> Null[Null layer]
  Scene1 --> Audio[Audio layer]

  style Scene2 fill:#E0F7F4,stroke:#00C1A2,stroke-width:4px
  style SceneLayer fill:#E0F7F4,stroke:#00C1A2,stroke-width:4px
  linkStyle 3 stroke:#00C1A2,stroke-width:2px
  linkStyle 4 stroke:#00C1A2,stroke-width:2px
```

- Nested scene
  - A scene can be nestable (can be a child of another scene via a scene layer) or non-nestable
- Scene layer
  - A layer that points to a nestable scene. It behaves like a regular layer (you can position, scale, and animate it), but its content comes from the referenced scene.
  - Changes to the source scene automatically reflect in all instances
  - Use `sceneLayer.scene` to access the referenced scene
  - Use `sceneLayer.break()` to convert it to a regular layer, breaking the link

### Layers

```mermaid
flowchart TD
  subgraph File
    Scene1[Scene]
    Scene2[Nestable scene]
  end

  Scene1 --> ShapeLayer[Shape layer]
  Scene1 --> Image[Image layer]
  Scene1 --> Text[Text layer]
  Scene1 --> SceneLayer[Scene layer]

  SceneLayer -.->|references| Scene2

  ShapeLayer --> Group
  ShapeLayer --> Shapes

  Group --> Group2[Group]
  Group --> Shapes
  Scene1 --> Null[Null layer]
  Scene1 --> Audio[Audio layer]

  style ShapeLayer fill:#E0F7F4,stroke:#00C1A2,stroke-width:4px
  style Image fill:#E0F7F4,stroke:#00C1A2,stroke-width:4px
  style Text fill:#E0F7F4,stroke:#00C1A2,stroke-width:4px
  style SceneLayer fill:#E0F7F4,stroke:#00C1A2,stroke-width:4px
  style Null fill:#E0F7F4,stroke:#00C1A2,stroke-width:4px
  style Audio fill:#E0F7F4,stroke:#00C1A2,stroke-width:4px
  linkStyle 0,1,2,3,9,10 stroke:#00C1A2,stroke-width:2px
```

Layers are top-level elements of a scene:

| Type          | Description                           |
| ------------- | ------------------------------------- |
| `Shape layer` | A layer containing shapes             |
| `Image layer` | A layer containing an image           |
| `Text layer`  | A layer containing text               |
| `Scene layer` | A layer that references another scene |
| `Null layer`  | A transform parent for other layers   |
| `Audio layer` | A layer that plays an audio asset     |

### Shapes

```mermaid
flowchart TD
  subgraph File
    Scene1[Scene]
    Scene2[Nestable scene]
  end

  Scene1 --> ShapeLayer[Shape layer]
  Scene1 --> Image[Image layer]
  Scene1 --> Text[Text layer]
  Scene1 --> SceneLayer[Scene layer]

  SceneLayer -.->|references| Scene2

  ShapeLayer --> Group
  ShapeLayer --> Shapes

  Group --> Group2[Group]
  Group --> Shapes
  Scene1 --> Null[Null layer]
  Scene1 --> Audio[Audio layer]

  style Group fill:#E0F7F4,stroke:#00C1A2,stroke-width:4px
  style Shapes fill:#E0F7F4,stroke:#00C1A2,stroke-width:4px
  style Group2 fill:#E0F7F4,stroke:#00C1A2,stroke-width:4px
  linkStyle 5,6,7,8 stroke:#00C1A2,stroke-width:2px
```

Shapes are nodes that represent, well, shapes. They can be children of containers or groups:

| Type        | Description                       |
| ----------- | --------------------------------- |
| `Group`     | Contains other shapes or groups   |
| `Rectangle` | Rectangle shape                   |
| `Ellipse`   | Ellipse shape                     |
| `Polygon`   | Polygon shape                     |
| `Star`      | Star shape                        |
| `Path`      | Any shape with custom vector data |

## Accessing scene content through `scene`

To access scene content, you can use:

| Entry Point  | Description                           | API                   |
| ------------ | ------------------------------------- | --------------------- |
| Active scene | Access the current active scene       | `creator.activeScene` |
| All scenes   | Access all scenes in the current file | `creator.scenes`      |

From there, you can access the contents of a scene by traversing its layers:

```typescript
const scene = creator.activeScene;
const layers = scene.layers;

for (const layer of layers) {
  // do something with the active scene's layers
  console.log(layer.name, layer.type);
}
```

## Accessing scene content through `selection`

Instead of accessing scene content through the `scene` object, you might want to access it through the current selection:

| Entry Point        | API                           |
| ------------------ | ----------------------------- |
| Selected nodes     | `creator.selection.nodes`     |
| Selected keyframes | `creator.selection.keyframes` |

## Common patterns

When navigating the scene hierarchy, here are patterns you might find helpful:

### 1. Node filtering

- Filter nodes by type to work only with specific node types.
- Useful for: working with selections or nodes that may contain a mix of different node types.

```typescript
// Get only image layers from selection
const imageLayers = creator.selection.nodes.filter((node): node is ImageLayer => node.type === 'IMAGE_LAYER');
```

### 2. Traverse down

- Walk down the node tree to process all children.
- Useful for: finding all shapes within a layer or applying changes recursively.

```typescript
// Recursively visit all shapes in a layer
function visitShapes(parent: ShapeLayer | Group, callback: (shape: Shape) => void) {
  const shapes = parent.shapes;

  for (const shape of shapes) {
    callback(shape);

    // Groups can contain shapes, so recurse into them
    if (shape.type === 'GROUP') {
      visitShapes(shape, callback);
    }
  }
}

// Example: Find all shapes of the selected layer(s)
const selection = creator.selection.nodes;
const shapes: Shape[] = [];

selection.forEach((node) => {
  if (node.type === 'SHAPE_LAYER') {
    visitShapes(node, (shape) => {
      shapes.push(shape);
    });
  }
});
```

{/* TODO(DOCS): add traversal up pattern after the API implements shape.parent */}

## Handling unknown node types

Some APIs, such as `creator.selection.nodes`, can return types your plugin does not support.

To avoid errors and crashes in your plugin, check `type` before reading type-specific members, and provide fallback handling for unknown types.

### Checking a node's type

Every layer, shape and asset has a `type` string, such as `"SHAPE_LAYER"`, `"RECTANGLE"` or `"AUDIO"`. Compare it with `if` or `switch`. In TypeScript, this also narrows the node, so the members of that type become available:

```typescript
for (const node of creator.selection.nodes) {
  switch (node.type) {
    case 'SHAPE_LAYER':
      node.fills; // ShapeLayer members
      break;
    case 'TEXT_LAYER':
      node.text; // TextLayer members
      break;
    case 'RECTANGLE':
      node.size; // Rectangle members
      break;
    default:
      // Unsupported or unknown type: provide fallback handling
      break;
  }
}
```

`creator.utils` has type guards for broader groups:

| Guard                                      | Returns `true` for                                 |
| ------------------------------------------ | -------------------------------------------------- |
| `creator.utils.isLayer(node)`              | Any layer                                          |
| `creator.utils.isShape(node)`              | Any shape                                          |
| `creator.utils.isTransformableLayer(node)` | Layers with a transform (every layer except audio) |

Assets work the same way: check `asset.type` (`"SCENE"`, `"IMAGE"`, `"FONT"`, `"AUDIO"`) before reading asset-specific members.

### Falling back on unsupported types

Keep a list of the types your plugin supports and skip the rest:

```typescript
const SUPPORTED_TYPES: ReadonlySet<string> = new Set(['SHAPE_LAYER', 'TEXT_LAYER', 'RECTANGLE', 'ELLIPSE']);

const supported = creator.selection.nodes.filter((node) => SUPPORTED_TYPES.has(node.type));
```

Decide what your plugin does with the nodes it skips:

- **Skip them and notify the user** when the plugin works on many nodes at once, such as batch-renaming. Tell the user that some layers could not be updated.
- **Notify the user upfront** when they selected only unsupported nodes. Show a message in your plugin UI, such as "Select a shape or text layer".

```typescript
if (supported.length === 0) {
  creator.ui.postMessage({ type: 'unsupported-selection' });
  return;
}
```

`creator.utils.isTransformableLayer` only exists in Creator builds that support audio layers. A plugin that must also run on older builds should use its own type list instead.
