# How Plugins Work
Understand the architecture of Lottie Creator Plugins.

For security purposes, Lottie Creator plugins are separated into a plugin sandbox (where your plugin code runs), and a UI iframe (where your plugin interface lives).

Your plugin sandbox and UI can communicate with each other via `postmessage`.

## Plugin architecture

Here's how Lottie Creator, your plugin sandbox, and your plugin UI connect:

```mermaid
flowchart LR
  subgraph creator["Lottie Creator"]
    scene["Scene graph (layers, shapes, keyframes, etc.)"]
  end

  subgraph sandbox["Plugin sandbox"]
    code["Your plugin code"]
  end

  subgraph iframe["Plugin UI (iframe)"]
    ui["Your HTML & JS code"]
  end

  scene <-->|"creator API"| code
  code <-->|"postMessage"| ui

```

Here's the difference between the plugin sandbox and the UI iframe:

<table>
  <thead>
    <tr>
      <th />

      <th>Plugin sandbox</th>
      <th>UI iframe</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        <strong>Runs</strong>
      </td>

      <td>
        Your plugin code (<code>plugin.ts/plugin.js</code>)
      </td>

      <td>
        Your interface (<code>App.tsx</code> or HTML)
      </td>
    </tr>

    <tr>
      <td>
        <strong>Has access to</strong>
      </td>

      <td>Creator APIs</td>
      <td>Browser APIs</td>
    </tr>

    <tr>
      <td>
        <strong>Can</strong>
      </td>

      <td>
        <ul>
          <li>Read/modify layers, shapes, keyframes</li>
          <li>Control the timeline</li>
          <li>Access user selection</li>
          <li>Store plugin data</li>
        </ul>
      </td>

      <td>
        <ul>
          <li>Render UI with React, Vue, or plain HTML</li>
          <li>Make network requests (fetch)</li>
          <li>Handle user input</li>
        </ul>
      </td>
    </tr>

    <tr>
      <td>
        <strong>Cannot</strong>
      </td>

      <td>
        <ul>
          <li>Directly update the DOM</li>
          <li>Access browser APIs</li>
        </ul>
      </td>

      <td>
        <ul>
          <li>Access Creator APIs</li>
          <li>Access the animation scene</li>
        </ul>
      </td>
    </tr>
  </tbody>
</table>

## Communication between UI and plugin

The two parts communicate through message passing. For example, here's how we might set up a plugin that creates a rectangle when you click on a button:

```mermaid
sequenceDiagram
    participant UI as Plugin UI (iframe)
    participant Plugin as Plugin Sandbox
    participant Creator as Lottie Creator API

    UI->>Plugin: postMessage({ pluginMessage: { type: 'create-rectangle' } })
    Plugin->>Creator: creator.activeScene.createShapeLayer()
    Creator->>Plugin: Returns created layer
    Plugin->>UI: creator.ui.postMessage({ type: 'success' })
```

### 1. UI sends a message to the plugin

When the user clicks the button, the UI sends a message to the plugin sandbox using `parent.postMessage()`.

```tsx
// In plugin UI (App.tsx)

function App() {
  const createRectangle = () => {
    // send a message to the plugin sandbox (must wrap in pluginMessage)
    parent.postMessage({ pluginMessage: { type: "create-rectangle" } }, "*");
  };

  return <button onClick={createRectangle}>Create Rectangle</button>;
}
```

### 2. Plugin receives the message and responds

The plugin sandbox listens for messages using `creator.ui.onMessage()`. When it receives the message, it can use the `creator` API to modify the scene, then send a response back to the UI.

```typescript
// In plugin sandbox (plugin.ts)

creator.ui.onMessage((message) => {
  // receive the message from the UI
  if (message.type === "create-rectangle") {
    // use the creator API to create a shape layer with a rectangle shape
    const layer = creator.activeScene.createShapeLayer({
      position: { x: 100, y: 100 },
    });
    layer.createRectangle({ size: { width: 200, height: 200 } });

    const fill = layer.createFill({
      type: "SOLID",
      color: { r: 0, g: 255, b: 0 },
    });

    // send a response back to the UI
    creator.ui.postMessage({ type: "success" });
  }
});
```

### 3. UI receives the response

The UI listens for messages from the plugin using `window.addEventListener('message', ...)`.

```tsx
// In plugin UI (App.tsx)

useEffect(() => {
  const handler = (event: MessageEvent) => {
    // extract the plugin message from the event (messages are wrapped in pluginMessage)
    const message = event.data.pluginMessage;

    if (message?.type === "success") {
      console.log("Rectangle created!");
    }
  };

  // listen for messages from the plugin sandbox
  window.addEventListener("message", handler);
  return () => window.removeEventListener("message", handler);
}, []);
```
