Skip to main content

Script Types Overview

Rive provides 8 runtime/course script types, each designed for a specific purpose. The editor also exposes FileFormat and TextFileFormat extension protocols for custom documents; those are covered separately because they do not attach to an artboard or run as runtime behavior scripts.

Runtime baseline

This overview is aligned to direct Web 2.42.0 -> C++ runtime-v0.1.344. Current editor-only and later-source surfaces remain explicitly tiered. For versioned API tracking, see Runtime Compatibility Baseline.

Need Full Access/Limitations Matrix?

For a comprehensive "what can each script type do?" reference (including callback parameters, path-geometry boundaries, and input accessibility), see Script Capability Matrix.

Coming from Part 1?

If you haven't read How Rive Scripts Work yet, start there first. It explains WHY scripts have the structure they do — the "protocol" concept, factory functions, and lifecycle callbacks.


The 8 Script Types

Script TypePrimary PurposePlacement / Binding Target
Node ScriptAnimation logic, custom renderingScene script node
Layout ScriptCustom layout behaviorLayout components
Converter ScriptData transformation for bindingsData bindings
Path Effect ScriptModify path geometryStrokes & Fills
ListenerAction ScriptCustom logic on state machine listener eventsState machine listeners
TransitionCondition ScriptCustom transition evaluation logicState machine transitions
Util ScriptShared code librariesNothing (imported)
Test ScriptUnit testing Util ScriptsNothing (run manually)

Editor extension protocols

ProtocolPurposePlacement
FileFormatClaim a binary extension and optionally preview itScript asset used by the editor/import pipeline
TextFileFormatClaim an editable text extension and provide highlighting, diagnostics, completions, hover, formatting, or previewsScript asset used by the editor/import pipeline

Text FileFormat documents export as Blob assets. Runtime scripts read the result with context:blob(name); they do not receive FormatDocument or EditorContext.

Listeners

Listener<T> is a function signature, not a script type. See Listeners for details.


Node Script

Use when: You need animation logic, custom drawing, or interactive behavior on a node.

Key features:

  • Lifecycle callbacks: init, update, advance, draw
  • Pointer event handlers: pointerDown, pointerMove, pointerUp
  • Current Editor-reference gamepad handlers: gamepadConnected, gamepadEvent, gamepadDisconnected
  • Source/runtime compatibility handlers: textEvent, keyboardEvent (not listed in the August 14 current Editor Node<T> reference)
  • Access to Renderer for custom drawing
  • Access to Canvas / GPUCanvas render work from draw for offscreen and shader workflows (Early Access for GPU)
  • Can have inputs from the editor

Placement: A Node script is added to the artboard as a script node. You can leave it at the artboard root or nest it under a group/shape for normal hierarchy behavior such as transform inheritance and draw order. Nesting does not pass the parent shape's NodeData or PathData into the Node callbacks.

Typical use cases:

  • Procedural animations (particles, physics)
  • Custom drawing (graphs, visualizations)
  • GPU shader passes and post-processing
  • Interactive elements (buttons, sliders)
  • Game logic (collision, scoring)

Factory return type: Node<T>

return function(): Node<MyScript>
return { init = init, advance = advance, draw = draw }
end

Learn more: Node Script Protocol → | Node Lifecycle →


Layout Script

Use when: You need programmatic control over how child elements are positioned and sized within a Layout component.

Key features:

  • All Node Script lifecycle callbacks PLUS:
  • measure() - Propose ideal size (for "Hug" fit type)
  • optional resize(size, displayScale) - React to box or display-scale changes

Typical use cases:

  • Masonry grids
  • Carousels with custom spacing
  • Responsive layouts with breakpoint logic
  • Data-driven layout systems

Factory return type: Layout<T>

return function(): Layout<MyLayout>
return { init = init, measure = measure, resize = resize, draw = draw }
end

At the Web 2.42.0 target, Rive dispatches resize(self, size, displayScale). displayScale is device pixels per layout point. A scale change after a valid size redispatches the callback; an unchanged scale is silent. Existing two-parameter callbacks remain compatible.

Learn more: Layout Script Protocol →


Converter Script

Use when: You need to transform data between a source and target in data bindings.

Key features:

  • convert(input) - Transform source → target
  • reverseConvert(input) - Transform target → source (for two-way binding)
  • Works with DataValue types (Number, String, Boolean, Color)

Typical use cases:

  • Format numbers (add units, decimals)
  • Temperature conversion (Celsius ↔ Fahrenheit)
  • Color transformations
  • String formatting/parsing

Factory return type: Converter<T, InputType, OutputType>

return function(): Converter<MyConverter, DataValueNumber, DataValueString>
return { convert = convert, reverseConvert = reverseConvert }
end

Learn more: Converter Script Protocol →


Path Effect Script

Use when: You need to modify the geometry of a path in real-time (stroke effects, fill distortions, warps).

Key features:

  • update(inPath, node) - Receives original PathData and host NodeReadData, returns modified PathData
  • advance(seconds) - Optional frame updates for animated effects
  • Access to PathCommand iteration

Typical use cases:

  • Wave/wobble distortion effects
  • Custom dash patterns
  • Procedural path generation
  • Animated stroke and fill effects

Factory return type: PathEffect<T>

return function(): PathEffect<MyEffect>
return { init = init, update = update, advance = advance }
end

Learn more: Path Effect Script Protocol →


ListenerAction Script

Use when: You need custom logic to run when a state machine listener event fires.

