# Screens Browser API

## Quick start

```js
await window.screens.ready();

await window.screens.replaceAll([
  {
    id: "hero",
    presetId: "centered",
    title: "Plan together",
    subtitle: "Invites, RSVPs, and updates in one place.",
    image: "data:image/png;base64,...",
    backgroundColor: "#F3F0FF",
    accentColor: "#6C5CE7",
    textColor: "#261B44",
  },
]);

await window.screens.render();
await window.screens.exportZip({ filename: "app-store-screens.zip" });
```

The API is registered before React mounts. `ready()` waits for the editor, fonts, images, DOM, and
two animation frames. All mutation methods return only after the resulting canvas is stable.

## Methods

```ts
window.screens.version; // "1.0.0"

ready(): Promise<ScreensCapabilities>
getCapabilities(): ScreensCapabilities
getState(): AutomationEditorState

replaceAll(
  drafts: ScreenDraft[],
  options?: { selectedId?: string },
): Promise<AutomationEditorState>

add(draft?: ScreenDraft): Promise<Screen>
update(screenId: string, patch: ScreenPatch): Promise<Screen>
remove(screenId: string): Promise<AutomationEditorState>
select(screenId: string): Promise<void>

applyPreset(
  screenId: string,
  presetId: string,
  overrides?: ScreenPatch,
): Promise<Screen>

applyTemplate(templateId: string): Promise<AutomationEditorState>
render(): Promise<void>

exportPng(
  screenId: string,
  options?: { filename?: string; download?: boolean },
): Promise<Blob>

exportZip(
  options?: { filename?: string; download?: boolean },
): Promise<Blob>
```

Exports download by default and also return a `Blob`. Pass `download: false` when another page
script will consume the blob.

`getCapabilities()` returns the current presets, templates, enum values, numeric limits, supported
image-source formats, API methods, and version. Prefer it over hard-coding choices.

`getState()` returns a structured clone:

```ts
interface AutomationEditorState {
  screens: Screen[];
  selectedScreenId: string | null;
  activeTemplateId: string | null;
}
```

## Screen input

A `ScreenDraft` is a partial `Screen`; `id` is optional and generated with
`crypto.randomUUID()`. Defaults come from a new screen. When `presetId` is supplied, preset
defaults are applied before draft overrides. `ScreenPatch` accepts the same editable fields except
`id` and `presetId`; use `applyPreset` to change a preset.

Fields:

- Identity: `id`, `presetId`
- Copy: `eyebrow`, `title`, `subtitle`, `footer`
- Eyebrow: `eyebrowFontSize`, `eyebrowTextColor`, `eyebrowBackgroundColor`,
  `eyebrowBorderEnabled`, `eyebrowBorderRadius`, `eyebrowUppercase`
- Assets: `image`, `overlayImage`, `backgroundImage`
- Palette: `backgroundColor`, `accentColor`, `accentStyle`, `textColor`
- Layout: `layout`, `textAlign`, `padding`, `shadowIntensity`
- Main image: `imageStyle`, `frameColor`, `imageScale`, `imageOffsetX`, `imageOffsetY`,
  `imageBorderRadius`, `imageRotation`, `imageTiltX`, `imageTiltY`, `imageCropLeft`,
  `imageCropRight`, `imageCropBottom`
- Overlay: `overlayScale`, `overlayOffsetX`, `overlayOffsetY`, `overlayRotation`,
  `overlayTiltX`, `overlayTiltY`, `overlayBorderRadius`
- Typography: `titleFontSize`, `subtitleFontSize`

Colors must be hexadecimal CSS colors. Optional eyebrow colors accept `null`. Assets accept `null`
or `data:image/*`, `blob:`, HTTP(S), or relative URLs. Use `getCapabilities().numericRanges` for
the current inclusive slider limits.

Enum values:

```js
{
  layout: ["poster", "hero", "cover", "centered", "quote", "press"],
  textAlign: ["left", "center"],
  imageStyle: ["device", "plain"],
  frameColor: ["desert", "natural", "blue", "black"],
  accentStyle: ["none", "glow", "confetti", "rings", "grid", "rays"]
}
```

## Errors

Rejected calls throw `ScreensApiError`:

```ts
{
  name: "ScreensApiError";
  code: string;
  message: string;
  details?: {
    field?: string;
    screenId?: string;
    value?: unknown;
    expected?: unknown;
  };
}
```

Stable codes include `NOT_READY`, `INVALID_ARGUMENT`, `UNKNOWN_FIELD`, `VALIDATION_ERROR`,
`DUPLICATE_ID`, `SCREEN_NOT_FOUND`, `LAST_SCREEN`, `PRESET_NOT_FOUND`, `TEMPLATE_NOT_FOUND`,
`RENDER_TIMEOUT`, `ASSET_LOAD_FAILED`, and `EXPORT_FAILED`.

Calls validate atomically. A rejected call does not create an undo step or partially change state.
