API reference
createField & options frozen · @fundamental-engine/core
The lowest-level entry point. createField(canvas, { host, ...options })
starts the engine on a canvas you provide and returns the
FieldHandle — a host is required (the core is
renderer-agnostic; @fundamental-engine/vanilla wires the browser host for you). The web
component, the FieldField class, and mountField() all wrap it.
Looking for the whole code surface? The
imperative API reference consolidates this table with the
FieldHandle, the sampling and observable reads, the agent view, policy and budgets and
the event bus — and gives every entry a generated JS · Swift · Kotlin support row, so you can
see which planes can configure a given option at all. This page stays as the flat option lookup.
Signature
TypeScript
import { createField } from '@fundamental-engine/core';
import { browserHost } from '@fundamental-engine/dom';
const field = createField(canvas, { host: browserHost(), ...options }); // → FieldHandle
// browser convenience — @fundamental-engine/vanilla re-exports a createField that wires browserHost() for you:
import { createField } from '@fundamental-engine/vanilla';
const field2 = createField(canvas, options); // host wired internally A host is required.
@fundamental-engine/core is renderer-agnostic, so
createField takes a host. In the browser, use createField
from @fundamental-engine/vanilla frozen · @fundamental-engine/vanilla (it wires
browserHost() frozen · @fundamental-engine/dom for you)
or pass host: browserHost() from
@fundamental-engine/dom. The snippets below omit it for brevity.
FieldOptions
Every field is optional. Defaults keep the live field unchanged until you opt in.
-
hostfrozen · @fundamental-engine/core FieldHost · default required - The environment seam (viewport, scroll, rAF, canvas). createField throws without it — pass browserHost() from @fundamental-engine/dom, or use @fundamental-engine/vanilla / the web component, which wire it for you.
-
accentstring · default palette's first stop - The travelling accent color (a hex string).
-
densitynumber · default 1 - Particle-count multiplier.
-
wavesboolean · default false - Draw the background Currents (the wave layers + bound shimmer). Opt-in (#979): a bare field has no carrier waves; pass true for the ambient resting structure.
-
waveStyle'linear' | 'circular' · default 'linear' - The wave current pattern. linear draws parallel horizontal waves; circular draws concentric orbits circling around the waveCenter or the star body. <field-root wave-style>.
-
waveCenterVec2 | (() => Vec2) | null · default null - The center coordinate (or coordinate-provider fn) for circular waves. Defaults to the first body tagged with star or vortex, or the center of the field. <field-root wave-center> (space-separated, e.g. "200 300").
-
background'opaque' | 'transparent' · default 'opaque' - Substrate background. 'transparent' clears to transparent instead of painting the near-black substrate, so the underlay composites over light content (an image, a 3D scene, a light page) — trails fade to transparent rather than to black. Also a <field-root background> attribute and live via setBackground.
-
depthnumber · default 0 - Optional z volume. 0 (the default) is the flat field, byte-identical to the 2D engine; > 0 opens a shallow depth the matter drifts through, projected as a size/alpha recession. Purely additive — no API requires z.
-
integrator'legacy' | 'fixed' | 'velocity-verlet' · default 'legacy' - Integration scheme (substrate doc 04 §Step 3, #659). 'fixed' opts into the partially frame-rate-corrected integrator: the FRICTION/HEAT_DECAY decays scale with dt (FRICTION^dt), so damping is consistent across frame rates — but by design it does NOT yet dt-scale force impulses (unsound for pair forces that mutate a neighbour in the same pass; deferred to the force-contract change, integrator.ts applyForce / doc-04 §Step 3); at the reference rate (dt === 1, and every golden/conformance run) it is byte-identical to the default 'legacy' semi-implicit Euler, so opting in never moves the golden. 'velocity-verlet' opts into the second-order velocity-Verlet scheme: the position full-step uses the previous step's stored acceleration (x += v·dt + ½·a·dt²), the force pass evaluates a′ at the updated position, and the velocity takes the half-step average (v += ½·(a + a′)·dt); kinematic velocity-replacing forces (jet/wall/lens/gate/warp) bypass the average as discontinuities, and decays are dt-scaled like 'fixed'. Higher positional accuracy, NOT a conservation guarantee (energy/momentum stay non-conserved by design; the per-step decay keeps it non-symplectic) — trajectories differ from 'legacy' by design once opted in. The default path never engages either mode. <field-root integrator>. Experimental.
-
render'none' | 'dots' | 'trails' | 'links' | 'metaballs' | 'voronoi' | 'streamlines' | 'flow' | 'knockout' | 'redshift' | 'blackbody' | 'depth' · default 'none' - Render mode for the underlay surface (behind content) — the same physics drawn differently. The default is 'none' (#538): the signals-only engine runs the full simulation + feedback (--d, --load, capture events) but draws nothing — the field is behavior first. Opt into a visible surface with 'dots' (particles) or another mode.
-
heatCenter{ x: number; y: number } · default { x: 0.5, y: 0.4 } - DECLARED render reference point (Wallpaper Rule, #975): the center of the cool→warm heat vignette the dots/depth swarm is tinted against, as viewport fractions ∈ [0,1] (resolved to px each frame). Formerly a hardcoded (W/2, H·0.4); the default reproduces it exactly, so the default render is byte-identical. Only affects the dots/depth render modes. Experimental.
-
redshiftObserver{ x: number; y: number } · default { x: 0.5, y: 0.5 } - DECLARED render reference point (Wallpaper Rule, #975): the observer the redshift mode measures each particle's radial velocity against (receding reddens, approaching blues), as viewport fractions ∈ [0,1]. Formerly a hardcoded (W/2, H/2); the default reproduces it exactly, so the redshift render is byte-identical. Only affects the redshift render mode. Experimental.
-
depthFocalnumber · default 480 - DECLARED render reference point (Wallpaper Rule, #975): the perspective focal length (CSS px) of the depth mode's camera — larger flattens the perspective, smaller exaggerates it. Formerly a hardcoded FOCAL = 480; the default reproduces it exactly, so the depth render is byte-identical. Only affects the depth render mode (pairs with depth > 0). Experimental.
-
heatmapFade{ start: number; span: number } · default { start: 0.3, span: 0.85 } - DECLARED page-layout reference (Wallpaper Rule, #975): how the density heatmap glow fades with scroll position — full above start·H, gone by (start+span)·H (H = viewport height). Formerly a hardcoded (1.15 - scrollY/H)/0.85 "content = first viewport" assumption; the default reproduces it exactly (full through 0.3 viewports, gone by 1.15), so the heatmap glow is byte-identical. Set a large span to disable the scroll fade. Only affects the density heatmap layer. Experimental.
-
overlayOverlayMode | OverlayMode[] · default 'off' - Field Surfaces: the overlay READING(S) drawn in front of content (see the overlay-readings table) — one reading or an additive stack. Set alongside render. <field-root> manages the front canvas (space-separated tokens in the attribute); for createField directly, pass overlayCanvas.
-
gridWarpnumber · default 1 - Distortion multiplier for the grid overlay (the reference lattice displaced by the field). 1 is the calibrated "legible, never chaotic" deflection; 2–3 exaggerates the deformation for demos; 0 flattens the lattice. Only affects the grid overlay mode. <field-root grid-warp>.
-
gridIntensitynumber · default 0.16 - Stroke intensity (opacity) of the grid overlay lattice ∈ [0,1] — turns the warped grid from a faint diagnostic into a visual centerpiece (#552). 0.16 is the calibrated default; raise it (~0.4) to make the bending space the hero of a section. Only affects the grid overlay mode. <field-root grid-intensity>.
-
boundsHTMLElement · default window - Contained fields (#540): scope the field to a single element instead of the viewport. A vanilla createField / new FieldField option — the field measures and renders inside the given element (a card, a panel), so a component can carry its own local field. Omit for the default full-window field. (containerHost() is the lower-level door.)
-
massboolean · default false - First-class mass: particle mass ∝ size and body forces accelerate by a = F/m; dynamic bodies also get inertial mass ∝ rendered area (#872).
-
reactionboolean · default false - Newtonian own-emission reaction (#873): a dynamic body feels the equal-and-opposite of the net impulse it imparts to nearby matter (a directional emitter recoils like a rocket). Best paired with mass. Experimental.
-
palettestring | string[] · default 'ours' - Accent template — a built-in name or custom hex stops.
-
themestring · default 'warm' - Ambient theme preset — 'warm' | 'cool' | 'mono'. Sets the free-particle heat ramp and the background-wave baseline (distinct from the travelling accent). 'warm' reproduces the shipped default.
-
gradientCoolstring · default theme's - Hex for the cool (resting) end of the free-particle heat ramp — overrides the theme. <field-root gradient-cool>.
-
gradientWarmstring · default theme's - Hex for the warm (energized) end of the heat ramp — overrides the theme. <field-root gradient-warm>.
-
waveBaselinestring[] · default theme's - Hex stops for the background-wave baseline — overrides the theme. <field-root wave-baseline> (space-separated).
-
attentionboolean · default false - Conserved attention — one finite strength budget; engaging a body starves the others.
-
causalityboolean · default false - Cross-boundary causality — a saturated body spills density to its neighbours.
-
heatmapboolean · default false - Density heatmap — a glow layer of where matter pools, sampled back to bodies as --field-heatmap-density.
-
separationnumber · default 0 - Strength of short-range particle-to-particle separation/repulsion force ∈ [0,1] to break up clumps in high-density areas. <field-root separation>.
-
ambientOrbitnumber · default 0.1 - DECLARED ambient bias (Wallpaper Rule, #978): the resting ambient formation's tangential swirl injected into attract bodies — the gentle spiral free matter traces around a well at rest. Formerly a hardcoded 0.1 painted into the default formation preset; now a documented dial defaulting to that value (resting behavior unchanged). Set 0 for a purely radial attract (no spiral). Applies to the ambient formation only. <field-root ambient-orbit>.
-
ambientWandernumber · default 1.0 - DECLARED ambient bias (Wallpaper Rule, #978): the resting ambient formation's wander term — the per-particle drift that keeps resting matter alive rather than frozen. Formerly a hardcoded 1.0 in the default formation preset; now a documented dial defaulting to that value (behavior unchanged). Lower for a calmer rest, 0 to still the drift. Applies to the ambient formation only. <field-root ambient-wander>.
-
restingMotion{ mode: 'thermal' | 'flow'; strength?: number } · default undefined (off) - The resting-motion floor (DECLARED, default OFF). Signals-first defaults leave a DRAWN field (render: 'dots') settling into its attract wells and freezing when idle; this is the honest, global alternative to painting waves — a small per-particle impulse the field MEASURES as --temperature, with nothing drawn. 'thermal' is the thermal force's Langevin kick applied field-wide (Box–Muller through the injected rng, so a seeded run reproduces); 'flow' is a divergence-free curl (the stream function ψ = sin(kx+φ)·sin(ky−φ), one eddy ≈ 400px) with a slow phase drift so it never settles. strength multiplies the impulse (default 1; 0 = off). Both scale with dt, so reduced motion (dt = 0) contributes exactly nothing. Default-off ⇒ the cross-plane conformance golden is untouched. <field-root resting-motion="thermal"> / <field-root resting-motion="flow 0.5">. Mirrored on Swift (FieldOptions.restingMotion) and Kotlin (createField(restingMotion =)).
-
overlayCanvasHTMLCanvasElement · default undefined - Field Surfaces: a caller-provided canvas for the overlay surface (drawn in front of content). The web component creates/manages this for you; pass it only when calling createField directly — createOverlaySurface() in @fundamental-engine/dom creates and places the same fixed, click-through, aria-hidden canvas (configurable blend / z-index) so you need not hand-roll it (#721).
-
overlayCanvasProvider() => HTMLCanvasElement | null · default undefined - Field Surfaces: a lazy alternative to overlayCanvas (#676). When no overlayCanvas is set, core calls this once — the first time an overlay reading actually goes active — to obtain the surface. Lets a host defer creating its full-viewport mix-blend canvas until an overlay is switched on, so the common overlay:off path never adds a canvas to the compositing tree at boot. <field-root> uses this internally; return null to decline. Ignored when overlayCanvas is set.
-
feedbackSinkFeedbackSink · default undefined - Advanced: route per-body density/feedback writes to the platform FeedbackRegistry instead of letting the engine write the DOM (Phase D3).
-
dprCapnumber · default 2 - Backing-store device-pixel-ratio ceiling (#410) — the dominant fill-rate lever. Effective DPR = min(devicePixelRatio, dprCap); capping at ~1.5 buys ~1.8× headroom on retina for a small perceptual softening. Runtime-settable via setDprCap. <field-root dpr-cap>.
-
overlayBackendRenderBackend · default Canvas 2D - Drawing backend for the overlay surface (#373) — the structural seam a WebGL/WebGPU surface implements. Defaults to the Canvas 2D implementation over overlayCanvas. See render-backend.ts.
-
rng() => number · default Math.random - Random source for ALL engine randomness — particle seeding, spawn scatter, jitter, release angles (#371). Supply a seeded generator to make a run reproducible (the record/replay seam).
-
now() => number · default performance.now - Wall-clock source for input-idle tracking (#371) — one of the three engine clocks (wall / frame / simulation). Defaults to performance.now; override in tests or replay harnesses.
-
policyFieldPolicy · default undefined - Runtime FIELD POLICY — what THIS host/session/user/app PERMITS at runtime (distinct lane from governance, which is what doctrine allows via static lint). FieldPolicy { allowBodyDataInSnapshots?, allowMotionProjection?, maxMotionBudget? (0..1), budgets?: Partial<FieldBudgets> }; FieldBudgets bounds consumable resources: motion/force/attention/thermal/render/privacy/accessibility/agentRead. WIRED today: the motion budget folds (via min) with reduced-motion + perf pressure into the effective motion the integrator/easing reads — reduced-motion always wins (a policy can lower motion, never raise it); the privacy budget (+ allowBodyDataInSnapshots) gates body data in snapshot(). Other budgets are declared-not-yet-enforced. Change it live with setPolicy. Purely additive — a field with no policy behaves exactly as before.
-
identify(el: HTMLElement) => FieldBodyIdentity | undefined · default undefined - First-class body identity resolver: derive a stable, structured FieldBodyIdentity ({ id, namespace?, kind?, host? }) from a DOM-scanned body's element, called once per body. The identity is surfaced on query()/snapshot() body readings and used as the stable key for diff/replay/relationships. Return undefined to fall back to the default derivation (the element DOM id, else a monotonic body-N). Purely additive — a field without identify behaves exactly as before.
Common configurations
Every option is optional and the defaults keep the field calm. These are the combinations
worth knowing — each is the whole options object (the host is omitted;
wire it per the signature above, or use @fundamental-engine/vanilla). Switch tabs to compare.
// the resting field — an accent and a palette, nothing else
createField(canvas, { accent: '#4da3ff', palette: 'ours' }); // draw the force field itself as arrows — a diagnostic view
createField(canvas, { render: 'streamlines' }); // focus one thing at a time — one finite strength budget,
// so engaging a body starves the others
createField(canvas, { attention: true }); // a large or low-power surface — half the particles (waves are already off by default)
createField(canvas, { density: 0.5 }); // first-class mass — particle mass ∝ size, bodies accelerate by a = F/m
createField(canvas, { mass: true }); These are creation-time. Most have a live counterpart on the
FieldHandle —
setPalette, setRender,
setAttention, setCausality — so you can change them after mount too.