View raw

Common element fields#

Every element type — text, shape, image, video, audio, composition, caption, particles — shares the fields on this page. Variant-specific fields live on each element's own reference page.

interface BaseElement {
  id?: string;
  name?: string;
  type: ElementType;
  track?: number;
  time?: number | string;
  duration?: number | string | 'auto' | 'end';

  // Transform
  x?: number | string | Keyframe[];
  y?: number | string | Keyframe[];
  x_anchor?: number | string;
  y_anchor?: number | string;
  width?: number | string | Keyframe[];
  height?: number | string | Keyframe[];
  rotation?: number | Keyframe[];
  scale?: number | Keyframe[];

  // Visual
  opacity?: number | Keyframe[];
  blend_mode?: 'normal' | 'multiply' | 'screen' | 'add' | 'overlay' | 'hard-light' | 'soft-light';

  // Animation
  animations?: Animation[];
  keyframe_animations?: KeyframeAnimation[];
}

Identity#

FieldTypeDefaultDescription
idstringautoStable identifier. Used by modify_element / remove_element in the MCP server and by keyframe_animations.property references. If omitted, the runtime assigns one.
namestringOptional human-readable label. Has no rendering effect.
typeElementTyperequiredOne of 'video', 'image', 'text', 'shape', 'audio', 'composition', 'caption', 'particles'. Discriminates which variant fields apply.

Timing#

FieldTypeDefaultDescription
tracknumber1Base draw order. Higher renders on top; track 1 is the bottom. It is the default and the tiebreak — the depth axis z (see Transform) takes precedence and orders elements; track decides only when depths are equal. Elements sharing a track keep document order.
timenumber | string0When the element appears, in seconds (or "50%" of the Source duration).
durationnumber | string | 'auto' | 'end''auto'How long the element stays. 'auto' uses the natural duration of media; 'end' extends to the Source's end.

Transform#

Positions use the top-left convention by default (the CSS / SVG / Canvas model): (x, y) is where the element's anchor lands on the canvas, and the anchor defaults to the element's top-left corner unless x_anchor / y_anchor say otherwise. So x: 0, y: 0 is the top-left corner and a full-frame layer is just x: 0, y: 0, width: W, height: H. Set x_anchor: '50%', y_anchor: '50%' to position by center. Rotation and scale always pivot the element's center, independent of the anchor.

FieldTypeDefaultDescription
xnumber | string | Keyframe[]0Horizontal position of the anchor. Number = pixels; string = '50%', '100vw', etc.
ynumber | string | Keyframe[]0Vertical position of the anchor.
znumber | Keyframe[]0Depth toward (+) / away from (−) the viewer — the layering axis: higher z draws on top, with track as the tiebreak when depths are equal. Under a camera it also foreshortens. (See PROTOCOL §4.2 / §4.4 for the full 3D set: x_rotation, y_rotation, z_rotation.)
x_anchornumber | string'0%'Anchor offset within the element's box. '0%' = left edge (default), '50%' = center, '100%' = right edge.
y_anchornumber | string'0%'Anchor offset within the element's box. '0%' = top (default), '50%' = center, '100%' = bottom.
widthnumber | string | Keyframe[]content-derivedWidth of the element's box in pixels.
heightnumber | string | Keyframe[]content-derivedHeight of the element's box.
rotationnumber | Keyframe[]0Rotation around the element's center, in degrees.
scalenumber | Keyframe[]1Uniform scale around the element's center. Multiplies width and height.

Visual#

FieldTypeDefaultDescription
opacitynumber | Keyframe[]100Element opacity, 0–100. Multiplied with parent composition opacity.
blend_modestring'normal'How the element composites with what's beneath it: normal, multiply, screen, add, overlay, hard-light, soft-light. Element-local — never affects other elements. See PROTOCOL.md §4.5.

Animation#

animations#

Named animation presets. Declarative — each one is a tag the runtime expands into a keyframe sequence. AI agents and humans both pick from this list; you don't write the curves yourself.

interface Animation {
  type: AnimationType;
  duration?: number;
  easing?: EasingFunction;
  time?: 'start' | 'end' | number;
  fade?: boolean;
  scope?: 'element' | 'track';
  split?: boolean;
}
FieldTypeDefaultDescription
typeAnimationTyperequiredThe preset name. See list below.
durationnumber0.8How long the animation runs, in seconds.
easingEasingFunctionpreset-defaultOptional override. See easings.
time'start' | 'end' | number'start'When the animation fires. 'start' = element appears; 'end' = element disappears; a number is the absolute time within the element's duration.
fadebooleanpreset-defaultWhether the animation should also fade. Used by some presets like slide-*-in.
scope'element' | 'track''element'Whether the animation applies to this element only or the whole track it sits on.
splitbooleanfalse(text/caption only) Animate per-character instead of the whole element.

Preset names#

fade-in, fade-out, slide-left-in, slide-right-in, slide-up-in, slide-down-in, slide-left-out, slide-right-out, slide-up-out, slide-down-out, scale-in, scale-out, rotate-in, rotate-out, bounce-in, bounce-out.

Example#

"animations": [
  { "type": "fade-in", "duration": 0.6 },
  { "type": "slide-up-in", "duration": 0.6, "easing": "ease-out-cubic" },
  { "type": "fade-out", "duration": 0.4, "time": "end" }
]

keyframe_animations#

Raw keyframe animation on any property. Use this when no preset fits — explicit position curves, color shifts, scale ramps tied to specific times.

interface KeyframeAnimation {
  property: string;
  keyframes: Keyframe[];
  easing?: EasingFunction;
}

interface Keyframe {
  time: number | string;
  value: number | string | [number, number];
  easing?: EasingFunction;
}
FieldTypeDescription
propertystringPath to the property: 'x', 'y', 'opacity', 'rotation', 'mask.progress', 'paths.0.stroke_progress'.
keyframesKeyframe[]At least two entries. Times must be ascending.
easingEasingFunctionDefault easing between keyframes that don't specify their own.

Example#

"keyframe_animations": [
  {
    "property": "y",
    "keyframes": [
      { "time": 0,   "value": 200, "easing": "ease-out-cubic" },
      { "time": 1.5, "value": 540 }
    ]
  }
]

Expressions#

Any numeric field above (x, y, width, height, rotation, scale, opacity, blur/filter params, effect params) also accepts an expression object — a formula evaluated per frame, instead of a static value or a keyframe table:

{ "y": { "expr": "540 + sin(t * PI) * 30" } }

The formula is a pure function of the element's own clock: t (element-local seconds), dur, i (index in a generated set), n (siblings), value (the field's base default), the constants PI/TAU/E, and a fixed math function set (sin, cos, clamp, lerp, smoothstep, linear, ease, noise, wiggle, random, …). It cannot reference other elements or read runtime input, so it is deterministic and can be baked to keyframes. Full grammar: PROTOCOL.md §3.6.

Easing functions#

linear, ease, ease-in, ease-out, ease-in-out, ease-in-cubic, ease-out-cubic, ease-in-out-cubic, ease-in-quad, ease-out-quad, ease-in-out-quad, ease-in-quart, ease-out-quart, ease-in-out-quart, ease-in-quint, ease-out-quint, ease-in-out-quint, ease-in-sine, ease-out-sine, ease-in-out-sine, ease-in-expo, ease-out-expo, ease-in-out-expo, ease-in-circ, ease-out-circ, ease-in-out-circ, ease-in-back, ease-out-back, ease-in-out-back, spring (damped harmonic with mass=1, damping=10, stiffness=100 — overshoots ~5% then settles).