API reference

Core & platform types

For advanced use and authoring your own forces. Core types describe field computation (renderer-agnostic); platform types describe DOM participation. 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] → color, size, glow
  size: number;
  cap: Body | null;          // the sink body that captured it
  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
}

Platform types

The core types above are renderer-agnostic. @fundamental-engine/platform adds the DOM participation layer: createFieldPlatform(root) returns a FieldPlatform binding the six registries to the FrameScheduler. See the platform overview.

TypeScript
// @fundamental-engine/platform — DOM participation (createFieldPlatform(root))
// Phase = the SCHEDULER phase (a runtime loop step) — not a particle or transition phase.
type Phase = 'discover' | 'read' | 'compute' | 'state' | 'write' | 'render';

interface FieldPlatform {
  measure: MeasurementRegistry;        // frame-stable geometry (read phase)
  state: StateRegistry;                // typed element state (number/boolean/string/vector2)
  feedback: FeedbackRegistry;          // CSS vars + thresholded events (write phase)
  relationships: RelationshipRegistry; // native href/aria/data-field-relation graph
  visuals: VisualBindingRegistry;      // visual ↔ semantic pairing (a11y)
  overlays: OverlayRegistry;           // render layers — read-only, never mutate physics
  scheduler: FrameScheduler;           // the six-phase loop
  on(phase: Phase, fn: (ctx: FrameContext) => void): () => void;
  tick(now?: number, viewport?: Viewport): FrameReport;
}

// lintPlatform(platform): PlatformLintWarning[]  — the field-system guardrails

Two words that mean different things

A couple of terms recur across lanes — they are disambiguated here so a type is never misread:

phase
Scheduler phase — a runtime loop step (discover → read → compute → state → write → render), the Phase type above. A transition phase (a weak-field state change, expressed by the morph token) and a particle phase (a particle property) are different things. There is no phase force token.
mass
A property / metric — the particle field m, or a recipe metric. It is not a runtime token; weight comes from gravity / attract.
potential
A diagnostic (a sampled scalar field), not a token — see diagnostic overlays.