# Generation API

Generate template SVGs, background SVGs, element briefs and apply-ready Design Lab documents with POST /api/generate and its versioned JSON contract.

`POST /api/generate` accepts a JSON body with `Content-Type: application/json`. The `kind` field selects one of four generators: `template` (the default), `background`, `element-brief` and `design-sequence`. `GET /api/generate` returns the current contract (`schemaVersion` 3) with the request schema, value ranges and examples. Read it before building a request. A top-level field that the contract does not define is rejected with `unknown_field`.

## Output [#output]

* `template` and `background` return a JSON envelope by default (`output: "json"`). The SVG is in `artifact.content`.
* `output: "raw"` returns the SVG itself as `image/svg+xml`.
* `element-brief` and `design-sequence` always return JSON.

Successful responses send `Cache-Control: no-store` and a `Content-Disposition` header with the file name.

## Design sequence [#design-sequence]

A `design-sequence` request builds a document for Design Lab, the Studio's layered composition tool. The document holds a shader sequence: a series of cuts through other materials that ends on the chosen material and holds it. The composition can also include the identity's brand mark, text layers and one converter effect.

```json
{
  "kind": "design-sequence",
  "identity": { "preset": "gt" },
  "ratio": "wide",
  "backgroundColor": "#111216",
  "shader": {
    "materialId": "paper-gem-smoke",
    "shaderSize": 1
  },
  "sequence": {
    "cutCount": 10,
    "finalHoldMs": 5000,
    "pace": "accelerating"
  },
  "effect": {
    "kind": "bayer",
    "opacity": 0.76,
    "foreground": "#F5F5F2",
    "background": "#111216"
  },
  "texts": [{ "value": "Open Source", "weight": 500 }],
  "export": { "width": 1920, "fps": 30, "quality": "best" }
}
```

| Field                                | Values                                                                                                                                  |
| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `shader.materialId`                  | Any ID listed by `/api/materials` (default `paper-gem-smoke`). Retired material IDs are rejected                                        |
| `shader.shaderSize`                  | Material zoom from 0.1 to 10 (default 1)                                                                                                |
| `shader.opacity`, `shader.blendMode` | 0–1; `normal`, `multiply`, `overlay` or `screen`                                                                                        |
| `shader.settings`                    | Shared material controls from `/api/materials`, and `effectProps` for Shaders.com materials                                             |
| `sequence.cutCount`                  | 8–12 cuts (default 10)                                                                                                                  |
| `sequence.finalHoldMs`               | 3000–6000 ms (default 5000)                                                                                                             |
| `sequence.pace`                      | `accelerating` (default) or `even`                                                                                                      |
| `effect.kind`                        | `bayer` (default), `ascii`, `halftone` or `posterize`, with `opacity`, `foreground`, `background` and converter settings                |
| `texts`                              | Up to 32 text layers, each with a `value` of up to 1000 characters                                                                      |
| `includeBrandMark`                   | `true` by default. An identity without a mark gets a monogram                                                                           |
| `ratio`                              | `wide` (default), `square` or `opengraph`                                                                                               |
| `backgroundColor`                    | Six-digit HEX (default `#111216`)                                                                                                       |
| `export`                             | `width` 320–3840, `fps` 12, 15, 24 or 30, `quality` `fast`, `balanced` or `best`, `durationMs` 1200–4000, `gifLoop` `raw` or `seamless` |

Image effects are not part of this request. Add them in the browser with `design.effects.add` after the document is applied.

The response is JSON with these fields:

* `schemaVersion: 1`: the version of the response envelope.
* `document`: an apply-ready Design Lab compatibility source with `version: 3`.
* `sequence.timeline` and `sequence.durationMs`: the resolved material IDs and cut boundaries.
* `automation`: the browser global and the exact apply and export commands.

