> ## Documentation Index
> Fetch the complete documentation index at: https://docs.goalgen.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Manifest Schema

> Complete reference for StudioTemplateManifestV1 — the JSON format produced by the GoalGen Creator Figma plugin.

## Overview

Every export from the GoalGen Creator plugin produces a `manifest.json` conforming to `StudioTemplateManifestV1`. Creator Studio uses this file to reconstruct the template on the canvas.

```json Example manifest.json theme={null}
{
  "_schema": "StudioTemplateManifestV1",
  "_pluginVersion": "1.1.0",
  "name": "Birthday Announcement",
  "frameWidth": 1080,
  "frameHeight": 1080,
  "layers": [
    {
      "id": "2:45",
      "name": "Background",
      "kind": "rect",
      "x": 0,
      "y": 0,
      "width": 1080,
      "height": 1080,
      "rotation": 0,
      "visible": true,
      "opacity": 1,
      "editableStyle": {
        "fill": "#1a1a2e"
      }
    },
    {
      "id": "2:46",
      "name": "profile-photo",
      "kind": "image",
      "x": 290,
      "y": 120,
      "width": 500,
      "height": 500,
      "rotation": 0,
      "visible": true,
      "opacity": 1,
      "src": "profile-photo.png"
    }
  ],
  "slots": [
    {
      "slotId": "slot-0",
      "targetLayerId": "2:46",
      "role": "userImage"
    }
  ]
}
```

***

## Top-level fields

| Field            | Type                         | Required | Description                                                                                 |
| ---------------- | ---------------------------- | -------- | ------------------------------------------------------------------------------------------- |
| `_schema`        | `"StudioTemplateManifestV1"` | ✅        | Schema identifier. Always this exact string.                                                |
| `_pluginVersion` | `string`                     | ✅        | Plugin version that produced this file (e.g. `"1.1.0"`).                                    |
| `name`           | `string`                     | ✅        | Display name of the template, taken from the Figma frame name.                              |
| `frameWidth`     | `number`                     | ✅        | Frame width in pixels (Figma document units).                                               |
| `frameHeight`    | `number`                     | ✅        | Frame height in pixels.                                                                     |
| `layers`         | `Layer[]`                    | ✅        | Ordered array of all exported layers (back-to-front).                                       |
| `slots`          | `Slot[]`                     | —        | Dynamic slot assignments. Present when the user has marked at least one slot in the plugin. |

***

## Layer object

Every item in `layers` shares a common set of geometry fields, plus kind-specific fields.

### Common geometry fields

| Field      | Type                                    | Description                                                |
| ---------- | --------------------------------------- | ---------------------------------------------------------- |
| `id`       | `string`                                | Figma node ID (e.g. `"2:45"`). Unique within the manifest. |
| `name`     | `string`                                | Original Figma layer name.                                 |
| `kind`     | `"rect" \| "path" \| "image" \| "text"` | Layer classification (see below).                          |
| `x`        | `number`                                | Horizontal offset from the frame origin, in pixels.        |
| `y`        | `number`                                | Vertical offset from the frame origin, in pixels.          |
| `width`    | `number`                                | Bounding box width, in pixels.                             |
| `height`   | `number`                                | Bounding box height, in pixels.                            |
| `rotation` | `number`                                | Clockwise rotation in degrees.                             |
| `visible`  | `boolean`                               | Whether the layer was visible at export time.              |
| `opacity`  | `number`                                | Layer opacity, `0`–`1`.                                    |

### `kind: "rect"` — Rectangle

A simple solid rectangle. No asset file. Style is encoded directly in the manifest.

```json theme={null}
{
  "kind": "rect",
  "editableStyle": {
    "fill": "#ff6b6b",
    "cornerRadius": 12
  }
}
```

| `editableStyle` field | Type     | Description                        |
| --------------------- | -------- | ---------------------------------- |
| `fill`                | `string` | CSS hex colour (e.g. `"#ff6b6b"`). |
| `cornerRadius`        | `number` | Border radius in pixels.           |

### `kind: "path"` — Vector path (manifest-encoded)

A vector shape exported as path data. No asset file.

