Skip to main content

Pointer Events

Prerequisites

Before this section, complete:

Build interactive controls, buttons, and gesture-driven interfaces using pointer event handlers.

Rive Context

Pointer handlers (pointerDown, pointerMove, pointerUp, pointerExit) are only called if you return them in the Node factory table. These events are local to the script's node, making them ideal for building self-contained interactive components.

Key concept: Use event:hit() to consume the event and stop propagation to nodes below.


Exercise 1: Press to Toggle Color ⭐⭐

Premise

pointerDown handles click events. Toggle state with 'not', update visuals, and call event:hit() to stop propagation.

Goal

By the end of this exercise, you will be able to Complete the pointerDown handler to toggle the button color between blue and orange on each press.

Use Case

This pattern shows up whenever you build behavior in Rive scripts.

Example scenarios:

  • Debugging script behavior
  • Driving animation logic

Setup

In Rive Editor:

  1. Create the script:

    • Assets panel → + → Script → Node Script
    • Name it Exercise1_Exercise1PressToToggleColor
  2. Attach and run:

    • Attach to any shape and press Play
  3. Open the Console:

    • View → Console

Starter Code

--!strict
-- Toggle button color on press

export type ToggleButton = {
path: Path,
paint: Paint,
isPressed: boolean,
}

function init(self: ToggleButton): boolean
self.isPressed = false

self.path = Path.new()
self.path:moveTo(Vector.xy(-60, -30))
self.path:lineTo(Vector.xy(60, -30))
self.path:lineTo(Vector.xy(60, 30))
self.path:lineTo(Vector.xy(-60, 30))
self.path:close()

self.paint = Paint.with({ style = "fill", color = Color.rgb(80, 170, 255) })

print("Toggle button ready")
return true
end

function pointerDown(self: ToggleButton, event: PointerEvent)
-- TODO 1: Toggle isPressed using 'not'
-- self.isPressed = not self.isPressed

-- TODO 2: Update paint color based on isPressed
-- Use: self.isPressed and Color.rgb(255, 120, 80) or Color.rgb(80, 170, 255)

-- TODO 3: Call event:hit() to consume the event

print("Button toggled!")
print("ANSWER: toggled")
end

function draw(self: ToggleButton, renderer: Renderer)
renderer:drawPath(self.path, self.paint)
end

return function(): Node<ToggleButton>
return {
init = init,
draw = draw,
pointerDown = pointerDown,
path = late(),
paint = late(),
isPressed = false,
}
end

Assignment

Complete these tasks:

  1. Complete the pointerDown handler to toggle the button color between blue and orange on each press.
  2. Run the script and verify the console output
  3. Copy the ANSWER: line into the validator

Expected Output

Console prints the relevant debug lines for this exercise.
ANSWER: <your result>

Verify Your Answer

Verify Your Answer

Checklist

  • --!strict is at the top
  • All TODOs are replaced with working code
  • Console output includes the ANSWER: line

How it works:

  1. The pointerDown handler toggles isPressed state
  2. The paint color updates based on the current state
  3. event:hit() consumes the event to prevent it from propagating

Exercise 2: Track Multiple Pointers ⭐⭐⭐

Premise

Each pointer has a unique event.id. Track them in a table: create on down, update on move, remove on up.

Goal

By the end of this exercise, you will be able to Complete the pointer handlers to track multiple touch points simultaneously.

Use Case

This pattern shows up whenever you build behavior in Rive scripts.

Example scenarios:

  • Debugging script behavior
  • Driving animation logic

Setup

In Rive Editor:

  1. Create the script:

    • Assets panel → + → Script → Node Script
    • Name it Exercise2_Exercise2TrackMultiplePointers
  2. Attach and run:

    • Attach to any shape and press Play
  3. Open the Console:

    • View → Console

Starter Code

--!strict
-- Track multiple pointers by their unique IDs

type PointerState = {
position: Vector,
}

export type MultiTouch = {
pointers: { [number]: PointerState },
pointerCount: number,
}

function init(self: MultiTouch): boolean
self.pointers = {}
self.pointerCount = 0
print("Multi-touch tracker ready")
return true
end

function pointerDown(self: MultiTouch, event: PointerEvent)
-- TODO 1: Create a new entry in self.pointers using event.id as key
-- Store { position = event.position }

-- TODO 2: Increment pointerCount and print the pointer number

-- TODO 3: If pointerCount >= 2, print the answer

-- TODO 4: Call event:hit()
end

function pointerMove(self: MultiTouch, event: PointerEvent)
-- TODO 5: Get the pointer from self.pointers[event.id]
-- If it exists, update its position
local pointer = self.pointers[event.id]
if pointer then
pointer.position = event.position
end
event:hit()
end

function pointerUp(self: MultiTouch, event: PointerEvent)
-- TODO 6: Remove the pointer by setting self.pointers[event.id] = nil
-- TODO 7: Decrement pointerCount
-- TODO 8: Call event:hit()
end

function draw(self: MultiTouch, renderer: Renderer)
-- Pointer positions can drive visuals here
end

return function(): Node<MultiTouch>
return {
init = init,
draw = draw,
pointerDown = pointerDown,
pointerMove = pointerMove,
pointerUp = pointerUp,
pointers = {},
pointerCount = 0,
}
end

Assignment

Complete these tasks:

  1. Complete the pointer handlers to track multiple touch points simultaneously.
  2. Run the script and verify the console output
  3. Copy the ANSWER: line into the validator

Expected Output

Console prints the relevant debug lines for this exercise.
ANSWER: <your result>

Verify Your Answer

Verify Your Answer

Checklist

  • --!strict is at the top
  • All TODOs are replaced with working code
  • Console output includes the ANSWER: line

How it works:

  1. Each pointer has a unique event.id
  2. pointerDown creates a new entry in the pointers table
  3. pointerMove updates the position for that specific pointer
  4. pointerUp removes the pointer from tracking

Key Takeaways

  • Pointer events are local to the script's node
  • Return handler functions in the factory table to receive events
  • Use event:hit() to consume events and stop propagation
  • Track pointers by their unique event.id for multi-touch support

Q:What does event:hit() do in a pointer handler?

Next Steps