rustmotion
A CLI tool that renders motion design videos from JSON scenarios. No browser, no Node.js — just a single Rust binary.
Install
Requirements: Rust toolchain + C++ compiler (for openh264). Recommended: ffmpeg CLI for 10-bit H.264 and H.265/VP9/ProRes/WebM/GIF output.
Quick Start
# Render a video
# Render with a specific codec
# Export as PNG sequence
# Export as animated GIF
# Render a single frame for preview
# Validate without rendering
# Export JSON Schema (for editor autocompletion or LLM prompts)
# Show scenario info
CLI Reference
rustmotion render
| Flag | Description | Default |
|---|---|---|
input |
Path to the JSON scenario file | (required) |
-o, --output |
Output file path | output.mp4 |
--frame <N> |
Render a single frame to PNG (0-indexed) | |
--codec <CODEC> |
Video codec: h264, h265, vp9, prores |
h264 |
--crf <0-51> |
Constant Rate Factor (lower = better quality) | 23 |
--format <FMT> |
Output format: mp4, webm, mov, gif, png-seq |
auto from extension |
--transparent |
Transparent background (PNG sequence, WebM, ProRes 4444) | false |
--output-format json |
Machine-readable JSON output for CI pipelines | |
-q, --quiet |
Suppress all output except errors |
JSON Scenario Format
Video Config
| Field | Type | Default | Description |
|---|---|---|---|
width |
u32 |
(required) | Video width in pixels (must be even) |
height |
u32 |
(required) | Video height in pixels (must be even) |
fps |
u32 |
30 |
Frames per second |
background |
string |
"#000000" |
Default background color (hex) |
codec |
string |
"h264" |
Video codec: h264, h265, vp9, prores |
crf |
u8 |
23 |
Constant Rate Factor (0-51, lower = better quality) |
Audio Tracks
| Field | Type | Default | Description |
|---|---|---|---|
src |
string |
(required) | Path to audio file (MP3, WAV, OGG, FLAC, AAC) |
start |
f64 |
0.0 |
Start time in the output video (seconds) |
end |
f64 |
End time (omit for full track) | |
volume |
f32 |
1.0 |
Volume multiplier (0.0 - 1.0) |
fade_in |
f64 |
Fade-in duration (seconds) | |
fade_out |
f64 |
Fade-out duration (seconds) |
Scenes
Each scene is an implicit flex container at video dimensions (default direction: column). Children participate in flex flow automatically. Use positioned container for absolute positioning.
| Field | Type | Default | Description |
|---|---|---|---|
duration |
f64 |
(required) | Scene duration in seconds |
background |
string |
Scene background (overrides video.background) |
|
freeze_at |
f64 |
Freeze the scene at this time (seconds) | |
children |
Component[] |
[] |
Components rendered bottom-to-top |
layout |
object |
Scene-level flex layout options | |
transition |
Transition |
Transition effect from the previous scene |
layout options: direction (column/row), gap, align_items (start/center/end/stretch), justify_content (start/center/end/space_between/space_around/space_evenly), padding
Transitions
Transitions blend between two consecutive scenes. Set on the second scene.
| Type | Description |
|---|---|
fade |
Linear crossfade between scenes |
wipe_left |
Horizontal wipe revealing scene B from the left |
wipe_right |
Horizontal wipe revealing scene B from the right |
wipe_up |
Vertical wipe revealing scene B from the top |
wipe_down |
Vertical wipe revealing scene B from the bottom |
zoom_in |
Scene A zooms in and fades out, revealing scene B |
zoom_out |
Scene B zooms out from larger to normal size |
flip |
3D Y-axis flip simulation |
clock_wipe |
Circular clockwise sweep from 12 o'clock |
iris |
Expanding circle from the center reveals scene B |
slide |
Scene B pushes scene A to the left |
dissolve |
Per-pixel noise dissolve |
none |
Hard cut at the midpoint |
| Field | Type | Default | Description |
|---|---|---|---|
type |
string |
(required) | One of the transition types above |
duration |
f64 |
0.5 |
Transition duration in seconds |
Include (Composable Scenarios)
Scene entries can reference external scenario files to inject their scenes inline:
| Field | Type | Default | Description |
|---|---|---|---|
include |
string |
(required) | Path (relative to parent file) or URL to a scenario JSON |
scenes |
usize[] |
Only include scenes at these 0-based indices. Omit to include all | |
config |
object |
Config overrides to pass to a structural component (see below) |
- The included file's
videoconfig is ignored - Audio tracks from included files are merged
- Includes can be nested (max depth: 8)
Structural Components (Variables)
Structural components are reusable scenario files with declared variables. When rendered standalone, default values apply. When included from a parent, the parent can override any variable.
Defining config
Add a config object at the root of a scenario. Each entry has a type, a default value, and an optional description:
Supported types: string, number, boolean, object, array. Array and object types allow passing full components (e.g. rich_text spans, children arrays).
Referencing config values
| Syntax | Context | Behavior |
|---|---|---|
"$var_name" |
Entire string value | Replaced by the config value (any type) |
"prefix $var_name suffix" |
String interpolation | Replaced inline (value must be string/number/boolean) |
{ "$var": "var_name" } |
Any position | Replaced by the config value (for non-string types in object position) |
"$$literal" |
Escape | Produces the literal string "$literal" |
Including with overrides
Config entries not listed in overrides keep their default values. Referencing an undefined config key produces an error.
Standalone rendering
When rendering a structural component directly (rustmotion render components/outro.json), all default values are applied automatically.
Components
All components are discriminated by "type". Rendered in array order (first = bottom, last = top).
Common Fields
Available on all component types:
| Field | Type | Default | Description |
|---|---|---|---|
start_at |
f64 |
Component appears at this time (seconds within scene) | |
end_at |
f64 |
Component disappears after this time |
Common Style Fields
All visual properties are inside a "style" object:
| Style field | Type | Default | Description |
|---|---|---|---|
opacity |
f32 |
1.0 |
0.0 to 1.0 |
padding |
f32 | {top, right, bottom, left} |
Inner spacing | |
margin |
f32 | {top, right, bottom, left} |
Outer spacing | |
animation |
array | object |
[] |
Animation effects (see Animations) |
Text
Root fields: content (required), max_width
| Style field | Type | Default | Description |
|---|---|---|---|
font-size |
f32 |
48.0 |
Font size in pixels |
color |
string |
"#FFFFFF" |
Text color (hex) |
font-family |
string |
"Inter" |
Font family name |
font-weight |
enum |
"normal" |
"normal" or "bold" |
font-style |
enum |
"normal" |
"normal", "italic", "oblique" |
text-align |
enum |
"left" |
"left", "center", "right" |
line-height |
f32 |
Line height multiplier | |
letter-spacing |
f32 |
Additional spacing between characters | |
text-shadow |
object |
{ "color": "#000", "offset_x": 2, "offset_y": 2, "blur": 4 } |
|
stroke |
object |
{ "color": "#000", "width": 2 } |
|
text-background |
object |
{ "color": "#000", "padding": 4, "corner_radius": 4 } |
Shape
Root fields: shape (required), size, text
| Style field | Type | Default | Description |
|---|---|---|---|
fill |
string | gradient |
Fill color (hex) or gradient object | |
stroke |
{color, width} |
Stroke outline | |
border-radius |
f32 |
Corner radius (for rounded_rect) |
Shape types: rect, circle, rounded_rect, ellipse, triangle, star (with points, default 5), polygon (with sides, default 6), path (with data SVG path string)
Gradient fill:
Types: linear, radial.
Embedded text in shapes (text field):
vertical_align: "top", "middle", "bottom" (default: "middle").
Image
| Field | Type | Default | Description |
|---|---|---|---|
src |
string |
(required) | Path to image file (PNG, JPEG, WebP) |
size |
{width, height} |
Target size (uses native image size if omitted) | |
fit |
string |
"cover" |
"cover", "contain", "fill", "none" |
SVG
Or with inline SVG:
| Field | Type | Default | Description |
|---|---|---|---|
src |
string |
Path to .svg file |
|
data |
string |
Inline SVG markup | |
size |
{width, height} |
Target size (uses SVG intrinsic size if omitted) |
One of src or data is required.
Icon
Renders an icon from the Iconify open-source framework (200,000+ icons from 150+ sets). Icons are fetched from the Iconify API at render time.
Browse all available icons at icon-sets.iconify.design.
| Field | Type | Default | Description |
|---|---|---|---|
icon |
string |
(required) | Iconify identifier "prefix:name" (e.g. "lucide:home", "mdi:account") |
size |
{width, height} |
24x24 |
Icon size in pixels |
Style: color (default "#FFFFFF")
Common icon sets:
| Prefix | Name | Best for |
|---|---|---|
lucide |
Lucide | Clean UI icons (default choice) |
mdi |
Material Design Icons | Material UI, Android |
heroicons |
Heroicons | Tailwind projects |
ph |
Phosphor | Modern UI |
tabler |
Tabler Icons | Dashboards |
simple-icons |
Simple Icons | Brand/company logos |
devicon |
Devicon | Programming language logos |
Video
Embeds a video clip as a component. Requires ffmpeg on PATH.
| Field | Type | Default | Description |
|---|---|---|---|
src |
string |
(required) | Path to video file |
size |
{width, height} |
(required) | Display size |
trim_start |
f64 |
0.0 |
Start offset in the source clip (seconds) |
trim_end |
f64 |
End offset in the source clip (seconds) | |
playback_rate |
f64 |
1.0 |
Playback speed (0.5 = half speed, 2.0 = double) |
fit |
string |
"cover" |
"cover", "contain", "fill" |
volume |
f32 |
1.0 |
Audio volume (0.0 = mute) |
loop_video |
bool |
Loop the clip |
GIF
Displays an animated GIF, synced to the scene timeline.
| Field | Type | Default | Description |
|---|---|---|---|
src |
string |
(required) | Path to .gif file |
size |
{width, height} |
Display size (uses GIF native size if omitted) | |
fit |
string |
"cover" |
"cover", "contain", "fill" |
loop_gif |
bool |
true |
Loop the GIF animation |
Caption
Timed word-by-word captions with active word highlighting.
| Field | Type | Default | Description |
|---|---|---|---|
words |
array |
(required) | [{ "text", "start", "end" }] |
mode |
enum |
"default" |
"default", "highlight", "karaoke", "bounce" |
active_color |
string |
"#FFD700" |
Active word color |
max_width |
f32 |
Maximum width before word-wrapping |
Style: font-size (48.0), font-family, color (#FFFFFF)
Counter
Animated number counter. Must be used standalone (not inside a card).
| Field | Type | Default | Description |
|---|---|---|---|
from |
f64 |
(required) | Start value |
to |
f64 |
(required) | End value |
decimals |
u8 |
0 |
Number of decimal places |
separator |
string |
Thousands separator (e.g. " ", ",") |
|
prefix |
string |
Text before the number (e.g. "$") |
|
suffix |
string |
Text after the number (e.g. "%", "€") |
|
easing |
string |
"linear" |
Easing for the counter interpolation |
Style: font-size, color, font-family, font-weight, text-align, letter-spacing, text-shadow, stroke
Positioned
Container that places children at fixed absolute coordinates (like Flutter's Stack/Positioned). Each child uses position: {x, y} relative to the container's top-left.
Container
Invisible wrapper that groups children for shared transforms (scale, opacity, rotation, etc.). Like an HTML <div> with no visual styling. When you scale a container, all children scale together from the container's center — no overlap or distortion.
Use container instead of card when you don't need background, border, or shadow.
Supports all flex layout properties (flex-direction, align-items, justify-content, gap, padding) and all style properties (animation, timeline, opacity, margin). No background, border, box-shadow, or clipping — children can overflow freely.
Card / Flex
Visual container with CSS-like flex & grid layout. flex is an alias for card. Each dimension of size can be a number or "auto".
Flex example:
Grid example (2x2): Grid containers need an explicit height (not "auto") to prevent rows from stretching.
Style fields:
| Style field | Type | Default | Description |
|---|---|---|---|
display |
enum |
"flex" |
"flex" or "grid" |
background |
string |
Background color (hex) | |
border-radius |
f32 |
12.0 |
Corner radius |
border |
object |
{ "color": "#E5E7EB", "width": 1 } |
|
box-shadow |
object |
{ "color": "#00000040", "offset_x": 0, "offset_y": 4, "blur": 12 } |
|
padding |
f32 | object |
Inner spacing | |
flex-direction |
enum |
"column" |
"column", "row", "column_reverse", "row_reverse" |
flex-wrap |
bool |
false |
Wrap children to next line |
align-items |
enum |
"start" |
"start", "center", "end", "stretch" |
justify-content |
enum |
"start" |
"start", "center", "end", "space_between", "space_around", "space_evenly" |
gap |
f32 |
0 |
Spacing between children |
grid-template-columns |
array |
[{"px": N}, {"fr": N}, "auto"] |
|
grid-template-rows |
array |
Same format as columns |
Per-child layout properties (in child "style"):
flex-grow(f32) — default 0flex-shrink(f32) — default 1flex-basis(f32) — defaults to natural sizealign-self(enum) —"start","center","end","stretch"grid-column(object) —{ "start": 1, "span": 2 }(1-indexed)grid-row(object) —{ "start": 1, "span": 2 }(1-indexed)
Codeblock
Code block with syntax highlighting, chrome, reveal animations, and animated diff transitions.
Root fields: code (required), language, theme, size, show_line_numbers, chrome, highlights, reveal, states
| Style field | Type | Default |
|---|---|---|
font-family |
string |
"JetBrains Mono" |
font-size |
f32 |
14.0 |
font-weight |
enum |
"normal" |
line-height |
f32 |
1.5 (multiplier) |
background |
string |
(uses theme) |
border-radius |
f32 |
12.0 |
padding |
f32 | object |
16 |
Chrome (Title Bar)
| Field | Type | Default | Description |
|---|---|---|---|
chrome.enabled |
bool |
true |
Show the title bar |
chrome.title |
string |
Title text (e.g. filename) |
Line Highlights
Reveal Animation
| Field | Type | Default | Description |
|---|---|---|---|
reveal.mode |
string |
(required) | "typewriter" or "line_by_line" |
reveal.start |
f64 |
0.0 |
Start time (seconds) |
reveal.duration |
f64 |
1.0 |
Duration (seconds) |
Code States (Diff Transitions)
Animate between code versions with automatic diff detection.
| Field | Type | Default | Description |
|---|---|---|---|
states[].code |
string |
(required) | New code content |
states[].at |
f64 |
(required) | Transition start time |
states[].duration |
f64 |
0.6 |
Transition duration |
states[].cursor.enabled |
bool |
true |
Show editing cursor |
states[].cursor.blink |
bool |
true |
Blink the cursor |
Available Themes (72)
Syntect built-in: base16-ocean.dark, base16-ocean.light, base16-eighties.dark, base16-mocha.dark, InspiredGitHub, Solarized (dark), Solarized (light)
Catppuccin: catppuccin-latte, catppuccin-frappe, catppuccin-macchiato, catppuccin-mocha
Shiki / VS Code: andromeeda, aurora-x, ayu-dark, ayu-light, ayu-mirage, dark-plus, dracula, dracula-soft, everforest-dark, everforest-light, github-dark, github-dark-default, github-dark-dimmed, github-dark-high-contrast, github-light, github-light-default, github-light-high-contrast, gruvbox-dark-hard, gruvbox-dark-medium, gruvbox-dark-soft, gruvbox-light-hard, gruvbox-light-medium, gruvbox-light-soft, horizon, horizon-bright, houston, kanagawa-dragon, kanagawa-lotus, kanagawa-wave, laserwave, light-plus, material-theme, material-theme-darker, material-theme-lighter, material-theme-ocean, material-theme-palenight, min-dark, min-light, monokai, night-owl, night-owl-light, nord, one-dark-pro, one-light, plastic, poimandres, red, rose-pine, rose-pine-dawn, rose-pine-moon, slack-dark, slack-ochin, snazzy-light, solarized-dark, solarized-light, synthwave-84, tokyo-night, vesper, vitesse-black, vitesse-dark, vitesse-light
Divider
Visual separator line (horizontal or vertical).
| Field | Type | Default | Description |
|---|---|---|---|
direction |
enum |
"horizontal" |
"horizontal" or "vertical" |
thickness |
f32 |
2.0 |
Line thickness in pixels |
line_style |
enum |
"solid" |
"solid", "dashed", "dotted" |
length |
f32 |
Fixed length (omit for 100% of parent) |
Style: color (default "#FFFFFF")
Badge
Compact label with text and optional icon, pill-shaped.
| Field | Type | Default | Description |
|---|---|---|---|
text |
string |
(required) | Badge text |
icon |
string |
Iconify icon id (e.g. "lucide:star") |
|
variant |
enum |
"solid" |
"solid" (filled) or "outline" (border only) |
badge_size |
enum |
"md" |
"sm", "md", "lg" |
Style: background (default "#3B82F6") — badge color for solid variant or border color for outline, font-size, font-family
Avatar
Circular image with optional border and status indicator.
| Field | Type | Default | Description |
|---|---|---|---|
src |
string |
(required) | Path to image file |
size |
f32 |
64.0 |
Diameter in pixels |
border_color |
string |
Border color (hex) | |
border_width |
f32 |
0.0 |
Border thickness |
status |
enum |
"none" |
"online", "offline", "away", "none" |
status_color |
string |
Override status dot color |
Status colors: online=#22C55E, offline=#9CA3AF, away=#F59E0B
Callout
Speech bubble with directional arrow.
| Field | Type | Default | Description |
|---|---|---|---|
text |
string |
(required) | Callout text |
arrow_direction |
enum |
"bottom" |
"top", "bottom", "left", "right" |
arrow_size |
f32 |
12.0 |
Arrow triangle size |
size |
{width, height} |
Fixed size (auto-sized if omitted) |
Style: background (default "#333333"), color (default "#FFFFFF"), border-radius (default 8), font-size (default 16), font-family
Terminal
Terminal/console window with colored lines and optional chrome.
| Field | Type | Default | Description |
|---|---|---|---|
lines |
array |
(required) | [{ "text", "line_type", "color" }] |
theme |
enum |
"dark" |
"dark" or "light" |
title |
string |
Window title | |
show_chrome |
bool |
true |
Show title bar with traffic light dots |
reveal |
object |
{ "mode": "typewriter"|"line_by_line", "start": 0, "duration": 1, "easing": "linear" } |
|
size |
{width, height} |
Terminal size (default 500x auto) |
Line types: "prompt" (shows $ prefix in green), "command" (white text), "output" (gray text)
Reveal modes: "typewriter" reveals characters one by one, "line_by_line" fades lines in sequentially.
Table
Data table with headers and styled rows.
| Field | Type | Default | Description |
|---|---|---|---|
headers |
string[] |
(required) | Column headers |
rows |
string[][] |
(required) | Data rows |
header_color |
string |
"#374151" |
Header row background |
row_colors |
string[] |
["#1F2937", "#111827"] |
Alternating row colors |
border_color |
string |
"#4B5563" |
Grid line color |
header_text_color |
string |
"#FFFFFF" |
Header text color |
size |
{width, height} |
Table size |
Style: color (default "#FFFFFF") — cell text color, font-size (default 14), font-family, border-radius
Chart
Data visualization with bar, line, or pie charts. Animated by default.
| Field | Type | Default | Description |
|---|---|---|---|
chart_type |
enum |
(required) | "bar", "line", "pie" |
data |
array |
(required) | [{ "value", "label"?, "color"? }] |
size |
{width, height} |
300x200 |
Chart size |
animated |
bool |
true |
Animate chart fill/draw |
animation_duration |
f64 |
1.5 |
Animation duration in seconds |
colors |
string[] |
Custom color palette (hex) |
Default palette: #3B82F6, #EF4444, #22C55E, #F59E0B, #8B5CF6, #EC4899, #06B6D4, #F97316
Mockup
Device frame (phone, laptop, browser) with image content inside.
| Field | Type | Default | Description |
|---|---|---|---|
device |
enum |
(required) | "iphone", "android", "laptop", "browser" |
src |
string |
(required) | Path to content image |
theme |
enum |
"dark" |
"dark" or "light" bezel color |
size |
{width, height} |
Device size (defaults: iPhone 375x812, Android 360x800, Laptop 800x550, Browser 800x600) |
Particle
Animated particle system for visual effects (confetti, snow, stars, bubbles).
| Field | Type | Default | Description |
|---|---|---|---|
particle_type |
enum |
(required) | "confetti", "snow", "stars", "bubbles", "halo" |
count |
u32 |
50 |
Number of particles |
colors |
string[] |
Custom colors (defaults vary by type) | |
speed |
f32 |
1.0 |
Speed multiplier |
size_range |
{min, max} |
{4, 12} |
Particle size range in pixels |
seed |
u64 |
42 |
Random seed for reproducible results |
Particle behaviors:
- confetti: colored rectangles falling with rotation and horizontal wobble
- snow: white circles falling gently with lateral drift
- stars: fixed positions with twinkling opacity
- bubbles: semi-transparent circles rising with oscillation
- halo: soft glowing circles drifting slowly with pulsing opacity (great for backgrounds)
Arrow
Directional arrow with optional bezier curves. Use draw_in or stroke_reveal animation presets for drawing effects.
| Field | Type | Default | Description |
|---|---|---|---|
x1, y1 |
f32 |
0.0 |
Start point |
x2, y2 |
f32 |
(required) | End point |
cp |
{x, y} |
Quadratic bezier control point | |
cp1, cp2 |
{x, y} |
Cubic bezier control points | |
curve |
f32 |
Auto-curve (-1.0 to 1.0) | |
width |
f32 |
3.0 |
Stroke width |
color |
string |
"#FFFFFF" |
Arrow color |
arrow_end |
bool |
true |
Arrowhead at end |
arrow_start |
bool |
false |
Arrowhead at start |
arrow_size |
f32 |
12.0 |
Arrowhead size |
dashed |
f32[] |
Dash pattern (e.g. [8, 4]) |
Connector
Connects two points with automatic routing. Great for diagrams and flowcharts.
| Field | Type | Default | Description |
|---|---|---|---|
from |
{x, y} |
(required) | Start point |
to |
{x, y} |
(required) | End point |
routing |
string |
"straight" |
"straight", "curved", "elbow" (L-shaped) |
curvature |
f32 |
0.4 |
Curve intensity (for curved routing) |
width |
f32 |
2.0 |
Stroke width |
color |
string |
"#FFFFFF" |
Line color |
arrow_end |
bool |
true |
Arrowhead at end |
arrow_start |
bool |
false |
Arrowhead at start |
arrow_size |
f32 |
10.0 |
Arrowhead size |
dashed |
f32[] |
Dash pattern |
Timeline
Step-by-step timeline with animated progress bar and node icons.
| Field | Type | Default | Description |
|---|---|---|---|
steps |
array |
(required) | [{ "label", "sublabel"?, "color"?, "icon"? }] |
width |
f32 |
800.0 |
Timeline width |
direction |
string |
"horizontal" |
"horizontal" or "vertical" |
node_radius |
f32 |
24.0 |
Circle radius |
bar_color |
string |
"#333333" |
Background bar color |
bar_fill_color |
string |
"#58A6FF" |
Filled bar color |
fill_progress |
f32 |
1.0 |
Progress 0.0 to 1.0 |
Lottie
Renders Lottie animations from pre-rendered PNG frame sequences.
| Field | Type | Default | Description |
|---|---|---|---|
src |
string |
Path to Lottie JSON (for timing metadata) | |
data |
string |
Inline Lottie JSON data | |
frames_dir |
string |
Directory with numbered PNGs (0000.png, 0001.png, ...) |
|
size |
{width, height} |
Display size (falls back to Lottie intrinsic size) | |
speed |
f32 |
1.0 |
Playback speed multiplier |
loop |
bool |
true |
Loop the animation |
Generate frames with: npx lottie-to-frames animation.json --output frames/
Cursor
Animated cursor with click effects, blinking, and smooth path animation.
| Field | Type | Default | Description |
|---|---|---|---|
width |
f32 |
3.0 |
Cursor width |
height |
f32 |
40.0 |
Cursor height |
color |
string |
"#FFFFFF" |
Cursor color |
blink |
f32 |
0.5 |
Blink cycle (0 = no blink) |
click_at |
f64[] |
[] |
Click animation times (seconds) |
auto_path |
array |
[] |
Waypoints: [{ "time", "x", "y" }] |
click_duration |
f32 |
0.3 |
Click animation duration |
path_easing |
string |
"ease_in_out" |
"linear", "ease_out", "ease_in_out" |
When auto_path is set, clicks trigger at each waypoint. Uses Catmull-Rom spline interpolation for smooth curves.
Line
Simple line from point A to point B. Supports draw_in animation.
| Field | Type | Default | Description |
|---|---|---|---|
x1, y1 |
f32 |
0.0 |
Start point |
x2, y2 |
f32 |
(required) | End point |
width |
f32 |
2.0 |
Stroke width |
color |
string |
"#FFFFFF" |
Line color |
dashed |
f32[] |
Dash pattern |
Rich Text
Multi-styled text with individually styled spans. Each span inherits unset properties from the component's style.
| Field | Type | Default | Description |
|---|---|---|---|
spans |
array |
(required) | [{ "text", "color"?, "font-size"?, "font-weight"?, "font-family"?, "font-style"?, "letter-spacing"? }] |
max_width |
f32 |
Maximum width before wrapping |
Scene-Level Features
Virtual Camera
Scenes support a virtual camera with animatable pan, zoom, and rotation.
| Field | Type | Default | Description |
|---|---|---|---|
x |
f32 |
0.0 |
Camera center X offset |
y |
f32 |
0.0 |
Camera center Y offset |
zoom |
f32 |
1.0 |
Zoom factor (2.0 = 2x in) |
rotation |
f32 |
0.0 |
Rotation in degrees |
keyframes |
array |
[] |
[{ "property", "values": [{"time", "value"}], "easing" }] |
Animated Background
Scenes can have animated gradient backgrounds. Gradients are interpolated in linear color space with subdivided color stops for smooth dark transitions.
| Field | Type | Default | Description |
|---|---|---|---|
colors |
string[] |
[] |
Gradient colors (hex) |
speed |
f32 |
30.0 |
Animation speed |
gradient_type |
string |
"linear" |
"linear" or "radial" |
preset |
string |
"gradient_shift", "concentric_circles", "grid_dots" |
|
element_size |
f32 |
4.0 |
Dot size for grid_dots; stroke width for concentric_circles |
spacing |
f32 |
60.0 |
Element spacing for grid_dots/concentric_circles |
count |
u32 |
Number of circles for concentric_circles (overrides spacing) |
Animations
All animation effects are defined inside style.animation as a typed array, each discriminated by "name". A single effect (without array) is also accepted.
Effect Types
| Effect name | Fields | Description |
|---|---|---|
| preset name | delay, duration, loop, overshoot |
Any of the 39 presets (e.g. fade_in_up, scale_in) |
| char preset | delay, duration, stagger, granularity, easing, overshoot |
Per-char/word text animation: char_scale_in, char_fade_in, char_wave, char_bounce, char_rotate_in, char_slide_up |
glow |
color, radius, intensity |
Luminous halo effect |
wiggle |
property, amplitude, frequency, mode, seed, ... |
Procedural noise animation |
orbit |
radius_x, radius_y, speed, depth, tilt, ... |
Elliptical orbital motion with pseudo-3D |
keyframes |
keyframes |
Custom keyframe animations |
motion_blur |
intensity |
Motion blur effect |
Components also support a timeline field (array of { "at": f64, "animation": [...] } steps) for multi-phase sequential animations within a scene.
Animation Presets
| Field | Type | Default | Description |
|---|---|---|---|
delay |
f64 |
0.0 |
Delay before animation starts (seconds) |
duration |
f64 |
0.8 |
Animation duration (seconds) |
loop |
bool |
false |
Loop the animation continuously |
overshoot |
f64 |
0.08 |
Overshoot/anticipation intensity for scale_in/scale_out (0.0 = none) |
Entrance Presets
| Preset | Description |
|---|---|
fade_in |
Fade from transparent |
fade_in_up |
Fade in + slide up |
fade_in_down |
Fade in + slide down |
fade_in_left |
Fade in + slide from left |
fade_in_right |
Fade in + slide from right |
slide_in_left |
Slide in from far left |
slide_in_right |
Slide in from far right |
slide_in_up |
Slide in from below |
slide_in_down |
Slide in from above |
scale_in |
Scale up from 0 with overshoot (configurable via overshoot, default 8%) |
bounce_in |
Bouncy scale from small to normal |
blur_in |
Fade in from blurred |
rotate_in |
Rotate + scale from half size |
elastic_in |
Elastic underdamped spring scale |
Exit Presets
| Preset | Description |
|---|---|
fade_out |
Fade to transparent |
fade_out_up |
Fade out + slide up |
fade_out_down |
Fade out + slide down |
slide_out_left |
Slide out to the left |
slide_out_right |
Slide out to the right |
slide_out_up |
Slide out upward |
slide_out_down |
Slide out downward |
scale_out |
Scale down to 0 with anticipation (configurable via overshoot, default 8%) |
bounce_out |
Bouncy scale to small |
blur_out |
Fade out with blur |
rotate_out |
Rotate + scale to half size |
Continuous Presets
Use "loop": true for continuous animation:
| Preset | Description |
|---|---|
pulse |
Gentle scale oscillation |
float |
Vertical floating motion |
shake |
Horizontal shake |
spin |
360-degree continuous rotation |
float_3d |
Floating + subtle 3D rotation with perspective |
3D Presets
| Preset | Description |
|---|---|
flip_in_x |
3D flip around X axis (card flip from top) |
flip_in_y |
3D flip around Y axis (card flip from side) |
flip_out_x |
3D flip out around X axis |
flip_out_y |
3D flip out around Y axis |
tilt_in |
3D tilt entrance (rotate_x + rotate_y) |
Stroke Presets
For arrows, connectors, and lines:
| Preset | Description |
|---|---|
draw_in |
Animate draw_progress from 0 to 1 (stroke drawing effect) |
stroke_reveal |
draw_in + fade-in opacity over first 20% of duration |
Special Presets
| Preset | Description |
|---|---|
typewriter |
Progressive character reveal |
wipe_left |
Slide in from left with fade |
wipe_right |
Slide in from right with fade |
Custom Keyframe Animations
Animatable properties: opacity, translate_x, translate_y, scale_x, scale_y, scale (both axes), rotation, blur, color, rotate_x, rotate_y, perspective
11 easing functions: linear, ease_in, ease_out, ease_in_out, ease_in_quad, ease_out_quad, ease_in_cubic, ease_out_cubic, ease_in_expo, ease_out_expo, spring
Spring physics (when easing is spring):
Glow
| Field | Type | Default | Description |
|---|---|---|---|
color |
string |
"#FFFFFF" |
Glow color (hex) |
radius |
f32 |
10.0 |
Blur radius |
intensity |
f32 |
1.0 |
Brightness multiplier |
Wiggle (Procedural Noise)
Wiggle adds continuous organic movement. Offsets are applied additively on top of presets and keyframes.
| Field | Type | Default | Description |
|---|---|---|---|
property |
string |
(required) | Property to wiggle (same as animatable properties) |
amplitude |
f64 |
(required) | Maximum deviation (pixels for translate, degrees for rotation) |
frequency |
f64 |
(required) | Cycles per second (Hz) |
mode |
string |
"noise" |
"noise" (layered simplex) or "sine" (pure sine wave) |
seed |
u64 |
0 |
Random seed for reproducible results (noise mode only) |
octaves |
u32 |
3 |
Noise complexity (noise mode only) |
phase |
f64 |
0.0 |
Phase offset |
decay |
f64 |
Exponential decay rate | |
easing |
string |
Remap noise through an easing curve |
Orbit (Circular/Elliptical Motion)
Creates continuous circular or elliptical orbital motion with pseudo-3D depth. Applied additively like wiggle.
| Field | Type | Default | Description |
|---|---|---|---|
radius_x |
f64 |
30.0 |
Horizontal orbit radius |
radius_y |
f64 |
30.0 |
Vertical orbit radius |
speed |
f64 |
0.5 |
Revolutions per second |
start_angle |
f64 |
0.0 |
Starting angle in degrees |
depth |
f64 |
0.15 |
Scale modulation for pseudo-3D |
opacity_depth |
f64 |
0.0 |
Opacity modulation for depth |
tilt |
f64 |
0.0 |
Orbit plane tilt in degrees |
phase |
f64 |
0.0 |
Phase offset (0.0 to 1.0) |
Per-Character / Per-Word Text Animation
Animate each character or word independently with staggered timing. Use char_* animation presets inside style.animation on text components.
Char animation presets: char_scale_in, char_fade_in, char_wave, char_bounce, char_rotate_in, char_slide_up
| Field | Type | Default | Description |
|---|---|---|---|
stagger |
f64 |
0.03 |
Delay between each unit (seconds) |
duration |
f64 |
0.4 |
Each unit's animation duration |
delay |
f64 |
0.0 |
Initial delay before first unit |
easing |
string |
"linear" |
Easing function |
granularity |
string |
"char" |
"char" (per-character) or "word" (per-word) |
overshoot |
f64 |
0.08 |
Overshoot intensity for char_scale_in/char_bounce (0.0 = none) |
Per-word mode ("granularity": "word") splits text by whitespace and animates each word as a unit. Use larger stagger values (0.1–0.3s) for word reveals:
3D Perspective Transforms
Any component can be rendered with true 3D perspective using keyframe animations on rotate_x, rotate_y, and perspective properties:
Uses a Skia M44 4x4 matrix for real 3D rendering. Components with box-shadow get 3D adaptive shadows — the shadow automatically shifts and scales based on tilt angles.
Timeline Sequencing
Define sequential animation phases within a single scene using the timeline field:
Each step activates at step.at seconds, with animations resolved relative to that time. Steps merge additively with base animations.
Motion Blur
Renders multiple sub-frames and composites them for physically-correct motion blur.
Output Formats
| Format | Command | Requires |
|---|---|---|
| MP4 (H.264 10-bit) | rustmotion render in.json -o out.mp4 |
ffmpeg (auto-detected) |
| MP4 (H.264 8-bit) | rustmotion render in.json -o out.mp4 |
Built-in (fallback without ffmpeg) |
| MP4 (H.265) | rustmotion render in.json -o out.mp4 --codec h265 |
ffmpeg |
| WebM (VP9) | rustmotion render in.json -o out.webm --codec vp9 |
ffmpeg |
| MOV (ProRes) | rustmotion render in.json -o out.mov --codec prores |
ffmpeg |
| Animated GIF | rustmotion render in.json -o out.gif --format gif |
Built-in |
| PNG Sequence | rustmotion render in.json -o frames/ --format png-seq |
Built-in |
| Single Frame | rustmotion render in.json --frame 0 -o preview.png |
Built-in |
Transparency is supported with --transparent for PNG sequences, WebM (VP9), and ProRes 4444.
Gradient quality: When ffmpeg is available, H.264 uses 10-bit color depth (
yuv420p10le,high10profile) which greatly reduces banding on dark gradients. For maximum quality, use--codec prores. The built-in openh264 encoder (fallback without ffmpeg) outputs 8-bit only.
Full Example
Architecture
- Rendering: skia-safe (same engine as Chrome/Flutter)
- Video encoding: openh264 (Cisco BSD, compiled from source) + ffmpeg (optional, for H.265/VP9/ProRes)
- Audio encoding: AAC via minimp4
- SVG rendering: resvg + usvg
- Icon rendering: Iconify API (200k+ icons)
- GIF decoding/encoding: gif crate
- MP4 muxing: minimp4
- JSON Schema: schemars (auto-generated from Rust types)
- Parallelism: rayon (multi-threaded frame rendering)
License
MIT