API Reference
Interface
Section titled “Interface”Simulator acts as an orchestrator that controls requestAnimationFrame based on SimulationContext.
const simulation = new Simulator();type SimulationContext = { clock: ClockPort; target: VectorReadablePort; kinetics: KineticsPort; physics: PhysicsPort | PhysicsPort[];};simulation.add(context);simulation.run();- clock: Defines when motion starts.
- target: Defines the destination position or vector.
- kinetics: Defines how motion progresses toward the target.
- physics: Defines where the computed motion result is applied (for example, an HTMLElement).
/ports
Section titled “/ports”See the full contracts in Ports.
ClockPort, VectorReadablePort, KineticsPort, and PhysicsPort are all interfaces.
Using interfaces allows overlapping implementations across responsibilities.
For example, pointerdown can act as the clock that starts the simulation while its coordinates are also used as the target.
Implements
Section titled “Implements”Simulator
Section titled “Simulator”Simulator starts clock-driven simulation when run() is called explicitly.
Use pause() to suspend execution, and destroy() to dispose the simulation completely.
class Simulator { run(): void; pause(): void; destroy(): void;}Internal Implementation
Section titled “Internal Implementation”For each requestAnimationFrame tick, clock-driven simulation executes three steps: snapshot, compute, and apply.
- In
snapshot,VectorReadablePort.snapshotis called for every target to capture frame-stable vectors. - In
compute,kineticsadvances the state toward the target vector. - In
apply, the state computed bykineticsis applied to the actual output target.
class Simulator { private applyStep(delta: number, now: number): void { this.snapshots.snapshotAll(now);
for (const { clock, kinetics, target } of this.contexts) { // ... kinetics.compute(delta, target.vector()); }
for (const { kinetics, physics } of this.contexts) { // ... physics.apply(kinetics.state); } }}Auto Pause
Section titled “Auto Pause”Simulator pauses automatically when clocks remain inactive for a period and kinetics motion stays below a small threshold.
Cleanup
Section titled “Cleanup”destroy() automatically calls ClockPort.destroy for all registered clocks.
As long as destroy() is called correctly, you usually do not need to handle DOM listener cleanup manually.