animascript · for rive

TypeScript syntax. C-class speed. Every Rive runtime.

AnimaScript is Rive’s language for fast scripts. Write .as files in a Rive project and rive compiles them to WebAssembly as you save. AnimaScript began as AssemblyScript and adds what Rive content needs: structs, closures, SIMD, threads and real time audio. The result runs everywhere Rive runs, on the browser’s own engine on the web and as compiled machine code on native platforms.

Get started Read the docs →
bounce.as
struct Vec2 {
    x: f32;
    y: f32;
}

export function reflect(v: Vec2, n: Vec2): Vec2 {
    // Structs never allocate: a Vec2 is two f32 values held
    // in locals, and it returns as two results.
    const d: f32 = 2.0 * (v.x * n.x + v.y * n.y);
    let r = Vec2();
    r.x = v.x - d * n.x;
    r.y = v.y - d * n.y;
    return r;
}

export function demo(): f32 {
    let v = Vec2();
    v.x = 3;
    v.y = -1;
    let n = Vec2();
    n.y = 1;
    return reflect(v, n).y;   // the bounce: 1
}
language

The TypeScript you know, with the parts fast code needs.

Types are real. An i32 is a 32 bit integer and an f32 stays in a register, so nothing sits between your arithmetic and the hardware: no boxing, no tagged values, no garbage on the hot path.

{ } Structs

Plain data that copies like a number and never allocates. A Vec2 is two f32 values in registers, and body.transform.p.x compiles to one load at a fixed offset.

structs →

=> Closures

Functions capture the locals around them, safe to keep in fields and return. Upstream AssemblyScript never shipped them.

closures →

@job Jobs & workers

Move heavy work off the frame. A @job function runs on a thread pool. A @worker lives across frames, talks through ports and shared memory, and can meet other workers at a barrier.

threads →

~ Audio processors

Render sound sample by sample on the audio thread, fed by rings and snapshots from your script. A processor renders the same samples on every platform, so a recording makes a reliable test.

audio →

v128 SIMD

Four lanes per instruction with the f32x4 and i32x4 builtins, on by default. Keep a scalar path beside it for browsers without SIMD, from the same source.

simd →

-O Optimized builds

Published builds inline small functions and turn a new that never escapes into plain locals, so code that makes a temporary object per step does not pay for the allocation.

build settings →
performance

Measured on real libraries.

Box2D physics, Google’s Draco mesh decoder and a physical model piano, each ported to AnimaScript and checked against the original.

1.4×
from native C on the Box2D pyramid benchmark, both with SIMD, on V8, Chrome’s engine
23.5 KB
gzipped Draco decoder that beats Google’s own on every test mesh, at under a quarter of its size
3%
of one core for a physical model piano holding a ten note chord on the audio thread
~1 s
from save to optimized machine code in rive’s live window, a tenth of that when cached
coming from luau

We recommend AnimaScript for every new script.

Luau is deprecated. Luau scripts keep running on every Rive runtime, but new scripting features land in AnimaScript, and threads and audio processors already exist only there. Start new scripts in AnimaScript and move existing ones as you work on them. Both languages implement the same protocols with the same hooks, so a script keeps its shape when it moves.

LuauAnimaScript
Typesgradual: values carry their type while the script runs static: an i32 is a 32 bit integer and a struct is plain data
On the webLuau’s virtual machine, itself compiled to WebAssembly, interprets the bytecode runs directly on the browser’s WebAssembly engine
NativelyLuau’s virtual machine interprets the bytecode machine code compiled ahead of time where the platform allows it, an interpreter elsewhere
Threadsnone jobs, workers, shared memory and barriers
Audioplays sounds plays sounds, and processors render samples on the audio thread

The same effects, written once in each language, in milliseconds of script time per frame as published, measured on an Apple M-series Mac:

rive-cli sampleLuauAnimaScript, compiled AnimaScript, interpreted
text_rain2.040.371.60
text_string0.300.030.26
text_island0.170.120.18

Where a script does its own math, compiled AnimaScript runs 5 to 10 times faster than Luau. Where it mostly calls into Rive to draw, both spend their time in the same engine code and the gap narrows. Even on an interpreter AnimaScript keeps level with Luau. On the web the gap grows, since Luau’s virtual machine runs there 1.4 to 2.1 times slower than natively, while AnimaScript runs on the browser’s engine about as fast as compiled native code. The one cost runs the other way: a module carries the parts of the standard library it uses, so the smallest scripts ship larger than their Luau bytecode.

runtime

One module, every platform.

The same WebAssembly module runs on the browser’s own engine on the web and as compiled machine code natively, with an interpreter where a platform cannot generate code. Every call runs under a time budget, so a runaway loop stops with an error instead of freezing the app.

Where scripts run →