start

Build Settings

What rive.yaml and the rive command change about how your scripts compile.

Debug and optimized builds

The live window, rive <dir>, builds your scripts for debugging. Every line carries a probe the debugger can stop on, every loop carries a fuel check so a runaway script stops at its time budget, and every throw keeps its message. That makes tight loops run several times slower than they ship, and the log says so the first time.

The other builds are optimized. They inline small functions, turn a new that never escapes its function into plain locals, and leave the debugger’s probes out:

CommandWhat it builds
rive <dir> the debug build, in a window that rebuilds on every save
rive <dir> --optimize an optimized build that keeps throw messages; use it for timing and long tests
rive <dir> --bench the scripts a publish ships, timed frame by frame
rive <dir> --publish, rive build the scripts a published file ships: optimized, without throw messages

Jobs, workers and audio processors are always optimized, even in the live window, since nothing can step into them with the debugger. See Threads.

Natively, rive runs your module as machine code compiled ahead of time whenever it can, and on an interpreter otherwise. The log names the one each job, worker and processor module runs on, such as processors module tier: interp. Headless runs, such as --test or --render-audio, take --aot to ask for compiled code too. See Where Scripts Run.

rive.yaml

These keys shape how AnimaScript builds. rive docs project/rive-yaml has every key.

KeyValuesWhat it does
scriptingwasm Required for .as files. Without it every .as file fails the build.
wasmSimdon (default), off, relaxed Which WebAssembly SIMD the module may use. off builds a module that also runs in browsers without SIMD, such as Safari before 16.4. relaxed also allows fused multiply-adds, whose results can differ by platform. See SIMD.
wasmFueltrue, false (default) Adds fuel checks to optimized builds too, so browsers can stop a runaway script at its time budget. They cost a few percent in loops and more in deep recursion.
dangerouslyFasttrue, false (default) Compiles the time budget out of every build. A runaway script then hangs any host, so only use it for trusted content. It cannot be combined with wasmFuel.
definesa map of names to integers or booleans Build constants; see below.
audioBuffer16 to 8192 frames The live window’s audio device buffer. A bigger buffer keeps a heavy audio processor from dropping out, at the cost of latency. See Audio Processors.

A library’s scripts can also compile differently from your own while you preview: its scriptMode picks whether the debugger steps into it and how its runaway loops are stopped. See rive docs project/rive-yaml.

Execution budgets and fuel are covered in Where Scripts Run.

Build defines

A build define is an integer constant the compiler knows while it compiles. Set one with a defines map in rive.yaml, holding integers or booleans, or with --define=NAME[=n] on the command line, where a name without a value is 1. The command line wins over the file.

rive.yaml
name: game
scripting: wasm
defines:
  PIN_TIER: 2
  NO_FOG: true
shell
rive . --define=PIN_TIER=2 --define=NO_FOG

A define is not a global variable. The compiler answers for it in two places:

An if on a constant never compiles its dead branch, so a define removes a whole feature from the module rather than skipping it at run time:

tiers.as
export function tier(): i32 {
    if (isDefined(PIN_TIER)) {
        return PIN_TIER;      // --define=PIN_TIER=2 folds this to 2
    }
    return adaptiveTier();
}

export function draw(): void {
    if (!isDefined(NO_FOG)) { // --define=NO_FOG compiles the pass out
        drawFog();
    }
}
your names win

A local, global or function with the same name hides the define, captured locals included, so a define only stands in for names your source never declares. A class of that name leaves the define in force. Arithmetic on a define wraps at 32 bits like the code it replaces. Prefix define names, as in PIANO_BLOCK, so they never collide with a name the standard library declares.

Compiler constants

A few constants come from the build itself rather than from your defines. They fold the same way, which is how one source serves several builds:

ConstantValue
ASC_FEATURE_SIMD 1 when wasmSimd is on or relaxed, 0 when it is off
ASC_FEATURE_RELAXED_SIMD 1 when wasmSimd is relaxed, 0 otherwise
ASC_DEBUG 1 in the live window’s debug build, 0 in optimized builds and in jobs, workers and audio processors
gated.as
export function tick(): void {
    if (ASC_DEBUG) {
        // Only in the debug build; optimized builds drop the branch.
        checkInvariants();
    }
}

Other ASC_ names from upstream AssemblyScript, such as ASC_TARGET, compile but are always 0 and never fold, so an if on one keeps both branches. Gate code on the constants above or on your own defines.