`document.version` is not the active canvas schema. `applySource(response.document)` validates and migrates the compatibility source. The Design Lab adapter then exposes the normalized result as CanvasDocument schema 2 with Design Lab metadata source version 4. Read the source again after applying it and before making targeted CanvasDocument edits. When the document is applied, Design Lab keeps `export.durationMs` only if it is 1200, 1600, 2400 or 4000 and uses 1600 otherwise.

Apply and render inside `/studio?tool=material`:

```js
await window.glyphfield.studio.applySource(response.document);
const artifact = await window.glyphfield.studio.invoke(
  'design.export',
  { format: 'mp4', mode: 'shader-sequence', download: true }
);
```

Choose `png`, `jpg`, `gif` or `mp4`. `mode: 'shader-sequence'` works with GIF and MP4 only. The export action resolves to the same artifact object that the UI produces, rendered with the live shader canvases, composition effects, text, marks, layer order and output settings. `download: true` also saves the file.

## Templates [#templates]

The `template` kind renders the Studio's brand templates as standalone SVG: OpenGraph images, terminal cards, slides, blog covers and partnership lockups. It uses the same layouts and renderer as the Studio and embeds the brand's font files and images, so the SVG renders in the brand typeface inside a plain `<img>` element. A font whose data URL is longer than 560,000 characters is not embedded. Each request renders one page.

When a request leaves out copy, the identity fills it in. Proof figures fill metrics slides, strategy pillars fill agenda slides, and the identity's own proof partner fills lockups. A lockup without a partner shows the placeholder text “Partner”.

```json
{
  "kind": "template",
  "template": "slides",
  "slideLayout": "agenda",
  "texture": "white",
  "title": "One system, every market.",
  "body": "Foundation\nExpression\nApplication\nDelivery",
  "identity": { "preset": "gt" },
  "output": "raw"
}
```

| Field                                          | Values                                                                                                                                                                                                                                                                                                                                     |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `template`                                     | `slides` (default), `blog`, `partnership`, `opengraph` or `terminal`                                                                                                                                                                                                                                                                       |
| `slideLayout`                                  | Slides only: `title`, `section`, `agenda`, `split`, `metrics`, `quote`, `timeline`, `statement`, `comparison`, `process`, `chart`, `team`, `image` or `closing`                                                                                                                                                                            |
| `layout`                                       | `opengraph`: `split`, `statement`, `media`, `centered`, `editorial`. `blog`: `editorial`, `feature`, `statement`, `centered`, `ledger`. `terminal`: `card`, `split`, `focus`, `caption`. `partnership`: `lockup`, `centered`, `hero`, `announcement`. Slides also accept `layout`, and sending both `layout` and `slideLayout` is an error |
| `format`                                       | `opengraph`, `wide`, `square`, `portrait`, `story`, `linkedin` or `lockup`. Slides use `16x9`, `4x3` or `square`                                                                                                                                                                                                                           |
| `texture`                                      | `white`, `dark`, `grid` or `noise`                                                                                                                                                                                                                                                                                                         |
| `language`                                     | Terminal only: `typescript`, `tsx`, `javascript`, `python`, `bash`, `json`, `html` or `css`                                                                                                                                                                                                                                                |
| `title`                                        | 1–240 characters                                                                                                                                                                                                                                                                                                                           |
| `body`                                         | 1–1000 characters, or 4000 for `terminal`. Slides read one list item per line, terminal cards read it as code, and other layouts use it as supporting copy where they have a slot for it                                                                                                                                                   |
| `background`, `foreground`                     | Six-digit HEX colors for the page surface and for every text layer                                                                                                                                                                                                                                                                         |
| `backgroundImageDataUrl`, `partnerLogoDataUrl` | Base64 image data URLs of up to 5,000,000 characters                                                                                                                                                                                                                                                                                       |
| `partnerId`                                    | For `partnership`: a proof asset ID of the identity, another built-in identity ID, or `template-northstar`                                                                                                                                                                                                                                 |
| `output`                                       | `json` (default) or `raw`                                                                                                                                                                                                                                                                                                                  |

