Data & Input
APIs for script inputs, properties, runtime context, and data binding.
Input
An input is a value on your script that appears as a control in the Rive editor's inspector panel. When someone changes that control, your script receives the new value automatically.
Think of inputs like knobs and sliders on a mixing board — they let you (or someone using your file) adjust behavior without editing code.
How Inputs Work
- You declare an input in your script's type definition
- You provide a default value in the factory return
- The input appears in the editor as a control (slider, checkbox, color picker, etc.)
- When the value changes, Rive calls your script's
update()function - You read the value with
self.inputName— no.valueneeded
export type MyNode = {
speed: Input<number>, -- declares an input called "speed"
}
function update(self: MyNode)
-- This runs whenever speed changes in the editor
print("Speed is now: " .. self.speed)
end
return function(): Node<MyNode>
return {
init = init,
update = update,
draw = draw,
speed = 50, -- default value: 50
}
end
Inputs (Input<T>) are read with self.speed — no .value.
Properties (Property<T>) from ViewModels are read with prop.value.
They look similar but work differently. If you're using self.something and it's an input, just use it directly.
Input<number>
A numeric value. Appears as a number field in the editor.
When to use: Anything that's a number — speed, size, count, opacity, angle, duration.
Factory default: Any number (e.g. 42, 0.5, 100).
How to read: self.speed returns the number directly.
export type Particle = {
speed: Input<number>,
size: Input<number>,
opacity: Input<number>,
}
function advance(self: Particle, seconds: number): boolean
-- Use the numbers directly
local distance = self.speed * seconds
local radius = self.size * 0.5
return true
end
return function(): Node<Particle>
return {
init = init,
advance = advance,
draw = draw,
speed = 100, -- pixels per second
size = 20, -- diameter in pixels
opacity = 255, -- fully opaque
}
end
Input<boolean>
A true/false toggle. Appears as a checkbox in the editor.
When to use: On/off switches — show/hide something, enable/disable a feature, flip a mode.
Factory default: true or false.
How to read: self.isVisible returns true or false.
export type Overlay = {
isVisible: Input<boolean>,
showShadow: Input<boolean>,
}
function draw(self: Overlay, renderer: Renderer)
if not self.isVisible then return end
renderer:drawPath(self.bgPath, self.bgPaint)
if self.showShadow then
renderer:drawPath(self.shadowPath, self.shadowPaint)
end
end
return function(): Node<Overlay>
return {
init = init,
draw = draw,
isVisible = true,
showShadow = false,
}
end
Input<string>
A text value. Appears as a text field in the editor.
When to use: Labels, names, mode selectors, anything that's text.
Factory default: Any string in quotes (e.g. "hello", "idle", "").
How to read: self.label returns the string directly.
export type Badge = {
label: Input<string>,
mode: Input<string>,
}
function update(self: Badge)
if self.mode == "warning" then
self.paint.color = Color.rgb(255, 200, 0)
elseif self.mode == "error" then
self.paint.color = Color.rgb(255, 60, 60)
else
self.paint.color = Color.rgb(100, 200, 100)
end
end
return function(): Node<Badge>
return {
init = init,
update = update,
draw = draw,
label = "Status",
mode = "normal",
}
end
Input<Color>
A color value. Appears as a color picker in the editor.
When to use: Tints, fills, backgrounds — any color that should be adjustable.
Factory default: A Color value like Color.rgb(255, 0, 0) or Color.rgba(100, 150, 200, 128).
How to read: self.tint returns a Color value you can assign to a paint.
export type ColoredShape = {
fillColor: Input<Color>,
strokeColor: Input<Color>,
}
function update(self: ColoredShape)
-- When either color changes, update the paints
self.fillPaint.color = self.fillColor
self.strokePaint.color = self.strokeColor
end
return function(): Node<ColoredShape>
return {
init = init,
update = update,
draw = draw,
fillColor = Color.rgb(80, 160, 255),
strokeColor = Color.rgb(40, 80, 180),
fillPaint = late(),
strokePaint = late(),
}
end
Input<Data.X>
A reference to a ViewModel instance — a named collection of properties defined in the Rive editor. This is how you connect your script to data that lives on the artboard.
When to use: When your script needs to read or write properties that are bound to visual elements — positions, scores, colors, toggles that drive the animation.
Factory default: late() — because the editor assigns the ViewModel instance at runtime. Your script doesn't know which instance it will receive until the file loads.
How to read: self.character gives you the ViewModel instance. To access its properties, use .propertyName.value:
export type Controller = {
character: Input<Data.Character>,
time: number,
}
function advance(self: Controller, seconds: number): boolean
self.time += seconds
-- Read a property
local currentX = self.character.posX.value
-- Write a property (updates all bound visual elements)
self.character.posX.value = math.sin(self.time) * 100
self.character.posY.value = math.cos(self.time) * 50
return true
end
return function(): Node<Controller>
return {
init = init,
advance = advance,
draw = draw,
character = late(), -- assigned by the editor
time = 0,
}
end
Editor setup:
- Create a ViewModel in the Rive editor (e.g.
CharacterwithposXandposYnumber properties) - Attach the script to a node
- In the script's input panel, assign the ViewModel instance to
character
.value?self.character is the ViewModel instance. self.character.posX is a Property<number>. Properties hold their value inside .value — that's how Rive tracks changes and updates bindings. So you always read/write with .value at the end.
Input<Artboard>
A reference to a nested artboard (component). Use this to create instances of reusable components at runtime — particles, list items, repeated UI elements.
When to use: When your script needs to stamp out copies of a component, each with its own data.
Factory default: late() — the editor assigns the artboard reference.
How to read: self.template gives you the artboard. Call :instance() to create a copy, optionally with a ViewModel:
export type Spawner = {
template: Input<Artboard>,
instances: { Artboard },
}
function init(self: Spawner, context: Context): boolean
self.instances = {}
-- Create 5 instances of the template
for i = 1, 5 do
local vm = Data.ItemVm.new()
local idx = vm:getNumber("index")
if idx then idx.value = i end
local inst = self.template:instance(vm)
inst.frameOrigin = false
table.insert(self.instances, inst)
end
return true
end
return function(): Node<Spawner>
return {
init = init,
advance = advance,
draw = draw,
template = late(), -- assigned by the editor
instances = {},
}
end
Editor setup:
- Create a component artboard (the thing you want to repeat)
- Attach the script to a node
- In the script's input panel, assign the component to
template
Input<Trigger>
A one-shot signal — like pressing a button. Unlike all other input types, a trigger doesn't hold a value. It fires once and is done.
When to use: Reset buttons, "play" signals, "spawn now" commands — any action that should happen once when activated.
Factory default: function() end — a function that does nothing. This is different from other inputs: triggers must be functions because Rive calls the function directly when the trigger fires. Using late() or nil causes the error "expected trigger X to be a function".
How it works: Rive calls your function the moment the trigger fires. You can override this function in init() to do something useful:
export type Resettable = {
resetTrigger: Input<Trigger>,
pendingReset: boolean,
score: number,
}
function init(self: Resettable, context: Context): boolean
-- Replace the do-nothing placeholder with a real function
self.resetTrigger = function()
self.pendingReset = true
end
return true
end
function advance(self: Resettable, seconds: number): boolean
if self.pendingReset then
self.pendingReset = false
self.score = 0 -- reset the score
end
return true
end
return function(): Node<Resettable>
return {
init = init,
advance = advance,
draw = draw,
resetTrigger = function() end, -- placeholder
pendingReset = false,
score = 0,
}
end
Execution order on a trigger frame: trigger fn → advance() → update().
Editor setup:
- Add a Trigger property to your ViewModel
- In the script's input panel, bind
resetTriggerto the ViewModel trigger - Fire it from a state machine, listener, or another script
See Trigger Inputs for a deeper walkthrough of the flag pattern and why it's useful.
Triggers can also be accessed via vm:getTrigger("name") with addListener(callback) — see PropertyTrigger.
Change Handling
When any input changes, Rive calls your update() function. This is where you react to new values — rebuild geometry, update colors, recalculate layout.
function update(self: MyNode)
-- Called whenever any input changes
-- Rebuild whatever depends on the inputs
rebuildShape(self)
end
update() does not tell you which input changed. If you need to know, store the previous value and compare:
function update(self: MyNode)
if self.size ~= self.lastSize then
rebuildPath(self)
self.lastSize = self.size
end
end
Property
Mutable property with change notification.
Attributes
property.value
The property value. Type: T (read/write)
Methods
property:addListener(callback)
Registers a change callback. Can be called with or without a bound object.
property:addListener(callback: () -> ())
property:addListener(obj: any, callback: (any) -> ())
property:removeListener(callback)
Removes a callback.
property:removeListener(callback: () -> ())
Context
Runtime context passed to init() in all script protocols.
Methods
context:viewModel()
Gets the main Artboard's ViewModel.
context:viewModel(): ViewModel?
context:rootViewModel()
Gets the root ViewModel of the artboard hierarchy.
context:rootViewModel(): ViewModel?
context:dataContext()
Gets the DataContext for hierarchy traversal.
context:dataContext(): DataContext?
context:image(name)
Gets an image asset by name.
context:image(name: string): Image?
context:blob(name)
Gets a blob (binary data) asset by name.
context:blob(name: string): Blob?
context:audio(name)
Gets an audio source asset by name.
context:audio(name: string): AudioSource?
context:markNeedsUpdate()
Requests an update on the next frame.
context:markNeedsUpdate()
See Also: ViewModel, DataContext, Image, Blob, AudioSource
ViewModel
Connects editor elements to data and code. Provides access to bound properties by type.
Attributes
viewModel.name
The name of the ViewModel. Type: string (read-only)
Methods
viewModel:getNumber(name)
Gets a numeric property by name.
viewModel:getNumber(name: string): Property<number>?
viewModel:getString(name)
Gets a string property by name.
viewModel:getString(name: string): Property<string>?
viewModel:getBoolean(name)
Gets a boolean property by name.
viewModel:getBoolean(name: string): Property<boolean>?
viewModel:getColor(name)
Gets a color property by name.
viewModel:getColor(name: string): Property<Color>?
viewModel:getTrigger(name)
Gets a trigger property by name.
viewModel:getTrigger(name: string): PropertyTrigger?
viewModel:getList(name)
Gets a list property by name.
viewModel:getList(name: string): PropertyList?
viewModel:getViewModel(name)
Gets a nested ViewModel by name. Returns a PropertyViewModel wrapper (access the ViewModel via .value).
viewModel:getViewModel(name: string): PropertyViewModel?
viewModel:getEnum(name)
Gets an enum property by name.
viewModel:getEnum(name: string): PropertyEnum?
viewModel:instance()
Creates an independent instance of the ViewModel.
viewModel:instance(): ViewModel
Example
function init(self: MyScript, context: Context): boolean
local vm = context:viewModel()
-- Get typed properties
local score = vm:getNumber("score")
local playerName = vm:getString("playerName")
local isActive = vm:getBoolean("isActive")
-- Read values
if score then
print(`Score: {score.value}`)
end
-- Listen for changes
if playerName then
playerName:addListener(function()
print(`Name changed to: {playerName.value}`)
end)
end
return true
end
See Also: Property, Context, PropertyTrigger
DataContext
Provides hierarchy traversal for data binding contexts. Obtained via context:dataContext().
Methods
dataContext:parent()
Gets the parent DataContext, or nil if at the root.
dataContext:parent(): DataContext?
dataContext:viewModel()
Gets the ViewModel associated with this context level.
dataContext:viewModel(): ViewModel?
Next Steps
- Continue to Events
- Need a refresher? Review Quick Reference