u/Jeff_at_Rive

Listener Action Scripts in Rive — Detecting Double Clicks

Rive's listener action scripts let you run custom logic when a listener fires in a state machine. One practical use case: distinguishing a double click from a single click, which is tricky to do with standard listeners alone.

Here's how the double click detector works:

The script uses three properties in its type definition: a threshold number (default 0.3 seconds), a clicked trigger, and a doubleClicked trigger pulled from the view model, plus a lastClickTime number initialized to -1.

In init, it grabs the view model and resolves both triggers by name.

In performAction, it checks that the incoming action is a pointer event, then captures the current time. It compares lastClickTime against the threshold:

• If lastClickTime >= 0 and time elapsed ≤ threshold → fires doubleClicked, resets lastClickTime to -1
• Otherwise → fires clicked, sets lastClickTime to now

Because threshold is exposed as a script input, you can override it per-listener without touching the script itself. In the demo it's set to 0.3s by default, adjustable to 0.5s or whatever feels right for your use case.

To wire it up: select your listener target shape, add a listener, set the event to Click, choose the listener action script type, and pick your script. The threshold input appears inline. Then in the state machine, use the Any State node with clicked and doubleClicked trigger conditions to drive transitions to whichever animations you want.

The video shows this applied to a bubble animation — single click triggers a grow-and-shrink, double click triggers a pop.

u/Jeff_at_Rive — 4 days ago

First Look: Stateful Components in Rive

Stateful Components are a new way to reuse components in Rive without wiring up a separate view model instance for each one.

Here's how they work: you build a component (say, a button) and attach a view model with whatever properties you want to expose — label text, background color, text color, etc. When you make it a component, you'll see a new Properties section in the inspector. Click + to choose which view model properties to expose, and mark each one as either input (you can set the value per instance) or output (the value can be read by a parent).

Once you nest that component somewhere else and flip it to stateful, those exposed properties show up directly in the inspector. Each instance can have its own values — no nested view model required. Copy the component 3 times, give each one a different label and color, done.

Nesting goes deeper too. A card component with its own view model can contain a stateful button, and you can bubble the button's properties up through the card's view model so the parent can override them as well.

Output properties work the other way: a slider component can expose its current value as an output, and a parent artboard can data bind to that value to read it in real time.

One more thing: input properties can be keyed on timelines. So you can animate a per-instance color override across a loop without touching the original component.

u/Jeff_at_Rive — 8 days ago

Relative binding in Rive lets you bind properties by name rather than by a fixed path. That means two completely different artboards — from two different files, with different view model names — can share the same data at runtime, as long as the property names match.

This video covers two practical uses of that:

  1. Swapping a single artboard component at runtime. You wrap your artboard in a parent file, bind the nested artboard to an "artboard" property using bind relative, then swap in a different .rive file at runtime. The replacement artboard picks up all the same data automatically — even if the source file has a differently named view model, the properties still resolve correctly.

  2. Swapping individual components in a multi-component dashboard. The example uses a world population dashboard with 7 continents, each with its own nested view model instance (color, name, population, percent). The dashboard has slots for different chart types — donut, bar, table. At runtime you can replace any slot with a new component from an external file. As long as the component's view model uses the same property names, the data maps over without any rewiring.

The key rule: property names must match. View model names and nesting order don't matter.

Useful if you're building things like:

  • Theming systems where the design can be swapped without touching the data layer
  • Dashboards with interchangeable visualizations
  • Library components that work across multiple host files
u/Jeff_at_Rive — 18 days ago