```json theme={null}
{
  "kind": "path",
  "pathData": "M 0 0 L 100 0 L 50 100 Z",
  "editableStyle": {
    "fill": "#ffffff"
  }
}
```

| Field                | Type     | Description                   |
| -------------------- | -------- | ----------------------------- |
| `pathData`           | `string` | SVG path `d` attribute value. |
| `editableStyle.fill` | `string` | Fill colour.                  |

### `kind: "image"` — Raster or vector asset

A layer exported as a PNG or SVG file.

```json theme={null}
{
  "kind": "image",
  "src": "hero-illustration.svg"
}
```

| Field | Type     | Description                                                                                                      |
| ----- | -------- | ---------------------------------------------------------------------------------------------------------------- |
| `src` | `string` | Filename of the asset (relative to the ZIP root). After Studio import this is replaced with an absolute CDN URL. |

<Info>
  At import time, Creator Studio replaces all relative `src` values with the permanent CDN URLs of the uploaded assets.
</Info>

### `kind: "text"` — Text layer

A text layer. The text content is preserved but font rendering is left to the canvas engine.

```json theme={null}
{
  "kind": "text",
  "editableStyle": {
    "content": "Happy Birthday!",
    "fontFamily": "Inter",
    "fontSize": 72,
    "fontWeight": 700,
    "color": "#ffffff",
    "textAlign": "center"
  }
}
```

| `editableStyle` field | Type                                           | Description                              |
| --------------------- | ---------------------------------------------- | ---------------------------------------- |
| `content`             | `string`                                       | The raw text content.                    |
| `fontFamily`          | `string`                                       | Font family name as registered in Figma. |
| `fontSize`            | `number`                                       | Font size in pixels.                     |
| `fontWeight`          | `number`                                       | CSS font weight (100–900).               |
| `color`               | `string`                                       | CSS hex colour.                          |
| `textAlign`           | `"left" \| "center" \| "right" \| "justified"` | Horizontal alignment.                    |

***

## Slot object

Slots declare which layers are dynamic — i.e., replaceable by the end-user when they personalise a template.

```json theme={null}
{
  "slotId": "slot-0",
  "targetLayerId": "2:46",
  "role": "userImage"
}
```

| Field           | Type       | Description                                                                      |
| --------------- | ---------- | -------------------------------------------------------------------------------- |
| `slotId`        | `string`   | Unique identifier within the manifest (auto-generated as `slot-0`, `slot-1`, …). |
| `targetLayerId` | `string`   | The `id` of the layer this slot controls. Must match a layer in `layers[]`.      |
| `role`          | `SlotRole` | What kind of content the user provides.                                          |

### SlotRole values

| Value       | Description                              | UI colour        |
| ----------- | ---------------------------------------- | ---------------- |
| `userImage` | User's photo or personal image           | Purple `#7b61ff` |
| `userText`  | User-editable text (name, caption, etc.) | Orange `#ff9f43` |
| `brandLogo` | Brand or organisation logo               | Green `#00DB65`  |

<Tip>
  A single frame can have multiple slots. Each slot targets exactly one layer. One layer can only have one slot role at a time.
</Tip>

***

## TypeScript types

The canonical types are defined in `GoalGen Creator/code.ts`:

```typescript theme={null}
type SlotRole = 'userImage' | 'userText' | 'brandLogo';

interface TemplateSlot {
  slotId: string;
  targetLayerId: string;
  role: SlotRole;
}

interface LayerEntry {
  id: string;
  name: string;
  kind: 'image' | 'path' | 'rect' | 'text';
  x: number;
  y: number;
  width: number;
  height: number;
  rotation: number;
  visible: boolean;
  opacity: number;
  src?: string;
  pathData?: string;
  editableStyle?: Record<string, unknown>;
}

interface StudioTemplateManifest {
  _schema: 'StudioTemplateManifestV1';
  _pluginVersion: string;
  name: string;
  frameWidth: number;
  frameHeight: number;
  layers: LayerEntry[];
  slots?: TemplateSlot[];
}
```

<Warning>
  The schema is versioned. If you need to make breaking changes, increment `_schema` to `StudioTemplateManifestV2` and handle migration in Creator Studio's import pipeline.
</Warning>
