Playback
Playing and pausing animations
Rive lets you specify what artboard to use, what animations and state machines to mix and play, and to control the play/pause state of each animation.
From here on we're going to use the term animations collectively to refer to both animations and state machines. Where there are differences between the two, we'll explicitly call this out.

Choosing an artboard

When a Rive object is instantiated, the artboard to use can be specified. If no artboard is given, the default artboard is used. Only one artboard can be used at a time.
Web
React
Flutter
Angular
1
new rive.Rive({
2
src: 'https://cdn.rive.app/animations/vehicles.riv',
3
canvas: document.getElementById('canvas'),
4
artboard: 'Truck',
5
autoplay: true
6
});
Copied!
1
export const Simple = () => (
2
<Rive src="https://cdn.rive.app/animations/vehicles.riv" artboard="Truck" />
3
);
4
5
// With `useRive` Hook:
6
export default function Simple() {
7
const { RiveComponent } = useRive({
8
src: 'https://cdn.rive.app/animations/vehicles.riv',
9
artboard: 'Truck',
10
autoplay: true,
11
});
12
13
return <RiveComponent />;
14
}
Copied!
1
RiveAnimation.network(
2
'https://cdn.rive.app/animations/vehicles.riv',
3
artboard: 'Truck'
4
);
Copied!
1
<canvas riv="vehicles" width="500" height="500" artboard="Truck">
2
3
</canvas>
Copied!
If no artboard name is provided, the default artboard is used.

Choosing starting animations

Starting animations can also be chosen when Rive is instantiated. A list of animation names can be provided.
Web
React
Flutter
Angular
1
// Play the idle animation
2
new rive.Rive({
3
src: 'https://cdn.rive.app/animations/vehicles.riv',
4
canvas: document.getElementById('canvas'),
5
animations: 'idle',
6
autoplay: true
7
});
8
9
// play and mix the idle and curves animations
10
new rive.Rive({
11
src: 'https://cdn.rive.app/animations/vehicles.riv',
12
canvas: document.getElementById('canvas'),
13
animations: ['idle', 'curves'],
14
autoplay: true
15
});
Copied!
1
// Play the idle animation
2
export const Simple = () => (
3
<Rive src="https://cdn.rive.app/animations/vehicles.riv" animations="idle" />
4
);
5
6
// play and mix the idle and curves animations
7
export const Simple = () => (
8
<Rive src="https://cdn.rive.app/animations/vehicles.riv" animations={['idle', 'curves']} />
9
);
10
11
// With `useRive` Hook:
12
export default function Simple() {
13
const { RiveComponent } = useRive({
14
src: 'https://cdn.rive.app/animations/vehicles.riv',
15
animations:{['idle', 'curves']},
16
autoplay: true,
17
});
18
19
return <RiveComponent />;
20
}
Copied!
1
// Play the curves animation
2
RiveAnimation.network(
3
'https://cdn.rive.app/animations/vehicles.riv',
4
animations: ['curves'],
5
);
6
7
// Play and mix both the idle and curves animations
8
RiveAnimation.network(
9
'https://cdn.rive.app/animations/vehicles.riv',
10
animations: ['idle', 'curves'],
11
),
Copied!
1
<!-- Play the curves animation -->
2
<canvas riv="vehicles" width="500" height="500">
3
<riv-animation name="curves" play></riv-animation>
4
</canvas>
5
6
<!-- Play and mix both the idle and curves animations -->
7
<canvas riv="vehicles" width="500" height="500">
8
<riv-animation name="idle" play></riv-animation>
9
<riv-animation name="curves" play></riv-animation>
10
</canvas>
Copied!

Choosing starting state machines

A starting state machine can be specified when Rive is instantiated. A state machine name can be provided.
Web
React
Flutter
Angular
1
new rive.Rive({
2
src: 'https://cdn.rive.app/animations/vehicles.riv',
3
canvas: document.getElementById('canvas'),
4
stateMachines: 'weather',
5
autoplay: true
6
});
Copied!
1
// State Machine require the useRive hook.
2
export default function Simple() {
3
const { RiveComponent } = useRive({
4
src: 'https://cdn.rive.app/animations/vehicles.riv',
5
stateMachines: "weather",
6
autoplay: true,
7
});
8
9
return <RiveComponent />;
10
}
Copied!
1
RiveAnimation.network(
2
'https://cdn.rive.app/animations/vehicles.riv',
3
stateMachines: ['weather'],
4
)
Copied!
1
<canvas riv="vehicles" width="500" height="500">
2
<riv-state-machine name="weather" play></riv-state-machine>
3
</canvas>
Copied!

Controlling playback

Playback of each animation and state machine can be separately controlled. You can play and pause playback using the play , pause and stop methods, either passing in the names of the animations you want to effect, or passing in nothing which will effect all instanced animations.
You can also provide callback to receive notification when certain events have occurred:
    onLoad when a rive file has been loaded and initialized; it's now ready for playback
    onPlay when one or more animations play; provides a list of animations
    onPause when one or more animations pause; provides a list of animations
    onLoop when an animation loops; provides the animation name
