Rive CLI 1.0.3

This release is about the keyboard. Keys are written by name in RML: keyType="escape" instead of keyType="256", so you can read which key a listener responds to without a lookup table. Tab moves focus in the preview window, and --key=right presses a key from the terminal so your agent can test without you. Update with rive update (curl install) or brew upgrade --cask rive-cli.

Keyboard and focus

  • โŒจ๏ธ --key presses a key from the terminal: rive myproject --key=right --screenshot presses Right and captures the result, exactly as if a user had pressed it. Add a phase to send half a keystroke (--key=a:down) or a modifier (--key=tab:down+shift); phases are down, repeat, up, or press (the default, down then up). Repeat it and mix it with --pointer and --advance in any order: click, type, wait, screenshot, in one command. Key names are the same ones you write in RML.

  • ๐Ÿ”ค Named keys in markup: <KeyboardInput keyType="up"/> instead of <KeyboardInput keyType="265"/>. Names cover letters, function keys, and the keypad (a, f1, kpEnter); arrows accept right or arrowRight. Leave keyType out, or set it to any, and the listener matches every key.

  • ๐Ÿ”€ Tab moves focus in the preview window: before, a focusable item inside a Component could not be reached with the keyboard at all, because nothing turned a Tab press into a move. Tab and Shift+Tab now step through every focusable item, Components included.

  • ๐ŸŽฏ Keyboard listeners keep the keys they handle: before, a scene that responded to Escape still passed Escape on to the app hosting it. Now a listener that matches the key consumes it. Other listeners on the same object still see the key; only parents and the host stop hearing it. โš ๏ธ If your app forwards keys into a Rive scene, expect keys the scene handles to stop reaching your own handlers.

  • ๐Ÿ” Your scene gets Tab before the viewer does: if the scene has a listener that handles Tab, it keeps Tab (repeats and release included); if not, Tab moves focus.

CLI commands and flags

  • ๐Ÿ“ค rive push can target your personal files: before, the project picker listed only Workspace projects. Personal files are now listed first, and projects you can only read are left off.

  • ๐Ÿšซ A mistyped flag is now an error: rive myproject --advnace=10 used to build without the flag and exit 0, so a typo silently changed what you captured. It now prints the unknown flag and exits 2. --json is accepted as an alias for --format=json.

  • ๐Ÿ“‹ rive schema always honours --json: rive schema KeyboardInput --json returns JSON, and so do --list --json and --search --json. Before, they fell back to the human-readable table when the terminal could not draw the picker, which broke agents parsing the output. Bitmask fields like keyPhase now list what each bit means.

  • ๐Ÿ” rive inspect --summary: the problems rive inspect already reports, plus a count of objects per type, so you can confirm a build produced the 12 text runs you expected. Honours --artboard, works on script-only projects, and counts view models and enums that live outside any artboard.

  • ๐Ÿค– rive create no longer hangs under an agent: rive create with no directory used to prompt for a name, and an agent running it in a pipe waited forever. It now prompts only when both stdin and stderr are a terminal (and never when RIVE_NO_TUI or CI is set); otherwise it exits 2 with the fix: rive create <dir>.

  • ๐Ÿ“ rive create scaffolds CLAUDE.md: Claude Code reads only its own filename, so the new file imports AGENTS.md. AGENTS.md now points agents at --format=json, the screenshot check, inspect --summary, and schema --json, and tells them RML is newer than their training data.

  • ๐Ÿ” Installer lists rive login last, with a note that you only need it for --publish, --rev, and push.

RML (the markup the CLI compiles)

  • ๐Ÿงฑ A misplaced input is a build error: <KeyboardInput> belongs inside <ListenerInputTypeKeyboard>. Put it anywhere else and, before, the file built clean, the input never reached the .riv, and the listener quietly fired on every key. The error now names the element and where it belongs.

  • ๐Ÿฉน XML mistakes are explained, not coded: a missing close tag used to report XML_ERROR_MISMATCHED_ELEMENT ErrorID=14. It now reads <Group> is never closed, or is closed by a different tag; add </Group> where it ends, with the line number. Same treatment for malformed elements, unquoted attributes, and empty files.

  • ๐Ÿงฉ Component instances keep their own values: before, a stateful Component's view model values were not linked to their instance in the .riv, so every instance showed the placeholder values the Component was authored with and its triggers did nothing. Each instance now carries its own values.

  • ๐Ÿ–ผ๏ธ <BitmapCache> (cache as bitmap) is now an RML core type.

Docs and samples

  • ๐Ÿ“– New docs/focus.md: how focus moves between items, not only how a listener checks for it.

  • ๐Ÿ“– format.md documents keyPhase (1 down, 2 repeat, 4 up; 7 fires on both press and release) and exact-match modifiers; gotchas.md covers the two valid listener spellings and the two-rows-per-arrow-press menu bug.

  • ๐Ÿงช New samples/keyboard_menu: a menu you drive with the arrow keys and Enter. samples/text_input updated.

  • ๐Ÿ”— The VS Code extension docs now link to the CLI's published page.


If you missed the CLI intro announcement, check the launch thread here: