Skip to content

Scheduling

The scheduler answers two different questions:

  • when should this code run? — next frame, every ten ticks, after a delay;
  • how will it stop? — explicitly with Cancel() or together with a feature scope.

Import it from the runtime where the work belongs. Client scheduling follows rendered frames; Reflex scheduling follows server simulation ticks.

import { scheduler } from "@killscript/sdk/client";
// Every client frame.
const frame = scheduler.frame(updateCamera);
// Approximately twice per second.
const interval = scheduler.every(0.5, updateHud);
// Once, after 10 game ticks.
const delayed = scheduler.afterTicks(10, showReadyState);
frame.Cancel();
interval.Cancel();
delayed.Cancel();

In Reflex, import from @killscript/sdk/server and use scheduler.tick() in place of frame().

MethodUse it forStops how
frame(callback)Camera, HUD and client input updatesCancel()
tick(callback)Reflex simulation checksCancel()
after(seconds, callback)A simple native one-shot delayCannot be cancelled
afterTicks(ticks, callback)A cancellable tick-based deadlineAutomatically or Cancel()
every(seconds, callback)A lightweight repeated taskCancel()
everyTicks(ticks, callback)A repeated simulation taskCancel()
until(predicate, callback)Wait until state becomes availableAutomatically or Cancel()
debounce(key, seconds, callback)Run only after calls stop arrivingReplaced by the next call with the same key
throttle(key, seconds, callback)Allow at most one call per intervalReturns whether it ran

every() does not try to replay missed calls after a slow frame. It schedules the next run from the time the current run is observed, which is usually the right behavior for UI refreshes and periodic scans.

Objects such as the local agent may not exist during module initialization. until() avoids a permanent frame loop for this one-time wait:

const waitForPlayer = scheduler.until(
() => Agents.GetLocalAgent() !== undefined,
() => initializeForPlayer(Agents.GetLocalAgent()!),
);

The returned subscription can still be cancelled if the owning feature is disabled before the player appears.

Debounce is useful when an expensive refresh should happen once after a burst of changes:

function settingsChanged(): void {
scheduler.debounce("settings:rebuild-hud", 0.2, rebuildHud);
}

debounce() does not return a subscription. A newer call with the same key invalidates the pending callback, but a feature scope cannot cancel it directly. Keep the callback harmless when its owning feature is no longer active.

Throttle runs immediately, then rejects calls until the interval expires:

function reportPosition(): void {
scheduler.throttle("debug:position", 1, () => {
print(`${Agents.GetLocalAgent()?.Movement.Position}`);
});
}

Keys are shared inside the generated client or server bundle. Prefix generic keys with a feature name so unrelated files do not suppress one another.