Skip to main content

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.
Example manifest.json
{
  "_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

FieldTypeRequiredDescription
_schema"StudioTemplateManifestV1"Schema identifier. Always this exact string.
_pluginVersionstringPlugin version that produced this file (e.g. "1.1.0").
namestringDisplay name of the template, taken from the Figma frame name.
frameWidthnumberFrame width in pixels (Figma document units).
frameHeightnumberFrame height in pixels.
layersLayer[]Ordered array of all exported layers (back-to-front).
slotsSlot[]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

FieldTypeDescription
idstringFigma node ID (e.g. "2:45"). Unique within the manifest.
namestringOriginal Figma layer name.
kind"rect" | "path" | "image" | "text"Layer classification (see below).
xnumberHorizontal offset from the frame origin, in pixels.
ynumberVertical offset from the frame origin, in pixels.
widthnumberBounding box width, in pixels.
heightnumberBounding box height, in pixels.
rotationnumberClockwise rotation in degrees.
visiblebooleanWhether the layer was visible at export time.
opacitynumberLayer opacity, 01.

kind: "rect" — Rectangle

A simple solid rectangle. No asset file. Style is encoded directly in the manifest.
{
  "kind": "rect",
  "editableStyle": {
    "fill": "#ff6b6b",
    "cornerRadius": 12
  }
}
editableStyle fieldTypeDescription
fillstringCSS hex colour (e.g. "#ff6b6b").
cornerRadiusnumberBorder radius in pixels.

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

A vector shape exported as path data. No asset file.
{
  "kind": "path",
  "pathData": "M 0 0 L 100 0 L 50 100 Z",
  "editableStyle": {
    "fill": "#ffffff"
  }
}
FieldTypeDescription
pathDatastringSVG path d attribute value.
editableStyle.fillstringFill colour.

kind: "image" — Raster or vector asset

A layer exported as a PNG or SVG file.
{
  "kind": "image",
  "src": "hero-illustration.svg"
}
FieldTypeDescription
srcstringFilename of the asset (relative to the ZIP root). After Studio import this is replaced with an absolute CDN URL.
At import time, Creator Studio replaces all relative src values with the permanent CDN URLs of the uploaded assets.

kind: "text" — Text layer

A text layer. The text content is preserved but font rendering is left to the canvas engine.
{
  "kind": "text",
  "editableStyle": {
    "content": "Happy Birthday!",
    "fontFamily": "Inter",
    "fontSize": 72,
    "fontWeight": 700,
    "color": "#ffffff",
    "textAlign": "center"
  }
}
editableStyle fieldTypeDescription
contentstringThe raw text content.
fontFamilystringFont family name as registered in Figma.
fontSizenumberFont size in pixels.
fontWeightnumberCSS font weight (100–900).
colorstringCSS 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.
{
  "slotId": "slot-0",
  "targetLayerId": "2:46",
  "role": "userImage"
}
FieldTypeDescription
slotIdstringUnique identifier within the manifest (auto-generated as slot-0, slot-1, …).
targetLayerIdstringThe id of the layer this slot controls. Must match a layer in layers[].
roleSlotRoleWhat kind of content the user provides.

SlotRole values

ValueDescriptionUI colour
userImageUser’s photo or personal imagePurple #7b61ff
userTextUser-editable text (name, caption, etc.)Orange #ff9f43
brandLogoBrand or organisation logoGreen #00DB65
A single frame can have multiple slots. Each slot targets exactly one layer. One layer can only have one slot role at a time.

TypeScript types

The canonical types are defined in GoalGen Creator/code.ts:
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[];
}
The schema is versioned. If you need to make breaking changes, increment _schema to StudioTemplateManifestV2 and handle migration in Creator Studio’s import pipeline.