---
title: "Submit a render job"
method: POST
path: "/v1/renders"
tags: ["renders"]
---

# Submit a render job

`POST /v1/renders`

## Request

- Base URL: `https://api.framelane.io`
- URL: `https://api.framelane.io/v1/renders`
- Auth: HTTP bearer

Enqueue a new render job on the GPU engine. The job moves through queued → processing → completed / failed asynchronously. Attach a webhook URL or register workspace-level webhooks to receive status updates. The response carries an ADVISORY `ok` + `violations[]` lint of the composition: the render is dispatched either way, and anything that actually blocks a submit is a 422 instead.

## Headers

- `Idempotency-Key` string, nullable

## Request body

- RenderRequest: Body for ``POST /v1/renders``. Defines the composition to render: dimensions, output format, timeline elements, and optional transitions. The render engine produces a single video artifact.
  - `version` 'v4' | 'v5', nullable: Wire version of this request. Omit it: the render task is v5 exactly when the request carries a v5 block, and v4 otherwise. `v5` accepts the v5 blocks (a shape's `geometry`, `frame` and `instance` elements, `operations`, `components`); `v4` refuses them.
  - `schema_version` 'v5', nullable: The document format an editor wrote this request in. Not sent to the renderer; `version` is the wire's.
  - `width` integer, nullable: Output width in pixels. Must be set together with `height` or both omitted.
  - `height` integer, nullable: Output height in pixels. Must be set together with `width` or both omitted.
  - `duration` number, nullable: Total composition duration in seconds. Inferred from elements when omitted.
  - `frame_rate` integer, nullable: Frames per second. When set, the output encodes at exactly this rate. Defaults to 30 when omitted.
  - `output_format` 'mp4' | 'webm' | 'mov' | 'gif' | 'png' | 'jpg': Values: - `mp4` — H.264 MP4 video — the default, widely compatible delivery format. - `webm` — VP9 WebM video — supports a transparent (alpha) background. - `mov` — QuickTime MOV — ProRes 4444 with a transparent (alpha) background; large files. - `gif` — Animated GIF — roadmap; not yet emitted by the renderer. - `png` — Single-frame PNG still — roadmap; not yet emitted by the renderer. - `jpg` — Single-frame JPEG still — roadmap; not yet emitted by the renderer.
  - `output_filename` string, nullable: Custom filename for the artifact (without extension). Auto-generated when omitted.
  - `background_color` string: RGBA background color in hex format (#RRGGBBAA).
  - `background_image_url` string, uri, nullable: URL of an image to use as the composition background.
  - `alpha` boolean: When true, produce an alpha-channel (transparent background) output. Requires `output_format=webm` or `output_format=mov`.
  - `elements` union[]: Ordered list of timeline elements (video, image, text, audio, etc.).
    - union
      - VideoElement
        - `lut_url` string, uri, nullable
        - `lut_intensity` number
        - `brightness` number: Brightness, -100..100, applied as a 0..2 colour multiplier (0 = no change). `-100` multiplies by 0: the element renders pure black while keeping its alpha — a silhouette of the artwork. Combine a `brightness: -100` copy of an image with `blur`, reduced `opacity` and a small offset, stacked beneath the real one, to fake the content-shaped drop shadow `shadow_x`/`shadow_y` cannot produce.
        - `contrast` number
        - `saturation` number
        - `exposure` number
        - `sharpness` number
        - `blur` number
        - `noise` number
        - `vignette` number
        - `hue_rotate` number
        - `temperature` number: White balance warm (+) / cool (−), −1..1; 0 = no-op. Applied as a channel matrix, after the classic brightness/contrast chain.
        - `tint` number: White balance magenta (+) / green (−), −1..1; 0 = no-op.
        - `vibrance` number: Saturation boost weighted toward muted colours, −1..1; 0 = no-op. Boosts flat colour without wrecking skin tones.
        - `highlights` number: Luma-masked tone lift of the brightest range, −1..1; 0 = no-op.
        - `shadows` number: Luma-masked tone lift of the darkest range, −1..1; 0 = no-op.
        - `crop_top` number
        - `crop_bottom` number
        - `crop_left` number
        - `crop_right` number
        - `border_radius` union: Corner radius in pixels — a single value, or per-corner `{top_left, top_right, bottom_right, bottom_left}` for asymmetric corners (e.g. a card rounded only on top). The renderer normalizes px to a 0–1 fraction of the element's shorter side (≈ half the shorter side is fully rounded) and clamps to that range. For shape elements use `corner_radius` (already 0–1).
          - integer
          - number
          - string
          - CornerRadiiPx: Per-corner radii in pixels (for `border_radius` on video/image/text elements).
            - `top_left` union
              - …
            - `top_right` union
              - …
            - `bottom_right` union
              - …
            - `bottom_left` union
              - …
        - `border_color` string, nullable
        - `border_width` union: Border thickness in pixels (converted to the renderer's relative border scale against the element's shorter side, so it survives resizes). The border outlines the element's border_radius-rounded quad — not the image's alpha silhouette.
          - integer
          - number
          - string
        - `shadow_color` string, nullable
        - `shadow_blur` union: Shadow softness, 0–100 (renderer blur-strength scale, not pixels): 0 = hard edge, 100 = maximum blur. Values are clamped to that range.
          - integer
          - number
          - string
        - `shadow_x` union: Horizontal shadow offset in pixels (converted to the renderer's relative offset scale). The shadow silhouette is the element's border_radius-rounded quad, not the content alpha — a cut-out PNG gets a card shadow, not an outline-shaped one. On a cut-out that reads as a floating rectangle (rotated with the element, which is the tell). For a shadow that follows the artwork, drop these fields and stack a second copy of the same image underneath at `brightness: -100` (a black silhouette, alpha preserved) with `blur` and reduced `opacity`, offset a few percent — see `brightness`.
          - integer
          - number
          - string
        - `shadow_y` union: Vertical shadow offset in pixels. See `shadow_x`.
          - integer
          - number
          - string
        - `blend_mode` 'none' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color_dodge' | 'color_burn' | 'hard_light' | 'soft_light' | 'difference' | 'add' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity': Values: - `none` — Normal compositing (source-over) — the default. - `multiply` — Multiply blend — darkens by multiplying layer colors. - `screen` — Screen blend — lightens by inverting, multiplying, inverting. - `overlay` — Overlay blend — multiply in shadows, screen in highlights. - `darken` — Darken blend — keeps the darker of the two layers per channel. - `lighten` — Lighten blend — keeps the lighter of the two layers per channel. - `color_dodge` — Color-dodge blend — brightens the base toward the blend color. - `color_burn` — Color-burn blend — darkens the base toward the blend color. - `hard_light` — Hard-light blend — overlay with layers swapped. - `soft_light` — Soft-light blend — a gentler hard-light. - `difference` — Difference blend — absolute difference of the two layers per channel. - `add` — Additive (linear-dodge) blend — sums layer colors, clamped. - `exclusion` — Exclusion blend — like difference, lower contrast. - `hue` — Hue blend — backdrop luminosity + saturation with the blend layer's hue. - `saturation` — Saturation blend — backdrop hue + luminosity with the blend layer's saturation. - `color` — Color blend — backdrop luminosity with the blend layer's hue + saturation. - `luminosity` — Luminosity blend — backdrop hue + saturation with the blend layer's luminosity.
        - `mask_shape` 'circle' | 'diamond' | 'hexagon' | 'star' | 'heart' | 'triangle': Analytic (SDF) shape mask that clips an element's coverage. §1. Values: - `circle` — Circular (ellipse) analytic mask, fit to the element bounds. - `diamond` — Diamond (rotated square) analytic mask. - `hexagon` — Regular hexagon analytic mask. - `star` — Five-point star analytic mask. - `heart` — Heart analytic mask. - `triangle` — Upward triangle analytic mask.
        - `mask` MaskConfig: Animated/feathered mask params layered on the analytic `mask_shape` (§5c).
          - `feather` number: Soften the mask's SDF edge.
          - `scale` number: Mask scale (iris reveals).
          - `center` Point
            - `x` number
            - `y` number
        - `mask_keyframes` MaskKeyframe[], nullable
          - `time` number, required: Timeline seconds.
          - `feather` number, nullable
          - `scale` number, nullable
          - `center` Point
            - `x` number
            - `y` number
          - `easing` string, nullable: Easing curve name — any `easings` catalog value (`linear`, `hold`, `ease_in_out`, `quad_out`, `expo_in_out`, `square_in_out` = step, …). Unknown names are rejected: the engine would silently fall back to linear. For spring/back/elastic/bezier use the sub-objects instead.
          - `spring` SpringEasing: Damped-spring ease over the keyframe segment. Only the damping ratio zeta = damping / (2 * sqrt(stiffness * mass)) shapes the curve; the segment's duration sets its timing. Below 1 the spring overshoots and rings (the defaults give zeta = 0.5); at 1 or above it settles without overshoot. An underdamped spring runs until its envelope decays to 0.1% (settle x w0 = ln(1000) / zeta, w0 = sqrt(stiffness / mass)). Since render-node's overdamped settle fix (GVR M3), a spring at zeta >= 1 runs over its slowest decay rate instead; before it, an overdamped spring's window was cut short and it reached the target still moving.
            - `stiffness` number: Stiffness; higher lowers zeta, so the spring rings more.
            - `damping` number: Damping; higher raises zeta (less overshoot), lower rings longer.
            - `mass` number: Mass; like stiffness, higher lowers zeta, so the spring rings more. It does not swing slower: the segment's duration sets the timing.
          - `back` BackEasing: Anticipate/overshoot ease (AE 'back').
            - `overshoot` number: Overshoot amount; AE default 1.70158.
            - `dir` 'in' | 'out': 'in' anticipates, 'out' overshoots.
          - `elastic` ElasticEasing: Elastic ring-out/ring-in ease.
            - `amplitude` number: Ring amplitude.
            - `period` number: Ring period as a fraction of the segment.
            - `dir` 'in' | 'out': 'in' rings before, 'out' after.
          - `bezier` BezierEasing: CSS cubic-bezier(x1, y1, x2, y2) timing curve.
            - `x1` number
            - `y1` number
            - `x2` number
            - `y2` number
        - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
          - `source` string, required: uuid of the source layer (auto-hidden). Text sources supported.
          - `mode` 'alpha' | 'luma'
          - `invert` boolean
        - `backdrop_blur` union: Glass: the scene behind the element, Gaussian-blurred, fills its footprint under its translucent content (a shape's own silhouette, a video's or image's box with its corner radius and mask). A Gaussian sigma in canvas px, as CSS `backdrop-filter: blur()` takes it; the renderer caps it at 128. 0 is off.
          - integer
          - number
          - string
        - `backdrop_blur_keyframes` BlurKeyframe[], nullable: Animate `backdrop_blur` over the timeline; replaces the static value while present.
          - `time` number, required: Timeline seconds.
          - `value` number, required: Gaussian sigma in canvas px at `time`, at most 128.
        - `layer_blur` number: Blurs the element itself as drawn: a Gaussian sigma in canvas px, as CSS `filter: blur()` takes it, spreading three sigma past its box. At most 128; 0 is off. Not on a shape yet (the editor's preview cannot draw it), and not with `blend_mode`, `backdrop_blur` or `matte`, beside which the renderer would draw the element without it.
        - `layer_blur_keyframes` BlurKeyframe[], nullable: Animate `layer_blur` over the timeline; replaces the static value while present.
          - `time` number, required: Timeline seconds.
          - `value` number, required: Gaussian sigma in canvas px at `time`, at most 128.
        - `glass` Glass: A refracting glass surface (V6, render-node AEC §1): within `bevel` px of the element's edge (a shape's own outline, a box's rounded corners) the scene behind is read inward, bent by `refraction`, its red and blue split by `dispersion`. With `backdrop_blur` it bends the blurred scene, without it the sharp one.
          - `bevel` number, nullable: Width of the bent band at the edge in canvas px, at most 256. Omitted: 16.
          - `refraction` number, nullable: How far the edge bends the scene inward, 0–1. Omitted: 0.5.
          - `dispersion` number, nullable: How far red and blue split apart at the edge, 0–1. Omitted: 0.
        - `x` union
          - integer
          - number
          - string
        - `y` union
          - integer
          - number
          - string
        - `width` union: Box width. Together with `height` this is a **cover** box, not a fit box: sized media (video, image) scales to fill it and the overflow is **cropped** — it is never letterboxed. A box whose aspect ratio differs from the source's therefore silently cuts the source's edges. To show a source whole, match the box aspect to it: on a `W`x`H` canvas, for a source of aspect `a`, `width% = a * height% * (H/W)` — e.g. a 1024x1536 asset (a=0.667) on 1920x1080 needs `width% = 0.375 * height%`. Percentages are of the canvas, not the parent.
          - integer
          - number
          - string
        - `height` union: Box height. See `width` — the pair is a cover box and crops rather than letterboxes. Percentages are of the canvas.
          - integer
          - number
          - string
        - `aspect_ratio` number, nullable: **Accepted but ignored — the renderer never receives this field.** It does NOT constrain or correct the `width`/`height` box, so it cannot be used to stop a mismatched box from cropping the source; size the box per `width` instead. Kept for backward compatibility.
        - `x_anchor` union: Horizontal pivot the element **rotates** about, measured across its own box (`0%` = left edge, `50%` = centre, `100%` = right edge; px values are an offset from the left edge). This is a pivot, not an alignment — `x` always places the element's centre, so the anchor changes nothing on an unrotated element. Honored on video, image and shape; text and the generator elements rotate about their centre and reject a non-default anchor.
          - integer
          - number
          - string
        - `y_anchor` union: Vertical pivot the element **rotates** about, measured across its own box (`0%` = top edge, `50%` = centre, `100%` = bottom edge). Same rules as `x_anchor`: a pivot, not an alignment.
          - integer
          - number
          - string
        - `x_rotation` union
          - integer
          - number
          - string
        - `y_rotation` union
          - integer
          - number
          - string
        - `z_rotation` union
          - integer
          - number
          - string
        - `x_scale` union
          - integer
          - number
          - string
        - `y_scale` union
          - integer
          - number
          - string
        - `flip_horizontal` boolean
        - `flip_vertical` boolean
        - `opacity` number
        - `z_index` integer, nullable: Stacking order (higher = on top). When omitted, elements stack in array order — later elements render above earlier ones (painter's rule); text defaults one layer above non-text. Set explicit values only when array order isn't the order you want.
        - `clip` boolean
        - `color_overlay` string, nullable: **Not supported by the renderer — setting this is rejected.** A strict submit returns `unsupported_feature` (422) and a dry-run reports it as a blocking violation; there is no native tint field to map it onto. To darken an element use `brightness` (`-100` is a black silhouette); to lay a colour over one, stack a `shape` with a flat or gradient `fill` above it.
        - `type` 'video'
        - `id` string, nullable: Unique identifier for this element. **Required on image elements** — an empty or missing ID causes the image to be silently skipped by the renderer. Recommended on all elements that are referenced by a transition.
        - `name` string, nullable: Optional human-readable label. Not used by the renderer.
        - `track` integer, nullable: Timeline track index (0–255). Informational only; not used by the renderer.
        - `time` number, nullable: When this element starts on the output timeline, in seconds. Defaults to `0` when omitted.
        - `visible` boolean: Set to `false` to skip this element without removing it from the request.
        - `locked` boolean: Marks the element locked in editors. Not sent to the renderer.
        - `source_url` string, uri, required: URL of the video file — MP4, MOV or WebM only; any other extension is rejected at submit. Must be accessible by the renderer.
        - `in_point` number, nullable: In point — seconds into the source file to start playing from. Defaults to `0`.
        - `out_point` number, nullable: Out point — seconds into the source file to stop playing. Defaults to end of source when omitted. Controls clip length on the timeline.
        - `speed` number: Playback speed. `1.0` = normal speed, `2.0` = 2× (half duration), `0.5` = half speed (double duration).
        - `playback_rate_keyframes` RateKeyframe[], nullable: Speed ramp (§5c): piecewise-linear playback-rate keyframes (absolute timeline seconds; rate 0 = freeze; at most 512 keyframes — the renderer truncates beyond that). Audio keeps the static rate — mute or detach it on ramped clips.
          - `time` number, required: Timeline seconds.
          - `rate` number, required: Playback rate (0 = freeze-frame).
        - `volume` number: Embedded audio volume as a percentage (0–100). Affects only the audio track inside this video clip.
        - `muted` boolean: Silence the clip's embedded audio. `volume` is kept, so unmuting restores the level.
        - `loop` boolean: Repeat the source to fill the clip: when playback passes the end of the file it restarts from the file's first frame (not `in_point`). Set `out_point` past the source's length to choose how long the clip runs — its timeline length is still `(out_point − in_point) / speed`. Requires `out_point`.
        - `fade_in_duration` number: Duration in seconds of a linear audio fade-in at the clip's start.
        - `fade_out_duration` number: Duration in seconds of a linear audio fade-out at the clip's end.
        - `effects` Effect[]
          - `type` 'vintage' | 'polaroid' | 'portra' | 'super8' | 'filmic' | 'add_grain' | 'rgb_split' | 'ghosting' | 'displacement_map' | 'posterize' | 'mosaic' | 'mosaic_blur' | 'mosaic_posterize' | 'cc_halftone' | 'cc_halftone_blue' | 'cc_halftone_green' | 'cc_halftone_red' | 'invert' | 'optics_compensation' | 'viewfinder' | 'night_vision' | 'thermal' | 'camera_lens_blur' | 'camera_lens_blur_bg' | 'box_blur' | 'lens_flare' | 'strobe_light' | 'snow' | 'glow' | 'sepia' | 'echo' | 'chromatic_aberration' | 'vhs' | 'vhs_overlay' | 'crt' | 'television' | 'glitch' | 'compression_glitch' | 'scanlines' | 'prism' | 'light_leaks' | 'film_burn' | 'duotone' | 'cross_process' | 'bleach_bypass' | 'chroma_key' | 'aurora': Values: - `vintage` — Faded, warm retro film look with lifted blacks. - `polaroid` — Instant-photo look — soft contrast, warm cast, subtle vignette. - `portra` — Kodak Portra-style film emulation with natural skin tones. - `super8` — Super-8 home-movie look — grain, gate weave, warm color. - `filmic` — Cinematic film grade with rolled-off highlights and rich contrast. - `add_grain` — Adds dusty analog film grain over the image. - `rgb_split` — Offsets the red/green/blue channels for a glitchy chromatic split. - `ghosting` — Trailing motion echoes, like persistence-of-vision smearing. - `displacement_map` — Warps the image with a displacement texture for a melted look. - `posterize` — Reduces the image to a small number of flat color bands. - `mosaic` — Pixelates the image into large mosaic blocks. - `mosaic_blur` — Pixelated mosaic with softened, blurred block edges. - `mosaic_posterize` — Combines mosaic pixelation with posterized colors. - `cc_halftone` — Comic-style halftone dot pattern. - `cc_halftone_blue` — Halftone dot pattern tinted blue. - `cc_halftone_green` — Halftone dot pattern tinted green. - `cc_halftone_red` — Halftone dot pattern tinted red. - `invert` — Inverts all colors (photo-negative). - `optics_compensation` — Fish-eye / lens-distortion warp. - `viewfinder` — Camera viewfinder overlay (REC indicator, framing marks). - `night_vision` — Green night-vision look with glow and noise. - `thermal` — Thermal-camera false-color heat map. - `camera_lens_blur` — Realistic bokeh lens blur across the frame. - `camera_lens_blur_bg` — Bokeh lens blur applied to the background only. - `box_blur` — Fast, uniform box blur. - `lens_flare` — Adds an anamorphic lens-flare streak and glints. - `strobe_light` — Rapid brightness strobing / flashing. - `snow` — Falling-snow particle overlay. - `glow` — Dreamy soft-glow bloom over highlights. - `sepia` — Sepia-toned monochrome with a vignette. - `echo` — Soft ghosted dream-echo overlay. - `chromatic_aberration` — Color-fringing at edges, like cheap-lens dispersion. - `vhs` — VHS tape look: tracking noise, color bleed, and wobble. - `vhs_overlay` — VHS noise/scanline layer composited over the source. - `crt` — CRT monitor look: screen curvature, scanlines, and phosphor glow. - `television` — Analog TV look: scanlines, static, and signal distortion. - `glitch` — Digital glitch: block displacement and channel tearing. - `compression_glitch` — MPEG compression artifacts: blocky macroblocks and datamosh. - `scanlines` — Horizontal scanlines overlaid on the image. - `prism` — Prismatic light refraction with a rainbow color split. - `light_leaks` — Warm light-leak streaks bleeding across the frame. - `film_burn` — Burning-film look with scorched edges and flares. - `duotone` — Two-tone color map (shadows to one hue, highlights to another). - `cross_process` — Cross-processed film look with shifted, punchy colors. - `bleach_bypass` — High-contrast, desaturated bleach-bypass film grade. - `chroma_key` — Keys out a color (green/blue screen); tune via `chroma_settings`. - `aurora` — Animated domain-warped fluid-gradient wash (§6); tune flow via `props` speed.
          - `intensity` number, nullable: Effect strength, 0 to 100. On a shader effect it is null unless set: the shader then runs at the engine's own full intensity rather than the effect-wide 50.
          - `intensity_keyframes` IntensityKeyframe[], nullable: Animate intensity over time (§2): piecewise-linear `[{time, value}]` in timeline seconds. Overrides the static `intensity` when set.
            - `time` number, required: Absolute timeline seconds.
            - `value` number, required: Effect intensity 0–1 at this time.
          - `props` object, nullable: Per-shader scalar props (§2), bound as `u_prop_<key>` (e.g. `{"speed": 0.6}` for aurora). Ignored for chroma_key (use `chroma_settings`).
          - `chroma_settings` ChromaKeyProps: Used when ``EffectType.CHROMA_KEY`` is selected. Keys against an explicit key **colour** in the YCbCr chroma plane, which is luma-independent, so shadows falling on the screen key out along with it. This replaced an hue/saturation/luminance-window shape that could not work. It was wired to ``effect_chroma.frag``, whose ``sensitivity`` is ``(hueMax - hueMin) * 0.5`` compared against an Oklab distance bounded around 0..0.9 — so the old defaults (60/180) produced a sensitivity of 60, discarded every pixel, and made the element vanish from the render. Nothing could have depended on the previous shape, because nothing rendered with it.
            - `key_color` string: The colour to key out. Green-screen green by default.
            - `threshold` number: Chroma distance from `key_color` below which a pixel is fully transparent. Raise it if fringes of the screen survive.
            - `smoothness` number: Width of the ramp from transparent to opaque, starting at `threshold`. Raise it to soften hard edges; 0 gives a hard cut.
            - `spill_suppress` number: How strongly surviving pixels near the key colour are pulled toward their own luma, removing green spill on hair and edges. 0 disables.
          - `shader` EffectShader: A runtime shader (render-node AEC §2) by its stored id. `POST /v1/shaders` compiles one from SkSL source; the render carries its compiled variants, so it renders on the farm and in the preview alike.
            - `id` string, required: The shader's id (`sh_...`): one of this workspace's or a shared one (GET /v1/shaders).
            - `params` object: Values of the shader's declared params by name: a number (`float`), "#RRGGBBAA" (`color`) or [x, y] (`vec2`), or keyframes `[{time, value}]` in timeline seconds. A param left out takes its declared default.
        - `motion` Motion[]
          - `type` 'identity' | 'fade' | 'slide_up' | 'slide_down' | 'slide_left' | 'slide_right' | 'zoom_in' | 'zoom_out' | 'rotate_cw' | 'rotate_ccw' | 'bounce' | 'wipe_left' | 'wipe_right' | 'wipe_up' | 'wipe_down' | 'ken_burns_in' | 'ken_burns_out' | 'ken_burns_in_out' | 'loop_wiggle' | 'loop_rotate' | 'loop_rotate_smooth' | 'loop_3d_spin' | 'loop_3d_sway' | 'blur' | 'evaporate' | 'overlay' | 'difference' | 'rubber_in' | 'whip_up' | 'whip_down' | 'glitch_pop' | 'drift_in' | 'drift_out' | 'loop_breathe' | 'loop_shimmer' | 'swing_in' | 'swing_out' | 'elastic_rise' | 'elastic_drop' | 'tilt_zoom' | 'loop_orbit' | 'smooth_pop': Values: - `identity` — Deliberate no-op carrier (no visible motion): attach a pure `audio` generator to any element without animating it. Element surfaces only. - `fade` — Fade in (entrance) or out (exit) via opacity. - `slide_up` — Slide in from below / out upward. - `slide_down` — Slide in from above / out downward. - `slide_left` — Slide in from the right / out to the left. - `slide_right` — Slide in from the left / out to the right. - `zoom_in` — Scale up from small to full size (entrance). - `zoom_out` — Scale down to small (exit). - `rotate_cw` — Spin in/out clockwise. - `rotate_ccw` — Spin in/out counter-clockwise. - `bounce` — Bounce in with an elastic overshoot / bounce out. - `wipe_left` — Reveal/conceal with a left-moving wipe. - `wipe_right` — Reveal/conceal with a right-moving wipe. - `wipe_up` — Reveal/conceal with an upward wipe. - `wipe_down` — Reveal/conceal with a downward wipe. - `ken_burns_in` — Slow zoom-in pan (Ken Burns) — entrance only. - `ken_burns_out` — Slow zoom-out pan (Ken Burns) — entrance only. - `ken_burns_in_out` — Slow zoom in then out (Ken Burns) — entrance only. - `loop_wiggle` — Continuous subtle wiggle (looping). - `loop_rotate` — Continuous stepped rotation (looping). - `loop_rotate_smooth` — Continuous smooth rotation (looping). - `loop_3d_spin` — Continuous 3D spin (looping). - `loop_3d_sway` — Continuous 3D sway (looping). - `blur` — Per-glyph soft blur-in (text entrance). - `evaporate` — Per-glyph rise, blur, and fade-out (text exit only). - `overlay` — Static Overlay blend fill (timing ignored). - `difference` — Static Difference blend fill (timing ignored). - `rubber_in` — Per-glyph rubbery overshoot as text springs in (text entrance). - `whip_up` — Per-glyph whip upward into place (text entrance). - `whip_down` — Per-glyph whip downward out of frame (text exit only). - `glitch_pop` — Per-glyph glitchy pop-in with jitter (text entrance). - `drift_in` — Per-glyph gentle drift and fade in (text entrance). - `drift_out` — Per-glyph gentle drift and fade out (text exit only). - `loop_breathe` — Per-glyph continuous breathing scale loop (text). - `loop_shimmer` — Per-glyph continuous shimmer loop (text). - `swing_in` — Element swings into place from an angle (entrance). - `swing_out` — Element swings away out of frame (exit only). - `elastic_rise` — Element rises with an elastic overshoot (entrance). - `elastic_drop` — Element drops away with an elastic recoil (exit only). - `tilt_zoom` — Element tilts and zooms into place (entrance). - `loop_orbit` — Element orbits continuously around its center (loop). - `smooth_pop` — Element pops in from 60% scale, overshooting slightly past full size before it settles, as it fades in (entrance).
          - `preset` string, nullable: Renderer animation name, used verbatim — any element animation on video/image/shape/group (e.g. `'pop'`, `'floatUp'`, `'out-slideBounceLeft'`, `'loop-heartBeat'`), any text animation on text (e.g. `'typewriter'`, `'roll'`, `'out-sink'`, `'loop-wavey'`). Reaches the presets `type` has no name for. The name carries its own direction: `out-*` names are exits, `loop-*` names loop with `duration` as one cycle, so `reversed` and `scope` do not apply. Exactly one of `type`, `preset` or `custom` must be set.
          - `custom` string, nullable: Name of a `custom_animations` entry to run instead of a catalog preset — the `element` registry for video/image/shape/group animations, the `text` registry for text. Exactly one of `type`, `preset` or `custom` must be set.
          - `time` number, required: Absolute start time on the output timeline in seconds. For entrances and loops set this to the element's `time`. For exits set this to element `time + duration − motion duration`. An entrance timed later than the element's own `time` leaves it fully rendered on screen until the entrance fires; the linter reports that as `ENTRANCE_AFTER_ELEMENT_START`.
          - `duration` number, required: How long the animation runs in seconds.
          - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
          - `reversed` boolean: Run the preset's exit form instead of its entrance. Only presets that ship both forms accept it — `fade`, `slide_*`, `wipe_*`, `rotate_*`, `bounce`. Entrance-only presets have a separate exit-only type instead: use `zoom_out` (not `zoom_in` reversed), `evaporate` (not `blur`), `whip_down`, `drift_out`, `swing_out`, `elastic_drop` — those six set this flag for you. See `GET /v1/capabilities` `motion[].element_exit` for the per-preset truth.
          - `scope` 'element' | 'character': Whether a motion preset applies to the whole element or per-glyph (text only). Values: - `element` — The motion animates the whole element as one unit. - `character` — The motion animates each text glyph individually (text only).
          - `delay` number: Seconds to wait before the animation starts (folded into the animation's start time on the wire — the engine has no standalone pre-start delay). On loop presets it spaces the repeats instead.
          - `spacing` number, nullable: Stagger multiplier between per-glyph/word windows on text animations (engine default 1 = fully sequential; smaller values overlap the windows). Ignored by block animations.
          - `loop` boolean
          - `audio` AudioGenerator: Audio-reactive property offsets driven by the soundtrack FFT (§3, W2). Each frame the mix reduces to the chosen feature and the element's properties get offset by ``amount × feature`` — beat-bounce, bass-pumped scale, etc.
            - `feature` 'amplitude' | 'bass' | 'mid' | 'high' | 'beat'
            - `scale` number: Scale offset per unit feature.
            - `opacity` number: Opacity offset per unit feature.
            - `translate` Point
              - …
            - `rotate` number: Rotation offset (degrees) per unit feature.
      - AudioElement
        - `type` 'audio'
        - `id` string, nullable: Unique identifier for this element. **Required on image elements** — an empty or missing ID causes the image to be silently skipped by the renderer. Recommended on all elements that are referenced by a transition.
        - `name` string, nullable: Optional human-readable label. Not used by the renderer.
        - `track` integer, nullable: Timeline track index (0–255). Informational only; not used by the renderer.
        - `time` number, nullable: When this element starts on the output timeline, in seconds. Defaults to `0` when omitted.
        - `visible` boolean: Set to `false` to skip this element. Audio has no picture — `false` drops the whole track from the render, it does not mute or hide it (the linter reports that as `AUDIO_HIDDEN`). To keep the track but silence it, set `muted: true`.
        - `locked` boolean: Marks the element locked in editors. Not sent to the renderer.
        - `source_url` string, uri, required: URL of the audio file. Must be accessible by the renderer.
        - `in_point` number, nullable: In point — seconds into the source file to start from. Defaults to `0`.
        - `out_point` number, nullable: Out point — seconds into the source file to stop. Defaults to end of source when omitted. Controls clip length on the timeline.
        - `speed` number: Playback speed. `1.0` = normal speed, `2.0` = 2× speed.
        - `volume` number: Audio volume as a percentage (1–100). **Must be greater than 0** — the renderer silently drops audio streams with `volume <= 0`. Use `muted` to silence the track.
        - `muted` boolean: Silence this track while keeping it, and its `volume`, in the composition. A muted track is left out of the render's audio.
        - `fade_in_duration` number: Duration in seconds of a linear audio fade-in at the clip's start.
        - `fade_out_duration` number: Duration in seconds of a linear audio fade-out at the clip's end.
      - TextElement
        - `border_radius` union: Corner radius in pixels — a single value, or per-corner `{top_left, top_right, bottom_right, bottom_left}` for asymmetric corners (e.g. a card rounded only on top). The renderer normalizes px to a 0–1 fraction of the element's shorter side (≈ half the shorter side is fully rounded) and clamps to that range. For shape elements use `corner_radius` (already 0–1).
          - integer
          - number
          - string
          - CornerRadiiPx: Per-corner radii in pixels (for `border_radius` on video/image/text elements).
            - `top_left` union
              - …
            - `top_right` union
              - …
            - `bottom_right` union
              - …
            - `bottom_left` union
              - …
        - `border_color` string, nullable
        - `border_width` union: Border thickness in pixels (converted to the renderer's relative border scale against the element's shorter side, so it survives resizes). The border outlines the element's border_radius-rounded quad — not the image's alpha silhouette.
          - integer
          - number
          - string
        - `shadow_color` string, nullable
        - `shadow_blur` union: Shadow softness, 0–100 (renderer blur-strength scale, not pixels): 0 = hard edge, 100 = maximum blur. Values are clamped to that range.
          - integer
          - number
          - string
        - `shadow_x` union: Horizontal shadow offset in pixels (converted to the renderer's relative offset scale). The shadow silhouette is the element's border_radius-rounded quad, not the content alpha — a cut-out PNG gets a card shadow, not an outline-shaped one. On a cut-out that reads as a floating rectangle (rotated with the element, which is the tell). For a shadow that follows the artwork, drop these fields and stack a second copy of the same image underneath at `brightness: -100` (a black silhouette, alpha preserved) with `blur` and reduced `opacity`, offset a few percent — see `brightness`.
          - integer
          - number
          - string
        - `shadow_y` union: Vertical shadow offset in pixels. See `shadow_x`.
          - integer
          - number
          - string
        - `x` union
          - integer
          - number
          - string
        - `y` union
          - integer
          - number
          - string
        - `width` union: Box width. Together with `height` this is a **cover** box, not a fit box: sized media (video, image) scales to fill it and the overflow is **cropped** — it is never letterboxed. A box whose aspect ratio differs from the source's therefore silently cuts the source's edges. To show a source whole, match the box aspect to it: on a `W`x`H` canvas, for a source of aspect `a`, `width% = a * height% * (H/W)` — e.g. a 1024x1536 asset (a=0.667) on 1920x1080 needs `width% = 0.375 * height%`. Percentages are of the canvas, not the parent.
          - integer
          - number
          - string
        - `height` union: Box height. See `width` — the pair is a cover box and crops rather than letterboxes. Percentages are of the canvas.
          - integer
          - number
          - string
        - `aspect_ratio` number, nullable: **Accepted but ignored — the renderer never receives this field.** It does NOT constrain or correct the `width`/`height` box, so it cannot be used to stop a mismatched box from cropping the source; size the box per `width` instead. Kept for backward compatibility.
        - `x_anchor` union: Horizontal pivot the element **rotates** about, measured across its own box (`0%` = left edge, `50%` = centre, `100%` = right edge; px values are an offset from the left edge). This is a pivot, not an alignment — `x` always places the element's centre, so the anchor changes nothing on an unrotated element. Honored on video, image and shape; text and the generator elements rotate about their centre and reject a non-default anchor.
          - integer
          - number
          - string
        - `y_anchor` union: Vertical pivot the element **rotates** about, measured across its own box (`0%` = top edge, `50%` = centre, `100%` = bottom edge). Same rules as `x_anchor`: a pivot, not an alignment.
          - integer
          - number
          - string
        - `x_rotation` union
          - integer
          - number
          - string
        - `y_rotation` union
          - integer
          - number
          - string
        - `z_rotation` union
          - integer
          - number
          - string
        - `x_scale` union
          - integer
          - number
          - string
        - `y_scale` union
          - integer
          - number
          - string
        - `flip_horizontal` boolean
        - `flip_vertical` boolean
        - `opacity` number
        - `z_index` integer, nullable: Stacking order (higher = on top). When omitted, elements stack in array order — later elements render above earlier ones (painter's rule); text defaults one layer above non-text. Set explicit values only when array order isn't the order you want.
        - `clip` boolean
        - `color_overlay` string, nullable: **Not supported by the renderer — setting this is rejected.** A strict submit returns `unsupported_feature` (422) and a dry-run reports it as a blocking violation; there is no native tint field to map it onto. To darken an element use `brightness` (`-100` is a black silhouette); to lay a colour over one, stack a `shape` with a flat or gradient `fill` above it.
        - `type` 'text'
        - `id` string, nullable: Unique identifier for this element. **Required on image elements** — an empty or missing ID causes the image to be silently skipped by the renderer. Recommended on all elements that are referenced by a transition.
        - `name` string, nullable: Optional human-readable label. Not used by the renderer.
        - `track` integer, nullable: Timeline track index (0–255). Informational only; not used by the renderer.
        - `time` number, nullable: When this element starts on the output timeline, in seconds. Defaults to `0` when omitted.
        - `visible` boolean: Set to `false` to skip this element without removing it from the request.
        - `locked` boolean: Marks the element locked in editors. Not sent to the renderer.
        - `duration` number, required: **Required.** Duration in seconds the text is visible. Omitting this field produces a zero-length window and the element will not appear in the render.
        - `text` string, required: The text content to render.
        - `font_family` string: Font family name. Must be available to the renderer.
        - `font_size` number: Font size in pixels.
        - `font_weight` integer: Font weight (100–900). The renderer has no variable weights: `600` and above render **bold**, everything below renders regular. Composes with `font_style` (italic + ≥600 = bold italic).
        - `font_style` 'normal' | 'italic' | 'bold' | 'bolditalic': Font style variant.
        - `text_color` string: Text fill color as a hex string.
        - `text_align` 'left' | 'center' | 'right': Horizontal text alignment.
        - `text_direction` 'ltr' | 'rtl': Text direction. `rtl` for right-to-left scripts (§4).
        - `text_decoration` 'none' | 'underline' | 'strikethrough': Text decoration. Only `none` renders. `underline` is reachable only per word — `words[].style.underline` — and `strikethrough` has no renderer path at all; both are rejected here (422) rather than silently dropped. Draw a strike-through as a thin `shape` rectangle over the text.
        - `tracking` number: Letter spacing (tracking) in pixels (converted to the renderer's width-relative unit on the wire). Positive values add space between characters.
        - `tabular_numbers` boolean: Tabular (monospaced) figures: every digit takes the same advance, so columns of numbers align across lines and a `counter` does not jitter as its value changes. The renderer's baked fonts carry the OpenType alternates; a font whose face lacks the feature gets synthesised tabular digits in the export only. Default `false` = the font's proportional figures.
        - `leading` number: Line height (leading) as a multiplier of font size. `1.2` = 20% taller than the font size.
        - `stroke_color` string, nullable: Outline color. Set together with `stroke_width` to enable text outlines.
        - `stroke_width` number: Outline width, em-relative (fraction of `font_size` — e.g. `0.05` = 5% of the font size). Has no effect unless `stroke_color` is also set.
        - `background_color` string, nullable: Secondary colour. Fills the box behind the text when `background` is `true`, **and** is the highlight colour for `word_animation.style` `color` (the active word) and `box` (the box) — those two styles require it.
        - `background_opacity` number
        - `x_padding` union
          - integer
          - number
          - string
        - `y_padding` union
          - integer
          - number
          - string
        - `background` boolean: Solid color box behind the full text block. Set `background_color` to choose the color.
        - `background_style` 'block' | 'line_hard' | 'line_round': Shape of the `background` plate: `block` — one box behind the whole text; `line_hard` — a square-cornered box behind each line; `line_round` — a rounded box behind each line. Requires `background: true`. An animation that centres its words draws the `block` plate whichever style is set.
        - `stroke` boolean: Outline-only mode — draws the glyph stroke with no fill. Requires `stroke_color` and `stroke_width`. When `false`, setting `stroke_color` + `stroke_width` gives fill + stroke (outlined).
        - `shadow` boolean: Built-in drop shadow.
        - `motion` Motion[]
          - `type` 'identity' | 'fade' | 'slide_up' | 'slide_down' | 'slide_left' | 'slide_right' | 'zoom_in' | 'zoom_out' | 'rotate_cw' | 'rotate_ccw' | 'bounce' | 'wipe_left' | 'wipe_right' | 'wipe_up' | 'wipe_down' | 'ken_burns_in' | 'ken_burns_out' | 'ken_burns_in_out' | 'loop_wiggle' | 'loop_rotate' | 'loop_rotate_smooth' | 'loop_3d_spin' | 'loop_3d_sway' | 'blur' | 'evaporate' | 'overlay' | 'difference' | 'rubber_in' | 'whip_up' | 'whip_down' | 'glitch_pop' | 'drift_in' | 'drift_out' | 'loop_breathe' | 'loop_shimmer' | 'swing_in' | 'swing_out' | 'elastic_rise' | 'elastic_drop' | 'tilt_zoom' | 'loop_orbit' | 'smooth_pop': Values: - `identity` — Deliberate no-op carrier (no visible motion): attach a pure `audio` generator to any element without animating it. Element surfaces only. - `fade` — Fade in (entrance) or out (exit) via opacity. - `slide_up` — Slide in from below / out upward. - `slide_down` — Slide in from above / out downward. - `slide_left` — Slide in from the right / out to the left. - `slide_right` — Slide in from the left / out to the right. - `zoom_in` — Scale up from small to full size (entrance). - `zoom_out` — Scale down to small (exit). - `rotate_cw` — Spin in/out clockwise. - `rotate_ccw` — Spin in/out counter-clockwise. - `bounce` — Bounce in with an elastic overshoot / bounce out. - `wipe_left` — Reveal/conceal with a left-moving wipe. - `wipe_right` — Reveal/conceal with a right-moving wipe. - `wipe_up` — Reveal/conceal with an upward wipe. - `wipe_down` — Reveal/conceal with a downward wipe. - `ken_burns_in` — Slow zoom-in pan (Ken Burns) — entrance only. - `ken_burns_out` — Slow zoom-out pan (Ken Burns) — entrance only. - `ken_burns_in_out` — Slow zoom in then out (Ken Burns) — entrance only. - `loop_wiggle` — Continuous subtle wiggle (looping). - `loop_rotate` — Continuous stepped rotation (looping). - `loop_rotate_smooth` — Continuous smooth rotation (looping). - `loop_3d_spin` — Continuous 3D spin (looping). - `loop_3d_sway` — Continuous 3D sway (looping). - `blur` — Per-glyph soft blur-in (text entrance). - `evaporate` — Per-glyph rise, blur, and fade-out (text exit only). - `overlay` — Static Overlay blend fill (timing ignored). - `difference` — Static Difference blend fill (timing ignored). - `rubber_in` — Per-glyph rubbery overshoot as text springs in (text entrance). - `whip_up` — Per-glyph whip upward into place (text entrance). - `whip_down` — Per-glyph whip downward out of frame (text exit only). - `glitch_pop` — Per-glyph glitchy pop-in with jitter (text entrance). - `drift_in` — Per-glyph gentle drift and fade in (text entrance). - `drift_out` — Per-glyph gentle drift and fade out (text exit only). - `loop_breathe` — Per-glyph continuous breathing scale loop (text). - `loop_shimmer` — Per-glyph continuous shimmer loop (text). - `swing_in` — Element swings into place from an angle (entrance). - `swing_out` — Element swings away out of frame (exit only). - `elastic_rise` — Element rises with an elastic overshoot (entrance). - `elastic_drop` — Element drops away with an elastic recoil (exit only). - `tilt_zoom` — Element tilts and zooms into place (entrance). - `loop_orbit` — Element orbits continuously around its center (loop). - `smooth_pop` — Element pops in from 60% scale, overshooting slightly past full size before it settles, as it fades in (entrance).
          - `preset` string, nullable: Renderer animation name, used verbatim — any element animation on video/image/shape/group (e.g. `'pop'`, `'floatUp'`, `'out-slideBounceLeft'`, `'loop-heartBeat'`), any text animation on text (e.g. `'typewriter'`, `'roll'`, `'out-sink'`, `'loop-wavey'`). Reaches the presets `type` has no name for. The name carries its own direction: `out-*` names are exits, `loop-*` names loop with `duration` as one cycle, so `reversed` and `scope` do not apply. Exactly one of `type`, `preset` or `custom` must be set.
          - `custom` string, nullable: Name of a `custom_animations` entry to run instead of a catalog preset — the `element` registry for video/image/shape/group animations, the `text` registry for text. Exactly one of `type`, `preset` or `custom` must be set.
          - `time` number, required: Absolute start time on the output timeline in seconds. For entrances and loops set this to the element's `time`. For exits set this to element `time + duration − motion duration`. An entrance timed later than the element's own `time` leaves it fully rendered on screen until the entrance fires; the linter reports that as `ENTRANCE_AFTER_ELEMENT_START`.
          - `duration` number, required: How long the animation runs in seconds.
          - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
          - `reversed` boolean: Run the preset's exit form instead of its entrance. Only presets that ship both forms accept it — `fade`, `slide_*`, `wipe_*`, `rotate_*`, `bounce`. Entrance-only presets have a separate exit-only type instead: use `zoom_out` (not `zoom_in` reversed), `evaporate` (not `blur`), `whip_down`, `drift_out`, `swing_out`, `elastic_drop` — those six set this flag for you. See `GET /v1/capabilities` `motion[].element_exit` for the per-preset truth.
          - `scope` 'element' | 'character': Whether a motion preset applies to the whole element or per-glyph (text only). Values: - `element` — The motion animates the whole element as one unit. - `character` — The motion animates each text glyph individually (text only).
          - `delay` number: Seconds to wait before the animation starts (folded into the animation's start time on the wire — the engine has no standalone pre-start delay). On loop presets it spaces the repeats instead.
          - `spacing` number, nullable: Stagger multiplier between per-glyph/word windows on text animations (engine default 1 = fully sequential; smaller values overlap the windows). Ignored by block animations.
          - `loop` boolean
          - `audio` AudioGenerator: Audio-reactive property offsets driven by the soundtrack FFT (§3, W2). Each frame the mix reduces to the chosen feature and the element's properties get offset by ``amount × feature`` — beat-bounce, bass-pumped scale, etc.
            - `feature` 'amplitude' | 'bass' | 'mid' | 'high' | 'beat'
            - `scale` number: Scale offset per unit feature.
            - `opacity` number: Opacity offset per unit feature.
            - `translate` Point
              - …
            - `rotate` number: Rotation offset (degrees) per unit feature.
        - `word_animation` WordAnimation
          - `style` 'glow' | 'box' | 'scale_pop' | 'slide_up' | 'fly_in' | 'color', required: [API extension] Word-level animations (require word_animation.words). Values: - `glow` — Highlights the active word with a glowing emphasis. - `box` — Draws a colored box behind the active word. - `scale_pop` — Pops the active word with a quick scale punch. - `slide_up` — Floats each word up into place as it becomes active. - `fly_in` — Drops each word in from above as it becomes active. - `color` — Recolors the active word (karaoke-style highlight).
          - `words` Word[], required
            - `text` string, required
            - `start` number, required: ABSOLUTE output-timeline seconds (not element-relative).
            - `end` number, required: ABSOLUTE output-timeline seconds (not element-relative).
        - `words` WordSpec[], nullable: Per-word timing and optional per-word style overrides (§4). Emitted as a top-level `words[]` array; use alongside `motion`/`animation_preset` for the animation. Editorial-emphasis captions = word timings + a styled keyword.
          - `word` string, required: The word (whole-word match; UTF-8).
          - `start` number, required: Word reveal start, seconds — drives a word-group animation; ignored without one.
          - `end` number, required: Word reveal end, seconds — drives a word-group animation; ignored without one.
          - `style` WordStyle: Per-word style override (§4 W3). Whole-word matches only.
            - `color` string, nullable
            - `bold` boolean, nullable
            - `italic` boolean, nullable
            - `underline` boolean, nullable
        - `counter` ValueCounter: Rewrite a text element from an eased numeric sweep (the animated stat hero, §4).
          - `from_value` number: Start value.
          - `to_value` number: End value.
          - `decimals` integer: Decimal places (0–6).
          - `prefix` string: Text prepended to the number.
          - `suffix` string: Text appended to the number, e.g. '%'.
          - `easing` string, nullable: Easing curve name from the `easings` catalog (e.g. 'quad_out', 'expo_out'). Only named curves apply here — the parameterized spring/back/elastic families are not available on the counter.
          - `start_time` number: Seconds into the element to start the sweep.
          - `length` number, nullable: Sweep duration; defaults to the element's remaining life.
        - `glow` TextGlow: Soft glow around the glyphs (§4).
          - `color` string, required
          - `size` number: Glow size, em-relative.
          - `intensity` number: Glow intensity.
        - `text_wrap` 'wrap' | 'nowrap'
        - `animation_preset` string, nullable: Renderer text-animation name (e.g. `'typewriter'`) — a catalog text animation or a `custom_animations.text` entry. Runs for the whole element window with per-glyph timings computed by the renderer. Use `motion[]` (with `type`, `preset` or `custom`) for structured timing control — but not both. Ignored when `word_animation` is set.
      - ImageElement
        - `lut_url` string, uri, nullable
        - `lut_intensity` number
        - `brightness` number: Brightness, -100..100, applied as a 0..2 colour multiplier (0 = no change). `-100` multiplies by 0: the element renders pure black while keeping its alpha — a silhouette of the artwork. Combine a `brightness: -100` copy of an image with `blur`, reduced `opacity` and a small offset, stacked beneath the real one, to fake the content-shaped drop shadow `shadow_x`/`shadow_y` cannot produce.
        - `contrast` number
        - `saturation` number
        - `exposure` number
        - `sharpness` number
        - `blur` number
        - `noise` number
        - `vignette` number
        - `hue_rotate` number
        - `temperature` number: White balance warm (+) / cool (−), −1..1; 0 = no-op. Applied as a channel matrix, after the classic brightness/contrast chain.
        - `tint` number: White balance magenta (+) / green (−), −1..1; 0 = no-op.
        - `vibrance` number: Saturation boost weighted toward muted colours, −1..1; 0 = no-op. Boosts flat colour without wrecking skin tones.
        - `highlights` number: Luma-masked tone lift of the brightest range, −1..1; 0 = no-op.
        - `shadows` number: Luma-masked tone lift of the darkest range, −1..1; 0 = no-op.
        - `crop_top` number
        - `crop_bottom` number
        - `crop_left` number
        - `crop_right` number
        - `border_radius` union: Corner radius in pixels — a single value, or per-corner `{top_left, top_right, bottom_right, bottom_left}` for asymmetric corners (e.g. a card rounded only on top). The renderer normalizes px to a 0–1 fraction of the element's shorter side (≈ half the shorter side is fully rounded) and clamps to that range. For shape elements use `corner_radius` (already 0–1).
          - integer
          - number
          - string
          - CornerRadiiPx: Per-corner radii in pixels (for `border_radius` on video/image/text elements).
            - `top_left` union
              - …
            - `top_right` union
              - …
            - `bottom_right` union
              - …
            - `bottom_left` union
              - …
        - `border_color` string, nullable
        - `border_width` union: Border thickness in pixels (converted to the renderer's relative border scale against the element's shorter side, so it survives resizes). The border outlines the element's border_radius-rounded quad — not the image's alpha silhouette.
          - integer
          - number
          - string
        - `shadow_color` string, nullable
        - `shadow_blur` union: Shadow softness, 0–100 (renderer blur-strength scale, not pixels): 0 = hard edge, 100 = maximum blur. Values are clamped to that range.
          - integer
          - number
          - string
        - `shadow_x` union: Horizontal shadow offset in pixels (converted to the renderer's relative offset scale). The shadow silhouette is the element's border_radius-rounded quad, not the content alpha — a cut-out PNG gets a card shadow, not an outline-shaped one. On a cut-out that reads as a floating rectangle (rotated with the element, which is the tell). For a shadow that follows the artwork, drop these fields and stack a second copy of the same image underneath at `brightness: -100` (a black silhouette, alpha preserved) with `blur` and reduced `opacity`, offset a few percent — see `brightness`.
          - integer
          - number
          - string
        - `shadow_y` union: Vertical shadow offset in pixels. See `shadow_x`.
          - integer
          - number
          - string
        - `blend_mode` 'none' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color_dodge' | 'color_burn' | 'hard_light' | 'soft_light' | 'difference' | 'add' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity': Values: - `none` — Normal compositing (source-over) — the default. - `multiply` — Multiply blend — darkens by multiplying layer colors. - `screen` — Screen blend — lightens by inverting, multiplying, inverting. - `overlay` — Overlay blend — multiply in shadows, screen in highlights. - `darken` — Darken blend — keeps the darker of the two layers per channel. - `lighten` — Lighten blend — keeps the lighter of the two layers per channel. - `color_dodge` — Color-dodge blend — brightens the base toward the blend color. - `color_burn` — Color-burn blend — darkens the base toward the blend color. - `hard_light` — Hard-light blend — overlay with layers swapped. - `soft_light` — Soft-light blend — a gentler hard-light. - `difference` — Difference blend — absolute difference of the two layers per channel. - `add` — Additive (linear-dodge) blend — sums layer colors, clamped. - `exclusion` — Exclusion blend — like difference, lower contrast. - `hue` — Hue blend — backdrop luminosity + saturation with the blend layer's hue. - `saturation` — Saturation blend — backdrop hue + luminosity with the blend layer's saturation. - `color` — Color blend — backdrop luminosity with the blend layer's hue + saturation. - `luminosity` — Luminosity blend — backdrop hue + saturation with the blend layer's luminosity.
        - `mask_shape` 'circle' | 'diamond' | 'hexagon' | 'star' | 'heart' | 'triangle': Analytic (SDF) shape mask that clips an element's coverage. §1. Values: - `circle` — Circular (ellipse) analytic mask, fit to the element bounds. - `diamond` — Diamond (rotated square) analytic mask. - `hexagon` — Regular hexagon analytic mask. - `star` — Five-point star analytic mask. - `heart` — Heart analytic mask. - `triangle` — Upward triangle analytic mask.
        - `mask` MaskConfig: Animated/feathered mask params layered on the analytic `mask_shape` (§5c).
          - `feather` number: Soften the mask's SDF edge.
          - `scale` number: Mask scale (iris reveals).
          - `center` Point
            - `x` number
            - `y` number
        - `mask_keyframes` MaskKeyframe[], nullable
          - `time` number, required: Timeline seconds.
          - `feather` number, nullable
          - `scale` number, nullable
          - `center` Point
            - `x` number
            - `y` number
          - `easing` string, nullable: Easing curve name — any `easings` catalog value (`linear`, `hold`, `ease_in_out`, `quad_out`, `expo_in_out`, `square_in_out` = step, …). Unknown names are rejected: the engine would silently fall back to linear. For spring/back/elastic/bezier use the sub-objects instead.
          - `spring` SpringEasing: Damped-spring ease over the keyframe segment. Only the damping ratio zeta = damping / (2 * sqrt(stiffness * mass)) shapes the curve; the segment's duration sets its timing. Below 1 the spring overshoots and rings (the defaults give zeta = 0.5); at 1 or above it settles without overshoot. An underdamped spring runs until its envelope decays to 0.1% (settle x w0 = ln(1000) / zeta, w0 = sqrt(stiffness / mass)). Since render-node's overdamped settle fix (GVR M3), a spring at zeta >= 1 runs over its slowest decay rate instead; before it, an overdamped spring's window was cut short and it reached the target still moving.
            - `stiffness` number: Stiffness; higher lowers zeta, so the spring rings more.
            - `damping` number: Damping; higher raises zeta (less overshoot), lower rings longer.
            - `mass` number: Mass; like stiffness, higher lowers zeta, so the spring rings more. It does not swing slower: the segment's duration sets the timing.
          - `back` BackEasing: Anticipate/overshoot ease (AE 'back').
            - `overshoot` number: Overshoot amount; AE default 1.70158.
            - `dir` 'in' | 'out': 'in' anticipates, 'out' overshoots.
          - `elastic` ElasticEasing: Elastic ring-out/ring-in ease.
            - `amplitude` number: Ring amplitude.
            - `period` number: Ring period as a fraction of the segment.
            - `dir` 'in' | 'out': 'in' rings before, 'out' after.
          - `bezier` BezierEasing: CSS cubic-bezier(x1, y1, x2, y2) timing curve.
            - `x1` number
            - `y1` number
            - `x2` number
            - `y2` number
        - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
          - `source` string, required: uuid of the source layer (auto-hidden). Text sources supported.
          - `mode` 'alpha' | 'luma'
          - `invert` boolean
        - `backdrop_blur` union: Glass: the scene behind the element, Gaussian-blurred, fills its footprint under its translucent content (a shape's own silhouette, a video's or image's box with its corner radius and mask). A Gaussian sigma in canvas px, as CSS `backdrop-filter: blur()` takes it; the renderer caps it at 128. 0 is off.
          - integer
          - number
          - string
        - `backdrop_blur_keyframes` BlurKeyframe[], nullable: Animate `backdrop_blur` over the timeline; replaces the static value while present.
          - `time` number, required: Timeline seconds.
          - `value` number, required: Gaussian sigma in canvas px at `time`, at most 128.
        - `layer_blur` number: Blurs the element itself as drawn: a Gaussian sigma in canvas px, as CSS `filter: blur()` takes it, spreading three sigma past its box. At most 128; 0 is off. Not on a shape yet (the editor's preview cannot draw it), and not with `blend_mode`, `backdrop_blur` or `matte`, beside which the renderer would draw the element without it.
        - `layer_blur_keyframes` BlurKeyframe[], nullable: Animate `layer_blur` over the timeline; replaces the static value while present.
          - `time` number, required: Timeline seconds.
          - `value` number, required: Gaussian sigma in canvas px at `time`, at most 128.
        - `glass` Glass: A refracting glass surface (V6, render-node AEC §1): within `bevel` px of the element's edge (a shape's own outline, a box's rounded corners) the scene behind is read inward, bent by `refraction`, its red and blue split by `dispersion`. With `backdrop_blur` it bends the blurred scene, without it the sharp one.
          - `bevel` number, nullable: Width of the bent band at the edge in canvas px, at most 256. Omitted: 16.
          - `refraction` number, nullable: How far the edge bends the scene inward, 0–1. Omitted: 0.5.
          - `dispersion` number, nullable: How far red and blue split apart at the edge, 0–1. Omitted: 0.
        - `x` union
          - integer
          - number
          - string
        - `y` union
          - integer
          - number
          - string
        - `width` union: Box width. Together with `height` this is a **cover** box, not a fit box: sized media (video, image) scales to fill it and the overflow is **cropped** — it is never letterboxed. A box whose aspect ratio differs from the source's therefore silently cuts the source's edges. To show a source whole, match the box aspect to it: on a `W`x`H` canvas, for a source of aspect `a`, `width% = a * height% * (H/W)` — e.g. a 1024x1536 asset (a=0.667) on 1920x1080 needs `width% = 0.375 * height%`. Percentages are of the canvas, not the parent.
          - integer
          - number
          - string
        - `height` union: Box height. See `width` — the pair is a cover box and crops rather than letterboxes. Percentages are of the canvas.
          - integer
          - number
          - string
        - `aspect_ratio` number, nullable: **Accepted but ignored — the renderer never receives this field.** It does NOT constrain or correct the `width`/`height` box, so it cannot be used to stop a mismatched box from cropping the source; size the box per `width` instead. Kept for backward compatibility.
        - `x_anchor` union: Horizontal pivot the element **rotates** about, measured across its own box (`0%` = left edge, `50%` = centre, `100%` = right edge; px values are an offset from the left edge). This is a pivot, not an alignment — `x` always places the element's centre, so the anchor changes nothing on an unrotated element. Honored on video, image and shape; text and the generator elements rotate about their centre and reject a non-default anchor.
          - integer
          - number
          - string
        - `y_anchor` union: Vertical pivot the element **rotates** about, measured across its own box (`0%` = top edge, `50%` = centre, `100%` = bottom edge). Same rules as `x_anchor`: a pivot, not an alignment.
          - integer
          - number
          - string
        - `x_rotation` union
          - integer
          - number
          - string
        - `y_rotation` union
          - integer
          - number
          - string
        - `z_rotation` union
          - integer
          - number
          - string
        - `x_scale` union
          - integer
          - number
          - string
        - `y_scale` union
          - integer
          - number
          - string
        - `flip_horizontal` boolean
        - `flip_vertical` boolean
        - `opacity` number
        - `z_index` integer, nullable: Stacking order (higher = on top). When omitted, elements stack in array order — later elements render above earlier ones (painter's rule); text defaults one layer above non-text. Set explicit values only when array order isn't the order you want.
        - `clip` boolean
        - `color_overlay` string, nullable: **Not supported by the renderer — setting this is rejected.** A strict submit returns `unsupported_feature` (422) and a dry-run reports it as a blocking violation; there is no native tint field to map it onto. To darken an element use `brightness` (`-100` is a black silhouette); to lay a colour over one, stack a `shape` with a flat or gradient `fill` above it.
        - `type` 'image'
        - `id` string, required: **Required.** Unique identifier for this image. An empty or missing ID causes the image to be silently skipped by the renderer.
        - `name` string, nullable: Optional human-readable label. Not used by the renderer.
        - `track` integer, nullable: Timeline track index (0–255). Informational only; not used by the renderer.
        - `time` number, nullable: When this element starts on the output timeline, in seconds. Defaults to `0` when omitted.
        - `visible` boolean: Set to `false` to skip this element without removing it from the request.
        - `locked` boolean: Marks the element locked in editors. Not sent to the renderer.
        - `duration` number, required: **Required.** Duration in seconds the image is visible. Omitting this field produces a zero-length window and the image will not appear in the render.
        - `source_url` string, uri, required: URL of the image file (PNG, JPG, WebP, GIF, SVG). A `.svg` draws a subset: groups and the basic shapes and paths, filled and stroked with flat colours. An element that uses anything else (a `style` attribute, `clip-path`, `mask`, `filter`, `stroke-dasharray`, a gradient or `currentColor` paint, `<text>`, `<use>`, `<image>`) is not drawn, nor anything inside it; an SVG that would draw nothing at all is refused at submit. Set explicit colours and presentation attributes, or pre-rasterize to PNG.
        - `effects` Effect[]
          - `type` 'vintage' | 'polaroid' | 'portra' | 'super8' | 'filmic' | 'add_grain' | 'rgb_split' | 'ghosting' | 'displacement_map' | 'posterize' | 'mosaic' | 'mosaic_blur' | 'mosaic_posterize' | 'cc_halftone' | 'cc_halftone_blue' | 'cc_halftone_green' | 'cc_halftone_red' | 'invert' | 'optics_compensation' | 'viewfinder' | 'night_vision' | 'thermal' | 'camera_lens_blur' | 'camera_lens_blur_bg' | 'box_blur' | 'lens_flare' | 'strobe_light' | 'snow' | 'glow' | 'sepia' | 'echo' | 'chromatic_aberration' | 'vhs' | 'vhs_overlay' | 'crt' | 'television' | 'glitch' | 'compression_glitch' | 'scanlines' | 'prism' | 'light_leaks' | 'film_burn' | 'duotone' | 'cross_process' | 'bleach_bypass' | 'chroma_key' | 'aurora': Values: - `vintage` — Faded, warm retro film look with lifted blacks. - `polaroid` — Instant-photo look — soft contrast, warm cast, subtle vignette. - `portra` — Kodak Portra-style film emulation with natural skin tones. - `super8` — Super-8 home-movie look — grain, gate weave, warm color. - `filmic` — Cinematic film grade with rolled-off highlights and rich contrast. - `add_grain` — Adds dusty analog film grain over the image. - `rgb_split` — Offsets the red/green/blue channels for a glitchy chromatic split. - `ghosting` — Trailing motion echoes, like persistence-of-vision smearing. - `displacement_map` — Warps the image with a displacement texture for a melted look. - `posterize` — Reduces the image to a small number of flat color bands. - `mosaic` — Pixelates the image into large mosaic blocks. - `mosaic_blur` — Pixelated mosaic with softened, blurred block edges. - `mosaic_posterize` — Combines mosaic pixelation with posterized colors. - `cc_halftone` — Comic-style halftone dot pattern. - `cc_halftone_blue` — Halftone dot pattern tinted blue. - `cc_halftone_green` — Halftone dot pattern tinted green. - `cc_halftone_red` — Halftone dot pattern tinted red. - `invert` — Inverts all colors (photo-negative). - `optics_compensation` — Fish-eye / lens-distortion warp. - `viewfinder` — Camera viewfinder overlay (REC indicator, framing marks). - `night_vision` — Green night-vision look with glow and noise. - `thermal` — Thermal-camera false-color heat map. - `camera_lens_blur` — Realistic bokeh lens blur across the frame. - `camera_lens_blur_bg` — Bokeh lens blur applied to the background only. - `box_blur` — Fast, uniform box blur. - `lens_flare` — Adds an anamorphic lens-flare streak and glints. - `strobe_light` — Rapid brightness strobing / flashing. - `snow` — Falling-snow particle overlay. - `glow` — Dreamy soft-glow bloom over highlights. - `sepia` — Sepia-toned monochrome with a vignette. - `echo` — Soft ghosted dream-echo overlay. - `chromatic_aberration` — Color-fringing at edges, like cheap-lens dispersion. - `vhs` — VHS tape look: tracking noise, color bleed, and wobble. - `vhs_overlay` — VHS noise/scanline layer composited over the source. - `crt` — CRT monitor look: screen curvature, scanlines, and phosphor glow. - `television` — Analog TV look: scanlines, static, and signal distortion. - `glitch` — Digital glitch: block displacement and channel tearing. - `compression_glitch` — MPEG compression artifacts: blocky macroblocks and datamosh. - `scanlines` — Horizontal scanlines overlaid on the image. - `prism` — Prismatic light refraction with a rainbow color split. - `light_leaks` — Warm light-leak streaks bleeding across the frame. - `film_burn` — Burning-film look with scorched edges and flares. - `duotone` — Two-tone color map (shadows to one hue, highlights to another). - `cross_process` — Cross-processed film look with shifted, punchy colors. - `bleach_bypass` — High-contrast, desaturated bleach-bypass film grade. - `chroma_key` — Keys out a color (green/blue screen); tune via `chroma_settings`. - `aurora` — Animated domain-warped fluid-gradient wash (§6); tune flow via `props` speed.
          - `intensity` number, nullable: Effect strength, 0 to 100. On a shader effect it is null unless set: the shader then runs at the engine's own full intensity rather than the effect-wide 50.
          - `intensity_keyframes` IntensityKeyframe[], nullable: Animate intensity over time (§2): piecewise-linear `[{time, value}]` in timeline seconds. Overrides the static `intensity` when set.
            - `time` number, required: Absolute timeline seconds.
            - `value` number, required: Effect intensity 0–1 at this time.
          - `props` object, nullable: Per-shader scalar props (§2), bound as `u_prop_<key>` (e.g. `{"speed": 0.6}` for aurora). Ignored for chroma_key (use `chroma_settings`).
          - `chroma_settings` ChromaKeyProps: Used when ``EffectType.CHROMA_KEY`` is selected. Keys against an explicit key **colour** in the YCbCr chroma plane, which is luma-independent, so shadows falling on the screen key out along with it. This replaced an hue/saturation/luminance-window shape that could not work. It was wired to ``effect_chroma.frag``, whose ``sensitivity`` is ``(hueMax - hueMin) * 0.5`` compared against an Oklab distance bounded around 0..0.9 — so the old defaults (60/180) produced a sensitivity of 60, discarded every pixel, and made the element vanish from the render. Nothing could have depended on the previous shape, because nothing rendered with it.
            - `key_color` string: The colour to key out. Green-screen green by default.
            - `threshold` number: Chroma distance from `key_color` below which a pixel is fully transparent. Raise it if fringes of the screen survive.
            - `smoothness` number: Width of the ramp from transparent to opaque, starting at `threshold`. Raise it to soften hard edges; 0 gives a hard cut.
            - `spill_suppress` number: How strongly surviving pixels near the key colour are pulled toward their own luma, removing green spill on hair and edges. 0 disables.
          - `shader` EffectShader: A runtime shader (render-node AEC §2) by its stored id. `POST /v1/shaders` compiles one from SkSL source; the render carries its compiled variants, so it renders on the farm and in the preview alike.
            - `id` string, required: The shader's id (`sh_...`): one of this workspace's or a shared one (GET /v1/shaders).
            - `params` object: Values of the shader's declared params by name: a number (`float`), "#RRGGBBAA" (`color`) or [x, y] (`vec2`), or keyframes `[{time, value}]` in timeline seconds. A param left out takes its declared default.
        - `motion` Motion[]
          - `type` 'identity' | 'fade' | 'slide_up' | 'slide_down' | 'slide_left' | 'slide_right' | 'zoom_in' | 'zoom_out' | 'rotate_cw' | 'rotate_ccw' | 'bounce' | 'wipe_left' | 'wipe_right' | 'wipe_up' | 'wipe_down' | 'ken_burns_in' | 'ken_burns_out' | 'ken_burns_in_out' | 'loop_wiggle' | 'loop_rotate' | 'loop_rotate_smooth' | 'loop_3d_spin' | 'loop_3d_sway' | 'blur' | 'evaporate' | 'overlay' | 'difference' | 'rubber_in' | 'whip_up' | 'whip_down' | 'glitch_pop' | 'drift_in' | 'drift_out' | 'loop_breathe' | 'loop_shimmer' | 'swing_in' | 'swing_out' | 'elastic_rise' | 'elastic_drop' | 'tilt_zoom' | 'loop_orbit' | 'smooth_pop': Values: - `identity` — Deliberate no-op carrier (no visible motion): attach a pure `audio` generator to any element without animating it. Element surfaces only. - `fade` — Fade in (entrance) or out (exit) via opacity. - `slide_up` — Slide in from below / out upward. - `slide_down` — Slide in from above / out downward. - `slide_left` — Slide in from the right / out to the left. - `slide_right` — Slide in from the left / out to the right. - `zoom_in` — Scale up from small to full size (entrance). - `zoom_out` — Scale down to small (exit). - `rotate_cw` — Spin in/out clockwise. - `rotate_ccw` — Spin in/out counter-clockwise. - `bounce` — Bounce in with an elastic overshoot / bounce out. - `wipe_left` — Reveal/conceal with a left-moving wipe. - `wipe_right` — Reveal/conceal with a right-moving wipe. - `wipe_up` — Reveal/conceal with an upward wipe. - `wipe_down` — Reveal/conceal with a downward wipe. - `ken_burns_in` — Slow zoom-in pan (Ken Burns) — entrance only. - `ken_burns_out` — Slow zoom-out pan (Ken Burns) — entrance only. - `ken_burns_in_out` — Slow zoom in then out (Ken Burns) — entrance only. - `loop_wiggle` — Continuous subtle wiggle (looping). - `loop_rotate` — Continuous stepped rotation (looping). - `loop_rotate_smooth` — Continuous smooth rotation (looping). - `loop_3d_spin` — Continuous 3D spin (looping). - `loop_3d_sway` — Continuous 3D sway (looping). - `blur` — Per-glyph soft blur-in (text entrance). - `evaporate` — Per-glyph rise, blur, and fade-out (text exit only). - `overlay` — Static Overlay blend fill (timing ignored). - `difference` — Static Difference blend fill (timing ignored). - `rubber_in` — Per-glyph rubbery overshoot as text springs in (text entrance). - `whip_up` — Per-glyph whip upward into place (text entrance). - `whip_down` — Per-glyph whip downward out of frame (text exit only). - `glitch_pop` — Per-glyph glitchy pop-in with jitter (text entrance). - `drift_in` — Per-glyph gentle drift and fade in (text entrance). - `drift_out` — Per-glyph gentle drift and fade out (text exit only). - `loop_breathe` — Per-glyph continuous breathing scale loop (text). - `loop_shimmer` — Per-glyph continuous shimmer loop (text). - `swing_in` — Element swings into place from an angle (entrance). - `swing_out` — Element swings away out of frame (exit only). - `elastic_rise` — Element rises with an elastic overshoot (entrance). - `elastic_drop` — Element drops away with an elastic recoil (exit only). - `tilt_zoom` — Element tilts and zooms into place (entrance). - `loop_orbit` — Element orbits continuously around its center (loop). - `smooth_pop` — Element pops in from 60% scale, overshooting slightly past full size before it settles, as it fades in (entrance).
          - `preset` string, nullable: Renderer animation name, used verbatim — any element animation on video/image/shape/group (e.g. `'pop'`, `'floatUp'`, `'out-slideBounceLeft'`, `'loop-heartBeat'`), any text animation on text (e.g. `'typewriter'`, `'roll'`, `'out-sink'`, `'loop-wavey'`). Reaches the presets `type` has no name for. The name carries its own direction: `out-*` names are exits, `loop-*` names loop with `duration` as one cycle, so `reversed` and `scope` do not apply. Exactly one of `type`, `preset` or `custom` must be set.
          - `custom` string, nullable: Name of a `custom_animations` entry to run instead of a catalog preset — the `element` registry for video/image/shape/group animations, the `text` registry for text. Exactly one of `type`, `preset` or `custom` must be set.
          - `time` number, required: Absolute start time on the output timeline in seconds. For entrances and loops set this to the element's `time`. For exits set this to element `time + duration − motion duration`. An entrance timed later than the element's own `time` leaves it fully rendered on screen until the entrance fires; the linter reports that as `ENTRANCE_AFTER_ELEMENT_START`.
          - `duration` number, required: How long the animation runs in seconds.
          - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
          - `reversed` boolean: Run the preset's exit form instead of its entrance. Only presets that ship both forms accept it — `fade`, `slide_*`, `wipe_*`, `rotate_*`, `bounce`. Entrance-only presets have a separate exit-only type instead: use `zoom_out` (not `zoom_in` reversed), `evaporate` (not `blur`), `whip_down`, `drift_out`, `swing_out`, `elastic_drop` — those six set this flag for you. See `GET /v1/capabilities` `motion[].element_exit` for the per-preset truth.
          - `scope` 'element' | 'character': Whether a motion preset applies to the whole element or per-glyph (text only). Values: - `element` — The motion animates the whole element as one unit. - `character` — The motion animates each text glyph individually (text only).
          - `delay` number: Seconds to wait before the animation starts (folded into the animation's start time on the wire — the engine has no standalone pre-start delay). On loop presets it spaces the repeats instead.
          - `spacing` number, nullable: Stagger multiplier between per-glyph/word windows on text animations (engine default 1 = fully sequential; smaller values overlap the windows). Ignored by block animations.
          - `loop` boolean
          - `audio` AudioGenerator: Audio-reactive property offsets driven by the soundtrack FFT (§3, W2). Each frame the mix reduces to the chosen feature and the element's properties get offset by ``amount × feature`` — beat-bounce, bass-pumped scale, etc.
            - `feature` 'amplitude' | 'bass' | 'mid' | 'high' | 'beat'
            - `scale` number: Scale offset per unit feature.
            - `opacity` number: Opacity offset per unit feature.
            - `translate` Point
              - …
            - `rotate` number: Rotation offset (degrees) per unit feature.
      - ShapeElement: A first-class vector primitive: SVG path fill + stroke, morphing (§5b).
        - `blend_mode` 'none' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color_dodge' | 'color_burn' | 'hard_light' | 'soft_light' | 'difference' | 'add' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity': Values: - `none` — Normal compositing (source-over) — the default. - `multiply` — Multiply blend — darkens by multiplying layer colors. - `screen` — Screen blend — lightens by inverting, multiplying, inverting. - `overlay` — Overlay blend — multiply in shadows, screen in highlights. - `darken` — Darken blend — keeps the darker of the two layers per channel. - `lighten` — Lighten blend — keeps the lighter of the two layers per channel. - `color_dodge` — Color-dodge blend — brightens the base toward the blend color. - `color_burn` — Color-burn blend — darkens the base toward the blend color. - `hard_light` — Hard-light blend — overlay with layers swapped. - `soft_light` — Soft-light blend — a gentler hard-light. - `difference` — Difference blend — absolute difference of the two layers per channel. - `add` — Additive (linear-dodge) blend — sums layer colors, clamped. - `exclusion` — Exclusion blend — like difference, lower contrast. - `hue` — Hue blend — backdrop luminosity + saturation with the blend layer's hue. - `saturation` — Saturation blend — backdrop hue + luminosity with the blend layer's saturation. - `color` — Color blend — backdrop luminosity with the blend layer's hue + saturation. - `luminosity` — Luminosity blend — backdrop hue + saturation with the blend layer's luminosity.
        - `mask_shape` 'circle' | 'diamond' | 'hexagon' | 'star' | 'heart' | 'triangle': Analytic (SDF) shape mask that clips an element's coverage. §1. Values: - `circle` — Circular (ellipse) analytic mask, fit to the element bounds. - `diamond` — Diamond (rotated square) analytic mask. - `hexagon` — Regular hexagon analytic mask. - `star` — Five-point star analytic mask. - `heart` — Heart analytic mask. - `triangle` — Upward triangle analytic mask.
        - `mask` MaskConfig: Animated/feathered mask params layered on the analytic `mask_shape` (§5c).
          - `feather` number: Soften the mask's SDF edge.
          - `scale` number: Mask scale (iris reveals).
          - `center` Point
            - `x` number
            - `y` number
        - `mask_keyframes` MaskKeyframe[], nullable
          - `time` number, required: Timeline seconds.
          - `feather` number, nullable
          - `scale` number, nullable
          - `center` Point
            - `x` number
            - `y` number
          - `easing` string, nullable: Easing curve name — any `easings` catalog value (`linear`, `hold`, `ease_in_out`, `quad_out`, `expo_in_out`, `square_in_out` = step, …). Unknown names are rejected: the engine would silently fall back to linear. For spring/back/elastic/bezier use the sub-objects instead.
          - `spring` SpringEasing: Damped-spring ease over the keyframe segment. Only the damping ratio zeta = damping / (2 * sqrt(stiffness * mass)) shapes the curve; the segment's duration sets its timing. Below 1 the spring overshoots and rings (the defaults give zeta = 0.5); at 1 or above it settles without overshoot. An underdamped spring runs until its envelope decays to 0.1% (settle x w0 = ln(1000) / zeta, w0 = sqrt(stiffness / mass)). Since render-node's overdamped settle fix (GVR M3), a spring at zeta >= 1 runs over its slowest decay rate instead; before it, an overdamped spring's window was cut short and it reached the target still moving.
            - `stiffness` number: Stiffness; higher lowers zeta, so the spring rings more.
            - `damping` number: Damping; higher raises zeta (less overshoot), lower rings longer.
            - `mass` number: Mass; like stiffness, higher lowers zeta, so the spring rings more. It does not swing slower: the segment's duration sets the timing.
          - `back` BackEasing: Anticipate/overshoot ease (AE 'back').
            - `overshoot` number: Overshoot amount; AE default 1.70158.
            - `dir` 'in' | 'out': 'in' anticipates, 'out' overshoots.
          - `elastic` ElasticEasing: Elastic ring-out/ring-in ease.
            - `amplitude` number: Ring amplitude.
            - `period` number: Ring period as a fraction of the segment.
            - `dir` 'in' | 'out': 'in' rings before, 'out' after.
          - `bezier` BezierEasing: CSS cubic-bezier(x1, y1, x2, y2) timing curve.
            - `x1` number
            - `y1` number
            - `x2` number
            - `y2` number
        - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
          - `source` string, required: uuid of the source layer (auto-hidden). Text sources supported.
          - `mode` 'alpha' | 'luma'
          - `invert` boolean
        - `backdrop_blur` union: Glass: the scene behind the element, Gaussian-blurred, fills its footprint under its translucent content (a shape's own silhouette, a video's or image's box with its corner radius and mask). A Gaussian sigma in canvas px, as CSS `backdrop-filter: blur()` takes it; the renderer caps it at 128. 0 is off.
          - integer
          - number
          - string
        - `backdrop_blur_keyframes` BlurKeyframe[], nullable: Animate `backdrop_blur` over the timeline; replaces the static value while present.
          - `time` number, required: Timeline seconds.
          - `value` number, required: Gaussian sigma in canvas px at `time`, at most 128.
        - `layer_blur` number: Blurs the element itself as drawn: a Gaussian sigma in canvas px, as CSS `filter: blur()` takes it, spreading three sigma past its box. At most 128; 0 is off. Not on a shape yet (the editor's preview cannot draw it), and not with `blend_mode`, `backdrop_blur` or `matte`, beside which the renderer would draw the element without it.
        - `layer_blur_keyframes` BlurKeyframe[], nullable: Animate `layer_blur` over the timeline; replaces the static value while present.
          - `time` number, required: Timeline seconds.
          - `value` number, required: Gaussian sigma in canvas px at `time`, at most 128.
        - `glass` Glass: A refracting glass surface (V6, render-node AEC §1): within `bevel` px of the element's edge (a shape's own outline, a box's rounded corners) the scene behind is read inward, bent by `refraction`, its red and blue split by `dispersion`. With `backdrop_blur` it bends the blurred scene, without it the sharp one.
          - `bevel` number, nullable: Width of the bent band at the edge in canvas px, at most 256. Omitted: 16.
          - `refraction` number, nullable: How far the edge bends the scene inward, 0–1. Omitted: 0.5.
          - `dispersion` number, nullable: How far red and blue split apart at the edge, 0–1. Omitted: 0.
        - `x` union
          - integer
          - number
          - string
        - `y` union
          - integer
          - number
          - string
        - `width` union: Box width. Together with `height` this is a **cover** box, not a fit box: sized media (video, image) scales to fill it and the overflow is **cropped** — it is never letterboxed. A box whose aspect ratio differs from the source's therefore silently cuts the source's edges. To show a source whole, match the box aspect to it: on a `W`x`H` canvas, for a source of aspect `a`, `width% = a * height% * (H/W)` — e.g. a 1024x1536 asset (a=0.667) on 1920x1080 needs `width% = 0.375 * height%`. Percentages are of the canvas, not the parent.
          - integer
          - number
          - string
        - `height` union: Box height. See `width` — the pair is a cover box and crops rather than letterboxes. Percentages are of the canvas.
          - integer
          - number
          - string
        - `aspect_ratio` number, nullable: **Accepted but ignored — the renderer never receives this field.** It does NOT constrain or correct the `width`/`height` box, so it cannot be used to stop a mismatched box from cropping the source; size the box per `width` instead. Kept for backward compatibility.
        - `x_anchor` union: Horizontal pivot the element **rotates** about, measured across its own box (`0%` = left edge, `50%` = centre, `100%` = right edge; px values are an offset from the left edge). This is a pivot, not an alignment — `x` always places the element's centre, so the anchor changes nothing on an unrotated element. Honored on video, image and shape; text and the generator elements rotate about their centre and reject a non-default anchor.
          - integer
          - number
          - string
        - `y_anchor` union: Vertical pivot the element **rotates** about, measured across its own box (`0%` = top edge, `50%` = centre, `100%` = bottom edge). Same rules as `x_anchor`: a pivot, not an alignment.
          - integer
          - number
          - string
        - `x_rotation` union
          - integer
          - number
          - string
        - `y_rotation` union
          - integer
          - number
          - string
        - `z_rotation` union
          - integer
          - number
          - string
        - `x_scale` union
          - integer
          - number
          - string
        - `y_scale` union
          - integer
          - number
          - string
        - `flip_horizontal` boolean
        - `flip_vertical` boolean
        - `opacity` number
        - `z_index` integer, nullable: Stacking order (higher = on top). When omitted, elements stack in array order — later elements render above earlier ones (painter's rule); text defaults one layer above non-text. Set explicit values only when array order isn't the order you want.
        - `clip` boolean
        - `color_overlay` string, nullable: **Not supported by the renderer — setting this is rejected.** A strict submit returns `unsupported_feature` (422) and a dry-run reports it as a blocking violation; there is no native tint field to map it onto. To darken an element use `brightness` (`-100` is a black silhouette); to lay a colour over one, stack a `shape` with a flat or gradient `fill` above it.
        - `type` 'shape'
        - `id` string, required: **Required.** Unique identifier.
        - `name` string, nullable: Optional human-readable label. Not used by the renderer.
        - `track` integer, nullable: Timeline track index (0–255). Informational only; not used by the renderer.
        - `time` number, nullable: When this element starts on the output timeline, in seconds. Defaults to `0` when omitted.
        - `visible` boolean: Set to `false` to skip this element without removing it from the request.
        - `locked` boolean: Marks the element locked in editors. Not sent to the renderer.
        - `duration` number, required: **Required.** Seconds the shape is visible.
        - `path` string, nullable: SVG path `d` (M L H V C S Q T A Z; elliptical arcs render as arcs). **Required** unless `geometry` is set.
        - `geometry` ShapeGeometry: A closed-form shape the engines draw analytically (AEC §5f): exactly one kind.
          - `rect` GeometryRect: A rectangle filling the element box, optionally with rounded corners.
            - `corner_radius` union: Corner radius in px: one number for all four corners, `[top_left, top_right, bottom_right, bottom_left]`, or `{top_left, top_right, bottom_right, bottom_left}` (missing corners 0). Omitted: square corners.
              - …
            - `smoothing` number, nullable: Figma's corner smoothing, 0 to 1: above 0 the corners ease into the edges (a squircle at 1). Omitted: 0, the plain rounded rect.
          - `ellipse` GeometryEllipse: The ellipse inscribed in the element box (a circle when the box is square).
          - `line` GeometryLine: A straight line painted with the shape's `stroke` (else its `fill`). Endpoints are px from the element box's top-left corner; the width is `stroke_width` and the ends are `stroke_linecap`. Endpoints left out give the box's horizontal centre line.
            - `x1` number, nullable
            - `y1` number, nullable
            - `x2` number, nullable
            - `y2` number, nullable
          - `ring` GeometryRing: A ring, arc, pie or segmented ring: circular, inscribed in the box's shorter side.
            - `inner_ratio` number, nullable: The hole's share of the radius, 0–1 (0 is a pie). Omitted: 0.
            - `inner_ratio_percent` number, nullable: `inner_ratio` as a percent (85 is 0.85).
            - `start_angle` number, nullable: Where the sweep starts, degrees, 0 at 3 o'clock, clockwise. Omitted: 0.
            - `sweep` number, nullable: Degrees drawn clockwise from `start_angle`. Omitted: 360. With `segments` the sweep is theirs, so leave it out.
            - `sweep_percent` number, nullable: `sweep` as a percent of the full circle (100 = 360°).
            - `cap` 'butt' | 'round', nullable: Ends of a partial sweep. Omitted: `butt`.
            - `segments` GeometrySegment[], nullable: Consecutive solid slices (at most 32, together at most 360°) drawn as one shape, so abutting slices leave no seam.
              - …
          - `arc` GeometryRing: A ring, arc, pie or segmented ring: circular, inscribed in the box's shorter side.
            - `inner_ratio` number, nullable: The hole's share of the radius, 0–1 (0 is a pie). Omitted: 0.
            - `inner_ratio_percent` number, nullable: `inner_ratio` as a percent (85 is 0.85).
            - `start_angle` number, nullable: Where the sweep starts, degrees, 0 at 3 o'clock, clockwise. Omitted: 0.
            - `sweep` number, nullable: Degrees drawn clockwise from `start_angle`. Omitted: 360. With `segments` the sweep is theirs, so leave it out.
            - `sweep_percent` number, nullable: `sweep` as a percent of the full circle (100 = 360°).
            - `cap` 'butt' | 'round', nullable: Ends of a partial sweep. Omitted: `butt`.
            - `segments` GeometrySegment[], nullable: Consecutive solid slices (at most 32, together at most 360°) drawn as one shape, so abutting slices leave no seam.
              - …
          - `polygon` GeometryPolygon: A regular polygon inscribed in the ellipse the box holds, its first vertex at 12 o'clock.
            - `sides` integer, nullable: Vertices. Omitted: 5.
            - `corner_radius` number, nullable: Rounds every vertex with an arc of this radius in px. Omitted: 0.
          - `star` GeometryStar: A star: `points` outer vertices on the ellipse the box holds (the first at 12 o'clock), alternating with inner ones on that ellipse scaled by `inner_ratio`.
            - `points` integer, nullable: Outer vertices. Omitted: 5.
            - `inner_ratio` number, nullable: The inner vertices' share of the outer ellipse. Omitted: 0.382, a regular pentagram's.
            - `corner_radius` number, nullable: Rounds every vertex with an arc of this radius in px. Omitted: 0.
          - `stroke_align` 'inside' | 'center' | 'outside', nullable: Where the stroke sits on the outline (`centre` is read as `center`). Omitted: `center`. A polygon, a star and a smoothed rect stroke centred.
          - `shadows` GeometryShadow[], nullable: Up to 4 shadows, the first on top, on a rect or an ellipse drawn as a circle.
            - `type` 'drop' | 'inner', nullable: Omitted: `drop`.
            - `x` number, nullable: Horizontal offset in px.
            - `y` number, nullable: Vertical offset in px, down positive.
            - `blur` number, nullable: CSS blur radius in px (sigma = blur / 2).
            - `spread` number, nullable: Spread in px.
            - `color` string, required
        - `view_box` number[]: `[x, y, width, height]` path coordinate space.
        - `fill` union: Fill: a hex colour (alpha ok), `"none"` for outline-only, a Gradient object (`{kind, angle_degrees, center, stops}`, ≥2 stops), or a CSS `linear-gradient(...)` / `radial-gradient(...)` string, which is normalised to the Gradient object at validation — read back, the composition holds the object. A gradient fill on a rectangular path is how you draw a gradient card, bar or pill — there is no separate `gradient` element. The gradient paints the shape's own path, so it fills any silhouette — a triangle, a blob, an icon outline, a morphing path — and layers on the same element with `stroke` / `stroke_width` / `stroke_dash`, `path_keyframes` (morph), `trim` / `trim_keyframes` (draw-on), `blend_mode`, `mask_shape` / `mask` / `mask_keyframes`, `matte` and `backdrop_blur`. `fill_rule`, `corner_radius` and `opacity` behave with a gradient exactly as they do with a flat colour.
          - string
          - 'none'
          - string: CSS gradient shorthand — `linear-gradient(...)` or `radial-gradient(...)`. Normalised to the Gradient object during validation; the renderer never sees a CSS string, and reading the composition back returns the object.
          - Gradient
            - `kind` 'linear' | 'radial' | 'conic': `conic` sweeps the stops clockwise once round `center`, starting at `angle_degrees`.
            - `angle_degrees` number: Linear gradient angle in degrees, measured clockwise on the screen (y down): 0 = left→right (offset 0 at the left), 90 = top→bottom, 45 = top-left→bottom-right, 315 = bottom-left→top-right, and the same convention governs a shape's gradient `fill`. A numeric CSS angle is box-relative: `135deg` behaves as `to bottom right` whatever the card's shape; only 0/90/180/270 are pixel-exact. On a conic gradient: where the sweep starts, degrees clockwise from 3 o'clock.
            - `center` Point
              - …
            - `stops` GradientStop[], required: Two or more colour stops.
              - …
        - `fill_rule` 'nonzero' | 'evenodd'
        - `stroke` string, nullable: Stroke colour.
        - `stroke_width` number, nullable: Stroke width in viewBox units, at most 100000 (absent = SVG 1.0; 0 disables).
        - `stroke_linecap` 'butt' | 'round' | 'square': Cap on the open ends of a stroked path (SVG `stroke-linecap`): `butt` stops at the endpoint, `round` and `square` extend it by half the stroke width. Closed paths have joins, not caps.
        - `stroke_linejoin` 'miter' | 'round' | 'bevel': Corner join of a stroked path (SVG `stroke-linejoin`): `miter` is the sharp corner (subject to `stroke_miter_limit`), `bevel` cuts it flat.
        - `stroke_miter_limit` number: SVG `stroke-miterlimit`: miter length over stroke width. A `miter` join sharper than this falls back to `bevel`.
        - `stroke_dash` number[], nullable: Dash pattern in viewBox units, SVG `stroke-dasharray` semantics: `[on, off, ...]` of any length — an odd-length array repeats so on/off alternate (`[4]` is 4 on, 4 off). Trim applies before dash, so a dashed path can draw itself on without the pattern re-flowing.
        - `stroke_dash_offset` number: Where the dash pattern starts along the path, in viewBox units (SVG `stroke-dashoffset`): positive shifts the pattern forward, negative backward.
        - `stroke_dash_offset_keyframes` DashOffsetKeyframe[], nullable: Animate the dash offset (timeline seconds) — marching ants: keyframe `offset` linearly by one dash period (the pattern's sum) per second. Needs a `stroke_dash`; while present it drives the offset in place of the static `stroke_dash_offset`.
          - `time` number, required: Timeline seconds.
          - `offset` number, required: Dash offset at this time, in viewBox units (SVG `stroke-dashoffset`).
          - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
          - `spring` SpringEasing: Damped-spring ease over the keyframe segment. Only the damping ratio zeta = damping / (2 * sqrt(stiffness * mass)) shapes the curve; the segment's duration sets its timing. Below 1 the spring overshoots and rings (the defaults give zeta = 0.5); at 1 or above it settles without overshoot. An underdamped spring runs until its envelope decays to 0.1% (settle x w0 = ln(1000) / zeta, w0 = sqrt(stiffness / mass)). Since render-node's overdamped settle fix (GVR M3), a spring at zeta >= 1 runs over its slowest decay rate instead; before it, an overdamped spring's window was cut short and it reached the target still moving.
            - `stiffness` number: Stiffness; higher lowers zeta, so the spring rings more.
            - `damping` number: Damping; higher raises zeta (less overshoot), lower rings longer.
            - `mass` number: Mass; like stiffness, higher lowers zeta, so the spring rings more. It does not swing slower: the segment's duration sets the timing.
          - `back` BackEasing: Anticipate/overshoot ease (AE 'back').
            - `overshoot` number: Overshoot amount; AE default 1.70158.
            - `dir` 'in' | 'out': 'in' anticipates, 'out' overshoots.
          - `elastic` ElasticEasing: Elastic ring-out/ring-in ease.
            - `amplitude` number: Ring amplitude.
            - `period` number: Ring period as a fraction of the segment.
            - `dir` 'in' | 'out': 'in' rings before, 'out' after.
          - `bezier` BezierEasing: CSS cubic-bezier(x1, y1, x2, y2) timing curve.
            - `x1` number
            - `y1` number
            - `x2` number
            - `y2` number
        - `stroke_marker_start` 'none' | 'triangle' | 'open_chevron' | 'dot': A head at the start of each open subpath, in the stroke's colour (render-node V2.6): `triangle` is filled, its tip on the endpoint (the shaft shortens to meet it); `open_chevron` is an open head stroked like the path; `dot` is a disc. Placed after the trim, so a draw-on keeps its head at the visible end, and left out of the dash. A closed subpath takes none. Needs a `stroke`; path shapes only.
        - `stroke_marker_end` 'none' | 'triangle' | 'open_chevron' | 'dot': A head at the end of each open subpath; see `stroke_marker_start`.
        - `stroke_marker_size` number: Marker length in stroke widths, 1–32 (4 is four times `stroke_width`).
        - `corner_radius` union: Corner radius, normalized 0–1 — a single value or per-corner `{top_left, top_right, bottom_right, bottom_left}`.
          - number
          - CornerRadii: Per-corner radii, each normalized 0–1 (1 = fully round on the shorter side).
            - `top_left` number
            - `top_right` number
            - `bottom_right` number
            - `bottom_left` number
        - `shadow` DropShadow: Drop shadow for shape elements, in the renderer's own units. ``distance`` and ``blur`` are the engine's unitless 0–100 strength scale, NOT pixels — a px-looking ``distance: 10`` is a fraction of what you meant on a small element and renders as nothing at all. The offset lands at ``distance × 0.0005 × the element's shorter side``; the reference scenes author 60–70 for both. For pixel-unit shadows use ``shadow_x``/``shadow_y`` on video and image elements. The layout lint reports a distance that renders under a pixel as ``SHADOW_BELOW_MIN_SIZE``.
          - `color` string, required
          - `distance` number: Shadow offset **strength**, 0–100 on the renderer's own scale — **not pixels**. The rendered offset is `distance × 0.0005 × the element's shorter side`, so on a 400px-tall card `60` drops the shadow 12px while a px-looking `8` drops it 1.6px, and on a 200px chip that same `8` is 0.8px — invisible. Author 60–70 (what the reference scenes use) and it scales with the element; for a specific N px offset use `distance = N ÷ (0.0005 × shorter_side_px)`. Must be > 0: distance 0 is skipped by the renderer entirely. For pixel-unit shadows use `shadow_x`/`shadow_y` on video/image elements.
          - `direction` number: Shadow direction in degrees (polar; 90 = down).
          - `blur` number: Shadow softness, 0–100 on the renderer's blur-strength scale — **not** a pixel radius, and unlike `distance` it does not scale with the element. `0` is a hard-edged offset copy (a legitimate poster look); 60–70 is the soft card shadow the reference scenes author. A px-looking `8` is a near-hard edge, not an 8px feather.
        - `path_keyframes` PathKeyframe[], nullable: Morph the path between keyframes (timeline seconds).
          - `time` number, required: Timeline seconds for this path.
          - `d` string, required: SVG path `d` at this time.
          - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
          - `spring` SpringEasing: Damped-spring ease over the keyframe segment. Only the damping ratio zeta = damping / (2 * sqrt(stiffness * mass)) shapes the curve; the segment's duration sets its timing. Below 1 the spring overshoots and rings (the defaults give zeta = 0.5); at 1 or above it settles without overshoot. An underdamped spring runs until its envelope decays to 0.1% (settle x w0 = ln(1000) / zeta, w0 = sqrt(stiffness / mass)). Since render-node's overdamped settle fix (GVR M3), a spring at zeta >= 1 runs over its slowest decay rate instead; before it, an overdamped spring's window was cut short and it reached the target still moving.
            - `stiffness` number: Stiffness; higher lowers zeta, so the spring rings more.
            - `damping` number: Damping; higher raises zeta (less overshoot), lower rings longer.
            - `mass` number: Mass; like stiffness, higher lowers zeta, so the spring rings more. It does not swing slower: the segment's duration sets the timing.
          - `back` BackEasing: Anticipate/overshoot ease (AE 'back').
            - `overshoot` number: Overshoot amount; AE default 1.70158.
            - `dir` 'in' | 'out': 'in' anticipates, 'out' overshoots.
          - `elastic` ElasticEasing: Elastic ring-out/ring-in ease.
            - `amplitude` number: Ring amplitude.
            - `period` number: Ring period as a fraction of the segment.
            - `dir` 'in' | 'out': 'in' rings before, 'out' after.
          - `bezier` BezierEasing: CSS cubic-bezier(x1, y1, x2, y2) timing curve.
            - `x1` number
            - `y1` number
            - `x2` number
            - `y2` number
        - `trim` TrimPath
          - `start` number: Trim start, 0–1 along the path.
          - `end` number: Trim end, 0–1 along the path.
        - `trim_keyframes` TrimKeyframe[], nullable: Animate the trim window (timeline seconds) — the draw-on: animate `end` 0→1 on a stroked path to draw a signature, underline or chart line. Absent `start`/`end` inherit the static `trim`.
          - `time` number, required: Timeline seconds.
          - `start` number, nullable
          - `end` number, nullable
          - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
          - `spring` SpringEasing: Damped-spring ease over the keyframe segment. Only the damping ratio zeta = damping / (2 * sqrt(stiffness * mass)) shapes the curve; the segment's duration sets its timing. Below 1 the spring overshoots and rings (the defaults give zeta = 0.5); at 1 or above it settles without overshoot. An underdamped spring runs until its envelope decays to 0.1% (settle x w0 = ln(1000) / zeta, w0 = sqrt(stiffness / mass)). Since render-node's overdamped settle fix (GVR M3), a spring at zeta >= 1 runs over its slowest decay rate instead; before it, an overdamped spring's window was cut short and it reached the target still moving.
            - `stiffness` number: Stiffness; higher lowers zeta, so the spring rings more.
            - `damping` number: Damping; higher raises zeta (less overshoot), lower rings longer.
            - `mass` number: Mass; like stiffness, higher lowers zeta, so the spring rings more. It does not swing slower: the segment's duration sets the timing.
          - `back` BackEasing: Anticipate/overshoot ease (AE 'back').
            - `overshoot` number: Overshoot amount; AE default 1.70158.
            - `dir` 'in' | 'out': 'in' anticipates, 'out' overshoots.
          - `elastic` ElasticEasing: Elastic ring-out/ring-in ease.
            - `amplitude` number: Ring amplitude.
            - `period` number: Ring period as a fraction of the segment.
            - `dir` 'in' | 'out': 'in' rings before, 'out' after.
          - `bezier` BezierEasing: CSS cubic-bezier(x1, y1, x2, y2) timing curve.
            - `x1` number
            - `y1` number
            - `x2` number
            - `y2` number
        - `effects` Effect[]: Shader effect chain (§6 W3).
          - `type` 'vintage' | 'polaroid' | 'portra' | 'super8' | 'filmic' | 'add_grain' | 'rgb_split' | 'ghosting' | 'displacement_map' | 'posterize' | 'mosaic' | 'mosaic_blur' | 'mosaic_posterize' | 'cc_halftone' | 'cc_halftone_blue' | 'cc_halftone_green' | 'cc_halftone_red' | 'invert' | 'optics_compensation' | 'viewfinder' | 'night_vision' | 'thermal' | 'camera_lens_blur' | 'camera_lens_blur_bg' | 'box_blur' | 'lens_flare' | 'strobe_light' | 'snow' | 'glow' | 'sepia' | 'echo' | 'chromatic_aberration' | 'vhs' | 'vhs_overlay' | 'crt' | 'television' | 'glitch' | 'compression_glitch' | 'scanlines' | 'prism' | 'light_leaks' | 'film_burn' | 'duotone' | 'cross_process' | 'bleach_bypass' | 'chroma_key' | 'aurora': Values: - `vintage` — Faded, warm retro film look with lifted blacks. - `polaroid` — Instant-photo look — soft contrast, warm cast, subtle vignette. - `portra` — Kodak Portra-style film emulation with natural skin tones. - `super8` — Super-8 home-movie look — grain, gate weave, warm color. - `filmic` — Cinematic film grade with rolled-off highlights and rich contrast. - `add_grain` — Adds dusty analog film grain over the image. - `rgb_split` — Offsets the red/green/blue channels for a glitchy chromatic split. - `ghosting` — Trailing motion echoes, like persistence-of-vision smearing. - `displacement_map` — Warps the image with a displacement texture for a melted look. - `posterize` — Reduces the image to a small number of flat color bands. - `mosaic` — Pixelates the image into large mosaic blocks. - `mosaic_blur` — Pixelated mosaic with softened, blurred block edges. - `mosaic_posterize` — Combines mosaic pixelation with posterized colors. - `cc_halftone` — Comic-style halftone dot pattern. - `cc_halftone_blue` — Halftone dot pattern tinted blue. - `cc_halftone_green` — Halftone dot pattern tinted green. - `cc_halftone_red` — Halftone dot pattern tinted red. - `invert` — Inverts all colors (photo-negative). - `optics_compensation` — Fish-eye / lens-distortion warp. - `viewfinder` — Camera viewfinder overlay (REC indicator, framing marks). - `night_vision` — Green night-vision look with glow and noise. - `thermal` — Thermal-camera false-color heat map. - `camera_lens_blur` — Realistic bokeh lens blur across the frame. - `camera_lens_blur_bg` — Bokeh lens blur applied to the background only. - `box_blur` — Fast, uniform box blur. - `lens_flare` — Adds an anamorphic lens-flare streak and glints. - `strobe_light` — Rapid brightness strobing / flashing. - `snow` — Falling-snow particle overlay. - `glow` — Dreamy soft-glow bloom over highlights. - `sepia` — Sepia-toned monochrome with a vignette. - `echo` — Soft ghosted dream-echo overlay. - `chromatic_aberration` — Color-fringing at edges, like cheap-lens dispersion. - `vhs` — VHS tape look: tracking noise, color bleed, and wobble. - `vhs_overlay` — VHS noise/scanline layer composited over the source. - `crt` — CRT monitor look: screen curvature, scanlines, and phosphor glow. - `television` — Analog TV look: scanlines, static, and signal distortion. - `glitch` — Digital glitch: block displacement and channel tearing. - `compression_glitch` — MPEG compression artifacts: blocky macroblocks and datamosh. - `scanlines` — Horizontal scanlines overlaid on the image. - `prism` — Prismatic light refraction with a rainbow color split. - `light_leaks` — Warm light-leak streaks bleeding across the frame. - `film_burn` — Burning-film look with scorched edges and flares. - `duotone` — Two-tone color map (shadows to one hue, highlights to another). - `cross_process` — Cross-processed film look with shifted, punchy colors. - `bleach_bypass` — High-contrast, desaturated bleach-bypass film grade. - `chroma_key` — Keys out a color (green/blue screen); tune via `chroma_settings`. - `aurora` — Animated domain-warped fluid-gradient wash (§6); tune flow via `props` speed.
          - `intensity` number, nullable: Effect strength, 0 to 100. On a shader effect it is null unless set: the shader then runs at the engine's own full intensity rather than the effect-wide 50.
          - `intensity_keyframes` IntensityKeyframe[], nullable: Animate intensity over time (§2): piecewise-linear `[{time, value}]` in timeline seconds. Overrides the static `intensity` when set.
            - `time` number, required: Absolute timeline seconds.
            - `value` number, required: Effect intensity 0–1 at this time.
          - `props` object, nullable: Per-shader scalar props (§2), bound as `u_prop_<key>` (e.g. `{"speed": 0.6}` for aurora). Ignored for chroma_key (use `chroma_settings`).
          - `chroma_settings` ChromaKeyProps: Used when ``EffectType.CHROMA_KEY`` is selected. Keys against an explicit key **colour** in the YCbCr chroma plane, which is luma-independent, so shadows falling on the screen key out along with it. This replaced an hue/saturation/luminance-window shape that could not work. It was wired to ``effect_chroma.frag``, whose ``sensitivity`` is ``(hueMax - hueMin) * 0.5`` compared against an Oklab distance bounded around 0..0.9 — so the old defaults (60/180) produced a sensitivity of 60, discarded every pixel, and made the element vanish from the render. Nothing could have depended on the previous shape, because nothing rendered with it.
            - `key_color` string: The colour to key out. Green-screen green by default.
            - `threshold` number: Chroma distance from `key_color` below which a pixel is fully transparent. Raise it if fringes of the screen survive.
            - `smoothness` number: Width of the ramp from transparent to opaque, starting at `threshold`. Raise it to soften hard edges; 0 gives a hard cut.
            - `spill_suppress` number: How strongly surviving pixels near the key colour are pulled toward their own luma, removing green spill on hair and edges. 0 disables.
          - `shader` EffectShader: A runtime shader (render-node AEC §2) by its stored id. `POST /v1/shaders` compiles one from SkSL source; the render carries its compiled variants, so it renders on the farm and in the preview alike.
            - `id` string, required: The shader's id (`sh_...`): one of this workspace's or a shared one (GET /v1/shaders).
            - `params` object: Values of the shader's declared params by name: a number (`float`), "#RRGGBBAA" (`color`) or [x, y] (`vec2`), or keyframes `[{time, value}]` in timeline seconds. A param left out takes its declared default.
        - `motion` Motion[]
          - `type` 'identity' | 'fade' | 'slide_up' | 'slide_down' | 'slide_left' | 'slide_right' | 'zoom_in' | 'zoom_out' | 'rotate_cw' | 'rotate_ccw' | 'bounce' | 'wipe_left' | 'wipe_right' | 'wipe_up' | 'wipe_down' | 'ken_burns_in' | 'ken_burns_out' | 'ken_burns_in_out' | 'loop_wiggle' | 'loop_rotate' | 'loop_rotate_smooth' | 'loop_3d_spin' | 'loop_3d_sway' | 'blur' | 'evaporate' | 'overlay' | 'difference' | 'rubber_in' | 'whip_up' | 'whip_down' | 'glitch_pop' | 'drift_in' | 'drift_out' | 'loop_breathe' | 'loop_shimmer' | 'swing_in' | 'swing_out' | 'elastic_rise' | 'elastic_drop' | 'tilt_zoom' | 'loop_orbit' | 'smooth_pop': Values: - `identity` — Deliberate no-op carrier (no visible motion): attach a pure `audio` generator to any element without animating it. Element surfaces only. - `fade` — Fade in (entrance) or out (exit) via opacity. - `slide_up` — Slide in from below / out upward. - `slide_down` — Slide in from above / out downward. - `slide_left` — Slide in from the right / out to the left. - `slide_right` — Slide in from the left / out to the right. - `zoom_in` — Scale up from small to full size (entrance). - `zoom_out` — Scale down to small (exit). - `rotate_cw` — Spin in/out clockwise. - `rotate_ccw` — Spin in/out counter-clockwise. - `bounce` — Bounce in with an elastic overshoot / bounce out. - `wipe_left` — Reveal/conceal with a left-moving wipe. - `wipe_right` — Reveal/conceal with a right-moving wipe. - `wipe_up` — Reveal/conceal with an upward wipe. - `wipe_down` — Reveal/conceal with a downward wipe. - `ken_burns_in` — Slow zoom-in pan (Ken Burns) — entrance only. - `ken_burns_out` — Slow zoom-out pan (Ken Burns) — entrance only. - `ken_burns_in_out` — Slow zoom in then out (Ken Burns) — entrance only. - `loop_wiggle` — Continuous subtle wiggle (looping). - `loop_rotate` — Continuous stepped rotation (looping). - `loop_rotate_smooth` — Continuous smooth rotation (looping). - `loop_3d_spin` — Continuous 3D spin (looping). - `loop_3d_sway` — Continuous 3D sway (looping). - `blur` — Per-glyph soft blur-in (text entrance). - `evaporate` — Per-glyph rise, blur, and fade-out (text exit only). - `overlay` — Static Overlay blend fill (timing ignored). - `difference` — Static Difference blend fill (timing ignored). - `rubber_in` — Per-glyph rubbery overshoot as text springs in (text entrance). - `whip_up` — Per-glyph whip upward into place (text entrance). - `whip_down` — Per-glyph whip downward out of frame (text exit only). - `glitch_pop` — Per-glyph glitchy pop-in with jitter (text entrance). - `drift_in` — Per-glyph gentle drift and fade in (text entrance). - `drift_out` — Per-glyph gentle drift and fade out (text exit only). - `loop_breathe` — Per-glyph continuous breathing scale loop (text). - `loop_shimmer` — Per-glyph continuous shimmer loop (text). - `swing_in` — Element swings into place from an angle (entrance). - `swing_out` — Element swings away out of frame (exit only). - `elastic_rise` — Element rises with an elastic overshoot (entrance). - `elastic_drop` — Element drops away with an elastic recoil (exit only). - `tilt_zoom` — Element tilts and zooms into place (entrance). - `loop_orbit` — Element orbits continuously around its center (loop). - `smooth_pop` — Element pops in from 60% scale, overshooting slightly past full size before it settles, as it fades in (entrance).
          - `preset` string, nullable: Renderer animation name, used verbatim — any element animation on video/image/shape/group (e.g. `'pop'`, `'floatUp'`, `'out-slideBounceLeft'`, `'loop-heartBeat'`), any text animation on text (e.g. `'typewriter'`, `'roll'`, `'out-sink'`, `'loop-wavey'`). Reaches the presets `type` has no name for. The name carries its own direction: `out-*` names are exits, `loop-*` names loop with `duration` as one cycle, so `reversed` and `scope` do not apply. Exactly one of `type`, `preset` or `custom` must be set.
          - `custom` string, nullable: Name of a `custom_animations` entry to run instead of a catalog preset — the `element` registry for video/image/shape/group animations, the `text` registry for text. Exactly one of `type`, `preset` or `custom` must be set.
          - `time` number, required: Absolute start time on the output timeline in seconds. For entrances and loops set this to the element's `time`. For exits set this to element `time + duration − motion duration`. An entrance timed later than the element's own `time` leaves it fully rendered on screen until the entrance fires; the linter reports that as `ENTRANCE_AFTER_ELEMENT_START`.
          - `duration` number, required: How long the animation runs in seconds.
          - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
          - `reversed` boolean: Run the preset's exit form instead of its entrance. Only presets that ship both forms accept it — `fade`, `slide_*`, `wipe_*`, `rotate_*`, `bounce`. Entrance-only presets have a separate exit-only type instead: use `zoom_out` (not `zoom_in` reversed), `evaporate` (not `blur`), `whip_down`, `drift_out`, `swing_out`, `elastic_drop` — those six set this flag for you. See `GET /v1/capabilities` `motion[].element_exit` for the per-preset truth.
          - `scope` 'element' | 'character': Whether a motion preset applies to the whole element or per-glyph (text only). Values: - `element` — The motion animates the whole element as one unit. - `character` — The motion animates each text glyph individually (text only).
          - `delay` number: Seconds to wait before the animation starts (folded into the animation's start time on the wire — the engine has no standalone pre-start delay). On loop presets it spaces the repeats instead.
          - `spacing` number, nullable: Stagger multiplier between per-glyph/word windows on text animations (engine default 1 = fully sequential; smaller values overlap the windows). Ignored by block animations.
          - `loop` boolean
          - `audio` AudioGenerator: Audio-reactive property offsets driven by the soundtrack FFT (§3, W2). Each frame the mix reduces to the chosen feature and the element's properties get offset by ``amount × feature`` — beat-bounce, bass-pumped scale, etc.
            - `feature` 'amplitude' | 'bass' | 'mid' | 'high' | 'beat'
            - `scale` number: Scale offset per unit feature.
            - `opacity` number: Opacity offset per unit feature.
            - `translate` Point
              - …
            - `rotate` number: Rotation offset (degrees) per unit feature.
      - FrameElement: A frame (render-node AEC §5): elements nested in its box, with its own clip, mask, matte, blend, effects and, as a composite, its own clock. Its children use design px from its top-left corner, frames and instances included.
        - `x` number, nullable: Left edge in design px from its parent's left edge (at the root, the `design_size` box's, else the output's). Omitted: 0.
        - `y` number, nullable: Top edge in design px from its parent's top edge. Omitted: 0.
        - `x_anchor` union: Pivot it turns and scales about, across its own box: a percent, or design px from its left edge. Omitted: the centre.
          - integer
          - number
          - string
        - `y_anchor` union: Pivot across its own box's height: a percent, or design px from its top edge. Omitted: the centre.
          - integer
          - number
          - string
        - `z_rotation` union: Rotation in degrees. Omitted: 0.
          - integer
          - number
          - string
        - `x_rotation` union: Perspective tilt (X axis) each element inside takes about its own centre, as a group's does. Omitted: 0.
          - integer
          - number
          - string
        - `y_rotation` union: Perspective tilt (Y axis); see `x_rotation`. Omitted: 0.
          - integer
          - number
          - string
        - `scale` number, nullable: Uniform scale about the anchor. Omitted: 1.
        - `opacity` number, nullable: Opacity 0 to 100 of everything inside. Omitted: 100.
        - `z_index` integer, nullable: Stacking order among its siblings (higher on top); ties draw in array order. Everything inside draws together at its place.
        - `duration` number, nullable: Seconds active. Omitted: until its parent ends.
        - `motion` Motion[]: Animations of the whole, about its anchor.
          - `type` 'identity' | 'fade' | 'slide_up' | 'slide_down' | 'slide_left' | 'slide_right' | 'zoom_in' | 'zoom_out' | 'rotate_cw' | 'rotate_ccw' | 'bounce' | 'wipe_left' | 'wipe_right' | 'wipe_up' | 'wipe_down' | 'ken_burns_in' | 'ken_burns_out' | 'ken_burns_in_out' | 'loop_wiggle' | 'loop_rotate' | 'loop_rotate_smooth' | 'loop_3d_spin' | 'loop_3d_sway' | 'blur' | 'evaporate' | 'overlay' | 'difference' | 'rubber_in' | 'whip_up' | 'whip_down' | 'glitch_pop' | 'drift_in' | 'drift_out' | 'loop_breathe' | 'loop_shimmer' | 'swing_in' | 'swing_out' | 'elastic_rise' | 'elastic_drop' | 'tilt_zoom' | 'loop_orbit' | 'smooth_pop': Values: - `identity` — Deliberate no-op carrier (no visible motion): attach a pure `audio` generator to any element without animating it. Element surfaces only. - `fade` — Fade in (entrance) or out (exit) via opacity. - `slide_up` — Slide in from below / out upward. - `slide_down` — Slide in from above / out downward. - `slide_left` — Slide in from the right / out to the left. - `slide_right` — Slide in from the left / out to the right. - `zoom_in` — Scale up from small to full size (entrance). - `zoom_out` — Scale down to small (exit). - `rotate_cw` — Spin in/out clockwise. - `rotate_ccw` — Spin in/out counter-clockwise. - `bounce` — Bounce in with an elastic overshoot / bounce out. - `wipe_left` — Reveal/conceal with a left-moving wipe. - `wipe_right` — Reveal/conceal with a right-moving wipe. - `wipe_up` — Reveal/conceal with an upward wipe. - `wipe_down` — Reveal/conceal with a downward wipe. - `ken_burns_in` — Slow zoom-in pan (Ken Burns) — entrance only. - `ken_burns_out` — Slow zoom-out pan (Ken Burns) — entrance only. - `ken_burns_in_out` — Slow zoom in then out (Ken Burns) — entrance only. - `loop_wiggle` — Continuous subtle wiggle (looping). - `loop_rotate` — Continuous stepped rotation (looping). - `loop_rotate_smooth` — Continuous smooth rotation (looping). - `loop_3d_spin` — Continuous 3D spin (looping). - `loop_3d_sway` — Continuous 3D sway (looping). - `blur` — Per-glyph soft blur-in (text entrance). - `evaporate` — Per-glyph rise, blur, and fade-out (text exit only). - `overlay` — Static Overlay blend fill (timing ignored). - `difference` — Static Difference blend fill (timing ignored). - `rubber_in` — Per-glyph rubbery overshoot as text springs in (text entrance). - `whip_up` — Per-glyph whip upward into place (text entrance). - `whip_down` — Per-glyph whip downward out of frame (text exit only). - `glitch_pop` — Per-glyph glitchy pop-in with jitter (text entrance). - `drift_in` — Per-glyph gentle drift and fade in (text entrance). - `drift_out` — Per-glyph gentle drift and fade out (text exit only). - `loop_breathe` — Per-glyph continuous breathing scale loop (text). - `loop_shimmer` — Per-glyph continuous shimmer loop (text). - `swing_in` — Element swings into place from an angle (entrance). - `swing_out` — Element swings away out of frame (exit only). - `elastic_rise` — Element rises with an elastic overshoot (entrance). - `elastic_drop` — Element drops away with an elastic recoil (exit only). - `tilt_zoom` — Element tilts and zooms into place (entrance). - `loop_orbit` — Element orbits continuously around its center (loop). - `smooth_pop` — Element pops in from 60% scale, overshooting slightly past full size before it settles, as it fades in (entrance).
          - `preset` string, nullable: Renderer animation name, used verbatim — any element animation on video/image/shape/group (e.g. `'pop'`, `'floatUp'`, `'out-slideBounceLeft'`, `'loop-heartBeat'`), any text animation on text (e.g. `'typewriter'`, `'roll'`, `'out-sink'`, `'loop-wavey'`). Reaches the presets `type` has no name for. The name carries its own direction: `out-*` names are exits, `loop-*` names loop with `duration` as one cycle, so `reversed` and `scope` do not apply. Exactly one of `type`, `preset` or `custom` must be set.
          - `custom` string, nullable: Name of a `custom_animations` entry to run instead of a catalog preset — the `element` registry for video/image/shape/group animations, the `text` registry for text. Exactly one of `type`, `preset` or `custom` must be set.
          - `time` number, required: Absolute start time on the output timeline in seconds. For entrances and loops set this to the element's `time`. For exits set this to element `time + duration − motion duration`. An entrance timed later than the element's own `time` leaves it fully rendered on screen until the entrance fires; the linter reports that as `ENTRANCE_AFTER_ELEMENT_START`.
          - `duration` number, required: How long the animation runs in seconds.
          - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
          - `reversed` boolean: Run the preset's exit form instead of its entrance. Only presets that ship both forms accept it — `fade`, `slide_*`, `wipe_*`, `rotate_*`, `bounce`. Entrance-only presets have a separate exit-only type instead: use `zoom_out` (not `zoom_in` reversed), `evaporate` (not `blur`), `whip_down`, `drift_out`, `swing_out`, `elastic_drop` — those six set this flag for you. See `GET /v1/capabilities` `motion[].element_exit` for the per-preset truth.
          - `scope` 'element' | 'character': Whether a motion preset applies to the whole element or per-glyph (text only). Values: - `element` — The motion animates the whole element as one unit. - `character` — The motion animates each text glyph individually (text only).
          - `delay` number: Seconds to wait before the animation starts (folded into the animation's start time on the wire — the engine has no standalone pre-start delay). On loop presets it spaces the repeats instead.
          - `spacing` number, nullable: Stagger multiplier between per-glyph/word windows on text animations (engine default 1 = fully sequential; smaller values overlap the windows). Ignored by block animations.
          - `loop` boolean
          - `audio` AudioGenerator: Audio-reactive property offsets driven by the soundtrack FFT (§3, W2). Each frame the mix reduces to the chosen feature and the element's properties get offset by ``amount × feature`` — beat-bounce, bass-pumped scale, etc.
            - `feature` 'amplitude' | 'bass' | 'mid' | 'high' | 'beat'
            - `scale` number: Scale offset per unit feature.
            - `opacity` number: Opacity offset per unit feature.
            - `translate` Point
              - …
            - `rotate` number: Rotation offset (degrees) per unit feature.
        - `clip` boolean, nullable: Crop what is inside to its box.
        - `corner_radius` union: Corner radius of the clip in design px: a number, `[top_left, top_right, bottom_right, bottom_left]` or `{top_left, ...}`. Applies with `clip`.
          - number
          - number[]
          - GeometryCornerRadii: Per-corner radii in px; a corner left out is 0.
            - `top_left` number, nullable
            - `top_right` number, nullable
            - `bottom_right` number, nullable
            - `bottom_left` number, nullable
        - `blend_mode` 'none' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color_dodge' | 'color_burn' | 'hard_light' | 'soft_light' | 'difference' | 'add' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity': Values: - `none` — Normal compositing (source-over) — the default. - `multiply` — Multiply blend — darkens by multiplying layer colors. - `screen` — Screen blend — lightens by inverting, multiplying, inverting. - `overlay` — Overlay blend — multiply in shadows, screen in highlights. - `darken` — Darken blend — keeps the darker of the two layers per channel. - `lighten` — Lighten blend — keeps the lighter of the two layers per channel. - `color_dodge` — Color-dodge blend — brightens the base toward the blend color. - `color_burn` — Color-burn blend — darkens the base toward the blend color. - `hard_light` — Hard-light blend — overlay with layers swapped. - `soft_light` — Soft-light blend — a gentler hard-light. - `difference` — Difference blend — absolute difference of the two layers per channel. - `add` — Additive (linear-dodge) blend — sums layer colors, clamped. - `exclusion` — Exclusion blend — like difference, lower contrast. - `hue` — Hue blend — backdrop luminosity + saturation with the blend layer's hue. - `saturation` — Saturation blend — backdrop hue + luminosity with the blend layer's saturation. - `color` — Color blend — backdrop luminosity with the blend layer's hue + saturation. - `luminosity` — Luminosity blend — backdrop hue + saturation with the blend layer's luminosity.
        - `mask_shape` 'circle' | 'diamond' | 'hexagon' | 'star' | 'heart' | 'triangle': Analytic (SDF) shape mask that clips an element's coverage. §1. Values: - `circle` — Circular (ellipse) analytic mask, fit to the element bounds. - `diamond` — Diamond (rotated square) analytic mask. - `hexagon` — Regular hexagon analytic mask. - `star` — Five-point star analytic mask. - `heart` — Heart analytic mask. - `triangle` — Upward triangle analytic mask.
        - `mask` MaskConfig: Animated/feathered mask params layered on the analytic `mask_shape` (§5c).
          - `feather` number: Soften the mask's SDF edge.
          - `scale` number: Mask scale (iris reveals).
          - `center` Point
            - `x` number
            - `y` number
        - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
          - `source` string, required: uuid of the source layer (auto-hidden). Text sources supported.
          - `mode` 'alpha' | 'luma'
          - `invert` boolean
        - `effects` Effect[]: Shader effects run over its content.
          - `type` 'vintage' | 'polaroid' | 'portra' | 'super8' | 'filmic' | 'add_grain' | 'rgb_split' | 'ghosting' | 'displacement_map' | 'posterize' | 'mosaic' | 'mosaic_blur' | 'mosaic_posterize' | 'cc_halftone' | 'cc_halftone_blue' | 'cc_halftone_green' | 'cc_halftone_red' | 'invert' | 'optics_compensation' | 'viewfinder' | 'night_vision' | 'thermal' | 'camera_lens_blur' | 'camera_lens_blur_bg' | 'box_blur' | 'lens_flare' | 'strobe_light' | 'snow' | 'glow' | 'sepia' | 'echo' | 'chromatic_aberration' | 'vhs' | 'vhs_overlay' | 'crt' | 'television' | 'glitch' | 'compression_glitch' | 'scanlines' | 'prism' | 'light_leaks' | 'film_burn' | 'duotone' | 'cross_process' | 'bleach_bypass' | 'chroma_key' | 'aurora': Values: - `vintage` — Faded, warm retro film look with lifted blacks. - `polaroid` — Instant-photo look — soft contrast, warm cast, subtle vignette. - `portra` — Kodak Portra-style film emulation with natural skin tones. - `super8` — Super-8 home-movie look — grain, gate weave, warm color. - `filmic` — Cinematic film grade with rolled-off highlights and rich contrast. - `add_grain` — Adds dusty analog film grain over the image. - `rgb_split` — Offsets the red/green/blue channels for a glitchy chromatic split. - `ghosting` — Trailing motion echoes, like persistence-of-vision smearing. - `displacement_map` — Warps the image with a displacement texture for a melted look. - `posterize` — Reduces the image to a small number of flat color bands. - `mosaic` — Pixelates the image into large mosaic blocks. - `mosaic_blur` — Pixelated mosaic with softened, blurred block edges. - `mosaic_posterize` — Combines mosaic pixelation with posterized colors. - `cc_halftone` — Comic-style halftone dot pattern. - `cc_halftone_blue` — Halftone dot pattern tinted blue. - `cc_halftone_green` — Halftone dot pattern tinted green. - `cc_halftone_red` — Halftone dot pattern tinted red. - `invert` — Inverts all colors (photo-negative). - `optics_compensation` — Fish-eye / lens-distortion warp. - `viewfinder` — Camera viewfinder overlay (REC indicator, framing marks). - `night_vision` — Green night-vision look with glow and noise. - `thermal` — Thermal-camera false-color heat map. - `camera_lens_blur` — Realistic bokeh lens blur across the frame. - `camera_lens_blur_bg` — Bokeh lens blur applied to the background only. - `box_blur` — Fast, uniform box blur. - `lens_flare` — Adds an anamorphic lens-flare streak and glints. - `strobe_light` — Rapid brightness strobing / flashing. - `snow` — Falling-snow particle overlay. - `glow` — Dreamy soft-glow bloom over highlights. - `sepia` — Sepia-toned monochrome with a vignette. - `echo` — Soft ghosted dream-echo overlay. - `chromatic_aberration` — Color-fringing at edges, like cheap-lens dispersion. - `vhs` — VHS tape look: tracking noise, color bleed, and wobble. - `vhs_overlay` — VHS noise/scanline layer composited over the source. - `crt` — CRT monitor look: screen curvature, scanlines, and phosphor glow. - `television` — Analog TV look: scanlines, static, and signal distortion. - `glitch` — Digital glitch: block displacement and channel tearing. - `compression_glitch` — MPEG compression artifacts: blocky macroblocks and datamosh. - `scanlines` — Horizontal scanlines overlaid on the image. - `prism` — Prismatic light refraction with a rainbow color split. - `light_leaks` — Warm light-leak streaks bleeding across the frame. - `film_burn` — Burning-film look with scorched edges and flares. - `duotone` — Two-tone color map (shadows to one hue, highlights to another). - `cross_process` — Cross-processed film look with shifted, punchy colors. - `bleach_bypass` — High-contrast, desaturated bleach-bypass film grade. - `chroma_key` — Keys out a color (green/blue screen); tune via `chroma_settings`. - `aurora` — Animated domain-warped fluid-gradient wash (§6); tune flow via `props` speed.
          - `intensity` number, nullable: Effect strength, 0 to 100. On a shader effect it is null unless set: the shader then runs at the engine's own full intensity rather than the effect-wide 50.
          - `intensity_keyframes` IntensityKeyframe[], nullable: Animate intensity over time (§2): piecewise-linear `[{time, value}]` in timeline seconds. Overrides the static `intensity` when set.
            - `time` number, required: Absolute timeline seconds.
            - `value` number, required: Effect intensity 0–1 at this time.
          - `props` object, nullable: Per-shader scalar props (§2), bound as `u_prop_<key>` (e.g. `{"speed": 0.6}` for aurora). Ignored for chroma_key (use `chroma_settings`).
          - `chroma_settings` ChromaKeyProps: Used when ``EffectType.CHROMA_KEY`` is selected. Keys against an explicit key **colour** in the YCbCr chroma plane, which is luma-independent, so shadows falling on the screen key out along with it. This replaced an hue/saturation/luminance-window shape that could not work. It was wired to ``effect_chroma.frag``, whose ``sensitivity`` is ``(hueMax - hueMin) * 0.5`` compared against an Oklab distance bounded around 0..0.9 — so the old defaults (60/180) produced a sensitivity of 60, discarded every pixel, and made the element vanish from the render. Nothing could have depended on the previous shape, because nothing rendered with it.
            - `key_color` string: The colour to key out. Green-screen green by default.
            - `threshold` number: Chroma distance from `key_color` below which a pixel is fully transparent. Raise it if fringes of the screen survive.
            - `smoothness` number: Width of the ramp from transparent to opaque, starting at `threshold`. Raise it to soften hard edges; 0 gives a hard cut.
            - `spill_suppress` number: How strongly surviving pixels near the key colour are pulled toward their own luma, removing green spill on hair and edges. 0 disables.
          - `shader` EffectShader: A runtime shader (render-node AEC §2) by its stored id. `POST /v1/shaders` compiles one from SkSL source; the render carries its compiled variants, so it renders on the farm and in the preview alike.
            - `id` string, required: The shader's id (`sh_...`): one of this workspace's or a shared one (GET /v1/shaders).
            - `params` object: Values of the shader's declared params by name: a number (`float`), "#RRGGBBAA" (`color`) or [x, y] (`vec2`), or keyframes `[{time, value}]` in timeline seconds. A param left out takes its declared default.
        - `render` 'flatten' | 'composite', nullable: `composite` makes it a nested composition whose content runs on `time_map`'s clock; its content is graphics only (no video). Omitted: `flatten`.
        - `time_map` TimeMap: A composite frame's clock (AEC §5): the time its children read.
          - `offset` number, nullable: Seconds into the children's timeline at the frame's start. Omitted: 0.
          - `speed` number, nullable: Rate of the children's timeline: 0 holds, below 0 plays backwards. Omitted: 1.
          - `loop` number, nullable: Seconds after which the children's timeline repeats. Omitted: no loop.
          - `freeze` number, nullable: Hold the children at this many seconds into their timeline; overrides `offset` and `speed`.
        - `type` 'frame'
        - `id` string, required: **Required.** Unique in the request; operations, mattes and anchors name it.
        - `name` string, nullable: Optional human-readable label. Not used by the renderer.
        - `track` integer, nullable: Timeline track index (0–255). Informational only; not used by the renderer.
        - `time` number, nullable: Start in seconds on its parent's clock (the composition's at the root). Omitted: its parent's start.
        - `visible` boolean: Set to `false` to skip this element without removing it from the request.
        - `locked` boolean: Marks the element locked in editors. Not sent to the renderer.
        - `width` number, nullable: Width in design px. Omitted: its parent's width.
        - `height` number, nullable: Height in design px. Omitted: its parent's height.
        - `slot` string, nullable: In a component body: the slot name an instance's `slots` fill in place of this frame's own children.
        - `children` union[]: The elements inside, in design px from this frame's top-left corner; frames and instances nest. Audio stays at the root.
          - union
            - ChildVideoElement: A video inside a frame. Not inside a composite frame, whose content is graphics only.
              - …
            - ChildTextElement: A text inside a frame; `width` is its wrap width.
              - …
            - ChildImageElement: An image inside a frame.
              - …
            - ChildShapeElement: A shape inside a frame.
              - …
            - FrameElement (recursive)
            - InstanceElement: An instance (render-node AEC §5g): a placed copy of a `components` definition. Its box is the component's (or its variant's); it sets the component's properties, fills its slots, and places, times and composites itself as a frame does.
              - …
      - InstanceElement: An instance (render-node AEC §5g): a placed copy of a `components` definition. Its box is the component's (or its variant's); it sets the component's properties, fills its slots, and places, times and composites itself as a frame does.
        - `x` number, nullable: Left edge in design px from its parent's left edge (at the root, the `design_size` box's, else the output's). Omitted: 0.
        - `y` number, nullable: Top edge in design px from its parent's top edge. Omitted: 0.
        - `x_anchor` union: Pivot it turns and scales about, across its own box: a percent, or design px from its left edge. Omitted: the centre.
          - integer
          - number
          - string
        - `y_anchor` union: Pivot across its own box's height: a percent, or design px from its top edge. Omitted: the centre.
          - integer
          - number
          - string
        - `z_rotation` union: Rotation in degrees. Omitted: 0.
          - integer
          - number
          - string
        - `x_rotation` union: Perspective tilt (X axis) each element inside takes about its own centre, as a group's does. Omitted: 0.
          - integer
          - number
          - string
        - `y_rotation` union: Perspective tilt (Y axis); see `x_rotation`. Omitted: 0.
          - integer
          - number
          - string
        - `scale` number, nullable: Uniform scale about the anchor. Omitted: 1.
        - `opacity` number, nullable: Opacity 0 to 100 of everything inside. Omitted: 100.
        - `z_index` integer, nullable: Stacking order among its siblings (higher on top); ties draw in array order. Everything inside draws together at its place.
        - `duration` number, nullable: Seconds active. Omitted: until its parent ends.
        - `motion` Motion[]: Animations of the whole, about its anchor.
          - `type` 'identity' | 'fade' | 'slide_up' | 'slide_down' | 'slide_left' | 'slide_right' | 'zoom_in' | 'zoom_out' | 'rotate_cw' | 'rotate_ccw' | 'bounce' | 'wipe_left' | 'wipe_right' | 'wipe_up' | 'wipe_down' | 'ken_burns_in' | 'ken_burns_out' | 'ken_burns_in_out' | 'loop_wiggle' | 'loop_rotate' | 'loop_rotate_smooth' | 'loop_3d_spin' | 'loop_3d_sway' | 'blur' | 'evaporate' | 'overlay' | 'difference' | 'rubber_in' | 'whip_up' | 'whip_down' | 'glitch_pop' | 'drift_in' | 'drift_out' | 'loop_breathe' | 'loop_shimmer' | 'swing_in' | 'swing_out' | 'elastic_rise' | 'elastic_drop' | 'tilt_zoom' | 'loop_orbit' | 'smooth_pop': Values: - `identity` — Deliberate no-op carrier (no visible motion): attach a pure `audio` generator to any element without animating it. Element surfaces only. - `fade` — Fade in (entrance) or out (exit) via opacity. - `slide_up` — Slide in from below / out upward. - `slide_down` — Slide in from above / out downward. - `slide_left` — Slide in from the right / out to the left. - `slide_right` — Slide in from the left / out to the right. - `zoom_in` — Scale up from small to full size (entrance). - `zoom_out` — Scale down to small (exit). - `rotate_cw` — Spin in/out clockwise. - `rotate_ccw` — Spin in/out counter-clockwise. - `bounce` — Bounce in with an elastic overshoot / bounce out. - `wipe_left` — Reveal/conceal with a left-moving wipe. - `wipe_right` — Reveal/conceal with a right-moving wipe. - `wipe_up` — Reveal/conceal with an upward wipe. - `wipe_down` — Reveal/conceal with a downward wipe. - `ken_burns_in` — Slow zoom-in pan (Ken Burns) — entrance only. - `ken_burns_out` — Slow zoom-out pan (Ken Burns) — entrance only. - `ken_burns_in_out` — Slow zoom in then out (Ken Burns) — entrance only. - `loop_wiggle` — Continuous subtle wiggle (looping). - `loop_rotate` — Continuous stepped rotation (looping). - `loop_rotate_smooth` — Continuous smooth rotation (looping). - `loop_3d_spin` — Continuous 3D spin (looping). - `loop_3d_sway` — Continuous 3D sway (looping). - `blur` — Per-glyph soft blur-in (text entrance). - `evaporate` — Per-glyph rise, blur, and fade-out (text exit only). - `overlay` — Static Overlay blend fill (timing ignored). - `difference` — Static Difference blend fill (timing ignored). - `rubber_in` — Per-glyph rubbery overshoot as text springs in (text entrance). - `whip_up` — Per-glyph whip upward into place (text entrance). - `whip_down` — Per-glyph whip downward out of frame (text exit only). - `glitch_pop` — Per-glyph glitchy pop-in with jitter (text entrance). - `drift_in` — Per-glyph gentle drift and fade in (text entrance). - `drift_out` — Per-glyph gentle drift and fade out (text exit only). - `loop_breathe` — Per-glyph continuous breathing scale loop (text). - `loop_shimmer` — Per-glyph continuous shimmer loop (text). - `swing_in` — Element swings into place from an angle (entrance). - `swing_out` — Element swings away out of frame (exit only). - `elastic_rise` — Element rises with an elastic overshoot (entrance). - `elastic_drop` — Element drops away with an elastic recoil (exit only). - `tilt_zoom` — Element tilts and zooms into place (entrance). - `loop_orbit` — Element orbits continuously around its center (loop). - `smooth_pop` — Element pops in from 60% scale, overshooting slightly past full size before it settles, as it fades in (entrance).
          - `preset` string, nullable: Renderer animation name, used verbatim — any element animation on video/image/shape/group (e.g. `'pop'`, `'floatUp'`, `'out-slideBounceLeft'`, `'loop-heartBeat'`), any text animation on text (e.g. `'typewriter'`, `'roll'`, `'out-sink'`, `'loop-wavey'`). Reaches the presets `type` has no name for. The name carries its own direction: `out-*` names are exits, `loop-*` names loop with `duration` as one cycle, so `reversed` and `scope` do not apply. Exactly one of `type`, `preset` or `custom` must be set.
          - `custom` string, nullable: Name of a `custom_animations` entry to run instead of a catalog preset — the `element` registry for video/image/shape/group animations, the `text` registry for text. Exactly one of `type`, `preset` or `custom` must be set.
          - `time` number, required: Absolute start time on the output timeline in seconds. For entrances and loops set this to the element's `time`. For exits set this to element `time + duration − motion duration`. An entrance timed later than the element's own `time` leaves it fully rendered on screen until the entrance fires; the linter reports that as `ENTRANCE_AFTER_ELEMENT_START`.
          - `duration` number, required: How long the animation runs in seconds.
          - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
          - `reversed` boolean: Run the preset's exit form instead of its entrance. Only presets that ship both forms accept it — `fade`, `slide_*`, `wipe_*`, `rotate_*`, `bounce`. Entrance-only presets have a separate exit-only type instead: use `zoom_out` (not `zoom_in` reversed), `evaporate` (not `blur`), `whip_down`, `drift_out`, `swing_out`, `elastic_drop` — those six set this flag for you. See `GET /v1/capabilities` `motion[].element_exit` for the per-preset truth.
          - `scope` 'element' | 'character': Whether a motion preset applies to the whole element or per-glyph (text only). Values: - `element` — The motion animates the whole element as one unit. - `character` — The motion animates each text glyph individually (text only).
          - `delay` number: Seconds to wait before the animation starts (folded into the animation's start time on the wire — the engine has no standalone pre-start delay). On loop presets it spaces the repeats instead.
          - `spacing` number, nullable: Stagger multiplier between per-glyph/word windows on text animations (engine default 1 = fully sequential; smaller values overlap the windows). Ignored by block animations.
          - `loop` boolean
          - `audio` AudioGenerator: Audio-reactive property offsets driven by the soundtrack FFT (§3, W2). Each frame the mix reduces to the chosen feature and the element's properties get offset by ``amount × feature`` — beat-bounce, bass-pumped scale, etc.
            - `feature` 'amplitude' | 'bass' | 'mid' | 'high' | 'beat'
            - `scale` number: Scale offset per unit feature.
            - `opacity` number: Opacity offset per unit feature.
            - `translate` Point
              - …
            - `rotate` number: Rotation offset (degrees) per unit feature.
        - `clip` boolean, nullable: Crop what is inside to its box.
        - `corner_radius` union: Corner radius of the clip in design px: a number, `[top_left, top_right, bottom_right, bottom_left]` or `{top_left, ...}`. Applies with `clip`.
          - number
          - number[]
          - GeometryCornerRadii: Per-corner radii in px; a corner left out is 0.
            - `top_left` number, nullable
            - `top_right` number, nullable
            - `bottom_right` number, nullable
            - `bottom_left` number, nullable
        - `blend_mode` 'none' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color_dodge' | 'color_burn' | 'hard_light' | 'soft_light' | 'difference' | 'add' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity': Values: - `none` — Normal compositing (source-over) — the default. - `multiply` — Multiply blend — darkens by multiplying layer colors. - `screen` — Screen blend — lightens by inverting, multiplying, inverting. - `overlay` — Overlay blend — multiply in shadows, screen in highlights. - `darken` — Darken blend — keeps the darker of the two layers per channel. - `lighten` — Lighten blend — keeps the lighter of the two layers per channel. - `color_dodge` — Color-dodge blend — brightens the base toward the blend color. - `color_burn` — Color-burn blend — darkens the base toward the blend color. - `hard_light` — Hard-light blend — overlay with layers swapped. - `soft_light` — Soft-light blend — a gentler hard-light. - `difference` — Difference blend — absolute difference of the two layers per channel. - `add` — Additive (linear-dodge) blend — sums layer colors, clamped. - `exclusion` — Exclusion blend — like difference, lower contrast. - `hue` — Hue blend — backdrop luminosity + saturation with the blend layer's hue. - `saturation` — Saturation blend — backdrop hue + luminosity with the blend layer's saturation. - `color` — Color blend — backdrop luminosity with the blend layer's hue + saturation. - `luminosity` — Luminosity blend — backdrop hue + saturation with the blend layer's luminosity.
        - `mask_shape` 'circle' | 'diamond' | 'hexagon' | 'star' | 'heart' | 'triangle': Analytic (SDF) shape mask that clips an element's coverage. §1. Values: - `circle` — Circular (ellipse) analytic mask, fit to the element bounds. - `diamond` — Diamond (rotated square) analytic mask. - `hexagon` — Regular hexagon analytic mask. - `star` — Five-point star analytic mask. - `heart` — Heart analytic mask. - `triangle` — Upward triangle analytic mask.
        - `mask` MaskConfig: Animated/feathered mask params layered on the analytic `mask_shape` (§5c).
          - `feather` number: Soften the mask's SDF edge.
          - `scale` number: Mask scale (iris reveals).
          - `center` Point
            - `x` number
            - `y` number
        - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
          - `source` string, required: uuid of the source layer (auto-hidden). Text sources supported.
          - `mode` 'alpha' | 'luma'
          - `invert` boolean
        - `effects` Effect[]: Shader effects run over its content.
          - `type` 'vintage' | 'polaroid' | 'portra' | 'super8' | 'filmic' | 'add_grain' | 'rgb_split' | 'ghosting' | 'displacement_map' | 'posterize' | 'mosaic' | 'mosaic_blur' | 'mosaic_posterize' | 'cc_halftone' | 'cc_halftone_blue' | 'cc_halftone_green' | 'cc_halftone_red' | 'invert' | 'optics_compensation' | 'viewfinder' | 'night_vision' | 'thermal' | 'camera_lens_blur' | 'camera_lens_blur_bg' | 'box_blur' | 'lens_flare' | 'strobe_light' | 'snow' | 'glow' | 'sepia' | 'echo' | 'chromatic_aberration' | 'vhs' | 'vhs_overlay' | 'crt' | 'television' | 'glitch' | 'compression_glitch' | 'scanlines' | 'prism' | 'light_leaks' | 'film_burn' | 'duotone' | 'cross_process' | 'bleach_bypass' | 'chroma_key' | 'aurora': Values: - `vintage` — Faded, warm retro film look with lifted blacks. - `polaroid` — Instant-photo look — soft contrast, warm cast, subtle vignette. - `portra` — Kodak Portra-style film emulation with natural skin tones. - `super8` — Super-8 home-movie look — grain, gate weave, warm color. - `filmic` — Cinematic film grade with rolled-off highlights and rich contrast. - `add_grain` — Adds dusty analog film grain over the image. - `rgb_split` — Offsets the red/green/blue channels for a glitchy chromatic split. - `ghosting` — Trailing motion echoes, like persistence-of-vision smearing. - `displacement_map` — Warps the image with a displacement texture for a melted look. - `posterize` — Reduces the image to a small number of flat color bands. - `mosaic` — Pixelates the image into large mosaic blocks. - `mosaic_blur` — Pixelated mosaic with softened, blurred block edges. - `mosaic_posterize` — Combines mosaic pixelation with posterized colors. - `cc_halftone` — Comic-style halftone dot pattern. - `cc_halftone_blue` — Halftone dot pattern tinted blue. - `cc_halftone_green` — Halftone dot pattern tinted green. - `cc_halftone_red` — Halftone dot pattern tinted red. - `invert` — Inverts all colors (photo-negative). - `optics_compensation` — Fish-eye / lens-distortion warp. - `viewfinder` — Camera viewfinder overlay (REC indicator, framing marks). - `night_vision` — Green night-vision look with glow and noise. - `thermal` — Thermal-camera false-color heat map. - `camera_lens_blur` — Realistic bokeh lens blur across the frame. - `camera_lens_blur_bg` — Bokeh lens blur applied to the background only. - `box_blur` — Fast, uniform box blur. - `lens_flare` — Adds an anamorphic lens-flare streak and glints. - `strobe_light` — Rapid brightness strobing / flashing. - `snow` — Falling-snow particle overlay. - `glow` — Dreamy soft-glow bloom over highlights. - `sepia` — Sepia-toned monochrome with a vignette. - `echo` — Soft ghosted dream-echo overlay. - `chromatic_aberration` — Color-fringing at edges, like cheap-lens dispersion. - `vhs` — VHS tape look: tracking noise, color bleed, and wobble. - `vhs_overlay` — VHS noise/scanline layer composited over the source. - `crt` — CRT monitor look: screen curvature, scanlines, and phosphor glow. - `television` — Analog TV look: scanlines, static, and signal distortion. - `glitch` — Digital glitch: block displacement and channel tearing. - `compression_glitch` — MPEG compression artifacts: blocky macroblocks and datamosh. - `scanlines` — Horizontal scanlines overlaid on the image. - `prism` — Prismatic light refraction with a rainbow color split. - `light_leaks` — Warm light-leak streaks bleeding across the frame. - `film_burn` — Burning-film look with scorched edges and flares. - `duotone` — Two-tone color map (shadows to one hue, highlights to another). - `cross_process` — Cross-processed film look with shifted, punchy colors. - `bleach_bypass` — High-contrast, desaturated bleach-bypass film grade. - `chroma_key` — Keys out a color (green/blue screen); tune via `chroma_settings`. - `aurora` — Animated domain-warped fluid-gradient wash (§6); tune flow via `props` speed.
          - `intensity` number, nullable: Effect strength, 0 to 100. On a shader effect it is null unless set: the shader then runs at the engine's own full intensity rather than the effect-wide 50.
          - `intensity_keyframes` IntensityKeyframe[], nullable: Animate intensity over time (§2): piecewise-linear `[{time, value}]` in timeline seconds. Overrides the static `intensity` when set.
            - `time` number, required: Absolute timeline seconds.
            - `value` number, required: Effect intensity 0–1 at this time.
          - `props` object, nullable: Per-shader scalar props (§2), bound as `u_prop_<key>` (e.g. `{"speed": 0.6}` for aurora). Ignored for chroma_key (use `chroma_settings`).
          - `chroma_settings` ChromaKeyProps: Used when ``EffectType.CHROMA_KEY`` is selected. Keys against an explicit key **colour** in the YCbCr chroma plane, which is luma-independent, so shadows falling on the screen key out along with it. This replaced an hue/saturation/luminance-window shape that could not work. It was wired to ``effect_chroma.frag``, whose ``sensitivity`` is ``(hueMax - hueMin) * 0.5`` compared against an Oklab distance bounded around 0..0.9 — so the old defaults (60/180) produced a sensitivity of 60, discarded every pixel, and made the element vanish from the render. Nothing could have depended on the previous shape, because nothing rendered with it.
            - `key_color` string: The colour to key out. Green-screen green by default.
            - `threshold` number: Chroma distance from `key_color` below which a pixel is fully transparent. Raise it if fringes of the screen survive.
            - `smoothness` number: Width of the ramp from transparent to opaque, starting at `threshold`. Raise it to soften hard edges; 0 gives a hard cut.
            - `spill_suppress` number: How strongly surviving pixels near the key colour are pulled toward their own luma, removing green spill on hair and edges. 0 disables.
          - `shader` EffectShader: A runtime shader (render-node AEC §2) by its stored id. `POST /v1/shaders` compiles one from SkSL source; the render carries its compiled variants, so it renders on the farm and in the preview alike.
            - `id` string, required: The shader's id (`sh_...`): one of this workspace's or a shared one (GET /v1/shaders).
            - `params` object: Values of the shader's declared params by name: a number (`float`), "#RRGGBBAA" (`color`) or [x, y] (`vec2`), or keyframes `[{time, value}]` in timeline seconds. A param left out takes its declared default.
        - `render` 'flatten' | 'composite', nullable: `composite` makes it a nested composition whose content runs on `time_map`'s clock; its content is graphics only (no video). Omitted: `flatten`.
        - `time_map` TimeMap: A composite frame's clock (AEC §5): the time its children read.
          - `offset` number, nullable: Seconds into the children's timeline at the frame's start. Omitted: 0.
          - `speed` number, nullable: Rate of the children's timeline: 0 holds, below 0 plays backwards. Omitted: 1.
          - `loop` number, nullable: Seconds after which the children's timeline repeats. Omitted: no loop.
          - `freeze` number, nullable: Hold the children at this many seconds into their timeline; overrides `offset` and `speed`.
        - `type` 'instance'
        - `id` string, required: **Required.** Its content's ids become `<id>/<child id>`.
        - `name` string, nullable: Optional human-readable label. Not used by the renderer.
        - `track` integer, nullable: Timeline track index (0–255). Informational only; not used by the renderer.
        - `time` number, required: **Required.** Start in seconds on its parent's clock; every time inside the component counts from it.
        - `visible` boolean: Set to `false` to skip this element without removing it from the request.
        - `locked` boolean: Marks the element locked in editors. Not sent to the renderer.
        - `component` string, required: The `components` entry it places.
        - `variant` string, nullable: The variant by name. Omitted: the first.
        - `properties` object: Values of the component's declared properties, by name, each of its type.
        - `slots` object: Content for the component's slots, by slot name, in place of the slot frame's own children.
  - `transitions` Transition[]: Transition effects applied between consecutive elements.
    - `type` 'cross_dissolve' | 'dip_to_black' | 'dip_to_white' | 'wipe_left' | 'wipe_right' | 'wipe_up' | 'wipe_down' | 'diagonal_wipe' | 'barn_doors_horizontal' | 'barn_doors_vertical' | 'iris' | 'page_turn' | 'cross_zoom' | 'gradient_wipe' | 'band_wipe' | 'box_wipe' | 'swirl' | 'glitch_memories' | 'window_slice' | 'cube' | 'doorway' | 'pinwheel' | 'water_drop' | 'crosshatch' | 'dreamy' | 'angular' | 'burn' | 'heart' | 'circle_open' | 'color_phase' | 'squares_wire' | 'whip_pan' | 'cinematic_zoom' | 'burn_edge' | 'shatter' | 'domain_warp' | 'circle_crop' | 'cross_warp' | 'fold_horizontal' | 'fold_vertical' | 'linear_blur' | 'minimise_bottom_left' | 'minimise_bottom_right' | 'minimise_top_left' | 'minimise_top_right' | 'ripple' | 'rotate' | 'splice' | 'three_stripes', required: Values: - `cross_dissolve` — Cross-dissolve — fades one clip into the next. - `dip_to_black` — Dips through black between clips. - `dip_to_white` — Dips through white between clips. - `wipe_left` — Wipes the next clip in from the right to the left. - `wipe_right` — Wipes the next clip in from the left to the right. - `wipe_up` — Wipes the next clip in from the bottom upward. - `wipe_down` — Wipes the next clip in from the top downward. - `diagonal_wipe` — Wipes across on a diagonal split. - `barn_doors_horizontal` — Two halves part horizontally like barn doors. - `barn_doors_vertical` — Two halves part vertically like barn doors. - `iris` — Circular iris (bullseye) open/close between clips. - `page_turn` — Page-flip / page-curl reveal. - `cross_zoom` — Zoom-blur push from one clip into the next. - `gradient_wipe` — Soft gradient-driven dissolve wipe. - `band_wipe` — Interleaved stripes wipe the next clip in. - `box_wipe` — Rectangular box grows to reveal the next clip. - `swirl` — Swirls the outgoing clip away in a spiral. - `glitch_memories` — Glitchy, memory-like distortion between clips. - `window_slice` — Slices the frame into sliding window strips. - `cube` — 3D cube rotation between the two clips. - `doorway` — Clips part like opening doors to reveal the next. - `pinwheel` — Pinwheel rotation wipe between clips. - `water_drop` — Rippling water-drop distortion reveals the next clip. - `crosshatch` — Crosshatch pattern dissolve between clips. - `dreamy` — Soft, dreamy blur-dissolve between clips. - `angular` — Angular wedge sweep between clips. - `burn` — Burning-film dissolve between clips. - `heart` — Heart-shaped iris reveal of the next clip. - `circle_open` — Expanding circle opens onto the next clip. - `color_phase` — Color-phase shift blends between clips. - `squares_wire` — Wireframe squares wipe between clips. - `whip_pan` — Directional motion-blur whip pan. - `cinematic_zoom` — Punch zoom with radial blur + chromatic fringing. - `burn_edge` — Noise-ridged burn front with ember glow and sparks. - `shatter` — Jittered shards fly apart revealing the incoming clip. - `domain_warp` — Organic noise-warped dissolve with an emissive frontier. - `circle_crop` — Both clips crop to a shrinking/growing circle through the cut. - `cross_warp` — Clips warp into each other along a dissolving threshold. - `fold_horizontal` — Outgoing clip folds away horizontally, revealing the incoming. - `fold_vertical` — Outgoing clip folds away vertically, revealing the incoming. - `linear_blur` — Cross-dissolve through a heavy directional blur peak. - `minimise_bottom_left` — Outgoing clip shrinks away into the bottom-left corner. - `minimise_bottom_right` — Outgoing clip shrinks away into the bottom-right corner. - `minimise_top_left` — Outgoing clip shrinks away into the top-left corner. - `minimise_top_right` — Outgoing clip shrinks away into the top-right corner. - `ripple` — Water-ripple distortion sweeps the cut across the frame. - `rotate` — Both clips rotate about the frame centre through the cut. - `splice` — Angled splice slides the incoming clip over the outgoing. - `three_stripes` — Three offset stripes sweep the incoming clip in.
    - `duration` number, required: Transition duration in seconds.
    - `from_id` string, nullable: ID of the outgoing video element (omit for the very first transition).
    - `to_id` string, nullable: ID of the incoming video element (omit for the very last transition).
    - `z_index` integer, nullable: **Deprecated — ignored by the renderer.** The transition draws at its linked videos' position; the engine reads no z key on a transition. Accepted for backward compatibility only.
  - `groups` Group[]: Transform groups over member elements (compose member→group→parent; optional stack layout), the alias of frames (§5). A request with `frame` or `instance` elements carries none.
    - `id` string, required: **Required.** Unique group id.
    - `parent` string, nullable: Parent group id for nesting.
    - `pivot` Point
      - `x` number
      - `y` number
    - `translate` Point
      - `x` number
      - `y` number
    - `scale` number: Group scale.
    - `rotation_degrees` number: In-plane (z) rotation of the group.
    - `x_rotation` union: Perspective tilt (X axis) applied to each member's orientation about its own centre — the tilted card-gallery look.
      - integer
      - number
      - string
    - `y_rotation` union: Perspective tilt (Y axis). See `x_rotation`.
      - integer
      - number
      - string
    - `opacity` number: Group opacity.
    - `members` string[]: Member element uuids.
    - `animations` Motion[]: Animations driving the whole group about `pivot`. Translate, scale, rotation and colour all compose — that is how you move or resize a whole scene as one unit. Two channels do NOT: a preset that animates **clip** (`wipe_left/right/up/down`) or **crop** (`ken_burns_*`) is a silent no-op on a group, doing nothing at all rather than erroring — put those on a member element instead. Non-uniform scale is also flattened here: only the x component of a `custom_animations` `scale` keyframe is used, so `{x:2,y:1}` scales uniformly. Note `zoom_out` barely moves (scale 1.0->0.9 under a full fade), so it reads as a pure fade; for a real shrink use a `custom` entry with the scale travel you want, or the group's static `scale`.
      - `type` 'identity' | 'fade' | 'slide_up' | 'slide_down' | 'slide_left' | 'slide_right' | 'zoom_in' | 'zoom_out' | 'rotate_cw' | 'rotate_ccw' | 'bounce' | 'wipe_left' | 'wipe_right' | 'wipe_up' | 'wipe_down' | 'ken_burns_in' | 'ken_burns_out' | 'ken_burns_in_out' | 'loop_wiggle' | 'loop_rotate' | 'loop_rotate_smooth' | 'loop_3d_spin' | 'loop_3d_sway' | 'blur' | 'evaporate' | 'overlay' | 'difference' | 'rubber_in' | 'whip_up' | 'whip_down' | 'glitch_pop' | 'drift_in' | 'drift_out' | 'loop_breathe' | 'loop_shimmer' | 'swing_in' | 'swing_out' | 'elastic_rise' | 'elastic_drop' | 'tilt_zoom' | 'loop_orbit' | 'smooth_pop': Values: - `identity` — Deliberate no-op carrier (no visible motion): attach a pure `audio` generator to any element without animating it. Element surfaces only. - `fade` — Fade in (entrance) or out (exit) via opacity. - `slide_up` — Slide in from below / out upward. - `slide_down` — Slide in from above / out downward. - `slide_left` — Slide in from the right / out to the left. - `slide_right` — Slide in from the left / out to the right. - `zoom_in` — Scale up from small to full size (entrance). - `zoom_out` — Scale down to small (exit). - `rotate_cw` — Spin in/out clockwise. - `rotate_ccw` — Spin in/out counter-clockwise. - `bounce` — Bounce in with an elastic overshoot / bounce out. - `wipe_left` — Reveal/conceal with a left-moving wipe. - `wipe_right` — Reveal/conceal with a right-moving wipe. - `wipe_up` — Reveal/conceal with an upward wipe. - `wipe_down` — Reveal/conceal with a downward wipe. - `ken_burns_in` — Slow zoom-in pan (Ken Burns) — entrance only. - `ken_burns_out` — Slow zoom-out pan (Ken Burns) — entrance only. - `ken_burns_in_out` — Slow zoom in then out (Ken Burns) — entrance only. - `loop_wiggle` — Continuous subtle wiggle (looping). - `loop_rotate` — Continuous stepped rotation (looping). - `loop_rotate_smooth` — Continuous smooth rotation (looping). - `loop_3d_spin` — Continuous 3D spin (looping). - `loop_3d_sway` — Continuous 3D sway (looping). - `blur` — Per-glyph soft blur-in (text entrance). - `evaporate` — Per-glyph rise, blur, and fade-out (text exit only). - `overlay` — Static Overlay blend fill (timing ignored). - `difference` — Static Difference blend fill (timing ignored). - `rubber_in` — Per-glyph rubbery overshoot as text springs in (text entrance). - `whip_up` — Per-glyph whip upward into place (text entrance). - `whip_down` — Per-glyph whip downward out of frame (text exit only). - `glitch_pop` — Per-glyph glitchy pop-in with jitter (text entrance). - `drift_in` — Per-glyph gentle drift and fade in (text entrance). - `drift_out` — Per-glyph gentle drift and fade out (text exit only). - `loop_breathe` — Per-glyph continuous breathing scale loop (text). - `loop_shimmer` — Per-glyph continuous shimmer loop (text). - `swing_in` — Element swings into place from an angle (entrance). - `swing_out` — Element swings away out of frame (exit only). - `elastic_rise` — Element rises with an elastic overshoot (entrance). - `elastic_drop` — Element drops away with an elastic recoil (exit only). - `tilt_zoom` — Element tilts and zooms into place (entrance). - `loop_orbit` — Element orbits continuously around its center (loop). - `smooth_pop` — Element pops in from 60% scale, overshooting slightly past full size before it settles, as it fades in (entrance).
      - `preset` string, nullable: Renderer animation name, used verbatim — any element animation on video/image/shape/group (e.g. `'pop'`, `'floatUp'`, `'out-slideBounceLeft'`, `'loop-heartBeat'`), any text animation on text (e.g. `'typewriter'`, `'roll'`, `'out-sink'`, `'loop-wavey'`). Reaches the presets `type` has no name for. The name carries its own direction: `out-*` names are exits, `loop-*` names loop with `duration` as one cycle, so `reversed` and `scope` do not apply. Exactly one of `type`, `preset` or `custom` must be set.
      - `custom` string, nullable: Name of a `custom_animations` entry to run instead of a catalog preset — the `element` registry for video/image/shape/group animations, the `text` registry for text. Exactly one of `type`, `preset` or `custom` must be set.
      - `time` number, required: Absolute start time on the output timeline in seconds. For entrances and loops set this to the element's `time`. For exits set this to element `time + duration − motion duration`. An entrance timed later than the element's own `time` leaves it fully rendered on screen until the entrance fires; the linter reports that as `ENTRANCE_AFTER_ELEMENT_START`.
      - `duration` number, required: How long the animation runs in seconds.
      - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
      - `reversed` boolean: Run the preset's exit form instead of its entrance. Only presets that ship both forms accept it — `fade`, `slide_*`, `wipe_*`, `rotate_*`, `bounce`. Entrance-only presets have a separate exit-only type instead: use `zoom_out` (not `zoom_in` reversed), `evaporate` (not `blur`), `whip_down`, `drift_out`, `swing_out`, `elastic_drop` — those six set this flag for you. See `GET /v1/capabilities` `motion[].element_exit` for the per-preset truth.
      - `scope` 'element' | 'character': Whether a motion preset applies to the whole element or per-glyph (text only). Values: - `element` — The motion animates the whole element as one unit. - `character` — The motion animates each text glyph individually (text only).
      - `delay` number: Seconds to wait before the animation starts (folded into the animation's start time on the wire — the engine has no standalone pre-start delay). On loop presets it spaces the repeats instead.
      - `spacing` number, nullable: Stagger multiplier between per-glyph/word windows on text animations (engine default 1 = fully sequential; smaller values overlap the windows). Ignored by block animations.
      - `loop` boolean
      - `audio` AudioGenerator: Audio-reactive property offsets driven by the soundtrack FFT (§3, W2). Each frame the mix reduces to the chosen feature and the element's properties get offset by ``amount × feature`` — beat-bounce, bass-pumped scale, etc.
        - `feature` 'amplitude' | 'bass' | 'mid' | 'high' | 'beat'
        - `scale` number: Scale offset per unit feature.
        - `opacity` number: Opacity offset per unit feature.
        - `translate` Point
          - `x` number
          - `y` number
        - `rotate` number: Rotation offset (degrees) per unit feature.
    - `layout` StackLayout: Resolve members into a row/column stack (§5, A2): the groups alias's stack, placed as before. A `frame` has no layout of its own (the host's, render-node O27).
      - `type` 'stack'
      - `direction` 'row' | 'column'
      - `gap` number: Gap between members, normalized along the main axis.
      - `align` 'start' | 'center' | 'end'
      - `origin` Point
        - `x` number
        - `y` number
  - `design_size` DesignSize: The logical root (render-node AEC §6): the box frames and instances at the root are placed in, in design px, scaled uniformly to the output, whose aspect it must have.
    - `width` number, required: Width in design px.
    - `height` number, required: Height in design px.
  - `operations` OperationsBlock: The `operations` block (render-node AEC §3; GVR §4.3): element properties driven over time and evaluated by the engine every frame. Each group counts from its anchor.
    - `markers` OperationMarker[]: Named times `marker` anchors read.
      - `name` string, required
      - `time` number, required: Seconds on the composition clock.
    - `groups` OperationGroup[]: At most 1000 groups and 10000 operations.
      - `id` string, nullable: A stable id for editors.
      - `name` string, nullable: A label, e.g. `Animate in`.
      - `role` string, nullable: What the group is for in editors (`in`, `out`, `loop`, …). Not sent to the renderer.
      - `anchor` OperationAnchor: Where a group's times count from (GVR §4.3 item 8).
        - `ref` 'composition' | 'element.start' | 'element.end' | 'marker' | 'instance.start', required: `composition` (0 s), `element.start` or `element.end` of `target`, a marker by `name`, or `instance.start` of `target` (in a component, its own instance).
        - `target` string, nullable: The element or instance an element or instance anchor reads.
        - `name` string, nullable: The marker a `marker` anchor reads.
        - `offset` number, nullable: Seconds added to the anchor. Omitted: 0.
      - `ops` union[], required: Operations and presets in document order: at equal starts the later replace wins.
        - union
          - Operation: One property driven over a window (GVR §4.3): the base value, then the replaces by start, then the multiplies and the adds. It holds `to` after `end`.
            - `id` string, nullable: A stable id for editors.
            - `target` string, required: The element id it drives; with a `child` split, a frame's.
            - `start` number, required: Seconds after the group's anchor.
            - `end` number, required: Seconds after the group's anchor; equal to `start` switches at once.
            - `property` string, required: A property registry path: `position.x`, `size.y`, `scale`, `rotation`, `opacity`, `fill`, `geometry.ring.segments[0].sweep`, `text.value`, …; a colour takes `.r`/`.g`/`.b`/`.a`. GET /v1/capabilities lists every path, its unit and range under `registry.properties`.
            - `from` union: Value at `start` (a string on `text.value`). Omitted on a replace: the value below it at `start`; on an add or multiply: the identity.
              - …
            - `to` union: Value at `end`, held after it. Omitted on a replace: the live base value; on an add or multiply: the identity.
              - …
            - `easing` union: A curve name (`ease_in_out`, `hold`, …), `{family, intensity}`, or one of `{bezier: [x1, y1, x2, y2]}`, `{spring}`, `{back}`, `{elastic}`. Omitted: linear.
              - …
            - `composite` 'replace' | 'add' | 'multiply', nullable: `replace` overrides what is below it from `start`; `add` and `multiply` stack on it (multiply on scale, opacity and colours). Omitted: `replace`.
            - `split` OperationSplit: Run the operation once per unit, each starting `rank × stagger` seconds after the operation's start, the rank by `order` (GVR §4.3 item 7).
              - …
            - `takeover` 'velocity', nullable: On a replace without `from`: start at the speed of what it replaces.
          - PresetOperation: An element preset run as operations over the window (GVR §4.3 item 10).
            - `id` string, nullable: A stable id for editors.
            - `target` string, required: The element id it drives; with a `child` split, a frame's.
            - `start` number, required: Seconds after the group's anchor.
            - `end` number, required: Seconds after the group's anchor; equal to `start` switches at once.
            - `preset` 'arcRise' | 'bounceIn' | 'drop' | 'elasticRise' | 'fade' | 'floatDown' | 'floatLeft' | 'floatRight' | 'floatUp' | 'gentleFloatDown' | 'gentleFloatLeft' | 'gentleFloatRight' | 'gentleFloatUp' | 'identity' | 'kenBurnsIn' | 'kenBurnsInOut' | 'kenBurnsOut' | 'loop-3DSpin' | 'loop-3DSway' | 'loop-bounce' | 'loop-heartBeat' | 'loop-jiggle' | 'loop-orbit' | 'loop-rotateBasic' | 'loop-rotateSmooth' | 'loop-squeezy' | 'loop-sway' | 'out-bounceOut' | 'out-dropOut' | 'out-elasticDrop' | 'out-fade' | 'out-floatDown' | 'out-floatLeft' | 'out-floatRight' | 'out-floatUp' | 'out-gentleFloatDown' | 'out-gentleFloatLeft' | 'out-gentleFloatRight' | 'out-gentleFloatUp' | 'out-pop' | 'out-slideBounceDown' | 'out-slideBounceLeft' | 'out-slideBounceRight' | 'out-slideBounceUp' | 'out-slideDown' | 'out-slideLeft' | 'out-slideRight' | 'out-slideUp' | 'out-spinAntiClockwise' | 'out-spinClockwise' | 'out-swingOut' | 'out-wipeDown' | 'out-wipeLeft' | 'out-wipeRight' | 'out-wipeUp' | 'out-zoomOut' | 'pop' | 'slideBounceDown' | 'slideBounceLeft' | 'slideBounceRight' | 'slideBounceUp' | 'slideDown' | 'slideLeft' | 'slideRight' | 'slideUp' | 'smoothPop' | 'spinAntiClockwise' | 'spinClockwise' | 'springPop' | 'swingIn' | 'tiltZoom' | 'wipeDown' | 'wipeLeft' | 'wipeRight' | 'wipeUp' | 'zoomIn', required: An element preset by the engine's name (`slideUp`, `zoomIn`, `fade`, …). Text presets stay on a text's `motion`.
  - `components` Component[]: Component definitions, which `instance` elements place. Schema of one: `blocks.components` in GET /v1/capabilities.
    - `id` string, required: What an instance's `component` names.
    - `width` number, required: Box width in design px.
    - `height` number, required: Box height in design px.
    - `clip` boolean, nullable: Its instances clip to the box unless they say otherwise.
    - `corner_radius` union: Its instances' clip corner radius in design px.
      - number
      - number[]
      - GeometryCornerRadii: Per-corner radii in px; a corner left out is 0.
        - `top_left` number, nullable
        - `top_right` number, nullable
        - `bottom_right` number, nullable
        - `bottom_left` number, nullable
    - `properties` ComponentProperty[]: What an instance can set.
      - `name` string, required: A letter, then letters, digits or `_`.
      - `type` 'text' | 'colour' | 'number' | 'boolean' | 'media' | 'component' | 'variant', required: `text`, `colour` (`#RRGGBB` or `#RRGGBBAA`), `number`, `boolean`, `media` (a URL), `component` (an id from `allowed`) or `variant` (a nested instance's).
      - `bind` string[], required: Body fields it writes, as `<child id>.<field>` in this API's field names: any element's `x`, `y`, `z_rotation`, `opacity` and `visible`; a frame's or instance's `scale` and `clip`; a text's `text`, `text_color` and `font_size`; a shape's `fill`, `stroke` and `stroke_width`; an image's or video's `source_url`; an instance's `component`, `variant` and `properties.<name>`.
      - `default` union: Its value when an instance sets none. Omitted: the body's own.
        - boolean
        - integer
        - number
        - string
      - `min` number, nullable: A `number` property's lowest value.
      - `max` number, nullable: A `number` property's highest value.
      - `allowed` string[], nullable: The component ids a `component` property may swap in. Required on one.
    - `children` union[], nullable: The body of a single-variant component, in design px from the box's top-left corner. Give this or `variants`.
      - union
        - ChildVideoElement: A video inside a frame. Not inside a composite frame, whose content is graphics only.
          - `lut_url` string, uri, nullable
          - `lut_intensity` number
          - `brightness` number: Brightness, -100..100, applied as a 0..2 colour multiplier (0 = no change). `-100` multiplies by 0: the element renders pure black while keeping its alpha — a silhouette of the artwork. Combine a `brightness: -100` copy of an image with `blur`, reduced `opacity` and a small offset, stacked beneath the real one, to fake the content-shaped drop shadow `shadow_x`/`shadow_y` cannot produce.
          - `contrast` number
          - `saturation` number
          - `exposure` number
          - `sharpness` number
          - `blur` number
          - `noise` number
          - `vignette` number
          - `hue_rotate` number
          - `temperature` number: White balance warm (+) / cool (−), −1..1; 0 = no-op. Applied as a channel matrix, after the classic brightness/contrast chain.
          - `tint` number: White balance magenta (+) / green (−), −1..1; 0 = no-op.
          - `vibrance` number: Saturation boost weighted toward muted colours, −1..1; 0 = no-op. Boosts flat colour without wrecking skin tones.
          - `highlights` number: Luma-masked tone lift of the brightest range, −1..1; 0 = no-op.
          - `shadows` number: Luma-masked tone lift of the darkest range, −1..1; 0 = no-op.
          - `crop_top` number
          - `crop_bottom` number
          - `crop_left` number
          - `crop_right` number
          - `border_radius` union: Corner radius in pixels — a single value, or per-corner `{top_left, top_right, bottom_right, bottom_left}` for asymmetric corners (e.g. a card rounded only on top). The renderer normalizes px to a 0–1 fraction of the element's shorter side (≈ half the shorter side is fully rounded) and clamps to that range. For shape elements use `corner_radius` (already 0–1).
            - integer
            - number
            - string
            - CornerRadiiPx: Per-corner radii in pixels (for `border_radius` on video/image/text elements).
              - …
          - `border_color` string, nullable
          - `border_width` union: Border thickness in pixels (converted to the renderer's relative border scale against the element's shorter side, so it survives resizes). The border outlines the element's border_radius-rounded quad — not the image's alpha silhouette.
            - integer
            - number
            - string
          - `shadow_color` string, nullable
          - `shadow_blur` union: Shadow softness, 0–100 (renderer blur-strength scale, not pixels): 0 = hard edge, 100 = maximum blur. Values are clamped to that range.
            - integer
            - number
            - string
          - `shadow_x` union: Horizontal shadow offset in pixels (converted to the renderer's relative offset scale). The shadow silhouette is the element's border_radius-rounded quad, not the content alpha — a cut-out PNG gets a card shadow, not an outline-shaped one. On a cut-out that reads as a floating rectangle (rotated with the element, which is the tell). For a shadow that follows the artwork, drop these fields and stack a second copy of the same image underneath at `brightness: -100` (a black silhouette, alpha preserved) with `blur` and reduced `opacity`, offset a few percent — see `brightness`.
            - integer
            - number
            - string
          - `shadow_y` union: Vertical shadow offset in pixels. See `shadow_x`.
            - integer
            - number
            - string
          - `blend_mode` 'none' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color_dodge' | 'color_burn' | 'hard_light' | 'soft_light' | 'difference' | 'add' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity': Values: - `none` — Normal compositing (source-over) — the default. - `multiply` — Multiply blend — darkens by multiplying layer colors. - `screen` — Screen blend — lightens by inverting, multiplying, inverting. - `overlay` — Overlay blend — multiply in shadows, screen in highlights. - `darken` — Darken blend — keeps the darker of the two layers per channel. - `lighten` — Lighten blend — keeps the lighter of the two layers per channel. - `color_dodge` — Color-dodge blend — brightens the base toward the blend color. - `color_burn` — Color-burn blend — darkens the base toward the blend color. - `hard_light` — Hard-light blend — overlay with layers swapped. - `soft_light` — Soft-light blend — a gentler hard-light. - `difference` — Difference blend — absolute difference of the two layers per channel. - `add` — Additive (linear-dodge) blend — sums layer colors, clamped. - `exclusion` — Exclusion blend — like difference, lower contrast. - `hue` — Hue blend — backdrop luminosity + saturation with the blend layer's hue. - `saturation` — Saturation blend — backdrop hue + luminosity with the blend layer's saturation. - `color` — Color blend — backdrop luminosity with the blend layer's hue + saturation. - `luminosity` — Luminosity blend — backdrop hue + saturation with the blend layer's luminosity.
          - `mask_shape` 'circle' | 'diamond' | 'hexagon' | 'star' | 'heart' | 'triangle': Analytic (SDF) shape mask that clips an element's coverage. §1. Values: - `circle` — Circular (ellipse) analytic mask, fit to the element bounds. - `diamond` — Diamond (rotated square) analytic mask. - `hexagon` — Regular hexagon analytic mask. - `star` — Five-point star analytic mask. - `heart` — Heart analytic mask. - `triangle` — Upward triangle analytic mask.
          - `mask` MaskConfig: Animated/feathered mask params layered on the analytic `mask_shape` (§5c).
            - `feather` number: Soften the mask's SDF edge.
            - `scale` number: Mask scale (iris reveals).
            - `center` Point
              - …
          - `mask_keyframes` MaskKeyframe[], nullable
            - `time` number, required: Timeline seconds.
            - `feather` number, nullable
            - `scale` number, nullable
            - `center` Point
              - …
            - `easing` string, nullable: Easing curve name — any `easings` catalog value (`linear`, `hold`, `ease_in_out`, `quad_out`, `expo_in_out`, `square_in_out` = step, …). Unknown names are rejected: the engine would silently fall back to linear. For spring/back/elastic/bezier use the sub-objects instead.
            - `spring` SpringEasing: Damped-spring ease over the keyframe segment. Only the damping ratio zeta = damping / (2 * sqrt(stiffness * mass)) shapes the curve; the segment's duration sets its timing. Below 1 the spring overshoots and rings (the defaults give zeta = 0.5); at 1 or above it settles without overshoot. An underdamped spring runs until its envelope decays to 0.1% (settle x w0 = ln(1000) / zeta, w0 = sqrt(stiffness / mass)). Since render-node's overdamped settle fix (GVR M3), a spring at zeta >= 1 runs over its slowest decay rate instead; before it, an overdamped spring's window was cut short and it reached the target still moving.
              - …
            - `back` BackEasing: Anticipate/overshoot ease (AE 'back').
              - …
            - `elastic` ElasticEasing: Elastic ring-out/ring-in ease.
              - …
            - `bezier` BezierEasing: CSS cubic-bezier(x1, y1, x2, y2) timing curve.
              - …
          - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
            - `source` string, required: uuid of the source layer (auto-hidden). Text sources supported.
            - `mode` 'alpha' | 'luma'
            - `invert` boolean
          - `backdrop_blur` union: Glass: the scene behind the element, Gaussian-blurred, fills its footprint under its translucent content (a shape's own silhouette, a video's or image's box with its corner radius and mask). A Gaussian sigma in canvas px, as CSS `backdrop-filter: blur()` takes it; the renderer caps it at 128. 0 is off.
            - integer
            - number
            - string
          - `backdrop_blur_keyframes` BlurKeyframe[], nullable: Animate `backdrop_blur` over the timeline; replaces the static value while present.
            - `time` number, required: Timeline seconds.
            - `value` number, required: Gaussian sigma in canvas px at `time`, at most 128.
          - `layer_blur` number: Blurs the element itself as drawn: a Gaussian sigma in canvas px, as CSS `filter: blur()` takes it, spreading three sigma past its box. At most 128; 0 is off. Not on a shape yet (the editor's preview cannot draw it), and not with `blend_mode`, `backdrop_blur` or `matte`, beside which the renderer would draw the element without it.
          - `layer_blur_keyframes` BlurKeyframe[], nullable: Animate `layer_blur` over the timeline; replaces the static value while present.
            - `time` number, required: Timeline seconds.
            - `value` number, required: Gaussian sigma in canvas px at `time`, at most 128.
          - `glass` Glass: A refracting glass surface (V6, render-node AEC §1): within `bevel` px of the element's edge (a shape's own outline, a box's rounded corners) the scene behind is read inward, bent by `refraction`, its red and blue split by `dispersion`. With `backdrop_blur` it bends the blurred scene, without it the sharp one.
            - `bevel` number, nullable: Width of the bent band at the edge in canvas px, at most 256. Omitted: 16.
            - `refraction` number, nullable: How far the edge bends the scene inward, 0–1. Omitted: 0.5.
            - `dispersion` number, nullable: How far red and blue split apart at the edge, 0–1. Omitted: 0.
          - `x` number, nullable: Left edge in design px from the frame's left edge. Omitted: 0.
          - `y` number, nullable: Top edge in design px from the frame's top edge. Omitted: 0.
          - `width` number, nullable: Width in design px. Omitted: the frame's width.
          - `height` number, nullable: Height in design px. Omitted: the frame's height (a text's: twice its `font_size`).
          - `aspect_ratio` number, nullable: **Accepted but ignored — the renderer never receives this field.** It does NOT constrain or correct the `width`/`height` box, so it cannot be used to stop a mismatched box from cropping the source; size the box per `width` instead. Kept for backward compatibility.
          - `x_anchor` union: Pivot the element turns and scales about, across its own box: a percent, or design px from its left edge.
            - integer
            - number
            - string
          - `y_anchor` union: Pivot across its own box's height: a percent, or design px from its top edge.
            - integer
            - number
            - string
          - `x_rotation` union
            - integer
            - number
            - string
          - `y_rotation` union
            - integer
            - number
            - string
          - `z_rotation` union
            - integer
            - number
            - string
          - `x_scale` union
            - integer
            - number
            - string
          - `y_scale` union
            - integer
            - number
            - string
          - `flip_horizontal` boolean
          - `flip_vertical` boolean
          - `opacity` number
          - `z_index` integer, nullable: Stacking order among the frame's children (higher on top); ties draw in array order.
          - `clip` boolean
          - `color_overlay` string, nullable: **Not supported by the renderer — setting this is rejected.** A strict submit returns `unsupported_feature` (422) and a dry-run reports it as a blocking violation; there is no native tint field to map it onto. To darken an element use `brightness` (`-100` is a black silhouette); to lay a colour over one, stack a `shape` with a flat or gradient `fill` above it.
          - `type` 'video'
          - `id` string, nullable: Unique identifier for this element. **Required on image elements** — an empty or missing ID causes the image to be silently skipped by the renderer. Recommended on all elements that are referenced by a transition.
          - `name` string, nullable: Optional human-readable label. Not used by the renderer.
          - `track` integer, nullable: Timeline track index (0–255). Informational only; not used by the renderer.
          - `time` number, nullable: Start in seconds on the clock the frame gives its children (the composition's, unless a composite frame maps it; inside a component, 0 is the instance's start). Omitted: the frame's start.
          - `visible` boolean: Set to `false` to skip this element without removing it from the request.
          - `locked` boolean: Marks the element locked in editors. Not sent to the renderer.
          - `source_url` string, uri, required: URL of the video file — MP4, MOV or WebM only; any other extension is rejected at submit. Must be accessible by the renderer.
          - `in_point` number, nullable: In point — seconds into the source file to start playing from. Defaults to `0`.
          - `out_point` number, nullable: Out point — seconds into the source file to stop playing. Defaults to end of source when omitted. Controls clip length on the timeline.
          - `speed` number: Playback speed. `1.0` = normal speed, `2.0` = 2× (half duration), `0.5` = half speed (double duration).
          - `playback_rate_keyframes` RateKeyframe[], nullable: Speed ramp (§5c): piecewise-linear playback-rate keyframes (absolute timeline seconds; rate 0 = freeze; at most 512 keyframes — the renderer truncates beyond that). Audio keeps the static rate — mute or detach it on ramped clips.
            - `time` number, required: Timeline seconds.
            - `rate` number, required: Playback rate (0 = freeze-frame).
          - `volume` number: Embedded audio volume as a percentage (0–100). Affects only the audio track inside this video clip.
          - `muted` boolean: Silence the clip's embedded audio. `volume` is kept, so unmuting restores the level.
          - `loop` boolean: Repeat the source to fill the clip: when playback passes the end of the file it restarts from the file's first frame (not `in_point`). Set `out_point` past the source's length to choose how long the clip runs — its timeline length is still `(out_point − in_point) / speed`. Requires `out_point`.
          - `fade_in_duration` number: Duration in seconds of a linear audio fade-in at the clip's start.
          - `fade_out_duration` number: Duration in seconds of a linear audio fade-out at the clip's end.
          - `effects` Effect[]
            - `type` 'vintage' | 'polaroid' | 'portra' | 'super8' | 'filmic' | 'add_grain' | 'rgb_split' | 'ghosting' | 'displacement_map' | 'posterize' | 'mosaic' | 'mosaic_blur' | 'mosaic_posterize' | 'cc_halftone' | 'cc_halftone_blue' | 'cc_halftone_green' | 'cc_halftone_red' | 'invert' | 'optics_compensation' | 'viewfinder' | 'night_vision' | 'thermal' | 'camera_lens_blur' | 'camera_lens_blur_bg' | 'box_blur' | 'lens_flare' | 'strobe_light' | 'snow' | 'glow' | 'sepia' | 'echo' | 'chromatic_aberration' | 'vhs' | 'vhs_overlay' | 'crt' | 'television' | 'glitch' | 'compression_glitch' | 'scanlines' | 'prism' | 'light_leaks' | 'film_burn' | 'duotone' | 'cross_process' | 'bleach_bypass' | 'chroma_key' | 'aurora': Values: - `vintage` — Faded, warm retro film look with lifted blacks. - `polaroid` — Instant-photo look — soft contrast, warm cast, subtle vignette. - `portra` — Kodak Portra-style film emulation with natural skin tones. - `super8` — Super-8 home-movie look — grain, gate weave, warm color. - `filmic` — Cinematic film grade with rolled-off highlights and rich contrast. - `add_grain` — Adds dusty analog film grain over the image. - `rgb_split` — Offsets the red/green/blue channels for a glitchy chromatic split. - `ghosting` — Trailing motion echoes, like persistence-of-vision smearing. - `displacement_map` — Warps the image with a displacement texture for a melted look. - `posterize` — Reduces the image to a small number of flat color bands. - `mosaic` — Pixelates the image into large mosaic blocks. - `mosaic_blur` — Pixelated mosaic with softened, blurred block edges. - `mosaic_posterize` — Combines mosaic pixelation with posterized colors. - `cc_halftone` — Comic-style halftone dot pattern. - `cc_halftone_blue` — Halftone dot pattern tinted blue. - `cc_halftone_green` — Halftone dot pattern tinted green. - `cc_halftone_red` — Halftone dot pattern tinted red. - `invert` — Inverts all colors (photo-negative). - `optics_compensation` — Fish-eye / lens-distortion warp. - `viewfinder` — Camera viewfinder overlay (REC indicator, framing marks). - `night_vision` — Green night-vision look with glow and noise. - `thermal` — Thermal-camera false-color heat map. - `camera_lens_blur` — Realistic bokeh lens blur across the frame. - `camera_lens_blur_bg` — Bokeh lens blur applied to the background only. - `box_blur` — Fast, uniform box blur. - `lens_flare` — Adds an anamorphic lens-flare streak and glints. - `strobe_light` — Rapid brightness strobing / flashing. - `snow` — Falling-snow particle overlay. - `glow` — Dreamy soft-glow bloom over highlights. - `sepia` — Sepia-toned monochrome with a vignette. - `echo` — Soft ghosted dream-echo overlay. - `chromatic_aberration` — Color-fringing at edges, like cheap-lens dispersion. - `vhs` — VHS tape look: tracking noise, color bleed, and wobble. - `vhs_overlay` — VHS noise/scanline layer composited over the source. - `crt` — CRT monitor look: screen curvature, scanlines, and phosphor glow. - `television` — Analog TV look: scanlines, static, and signal distortion. - `glitch` — Digital glitch: block displacement and channel tearing. - `compression_glitch` — MPEG compression artifacts: blocky macroblocks and datamosh. - `scanlines` — Horizontal scanlines overlaid on the image. - `prism` — Prismatic light refraction with a rainbow color split. - `light_leaks` — Warm light-leak streaks bleeding across the frame. - `film_burn` — Burning-film look with scorched edges and flares. - `duotone` — Two-tone color map (shadows to one hue, highlights to another). - `cross_process` — Cross-processed film look with shifted, punchy colors. - `bleach_bypass` — High-contrast, desaturated bleach-bypass film grade. - `chroma_key` — Keys out a color (green/blue screen); tune via `chroma_settings`. - `aurora` — Animated domain-warped fluid-gradient wash (§6); tune flow via `props` speed.
            - `intensity` number, nullable: Effect strength, 0 to 100. On a shader effect it is null unless set: the shader then runs at the engine's own full intensity rather than the effect-wide 50.
            - `intensity_keyframes` IntensityKeyframe[], nullable: Animate intensity over time (§2): piecewise-linear `[{time, value}]` in timeline seconds. Overrides the static `intensity` when set.
              - …
            - `props` object, nullable: Per-shader scalar props (§2), bound as `u_prop_<key>` (e.g. `{"speed": 0.6}` for aurora). Ignored for chroma_key (use `chroma_settings`).
            - `chroma_settings` ChromaKeyProps: Used when ``EffectType.CHROMA_KEY`` is selected. Keys against an explicit key **colour** in the YCbCr chroma plane, which is luma-independent, so shadows falling on the screen key out along with it. This replaced an hue/saturation/luminance-window shape that could not work. It was wired to ``effect_chroma.frag``, whose ``sensitivity`` is ``(hueMax - hueMin) * 0.5`` compared against an Oklab distance bounded around 0..0.9 — so the old defaults (60/180) produced a sensitivity of 60, discarded every pixel, and made the element vanish from the render. Nothing could have depended on the previous shape, because nothing rendered with it.
              - …
            - `shader` EffectShader: A runtime shader (render-node AEC §2) by its stored id. `POST /v1/shaders` compiles one from SkSL source; the render carries its compiled variants, so it renders on the farm and in the preview alike.
              - …
          - `motion` Motion[]
            - `type` 'identity' | 'fade' | 'slide_up' | 'slide_down' | 'slide_left' | 'slide_right' | 'zoom_in' | 'zoom_out' | 'rotate_cw' | 'rotate_ccw' | 'bounce' | 'wipe_left' | 'wipe_right' | 'wipe_up' | 'wipe_down' | 'ken_burns_in' | 'ken_burns_out' | 'ken_burns_in_out' | 'loop_wiggle' | 'loop_rotate' | 'loop_rotate_smooth' | 'loop_3d_spin' | 'loop_3d_sway' | 'blur' | 'evaporate' | 'overlay' | 'difference' | 'rubber_in' | 'whip_up' | 'whip_down' | 'glitch_pop' | 'drift_in' | 'drift_out' | 'loop_breathe' | 'loop_shimmer' | 'swing_in' | 'swing_out' | 'elastic_rise' | 'elastic_drop' | 'tilt_zoom' | 'loop_orbit' | 'smooth_pop': Values: - `identity` — Deliberate no-op carrier (no visible motion): attach a pure `audio` generator to any element without animating it. Element surfaces only. - `fade` — Fade in (entrance) or out (exit) via opacity. - `slide_up` — Slide in from below / out upward. - `slide_down` — Slide in from above / out downward. - `slide_left` — Slide in from the right / out to the left. - `slide_right` — Slide in from the left / out to the right. - `zoom_in` — Scale up from small to full size (entrance). - `zoom_out` — Scale down to small (exit). - `rotate_cw` — Spin in/out clockwise. - `rotate_ccw` — Spin in/out counter-clockwise. - `bounce` — Bounce in with an elastic overshoot / bounce out. - `wipe_left` — Reveal/conceal with a left-moving wipe. - `wipe_right` — Reveal/conceal with a right-moving wipe. - `wipe_up` — Reveal/conceal with an upward wipe. - `wipe_down` — Reveal/conceal with a downward wipe. - `ken_burns_in` — Slow zoom-in pan (Ken Burns) — entrance only. - `ken_burns_out` — Slow zoom-out pan (Ken Burns) — entrance only. - `ken_burns_in_out` — Slow zoom in then out (Ken Burns) — entrance only. - `loop_wiggle` — Continuous subtle wiggle (looping). - `loop_rotate` — Continuous stepped rotation (looping). - `loop_rotate_smooth` — Continuous smooth rotation (looping). - `loop_3d_spin` — Continuous 3D spin (looping). - `loop_3d_sway` — Continuous 3D sway (looping). - `blur` — Per-glyph soft blur-in (text entrance). - `evaporate` — Per-glyph rise, blur, and fade-out (text exit only). - `overlay` — Static Overlay blend fill (timing ignored). - `difference` — Static Difference blend fill (timing ignored). - `rubber_in` — Per-glyph rubbery overshoot as text springs in (text entrance). - `whip_up` — Per-glyph whip upward into place (text entrance). - `whip_down` — Per-glyph whip downward out of frame (text exit only). - `glitch_pop` — Per-glyph glitchy pop-in with jitter (text entrance). - `drift_in` — Per-glyph gentle drift and fade in (text entrance). - `drift_out` — Per-glyph gentle drift and fade out (text exit only). - `loop_breathe` — Per-glyph continuous breathing scale loop (text). - `loop_shimmer` — Per-glyph continuous shimmer loop (text). - `swing_in` — Element swings into place from an angle (entrance). - `swing_out` — Element swings away out of frame (exit only). - `elastic_rise` — Element rises with an elastic overshoot (entrance). - `elastic_drop` — Element drops away with an elastic recoil (exit only). - `tilt_zoom` — Element tilts and zooms into place (entrance). - `loop_orbit` — Element orbits continuously around its center (loop). - `smooth_pop` — Element pops in from 60% scale, overshooting slightly past full size before it settles, as it fades in (entrance).
            - `preset` string, nullable: Renderer animation name, used verbatim — any element animation on video/image/shape/group (e.g. `'pop'`, `'floatUp'`, `'out-slideBounceLeft'`, `'loop-heartBeat'`), any text animation on text (e.g. `'typewriter'`, `'roll'`, `'out-sink'`, `'loop-wavey'`). Reaches the presets `type` has no name for. The name carries its own direction: `out-*` names are exits, `loop-*` names loop with `duration` as one cycle, so `reversed` and `scope` do not apply. Exactly one of `type`, `preset` or `custom` must be set.
            - `custom` string, nullable: Name of a `custom_animations` entry to run instead of a catalog preset — the `element` registry for video/image/shape/group animations, the `text` registry for text. Exactly one of `type`, `preset` or `custom` must be set.
            - `time` number, required: Absolute start time on the output timeline in seconds. For entrances and loops set this to the element's `time`. For exits set this to element `time + duration − motion duration`. An entrance timed later than the element's own `time` leaves it fully rendered on screen until the entrance fires; the linter reports that as `ENTRANCE_AFTER_ELEMENT_START`.
            - `duration` number, required: How long the animation runs in seconds.
            - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
            - `reversed` boolean: Run the preset's exit form instead of its entrance. Only presets that ship both forms accept it — `fade`, `slide_*`, `wipe_*`, `rotate_*`, `bounce`. Entrance-only presets have a separate exit-only type instead: use `zoom_out` (not `zoom_in` reversed), `evaporate` (not `blur`), `whip_down`, `drift_out`, `swing_out`, `elastic_drop` — those six set this flag for you. See `GET /v1/capabilities` `motion[].element_exit` for the per-preset truth.
            - `scope` 'element' | 'character': Whether a motion preset applies to the whole element or per-glyph (text only). Values: - `element` — The motion animates the whole element as one unit. - `character` — The motion animates each text glyph individually (text only).
            - `delay` number: Seconds to wait before the animation starts (folded into the animation's start time on the wire — the engine has no standalone pre-start delay). On loop presets it spaces the repeats instead.
            - `spacing` number, nullable: Stagger multiplier between per-glyph/word windows on text animations (engine default 1 = fully sequential; smaller values overlap the windows). Ignored by block animations.
            - `loop` boolean
            - `audio` AudioGenerator: Audio-reactive property offsets driven by the soundtrack FFT (§3, W2). Each frame the mix reduces to the chosen feature and the element's properties get offset by ``amount × feature`` — beat-bounce, bass-pumped scale, etc.
              - …
        - ChildTextElement: A text inside a frame; `width` is its wrap width.
          - `border_radius` union: Corner radius in pixels — a single value, or per-corner `{top_left, top_right, bottom_right, bottom_left}` for asymmetric corners (e.g. a card rounded only on top). The renderer normalizes px to a 0–1 fraction of the element's shorter side (≈ half the shorter side is fully rounded) and clamps to that range. For shape elements use `corner_radius` (already 0–1).
            - integer
            - number
            - string
            - CornerRadiiPx: Per-corner radii in pixels (for `border_radius` on video/image/text elements).
              - …
          - `border_color` string, nullable
          - `border_width` union: Border thickness in pixels (converted to the renderer's relative border scale against the element's shorter side, so it survives resizes). The border outlines the element's border_radius-rounded quad — not the image's alpha silhouette.
            - integer
            - number
            - string
          - `shadow_color` string, nullable
          - `shadow_blur` union: Shadow softness, 0–100 (renderer blur-strength scale, not pixels): 0 = hard edge, 100 = maximum blur. Values are clamped to that range.
            - integer
            - number
            - string
          - `shadow_x` union: Horizontal shadow offset in pixels (converted to the renderer's relative offset scale). The shadow silhouette is the element's border_radius-rounded quad, not the content alpha — a cut-out PNG gets a card shadow, not an outline-shaped one. On a cut-out that reads as a floating rectangle (rotated with the element, which is the tell). For a shadow that follows the artwork, drop these fields and stack a second copy of the same image underneath at `brightness: -100` (a black silhouette, alpha preserved) with `blur` and reduced `opacity`, offset a few percent — see `brightness`.
            - integer
            - number
            - string
          - `shadow_y` union: Vertical shadow offset in pixels. See `shadow_x`.
            - integer
            - number
            - string
          - `x` number, nullable: Left edge in design px from the frame's left edge. Omitted: 0.
          - `y` number, nullable: Top edge in design px from the frame's top edge. Omitted: 0.
          - `width` number, nullable: Width in design px. Omitted: the frame's width.
          - `height` number, nullable: Height in design px. Omitted: the frame's height (a text's: twice its `font_size`).
          - `aspect_ratio` number, nullable: **Accepted but ignored — the renderer never receives this field.** It does NOT constrain or correct the `width`/`height` box, so it cannot be used to stop a mismatched box from cropping the source; size the box per `width` instead. Kept for backward compatibility.
          - `x_anchor` union: Pivot the element turns and scales about, across its own box: a percent, or design px from its left edge.
            - integer
            - number
            - string
          - `y_anchor` union: Pivot across its own box's height: a percent, or design px from its top edge.
            - integer
            - number
            - string
          - `x_rotation` union
            - integer
            - number
            - string
          - `y_rotation` union
            - integer
            - number
            - string
          - `z_rotation` union
            - integer
            - number
            - string
          - `x_scale` union
            - integer
            - number
            - string
          - `y_scale` union
            - integer
            - number
            - string
          - `flip_horizontal` boolean
          - `flip_vertical` boolean
          - `opacity` number
          - `z_index` integer, nullable: Stacking order among the frame's children (higher on top); ties draw in array order.
          - `clip` boolean
          - `color_overlay` string, nullable: **Not supported by the renderer — setting this is rejected.** A strict submit returns `unsupported_feature` (422) and a dry-run reports it as a blocking violation; there is no native tint field to map it onto. To darken an element use `brightness` (`-100` is a black silhouette); to lay a colour over one, stack a `shape` with a flat or gradient `fill` above it.
          - `type` 'text'
          - `id` string, nullable: Unique identifier for this element. **Required on image elements** — an empty or missing ID causes the image to be silently skipped by the renderer. Recommended on all elements that are referenced by a transition.
          - `name` string, nullable: Optional human-readable label. Not used by the renderer.
          - `track` integer, nullable: Timeline track index (0–255). Informational only; not used by the renderer.
          - `time` number, nullable: Start in seconds on the clock the frame gives its children (the composition's, unless a composite frame maps it; inside a component, 0 is the instance's start). Omitted: the frame's start.
          - `visible` boolean: Set to `false` to skip this element without removing it from the request.
          - `locked` boolean: Marks the element locked in editors. Not sent to the renderer.
          - `duration` number, nullable: Seconds visible. Omitted: until the frame ends.
          - `text` string, required: The text content to render.
          - `font_family` string: Font family name. Must be available to the renderer.
          - `font_size` number: Font size in pixels.
          - `font_weight` integer: Font weight (100–900). The renderer has no variable weights: `600` and above render **bold**, everything below renders regular. Composes with `font_style` (italic + ≥600 = bold italic).
          - `font_style` 'normal' | 'italic' | 'bold' | 'bolditalic': Font style variant.
          - `text_color` string: Text fill color as a hex string.
          - `text_align` 'left' | 'center' | 'right': Horizontal text alignment.
          - `text_direction` 'ltr' | 'rtl': Text direction. `rtl` for right-to-left scripts (§4).
          - `text_decoration` 'none' | 'underline' | 'strikethrough': Text decoration. Only `none` renders. `underline` is reachable only per word — `words[].style.underline` — and `strikethrough` has no renderer path at all; both are rejected here (422) rather than silently dropped. Draw a strike-through as a thin `shape` rectangle over the text.
          - `tracking` number: Letter spacing (tracking) in pixels (converted to the renderer's width-relative unit on the wire). Positive values add space between characters.
          - `tabular_numbers` boolean: Tabular (monospaced) figures: every digit takes the same advance, so columns of numbers align across lines and a `counter` does not jitter as its value changes. The renderer's baked fonts carry the OpenType alternates; a font whose face lacks the feature gets synthesised tabular digits in the export only. Default `false` = the font's proportional figures.
          - `leading` number: Line height (leading) as a multiplier of font size. `1.2` = 20% taller than the font size.
          - `stroke_color` string, nullable: Outline color. Set together with `stroke_width` to enable text outlines.
          - `stroke_width` number: Outline width, em-relative (fraction of `font_size` — e.g. `0.05` = 5% of the font size). Has no effect unless `stroke_color` is also set.
          - `background_color` string, nullable: Secondary colour. Fills the box behind the text when `background` is `true`, **and** is the highlight colour for `word_animation.style` `color` (the active word) and `box` (the box) — those two styles require it.
          - `background_opacity` number
          - `x_padding` union
            - integer
            - number
            - string
          - `y_padding` union
            - integer
            - number
            - string
          - `background` boolean: Solid color box behind the full text block. Set `background_color` to choose the color.
          - `background_style` 'block' | 'line_hard' | 'line_round': Shape of the `background` plate: `block` — one box behind the whole text; `line_hard` — a square-cornered box behind each line; `line_round` — a rounded box behind each line. Requires `background: true`. An animation that centres its words draws the `block` plate whichever style is set.
          - `stroke` boolean: Outline-only mode — draws the glyph stroke with no fill. Requires `stroke_color` and `stroke_width`. When `false`, setting `stroke_color` + `stroke_width` gives fill + stroke (outlined).
          - `shadow` boolean: Built-in drop shadow.
          - `motion` Motion[]
            - `type` 'identity' | 'fade' | 'slide_up' | 'slide_down' | 'slide_left' | 'slide_right' | 'zoom_in' | 'zoom_out' | 'rotate_cw' | 'rotate_ccw' | 'bounce' | 'wipe_left' | 'wipe_right' | 'wipe_up' | 'wipe_down' | 'ken_burns_in' | 'ken_burns_out' | 'ken_burns_in_out' | 'loop_wiggle' | 'loop_rotate' | 'loop_rotate_smooth' | 'loop_3d_spin' | 'loop_3d_sway' | 'blur' | 'evaporate' | 'overlay' | 'difference' | 'rubber_in' | 'whip_up' | 'whip_down' | 'glitch_pop' | 'drift_in' | 'drift_out' | 'loop_breathe' | 'loop_shimmer' | 'swing_in' | 'swing_out' | 'elastic_rise' | 'elastic_drop' | 'tilt_zoom' | 'loop_orbit' | 'smooth_pop': Values: - `identity` — Deliberate no-op carrier (no visible motion): attach a pure `audio` generator to any element without animating it. Element surfaces only. - `fade` — Fade in (entrance) or out (exit) via opacity. - `slide_up` — Slide in from below / out upward. - `slide_down` — Slide in from above / out downward. - `slide_left` — Slide in from the right / out to the left. - `slide_right` — Slide in from the left / out to the right. - `zoom_in` — Scale up from small to full size (entrance). - `zoom_out` — Scale down to small (exit). - `rotate_cw` — Spin in/out clockwise. - `rotate_ccw` — Spin in/out counter-clockwise. - `bounce` — Bounce in with an elastic overshoot / bounce out. - `wipe_left` — Reveal/conceal with a left-moving wipe. - `wipe_right` — Reveal/conceal with a right-moving wipe. - `wipe_up` — Reveal/conceal with an upward wipe. - `wipe_down` — Reveal/conceal with a downward wipe. - `ken_burns_in` — Slow zoom-in pan (Ken Burns) — entrance only. - `ken_burns_out` — Slow zoom-out pan (Ken Burns) — entrance only. - `ken_burns_in_out` — Slow zoom in then out (Ken Burns) — entrance only. - `loop_wiggle` — Continuous subtle wiggle (looping). - `loop_rotate` — Continuous stepped rotation (looping). - `loop_rotate_smooth` — Continuous smooth rotation (looping). - `loop_3d_spin` — Continuous 3D spin (looping). - `loop_3d_sway` — Continuous 3D sway (looping). - `blur` — Per-glyph soft blur-in (text entrance). - `evaporate` — Per-glyph rise, blur, and fade-out (text exit only). - `overlay` — Static Overlay blend fill (timing ignored). - `difference` — Static Difference blend fill (timing ignored). - `rubber_in` — Per-glyph rubbery overshoot as text springs in (text entrance). - `whip_up` — Per-glyph whip upward into place (text entrance). - `whip_down` — Per-glyph whip downward out of frame (text exit only). - `glitch_pop` — Per-glyph glitchy pop-in with jitter (text entrance). - `drift_in` — Per-glyph gentle drift and fade in (text entrance). - `drift_out` — Per-glyph gentle drift and fade out (text exit only). - `loop_breathe` — Per-glyph continuous breathing scale loop (text). - `loop_shimmer` — Per-glyph continuous shimmer loop (text). - `swing_in` — Element swings into place from an angle (entrance). - `swing_out` — Element swings away out of frame (exit only). - `elastic_rise` — Element rises with an elastic overshoot (entrance). - `elastic_drop` — Element drops away with an elastic recoil (exit only). - `tilt_zoom` — Element tilts and zooms into place (entrance). - `loop_orbit` — Element orbits continuously around its center (loop). - `smooth_pop` — Element pops in from 60% scale, overshooting slightly past full size before it settles, as it fades in (entrance).
            - `preset` string, nullable: Renderer animation name, used verbatim — any element animation on video/image/shape/group (e.g. `'pop'`, `'floatUp'`, `'out-slideBounceLeft'`, `'loop-heartBeat'`), any text animation on text (e.g. `'typewriter'`, `'roll'`, `'out-sink'`, `'loop-wavey'`). Reaches the presets `type` has no name for. The name carries its own direction: `out-*` names are exits, `loop-*` names loop with `duration` as one cycle, so `reversed` and `scope` do not apply. Exactly one of `type`, `preset` or `custom` must be set.
            - `custom` string, nullable: Name of a `custom_animations` entry to run instead of a catalog preset — the `element` registry for video/image/shape/group animations, the `text` registry for text. Exactly one of `type`, `preset` or `custom` must be set.
            - `time` number, required: Absolute start time on the output timeline in seconds. For entrances and loops set this to the element's `time`. For exits set this to element `time + duration − motion duration`. An entrance timed later than the element's own `time` leaves it fully rendered on screen until the entrance fires; the linter reports that as `ENTRANCE_AFTER_ELEMENT_START`.
            - `duration` number, required: How long the animation runs in seconds.
            - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
            - `reversed` boolean: Run the preset's exit form instead of its entrance. Only presets that ship both forms accept it — `fade`, `slide_*`, `wipe_*`, `rotate_*`, `bounce`. Entrance-only presets have a separate exit-only type instead: use `zoom_out` (not `zoom_in` reversed), `evaporate` (not `blur`), `whip_down`, `drift_out`, `swing_out`, `elastic_drop` — those six set this flag for you. See `GET /v1/capabilities` `motion[].element_exit` for the per-preset truth.
            - `scope` 'element' | 'character': Whether a motion preset applies to the whole element or per-glyph (text only). Values: - `element` — The motion animates the whole element as one unit. - `character` — The motion animates each text glyph individually (text only).
            - `delay` number: Seconds to wait before the animation starts (folded into the animation's start time on the wire — the engine has no standalone pre-start delay). On loop presets it spaces the repeats instead.
            - `spacing` number, nullable: Stagger multiplier between per-glyph/word windows on text animations (engine default 1 = fully sequential; smaller values overlap the windows). Ignored by block animations.
            - `loop` boolean
            - `audio` AudioGenerator: Audio-reactive property offsets driven by the soundtrack FFT (§3, W2). Each frame the mix reduces to the chosen feature and the element's properties get offset by ``amount × feature`` — beat-bounce, bass-pumped scale, etc.
              - …
          - `word_animation` WordAnimation
            - `style` 'glow' | 'box' | 'scale_pop' | 'slide_up' | 'fly_in' | 'color', required: [API extension] Word-level animations (require word_animation.words). Values: - `glow` — Highlights the active word with a glowing emphasis. - `box` — Draws a colored box behind the active word. - `scale_pop` — Pops the active word with a quick scale punch. - `slide_up` — Floats each word up into place as it becomes active. - `fly_in` — Drops each word in from above as it becomes active. - `color` — Recolors the active word (karaoke-style highlight).
            - `words` Word[], required
              - …
          - `words` WordSpec[], nullable: Per-word timing and optional per-word style overrides (§4). Emitted as a top-level `words[]` array; use alongside `motion`/`animation_preset` for the animation. Editorial-emphasis captions = word timings + a styled keyword.
            - `word` string, required: The word (whole-word match; UTF-8).
            - `start` number, required: Word reveal start, seconds — drives a word-group animation; ignored without one.
            - `end` number, required: Word reveal end, seconds — drives a word-group animation; ignored without one.
            - `style` WordStyle: Per-word style override (§4 W3). Whole-word matches only.
              - …
          - `counter` ValueCounter: Rewrite a text element from an eased numeric sweep (the animated stat hero, §4).
            - `from_value` number: Start value.
            - `to_value` number: End value.
            - `decimals` integer: Decimal places (0–6).
            - `prefix` string: Text prepended to the number.
            - `suffix` string: Text appended to the number, e.g. '%'.
            - `easing` string, nullable: Easing curve name from the `easings` catalog (e.g. 'quad_out', 'expo_out'). Only named curves apply here — the parameterized spring/back/elastic families are not available on the counter.
            - `start_time` number: Seconds into the element to start the sweep.
            - `length` number, nullable: Sweep duration; defaults to the element's remaining life.
          - `glow` TextGlow: Soft glow around the glyphs (§4).
            - `color` string, required
            - `size` number: Glow size, em-relative.
            - `intensity` number: Glow intensity.
          - `text_wrap` 'wrap' | 'nowrap'
          - `animation_preset` string, nullable: Renderer text-animation name (e.g. `'typewriter'`) — a catalog text animation or a `custom_animations.text` entry. Runs for the whole element window with per-glyph timings computed by the renderer. Use `motion[]` (with `type`, `preset` or `custom`) for structured timing control — but not both. Ignored when `word_animation` is set.
        - ChildImageElement: An image inside a frame.
          - `lut_url` string, uri, nullable
          - `lut_intensity` number
          - `brightness` number: Brightness, -100..100, applied as a 0..2 colour multiplier (0 = no change). `-100` multiplies by 0: the element renders pure black while keeping its alpha — a silhouette of the artwork. Combine a `brightness: -100` copy of an image with `blur`, reduced `opacity` and a small offset, stacked beneath the real one, to fake the content-shaped drop shadow `shadow_x`/`shadow_y` cannot produce.
          - `contrast` number
          - `saturation` number
          - `exposure` number
          - `sharpness` number
          - `blur` number
          - `noise` number
          - `vignette` number
          - `hue_rotate` number
          - `temperature` number: White balance warm (+) / cool (−), −1..1; 0 = no-op. Applied as a channel matrix, after the classic brightness/contrast chain.
          - `tint` number: White balance magenta (+) / green (−), −1..1; 0 = no-op.
          - `vibrance` number: Saturation boost weighted toward muted colours, −1..1; 0 = no-op. Boosts flat colour without wrecking skin tones.
          - `highlights` number: Luma-masked tone lift of the brightest range, −1..1; 0 = no-op.
          - `shadows` number: Luma-masked tone lift of the darkest range, −1..1; 0 = no-op.
          - `crop_top` number
          - `crop_bottom` number
          - `crop_left` number
          - `crop_right` number
          - `border_radius` union: Corner radius in pixels — a single value, or per-corner `{top_left, top_right, bottom_right, bottom_left}` for asymmetric corners (e.g. a card rounded only on top). The renderer normalizes px to a 0–1 fraction of the element's shorter side (≈ half the shorter side is fully rounded) and clamps to that range. For shape elements use `corner_radius` (already 0–1).
            - integer
            - number
            - string
            - CornerRadiiPx: Per-corner radii in pixels (for `border_radius` on video/image/text elements).
              - …
          - `border_color` string, nullable
          - `border_width` union: Border thickness in pixels (converted to the renderer's relative border scale against the element's shorter side, so it survives resizes). The border outlines the element's border_radius-rounded quad — not the image's alpha silhouette.
            - integer
            - number
            - string
          - `shadow_color` string, nullable
          - `shadow_blur` union: Shadow softness, 0–100 (renderer blur-strength scale, not pixels): 0 = hard edge, 100 = maximum blur. Values are clamped to that range.
            - integer
            - number
            - string
          - `shadow_x` union: Horizontal shadow offset in pixels (converted to the renderer's relative offset scale). The shadow silhouette is the element's border_radius-rounded quad, not the content alpha — a cut-out PNG gets a card shadow, not an outline-shaped one. On a cut-out that reads as a floating rectangle (rotated with the element, which is the tell). For a shadow that follows the artwork, drop these fields and stack a second copy of the same image underneath at `brightness: -100` (a black silhouette, alpha preserved) with `blur` and reduced `opacity`, offset a few percent — see `brightness`.
            - integer
            - number
            - string
          - `shadow_y` union: Vertical shadow offset in pixels. See `shadow_x`.
            - integer
            - number
            - string
          - `blend_mode` 'none' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color_dodge' | 'color_burn' | 'hard_light' | 'soft_light' | 'difference' | 'add' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity': Values: - `none` — Normal compositing (source-over) — the default. - `multiply` — Multiply blend — darkens by multiplying layer colors. - `screen` — Screen blend — lightens by inverting, multiplying, inverting. - `overlay` — Overlay blend — multiply in shadows, screen in highlights. - `darken` — Darken blend — keeps the darker of the two layers per channel. - `lighten` — Lighten blend — keeps the lighter of the two layers per channel. - `color_dodge` — Color-dodge blend — brightens the base toward the blend color. - `color_burn` — Color-burn blend — darkens the base toward the blend color. - `hard_light` — Hard-light blend — overlay with layers swapped. - `soft_light` — Soft-light blend — a gentler hard-light. - `difference` — Difference blend — absolute difference of the two layers per channel. - `add` — Additive (linear-dodge) blend — sums layer colors, clamped. - `exclusion` — Exclusion blend — like difference, lower contrast. - `hue` — Hue blend — backdrop luminosity + saturation with the blend layer's hue. - `saturation` — Saturation blend — backdrop hue + luminosity with the blend layer's saturation. - `color` — Color blend — backdrop luminosity with the blend layer's hue + saturation. - `luminosity` — Luminosity blend — backdrop hue + saturation with the blend layer's luminosity.
          - `mask_shape` 'circle' | 'diamond' | 'hexagon' | 'star' | 'heart' | 'triangle': Analytic (SDF) shape mask that clips an element's coverage. §1. Values: - `circle` — Circular (ellipse) analytic mask, fit to the element bounds. - `diamond` — Diamond (rotated square) analytic mask. - `hexagon` — Regular hexagon analytic mask. - `star` — Five-point star analytic mask. - `heart` — Heart analytic mask. - `triangle` — Upward triangle analytic mask.
          - `mask` MaskConfig: Animated/feathered mask params layered on the analytic `mask_shape` (§5c).
            - `feather` number: Soften the mask's SDF edge.
            - `scale` number: Mask scale (iris reveals).
            - `center` Point
              - …
          - `mask_keyframes` MaskKeyframe[], nullable
            - `time` number, required: Timeline seconds.
            - `feather` number, nullable
            - `scale` number, nullable
            - `center` Point
              - …
            - `easing` string, nullable: Easing curve name — any `easings` catalog value (`linear`, `hold`, `ease_in_out`, `quad_out`, `expo_in_out`, `square_in_out` = step, …). Unknown names are rejected: the engine would silently fall back to linear. For spring/back/elastic/bezier use the sub-objects instead.
            - `spring` SpringEasing: Damped-spring ease over the keyframe segment. Only the damping ratio zeta = damping / (2 * sqrt(stiffness * mass)) shapes the curve; the segment's duration sets its timing. Below 1 the spring overshoots and rings (the defaults give zeta = 0.5); at 1 or above it settles without overshoot. An underdamped spring runs until its envelope decays to 0.1% (settle x w0 = ln(1000) / zeta, w0 = sqrt(stiffness / mass)). Since render-node's overdamped settle fix (GVR M3), a spring at zeta >= 1 runs over its slowest decay rate instead; before it, an overdamped spring's window was cut short and it reached the target still moving.
              - …
            - `back` BackEasing: Anticipate/overshoot ease (AE 'back').
              - …
            - `elastic` ElasticEasing: Elastic ring-out/ring-in ease.
              - …
            - `bezier` BezierEasing: CSS cubic-bezier(x1, y1, x2, y2) timing curve.
              - …
          - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
            - `source` string, required: uuid of the source layer (auto-hidden). Text sources supported.
            - `mode` 'alpha' | 'luma'
            - `invert` boolean
          - `backdrop_blur` union: Glass: the scene behind the element, Gaussian-blurred, fills its footprint under its translucent content (a shape's own silhouette, a video's or image's box with its corner radius and mask). A Gaussian sigma in canvas px, as CSS `backdrop-filter: blur()` takes it; the renderer caps it at 128. 0 is off.
            - integer
            - number
            - string
          - `backdrop_blur_keyframes` BlurKeyframe[], nullable: Animate `backdrop_blur` over the timeline; replaces the static value while present.
            - `time` number, required: Timeline seconds.
            - `value` number, required: Gaussian sigma in canvas px at `time`, at most 128.
          - `layer_blur` number: Blurs the element itself as drawn: a Gaussian sigma in canvas px, as CSS `filter: blur()` takes it, spreading three sigma past its box. At most 128; 0 is off. Not on a shape yet (the editor's preview cannot draw it), and not with `blend_mode`, `backdrop_blur` or `matte`, beside which the renderer would draw the element without it.
          - `layer_blur_keyframes` BlurKeyframe[], nullable: Animate `layer_blur` over the timeline; replaces the static value while present.
            - `time` number, required: Timeline seconds.
            - `value` number, required: Gaussian sigma in canvas px at `time`, at most 128.
          - `glass` Glass: A refracting glass surface (V6, render-node AEC §1): within `bevel` px of the element's edge (a shape's own outline, a box's rounded corners) the scene behind is read inward, bent by `refraction`, its red and blue split by `dispersion`. With `backdrop_blur` it bends the blurred scene, without it the sharp one.
            - `bevel` number, nullable: Width of the bent band at the edge in canvas px, at most 256. Omitted: 16.
            - `refraction` number, nullable: How far the edge bends the scene inward, 0–1. Omitted: 0.5.
            - `dispersion` number, nullable: How far red and blue split apart at the edge, 0–1. Omitted: 0.
          - `x` number, nullable: Left edge in design px from the frame's left edge. Omitted: 0.
          - `y` number, nullable: Top edge in design px from the frame's top edge. Omitted: 0.
          - `width` number, nullable: Width in design px. Omitted: the frame's width.
          - `height` number, nullable: Height in design px. Omitted: the frame's height (a text's: twice its `font_size`).
          - `aspect_ratio` number, nullable: **Accepted but ignored — the renderer never receives this field.** It does NOT constrain or correct the `width`/`height` box, so it cannot be used to stop a mismatched box from cropping the source; size the box per `width` instead. Kept for backward compatibility.
          - `x_anchor` union: Pivot the element turns and scales about, across its own box: a percent, or design px from its left edge.
            - integer
            - number
            - string
          - `y_anchor` union: Pivot across its own box's height: a percent, or design px from its top edge.
            - integer
            - number
            - string
          - `x_rotation` union
            - integer
            - number
            - string
          - `y_rotation` union
            - integer
            - number
            - string
          - `z_rotation` union
            - integer
            - number
            - string
          - `x_scale` union
            - integer
            - number
            - string
          - `y_scale` union
            - integer
            - number
            - string
          - `flip_horizontal` boolean
          - `flip_vertical` boolean
          - `opacity` number
          - `z_index` integer, nullable: Stacking order among the frame's children (higher on top); ties draw in array order.
          - `clip` boolean
          - `color_overlay` string, nullable: **Not supported by the renderer — setting this is rejected.** A strict submit returns `unsupported_feature` (422) and a dry-run reports it as a blocking violation; there is no native tint field to map it onto. To darken an element use `brightness` (`-100` is a black silhouette); to lay a colour over one, stack a `shape` with a flat or gradient `fill` above it.
          - `type` 'image'
          - `id` string, required: **Required.** Unique identifier for this image. An empty or missing ID causes the image to be silently skipped by the renderer.
          - `name` string, nullable: Optional human-readable label. Not used by the renderer.
          - `track` integer, nullable: Timeline track index (0–255). Informational only; not used by the renderer.
          - `time` number, nullable: Start in seconds on the clock the frame gives its children (the composition's, unless a composite frame maps it; inside a component, 0 is the instance's start). Omitted: the frame's start.
          - `visible` boolean: Set to `false` to skip this element without removing it from the request.
          - `locked` boolean: Marks the element locked in editors. Not sent to the renderer.
          - `duration` number, nullable: Seconds visible. Omitted: until the frame ends.
          - `source_url` string, uri, required: URL of the image file (PNG, JPG, WebP, GIF, SVG). A `.svg` draws a subset: groups and the basic shapes and paths, filled and stroked with flat colours. An element that uses anything else (a `style` attribute, `clip-path`, `mask`, `filter`, `stroke-dasharray`, a gradient or `currentColor` paint, `<text>`, `<use>`, `<image>`) is not drawn, nor anything inside it; an SVG that would draw nothing at all is refused at submit. Set explicit colours and presentation attributes, or pre-rasterize to PNG.
          - `effects` Effect[]
            - `type` 'vintage' | 'polaroid' | 'portra' | 'super8' | 'filmic' | 'add_grain' | 'rgb_split' | 'ghosting' | 'displacement_map' | 'posterize' | 'mosaic' | 'mosaic_blur' | 'mosaic_posterize' | 'cc_halftone' | 'cc_halftone_blue' | 'cc_halftone_green' | 'cc_halftone_red' | 'invert' | 'optics_compensation' | 'viewfinder' | 'night_vision' | 'thermal' | 'camera_lens_blur' | 'camera_lens_blur_bg' | 'box_blur' | 'lens_flare' | 'strobe_light' | 'snow' | 'glow' | 'sepia' | 'echo' | 'chromatic_aberration' | 'vhs' | 'vhs_overlay' | 'crt' | 'television' | 'glitch' | 'compression_glitch' | 'scanlines' | 'prism' | 'light_leaks' | 'film_burn' | 'duotone' | 'cross_process' | 'bleach_bypass' | 'chroma_key' | 'aurora': Values: - `vintage` — Faded, warm retro film look with lifted blacks. - `polaroid` — Instant-photo look — soft contrast, warm cast, subtle vignette. - `portra` — Kodak Portra-style film emulation with natural skin tones. - `super8` — Super-8 home-movie look — grain, gate weave, warm color. - `filmic` — Cinematic film grade with rolled-off highlights and rich contrast. - `add_grain` — Adds dusty analog film grain over the image. - `rgb_split` — Offsets the red/green/blue channels for a glitchy chromatic split. - `ghosting` — Trailing motion echoes, like persistence-of-vision smearing. - `displacement_map` — Warps the image with a displacement texture for a melted look. - `posterize` — Reduces the image to a small number of flat color bands. - `mosaic` — Pixelates the image into large mosaic blocks. - `mosaic_blur` — Pixelated mosaic with softened, blurred block edges. - `mosaic_posterize` — Combines mosaic pixelation with posterized colors. - `cc_halftone` — Comic-style halftone dot pattern. - `cc_halftone_blue` — Halftone dot pattern tinted blue. - `cc_halftone_green` — Halftone dot pattern tinted green. - `cc_halftone_red` — Halftone dot pattern tinted red. - `invert` — Inverts all colors (photo-negative). - `optics_compensation` — Fish-eye / lens-distortion warp. - `viewfinder` — Camera viewfinder overlay (REC indicator, framing marks). - `night_vision` — Green night-vision look with glow and noise. - `thermal` — Thermal-camera false-color heat map. - `camera_lens_blur` — Realistic bokeh lens blur across the frame. - `camera_lens_blur_bg` — Bokeh lens blur applied to the background only. - `box_blur` — Fast, uniform box blur. - `lens_flare` — Adds an anamorphic lens-flare streak and glints. - `strobe_light` — Rapid brightness strobing / flashing. - `snow` — Falling-snow particle overlay. - `glow` — Dreamy soft-glow bloom over highlights. - `sepia` — Sepia-toned monochrome with a vignette. - `echo` — Soft ghosted dream-echo overlay. - `chromatic_aberration` — Color-fringing at edges, like cheap-lens dispersion. - `vhs` — VHS tape look: tracking noise, color bleed, and wobble. - `vhs_overlay` — VHS noise/scanline layer composited over the source. - `crt` — CRT monitor look: screen curvature, scanlines, and phosphor glow. - `television` — Analog TV look: scanlines, static, and signal distortion. - `glitch` — Digital glitch: block displacement and channel tearing. - `compression_glitch` — MPEG compression artifacts: blocky macroblocks and datamosh. - `scanlines` — Horizontal scanlines overlaid on the image. - `prism` — Prismatic light refraction with a rainbow color split. - `light_leaks` — Warm light-leak streaks bleeding across the frame. - `film_burn` — Burning-film look with scorched edges and flares. - `duotone` — Two-tone color map (shadows to one hue, highlights to another). - `cross_process` — Cross-processed film look with shifted, punchy colors. - `bleach_bypass` — High-contrast, desaturated bleach-bypass film grade. - `chroma_key` — Keys out a color (green/blue screen); tune via `chroma_settings`. - `aurora` — Animated domain-warped fluid-gradient wash (§6); tune flow via `props` speed.
            - `intensity` number, nullable: Effect strength, 0 to 100. On a shader effect it is null unless set: the shader then runs at the engine's own full intensity rather than the effect-wide 50.
            - `intensity_keyframes` IntensityKeyframe[], nullable: Animate intensity over time (§2): piecewise-linear `[{time, value}]` in timeline seconds. Overrides the static `intensity` when set.
              - …
            - `props` object, nullable: Per-shader scalar props (§2), bound as `u_prop_<key>` (e.g. `{"speed": 0.6}` for aurora). Ignored for chroma_key (use `chroma_settings`).
            - `chroma_settings` ChromaKeyProps: Used when ``EffectType.CHROMA_KEY`` is selected. Keys against an explicit key **colour** in the YCbCr chroma plane, which is luma-independent, so shadows falling on the screen key out along with it. This replaced an hue/saturation/luminance-window shape that could not work. It was wired to ``effect_chroma.frag``, whose ``sensitivity`` is ``(hueMax - hueMin) * 0.5`` compared against an Oklab distance bounded around 0..0.9 — so the old defaults (60/180) produced a sensitivity of 60, discarded every pixel, and made the element vanish from the render. Nothing could have depended on the previous shape, because nothing rendered with it.
              - …
            - `shader` EffectShader: A runtime shader (render-node AEC §2) by its stored id. `POST /v1/shaders` compiles one from SkSL source; the render carries its compiled variants, so it renders on the farm and in the preview alike.
              - …
          - `motion` Motion[]
            - `type` 'identity' | 'fade' | 'slide_up' | 'slide_down' | 'slide_left' | 'slide_right' | 'zoom_in' | 'zoom_out' | 'rotate_cw' | 'rotate_ccw' | 'bounce' | 'wipe_left' | 'wipe_right' | 'wipe_up' | 'wipe_down' | 'ken_burns_in' | 'ken_burns_out' | 'ken_burns_in_out' | 'loop_wiggle' | 'loop_rotate' | 'loop_rotate_smooth' | 'loop_3d_spin' | 'loop_3d_sway' | 'blur' | 'evaporate' | 'overlay' | 'difference' | 'rubber_in' | 'whip_up' | 'whip_down' | 'glitch_pop' | 'drift_in' | 'drift_out' | 'loop_breathe' | 'loop_shimmer' | 'swing_in' | 'swing_out' | 'elastic_rise' | 'elastic_drop' | 'tilt_zoom' | 'loop_orbit' | 'smooth_pop': Values: - `identity` — Deliberate no-op carrier (no visible motion): attach a pure `audio` generator to any element without animating it. Element surfaces only. - `fade` — Fade in (entrance) or out (exit) via opacity. - `slide_up` — Slide in from below / out upward. - `slide_down` — Slide in from above / out downward. - `slide_left` — Slide in from the right / out to the left. - `slide_right` — Slide in from the left / out to the right. - `zoom_in` — Scale up from small to full size (entrance). - `zoom_out` — Scale down to small (exit). - `rotate_cw` — Spin in/out clockwise. - `rotate_ccw` — Spin in/out counter-clockwise. - `bounce` — Bounce in with an elastic overshoot / bounce out. - `wipe_left` — Reveal/conceal with a left-moving wipe. - `wipe_right` — Reveal/conceal with a right-moving wipe. - `wipe_up` — Reveal/conceal with an upward wipe. - `wipe_down` — Reveal/conceal with a downward wipe. - `ken_burns_in` — Slow zoom-in pan (Ken Burns) — entrance only. - `ken_burns_out` — Slow zoom-out pan (Ken Burns) — entrance only. - `ken_burns_in_out` — Slow zoom in then out (Ken Burns) — entrance only. - `loop_wiggle` — Continuous subtle wiggle (looping). - `loop_rotate` — Continuous stepped rotation (looping). - `loop_rotate_smooth` — Continuous smooth rotation (looping). - `loop_3d_spin` — Continuous 3D spin (looping). - `loop_3d_sway` — Continuous 3D sway (looping). - `blur` — Per-glyph soft blur-in (text entrance). - `evaporate` — Per-glyph rise, blur, and fade-out (text exit only). - `overlay` — Static Overlay blend fill (timing ignored). - `difference` — Static Difference blend fill (timing ignored). - `rubber_in` — Per-glyph rubbery overshoot as text springs in (text entrance). - `whip_up` — Per-glyph whip upward into place (text entrance). - `whip_down` — Per-glyph whip downward out of frame (text exit only). - `glitch_pop` — Per-glyph glitchy pop-in with jitter (text entrance). - `drift_in` — Per-glyph gentle drift and fade in (text entrance). - `drift_out` — Per-glyph gentle drift and fade out (text exit only). - `loop_breathe` — Per-glyph continuous breathing scale loop (text). - `loop_shimmer` — Per-glyph continuous shimmer loop (text). - `swing_in` — Element swings into place from an angle (entrance). - `swing_out` — Element swings away out of frame (exit only). - `elastic_rise` — Element rises with an elastic overshoot (entrance). - `elastic_drop` — Element drops away with an elastic recoil (exit only). - `tilt_zoom` — Element tilts and zooms into place (entrance). - `loop_orbit` — Element orbits continuously around its center (loop). - `smooth_pop` — Element pops in from 60% scale, overshooting slightly past full size before it settles, as it fades in (entrance).
            - `preset` string, nullable: Renderer animation name, used verbatim — any element animation on video/image/shape/group (e.g. `'pop'`, `'floatUp'`, `'out-slideBounceLeft'`, `'loop-heartBeat'`), any text animation on text (e.g. `'typewriter'`, `'roll'`, `'out-sink'`, `'loop-wavey'`). Reaches the presets `type` has no name for. The name carries its own direction: `out-*` names are exits, `loop-*` names loop with `duration` as one cycle, so `reversed` and `scope` do not apply. Exactly one of `type`, `preset` or `custom` must be set.
            - `custom` string, nullable: Name of a `custom_animations` entry to run instead of a catalog preset — the `element` registry for video/image/shape/group animations, the `text` registry for text. Exactly one of `type`, `preset` or `custom` must be set.
            - `time` number, required: Absolute start time on the output timeline in seconds. For entrances and loops set this to the element's `time`. For exits set this to element `time + duration − motion duration`. An entrance timed later than the element's own `time` leaves it fully rendered on screen until the entrance fires; the linter reports that as `ENTRANCE_AFTER_ELEMENT_START`.
            - `duration` number, required: How long the animation runs in seconds.
            - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
            - `reversed` boolean: Run the preset's exit form instead of its entrance. Only presets that ship both forms accept it — `fade`, `slide_*`, `wipe_*`, `rotate_*`, `bounce`. Entrance-only presets have a separate exit-only type instead: use `zoom_out` (not `zoom_in` reversed), `evaporate` (not `blur`), `whip_down`, `drift_out`, `swing_out`, `elastic_drop` — those six set this flag for you. See `GET /v1/capabilities` `motion[].element_exit` for the per-preset truth.
            - `scope` 'element' | 'character': Whether a motion preset applies to the whole element or per-glyph (text only). Values: - `element` — The motion animates the whole element as one unit. - `character` — The motion animates each text glyph individually (text only).
            - `delay` number: Seconds to wait before the animation starts (folded into the animation's start time on the wire — the engine has no standalone pre-start delay). On loop presets it spaces the repeats instead.
            - `spacing` number, nullable: Stagger multiplier between per-glyph/word windows on text animations (engine default 1 = fully sequential; smaller values overlap the windows). Ignored by block animations.
            - `loop` boolean
            - `audio` AudioGenerator: Audio-reactive property offsets driven by the soundtrack FFT (§3, W2). Each frame the mix reduces to the chosen feature and the element's properties get offset by ``amount × feature`` — beat-bounce, bass-pumped scale, etc.
              - …
        - ChildShapeElement: A shape inside a frame.
          - `blend_mode` 'none' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color_dodge' | 'color_burn' | 'hard_light' | 'soft_light' | 'difference' | 'add' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity': Values: - `none` — Normal compositing (source-over) — the default. - `multiply` — Multiply blend — darkens by multiplying layer colors. - `screen` — Screen blend — lightens by inverting, multiplying, inverting. - `overlay` — Overlay blend — multiply in shadows, screen in highlights. - `darken` — Darken blend — keeps the darker of the two layers per channel. - `lighten` — Lighten blend — keeps the lighter of the two layers per channel. - `color_dodge` — Color-dodge blend — brightens the base toward the blend color. - `color_burn` — Color-burn blend — darkens the base toward the blend color. - `hard_light` — Hard-light blend — overlay with layers swapped. - `soft_light` — Soft-light blend — a gentler hard-light. - `difference` — Difference blend — absolute difference of the two layers per channel. - `add` — Additive (linear-dodge) blend — sums layer colors, clamped. - `exclusion` — Exclusion blend — like difference, lower contrast. - `hue` — Hue blend — backdrop luminosity + saturation with the blend layer's hue. - `saturation` — Saturation blend — backdrop hue + luminosity with the blend layer's saturation. - `color` — Color blend — backdrop luminosity with the blend layer's hue + saturation. - `luminosity` — Luminosity blend — backdrop hue + saturation with the blend layer's luminosity.
          - `mask_shape` 'circle' | 'diamond' | 'hexagon' | 'star' | 'heart' | 'triangle': Analytic (SDF) shape mask that clips an element's coverage. §1. Values: - `circle` — Circular (ellipse) analytic mask, fit to the element bounds. - `diamond` — Diamond (rotated square) analytic mask. - `hexagon` — Regular hexagon analytic mask. - `star` — Five-point star analytic mask. - `heart` — Heart analytic mask. - `triangle` — Upward triangle analytic mask.
          - `mask` MaskConfig: Animated/feathered mask params layered on the analytic `mask_shape` (§5c).
            - `feather` number: Soften the mask's SDF edge.
            - `scale` number: Mask scale (iris reveals).
            - `center` Point
              - …
          - `mask_keyframes` MaskKeyframe[], nullable
            - `time` number, required: Timeline seconds.
            - `feather` number, nullable
            - `scale` number, nullable
            - `center` Point
              - …
            - `easing` string, nullable: Easing curve name — any `easings` catalog value (`linear`, `hold`, `ease_in_out`, `quad_out`, `expo_in_out`, `square_in_out` = step, …). Unknown names are rejected: the engine would silently fall back to linear. For spring/back/elastic/bezier use the sub-objects instead.
            - `spring` SpringEasing: Damped-spring ease over the keyframe segment. Only the damping ratio zeta = damping / (2 * sqrt(stiffness * mass)) shapes the curve; the segment's duration sets its timing. Below 1 the spring overshoots and rings (the defaults give zeta = 0.5); at 1 or above it settles without overshoot. An underdamped spring runs until its envelope decays to 0.1% (settle x w0 = ln(1000) / zeta, w0 = sqrt(stiffness / mass)). Since render-node's overdamped settle fix (GVR M3), a spring at zeta >= 1 runs over its slowest decay rate instead; before it, an overdamped spring's window was cut short and it reached the target still moving.
              - …
            - `back` BackEasing: Anticipate/overshoot ease (AE 'back').
              - …
            - `elastic` ElasticEasing: Elastic ring-out/ring-in ease.
              - …
            - `bezier` BezierEasing: CSS cubic-bezier(x1, y1, x2, y2) timing curve.
              - …
          - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
            - `source` string, required: uuid of the source layer (auto-hidden). Text sources supported.
            - `mode` 'alpha' | 'luma'
            - `invert` boolean
          - `backdrop_blur` union: Glass: the scene behind the element, Gaussian-blurred, fills its footprint under its translucent content (a shape's own silhouette, a video's or image's box with its corner radius and mask). A Gaussian sigma in canvas px, as CSS `backdrop-filter: blur()` takes it; the renderer caps it at 128. 0 is off.
            - integer
            - number
            - string
          - `backdrop_blur_keyframes` BlurKeyframe[], nullable: Animate `backdrop_blur` over the timeline; replaces the static value while present.
            - `time` number, required: Timeline seconds.
            - `value` number, required: Gaussian sigma in canvas px at `time`, at most 128.
          - `layer_blur` number: Blurs the element itself as drawn: a Gaussian sigma in canvas px, as CSS `filter: blur()` takes it, spreading three sigma past its box. At most 128; 0 is off. Not on a shape yet (the editor's preview cannot draw it), and not with `blend_mode`, `backdrop_blur` or `matte`, beside which the renderer would draw the element without it.
          - `layer_blur_keyframes` BlurKeyframe[], nullable: Animate `layer_blur` over the timeline; replaces the static value while present.
            - `time` number, required: Timeline seconds.
            - `value` number, required: Gaussian sigma in canvas px at `time`, at most 128.
          - `glass` Glass: A refracting glass surface (V6, render-node AEC §1): within `bevel` px of the element's edge (a shape's own outline, a box's rounded corners) the scene behind is read inward, bent by `refraction`, its red and blue split by `dispersion`. With `backdrop_blur` it bends the blurred scene, without it the sharp one.
            - `bevel` number, nullable: Width of the bent band at the edge in canvas px, at most 256. Omitted: 16.
            - `refraction` number, nullable: How far the edge bends the scene inward, 0–1. Omitted: 0.5.
            - `dispersion` number, nullable: How far red and blue split apart at the edge, 0–1. Omitted: 0.
          - `x` number, nullable: Left edge in design px from the frame's left edge. Omitted: 0.
          - `y` number, nullable: Top edge in design px from the frame's top edge. Omitted: 0.
          - `width` number, nullable: Width in design px. Omitted: the frame's width.
          - `height` number, nullable: Height in design px. Omitted: the frame's height (a text's: twice its `font_size`).
          - `aspect_ratio` number, nullable: **Accepted but ignored — the renderer never receives this field.** It does NOT constrain or correct the `width`/`height` box, so it cannot be used to stop a mismatched box from cropping the source; size the box per `width` instead. Kept for backward compatibility.
          - `x_anchor` union: Pivot the element turns and scales about, across its own box: a percent, or design px from its left edge.
            - integer
            - number
            - string
          - `y_anchor` union: Pivot across its own box's height: a percent, or design px from its top edge.
            - integer
            - number
            - string
          - `x_rotation` union
            - integer
            - number
            - string
          - `y_rotation` union
            - integer
            - number
            - string
          - `z_rotation` union
            - integer
            - number
            - string
          - `x_scale` union
            - integer
            - number
            - string
          - `y_scale` union
            - integer
            - number
            - string
          - `flip_horizontal` boolean
          - `flip_vertical` boolean
          - `opacity` number
          - `z_index` integer, nullable: Stacking order among the frame's children (higher on top); ties draw in array order.
          - `clip` boolean
          - `color_overlay` string, nullable: **Not supported by the renderer — setting this is rejected.** A strict submit returns `unsupported_feature` (422) and a dry-run reports it as a blocking violation; there is no native tint field to map it onto. To darken an element use `brightness` (`-100` is a black silhouette); to lay a colour over one, stack a `shape` with a flat or gradient `fill` above it.
          - `type` 'shape'
          - `id` string, required: **Required.** Unique identifier.
          - `name` string, nullable: Optional human-readable label. Not used by the renderer.
          - `track` integer, nullable: Timeline track index (0–255). Informational only; not used by the renderer.
          - `time` number, nullable: Start in seconds on the clock the frame gives its children (the composition's, unless a composite frame maps it; inside a component, 0 is the instance's start). Omitted: the frame's start.
          - `visible` boolean: Set to `false` to skip this element without removing it from the request.
          - `locked` boolean: Marks the element locked in editors. Not sent to the renderer.
          - `duration` number, nullable: Seconds visible. Omitted: until the frame ends.
          - `path` string, nullable: SVG path `d` (M L H V C S Q T A Z; elliptical arcs render as arcs). **Required** unless `geometry` is set.
          - `geometry` ShapeGeometry: A closed-form shape the engines draw analytically (AEC §5f): exactly one kind.
            - `rect` GeometryRect: A rectangle filling the element box, optionally with rounded corners.
              - …
            - `ellipse` GeometryEllipse: The ellipse inscribed in the element box (a circle when the box is square).
            - `line` GeometryLine: A straight line painted with the shape's `stroke` (else its `fill`). Endpoints are px from the element box's top-left corner; the width is `stroke_width` and the ends are `stroke_linecap`. Endpoints left out give the box's horizontal centre line.
              - …
            - `ring` GeometryRing: A ring, arc, pie or segmented ring: circular, inscribed in the box's shorter side.
              - …
            - `arc` GeometryRing: A ring, arc, pie or segmented ring: circular, inscribed in the box's shorter side.
              - …
            - `polygon` GeometryPolygon: A regular polygon inscribed in the ellipse the box holds, its first vertex at 12 o'clock.
              - …
            - `star` GeometryStar: A star: `points` outer vertices on the ellipse the box holds (the first at 12 o'clock), alternating with inner ones on that ellipse scaled by `inner_ratio`.
              - …
            - `stroke_align` 'inside' | 'center' | 'outside', nullable: Where the stroke sits on the outline (`centre` is read as `center`). Omitted: `center`. A polygon, a star and a smoothed rect stroke centred.
            - `shadows` GeometryShadow[], nullable: Up to 4 shadows, the first on top, on a rect or an ellipse drawn as a circle.
              - …
          - `view_box` number[]: `[x, y, width, height]` path coordinate space.
          - `fill` union: Fill: a hex colour (alpha ok), `"none"` for outline-only, a Gradient object (`{kind, angle_degrees, center, stops}`, ≥2 stops), or a CSS `linear-gradient(...)` / `radial-gradient(...)` string, which is normalised to the Gradient object at validation — read back, the composition holds the object. A gradient fill on a rectangular path is how you draw a gradient card, bar or pill — there is no separate `gradient` element. The gradient paints the shape's own path, so it fills any silhouette — a triangle, a blob, an icon outline, a morphing path — and layers on the same element with `stroke` / `stroke_width` / `stroke_dash`, `path_keyframes` (morph), `trim` / `trim_keyframes` (draw-on), `blend_mode`, `mask_shape` / `mask` / `mask_keyframes`, `matte` and `backdrop_blur`. `fill_rule`, `corner_radius` and `opacity` behave with a gradient exactly as they do with a flat colour.
            - string
            - 'none'
            - string: CSS gradient shorthand — `linear-gradient(...)` or `radial-gradient(...)`. Normalised to the Gradient object during validation; the renderer never sees a CSS string, and reading the composition back returns the object.
            - Gradient
              - …
          - `fill_rule` 'nonzero' | 'evenodd'
          - `stroke` string, nullable: Stroke colour.
          - `stroke_width` number, nullable: Stroke width in viewBox units, at most 100000 (absent = SVG 1.0; 0 disables).
          - `stroke_linecap` 'butt' | 'round' | 'square': Cap on the open ends of a stroked path (SVG `stroke-linecap`): `butt` stops at the endpoint, `round` and `square` extend it by half the stroke width. Closed paths have joins, not caps.
          - `stroke_linejoin` 'miter' | 'round' | 'bevel': Corner join of a stroked path (SVG `stroke-linejoin`): `miter` is the sharp corner (subject to `stroke_miter_limit`), `bevel` cuts it flat.
          - `stroke_miter_limit` number: SVG `stroke-miterlimit`: miter length over stroke width. A `miter` join sharper than this falls back to `bevel`.
          - `stroke_dash` number[], nullable: Dash pattern in viewBox units, SVG `stroke-dasharray` semantics: `[on, off, ...]` of any length — an odd-length array repeats so on/off alternate (`[4]` is 4 on, 4 off). Trim applies before dash, so a dashed path can draw itself on without the pattern re-flowing.
          - `stroke_dash_offset` number: Where the dash pattern starts along the path, in viewBox units (SVG `stroke-dashoffset`): positive shifts the pattern forward, negative backward.
          - `stroke_dash_offset_keyframes` DashOffsetKeyframe[], nullable: Animate the dash offset (timeline seconds) — marching ants: keyframe `offset` linearly by one dash period (the pattern's sum) per second. Needs a `stroke_dash`; while present it drives the offset in place of the static `stroke_dash_offset`.
            - `time` number, required: Timeline seconds.
            - `offset` number, required: Dash offset at this time, in viewBox units (SVG `stroke-dashoffset`).
            - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
            - `spring` SpringEasing: Damped-spring ease over the keyframe segment. Only the damping ratio zeta = damping / (2 * sqrt(stiffness * mass)) shapes the curve; the segment's duration sets its timing. Below 1 the spring overshoots and rings (the defaults give zeta = 0.5); at 1 or above it settles without overshoot. An underdamped spring runs until its envelope decays to 0.1% (settle x w0 = ln(1000) / zeta, w0 = sqrt(stiffness / mass)). Since render-node's overdamped settle fix (GVR M3), a spring at zeta >= 1 runs over its slowest decay rate instead; before it, an overdamped spring's window was cut short and it reached the target still moving.
              - …
            - `back` BackEasing: Anticipate/overshoot ease (AE 'back').
              - …
            - `elastic` ElasticEasing: Elastic ring-out/ring-in ease.
              - …
            - `bezier` BezierEasing: CSS cubic-bezier(x1, y1, x2, y2) timing curve.
              - …
          - `stroke_marker_start` 'none' | 'triangle' | 'open_chevron' | 'dot': A head at the start of each open subpath, in the stroke's colour (render-node V2.6): `triangle` is filled, its tip on the endpoint (the shaft shortens to meet it); `open_chevron` is an open head stroked like the path; `dot` is a disc. Placed after the trim, so a draw-on keeps its head at the visible end, and left out of the dash. A closed subpath takes none. Needs a `stroke`; path shapes only.
          - `stroke_marker_end` 'none' | 'triangle' | 'open_chevron' | 'dot': A head at the end of each open subpath; see `stroke_marker_start`.
          - `stroke_marker_size` number: Marker length in stroke widths, 1–32 (4 is four times `stroke_width`).
          - `corner_radius` union: Corner radius, normalized 0–1 — a single value or per-corner `{top_left, top_right, bottom_right, bottom_left}`.
            - number
            - CornerRadii: Per-corner radii, each normalized 0–1 (1 = fully round on the shorter side).
              - …
          - `shadow` DropShadow: Drop shadow for shape elements, in the renderer's own units. ``distance`` and ``blur`` are the engine's unitless 0–100 strength scale, NOT pixels — a px-looking ``distance: 10`` is a fraction of what you meant on a small element and renders as nothing at all. The offset lands at ``distance × 0.0005 × the element's shorter side``; the reference scenes author 60–70 for both. For pixel-unit shadows use ``shadow_x``/``shadow_y`` on video and image elements. The layout lint reports a distance that renders under a pixel as ``SHADOW_BELOW_MIN_SIZE``.
            - `color` string, required
            - `distance` number: Shadow offset **strength**, 0–100 on the renderer's own scale — **not pixels**. The rendered offset is `distance × 0.0005 × the element's shorter side`, so on a 400px-tall card `60` drops the shadow 12px while a px-looking `8` drops it 1.6px, and on a 200px chip that same `8` is 0.8px — invisible. Author 60–70 (what the reference scenes use) and it scales with the element; for a specific N px offset use `distance = N ÷ (0.0005 × shorter_side_px)`. Must be > 0: distance 0 is skipped by the renderer entirely. For pixel-unit shadows use `shadow_x`/`shadow_y` on video/image elements.
            - `direction` number: Shadow direction in degrees (polar; 90 = down).
            - `blur` number: Shadow softness, 0–100 on the renderer's blur-strength scale — **not** a pixel radius, and unlike `distance` it does not scale with the element. `0` is a hard-edged offset copy (a legitimate poster look); 60–70 is the soft card shadow the reference scenes author. A px-looking `8` is a near-hard edge, not an 8px feather.
          - `path_keyframes` PathKeyframe[], nullable: Morph the path between keyframes (timeline seconds).
            - `time` number, required: Timeline seconds for this path.
            - `d` string, required: SVG path `d` at this time.
            - `easing` 'linear' | 'hold' | 'ease_in' | 'ease_out' | 'ease_in_out' | 'sin_in' | 'sin_out' | 'sin_in_out' | 'square_in' | 'square_out' | 'square_in_out' | 'expo_in' | 'expo_out' | 'expo_in_out' | 'quad_in' | 'quad_out' | 'quad_in_out' | 'cubic_in' | 'cubic_out' | 'cubic_in_out' | 'quart_in' | 'quart_out' | 'quart_in_out' | 'quint_in' | 'quint_out' | 'quint_in_out': The engine's shared easing name map (Easing.cpp `StringToEasingType`). Every name here resolves on every keyframe surface (morph/trim/mask/custom animation keyframes, selector ``ease``, counter ``easing``). ``ease_in`` / ``ease_out`` / ``ease_in_out`` are the AE/CSS aliases of the ``quad_*`` curves. ``square_*`` is a **step** family (``square_in_out`` snaps at the midpoint), not a power curve — the quadratic curves are ``quad_*``. ``hold`` freezes the prior value until the next keyframe. The parameterized families (spring / back / elastic / bezier) are not names: express them through the dedicated keyframe sub-objects. Values: - `linear` — Constant speed, no acceleration. - `hold` — Freeze the previous value until the next keyframe (step). - `ease_in` — Starts slow, accelerates (alias of quad_in). - `ease_out` — Starts fast, decelerates (alias of quad_out). - `ease_in_out` — Slow start and end, faster in the middle (alias of quad_in_out). - `sin_in` — Gentle sinusoidal acceleration in. - `sin_out` — Gentle sinusoidal deceleration out. - `sin_in_out` — Gentle sinusoidal ease both ends. - `square_in` — Step: snaps at the segment end (not a power curve). - `square_out` — Step: snaps at the segment start (not a power curve). - `square_in_out` — Step: snaps at the midpoint — the typewriter/glitch snap. - `expo_in` — Extreme exponential acceleration in. - `expo_out` — Extreme exponential deceleration out. - `expo_in_out` — Extreme exponential ease both ends. - `quad_in` — Quadratic acceleration in. - `quad_out` — Quadratic deceleration out. - `quad_in_out` — Quadratic ease both ends. - `cubic_in` — Cubic acceleration in (stronger than quad). - `cubic_out` — Cubic deceleration out (stronger than quad). - `cubic_in_out` — Cubic ease both ends. - `quart_in` — Quartic acceleration in. - `quart_out` — Quartic deceleration out. - `quart_in_out` — Quartic ease both ends. - `quint_in` — Quintic acceleration in (near-expo). - `quint_out` — Quintic deceleration out (near-expo). - `quint_in_out` — Quintic ease both ends.
- … truncated; see the full OpenAPI document linked below

## Response `200`

Idempotent replay — same Idempotency-Key reused.

- RenderSubmitOut: A freshly submitted render: the job row plus the advisory lint of its composition. Returned only by the two submit routes (``POST /v1/renders``, ``POST /v1/projects/{id}/renders``). A *subclass* rather than two more fields on :class:`JobOut`, because ``JobOut`` is the shape of a job row on every read route (``GET /v1/renders``, all ``/v1/tasks`` routes, the MCP read tools) where a lint result does not exist and would be permanently null.
  - `id` string, required: Unique job ID. Prefix indicates type: `render_` or `task_`.
  - `kind` 'render' | 'task', required
  - `is_preview` boolean: True for a cheap preview render. Previews are not billed and are excluded from the renders list.
  - `editor_url` string, nullable: Open the project this job was submitted from in the authenticated console. Absent for a job with no project.
  - `task_type` 'transcribe': The AI task types the API offers. Values: - `transcribe` — Speech-to-text transcription (via AssemblyAI) with optional analysis. Returns the transcript inline on the task's `result` object — there is no file artifact, so `output` is null and `/v1/tasks/{id}/download` returns 404.
  - `workspace_id` string, required: ID of the workspace that owns this job.
  - `status` 'ingesting' | 'queued' | 'processing' | 'completed' | 'failed' | 'cancelled', required: Values: - `ingesting` — External source files are being probed for duration before the render is queued. - `queued` — Accepted and waiting for a worker to pick it up. - `processing` — Actively rendering or processing. - `completed` — Finished successfully; the output artifact is available. - `failed` — Terminated with an error (see `error`). - `cancelled` — Cancelled by the caller before completion.
  - `progress_percent` integer: 0–100 progress indicator updated by the render engine.
  - `progress_stage` 'downloading' | 'compositing' | 'encoding' | 'uploading': Values: - `downloading` — Fetching source media. - `compositing` — Compositing the scene on the GPU. - `encoding` — Encoding the output video. - `uploading` — Uploading the finished artifact to storage.
  - `output` JobOutput
    - `url` string, nullable: CDN URL to the completed artifact.
    - `width` integer, nullable: Output video width in pixels.
    - `height` integer, nullable: Output video height in pixels.
    - `duration` number, nullable: Output duration in seconds.
    - `size_bytes` integer, nullable: Artifact file size in bytes.
  - `result` object, nullable: Structured JSON result for tasks that return data rather than a file — `transcribe` returns the transcript here (`text`, `words`, `utterances`, and any requested analysis). Populated once `status == completed`; `null` for renders and for any job whose only artifact is the file at `output.url`.
  - `error` JobError
    - `code` 'invalid_source' | 'source_not_found' | 'source_too_large' | 'asset_not_ready' | 'codec_unsupported' | 'decode_failed' | 'encode_failed' | 'timeout' | 'out_of_memory' | 'gpu_error' | 'upload_failed' | 'provider_error' | 'ingest_failed' | 'render_refused' | 'internal' | 'cancelled', required: Structured error codes surfaced on Job.error_code. Values: - `invalid_source` — A source URL was malformed or inaccessible. - `source_not_found` — A source URL returned 404. - `source_too_large` — A source file exceeded the maximum allowed size. - `asset_not_ready` — A referenced asset was still ingesting when the job ran. - `codec_unsupported` — A source used a codec the renderer cannot decode. - `decode_failed` — A source file could not be decoded. - `encode_failed` — The output could not be encoded. - `timeout` — Processing exceeded the time limit. - `out_of_memory` — The renderer ran out of GPU memory. - `gpu_error` — A GPU hardware/driver error occurred. - `upload_failed` — The output artifact failed to upload to storage. - `provider_error` — An upstream provider (e.g. AssemblyAI) returned an error. - `ingest_failed` — An external source could not be probed (unreachable, not a media file, or timed out). - `render_refused` — The renderer refused the composition by name: a runtime shader that did not compile or ran over its GPU time budget, or an operation, a component or a nested composition it could not apply. `error_message` carries the engine's words; change what it names and submit again. - `internal` — An unexpected internal error occurred. - `cancelled` — The job was cancelled.
    - `message` string, required: Human-readable error description.
  - `metadata` object: Caller-supplied key-value pairs echoed back on every webhook and response.
  - `created_at` string, date-time, required: ISO-8601 UTC timestamp when the job was created.
  - `updated_at` string, date-time, required: ISO-8601 UTC timestamp of the last status change.
  - `completed_at` string, date-time, nullable: ISO-8601 UTC timestamp when the job reached a terminal state.
  - `ok` boolean, required: Advisory — the render was still accepted and dispatched. False means the composition has error-severity findings that will likely make the output wrong (a self-transition, a fully off-canvas element); it does NOT mean the submission was refused. Everything that actually blocks a render is a 422 before you ever see this field.
  - `violations` Violation[]: Advisory — the render was still accepted and dispatched. Cross-element and layout findings from the same linter the preview dry-run runs, attached so you can see problems on the render you just paid for instead of only in the artifact. To catch these BEFORE spending a render, call POST /v1/preview with dry_run.Truncated to the first 36 findings (errors first) on very large compositions, with a VIOLATIONS_TRUNCATED marker carrying the full count; the free dry run is never truncated.
    - `code` string, required: Stable machine code, e.g. 'DANGLING_TRANSITION'.
    - `message` string, required: Human-readable explanation.
    - `severity` 'error' | 'warning'
    - `path` string, nullable: Where it happened, e.g. 'elements[2]' or 'transitions[0].from_id'.
    - `pointer` string, nullable: The same place as an RFC 6901 JSON pointer into the request, e.g. '/elements/2/children/0/text_color'.
    - `target_id` string, nullable: Id of the element, frame, instance or group the finding is about; inside an instance, its expanded path (e.g. 'card1/title'). Null when it names none.
    - `bbox` number[], nullable: Canvas-space box [x, y, w, h] in pixels for layout findings (B1); null otherwise.
    - `time` number, nullable: Timeline second at which the finding applies; null for whole-timeline findings.

## Other responses

- `202`: Successful Response
- `401`: Missing or invalid API key.
- `402`: Free-tier render quota exceeded (upgrade to continue).
- `409`: Idempotency conflict (different body for the same key).
- `422`: Validation error or unsupported feature.
- `429`: Rate limit exceeded.

---

[API](https://skmtc.dev/framelane/apis/framelane-api.md) · [All operations](https://skmtc.dev/framelane/apis/framelane-api/llms.txt) · [OpenAPI document](https://skmtc.dev/framelane/apis/framelane-api/revisions/a223001ca8e5?raw)
