Runtimes State Machines

State Machines

Playing and changing inputs in state machines

For more information on designing and building state machines in Rive, please refer to: .

Rive's state machines provide a way to combine a set of animations and manage the transition between them through a series of inputs that can be programmatically controlled. Once a state machine is instantiated and playing, transitioning states can be accomplished by changing boolean or double-value inputs, or firing trigger inputs. The effects of these will be dependent on how the state machine has been configured in the editor.

Playing state machines

State machines are instantiated in much the same manner as animations: provide the state machine name to the Rive object when instantiated. Ensure that the Rive instance is set to auto-play on initialization to allow the state machine to start immediately.

const r = new rive.Rive({
    src: '',
    canvas: document.getElementById('canvas'),
    autoplay: true,
    stateMachines: 'bumpy',
    fit: rive.Fit.cover,

Controlling state machine inputs

Once the Rive file is loaded and instantiated, the state machine(s) can be queried for inputs, and these input values can be set, and in the case of triggers, fired, all programmatically.


The web runtime provides an onLoad callback that's run when the Rive file is loaded and ready for use. We use this callback to ensure that the state machine is instantiated when we query for inputs.

<div id="button">
    <canvas id="canvas" width="1000" height="500"></canvas>
<script src=""></script>
    const button = document.getElementById('button');

    const r = new rive.Rive({
        src: '',
        canvas: document.getElementById('canvas'),
        autoplay: true,
        stateMachines: 'bumpy',
        fit: rive.Fit.cover,
        onLoad: (_) => {
            // Get the inputs via the name of the state machine
            const inputs = r.stateMachineInputs('bumpy');
            // Find the input you want to set a value for, or trigger
            const bumpTrigger = inputs.find(i => === 'bump');
            button.onclick = () =>;

We use the stateMachineInputs function on the Rive object to retrieve the inputs. Each input will have a name and type. There are three types:

  • StateMachineInputType.Trigger which has a fire() function

  • StateMachineInputType.Number which has a value number property where you can get/set the value

  • StateMachineInputType.Boolean which has a value boolean property where you can get/set the value

const inputs = r.stateMachineInputs('bumpy');
inputs.forEach(i => {
    const inputName =;
    const inputType = i.type;
    switch(inputType) {
        case rive.StateMachineInputType.Trigger:
        case rive.StateMachineInputType.Number:
            i.value = 42;
        case rive.StateMachineInputType.Boolean:
            i.value = true;

State change event callback

We can set a callback to determine when the state machine changes state. onStateChange provides an event parameter that gives us the string name(s) of the current state(s):

const r = new rive.Rive({
    src: '',
    canvas: document.getElementById('canvas'),
    autoplay: true,
    stateMachines: 'bumpy',
    onStateChange: (event) => {
        stateName.innerHTML =[0];

Nested Inputs

It's possible to set nested inputs at runtime—an input that is not on the main artboard but on a nested artboard. See . To set a nested input, you'll need to take note of the path where the input exists at an artboard level.

For example, let's say you want to set the volume input on the Volume Component artboard.

This artboard is loaded twice as a nested artboard inside the Volume Molecule artboard and has the unique component names:

  • Volume Component

  • FX Component

It's important to mark the Nested Artboard name as exported: Right-click the component and select Export name. The name will then be surrounded in square brackets, indicating its name is exported. See for more information.

On the main artboard, called Menu, the Volume Molecule artboard is loaded.

The correct paths to set the volume input for these two nested artboards, from the Menu artboard, are:

  • Music Volume: "Volume Molecule/Volume Component"

  • FX Volume: "Volume Molecule/FX Component"

Note that the path should only include Nested Artboards. In this example, the full hierarchy is actually:

  • Menu -> Volume Molecule -> Volume Component

  • Menu -> Volume Molecule -> Fx Component

Menu is the loaded Artboard and, as such, is excluded from the path.

In this example, the nested input is two levels (nested artboards) deep. If you wanted to set an input on the Volume Molecule artboard (one level deep), the path is simply: "Volume Molecule" .

Using this path approach you can access deeper nested artboards by continuing to construct the path, for example: "Artboard-Nested-Level1/Arboard-Nested-Level2/Artboard-Nested-Level3", and so on.

Do not use "/" in the name for your components, as that will break the search functionality at runtime.

To set the Volume input from the above example:

const rive = Rive({...});
rive?.setNumberStateAtPath("volume", 80.0, "Volume Molecule/Volume Component");

All options:

  • setNumberStateAtPath(inputName: string, value: number, path: string)

  • setBooleanStateAtPath(inputName: string, value: boolean, path: string)

  • fireStateAtPath(inputName: string, path: string)

Rive Listeners

If your Rive file has Rive Listeners () and you've configured your Rive instance with a state machine according to the steps outlined per runtime above, there is no additional configuration or options needed to enable the pointer events to be captured on the Rive instance. The event capturing is handled internally by the Rive widget/component.

However, if you are going about constructing your own render loop and using low-level APIs to drive Rive content, (i.e. ) , you may need to set up event listeners manually to capture user interaction and pass feedback down to the state machine (i.e. see setup in JS).