DEPRECATION NOTICE: This entire page documents the legacy Animation
Playback system. For new projects: Use State
Machines instead. For existing projects: Plan
to migrate from direct animation control to State Machines as soon as
possible. This content is provided for legacy support only.
If you are trying to coordinate multiple animations’ playback at runtime,
consider using a state machine instead to do this for you!
Choosing starting animations
Starting animations can also be chosen when Rive is instantiated. The first animation on the artboard may play if one is not provided, or a state machine is not set.- Web
- React
- React Native
- Flutter
- Apple
- Android
Copy
Ask AI
// Play the idle animation
new rive.Rive({
src: 'https://cdn.rive.app/animations/vehicles.riv',
canvas: document.getElementById('canvas'),
animations: 'idle',
autoplay: true
});
Copy
Ask AI
// Play the idle animation
export const Simple = () => (
<Rive src="https://cdn.rive.app/animations/vehicles.riv" animations="idle" />
);
// With `useRive` Hook:
export default function Simple() {
const { RiveComponent } = useRive({
src: 'https://cdn.rive.app/animations/vehicles.riv',
animations: ['idle'],
autoplay: true,
});
return <RiveComponent />;
}
Currently, with the React Native runtime, you can set one animation to autoplay at the start. Despite this, see below in the playback sections to see how you can mix multiple animations on playback functions.
Copy
Ask AI
export default function App() {
return (
<View>
<Rive
resourceName="truck_v7"
artboardName="Jeep"
autoplay
animationName="idle"
/>
</View>
);
}
Copy
Ask AI
// Create a File, Artboard, and SingleAnimationPainter
final file = (await File.asset(
'assets/rewards.riv',
riveFactory: Factory.rive,
))!;
final artboard = file.artboard('Main')!;
final animationPainter = SingleAnimationPainter("Artboard Name");
// Later create the widget
return RiveArtboardWidget(
artboard: artboard,
painter: animationPainter,
);
By default,
RiveViewModel will automatically play the animation or state machine you’ve given it.SwiftUI
Copy
Ask AI
struct AnimationView: View {
var body: some View {
RiveViewModel(
fileName: "dancing_banana",
animationName: "Charleston",
artboardName: "Banana"
).view()
}
}
UIKit
Copy
Ask AI
class AnimationViewController: UIViewController {
@IBOutlet weak var riveView: RiveView!
var bananaVM = RiveViewModel(
fileName: "dancing_banana",
animationName: "Charleston",
artboardName: "Banana"
)
override func viewDidLoad() {
bananaVM.setView(riveView)
}
}
With the Android runtime, specify one animation with the Or
riveAnimation property.Copy
Ask AI
<app.rive.runtime.kotlin.RiveAnimationView
app:riveAutoPlay="true"
app:riveArtboard="Square"
app:riveAnimation="rollaround"
app:riveResource="@raw/artboard_animations" />
Copy
Ask AI
animationView.setRiveResource(
R.raw.artboard_animations,
artboardName = "Square",
animationName = "rollaround",
autoplay = true
)
Controlling playback
Playback of each animation and state machine can be separately controlled. You can play and pause playback using theplay , pause and stop methods, either passing in the names of the animations you want to affect or passing in nothing which will affect all instanced animations.
- Web
- React
- React Native
- Flutter
- Apple
- Android
Invoking Playback Controls
With the web runtime, you can provide callback functions to receive notification when certain animation events have occurred:onLoadwhen a rive file has been loaded and initialized; it’s now ready for playbackonPlaywhen one or more animations play; provides a list of animationsonPausewhen one or more animations pause; provides a list of animationsonStopwhen one or more animations are stopped; provides a list of animationsonLoopwhen an animation loops; provides the animation name
Copy
Ask AI
const idleButton = document.getElementById("idle");
const wipersButton = document.getElementById("wipers");
const loopDiv = document.getElementById("loop");
const truck = new rive.Rive({
src: "https://cdn.rive.app/animations/vehicles.riv",
artboard: "Jeep",
canvas: document.getElementById("canvas"),
layout: new rive.Layout({ fit: "fill" }),
// Listen for play events to update button text
onPlay: (event) => {
const names = event.data;
names.forEach((name) => {
if (name === "idle") {
idleButton.innerHTML = "Stop Truck";
} else if (name === "windshield_wipers") {
wipersButton.innerHTML = "Stop Wipers";
}
});
},
// Listen for pause events to update button text
onPause: (event) => {
const names = event.data;
names.forEach((name) => {
if (name === "idle") {
idleButton.innerHTML = "Start Truck";
} else if (name === "windshield_wipers") {
wipersButton.innerHTML = "Start Wipers";
}
});
},
onLoop: (event) => {
loopDiv.innerHTML = `Looped Animation: ${event.data.animation}`;
}
});
idleButton.onclick = (_) =>
truck.playingAnimationNames.includes("idle")
? truck.pause("idle")
: truck.play("idle");
wipersButton.onclick = (_) =>
truck.playingAnimationNames.includes("windshield_wipers")
? truck.pause("windshield_wipers")
: truck.play("windshield_wipers");
Invoking Playback Controls
Very similarly to Web, you can pass in Rive params and callbacks for certain animation events. See the Web tab for some examples of callbacks you can set. Additionally, you can use therive object returned from the useRive hook to invoke playback controls.See the example below here: https://codesandbox.io/p/sandbox/adoring-sea-n7m59fCopy
Ask AI
import { useState } from "react";
import { useRive, Layout, Fit } from "@rive-app/react-canvas";
export default function App() {
const [truckButtonText, setTruckButtonText] = useState("Start Truck");
const [wiperButtonText, setWiperButtonText] = useState("Start Wipers");
// animation will show the first frame but not start playing
const { rive, RiveComponent } = useRive({
src: "https://cdn.rive.app/animations/vehicles.riv",
artboard: "Jeep",
layout: new Layout({ fit: Fit.Cover }),
// Listen for play events to update button text
onPlay: (event) => {
const names = event.data;
names.forEach((name) => {
if (name === "idle") {
setTruckButtonText("Stop Truck");
} else if (name === "windshield_wipers") {
setWiperButtonText("Stop Wipers");
}
});
},
// Listen for pause events to update button text
onPause: (event) => {
const names = event.data;
names.forEach((name) => {
if (name === "idle") {
setTruckButtonText("Start Truck");
} else if (name === "windshield_wipers") {
setWiperButtonText("Start Wipers");
}
});
},
});
function onStartTruckClick() {
if (rive) {
if (rive.playingAnimationNames.includes("idle")) {
rive.pause("idle");
} else {
rive.play("idle");
}
}
}
function onStartWiperClick() {
if (rive) {
if (rive.playingAnimationNames.includes("windshield_wipers")) {
rive.pause("windshield_wipers");
} else {
rive.play("windshield_wipers");
}
}
}
return (
<>
<div>
<RiveComponent style={{ height: "1000px" }} />
</div>
<div>
<button id="idle" onClick={onStartTruckClick}>
{truckButtonText}
</button>
<button id="wipers" onClick={onStartWiperClick}>
{wiperButtonText}
</button>
</div>
</>
);
}
Invoking Playback Controls
To trigger animation playback controls, set aref on the Rive component rendered. Once the ref is populated, you can trigger functions such as play, pause, etc. See the ref method docs for React Native Rive Ref Methods.Copy
Ask AI
import Rive, { RiveRef } from 'rive-react-native'
export default function App() {
const riveRef = React.useRef<RiveRef>(null);
const handlePlayPress = () => {
riveRef?.current?.play();
};
const handlePausePress = () => {
riveRef?.current?.pause();
};
return (
<View>
<Rive
resourceName="truck_v7"
animationName="idle"
ref={riveRef}
/>
<Button onPress={handlePlayPress} title="play">
<Button onPress={handlePausePress} title="pause">
</View>
);
}
Flutter handles things a little differently compared to the other runtimes due to its reactive nature.Every animation and state machine in Flutter has an underlying painter that manages the state/painting/advancing.In order to access controls for animations, you’ll need to create a
SingleAnimationPainter or StateMachinePainter and pass it to the RiveArtboardWidget.Or you can create RiveWidgetController and pass it to the RiveWidget to control playback of state machines with a more feature-rich API (recommended).This painter concept is extensible, and you can also create your own custom painter, for example, to control multiple animations at once.Invoking Playback Controls
After creating aRiveViewModel, you can invoke animation playback control methods on a reference to this view model.Very often that will be all that is needed to display your Rive asset. However, we have some convenient controls for when you want more fine-grained control of when it plays and doesn’t.You can also choose the loop mode of the animation as additional parameters as needed. Along with playing animations, you similarly have the ability to pause, stop, and reset animation(s).Playing withoutplay(animationName: String? = nil, loop: Loop = .autoLoop, direction: Direction = .autoDirection)animationName- Name of the animation to playloop- Loop mode to play the animation in. Possible values listed below:oneShot- plays animation through onceloop- plays through animation and repeats from the set starting timepingPong- plays animation from start -> end, then end -> start on repeatautoLoop(default) - plays through the loop setting set on the animation
direction- Direction to play the animation inbackwards- plays through animation timeline backwardforwards- plays through animation timeline forwardsautoDirection- plays through direction set on the animation
pause()stop()reset()
Play
If you set autoplay to false you can play the active animation or state machine very simply.Copy
Ask AI
simpleVM.play()
Copy
Ask AI
simpleVM.play(animationName: "Fancy Animation")
Pause/Stop/Reset
Based on certain events in your app you may want to adjust the playback further.Copy
Ask AI
simpleVM.pause()
simpleVM.stop()
simpleVM.reset()
Player Delegates
This runtime allows for delegates that can be set on theRiveViewModel. You can use delegates to define functions that hook into when certain playback events are invoked. See the below class for how you can hook into the following playback events:- played
- paused
- stopped
- advanced
- animation looped
Copy
Ask AI
class ToggleViewModel: RiveViewModel {
private let onAnimation: String = "On"
private let offAnimation: String = "Off"
private let startAnimation: String = "StartOff"
var action: ((Bool) -> Void)? = nil
var isOn = false {
didSet {
stop()
play(animationName: isOn ? onAnimation : offAnimation)
action?(isOn)
}
}
init() {
super.init(fileName: "toggle", animationName: startAnimation, fit: .cover)
}
func view(_ action: ((Bool) -> Void)? = nil) -> some View {
self.action = action
return super.view().frame(width: 100, height: 50, alignment: .center)
}
// When an animation is played
override func player(playedWithModel riveModel: RiveModel?) {
if let animationName = riveModel?.animation?.name() {...}
}
// When an animation is paused
override func player(pausedWithModel riveModel: RiveModel?) {
if let animationName = riveModel?.animation?.name() {...}
}
// When an animation is stopped
override func player(stoppedWithModel riveModel: RiveModel?) {
if let animationName = riveModel?.animation?.name() {...}
}
// When an animation is looped
override func player(loopedWithModel riveModel: RiveModel?, type: Int) {
if let animationName = riveModel?.animation?.name() {...}
}
// When an animation is advanced
override func player(didAdvanceby seconds: Double, riveModel: RiveModel?) {...}
}
Invoking Playback Controls
After setting the Rive Resource with your animation view, you can invoke animation playback control methods.Along with programmatically playing an animation, you can also choose the loop mode and direction of the animation as additional parameters as needed. You can additionally pause or stop an animation as well.Copy
Ask AI
// Play one animation
animationView.play("rollaround")
// Set loop mode and direction
animationView.play("rollaround", Loop.ONE_SHOT, Direction.Backwards)
animationView.pause()
animationView.pause("bouncing")
animationView.stop()
animationView.stop("bouncing")
Animation Event Listeners
The Rive Android runtime also allows listener registration. Check out the events section in the rive player for an example of how this works.Copy
Ask AI
val listener = object : Listener {
override fun notifyPlay(animation: PlayableInstance) {
var text: String? = null
if (animation is LinearAnimationInstance) {
text = animation.name
}
}
override fun notifyPause(animation: PlayableInstance) {
var text: String? = null
if (animation is LinearAnimationInstance) {
text = animation.name
}
}
override fun notifyStop(animation: PlayableInstance) {
var text: String? = null
if (animation is LinearAnimationInstance) {
text = animation.name
}
}
override fun notifyLoop(animation: PlayableInstance) {
var text: String? = null
if (animation is LinearAnimationInstance) {
text = animation.name
}
}
}
animationView.registerListener(listener)