---
title: "Get a project"
method: GET
path: "/v1/projects/{project_id}"
tags: ["projects"]
---

# Get a project

`GET /v1/projects/{project_id}`

## Request

- Base URL: `https://api.framelane.io`
- URL: `https://api.framelane.io/v1/projects/{project_id}`
- Auth: HTTP bearer

Returns a project. `view=summary` (default) omits the full request; `view=full` includes it. A published template from another workspace reads here too, read-only: every write route answers 404 for it.

## Path parameters

- `project_id` string, required

## Query parameters

- `view` 'summary' | 'full': How much of a project to return from ``GET /v1/projects/{id}``.

## Response `200`

Successful Response

- ProjectOut: A project. ``render_request`` is populated only for ``view=full``.
  - `id` string, required: Unique project id.
  - `name` string, required: Display name.
  - `version` integer, required: Head version. Bumped on every applied ops batch.
  - `workspace_id` string, required: Owning workspace id.
  - `editor_url` string, required: Open this project in the authenticated console.
  - `kind` 'project' | 'template': `project`, or `template`: a project used as a copy source.
  - `source_project_id` string, nullable: The project or template this one was copied from.
  - `source_kind` 'project' | 'template' | 'public_template', nullable: What the source was: `project` (a duplicate), `template` (one of your templates) or `public_template` (a published template from the gallery).
  - `thumbnail_url` string, nullable: A poster image of the head; null until one is generated.
  - `thumbnail_version` integer, nullable: The head version the thumbnail shows. It is stale while this is below `version`.
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required
  - `summary` ProjectSummary, required: A token-light view of a composition: canvas + one line per element.
    - `width` integer, nullable
    - `height` integer, nullable
    - `duration` number, nullable
    - `frame_rate` integer, nullable
    - `output_format` string, nullable
    - `element_count` integer: Elements at every depth: the root's, each frame's children and each instance's slot content.
    - `transition_count` integer
    - `frame_count` integer: Frames, at every depth.
    - `instance_count` integer: Instances, at every depth.
    - `operation_count` integer: Entries in the request's `operations` groups.
    - `component_count` integer: Component definitions.
    - `deepest` string[]: Ids from a root element down to the most deeply nested element (the first in document order); empty when nothing nests.
    - `renders_count` integer, nullable: Number of billable renders submitted for this project. Null when not computed.
    - `elements` ProjectElementSummary[]
      - `id` string, nullable: Element id (the op target).
      - `parent` string, nullable: The frame or instance (for its slot content) it sits in; null at the root.
      - `type` string, required: Element type: video, audio, text, image, etc.
      - `time` number, nullable: Start time on the timeline, in seconds.
      - `duration` number, nullable: On-timeline duration, when derivable.
      - `label` string, nullable: Human label (name / text), truncated.
      - `source` string, nullable: Source filename for media elements.
  - `render_request` 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).
              - …
          - `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` 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.
              - …
            - `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.
              - …
        - 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).
              - …
          - `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.
              - …
          - `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.
        - 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).
              - …
          - `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` 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.
              - …
            - `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.
              - …
        - 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
              - …
          - `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` 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.
              - …
            - `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.
            - `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.
              - …
          - `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.
              - …
            - `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.
              - …
          - `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.
              - …
            - `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.
              - …
        - 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.
              - …
          - `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.
              - …
          - `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
              - …
          - `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.
              - …
            - `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.
              - …
          - `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
              - …
        - 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.
              - …
          - `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.
              - …
          - `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
              - …
          - `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.
              - …
            - `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.
              - …
          - `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`.
              - …
            - PresetOperation: An element preset run as operations over the window (GVR §4.3 item 10).
              - …
    - `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).
              - …
            - `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.
              - …
            - `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.
              - …
            - `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`.
              - …
            - `shadow_y` union: Vertical shadow offset in pixels. See `shadow_x`.
              - …
            - `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).
              - …
            - `mask_keyframes` MaskKeyframe[], nullable
              - …
            - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
              - …
            - `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.
              - …
            - `backdrop_blur_keyframes` BlurKeyframe[], nullable: Animate `backdrop_blur` over the timeline; replaces the static value while present.
              - …
            - `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.
              - …
            - `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.
              - …
            - `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.
              - …
            - `y_anchor` union: Pivot across its own box's height: a percent, or design px from its top edge.
              - …
            - `x_rotation` union
              - …
            - `y_rotation` union
              - …
            - `z_rotation` union
              - …
            - `x_scale` union
              - …
            - `y_scale` union
              - …
            - `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.
              - …
            - `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[]
              - …
            - `motion` Motion[]
              - …
          - 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).
              - …
            - `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.
              - …
            - `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.
              - …
            - `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`.
              - …
            - `shadow_y` union: Vertical shadow offset in pixels. See `shadow_x`.
              - …
            - `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.
              - …
            - `y_anchor` union: Pivot across its own box's height: a percent, or design px from its top edge.
              - …
            - `x_rotation` union
              - …
            - `y_rotation` union
              - …
            - `z_rotation` union
              - …
            - `x_scale` union
              - …
            - `y_scale` union
              - …
            - `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
              - …
            - `y_padding` union
              - …
            - `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[]
              - …
            - `word_animation` WordAnimation
              - …
            - `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.
              - …
            - `counter` ValueCounter: Rewrite a text element from an eased numeric sweep (the animated stat hero, §4).
              - …
            - `glow` TextGlow: Soft glow around the glyphs (§4).
              - …
            - `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).
              - …
            - `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.
              - …
            - `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.
              - …
            - `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`.
              - …
            - `shadow_y` union: Vertical shadow offset in pixels. See `shadow_x`.
              - …
            - `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).
              - …
            - `mask_keyframes` MaskKeyframe[], nullable
              - …
            - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
              - …
            - `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.
              - …
            - `backdrop_blur_keyframes` BlurKeyframe[], nullable: Animate `backdrop_blur` over the timeline; replaces the static value while present.
              - …
            - `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.
              - …
            - `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.
              - …
            - `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.
              - …
            - `y_anchor` union: Pivot across its own box's height: a percent, or design px from its top edge.
              - …
            - `x_rotation` union
              - …
            - `y_rotation` union
              - …
            - `z_rotation` union
              - …
            - `x_scale` union
              - …
            - `y_scale` union
              - …
            - `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[]
              - …
            - `motion` Motion[]
              - …
          - 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).
              - …
            - `mask_keyframes` MaskKeyframe[], nullable
              - …
            - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
              - …
            - `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.
              - …
            - `backdrop_blur_keyframes` BlurKeyframe[], nullable: Animate `backdrop_blur` over the timeline; replaces the static value while present.
              - …
            - `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.
              - …
            - `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.
              - …
            - `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.
              - …
            - `y_anchor` union: Pivot across its own box's height: a percent, or design px from its top edge.
              - …
            - `x_rotation` union
              - …
            - `y_rotation` union
              - …
            - `z_rotation` union
              - …
            - `x_scale` union
              - …
            - `y_scale` union
              - …
            - `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.
              - …
            - `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.
              - …
            - `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`.
              - …
            - `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}`.
              - …
            - `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``.
              - …
            - `path_keyframes` PathKeyframe[], nullable: Morph the path between keyframes (timeline seconds).
              - …
            - `trim` TrimPath
              - …
            - `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`.
              - …
            - `effects` Effect[]: Shader effect chain (§6 W3).
              - …
            - `motion` Motion[]
              - …
          - 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.
              - …
            - `y_anchor` union: Pivot across its own box's height: a percent, or design px from its top edge. Omitted: the centre.
              - …
            - `z_rotation` union: Rotation in degrees. Omitted: 0.
              - …
            - `x_rotation` union: Perspective tilt (X axis) each element inside takes about its own centre, as a group's does. Omitted: 0.
              - …
            - `y_rotation` union: Perspective tilt (Y axis); see `x_rotation`. Omitted: 0.
              - …
            - `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.
              - …
            - `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`.
              - …
            - `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).
              - …
            - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
              - …
            - `effects` Effect[]: Shader effects run over its content.
              - …
            - `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.
              - …
            - `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.
              - …
          - 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.
              - …
            - `y_anchor` union: Pivot across its own box's height: a percent, or design px from its top edge. Omitted: the centre.
              - …
            - `z_rotation` union: Rotation in degrees. Omitted: 0.
              - …
            - `x_rotation` union: Perspective tilt (X axis) each element inside takes about its own centre, as a group's does. Omitted: 0.
              - …
            - `y_rotation` union: Perspective tilt (Y axis); see `x_rotation`. Omitted: 0.
              - …
            - `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.
              - …
            - `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`.
              - …
            - `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).
              - …
            - `matte` Matte: Track matte (§5d): drive this element's coverage from another layer's render.
              - …
            - `effects` Effect[]: Shader effects run over its content.
              - …
            - `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.
              - …
            - `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.
      - `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
              - …
      - `variants` ComponentVariant[], nullable: Named bodies, the first the default. Give this or `children`.
        - `name` string, required
        - `width` number, nullable: Its box width in design px. Omitted: the component's.
        - `height` number, nullable: Its box height in design px. Omitted: the component's.
        - `children` union[]: Its body, in design px from the box's top-left corner.
          - 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: 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.
              - …
            - 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.
              - …
        - `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).
              - …
            - `ops` union[], required: Operations and presets in document order: at equal starts the later replace wins.
              - …
    - `motion_blur` MotionBlur: Shutter-based temporal supersampling of the whole composition (§5c). Opt-in and costly: every frame renders `samples` times, and accumulation is CPU-side, so the render falls back to **software encoding** — expect roughly `samples`× render time.
      - `samples` integer, required: Temporal samples per frame (2–32).
      - `shutter` number: Shutter fraction of the frame interval, (0–1]. (Exactly 0 is rejected: it renders N identical samples — full cost, zero blur.)
    - `background_gradient` union: Canvas-sized gradient fill behind every layer (§6). Rendered for the full output slice. Accepts a Gradient object or a CSS `linear-gradient(...)` string.
      - 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
          - `x` number
          - `y` number
        - `stops` GradientStop[], required: Two or more colour stops.
          - `offset` number, required: Position along the gradient, 0–1.
          - `color` string, required: Stop colour (hex, alpha supported).
    - `watermark_url` string, uri, nullable: Watermark image overlaid on the output (§6).
    - `custom_animations` CustomAnimationRegistry: Inline custom-animation registries for element and text animations (§3). `element` entries are bindable from any video/image/shape/group animation via `motion[].custom` (or `animations[].custom` on groups). `text` entries bind from a text element's `animation_preset` or `motion[].custom`. Names that shadow a catalog preset — or the reserved static keys `none`/ `overlay`/`difference` — are rejected here: the engine warn-and-*ignores* such a definition (renderer_node.cpp:1500-1516) and the reference then silently resolves to the catalog preset instead of yours.
      - `element` CustomAnimation[]
        - `name` string, required: Reference name (reserved/catalog-shadowing names are rejected).
        - `keyframes` AnimationKeyframe[], required
          - `time` number, required: Fraction of the animation (0–1).
          - `easing` string, nullable: Easing into this keyframe — any `easings` catalog name (`quad_out`, `expo_in_out`, `hold`, …). Unknown names are rejected. A `bezier`/`spring`/`back`/`elastic` sub-object overrides it.
          - `bezier` BezierEasing: CSS cubic-bezier(x1, y1, x2, y2) timing curve.
            - `x1` number
            - `y1` number
            - `x2` number
            - `y2` number
          - `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.
          - `translate` Point
            - `x` number
            - `y` number
          - `path` SpatialPath: Cubic-bezier control points curving the translate into this keyframe. The segment from the previous keyframe's position travels along the bezier defined by `c1`/`c2` (same units as `translate`) instead of a straight line.
            - `c1` Point, required
              - …
            - `c2` Point, required
              - …
          - `scale` union: Uniform scale factor, or `{x, y}` for non-uniform scale.
            - number
            - ScaleXY: Non-uniform scale for a custom-animation keyframe.
              - …
          - `rotate` number, nullable: In-plane (z) rotation, degrees.
          - `rotation` RotationXYZ: 3D rotation (degrees) for a custom-animation keyframe. Non-zero `x`/`y` renders true perspective tilt through the engine's 45° fov camera — the animated 3D-card family (spins, tilting reveals). This is also the engine-recommended way to tilt *text*, which has no static tilt.
            - `x` number
            - `y` number
            - `z` number
          - `opacity` number, nullable
          - `color` string, nullable: Colour tint at this keyframe (multiplied with the element). An 8-digit hex alpha composes with `opacity` — when both are set, `opacity` wins for the alpha channel.
          - `blur` number, nullable: Per-glyph blur amount (fraction of the em). Text registries only.
        - `group` 'block' | 'word' | 'glyph': What the animation repeats over: the whole text block, each word, or each glyph. Required for `selector` to shape anything — a selector over a single block has nothing to range across. Text registries only.
        - `selector` RangeSelector: AE-style range selector: shape a text animation's amount by position (§4, W2).
          - `based_on` 'glyph' | 'word'
          - `start` number: Range start, fraction along the text.
          - `end` number: Range end, fraction along the text.
          - `falloff` number: Ease to zero over this fraction beyond each edge.
          - `ease` string, nullable: Easing curve name for the falloff.
          - `invert` boolean
      - `text` CustomAnimation[]
        - `name` string, required: Reference name (reserved/catalog-shadowing names are rejected).
        - `keyframes` AnimationKeyframe[], required
          - `time` number, required: Fraction of the animation (0–1).
          - `easing` string, nullable: Easing into this keyframe — any `easings` catalog name (`quad_out`, `expo_in_out`, `hold`, …). Unknown names are rejected. A `bezier`/`spring`/`back`/`elastic` sub-object overrides it.
          - `bezier` BezierEasing: CSS cubic-bezier(x1, y1, x2, y2) timing curve.
            - `x1` number
            - `y1` number
            - `x2` number
            - `y2` number
          - `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.
          - `translate` Point
            - `x` number
            - `y` number
          - `path` SpatialPath: Cubic-bezier control points curving the translate into this keyframe. The segment from the previous keyframe's position travels along the bezier defined by `c1`/`c2` (same units as `translate`) instead of a straight line.
            - `c1` Point, required
              - …
            - `c2` Point, required
              - …
          - `scale` union: Uniform scale factor, or `{x, y}` for non-uniform scale.
            - number
            - ScaleXY: Non-uniform scale for a custom-animation keyframe.
              - …
          - `rotate` number, nullable: In-plane (z) rotation, degrees.
          - `rotation` RotationXYZ: 3D rotation (degrees) for a custom-animation keyframe. Non-zero `x`/`y` renders true perspective tilt through the engine's 45° fov camera — the animated 3D-card family (spins, tilting reveals). This is also the engine-recommended way to tilt *text*, which has no static tilt.
            - `x` number
            - `y` number
            - `z` number
          - `opacity` number, nullable
          - `color` string, nullable: Colour tint at this keyframe (multiplied with the element). An 8-digit hex alpha composes with `opacity` — when both are set, `opacity` wins for the alpha channel.
          - `blur` number, nullable: Per-glyph blur amount (fraction of the em). Text registries only.
        - `group` 'block' | 'word' | 'glyph': What the animation repeats over: the whole text block, each word, or each glyph. Required for `selector` to shape anything — a selector over a single block has nothing to range across. Text registries only.
        - `selector` RangeSelector: AE-style range selector: shape a text animation's amount by position (§4, W2).
          - `based_on` 'glyph' | 'word'
          - `start` number: Range start, fraction along the text.
          - `end` number: Range end, fraction along the text.
          - `falloff` number: Ease to zero over this fraction beyond each edge.
          - `ease` string, nullable: Easing curve name for the falloff.
          - `invert` boolean
    - `metadata` object: Arbitrary key-value pairs echoed back in all webhook payloads.
    - `webhook_url` string, uri, nullable: Per-request webhook URL. Overrides workspace-level webhooks for this job only. Receives `render.completed`, `render.failed`, and progress events.
    - `ingest_external` boolean, nullable: Controls handling of video/audio source URLs that are not hosted by Framelane. When `true` (the default), each such file is probed for its duration before rendering: the job starts in the `ingesting` state and moves to `queued` once the probe answers, so elements may omit `out_point`. The file itself is fetched by the renderer at render time, so the URL must be a direct, public https link to the media (not a share page) that supports range requests. When `false`, the URL is passed straight through and video/audio require an explicit `out_point`.

## Other responses

- `401`: Missing or invalid API key.
- `404`: Project not found.
- `422`: Validation Error

---

[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)
