Skip to content

Timer

The GameTimer provides pause-aware timing primitives for game logic. It offers one-shot delays, repeating intervals, and pollable cooldowns -- all operating in game-time milliseconds derived from the engine's delta time.

When the game is paused, all timers freeze automatically.

Accessing the Timer

typescript
const engine = await createGameEngine({ canvas });
const timer = engine.timer;

API Reference

MethodSignatureReturnsDescription
delay(ms : number, callback : () => void)() => voidOne-shot timer; returns a cancel function
interval(ms : number, callback : () => void)() => voidRepeating timer; returns a cancel function
cooldown(ms : number)CooldownHandlePollable cooldown handle
cancelAll()voidCancel all active delays, intervals, and cooldowns

delay

Fires a callback once after ms milliseconds of game time. Returns a cancel function.

typescript
showHitIndicator();
const cancel = engine.timer.delay(200, () =>
{
    hideHitIndicator();
});

// Changed your mind? Cancel it.
cancel();

The ms parameter must be >= 0. Passing a negative value throws a RangeError.

interval

Fires a callback repeatedly every ms milliseconds of game time. Returns a cancel function.

typescript
// Regenerate 1 HP every 2 seconds
const cancel = engine.timer.interval(2000, () =>
{
    player.state.hp = Math.min(player.state.hp + 1, player.state.maxHp);
});

// Stop regeneration
cancel();

The ms parameter must be > 0 (strictly positive). Passing zero or a negative value throws a RangeError.

WARNING

An interval of 0 is not allowed because it would fire infinitely within a single frame. Use delay(0, ...) for a next-frame callback instead.

cooldown

Creates a pollable cooldown handle. Starts in the ready state. After calling reset(), the cooldown becomes not-ready until ms milliseconds of game time have elapsed.

typescript
const fireCooldown = engine.timer.cooldown(500);

function tryShoot() : void
{
    if(fireCooldown.ready)
    {
        shootProjectile();
        fireCooldown.reset(); // Starts the 500ms cooldown
    }
}

CooldownHandle

typescript
interface CooldownHandle
{
    readonly ready : boolean;
    reset() : void;
}
Property / MethodTypeDescription
readybooleantrue when the cooldown has elapsed (or has never been reset)
reset()() => voidStart (or restart) the cooldown timer

Cooldowns are passive -- they do not fire callbacks. Check ready whenever you need to gate an action. This makes them ideal for ability cooldowns, rate-limiting player actions, or any "can I do this yet?" check.

cancelAll

Clears all active delays, intervals, and cooldowns:

typescript
engine.timer.cancelAll();

This is called automatically during level transitions, so you do not need to manually clean up timers when switching levels.

Any CooldownHandle references you are still holding will report ready: true after cancelAll() is called.

Game Time vs. Wall Time

All durations are measured in game-time milliseconds. The timer advances by the engine's delta time each frame via an internal tick(dtMs) call. Key consequences:

BehaviorDetail
Pausing freezes all timersWhen the game is paused, tick() is not called -- delays, intervals, and cooldowns all freeze
Frame rate affects granularityA 500ms delay fires on the first frame where accumulated time >= 500ms. At 60fps (~16.7ms/frame), that is within one frame of accuracy.
No built-in time scaleThere is no time multiplier. Slow-motion or fast-forward would need to be implemented at the engine loop level.

Usage Patterns

Timed Power-Up

typescript
function activateShield(entity : GameEntity) : void
{
    entity.state.shielded = true;

    engine.timer.delay(5000, () =>
    {
        entity.state.shielded = false;
    });
}

Spawn Wave Timer

typescript
let wave = 0;

const cancelWaves = engine.timer.interval(10000, () =>
{
    wave++;
    spawnEnemyWave(wave);

    if(wave >= maxWaves)
    {
        cancelWaves();
    }
});

Rate-Limited Action

typescript
const dashCooldown = engine.timer.cooldown(3000);

engine.subscribeAction('dash', () =>
{
    if(dashCooldown.ready)
    {
        performDash();
        dashCooldown.reset();
    }
});

Released under the MIT License.