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.
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.
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.
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.
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.
// @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), thePhasetype above. A transition phase (a weak-field state change, expressed by themorphtoken) and a particle phase (a particle property) are different things. There is nophaseforce token. mass- A property / metric — the particle field
m, or a recipe metric. It is not a runtime token; weight comes fromgravity/attract. potential- A diagnostic (a sampled scalar field), not a token — see diagnostic overlays.