timer
Import from @pierre/ecs/modules/timer.
A small, embeddable countdown value — the shared timing primitive
behind modules/lifetime, modules/cooldown, and (later)
modules/spawner.
Timer is a value, not a component or system. Embed it wherever a
countdown belongs — as a flat component (its fields are all primitives, so
timerSchema plugs straight into simpleComponent) or as a field on game
state (e.g. a global spawn cadence). Because it is a value, an entity can
hold several independent timers (a lifetime and a fire cooldown) without
collision.
type TimerMode = 'once' | 'repeating';
interface Timer { remainingMs: number; durationMs: number; mode: TimerMode; justFinished: boolean;}
const timerSchema: SimpleSchema<Timer>;
function makeTimer(durationMs: number, mode?: TimerMode): Timer;function tickTimer(t: Timer, dtMs: number): void;function finished(t: Timer): boolean;function justFinished(t: Timer): boolean;function fraction(t: Timer): number; // elapsed [0,1]; remaining = 1 - fractionfunction restart(t: Timer, durationMs?: number): void;oncecounts down, clamps to zero, and latches —finishedstays true;justFinishedis true only on the crossing tick.repeatingwraps on reaching zero (multiple wraps in one tick coalesce into a singlejustFinished);finishedreports the per-tick wrap edge.
As a flat component field-set
Section titled “As a flat component field-set”import { timerSchema, type Timer } from '@pierre/ecs/modules/timer';import { simpleComponent } from '@pierre/ecs';
type Charge = Timer;const ChargeDef = simpleComponent<Charge>('charge', timerSchema);As plain game-state (global cadence)
Section titled “As plain game-state (global cadence)”import { makeTimer, tickTimer, justFinished } from '@pierre/ecs/modules/timer';
state.spawnTimer = makeTimer(1500, 'repeating');// each frame:tickTimer(state.spawnTimer, dtMs);if (justFinished(state.spawnTimer)) spawnEnemy();Import via @pierre/ecs/modules/timer. Depends on core only (SimpleSchema).