Skip to main content

Script Types Overview

Rive provides 6 script types, each designed for a specific purpose. This page gives you the big picture — which script type to choose and when.

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 6 Script Types

Script TypePrimary PurposeAttach To
Node ScriptAnimation logic, custom renderingAny node
Layout ScriptCustom layout behaviorLayout components
Converter ScriptData transformation for bindingsData bindings
Path Effect ScriptModify path geometryStrokes
Util ScriptShared code librariesNothing (imported)
Test ScriptUnit testing Util ScriptsNothing (run manually)
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
  • Access to Renderer for custom drawing
  • Can have inputs from the editor

Typical use cases:

  • Procedural animations (particles, physics)
  • Custom drawing (graphs, visualizations)
  • 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)
  • resize(size) - React to size changes, position children

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

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, distortions).

Key features:

  • update(inPath) - Receives original PathData, 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 effects

Factory return type: PathEffect<T>

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

Learn more: Path Effect Script 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:

  • Inputs are the bridge. Bind state machine inputs to script inputs or ViewModel properties.
  • 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 updates an Input (e.g., isHovering = true)
  2. Script reads that input in update() or advance()
  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>
ListenerListener<T>
UtilModule table (no factory)
TestTests function (no factory)

Next Steps