UNAVI Docs unavi.xyz
Build · Start

How scripts run

A script is a WebAssembly component attached to a prim. The host calls into it on a fixed schedule, and it calls back out through the wired:* API.

Lifecycle

A script exports three functions, defined on wired:script/lifecycle.

FunctionRunsUse it for
initOnce, before anything elseSetup
updateOnce per rendered frameDrawing and animation
fixed-update20 times a secondInput, messages, and physics

Calls into one script never overlap. If a call runs long, the next one is skipped rather than queued.

Subscriptions

Events reach a script as a subscription it reads from, never as a callback. Input, messages, and portal intents all work this way.

Each subscription queues up to 64 items. Call drain once per fixed-update to take what has arrived.

    fn fixed_update(
        &mut self,
        _tick: exports::wired::script::lifecycle::Tick,
    ) -> anyhow::Result<()> {
        for event in self.input.drain(32) {
            println!("got input: {event:#?}");
        }
        Ok(())
    }

If a script stops draining, the oldest items are dropped once the queue is full.

Permissions

A script can only call the APIs its author is trusted with on this peer. See Trust and permissions for what each trust level unlocks.

Trust can change while a script runs. wired:script/host.granted checks for a permission ahead of time.

if wired::script::host::granted(wired::core::error::Permission::InputDevice) {
    // safe to call wired::input::device::listen
}

Errors

Every host call that can fail returns a wired:core/error. The ones a script should expect to handle are:

Using a handle that was already dropped is a bug rather than an error. The script traps, and the host stops it for good.