Web
React
Flutter
Angular
1
<!doctype html>
2
<html lang="en">
3
<head>
4
<meta charset="utf-8">
5
<meta name="viewport" content="user-scalable=no">
6
<title>Manually Control Rive Animations</title>
7
<link rel="stylesheet" href="styles.css">
8
</head>
9
<body class="parent">
10
<div>
11
<canvas id="canvas" width="500" height="500"></canvas>
12
</div>
13
<div>
14
<button id="idle">Start Truck</button>
15
<button id="wipers">Start Wipers</button>
16
</div>
17
18
<script src="/dist/rive.min.js"></script>
19
<script>
20
// animation will show the first frame but not start playing
21
const truck = new rive.Rive({
22
src: 'https://cdn.rive.app/animations/vehicles.riv',
23
artboard: 'Jeep',
24
canvas: document.getElementById('canvas'),
25
layout: new rive.Layout({fit: 'fill'}),
26
});
27
28
const idleButton = document.getElementById('idle');
29
const wipersButton = document.getElementById('wipers');
30
31
idleButton.onclick = _ =>
32
truck.playingAnimationNames.includes('idle') ?
33
truck.pause('idle') :
34
truck.play('idle');
35
36
wipersButton.onclick = _ =>
37
truck.playingAnimationNames.includes('windshield_wipers') ?
38
truck.pause('windshield_wipers') :
39
truck.play('windshield_wipers');
40
41
// Listen for play events to update button text
42
truck.on(rive.EventType.Play, (event) => {
43
const names = event.data;
44
names.forEach((name) => {
45
if (name === 'idle') {
46
idleButton.innerHTML = 'Stop Truck';
47
} else if (name === 'windshield_wipers') {
48
wipersButton.innerHTML = 'Stop Wipers';
49
}
50
});
51
});
52
53
// Listen for pause events to update button text
54
truck.on(rive.EventType.Pause, (event) => {
55
const names = event.data;
56
names.forEach((name) => {
57
if (name === 'idle') {
58
idleButton.innerHTML = 'Start Truck';
59
} else if (name === 'windshield_wipers') {
60
wipersButton.innerHTML = 'Start Wipers';
61
}
62
});
63
});
64
</script>
65
</body>
66
</html>
Copied!
1
import { useState, useEffect } from "react";
2
import { useRive, Layout, Fit } from "rive-react";
3
4
export default function App() {
5
const [truckButtonText, setTruckButtonText] = useState("Start Truck");
6
const [wiperButtonText, setWiperButtonText] = useState("Start Wipers");
7
8
// animation will show the first frame but not start playing
9
const { rive, RiveComponent } = useRive({
10
src: "https://cdn.rive.app/animations/vehicles.riv",
11
artboard: "Jeep",
12
layout: new Layout({ fit: Fit.Cover }),
13
});
14
15
useEffect(() => {
16
if (rive) {
17
// Listen for play events to update button text
18
rive.on("play", (event) => {
19
const names = event.data;
20
names.forEach((name) => {
21
if (name === "idle") {
22
setTruckButtonText("Stop Truck");
23
} else if (name === "windshield_wipers") {
24
setWiperButtonText("Stop Wipers");
25
}
26
});
27
});
28
29
// Listen for pause events to update button text
30
rive.on("pause", (event) => {
31
const names = event.data;
32
names.forEach((name) => {
33
if (name === "idle") {
34
setTruckButtonText("Start Truck");
35
} else if (name === "windshield_wipers") {
36
setWiperButtonText("Start Wipers");
37
}
38
});
39
});
40
}
41
}, [rive]);
42
43
function onStartTruckClick() {
44
if (rive) {
45
if (rive.playingAnimationNames.includes("idle")) {
46
rive.pause("idle");
47
} else {
48
rive.play("idle");
49
}
50
}
51
}
52
53
function onStartWiperClick() {
54
if (rive) {
55
if (rive.playingAnimationNames.includes("windshield_wipers")) {
56
rive.pause("windshield_wipers");
57
} else {
58
rive.play("windshield_wipers");
59
}
60
}
61
}
62
63
return (
64
<>
65
<div>
66
<RiveComponent style={{ height: "1000px" }} />
67
</div>
68
<div>
69
<button id="idle" onClick={onStartTruckClick}>
70
{truckButtonText}
71
</button>
72
<button id="wipers" onClick={onStartWiperClick}>
73
{wiperButtonText}
74
</button>
75
</div>
76
</>
77
);
78
}
Copied!
Flutter handles things a little differently to the other runtimes due to its reactive nature.
Every animation and state machine in Flutter has an underlying controller that manages the state of each animation. When you pass a list of animation names to the RiveAnimation widget, it creates and manages controllers for each.
On order to access control to animations, you'll need to instantiate a RiveAnimationController for each animation, and pass the controller to the widget instead of its name. You can mix and match passing in controllers and names, but don't pass in both for the same animation.
There are a number of controllers provided in the runtime that perform certain tasks. We'll cover these as they become relevant.

Manually controlling a looping animation

