Skip to content
ForgeCastDocs

Overlay document format

The JSON an overlay or widget is made of, shared by the predefined overlays, the Editor and the API.

An overlay is a JSON document. The predefined overlays, the Editor and the API all use the same format. This is version 1 ("schema": 1).

{
  "schema": 1,
  "kind": "overlay",
  "canvas": { "width": 1920, "height": 1080 },
  "background": { "kind": "image", "source": { "kind": "builtin", "id": "bg-starting" }, "fit": "cover" },
  "timeline": { "durationMs": 6000, "loop": true },
  "vars": [ /* settings the streamer can change */ ],
  "layers": [ /* bottom to top */ ]
}

Top-level fields

Name

Type

Limits and safety rules

Documents are rendered inside OBS on a streamer's own computer, so the server checks them strictly. Anything that doesn't match is rejected with 400 validation_error and a path to the problem. Unknown properties are rejected at every level, colours are #RRGGBB or #RRGGBBAA, and image URLs must be public https.

Image sources

Wherever a document shows a picture, the source is one of:

  • { "kind": "url", ... }: a public https address (see the rules above);
  • { "kind": "builtin", "id": "bg-starting" }: art bundled with ForgeCast;
  • { "kind": "var", "key": "logo" }: a picture setting of the same document;
  • { "kind": "asset", "id": "<uuid>" }: an uploaded file (in future).

Common layer fields

Every layer has these. The props depend on its type.

Name

Type

Fills

A fill is one of:

  • { "kind": "solid", "color": "#RRGGBB" }
  • { "kind": "gradient", "angle": 0-360, "stops": [{ "at": 0-1, "color": "#RRGGBB" }, ...] }: a linear gradient, 2–8 stops
  • { "kind": "radial", "stops": [...] }: a circular gradient from the centre, 2–8 stops

Colours may include an alpha channel (#RRGGBBAA), so a stop can fade to transparent.

Layer types

Open a type to see its props.

Effects

fx applies to the whole layer. Every field is optional.

Name

Type

Settings and variables

vars lists the settings a document offers. The streamer changes them in the ForgeCast app and the document shows them; the values never go into the document.

"vars": [
  { "key": "goal", "label": "Goal", "type": "number", "default": 1000, "min": 1, "max": 1000000, "hint": "How many subscribers you are aiming for" },
  { "key": "title", "label": "Title", "type": "text", "default": "Sub goal", "maxLength": 24 },
  { "key": "accent", "label": "Bar colour", "type": "color", "default": "#3C9CFC" },
  { "key": "logo", "label": "Logo", "type": "image" }
]

Name

Type

At most 24 settings. A value that doesn't fit its setting (out of range, too long, not a colour) is put right or ignored; it's never trusted.

Using them in text. In any text that allows variables, {{goal}} shows the setting's value, next to the live ones ({{subscribers}}, {{viewers}}, {{likes}}, {{members}}, {{channel.name}}, {{latest.member.name}} …). Add |compact for a short number (12.5K) or |raw for one without separators.

Using a picture setting. Name it as an image source: { "kind": "var", "key": "logo" } (in an Image layer, a background, or a particle emitter's images). It must name an image setting of the same document.

Binding a property to a setting. A layer's bindings map a property path to a variable, for things a text can't reach:

{ "type": "goal", "id": "bar", "bindings": { "target": "{{goal}}", "barFill.color": "{{accent}}" }, "props": { "...": "..." } }

Only some properties can be bound (anything else is ignored), and a binding that would make the layer invalid is ignored too.

Animations

animations is a list of blocks on the overlay's timeline. Each block animates one or more properties between keyframes over a window of time:

{
  "id": "anim-1",
  "name": "Slide in from left",
  "startMs": 0,
  "durationMs": 800,
  "easing": "cubic-out",
  "iterations": 1,
  "yoyo": false,
  "fill": "backwards",
  "tracks": {
    "x": [ { "t": 0, "v": -200 }, { "t": 1, "v": 0 } ],
    "opacity": [ { "t": 0, "v": 0 }, { "t": 0.6, "v": 1 } ]
  }
}

Name

Type

Animated properties are always changes from the layer's own pose, so moving or resizing a layer never breaks its animation:

PropertyRangeCombines byMeaning
x, y±20000addingOffset in pixels
rotate±3600addingExtra rotation, degrees
skewX, skewY±80addingDegrees
blur0–200addingExtra blur, pixels
scale, scaleX, scaleY0–20multiplying1 = unchanged
opacity0–1multiplying1 = unchanged
brightness0–5multiplying1 = unchanged
reveal0–1multiplyingHow much is shown. Text types out character by character; other layers wipe in from the left.

When several blocks animate the same property at once they combine (offsets add up, multipliers multiply). The result is always clamped to the allowed range.

On this page