Write Rive animations as JSON. Compile them to real .riv files. Prove they work before you ship.
Live demo and verification lab · Skill file for agents · Scene schema
An AI agent can write an animation scene in seconds. It cannot tell you whether a state is missing,
a property sits on the wrong object, or the file quietly breaks in the real Rive player. rive-cli
turns those unknowns into checks you can run again, in a terminal or in CI.
The coffee loader on the demo page is not a recording.
It is a .riv file this tool built from JSON, playing in the official Rive runtime. Against the
file Rive's own designers made, it holds a 0.2833% maximum pixel difference across the checked
frames.
- A file format you can edit. Scenes are plain JSON in your repo, so they diff, review, and merge.
- A binary the runtime accepts.
generatewrites the.rivformat the Rive players read, with no editor in the loop. - Answers a tool can act on. Object counts, missing types, pixel differences, content bounds, and a text coverage map, all available as JSON.
- A self-describing contract.
schema,types, anddescribelist every field, parent, and animatable property, so an agent never has to guess.
Start from a known-good scene, make it your own, compile it, validate the binary, then render it with the real Rive canvas runtime:
rive-cli new spinner -o scene.json
# Edit scene.json.
rive-cli generate scene.json -o out.riv
rive-cli validate out.riv
rive-cli render out.riv --frames 0,15,30,45 --preview -o frames/render --preview prints an ASCII coverage map, dominant-colour percentage, and non-background bounds for each frame. It also writes preview.txt and manifest.json, alongside the PNG files, so a non-visual workflow can still inspect what was rendered.
rive-cli generate scene.json -o output.riv
rive-cli validate output.riv
rive-cli inspect output.riv --type-name Shape
rive-cli decompile output.riv --jsongenerate INPUTaccepts-o, --output,--file-id, and--json.validate FILEaccepts--json.inspect FILEaccepts--json,--artboard-index,--artboard-name,--local-index,--type-key,--type-name,--object-index, and--property-key.decompile FILEaccepts--json.
--json is also available globally and on each command that produces structured output. Errors in JSON mode use the stable envelope {ok, command, code, message}.
rive-cli schema
rive-cli schema --compact
rive-cli types --category paint
rive-cli describe ellipse --jsonschemaprints the complete SceneSpec JSON schema;--compactremoves indentation.typeslists usable object types;--categoryfilters the list.describe TYPEreports the type's fields, enum values, valid parents, and animatable properties. Its animation-property resolver is the same onegenerateuses.
rive-cli new --list
rive-cli new animated -o scene.jsonnew TEMPLATE writes a known-good SceneSpec to standard output or, with -o, --output, to a file. The available templates are shape, animated, gradient, spinner, button, and multi.
rive-cli render output.riv
rive-cli render output.riv --frames 0,15,30,45 -o frames/
rive-cli render output.riv --frames 0..120:10 --width 800 --height 600
rive-cli render output.riv --animation spin --contact-sheetrender FILE drives headless Chromium directly over CDP from Rust; it does not use Node or Playwright. A Chrome or Chromium executable is therefore required. For a non-standard browser location, set $RIVE_CHROME or pass --browser /path/to/chromium.
Render options:
| Option | Purpose |
|---|---|
-o, --output DIR |
PNG and manifest output directory (default renders) |
--frames LIST_OR_RANGE |
Frame list such as 0,15,30, or range such as 0..120:10 |
--fps FPS |
Frames per second used to convert indices to time |
--animation NAME |
Linear animation to scrub |
--state-machine NAME |
State machine to advance instead of an animation |
--input NAME=VALUE[@FRAME] |
Repeatable state-machine bool, number, or trigger input. @FRAME applies it when the stepper reaches that frame |
--pointer EVENT:X,Y@FRAME |
Repeatable pointer event (down, up, move, enter, exit) in artboard coordinates, dispatched through Rive's own listener handling |
--artboard NAME |
Artboard to render |
--width PX, --height PX, --scale RATIO |
Logical dimensions and device-pixel multiplier |
--background COLOR |
Background behind the artboard, for example #202024 |
--contact-sheet |
Write a horizontal filmstrip in addition to individual frames |
--preview |
Print and write text coverage previews |
--browser PATH |
Override browser discovery |
--json |
Emit the render manifest as JSON |
Each frame in manifest.json records its PNG path, distinct-colour count, and blank flag, and the manifest also records the inputs and pointer events that were applied. Identical inputs produce byte-identical PNGs.
--input and --pointer both require --state-machine. Interaction is proved the same way animation is: render the same frames with and without the flag and require the frames before the scheduled frame to be byte-identical.
rive-cli compare official.riv ours.riv \
--frames 0,15,30,45 \
--reference-state-machine 'State Machine 1' \
--candidate-state-machine 'State Machine 1' \
--max-pixel-diff 5compare REFERENCE CANDIDATE decompiles both files, renders both, and prints a per-type object
delta table plus a pixel difference for each frame. It exits non-zero only when you pass
--max-pixel-diff PCT and the worst frame goes over it, so it drops into CI as a gate. Frame,
size, background, animation, and state-machine flags mirror render, with --reference- and
--candidate- prefixes where the two files differ.
rive-cli --list-presets
rive-cli ai generate --template spinner -o output.riv
rive-cli ai lab --suite evals/suites/prompt_lab.v1.jsonai generate accepts either --prompt or --template; ai lab runs a suite given by --suite. The optional MCP server is built with --features mcp.
Read skills/rive-animation/SKILL.md before authoring a scene. It describes the scaffold → discover → generate → validate → render loop and the runtime constraints that structural validation alone cannot catch.
The ten scenes in showcase/ are a gallery of working examples: six basics authored end to end by a fresh-context agent, and four advanced scenes covering embedded fonts, path morphing, embedded imagery and pointer-driven state machines. Use rive-cli describe <type> rather than guessing fields or animation properties.
site/ is a dependency-free page published at
george-rd.github.io/rive-rs-cli. Everything on it plays
live in the vendored Rive runtime, so nothing is a recording. The landing hero is this tool's own
parity/reproductions/coffee_loader.riv, and the
verification lab puts each
official Rive file beside the copy rive-cli generated, with the measured gap underneath.
Preview it with node site/serve.js. .github/workflows/pages.yml publishes it, and
node tests/playwright/site-validation.js asserts every canvas paints, the reported figures match
parity/results.json, and the console stays clean.
parity/ holds the official files, the JSON that reproduces them, and
results.json, the numbers the lab displays. parity/fetch-official.sh re-fetches the upstream
files and checks them against a pinned manifest.
promo/ is a Remotion composition assembled from PNG sequences that rive-cli render produced, so every frame in the video is a frame the test suite verifies. See promo/README.md to rebuild it.
Scene specs require scene_format_version: 1:
{
"scene_format_version": 1,
"artboard": {
"name": "Main",
"width": 500,
"height": 500,
"children": []
}
}The complete generated schema is docs/scene.schema.v1.json. Format and runtime-compatibility constraints are recorded in docs/format-spec.md.
Build from source:
cargo build --release
./target/release/rive-cli --helpPrebuilt binaries and platform packages are documented in docs/install.md.
cargo test
npx -y -p playwright node tests/playwright/regression.js
npx -y -p playwright node tests/playwright/visual-regression.jsThe Rust tests cover generation and structural validation. The runtime and visual regressions load generated files in the official Rive canvas runtime and compare actual renders against PNG baselines.
MIT