SimpleAnimation is a basic controller that provides simple playback control of an animation. With this you can play, pause, and reset animations.
In the following example, the isActive property of SimpleAnimation is used to play and pause a single animation.
1
import 'package:flutter/material.dart';
2
import 'package:rive/rive.dart';
3
4
class PlayPauseAnimation extends StatefulWidget {
5
const PlayPauseAnimation({Key? key}) : super(key: key);
6
7
@override
8
_PlayPauseAnimationState createState() => _PlayPauseAnimationState();
9
}
10
11
class _PlayPauseAnimationState extends State<PlayPauseAnimation> {
12
/// Controller for playback
13
late RiveAnimationController _controller;
14
15
/// Toggles between play and pause animation states
16
void _togglePlay() =>
17
setState(() => _controller.isActive = !_controller.isActive);
18
19
/// Tracks if the animation is playing by whether controller is running
20
bool get isPlaying => _controller.isActive;
21
22
@override
23
void initState() {
24
super.initState();
25
_controller = SimpleAnimation('idle');
26
}
27
28
@override
29
Widget build(BuildContext context) {
30
return Scaffold(
31
appBar: AppBar(
32
title: const Text('Animation Example'),
33
),
34
body: Center(
35
child: RiveAnimation.network(
36
'https://cdn.rive.app/animations/vehicles.riv',
37
controllers: [_controller],
38
// Update the play state when the widget's initialized
39
onInit: () => setState(() {}),
40
),
41
),
42
floatingActionButton: FloatingActionButton(
43
onPressed: _togglePlay,
44
tooltip: isPlaying ? 'Pause' : 'Play',
45
child: Icon(
46
isPlaying ? Icons.pause : Icons.play_arrow,
47
),
48
),
49
);
50
}
51
}
Copied!

Repeatedly playing a one-shot animation

One-shot animations do not loop. OneShotAnimation is a controller that will automatically stop and reset a one-shot animation when it has played through so it can be repeatedly played as required.
The controller also provides two callbacks: onStart and onStop that will fire when the animation starts and stops playing respectively.
The example below demonstrates mixing animation names with controllers. The idle and curves animations are managed by the runtime and as their looping animations will play continuously. bounce is a one-shot and is triggered when the button is tapped. The runtime will then play bounce, mixing it cleanly with the looping animations.
1
import 'package:flutter/material.dart';
2
import 'package:rive/rive.dart';
3
4
class PlayOneShotAnimation extends StatefulWidget {
5
const PlayOneShotAnimation({Key? key}) : super(key: key);
6
7
@override
8
_PlayOneShotAnimationState createState() => _PlayOneShotAnimationState();
9
}
10
11
class _PlayOneShotAnimationState extends State<PlayOneShotAnimation> {
12
/// Controller for playback
13
late RiveAnimationController _controller;
14
15
/// Is the animation currently playing?
16
bool _isPlaying = false;
17
18
@override
19
void initState() {
20
super.initState();
21
_controller = OneShotAnimation(
22
'bounce',
23
autoplay: false,
24
onStop: () => setState(() => _isPlaying = false),
25
onStart: () => setState(() => _isPlaying = true),
26
);
27
}
28
29
@override
30
Widget build(BuildContext context) {
31
return Scaffold(
32
appBar: AppBar(
33
title: const Text('One-Shot Example'),
34
),
35
body: Center(
36
child: RiveAnimation.network(
37
'https://cdn.rive.app/animations/vehicles.riv',
38
animations: const ['idle', 'curves'],
39
controllers: [_controller],
40
),
41
),
42
floatingActionButton: FloatingActionButton(
43
// disable the button while playing the animation
44
onPressed: () => _isPlaying ? null : _controller.isActive = true,
45
tooltip: 'Play',
46
child: const Icon(Icons.arrow_upward),
47
),
48
);
49
}
50
}
Copied!

Simple manipulation

You can apply simple manipulation on the riv-animation directive:
1
<canvas riv="vehicles" width="500" height="500">
2
<riv-animation name="curves" [play]="playing" speed="0.5"></riv-animation>
3
</canvas>
4
5
<button (click)="playing = !playing">Toggle Player</button>
Copied!
If speed is negative, the animation goes in reverse.

Advance manipulation

For more advances manipulations you can use the riv-player directive:
1
<canvas riv="vehicles" width="500" height="500">
2
<riv-player #player="rivPlayer" name="curves" [time]="time" mode="one-shot"></riv-player>
3
</canvas>
4
5
<input type="range" step="0.1"
6
(input)="time = $event.target.value"
7
[min]="player.startTime"
8
[max]="player.endTime"
9
/>
Copied!
    The time input will let you specify a moment in ms in the animation.
    The mode input will force the mode "one-shot", "loop" or "ping-pong" (if undefined, default mode is used).

Manipulate nodes

You can select a specific node in the animation with the riv-node, riv-bone & riv-root-bone directives :
1
<canvas riv="vehicles" (mouseover)="position = $event.x">
2
<riv-node name="wheel" [x]="position" scaleX="0.5"></riv-node>
3
</canvas>
Copied!
If the property of the node is updated by the animation, the animation wins.
Last modified 17d ago