API reference
Core types
For advanced use and authoring your own forces. A force is just an object implementing the
Force contract — the engine never special-cases any single one.
Force
The contract every force implements. apply nudges one particle given one body and the shared env.
TypeScript
interface Force {
token: string; // unique id, used in data-body
label: string;
apply(b: Body, p: Particle, env: Env): void; // the per-frame law
kinematic?: boolean; // replaces velocity (wall/jet/lens/gate) — not mass-scaled
modify?(b: Body, p: Particle, env: Env): // optional (resonate, spotlight)
{ strength?: number; gate?: boolean };
source?(b: Body, env: Env): void; // class [S] — create matter (spawn), once per body per frame
field?(b: Body, x: number, y: number): Vec2; // the visual/structure field at a point:
// draws field lines + the streamlines field-flow view
} Body
A DOM element as a force source — parsed from data-* attributes, then refreshed each frame.
TypeScript
interface Body {
el: HTMLElement;
tokens: string[]; // composed force ids
strength: number; // S (data-strength)
range: number; // d_max (data-range, px)
spin: number; // ± (data-spin)
angle: number; // radians (data-angle)
ux: number; uy: number;// heading unit vector
when: string; // condition gate id
feedback: boolean; // density write-back opt-in
shaped?: boolean; // sample the box surface, not the centre (data-shaped)
rect?: () => DOMRect; // custom rect provider (shadow-DOM body whose box ≠ host box)
writeTarget?: HTMLElement; // element that receives the CSS write-back (defaults to el)
// runtime state, refreshed each frame:
cx: number; cy: number;// rect centre (canvas space)
hw: number; hh: number;// half-extents
on: boolean; // engaged (data-active)
vis: boolean; // on-screen
count: number; d: number; // density tally + eased value ∈ [0,1] (also the charge Q)
} Particle
A point-mass in the conserved pool.
TypeScript
interface Particle {
x: number; y: number; // position
vx: number; vy: number; // velocity
m: number; // mass (1 = nominal)
heat: number; // ∈ [0,1] → colour, size, glow
size: number;
cap: Body | null; // capturing absorb body
color?: string; // carried pigment
} Env
The shared per-frame environment handed to every force — precomputed vectors plus the engine services.
TypeScript
interface Env {
dx: number; dy: number; // vector body → particle
dist: number; // its length, clamped ≥ 1
form: Formation; // active eased formation
W: number; H: number; // canvas size
t: number; frameN: number; dt: number; // time, frame, step (0 under reduced motion)
neighbors(p: Particle, r: number): Particle[]; // spatial query
grid(name: string): ScalarGrid; // persistent field buffer
spark(x, y, power, color?): void; // micro-reaction
}