Getting Started
From an empty folder to an AnimaScript script running in a Rive file.
Install rive
rive is Rive’s command line tool. It turns a folder of source
files into a Rive file and shows the result in a window that rebuilds every time
you save. It carries the AnimaScript compiler and standard library, so there is
nothing else to install.
curl -fsSL https://releases.rive.app/cli/install.sh | sh
rive --version
A first project
A project is a folder with a rive.yaml. AnimaScript compiles to
WebAssembly, so the project turns it on with scripting: wasm. Without
a scene file, the artboard key sizes the artboard the script draws
into:
name: hello
scripting: wasm
artboard:
width: 800
height: 600
background: "#1D1D1D"
A script is an exported class that extends one of the protocol bases in
rive/host. The base decides what the script is: a
Layout draws into a layout box, a Node draws in the
artboard tree, a Converter transforms a data bound value, and
PathEffect, ListenerAction,
TransitionCondition, Interpolator and
Transition do what their names say. The host calls only the hooks
your class overrides, and each one is marked override:
import { Layout, Context } from "rive/host";
import { Renderer } from "rive/renderer";
import { Paint } from "rive/paint";
import { Path } from "rive/path";
import { Vector } from "rive/vector";
import { Color } from "rive/color";
// A square orbiting the artboard.
export class Hello extends Layout {
paint: Paint = new Paint();
path: Path = new Path();
width: f64 = 0;
height: f64 = 0;
elapsed: f64 = 0;
override init(context: Context): bool {
this.paint.color = Color.rgb(255, 100, 50);
context.log("hello from rive");
return true;
}
override resize(width: f64, height: f64, scale: f64): void {
this.width = width;
this.height = height;
}
override advance(seconds: f64): bool {
this.elapsed += seconds;
return true;
}
override draw(renderer: Renderer): void {
const w = this.width;
const h = this.height;
const cx = w / 2 + Math.cos(this.elapsed) * w * 0.25;
const cy = h / 2 + Math.sin(this.elapsed * 1.3) * h * 0.25;
const r = Math.min(w, h) * 0.1;
const path = this.path;
path.reset();
path.moveTo(Vector.xy(<f32>(cx - r), <f32>(cy - r)));
path.lineTo(Vector.xy(<f32>(cx + r), <f32>(cy - r)));
path.lineTo(Vector.xy(<f32>(cx + r), <f32>(cy + r)));
path.lineTo(Vector.xy(<f32>(cx - r), <f32>(cy + r)));
path.close();
renderer.drawPath(path, this.paint);
}
}
Run it, and leave the window open while you edit:
rive . # the live window, rebuilt on every save
rive . --verify # check every script without running anything
rive . --test # run the project's Tests scripts headless
Every .as file in the folder is picked up, and all of them compile
into one module. A file without an exported protocol class is a library: other
scripts import from it with a relative path, as in
import { clamp } from "./math", and from the Rive API with
rive/*. rive docs animascript/protocols lists every hook
and how a scene attaches a script, and rive docs animascript/api
has the whole API, one page per rive/* module.
A project with scripting: wasm compiles its .as
files. Luau scripts belong in a project without it.
Trying the language here
Examples on this site with a run button compile in your browser with
the same compiler rive uses, and run on your browser’s
WebAssembly engine. Edit them freely. The in-page runner gives examples a
print function for output; scripts in a project use
context.log or console.log instead.
export function greet(name: string): string {
return "hello, " + name;
}
import { greet } from "./greeting";
declare function print(s: string): void;
export function main(): i32 {
print(greet("AnimaScript"));
return 0;
}
From here, Concepts tours the language, Structs covers the data types that make fast code easy, and Threads shows how to move work off the frame.