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). Optional: ffmpeg CLI for 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 has a duration, optional background, layers rendered in order, and an optional transition to the next scene.
| 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). All frames after this point render the frozen state | |
layers |
Layer[] |
[] |
Layers rendered bottom-to-top |
transition |
Transition |
Transition effect to the next scene |
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 (scene A folds away, scene B unfolds) |
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 (each pixel switches independently) |
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 |
Layers
All layers share a common set of fields for animation, timing, and effects, plus type-specific fields. Layers are rendered in array order (first = bottom, last = top).
Common Fields
These fields are available on all layer types (except group and caption where noted):
| Field | Type | Default | Description |
|---|---|---|---|
position |
{x, y} |
{x: 0, y: 0} |
Position in pixels |
opacity |
f32 |
1.0 |
Layer opacity (0.0 - 1.0) |
animations |
Animation[] |
[] |
Custom keyframe animations |
preset |
string |
Preset animation name (see Animation Presets) | |
preset_config |
PresetConfig |
Preset timing configuration | |
start_at |
f64 |
Layer appears at this time (seconds within scene) | |
end_at |
f64 |
Layer disappears after this time (seconds within scene) | |
wiggle |
WiggleConfig[] |
Procedural noise-based animation (see Wiggle) | |
motion_blur |
f32 |
Motion blur intensity (0.0 - 1.0). Uses temporal multi-sampling | |
padding |
f32 | {top, right, bottom, left} |
null |
Inner spacing — enlarges the bounding box and insets the content |
margin |
f32 | {top, right, bottom, left} |
null |
Outer spacing — offsets the layer and affects card layout |
Padding and margin accept either a uniform number ("padding": 16) or per-side values ("margin": {"top": 32, "right": 16, "bottom": 32, "left": 16}). In card layouts, margin adds space around the child; padding insets the content within the child. For standalone layers, margin offsets the rendered position, and padding offsets the content.
Note:
CardLayerandCodeblockLayermanage their own internal padding. The globalpaddingfield does not apply to them — onlymarginis used.
Text Layer
| Field | Type | Default | Description |
|---|---|---|---|
content |
string |
(required) | Text to display. Supports \n for line breaks |
font_size |
f32 |
48.0 |
Font size in pixels |
color |
string |
"#FFFFFF" |
Text color (hex). Can be animated via "color" property |
font_family |
string |
"Inter" |
Font family name (uses system fonts) |
font_weight |
string |
"normal" |
"normal" or "bold" |
align |
string |
"left" |
"left", "center", or "right" |
max_width |
f32 |
Maximum text width before word-wrapping | |
line_height |
f32 |
font_size * 1.3 |
Line height in pixels |
letter_spacing |
f32 |
0.0 |
Additional spacing between characters |
Shape Layer
| Field | Type | Default | Description |
|---|---|---|---|
shape |
ShapeType |
(required) | Shape type (see below) |
size |
{width, height} |
{width: 100, height: 100} |
Shape dimensions |
fill |
string | Gradient |
Fill color (hex string) or gradient object | |
stroke |
Stroke |
Stroke outline | |
corner_radius |
f32 |
8.0 |
Corner radius (for rounded_rect) |
Shape Types
| Type | Description | Extra Fields |
|---|---|---|
"rect" |
Rectangle | |
"circle" |
Circle (fits inside size rect) | |
"rounded_rect" |
Rectangle with rounded corners | corner_radius |
"ellipse" |
Ellipse (fits inside size rect) | |
"triangle" |
Equilateral triangle pointing up | |
"star" |
Star polygon | points (default: 5) |
"polygon" |
Regular polygon | sides (default: 6) |
"path" |
SVG path | data (SVG path string, required) |
Star and polygon examples:
Fill
Fill accepts either a solid hex color string or a gradient object:
"fill": "#ff6b6b"
"fill":
| Gradient Field | Type | Default | Description |
|---|---|---|---|
type |
string |
(required) | "linear" or "radial" |
colors |
string[] |
(required) | Array of hex colors |
stops |
f32[] |
Color stop positions (0.0 - 1.0) | |
angle |
f32 |
0.0 |
Angle in degrees (linear gradients only) |
Stroke
| Field | Type | Default | Description |
|---|---|---|---|
color |
string |
(required) | Stroke color (hex) |
width |
f32 |
2.0 |
Stroke width in pixels |
Image Layer
| 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 |
"contain" |
"cover", "contain", or "fill" |
SVG Layer
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 Layer
Renders an icon from the Iconify library. The icon SVG is fetched automatically from the Iconify API.
| Field | Type | Default | Description |
|---|---|---|---|
icon |
string |
(required) | Iconify identifier "prefix:name" (e.g. "lucide:home", "mdi:account") |
color |
string |
"#FFFFFF" |
Icon color (replaces currentColor) |
size |
{width, height} |
24x24 |
Icon size in pixels |
Browse available icons at icon-sets.iconify.design.
Video Layer
Embeds a video clip as a layer. 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 |
"contain" |
"cover", "contain", or "fill" |
volume |
f32 |
1.0 |
Audio volume (0.0 = mute) |
loop_video |
bool |
Loop the clip |
GIF Layer
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 |
"contain" |
"cover", "contain", or "fill" |
loop_gif |
bool |
true |
Loop the GIF animation |
Caption Layer
TikTok-style word-by-word subtitles with active word highlighting.
| Field | Type | Default | Description |
|---|---|---|---|
words |
CaptionWord[] |
(required) | Array of timed words |
font_size |
f32 |
48.0 |
Font size |
font_family |
string |
"Inter" |
Font family |
color |
string |
"#FFFFFF" |
Default (inactive) word color |
active_color |
string |
"#FFFF00" |
Active word color |
background |
string |
Background pill color (hex with alpha, e.g. "#00000088") |
|
style |
string |
"highlight" |
Caption style (see below) |
max_width |
f32 |
Maximum width before word-wrapping |
CaptionWord
| Field | Type | Description |
|---|---|---|
text |
string |
The word text |
start |
f64 |
Start timestamp (seconds, within scene) |
end |
f64 |
End timestamp (seconds, within scene) |
Caption Styles
| Style | Description |
|---|---|
"highlight" |
All words visible, active word changes color |
"karaoke" |
All words visible, active word highlighted (same rendering as highlight) |
"word_by_word" |
Only the active word is shown at a time |
Codeblock Layer
Renders code with syntax highlighting (powered by Syntect), carbon.now.sh-style chrome (title bar with dots), reveal animations, and animated diff transitions between code states.
| Field | Type | Default | Description |
|---|---|---|---|
code |
string |
(required) | Initial code content |
language |
string |
"plain" |
Language for syntax highlighting (e.g. "rust", "javascript", "python") |
theme |
string |
"base16-ocean.dark" |
Theme name (see available themes below) |
font_family |
string |
"JetBrains Mono" |
Monospace font family |
font_size |
f32 |
16.0 |
Font size in pixels |
font_weight |
u16 |
400 |
Font weight (100=Thin, 300=Light, 400=Normal, 500=Medium, 600=SemiBold, 700=Bold, 900=Black) |
line_height |
f32 |
1.5 |
Line height multiplier |
background |
string |
Background color (uses theme default if omitted) | |
show_line_numbers |
bool |
false |
Show line numbers in the gutter |
corner_radius |
f32 |
12.0 |
Background corner radius |
padding |
CodeblockPadding |
Padding around the code area |
Chrome (Title Bar)
Carbon.now.sh-style title bar with colored dots.
| Field | Type | Default | Description |
|---|---|---|---|
chrome.enabled |
bool |
true |
Show the title bar |
chrome.title |
string |
Title text (e.g. filename) | |
chrome.color |
string |
"#343d46" |
Title bar background color |
Line Highlights
Highlight specific lines with a colored background, optionally timed.
| Field | Type | Default | Description |
|---|---|---|---|
highlights[].lines |
u32[] |
(required) | Line numbers to highlight (1-indexed) |
highlights[].color |
string |
"#FFFF0033" |
Highlight color (hex with alpha) |
highlights[].start |
f64 |
Start time (always visible if omitted) | |
highlights[].end |
f64 |
End time |
Reveal Animation
Animate the initial code appearance.
| Field | Type | Default | Description |
|---|---|---|---|
reveal.mode |
string |
(required) | "typewriter" (char by char) or "line_by_line" |
reveal.start |
f64 |
0.0 |
Start time (seconds) |
reveal.duration |
f64 |
1.0 |
Duration (seconds) |
reveal.easing |
string |
"linear" |
Easing function |
Code States (Diff Transitions)
Animate between code versions with automatic diff detection. Unchanged lines slide smoothly, deleted lines fade out, inserted lines fade in, and modified lines show a cursor editing effect.
| Field | Type | Default | Description |
|---|---|---|---|
states[].code |
string |
(required) | New code content |
states[].at |
f64 |
(required) | Transition start time (seconds) |
states[].duration |
f64 |
0.6 |
Transition duration |
states[].easing |
string |
"ease_in_out" |
Easing function |
states[].cursor.enabled |
bool |
true |
Show editing cursor on modified lines |
states[].cursor.color |
string |
"#FFFFFF" |
Cursor color |
states[].cursor.width |
f32 |
2.0 |
Cursor width in pixels |
states[].cursor.blink |
bool |
true |
Blink the cursor (~530ms) |
states[].highlights |
CodeblockHighlight[] |
Override highlights for this state |
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
Counter Layer
Animated number counter that interpolates from a start value to an end value over the layer's visible duration. Uses text rendering internally.
| 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 (see Easing Functions) |
font_size |
f32 |
48.0 |
Font size in pixels |
color |
string |
"#FFFFFF" |
Text color (hex) |
font_family |
string |
"Inter" |
Font family name |
font_weight |
string |
"normal" |
"normal" or "bold" |
align |
string |
"left" |
"left", "center", or "right" |
letter_spacing |
f32 |
Additional spacing between characters | |
shadow |
TextShadow |
Drop shadow behind text | |
stroke |
Stroke |
Text outline/stroke |
The counter animates over the layer's visible duration (start_at to end_at, or the full scene duration if omitted). The easing field controls the interpolation curve of the number, independently from any visual animation presets applied to the layer.
Flex Layer (Layout Container)
A pure layout container that automatically positions its children using flex or grid layout. It has no visual styling (no background, border, or shadow by default) — use it to stack or arrange layers without adding visual chrome.
flex is an alias for card — they share the same properties. Use flex when you only need layout, and card when you need visual styling.
See Card Layer for all available properties (direction, align, justify, gap, wrap, padding, grid properties, etc.).
Card Layer (Flex & Grid Container)
A visual container with CSS-like layout (flex by default, grid optional) for its children. Unlike group (which uses absolute positioning with no visual style), card automatically positions children and supports background, border, shadow, corner radius, and padding.
Flex Layout Example
Grid Layout Example
| Field | Type | Default | Description |
|---|---|---|---|
display |
string |
"flex" |
Layout mode: "flex" or "grid" |
size |
{width, height} |
Container size. Each dimension can be a number or "auto". Auto-calculated from children if omitted |
|
background |
string |
Background color (hex) | |
corner_radius |
f32 |
12.0 |
Corner radius for rounded corners |
border |
CardBorder |
Border stroke | |
shadow |
CardShadow |
Drop shadow | |
padding |
f32 | {top, right, bottom, left} |
Padding inside the card (uniform number or per-side) | |
direction |
string |
"column" |
"column", "row", "column_reverse", "row_reverse" |
wrap |
bool |
false |
Wrap children to next line when they exceed available space |
align |
string |
"start" |
Cross-axis alignment: "start", "center", "end", "stretch" |
justify |
string |
"start" |
Main-axis justification: "start", "center", "end", "space_between", "space_around", "space_evenly" |
gap |
f32 |
0.0 |
Spacing between children (pixels) |
grid_template_columns |
GridTrack[] |
Grid column definitions (required for grid display) | |
grid_template_rows |
GridTrack[] |
Grid row definitions (defaults to [{"fr": 1}]) |
|
layers |
CardChild[] |
[] |
Child layers (positioned automatically; their position field is ignored) |
Per-child Layout Properties
These properties are set directly on child layers within layers:
| Field | Type | Default | Description |
|---|---|---|---|
flex_grow |
f32 |
0 |
How much the child grows to fill remaining space (flex only) |
flex_shrink |
f32 |
1 |
How much the child shrinks when space is insufficient (flex only) |
flex_basis |
f32 |
Base size before grow/shrink (defaults to natural size) | |
align_self |
string |
Per-child cross-axis alignment override: "start", "center", "end", "stretch" |
|
grid_column |
GridPlacement |
Grid column placement (grid only) | |
grid_row |
GridPlacement |
Grid row placement (grid only) |
GridTrack
| Format | Description |
|---|---|
{"px": N} |
Fixed size in pixels |
{"fr": N} |
Fractional unit (distributes remaining space) |
"auto" |
Sized to fit content |
GridPlacement
| Field | Type | Default | Description |
|---|---|---|---|
start |
i32 |
1-indexed grid line (1 = first column/row) | |
span |
u32 |
1 |
Number of tracks to span |
CardBorder
| Field | Type | Default | Description |
|---|---|---|---|
color |
string |
(required) | Border color (hex) |
width |
f32 |
1.0 |
Border width in pixels |
CardShadow
| Field | Type | Default | Description |
|---|---|---|---|
color |
string |
(required) | Shadow color (hex with alpha, e.g. "#00000040") |
offset_x |
f32 |
0.0 |
Horizontal shadow offset |
offset_y |
f32 |
0.0 |
Vertical shadow offset |
blur |
f32 |
0.0 |
Shadow blur radius |
Group Layer
Groups nested layers with a shared position and opacity.
| Field | Type | Default | Description |
|---|---|---|---|
layers |
Layer[] |
[] |
Nested layers (positions relative to group) |
position |
{x, y} |
{x: 0, y: 0} |
Group offset |
opacity |
f32 |
1.0 |
Group opacity (applied to all children) |
Animations
Custom Keyframe Animations
Animate any property over time with keyframes:
Animatable Properties
| Property | Type | Description |
|---|---|---|
opacity |
number | Layer opacity (0.0 - 1.0) |
position.x |
number | Horizontal offset in pixels |
position.y |
number | Vertical offset in pixels |
scale |
number | Uniform scale (1.0 = 100%) |
scale.x |
number | Horizontal scale |
scale.y |
number | Vertical scale |
rotation |
number | Rotation in degrees |
blur |
number | Gaussian blur radius |
visible_chars |
number | Number of visible characters (for text) |
visible_chars_progress |
number | Character reveal progress 0.0 - 1.0 (for text) |
color |
color | Color interpolation (hex strings, e.g. "#FF0000") |
Easing Functions
| Easing | Description |
|---|---|
linear |
Constant speed |
ease_in |
Cubic ease in (slow start) |
ease_out |
Cubic ease out (slow end) — default |
ease_in_out |
Cubic ease in and out |
ease_in_quad |
Quadratic ease in |
ease_out_quad |
Quadratic ease out |
ease_in_cubic |
Cubic ease in |
ease_out_cubic |
Cubic ease out |
ease_in_expo |
Exponential ease in |
ease_out_expo |
Exponential ease out |
spring |
Spring physics (uses spring config) |
Spring Config
When using "easing": "spring", provide a spring object:
| Field | Type | Default | Description |
|---|---|---|---|
damping |
f64 |
15.0 |
Damping coefficient (higher = less oscillation) |
stiffness |
f64 |
100.0 |
Spring stiffness (higher = faster) |
mass |
f64 |
1.0 |
Mass (higher = slower, more inertia) |
Animation Presets
Presets are ready-to-use animations. Set preset on any layer:
Preset Config
| 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 |
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 spring bounce |
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 |
bounce_out |
Bouncy scale to small |
blur_out |
Fade out with blur |
rotate_out |
Rotate + scale to half size |
Continuous Presets
These presets loop automatically when "loop": true is set in preset_config:
| Preset | Description |
|---|---|
pulse |
Gentle scale oscillation (1.0 - 1.05) |
float |
Vertical floating motion |
shake |
Horizontal shake |
spin |
360-degree continuous rotation |
Special Presets
| Preset | Description |
|---|---|
typewriter |
Progressive character reveal (left to right) |
wipe_left |
Slide in from left with fade |
wipe_right |
Slide in from right with fade |
Wiggle
Wiggle adds procedural noise-based motion to any animatable property. Unlike keyframe animations, wiggle produces continuous organic movement.
| Field | Type | Default | Description |
|---|---|---|---|
property |
string |
(required) | Property to wiggle (same as animatable properties) |
amplitude |
f64 |
(required) | Maximum deviation (pixels for position, degrees for rotation, etc.) |
frequency |
f64 |
(required) | Oscillations per second |
seed |
u64 |
0 |
Random seed for reproducible results |
octaves |
u32 |
3 |
Noise complexity (more octaves = more organic detail) |
phase |
f64 |
0.0 |
Phase offset (shifts the noise pattern in time) |
decay |
f64 |
Exponential decay rate (amplitude diminishes over time) | |
easing |
string |
Remap noise output through an easing curve |
Wiggle offsets are applied additively on top of keyframe animations and presets.
Layer Timing
Control when layers appear and disappear within a scene using start_at and end_at:
start_at: the layer is invisible before this time. Animation time is offset sot=0in keyframes corresponds tostart_atend_at: the layer is invisible after this time- Both are optional and independent
start_atmust be less thanend_atwhen both are set
Motion Blur
Adds physically-correct motion blur by rendering multiple sub-frames and compositing them:
| Value | Effect |
|---|---|
0.0 |
No blur |
0.5 |
Moderate blur |
1.0 |
Full frame-duration blur |
The renderer samples 5 sub-frames around the current time, each with proportional opacity.
Glow Effect
Adds a soft luminous halo around any component (text, shapes, icons, etc.). The glow renders as a pre-pass behind the component, keeping the content crisp and readable.
| Field | Type | Default | Description |
|---|---|---|---|
glow.color |
string |
"#FFFFFF" |
Glow color (hex #RRGGBB or #RRGGBBAA) |
glow.radius |
f32 |
10.0 |
Blur radius of the glow |
glow.intensity |
f32 |
1.0 |
Brightness multiplier (higher = brighter, more visible glow) |
Works on all component types: text, shape, icon, image, svg, card, etc.
Freeze Frame
Freeze a scene at a specific point in time. All frames after freeze_at render the frozen state (animations stop, layers stay in place):
The scene continues for its full duration but the visual output is frozen from freeze_at onward.
Output Formats
| Format | Command | Requires |
|---|---|---|
| MP4 (H.264) | rustmotion render in.json -o out.mp4 |
Built-in |
| 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.
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
- GIF decoding/encoding: gif crate
- MP4 muxing: minimp4
- JSON Schema: schemars (auto-generated from Rust types)
- Parallelism: rayon (multi-threaded frame rendering)
License
MIT