@field-ui/core
v0.3.1
Published
A reciprocal DOM-physics field — elements bend the field; the field's density bends them back.
Downloads
940
Maintainers
Readme
field-ui
The renderer-agnostic field engine. @field-ui/core computes the field: forces, particles, metrics,
recipes, diagnostics, and conformance, against plain data, with zero runtime dependencies and
zero DOM. Your page's elements become physical bodies in one shared field; they exert force, and
the field's local density bends them back. The visible canvas is one render surface, not the system.
This is the core. Most apps consume it through a thin adapter that wires the browser for you:
@field-ui/elements (web component), @field-ui/react, or
@field-ui/vanilla. Reach for the core directly when you own the render loop or target a
renderer other than the DOM canvas.
→ Live manual, Lab, and design system at field-ui.com.
Install
npm i @field-ui/coreThe browser host lives in @field-ui/platform; most apps reach for a thin adapter
(@field-ui/elements, @field-ui/react, @field-ui/vanilla)
instead of wiring the host themselves. The public surface is frozen for 0.x (see
API stability).
What's inside
- 36 forces in three families: 9 canonical verbs (
attract,repel,swirl,stream,viscosity,jet,tether,wall,sink), 8 natural primitives (gravity,charge,magnetism,thermal,collide,diffuse,propagate,memory), and 19 designed-extended forces (lens,gate,buoyancy,shear,crystallize,align,wind,cohesion,pressure,link,morph,hunt,spawn,resonate,spotlight, thescreenquiet zone,pigment, field-line transportfieldflow, and wormhole relocatewarp). - 8 presets compose those primitives into cosmology with no new engine code (
blackhole,star,galaxy,tornado, …), plus 5 formations that bias the whole field and 6 condition gates. - 16 render modes: matter/structure (
dots,trails,links,streamlines,metaballs,voronoi,field-lines,heatmap) and diagnostics (force-vectors,contours,potential,energy,topology,inspector,causality,prediction). - 64 recipes across 4 tiers: a recipe is a portable field program.
compileRecipe()lives here (pure, no DOM);applyRecipe()andbindData()are in@field-ui/platform. - A conformance framework that fires known particles into each force and checks the measured trajectory against the math. The same catalog drives the tests and the visual Lab.
Quick start
createField is renderer-agnostic, so it requires a host (a FieldHost: viewport, scroll, raf,
and a canvas). In the browser, the host comes from @field-ui/platform:
import { createField } from '@field-ui/core';
import { browserHost } from '@field-ui/platform';
const canvas = document.querySelector('canvas')!;
const field = createField(canvas, { host: browserHost(), accent: '#4da3ff' });
// Any [data-body] element on the page becomes a force the field reacts to:
// <a data-body="attract" data-strength="0.9" data-range="320" data-feedback>pull me</a>
field.scan(); // re-scan [data-body] after a DOM changeIf you do not want to wire the host yourself, @field-ui/vanilla re-exports a
host-bundled createField (and a FieldField class), and @field-ui/elements /
@field-ui/react wrap it as a custom element / component. createField called without a
host throws a clear error pointing you to those doors.
The model
- Bodies are declared in markup with
data-body="<force> <force>…"(forces compose). Common attributes:data-strength,data-range,data-color,data-when(a condition gate), anddata-feedback(two-way density write-back). - The field is one conserved pool of particles. It re-reads every body's rectangle each frame, so any layout change is a change to the force geometry.
- Feedback samples the density gathered on a body and eases it into the element's
--field-densitycustom property (with--dand--forces-densityas legacy aliases). Drive weight, glow, and scale from it.
The handle
createField returns a FieldHandle:
field.scan(); // re-scan [data-body] after a DOM change
field.setAccent('#a78bfa'); // recolor the travelling accent
field.setPalette('heatmap'); // swap the accent color template
field.setFormation('wells'); // switch the global formation
field.setAttention(true); // conserved attention — one finite strength budget
field.setCausality(true); // cross-boundary causality — density spills to neighbours
field.setRender('streamlines'); // draw the force field itself (a diagnostic mode)
field.flowTo(x, y); // place a movable flow focus the field bends toward
field.burst(x, y, '#fff'); // a one-shot shove + heat near a point
field.destroy(); // stop the loop, release listenersReduced motion is honoured (prefers-reduced-motion freezes the sim), and the loop pauses when the tab
is backgrounded.
Recipes
A recipe names an intent and composes existing tokens into behavior. It never adds engine behavior, and
its lanes stay separate: concepts describe, tokens execute, metrics measure, diagnostics explain,
conditions activate. compileRecipe() turns a FieldRecipe into a compiled plan with no DOM:
import { compileRecipe, recipeById } from '@field-ui/core';
const plan = compileRecipe(recipeById('priority-well')!);
// → bodies, relationships, feedback, diagnostics, metrics, and a reduced-motion output.applyRecipe() (run a recipe on a live DOM platform) and bindData() (records → bodies) are in
@field-ui/platform. Browse all 64 at /docs/gallery.
Renderer-agnostic
The engine touches no DOM globals (a boundary test keeps the allowlist empty). Everything the browser
provides arrives through an injected FieldHost, so the same engine runs on a DOM canvas, an offscreen
canvas, a headless harness, or any renderer you implement. browserHost() (in
@field-ui/platform) is the canonical DOM implementation of that contract.
Related
@field-ui/platform · @field-ui/elements ·
@field-ui/react · @field-ui/vanilla · the
documentation map.
License
MIT © Zach Shallbetter
