Skip to main content
Run rive --help for this list in your terminal, and rive --version to print the installed version.

Commands

update, switch and uninstall are only supported for the installer build under ~/.rive/bin. If installing the CLI via Homebrew, use the brew methods to manage CLI versioning and updates.

Project flags

These apply to rive <project-dir>.

Build modes

Mutually exclusive, so pick one. --screenshot, --semantics, --data-dump and --render-audio under Capture each count as one of them. With none of them, the CLI opens the preview window and rebuilds as you edit.
--publish may add a watermark to the graphic. A clean .riv needs two things: the project bound to a file in your Rive account, and that file in a workspace on the Cadet plan or higher. Binding is done by rive push, which records push.fileId in rive.yaml. The watermark applies whether or not the project has scripts.

Modifiers

These attach to whichever mode you chose.

Capture

--bench runs instead of --screenshot, not alongside it. Passing both times the frames and writes no PNG, without saying so. It is a build mode in its own right, so it does not combine with --verify, --once, --publish or --test. It renders at the artboard’s own size and ignores --viewport, and it runs 300 warm-up frames before the ones it times.

Driving the scene

Interactions run in the order you write them, and every one of them needs a capture mode: --screenshot, --semantics, --data-dump or --render-audio.

Advancing time

--advance steps the scene where it sits among the other interactions. A bare number is whole frames at 60fps; 1s or 250ms is animation time, stepped in 1/60s frames with one shorter frame for any remainder. The time forms take a decimal point, so 1.5s is 90 frames.
Position it for what you need:
A sign, whitespace, trailing text, a decimal point on a bare frame count, or a value above a 32-bit unsigned integer is rejected with exit code 2.
--advance replaces --frame. A bare --advance=N means what --frame=N meant, so --frame=20 becomes --advance=20. Passing --frame is an error naming --advance.--bench takes its own frame count and does not combine with --advance, --pointer, --gamepad, --semantics or --semantic-action.

Setting data

--data takes a property path and a value. The path starts at the view model instance bound to the artboard, and every segment is a property name, so a flat view model takes the bare property and a nested one takes a path:
A --data before any interaction sets a starting value. One placed after a --pointer, --touch, --key, --gamepad, --semantic-action or --advance applies at that point in the sequence and then runs a frame, so you can change data mid-run. Repeat the flag to set several:
A path that matches no property fails the run with --data <path>: no property at this path and exit 1, and no capture is written. An artboard with no view model bound reports --data <path>: no view model is bound to this artboard instead. Both print even under --quiet.

Reading data back

--data sets values going in; --data-dump reads them back out. It builds, runs headless, and writes the bound view model values as JSON, so a test can assert on what the scene computed:
--data-dump-every turns that into a time series instead of a single reading: a header, a frame-0 baseline, then only what changed on each sample, written to build/<name>.data.jsonl. It takes a whole number of frames at 60fps, and counts the frames gestures advance internally.

Simulating a keystroke

--key sends a key through the same dispatch path a real one takes. The phase is down, repeat or up, and defaults to press, which is a down then an up. Modifiers attach with +:
Key names are the same ones the markup uses, so right, escape, f1 and kpEnter all resolve.
Keys only reach whatever holds Rive focus. With nothing focused, the CLI says so and names the fix: the file needs a FocusData on the listener’s target, and something to focus it.

Simulating a pointer

--pointer takes a kind and a position. down, up, move, exit, and click each take a single point. click expands to a move, a press and a release with a frame between each, because a state machine only sees a gesture when it next runs:
wheel@x,y:dx,dy[:notches] and trackpad@x,y:dx,dy[:steps] scroll the content by dx,dy in artboard units. A wheel is one notch unless counted, and a trackpad is a two-finger swipe that flings, defaulting to 8 steps. --pointer only checks the shape of the value. A kind it does not know parses fine, then fails at delivery with pointer: unknown gesture and exits with 1. drag is a fifth kind, and the only one with a different shape: drag@x1,y1>x2,y2[:steps]. It moves to the first point, presses, emits steps moves along the line to the second point, then releases. steps defaults to 8. Every event gets its own frame, so a drag runs for steps + 3 frames: a higher count is a finer and slower sweep, a lower one a flick. Scroll physics reads the velocity that implies, so the count changes how far a scroll throws.
Quote the drag value so the shell does not read > as a redirection.