The default size is 1600 × 900 for slides, 1200 × 630 for OpenGraph, terminal and blog, and 1200 × 600 for partnership. `format` changes it. The file name is `<identity slug>-<template>-<width>x<height>.svg`.

`identity` accepts `{ preset }` with optional overrides, `{ id }` with an ID from `/api/identities`, or a complete identity object from `/api/identities` (custom identities included). The default preset is `starter`. An unknown `id` returns `unknown_identity`, and an invalid complete identity returns `invalid_identity`. A field next to `preset` that is not an override is rejected with `unknown_field`. See [Identities and custom assets](/docs/agents/identity-assets).

## Background [#background]

The `background` kind generates gradient, grain-gradient, dither, pattern and tactile surface SVGs. For a built-in identity, the colors default to its palette. [Tactile backgrounds](/docs/studio/logo-background) lists every setting, including the `surface*` fields and the CC0 surface references.

```json
{
  "kind": "background",
  "identity": { "preset": "gt" },
  "settings": {
    "width": 1200,
    "height": 630,
    "style": "grain-gradient",
    "gradient": "mesh",
    "angle": 32,
    "colorA": "#FFFFFF",
    "colorB": "#181818",
    "colorC": "#737373",
    "focalX": 42,
    "focalY": 38,
    "relief": 24,
    "grain": 18,
    "pattern": "dots",
    "patternOpacity": 14,
    "spacing": 24,
    "logoTone": "black",
    "logoScale": 24,
    "logoOpacity": 100,
    "logoX": 0,
    "logoY": 0
  },
  "output": "raw"
}
```

`settings.width` and `settings.height` must each be an integer from 64 to 4096 (`invalid_dimensions`). Width × height may not exceed 12,000,000 pixels (`pixel_limit`). Unknown keys inside `settings` are ignored, so check their spelling against the contract.

## Element brief [#element-brief]

The `element-brief` kind resolves one record from `/api/elements` against an identity. `elementId` is required.

```json
{
  "kind": "element-brief",
  "elementId": "email-signature",
  "identity": {
    "preset": "custom",
    "name": "Acme",
    "website": "acme.test",
    "tagline": "Tools for careful teams."
  }
}
```

The response is `{ element, generation: { previewFamily, source: '/api/elements' }, identity, schemaVersion: 1 }`. `element` is the catalog record with its ID, name, category, description, dimensions, format, symbol, keywords and preview family. `identity` holds the resolved colors, description, ID, name, positioning, short name, tagline, typography, voice and website. The HTTP brief has no editor settings and does not render an image. The Brand elements menu item **Download element brief** adds the element's current settings.

## JSON artifact envelope [#json-artifact-envelope]

```json
{
  "schemaVersion": 1,
  "artifact": {
    "content": "<svg ...>...</svg>",
    "filename": "general-translation-slides-1600x900.svg",
    "mimeType": "image/svg+xml",
    "width": 1600,
    "height": 900
  }
}
```

Check `schemaVersion`, `mimeType` and the dimensions before storing the content.

## Studio source and generation requests [#studio-source-and-generation-requests]

The Studio source drawer (**File** → **Edit source code**) shows the complete JSON state of the active browser tool. Design Lab source is CanvasDocument schema 2 with Design Lab metadata source version 4. Each tool's source has its own shape, and none of them is a valid `POST /api/generate` body.

`design-sequence` is the one bridge between the two. It returns a compact document that the browser converts to current Studio source. For other tools, read and apply source or operate the controls through `window.glyphfield.studio`.

## Errors [#errors]

Errors return `{ error: { code, field, message }, schemaVersion: 1 }`. The codes are `invalid_json`, `unknown_field`, `invalid_request`, `unknown_identity`, `invalid_identity`, `invalid_dimensions` and `pixel_limit` (400), `request_too_large` (413, a body over 5,250,000 bytes), `unsupported_media_type` (415) and `generation_failed` (500). See [API errors and limits](/docs/agents/errors).