Key features:

  • init(self, context) - One-time initialization
  • performAction(self, listenerContext) - Executed when the listener action triggers (preferred)
  • perform(self, pointerEvent) - Legacy/deprecated callback in older scaffolds
  • listenerContext supports typed branching (is... / as...) for pointer, keyboard, text, focus, and listener payload kinds
  • Attached to state machine listener events

Typical use cases:

  • Custom side-effects when a state transition fires a listener
  • Triggering audio, analytics, or other actions from state machine events
  • Complex logic that can't be expressed with simple state machine outputs

Factory return type: ListenerAction<T>

return function(): ListenerAction<MyAction>
return { init = init, performAction = performAction }
end

Learn more: ListenerAction Script Protocol →


TransitionCondition Script

Use when: You need custom logic to evaluate whether a state machine transition should fire.

Key features:

  • init(self, context) - One-time initialization
  • evaluate(self) - Returns true/false to allow/block the transition
  • Attached to state machine transitions

Typical use cases:

  • Complex transition conditions that depend on multiple inputs
  • Time-based or physics-based transition logic
  • Conditions that require script-level computation

Factory return type: TransitionCondition<T>

return function(): TransitionCondition<MyCondition>
return { init = init, evaluate = evaluate }
end

Learn more: TransitionCondition Script Protocol →


ScriptedInterpolator (Runtime-Backed Advanced Protocol)

Use when: You need custom interpolation curves at runtime for keyframe value blending and want script-controlled easing behavior.

Current status:

  • Runtime support is present in the audited C++ bindings tracked by the current compatibility baseline.
  • This protocol is documented in LERP for compatibility tracking and advanced usage.
  • Editor UI exposure can lag runtime support; verify availability in your current editor build before production use.

Key methods:

  • transform(self, factor) -> number (optional)
  • transformValue(self, valueFrom, valueTo, factor) -> number (optional)

Fallback behavior:

  • If methods are omitted or fail, runtime falls back to standard linear interpolation behavior.

Learn more: ScriptedInterpolator Protocol →


Util Script

Use when: You have shared code (math functions, constants, helpers) used by multiple scripts.

Creating a Util Script

In the Rive editor, select Blank Script from the script type dropdown. There is no dedicated "Util Script" option—you create one by selecting Blank Script and following the Util Script pattern described below and in the official Rive docs.

Key features:

  • No lifecycle callbacks — just a module table
  • Imported with require("UtilName")
  • Runs once when first required (cached)
  • Perfect for pure functions and constants

Typical use cases:

  • Math utilities (lerp, clamp, easing functions)
  • Color palettes and constants
  • Helper functions shared across scripts
  • Configuration objects

Return type: Module table (not a factory)

local MathUtils = {}

function MathUtils.lerp(a: number, b: number, t: number): number
return a + (b - a) * t
end

return MathUtils

Learn more: Util Script Protocol →


Event Listening (Not a Script Type)

Listener<T> is NOT a Script Type

Listener<T> is a function signature for addListener()/removeListener() methods, not a script return type.

To handle events in Rive, use these patterns:

1. ViewModel Property Listeners (in Node scripts):

function init(self: MyNode, context: Context): boolean
local vm = context:viewModel()
local score = vm:getNumber("score")
if score then
score:addListener(function()
print("Score changed to: " .. score.value)
end)
end
return true
end

2. Pointer Events (in Node scripts):

function pointerDown(self: MyNode, event: PointerEvent)
print("Clicked at: " .. event.position.x)
end

Learn more: Listeners →


Test Script

Use when: You want to write unit tests for your Util Scripts.

Key features:

  • setup(test: Tester) - Define test cases
  • test.case(name, fn) - Individual test
  • test.group(name, fn) - Group related tests
  • expect(value).is(expected) - Assertions

Typical use cases:

  • Verify math utilities work correctly
  • Test edge cases in helper functions
  • Regression testing after changes
  • Document expected behavior

Return type: Tests (function)

local MathUtils = require('MathUtils')

function setup(test: Tester)
test.case('lerp at 0.5', function(expect)
expect(MathUtils.lerp(0, 100, 0.5)).is(50)
end)
end

return function(): Tests
return setup
end

Learn more: Test Script Protocol →


Scripts and State Machines

Rive state machines decide what state an animation is in. Scripts decide how that state is visualized or extended.

How they connect:

  • ViewModels are the primary data bridge. Use ViewModel properties to drive script behavior and UI state.
  • Script Inputs (Input<T>) are best for per-instance tuning from the inspector.
  • State machine inputs are a legacy path for data flow; use them only when integrating existing files.
  • Property listeners (addListener()) respond to ViewModel property changes triggered by state machines.
  • Node scripts render visuals and can read inputs or ViewModel values to drive drawing.

Typical flow:

  1. State machine or interaction updates a ViewModel property (for example, isHovering = true)
  2. Script reads that value in update() or via addListener()
  3. Script changes visuals in draw() or updates ViewModel data

If you need to react to property changes, use property:addListener() in a Node script. If you need to render or animate based on inputs, use update() or advance() callbacks.


Quick Decision Guide


Factory Functions Recap

Remember from Part 1: every script (except Util and Test) uses a factory function. The factory creates fresh instances so each object using your script gets its own data.

Script TypeFactory Return
NodeNode<T>
LayoutLayout<T>
ConverterConverter<T, In, Out>
Path EffectPathEffect<T>
ListenerActionListenerAction<T>
TransitionConditionTransitionCondition<T>
UtilModule table (no factory)
TestTests function (no factory)

Next Steps