Serving

Other

Publishing to the web

--publish=web builds, signs and hosts the project as a page anyone can open. See Publishing to the web.

Preview window commands

Type these in the terminal while the preview window is open.

Per-command flags

create

--from-rev converts an editor .rev into a project: scene.rml plus its scripts and assets as files. Without a <dir>, the .rev’s own name is used. The directory must be empty or new. --from-remote-file does the same conversion on a file downloaded from your Rive account. Without a file ID, the CLI lists your projects and files to pick from. rive.yaml records the link, so rive push updates that source file and rive pull brings any remote changes in. This requires a logged in session with rive login.

schema

docs

samples

inspect

Exits 1 when problems contains an error, and 1 with a message on stderr when the directory has no rive.yaml.

push

This uploads the project to your Rive account, replacing the bound file’s contents and adding an entry to its revision history. It is the same artifact --rev would export. See Pushing to a Rive file.

pull

Downloads the Rive file the project is linked to and writes it over the project: the scene markup, and every script, shader and asset as a file. Files whose bytes already match are left alone, and build inputs missing from the remote file are reported rather than deleted. rive.yaml takes the remote file’s main artboard and build settings and keeps every other line. AGENTS.md, CLAUDE.md and anything else you added are untouched. This command names the file and the project and asks before it runs, defaulting to no:
At this time, pull replaces your local project’s scene, scripts and assets with the remote file’s.

ls

Lists what is in your Rive account, one workspace at a time. It only reads. On a terminal it browses: arrows move, enter or right opens, left or backspace goes up, typing filters, escape quits. Piped, under an agent, or with RIVE_NO_TUI=1, it prints instead. Every row names its kind and its id, and the JSON keys are projectId, folderId and fileId, which are the ids the other commands take:

workspace

rive ls and rive push work one workspace at a time, and this chooses which. It is your personal workspace until you switch, and the choice persists. Use rive ls --workspace=<id> to read another one without switching.

open

Works for any file you can open, and rive ls prints file ids.

library

A library is content published in Rive that other files import: artboards marked as components, view models, enums, scripts and shaders. What a project imports is recorded in the libraries block of rive.yaml, and rive pull downloads the snapshots. library list reads the project’s own markup, so it runs offline and needs no session. The rest need rive login.
library search and library publish depend on the workspace’s plan. Where it is not enabled the CLI says so and names the account page to upgrade on. library list, library info and library update have no such check.
Each subcommand takes its own flags. A library is named by its id rather than its name, because a library’s name is its source file’s name and can change at any time. library search takes --project to answer for a project other than this one; library info does not, since an id names a library on its own.
library publish pushes the project before publishing, because a version is cut from the file’s content. That push overwrites the remote file, so run rive pull first if someone else has been working in it.

doctor

doctor prints a row per check, each ok, warn or fail. version, update, auth, live-link and project cover authoring, and further rows report on device builds where the platform supports them. It exits 0 when everything is ok or warn, and 1 when a check fails.

Signing in

Credentials live outside the project: ~/.config/rive/app.rive.cli/ on macOS and Linux, honouring XDG_CONFIG_HOME, and Windows Credential Manager on Windows.
A gated mode checks the session live, so --publish and --rev fail on a dropped connection even with valid stored credentials.

Exit codes

Any argument without a leading -- is read as the project directory. Passing more than one is not an error: the CLI builds the one furthest right and says nothing about the others, so a stray word changes what gets built.

JSON output

--format=json on --once, --verify, --publish or --test prints one JSON object on stdout. data differs per mode. --verify and --once carry the build:
--test carries the run:
command is the mode, not the flag: "build" for --once, "verify" for --verify, "publish" for --publish, "test" for --test. Each entry in data.problems is {severity, kind, code, script, line, column, message}, with severity one of error, warning or hint. errors repeats them as script:line message strings. data.riv is null on --verify and on any failed build. Logs stay on stderr, so stdout carries nothing else.

Environment variables

Interactive pickers draw on stderr, so redirecting stdout alone does not disable them. Where no picker can draw (TERM=dumb, RIVE_NO_TUI=1, or stdin not a terminal as in CI), the CLI falls back to printing the list instead.