@depths/waves
v0.5.0
Published
Type-safe video generation engine for converting JSON IR to rendered videos using Remotion
Maintainers
Readme
@depths/waves (v0.5.0)
@depths/waves is a TypeScript-first library + CLI for rendering videos from a JSON "intermediate representation" (IR) using Remotion.
The intended workflow is:
- An LLM (or a human) produces JSON that conforms to a schema (
VideoIRSchema). - The IR is validated (schema + semantics + registry contracts).
- The IR is rendered to an output video file (MP4 by default) using Remotion.
v0.2.0 introduced a shadcn-like catalog of higher-level "composite" components and a hybrid IR that supports:
- Segments (recommended for agents): sequential scenes with optional overlaps ("transitions")
- Timeline (escape hatch): explicit timed nodes with overlaps allowed
v0.4.0 focuses on unified aesthetics control:
- Theme tokens: shadcn-ish design tokens (colors, typography, spacing, radii, shadows, motion) declared once at the video level
- Presets: built-in theme presets for fast, consistent styling
- Token-only styling: components reference token keys (no hardcoded styling constants in primitives or composites)
- Visual debugging workflow:
waves stillsand--debugBounds/--debugLabelsto inspect alignment issues without pixel tests
v0.5.0 focuses on robustness and performance:
- Faster agent loops: deterministic bundle caching (
.waves-cache/) so repeated renders don't re-bundle - Fail-fast assets: local
/assets/...references are checked before expensive renders - Deterministic font loading: theme fonts must load successfully or the render is cancelled
- Stricter transitions: invalid transition types/props are rejected (no silent overlaps)
Table of contents
- Concept (end-to-end)
- Installation
- CLI (agent workflow)
- IR v3.0 (authoring contract)
- Components (primitives + composites)
- Examples (composition recipes)
- Library API (quickstart)
- Assets and paths (Windows/Linux)
- Rendering prerequisites
- Local CLI testing (before publishing)
- Contributing
Concept (end-to-end)
What problem this solves
Remotion is a powerful way to render videos by writing React components. But for "LLM -> video" workflows, you need more than React:
- A strict authoring contract (so the model can reliably output something valid)
- Fast, deterministic validation (so failures happen before render time)
- A component catalog (so the model composes using known building blocks)
- A CLI (so an agent can drive the entire pipeline from a terminal)
Waves is a thin, explicit layer over Remotion that provides exactly those pieces.
Mental model
Think of Waves as a compiler + runtime:
- Author: you (or an agent) author a JSON IR document
- Validate: Waves validates schema + semantics + component props
- Compile: Waves compiles high-level authoring (segments) into a render-ready timeline
- Render: Waves invokes Remotion bundling + rendering to produce an MP4
At render time, Waves is "just React + Remotion". The strictness lives earlier (IR + validation + registry contracts).
Core building blocks
The codebase has a small number of core concepts:
- Video IR (
VideoIRSchema): the JSON document format you author. - v0.4.0+ targets
version: "3.0"only.- You author exactly one of
segments[](recommended) ortimeline[](escape hatch).
- You author exactly one of
- Component Registry (
ComponentRegistry): a map from stringtype-> React component + Zod props schema + metadata.- Only registered components can render.
- Props are validated with Zod and defaults are applied deterministically.
- Validator (
IRValidator): validates:- IR schema (Zod)
- semantic rules (timing bounds, duration math, transition overlap constraints)
- registry contracts (type exists, props valid, children allowed, etc.)
- Compiler (
compileToRenderGraph): compiles authored IR into a normalized, timed representation used by rendering.- In segments mode: inserts an internal
Segmentwrapper node for each segment and computes overlaps. - In timeline mode: fills missing
timingdefaults (whole-video / whole-parent).
- In segments mode: inserts an internal
- Renderer (
WavesEngine): bundles a temporary Remotion project and calls Remotion's renderer.- It writes a temporary entrypoint, bundles, selects a composition, and renders media.
How segments + transitions work
Segments are the recommended authoring style for agents because they reduce timing math:
- Each segment has
durationInFramesand arootnode. - Segment start times are derived by order.
- Optional overlaps are declared via
transitionToNext.
Waves compiles segments into a "render timeline" (a list of timed component nodes). Each segment becomes:
- a root
Segmentnode (internal; not shown in the LLM catalog) - whose child is the authored
rootnode
Why the internal Segment wrapper exists:
- Overlap transitions are easiest to implement at the segment boundary.
- The wrapper can apply fade/slide/zoom/clip effects for the first/last frames of a segment.
- The wrapper receives both the "enter transition" (inferred from the previous segment's
transitionToNext) and the "exit transition" (the current segment'stransitionToNext).
Overlap math:
- Let segment
ihave durationDi. - Let overlap
Oi(in frames) betheme.motion.durationsInFrames[segments[i].transitionToNext.duration](only for segments that have a next segment). - Then the compiled start time is:
start(0) = 0start(i+1) = start(i) + Di - Oi
- The compiled video end must equal
video.durationInFrames.
Validation model
Waves tries to fail early with errors that are usable for an agent:
- Schema validation (Zod):
- ensures the IR has the expected structure (types, required fields, etc.)
- Semantic validation:
- validates segment overlap constraints (overlap cannot exceed either segment)
- validates that all timed nodes stay within their parent duration
- validates that the compiled timeline end equals
video.durationInFrames
- Registry validation:
- unknown component types fail
- props fail if they don't match the component's Zod schema
- children fail if the component metadata forbids children (or requires a certain number)
The validator applies Zod defaults into the IR node objects. This is intentional: it makes render-time props deterministic and reduces "undefined" cases inside components.
Rendering model
Rendering is done by generating a tiny Remotion project on the fly:
- Waves validates + compiles the IR to a timed timeline.
- Waves writes a temporary
entry.tsxthat:- registers the
WavesCompositionas the Remotion root - embeds the compiled IR as JSON
- registers built-in components (and optional user
--registermodules)
- registers the
- Waves calls
@remotion/bundlerto create a bundle. - Waves calls
@remotion/rendererto select the composition and render media.
This means you do not need to maintain a separate Remotion project just to use Waves.
Installation
npm i @depths/wavesPeer dependencies (must be installed by the consumer):
npm i react remotionNode: see package.json engines (this repo targets Node 22+).
CLI (agent workflow)
Waves ships a waves CLI so a locally running AI agent (or any terminal user) can:
- fetch a system prompt + JSON Schemas + catalog
- write a starter IR file
- validate the IR
- render an MP4 from the IR
Install locally (recommended):
npm i -D @depths/wavesRun via the local bin:
npx waves --helpTypical agent loop
For an agent that can execute terminal commands, the recommended flow is:
waves prompt --format json --out waves-prompt.json- Use
waves-prompt.json.systemPrompt+waves-prompt.json.schemas+waves-prompt.json.catalogas the authoring contract for the model - Have the model output a single JSON object (Video IR)
- Write that JSON to
video.v3.json waves validate --in video.v3.jsonuntil it passeswaves render --in video.v3.json --out output.mp4 ...
1) Get the prompt payload (system prompt + schemas + catalog)
Machine-readable payload (recommended for agents):
npx waves prompt --format json --pretty --out ./waves-prompt.jsonHuman-readable system prompt:
npx waves prompt --format text --out ./waves-system-prompt.txtSchemas only:
npx waves schema --kind all --pretty --out ./waves-schemas.jsonComponent catalog (grouped by category):
npx waves catalog
npx waves catalog --format json --pretty --out ./waves-catalog.jsonIf you register custom components at module import time, include them with repeatable --register:
npx waves prompt --format json --register ./src/register-waves-components.ts
npx waves schema --kind components --register ./src/register-waves-components.ts
npx waves validate --in ./video.v3.json --register ./src/register-waves-components.tsImportant notes on --register:
- The value must be a Node-loadable module at runtime (typically a
.js/.mjsfile). - If you pass a path, prefer an absolute path or a relative path with
./. - A registration module usually calls
globalRegistry.register(...)to add custom components before validation/rendering. - Re-registering an existing
typethrows (registry types are unique).
2) Write IR JSON
npx waves write-ir --template basic --pretty --out ./video.v3.json3) Validate IR JSON
npx waves validate --in ./video.v3.jsonStructured validation result:
npx waves validate --in ./video.v3.json --format json4) Render MP4
npx waves render --in ./video.v3.json --out ./output.mp4 --codec h264 --crf 28 --concurrency 1If your IR references "/assets/..." paths, pass --publicDir and ensure the files exist at ${publicDir}/assets/...:
npx waves render --in ./video.v3.json --out ./output.mp4 --publicDir ./publicExit codes
0: success1: usage error (invalid flags/command)2: validation failure (invalid JSON or IR validation errors)3: render failure4: I/O error (missing/unreadable/unwritable files)5: internal error (bug)
Command reference
This section documents every command and flag supported by the current CLI implementation (src/cli.ts).
waves --help / waves help
Prints a short help text.
waves --version
Prints the package version (e.g. 0.5.0).
waves prompt
Outputs an "agent-ready" payload that includes:
systemPrompt: a full system prompt stringschemas.videoIR: JSON Schema for authoring IR (segments mode)schemas.components: a JSON object keyed by componenttypecontaining props JSON Schemas + metadatacatalog: categories + items (flattened list for easier prompting / UI)
Flags:
--format text|json(defaulttext)--maxChars <n>(text format only; truncates the prompt)--pretty(json format only)--out <path>(optional; writes the output to a file in addition to stdout)--register <module>(repeatable)
Examples:
npx waves prompt --format json --pretty --out ./waves-prompt.json
npx waves prompt --format text --maxChars 4000 --out ./waves-system-prompt.txtwaves schema
Outputs JSON Schemas only.
Flags:
--kind video-ir|components|all(defaultall)--pretty--out <path>(optional; writes output to a file in addition to stdout)--register <module>(repeatable; affects--kind componentsandall)
Examples:
npx waves schema --kind video-ir --pretty --out ./schema.video-ir.json
npx waves schema --kind components --pretty --out ./schema.components.jsonwaves catalog
Prints the built-in component catalog grouped by category.
Flags:
--format text|json(defaulttext)--pretty(json format only)--out <path>(optional; writes output to a file in addition to stdout)--includeInternal(includes internal-only types such asSegment)--register <module>(repeatable; adds additional registered types)
Examples:
npx waves catalog
npx waves catalog --format json --pretty --out ./waves-catalog.jsonwaves themes
Lists built-in theme presets (or prints the full token object for a preset).
Flags:
--format text|json(defaulttext)--id <preset>(optional; when set, prints the preset tokens instead of listing preset ids)--pretty(json format only)--out <path>(optional)
Examples:
npx waves themes
npx waves themes --format json --pretty --out ./waves-themes.json
npx waves themes --id studio-dark --format json --pretty --out ./studio-dark.tokens.jsonwaves write-ir
Writes a starter IR JSON file (always version: "3.0" segments mode).
Flags:
--template minimal|basic(defaultminimal)--preset <id>(optional; defaultstudio-dark)--themeOverrides <path>(optional; JSON theme override object merged over the preset)--pretty--out <path>(required)
Examples:
npx waves write-ir --template minimal --pretty --out ./video.v3.json
npx waves write-ir --template basic --pretty --out ./examples/basic.v3.jsonwaves validate
Validates an IR JSON file.
Flags:
--in <path>(required)--format text|json(defaulttext)--pretty(json format only)--preset <id>(optional; overrides the IR theme preset id)--themeOverrides <path>(optional; JSON theme override object merged over IR theme overrides)--register <module>(repeatable)
Behavior:
- text format prints
okto stdout on success, otherwise prints a human-readable list to stderr and exits non-zero. - json format prints
{ "success": true }or{ "success": false, "errors": [...] }to stdout.
Examples:
npx waves validate --in ./video.v3.json
npx waves validate --in ./video.v3.json --format json --prettywaves render
Renders an MP4 from an IR JSON file.
Flags:
--in <path>(required)--out <path>(required)--publicDir <path>(optional; required if your IR uses/assets/...paths)--codec h264|h265|vp8|vp9(optional; defaulth264)--crf <n>(optional; forwarded to Remotion renderer)--concurrency <n|string>(optional; forwarded to Remotion renderer)--preset <id>(optional; overrides the IR theme preset id)--themeOverrides <path>(optional; JSON theme override object merged over IR theme overrides)--debugBounds(optional; draws debug outlines for every rendered node)--debugLabels(optional; labels debug outlines withtype#id)--register <module>(repeatable)--pretty(only affects the formatting of error JSON when render fails)
Examples:
npx waves render --in ./video.v3.json --out ./output.mp4 --codec h264 --crf 28 --concurrency 1
npx waves render --in ./video.v3.json --out ./output.mp4 --publicDir ./public
npx waves render --in ./video.v3.json --out ./output.mp4 --publicDir ./public --debugBounds --debugLabelswaves stills
Renders a set of still images (single frames) from an IR JSON file. This is the recommended way to iterate on alignment and overlays without re-rendering full MP4s.
Flags:
--in <path>(required)--outDir <path>(required)--frames <csv>(required; e.g."0,30,60")--publicDir <path>(optional; required if your IR uses/assets/...paths)--imageFormat png|jpeg|webp(optional; defaultpng)--scale <n>(optional; default1)--jpegQuality <n>(optional; default90; only used when--imageFormat jpeg)--preset <id>(optional; overrides the IR theme preset id)--themeOverrides <path>(optional; JSON theme override object merged over IR theme overrides)--debugBounds/--debugLabels(same aswaves render)--register <module>(repeatable)
Examples:
npx waves stills --in ./video.v3.json --outDir ./examples/_stills --frames "0,45,90" --publicDir ./public
npx waves stills --in ./video.v3.json --outDir ./examples/_stills --frames "0,45,90" --publicDir ./public --debugBounds --debugLabelsIR v3.0 (authoring contract)
v0.4.0+ targets version: "3.0" only.
Recommended: segments[] (high-level)
In segments mode, you provide sequential segments and Waves compiles them into an explicit timed timeline. You usually do not need to specify timing on nodes.
Key rules:
- Segment overlap is controlled by
transitionToNext.duration(a theme motion token key like"fast","base","slow"). transitionToNextis only valid when there is a "next" segment (i.e. it is not allowed on the last segment).- The total video duration must match the compiled timeline end:
video.durationInFrames = sum(segment.durationInFrames) - sum(overlap)- where
overlap = theme.motion.durationsInFrames[transitionToNext.duration]for each segment that has a next segment (after resolving the theme preset + overrides).
Minimal example:
{
"version": "3.0",
"video": { "id": "main", "width": 1920, "height": 1080, "fps": 30, "durationInFrames": 60 },
"theme": { "preset": "studio-dark" },
"segments": [
{
"id": "scene-1",
"durationInFrames": 60,
"root": {
"id": "root",
"type": "Scene",
"props": { "background": { "type": "color", "token": "background" } },
"children": [{ "id": "t1", "type": "Text", "props": { "content": "Hello" } }]
}
}
]
}Supported transitionToNext.type values (segment overlap transitions):
FadeTransitionSlideTransition(props:{ direction: "left"|"right"|"up"|"down", distance?: "enter"|"nudge"|"travel" })ZoomTransition(props:{ type: "zoomIn"|"zoomOut" })WipeTransition(props:{ direction: "left"|"right"|"up"|"down"|"diagonal", softEdge?: boolean })CircularReveal(props:{ direction: "open"|"close", center?: { x: 0..1, y: 0..1 } })
Escape hatch: timeline[] (low-level)
In timeline mode you provide explicit timings. Each node's timing is relative to its parent sequence (nested timing is "local").
Notes:
- Root
timingis optional; if omitted, Waves treats the node as spanning the full video duration. - Child
timingis optional; if omitted, Waves treats the child as spanning the full parent duration.
{
"version": "3.0",
"video": { "id": "main", "width": 1920, "height": 1080, "fps": 30, "durationInFrames": 60 },
"theme": { "preset": "studio-dark" },
"timeline": [
{
"id": "scene",
"type": "Scene",
"timing": { "from": 0, "durationInFrames": 60 },
"props": { "background": { "type": "color", "token": "background" } }
}
]
}Component nodes
Nodes are structural (the IR does not hard-code component types):
type ComponentNode = {
id: string;
type: string; // must be registered at validate/render time
props?: Record<string, unknown>;
timing?: { from: number; durationInFrames: number };
children?: ComponentNode[];
};Validation uses the registry to enforce:
- unknown component types (error)
- props schemas (Zod validation, defaults applied)
- whether a component can have
children(metadata contract)
Components (primitives + composites)
Waves renders only components that have been explicitly registered in the ComponentRegistry. Each component is defined by:
- a string type (e.g.
"Scene","TypewriterText") - a React component implementation (Remotion primitives + CSS)
- a Zod props schema (validation + defaults)
- metadata (kind/category/description/LLM guidance/children contract)
Primitives vs composites
- Primitives are low-level building blocks (layout, text, media). They are intentionally generic.
- Composites are higher-level building blocks (shadcn-like) that encode common video patterns: titles, lower thirds, social cards, charts, transitions, etc.
In general:
- Prefer composites for agent-authored videos (less "design work" for the model).
- Use primitives when you need precise control or to build new composites.
Categories and children contracts
Each component is categorized (text, layout, media, transition, etc.) to help an agent choose the right tool.
Some components can have nested children in the IR. This is controlled by metadata:
acceptsChildren: true|false- optional
minChildren/maxChildrenconstraints
If a component does not accept children and the IR provides children, validation fails before rendering.
Internal props: __wavesDurationInFrames
At render time, Waves injects __wavesDurationInFrames into every component. This is the duration of the node's Sequence.
This allows components to implement "in/out" animations without the author hand-computing timings.
This prop is not part of the author-facing props schema and does not appear in the tables below.
Keeping docs in sync
The tables below are generated from the live registry JSON Schemas to reduce drift.
Regenerate after changing component props/metadata:
npm run build
node scripts/generate-readme-components.mjsComponents summary
| Type | Kind | Category | Children | Internal | Description |
| - | - | - | - | - | - |
| IntroScene | composite | branding | no | no | Branded intro scene (logo + company name + optional tagline) |
| LogoReveal | composite | branding | no | no | Logo intro animation (fade/scale/rotate/slide), optionally with a sound effect |
| OutroScene | composite | branding | no | no | End screen with logo, message, optional CTA buttons and social handles |
| Watermark | composite | branding | no | no | Persistent logo/text watermark in a corner |
| AnimatedCounter | composite | data | no | no | Animated numeric counter (spring or linear), optionally with an icon and suffix |
| BarChart | composite | data | no | no | Animated bar chart (vertical or horizontal) |
| LineGraph | composite | data | no | no | Animated line graph (SVG) with draw/reveal modes |
| ProgressBar | composite | data | no | no | Animated progress bar that fills over the component duration |
| ProgressRing | composite | data | no | no | Circular progress indicator (SVG) that animates from 0 to percentage over duration |
| Image | primitive | image | no | no | Full-frame image with object-fit options |
| ImageCollage | composite | image | no | no | Collage of multiple images in a grid/stack/scatter layout with staggered entrances |
| ImageReveal | composite | image | no | no | Reveals an image with wipe/expand/iris entrance effects |
| ImageSequence | composite | image | no | no | Plays a numbered image sequence (frame-by-frame) |
| ImageWithCaption | composite | image | no | no | Image with a caption strip (top/bottom) or overlay caption |
| KenBurnsImage | composite | image | no | no | Slow zoom and pan (Ken Burns effect) for a still image |
| Box | primitive | layout | yes | no | Flow container for layout and backgrounds (layout-safe) |
| CardStack | composite | layout | no | no | Sequential stacked cards (2-5) with flip/slide/fade transitions |
| Frame | primitive | layout | yes | no | Absolute-positioned container (x/y placement) |
| Grid | primitive | layout | yes | no | Grid layout container with configurable rows/columns |
| GridLayout | composite | layout | yes (1..∞) | no | Simple responsive grid layout for child components |
| Layer | primitive | layout | yes (1..∞) | no | One overlay layer with explicit zIndex inside Layers |
| Layers | primitive | layout | yes (1..∞) | no | Overlay container for stacking children (use Layer for zIndex) |
| Scene | primitive | layout | yes | no | Scene container with a background and nested children |
| Segment | primitive | layout | yes (1..1) | yes | Internal segment wrapper (used by v2 segments compiler) |
| Shape | primitive | layout | no | no | Simple rect/circle shape for UI accents |
| SplitScreen | composite | layout | yes (2..2) | no | Two-panel split screen layout |
| Stack | primitive | layout | yes | no | Flexbox stack layout (row/column) with gap and alignment |
| ThirdLowerBanner | composite | layout | no | no | Broadcast-style lower-third banner with name/title and optional avatar |
| Audio | primitive | media | no | no | Plays an audio file with optional trimming and fade in/out |
| Video | primitive | media | no | no | Full-frame video with object-fit options |
| VideoWithOverlay | composite | media | no | no | Video background with an optional overlay (text/logo/gradient) |
| InstagramStory | composite | social | no | no | Instagram story-style layout with profile header, text overlay, and optional sticker |
| TikTokCaption | composite | social | no | no | TikTok-style captions with stroke and optional word highlighting |
| TwitterCard | composite | social | no | no | Twitter/X post card layout with author header and optional image |
| YouTubeThumbnail | composite | social | no | no | YouTube-style thumbnail layout (16:9) with bold title and optional face cutout |
| CountUpText | composite | text | no | no | Counts from a start value to an end value with formatting options |
| GlitchText | composite | text | no | no | Cyberpunk-style glitch text with RGB split jitter |
| KineticTypography | composite | text | no | no | Rhythmic single-word kinetic typography driven by a timing array |
| OutlineText | composite | text | no | no | Outlined title text with simple draw/fill animation |
| SplitText | composite | text | no | no | Animated text where each word or letter enters with a staggered effect |
| SubtitleText | composite | text | no | no | Caption/subtitle box with fade in/out and optional highlighted words |
| Text | primitive | text | no | no | Displays animated text with positioning and animation options |
| TypewriterText | composite | text | no | no | Character-by-character text reveal with optional blinking cursor |
| CircularReveal | composite | transition | yes (1..∞) | no | Circular iris reveal/hide transition wrapper |
| FadeTransition | composite | transition | yes (1..∞) | no | Fade in/out wrapper (used for segment transitions and overlays) |
| SlideTransition | composite | transition | yes (1..∞) | no | Slide in/out wrapper transition |
| WipeTransition | composite | transition | yes (1..∞) | no | Directional wipe reveal/hide wrapper transition |
| ZoomTransition | composite | transition | yes (1..∞) | no | Zoom in/out wrapper transition |
Components reference
Category: branding
IntroScene
- kind:
composite - category:
branding - internal:
false - children:
no - description: Branded intro scene (logo + company name + optional tagline)
- llmGuidance: Use as the first segment. Works best at 3-5 seconds. Uses theme tokens (no raw styling). musicTrack can add ambience.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| background | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "background" | |
| companyName | string | yes | | minLength=1 |
| font | enum("display" | "body" | "mono") | yes | "display" | |
| logoSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl") | yes | "xl" | |
| logoSrc | string | yes | | minLength=1 |
| musicTrack | string | no | | |
| nameColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "foreground" | |
| nameSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "4xl" | |
| nameWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "black" | |
| tagline | string | no | | |
| taglineColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "mutedForeground" | |
| taglineSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "xl" | |
| taglineWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "semibold" | |
LogoReveal
- kind:
composite - category:
branding - internal:
false - children:
no - description: Logo intro animation (fade/scale/rotate/slide), optionally with a sound effect
- llmGuidance: Use for intros/outros. Keep the logo high-contrast and centered. Uses theme tokens (no raw styling). soundEffect can be a short sting.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| background | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "background" | |
| effect | enum("fade" | "scale" | "rotate" | "slide") | yes | "scale" | |
| logoSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl") | yes | "xl" | |
| logoSrc | string | yes | | minLength=1 |
| slideDistance | enum("enter" | "nudge" | "travel") | yes | "travel" | |
| soundEffect | string | no | | |
OutroScene
- kind:
composite - category:
branding - internal:
false - children:
no - description: End screen with logo, message, optional CTA buttons and social handles
- llmGuidance: Use as the last segment. Keep CTAs <=3 for clarity. Uses theme tokens (no raw styling).
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| background | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "background" | |
| ctaBackground | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "muted" | |
| ctaButtons | array | no | | maxItems=3 |
| ctaColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "foreground" | |
| ctaRadius | enum("none" | "sm" | "md" | "lg" | "full") | yes | "md" | |
| ctaTextSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "lg" | |
| ctaTextWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "bold" | |
| logoSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl") | yes | "lg" | |
| logoSrc | string | yes | | minLength=1 |
| message | string | yes | "Thank You" | |
| messageColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "foreground" | |
| messageFont | enum("display" | "body" | "mono") | yes | "display" | |
| messageSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "4xl" | |
| messageWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "black" | |
| socialColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "mutedForeground" | |
| socialHandles | array | no | | maxItems=4 |
| socialTextSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "md" | |
| socialTextWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "semibold" | |
Watermark
- kind:
composite - category:
branding - internal:
false - children:
no - description: Persistent logo/text watermark in a corner
- llmGuidance: Use subtle opacity. bottomRight is standard. Uses theme tokens (no raw styling).
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| color | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "mutedForeground" | |
| font | enum("display" | "body" | "mono") | yes | "body" | |
| opacity | enum("faint" | "subtle" | "medium" | "strong") | yes | "subtle" | |
| position | enum("topLeft" | "topRight" | "bottomLeft" | "bottomRight") | yes | "bottomRight" | |
| size | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "16" | |
| src | string | no | | |
| text | string | no | | |
| textSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "lg" | |
| textWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "bold" | |
| type | enum("logo" | "text") | yes | "logo" | |
Category: data
AnimatedCounter
- kind:
composite - category:
data - internal:
false - children:
no - description: Animated numeric counter (spring or linear), optionally with an icon and suffix
- llmGuidance: Use for big stats. animationType="spring" feels natural. suffix for units (%, K, M). Uses theme tokens (no raw styling).
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| animationType | enum("spring" | "linear") | yes | "spring" | |
| color | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "foreground" | |
| font | enum("display" | "body" | "mono") | yes | "display" | |
| from | number | yes | 0 | |
| icon | string | no | | |
| iconSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "2xl" | |
| size | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "5xl" | |
| suffix | string | no | | |
| to | number | yes | 100 | |
| weight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "black" | |
BarChart
- kind:
composite - category:
data - internal:
false - children:
no - description: Animated bar chart (vertical or horizontal)
- llmGuidance: Use 2-6 bars. Provide maxValue to lock scale across multiple charts. Uses theme tokens (no raw styling).
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| data | array | yes | | minItems=2, maxItems=8 |
| gap | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "6" | |
| gridColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "border" | |
| gridOpacity | enum("faint" | "subtle" | "medium" | "strong") | yes | "faint" | |
| gridRowSize | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "16" | |
| labelColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "foreground" | |
| labelSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "md" | |
| labelWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "semibold" | |
| maxValue | number | no | | |
| orientation | enum("horizontal" | "vertical") | yes | "vertical" | |
| padding | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "24" | |
| radius | enum("none" | "sm" | "md" | "lg" | "full") | yes | "sm" | |
| showGrid | boolean | yes | false | |
| showValues | boolean | yes | true | |
| stagger | enum("fast" | "base" | "slow") | yes | "fast" | |
| trackColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "muted" | |
| trackRadius | enum("none" | "sm" | "md" | "lg" | "full") | yes | "full" | |
| valueColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "foreground" | |
| valueSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "lg" | |
| valueWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "bold" | |
LineGraph
- kind:
composite - category:
data - internal:
false - children:
no - description: Animated line graph (SVG) with draw/reveal modes
- llmGuidance: Use 5-20 points. animate="draw" traces the line; animate="reveal" wipes it left-to-right. Uses theme tokens (no raw styling).
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| animate | enum("draw" | "reveal") | yes | "draw" | |
| color | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "primary" | |
| data | array | yes | | minItems=2, maxItems=50 |
| dotRadius | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "2" | |
| fillArea | boolean | yes | false | |
| fillOpacity | enum("faint" | "subtle" | "medium" | "strong") | yes | "faint" | |
| padding | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "8" | |
| showDots | boolean | yes | true | |
| strokeWidth | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "1" | |
ProgressBar
- kind:
composite - category:
data - internal:
false - children:
no - description: Animated progress bar that fills over the component duration
- llmGuidance: Use for loading/countdowns. showPercentage=true is helpful for clarity. Uses theme tokens (no raw styling).
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| barColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "primary" | |
| edgeOffset | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "12" | |
| height | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "3" | |
| insetX | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "20" | |
| label | string | no | | |
| labelColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "foreground" | |
| labelFont | enum("display" | "body" | "mono") | yes | "body" | |
| labelSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "md" | |
| labelWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "bold" | |
| position | enum("top" | "bottom") | yes | "bottom" | |
| radius | enum("none" | "sm" | "md" | "lg" | "full") | yes | "full" | |
| showPercentage | boolean | yes | true | |
| trackColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "muted" | |
ProgressRing
- kind:
composite - category:
data - internal:
false - children:
no - description: Circular progress indicator (SVG) that animates from 0 to percentage over duration
- llmGuidance: Use for completion and goals. showLabel displays the percentage. Uses theme tokens (no raw styling).
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| color | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "primary" | |
| labelColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "foreground" | |
| labelFont | enum("display" | "body" | "mono") | yes | "display" | |
| labelSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "xl" | |
| labelWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "black" | |
| percentage | number | yes | | min=0, max=100 |
| showLabel | boolean | yes | true | |
| size | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl") | yes | "lg" | |
| strokeWidth | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "5" | |
| trackColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "muted" | |
Category: image
Image
- kind:
primitive - category:
image - internal:
false - children:
no - description: Full-frame image with object-fit options
- llmGuidance: Use Image for pictures and backgrounds. Use fit="cover" for full-bleed, fit="contain" to avoid cropping.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| borderRadius | enum("none" | "sm" | "md" | "lg" | "full") | yes | "none" | |
| fit | enum("cover" | "contain") | yes | "cover" | |
| opacity | number | yes | 1 | min=0, max=1 |
| src | string | yes | | minLength=1 |
ImageCollage
- kind:
composite - category:
image - internal:
false - children:
no - description: Collage of multiple images in a grid/stack/scatter layout with staggered entrances
- llmGuidance: Use 2-6 images for best results. layout="grid" is clean; "scatter" is energetic. Uses theme tokens (no raw styling).
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| captionBackground | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "background" | |
| captionColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "foreground" | |
| captionFont | enum("display" | "body" | "mono") | yes | "body" | |
| captionOpacity | enum("faint" | "subtle" | "medium" | "strong") | yes | "medium" | |
| captionPadding | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "3" | |
| captionSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "md" | |
| captionWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "bold" | |
| cardHeight | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl") | yes | "xl" | |
| cardWidth | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl") | yes | "2xl" | |
| gap | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "6" | |
| images | array | yes | | minItems=2, maxItems=9 |
| layout | enum("grid" | "stack" | "scatter") | yes | "grid" | |
| padding | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "20" | |
| radius | enum("none" | "sm" | "md" | "lg" | "full") | yes | "md" | |
| shadow | enum("sm" | "md" | "lg") | yes | "lg" | |
| stagger | enum("fast" | "base" | "slow") | yes | "fast" | |
ImageReveal
- kind:
composite - category:
image - internal:
false - children:
no - description: Reveals an image with wipe/expand/iris entrance effects
- llmGuidance: Use wipe for directional reveals, expand for subtle pop-in, iris for circular mask openings.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| direction | enum("left" | "right" | "top" | "bottom" | "center") | yes | "left" | |
| revealType | enum("wipe" | "expand" | "iris") | yes | "wipe" | |
| src | string | yes | | minLength=1 |
ImageSequence
- kind:
composite - category:
image - internal:
false - children:
no - description: Plays a numbered image sequence (frame-by-frame)
- llmGuidance: Use for exported sprite sequences. basePath can be /assets/seq and filePattern like img_{frame}.png.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| basePath | string | yes | | minLength=1 |
| filePattern | string | yes | "frame_{frame}.png" | |
| fps | integer | yes | 30 | min=1, max=120 |
| frameCount | integer | yes | | max=9007199254740991 |
ImageWithCaption
- kind:
composite - category:
image - internal:
false - children:
no - description: Image with a caption strip (top/bottom) or overlay caption
- llmGuidance: Use overlay for quotes/testimonials over photos. Use bottom for standard captions. Uses theme tokens (no raw styling).
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| caption | string | yes | | maxLength=200 |
| captionBackground | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "muted" | |
| captionColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "foreground" | |
| captionFont | enum("display" | "body" | "mono") | yes | "body" | |
| captionPadding | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "5" | |
| captionPosition | enum("top" | "bottom" | "overlay") | yes | "bottom" | |
| captionRadius | enum("none" | "sm" | "md" | "lg" | "full") | yes | "md" | |
| captionSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "xl" | |
| captionWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "bold" | |
| src | string | yes | | minLength=1 |
KenBurnsImage
- kind:
composite - category:
image - internal:
false - children:
no - description: Slow zoom and pan (Ken Burns effect) for a still image
- llmGuidance: Classic documentary-style motion. mode controls zoom; panDirection adds drift. Uses theme tokens (no raw styling).
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| mode | enum("zoomIn" | "zoomOut" | "none") | yes | "zoomIn" | |
| panDirection | enum("none" | "left" | "right" | "up" | "down") | yes | "none" | |
| panDistance | enum("enter" | "nudge" | "travel") | yes | "nudge" | |
| src | string | yes | | minLength=1 |
Category: layout
Box
- kind:
primitive - category:
layout - internal:
false - children:
yes - description: Flow container for layout and backgrounds (layout-safe)
- llmGuidance: Use Box as a container inside Grid/Stack. Box participates in layout flow. For x/y positioning, use Frame.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| backgroundColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | no | | |
| borderRadius | enum("none" | "sm" | "md" | "lg" | "full") | yes | "none" | |
| height | number | no | | |
| opacity | number | yes | 1 | min=0, max=1 |
| padding | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "0" | |
| width | number | no | | |
CardStack
- kind:
composite - category:
layout - internal:
false - children:
no - description: Sequential stacked cards (2-5) with flip/slide/fade transitions
- llmGuidance: Use for steps/features. displayDuration is frames per card. Uses theme tokens (no raw styling).
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| background | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "surface" | |
| cards | array | yes | | minItems=2, maxItems=5 |
| contentFont | enum("display" | "body" | "mono") | yes | "body" | |
| contentOpacity | enum("faint" | "subtle" | "medium" | "strong") | yes | "strong" | |
| contentSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "xl" | |
| contentWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "bold" | |
| displayDuration | integer | yes | 90 | min=30, max=150 |
| padding | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "16" | |
| radius | enum("none" | "sm" | "md" | "lg" | "full") | yes | "lg" | |
| shadow | enum("sm" | "md" | "lg") | yes | "lg" | |
| textColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "surfaceForeground" | |
| titleFont | enum("display" | "body" | "mono") | yes | "display" | |
| titleSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "4xl" | |
| titleWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "black" | |
| transition | enum("flip" | "slide" | "fade") | yes | "flip" | |
Frame
- kind:
primitive - category:
layout - internal:
false - children:
yes - description: Absolute-positioned container (x/y placement)
- llmGuidance: Use Frame for precise pixel placement (x/y). Use Box for normal layout flow inside Grid/Stack.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| backgroundColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | no | | |
| borderRadius | enum("none" | "sm" | "md" | "lg" | "full") | yes | "none" | |
| height | number | no | | |
| opacity | number | yes | 1 | min=0, max=1 |
| padding | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "0" | |
| width | number | no | | |
| x | number | yes | 0 | |
| y | number | yes | 0 | |
Grid
- kind:
primitive - category:
layout - internal:
false - children:
yes - description: Grid layout container with configurable rows/columns
- llmGuidance: Use Grid for photo collages and dashboards. Provide exactly rows*columns children when possible.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| align | enum("start" | "center" | "end" | "stretch") | yes | "stretch" | |
| columns | integer | yes | 2 | min=1, max=12 |
| gap | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "6" | |
| justify | enum("start" | "center" | "end" | "stretch") | yes | "stretch" | |
| padding | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "0" | |
| rows | integer | yes | 1 | min=1, max=12 |
GridLayout
- kind:
composite - category:
layout - internal:
false - children:
yes (1..∞) - description: Simple responsive grid layout for child components
- llmGuidance: Use for dashboards and collages. 2x2 is a good default for 4 items.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| columns | integer | yes | 2 | min=1, max=4 |
| gap | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "5" | |
| padding | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "10" | |
| rows | integer | yes | 2 | min=1, max=4 |
Layer
- kind:
primitive - category:
layout - internal:
false - children:
yes (1..∞) - description: One overlay layer with explicit zIndex inside Layers
- llmGuidance: Use Layer inside Layers to control stacking. Put exactly one child in a Layer (recommended).
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| inset | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "0" | |
| opacity | number | yes | 1 | min=0, max=1 |
| pointerEvents | enum("none" | "auto") | yes | "none" | |
| zIndex | integer | yes | 0 | min=-9007199254740991, max=9007199254740991 |
Layers
- kind:
primitive - category:
layout - internal:
false - children:
yes (1..∞) - description: Overlay container for stacking children (use Layer for zIndex)
- llmGuidance: Use Layers to stack background/content/overlays. Prefer Layer children with explicit zIndex.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| overflow | enum("visible" | "hidden") | yes | "visible" | |
Scene
- kind:
primitive - category:
layout - internal:
false - children:
yes - description: Scene container with a background and nested children
- llmGuidance: Use Scene to define a segment of the video. Scene timings must be sequential with no gaps. Put Text and Audio as children.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| background | oneOf(object | object | object) | yes | | |
Segment
- kind:
primitive - category:
layout - internal:
true - children:
yes (1..1) - description: Internal segment wrapper (used by v2 segments compiler)
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| enterTransition | object | no | | additionalProperties=false |
| exitTransition | object | no | | additionalProperties=false |
Shape
- kind:
primitive - category:
layout - internal:
false - children:
no - description: Simple rect/circle shape for UI accents
- llmGuidance: Use Shape for lines, badges, and simple UI blocks. Use circle for dots and rings.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| fill | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "foreground" | |
| height | number | yes | 100 | |
| opacity | number | yes | 1 | min=0, max=1 |
| radius | enum("none" | "sm" | "md" | "lg" | "full") | yes | "none" | |
| shape | enum("rect" | "circle") | yes | "rect" | |
| strokeColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | no | | |
| strokeWidth | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "0" | |
| width | number | yes | 100 | |
| x | number | yes | 0 | |
| y | number | yes | 0 | |
SplitScreen
- kind:
composite - category:
layout - internal:
false - children:
yes (2..2) - description: Two-panel split screen layout
- llmGuidance: Provide exactly 2 children. Use orientation="vertical" for left/right and "horizontal" for top/bottom.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| dividerColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | no | | |
| dividerOpacity | enum("faint" | "subtle" | "medium" | "strong") | yes | "subtle" | |
| dividerThickness | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "1" | |
| gap | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "12" | |
| orientation | enum("vertical" | "horizontal") | yes | "vertical" | |
| padding | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "20" | |
| split | number | yes | 0.5 | min=0.1, max=0.9 |
Stack
- kind:
primitive - category:
layout - internal:
false - children:
yes - description: Flexbox stack layout (row/column) with gap and alignment
- llmGuidance: Use Stack to arrange child components in a row or column without manual positioning.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| align | enum("start" | "center" | "end" | "stretch") | yes | "center" | |
| direction | enum("row" | "column") | yes | "column" | |
| gap | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "6" | |
| justify | enum("start" | "center" | "end" | "between") | yes | "center" | |
| padding | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "0" | |
ThirdLowerBanner
- kind:
composite - category:
layout - internal:
false - children:
no - description: Broadcast-style lower-third banner with name/title and optional avatar
- llmGuidance: Use for speaker introductions. name = big label, title = smaller subtitle. showAvatar + avatarSrc for profile image.
Props:
| Prop | Type | Required | Default | Notes |
| - | - | - | - | - |
| accent | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "primary" | |
| avatarBox | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl") | yes | "md" | |
| avatarSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl") | yes | "sm" | |
| avatarSrc | string | no | | |
| background | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "muted" | |
| barWidth | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "2" | |
| inset | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "20" | |
| minHeight | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl") | yes | "md" | |
| name | string | yes | | maxLength=50 |
| nameColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "foreground" | |
| nameFont | enum("display" | "body" | "mono") | yes | "display" | |
| nameSize | enum("xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl") | yes | "3xl" | |
| nameWeight | enum("regular" | "medium" | "semibold" | "bold" | "black") | yes | "black" | |
| paddingX | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "8" | |
| paddingY | enum("0" | "1" | "2" | "3" | "4" | "5" | "6" | "8" | "10" | "12" | "16" | "20" | "24" | "32") | yes | "6" | |
| radius | enum("none" | "sm" | "md" | "lg" | "full") | yes | "md" | |
| showAvatar | boolean | yes | false | |
| title | string | yes | | maxLength=100 |
| titleColor | enum("background" | "foreground" | "surface" | "surfaceForeground" | "muted" | "mutedForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "accent" | "accentForeground" | "border" | "ring") | yes | "mutedForegro
