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
}