DriftScript
Documentation

Guide

Tasks and scopes

Asynchronous behaviour with an owner, on three clocks that are not interchangeable.

Asynchronous behaviour here is a task with an owner rather than a promise nobody holds. What that buys over a promise is cancellation, an owner, a chosen clock, and a scheduler the host can change later without changing every script.

A scope cancels what it owns

Leaving a scope cancels whatever has not finished, so detached work cannot outlive the thing that started it. A scope opened inside a plain function is refused: it would be left on the same tick it was opened, cancelling everything spawned into it.

// A task is asynchronous behaviour with an owner.
//
// `spawn` starts one inside a `scope`, and leaving the scope cancels whatever has not finished.
// That is the rule that stops detached work outliving the thing that created it, and it is
// structural here rather than something every author has to remember.
//
// `begin` is a task rather than a function, and the compiler insists: a scope opened in a function
// would be left on the same tick it was opened, cancelling everything spawned into it.

data Signal {
    fired: bool = false
    count: u32 = 0
}

task pulse(signal: mut Signal) {
    await fixedTime(250ms)
    signal.count = signal.count +| 1
    signal.fired = true
}

task begin(signal: mut Signal) {
    scope effect {
        spawn pulse(signal)
        await fixedTime(1s)
    }
}

Three clocks, and they are not interchangeable

fixedTime is the simulation step and the only clock a deterministic task may await. frameTime is the clamped frame delta and is the one to animate against, so a stall cannot advance two seconds of animation in a single frame. wallTime is the same gap untouched, and is for diagnostics.

Awaiting a clock and reading one are different rules

Inside a deterministic function, awaiting the fixed step is accepted: a resume point counted in whole ticks is a function of the tick count and replays identically. Reading a delta is refused, because a simulation is given its delta as a parameter, and one that reached out for it has stopped being a function of its inputs.