field-ui · a relational field runtime for the DOM
Elements have mass.
Importance is gravity. Signal is charge. Relation is binding. Change is decay. The
forces that order the physical world translate an interface — its elements and its
data alike — better than any system built for either. field-ui returns what your
markup already carries as live --field-* variables you style with:
every element a body in one field, where what matters pulls, what’s related binds,
and what you attend to charges.
Most UI frameworks let you declare importance. field-ui is the first that enforces it — physically. You can’t style everything as urgent.
Add it to the stack you already have.
Most projects want @field-ui/vanilla — framework-free and
host-bundled, so createField works with no wiring. React users
want @field-ui/react. The core engine has zero runtime dependencies.
npm i @field-ui/vanilla Recommended — framework-free, host-bundled (createField works with no wiring). npm i @field-ui/react The <FieldField> React component + useFieldField hook.
No build step? Import from a CDN (playground / prototyping only):
import { createField } from 'https://esm.sh/@field-ui/vanilla'
The full package map and an install-to-reacting-headline walkthrough live in the docs.
A real interface you’d actually build.
An inbox of real unanswered questions, ranked by urgency — recency, votes, and views become mass. But the page holds one fixed attention budget, so brightening one ask dims the rest. No particle swarm; the measurement comes back as type and ink.
Open this example →Most frameworks let you declare importance. field-ui enforces it.
You can’t style everything as urgent — the attention budget is conserved. Express “these are related,” “the user has dwelled here,” or “this is unstable” as first-class runtime state, instead of hand-rolling badges, spinners, and bespoke animation for each. See conserved attention →
data-*you author → measureruntime → --field-*runtime writes back → you styleCSS Stop building the systems that exist because the DOM is blind.
The DOM can’t see what matters, what’s related, or what’s gone stale — so teams build that sight by hand, again and again. field-ui gives the DOM a continuous answer, and a whole category of code stops being yours to write and maintain.
- Priority you don’t store or sort. Importance is a measurement the field reads each frame (
--field-density), not state you keep in a store and re-sort on every change. See it work → - “Everything is P1,” solved by a law. Attention is one conserved budget — emphasize one thing and the rest necessarily yield. The normalization pass teams enforce with scoring schemes and meetings becomes something the runtime cannot violate. See it work →
- Relationships you don’t model. Connection emerges from proximity and conservation — threads, cross-boundary spill — instead of adjacency lists and graph traversal you maintain. See it work →
- Staleness without timers. Recency and decay are a force in the runtime, continuous, not a cron job or a computed column you babysit. See it work →
- One model, always current. The field re-resolves every frame, so a priority shift doesn’t fire a sort-and-re-render pass — the readout is simply already current. See it work →
field-ui doesn’t hand you a better abstraction over these jobs. It makes the question each one answered — what matters, what’s related, what’s stale — answerable by the field, so the job itself goes away.
- Zero runtime dependencies. The core engine ships with none.
- Costs almost nothing to run. Not main-thread-bound; sub-millisecond at real-page scale (~130 particles, 0.25 ms/frame). The live homepage runs 42 field instances at 120 fps with no long tasks on desktop. The measurements →
- Accessible by construction. Semantic HTML stays the source of truth; reduced-motion equivalents are enforced and linted.
- Auditable. Code-verified docs, conformance tests, a frozen 0.x API.
Trust UI for AI output.
Show support, contradiction, confidence, and provenance for model output as an inspectable field — the same deterministic field math behind the Evidence and Search studies, aimed at where it’s most urgent.
Now — how it works, live over the running engine.
Everything above is built from one contract: data-* in,
--field-* out. Below is the complete, executable manual —
36 forces, the presets, and the system behaviour, each demo
running on the real engine.
Substrate
What the field is made of — and how it locks to the page.
The platform maps semantic elements into field coordinates.
The runtime measures registered bodies through the host / platform boundary and maps each element’s box into the field — so the field and the page describe the same space.
Because it re-measures as the page changes, the field stays locked to the visible boxes through scroll, resize, and reflow.
Particles are point-masses in a medium.
Each particle carries a velocity and a nominal mass — m = 1 by default. Every frame its velocity is multiplied by a friction factor — momentum bleeds off instead of accumulating.
Damping is why the field settles into calm swarms rather than scattering. The formula shows the opt-in mode — mass: true — where m scales with size; default particles run at nominal mass m = 1.
The waves are a flow field.
Near a wave line, particles pick up a drag vector along the slope of the curve — the derivative of the sine — so they drift like debris carried down a river.
It’s why the resting field feels alive without any input.
Every page already has these four. field-ui gives them behavior.
Pick one, and watch the same page resolve through a different field.
Gravity translates priority into convergence.
They are not four effects — they are four ways a semantic surface can behave.
A body isn’t only a force. It can be a vessel.
Forces push and pull. But a body can also take matter in — it captures the dots near it, holds them as it fills, and releases them all at once when it’s full. Capture, hold, release: nothing conjured, nothing deleted. Matter just changes hands.
The shipped case is a sink. data-absorb sets how close it
grabs from; data-max sets how much it can hold; the engine writes the fill
back as --load, so the body can show how full it is. Drag it through the
swarm and watch the meter climb — then pop.
Natural-field translations
Every interface already has priority, polarity, binding, and transformation. field-ui translates the four fundamental fields into those relations — gravity becomes priority, electromagnetism becomes polarity and signal, strong becomes binding, weak becomes transformation. The runtime tokens below are engine expressions of that grammar (true 1/d², Lorentz, Langevin, diffusion, waves) — translations, not additional fundamental fields. See the Natural Fields model.
A heavy headline with a true 1/d² pull — a real well.
True softened inverse-square — a real 1/d² law.
Two states that demix charged matter into +/− domains.
The signed sibling of gravity — like repels, opposite attracts.
A region that curves moving charge into cyclotron arcs.
The Lorentz force — curves a moving charge, doing no work.
A "hot" badge that agitates the field with Brownian heat.
Langevin/Brownian agitation — a real temperature in the medium.
A dense cluster where particles ricochet like billiards.
Elastic pairwise collision — the hard-sphere billiard force.
A trail particles lay down and follow — stigmergy.
A pheromone field — deposit a mark and follow the diffused gradient.
A button that fires a real shock wave across the field.
A travelling wave — particles ride the expanding front.
A frequently-used path that wears in and starts pulling harder.
The field remembers — occupancy wears in paths that pull harder.
Forces
What a single body can do to the matter around it — designed UI verbs, stable and bounded. A designed verb is not a natural field: an attractor is not gravity, a repeller is not charge.
A body can pull the field into orbit.
An attractor defines a gravity well. The pull grows as distance falls, and a tangential component bends incoming particles into stable spirals.
Drag the attractor — the force is bound to the element, not the cursor.
A body can push the field away.
A repeller is an inverted well — the force points outward, carving a clean void the rest of the field flows around.
Drag the repeller and watch a clearing open around it.
A body can be a wall.
A wall is an axis-aligned box. A crossing particle has its perpendicular velocity reversed and scaled by elasticity, then is projected back out — a hard hit throws a spark.
Drag the wall into the drifting particles to deflect them.
A body can spin the field.
A swirl applies a dominantly tangential force — a swirl, not a drain. The inward pull is light (the swirl dominates
it roughly eightfold), so matter wheels around the body instead of falling
in. A tight inward spiral is a preset (whirlpool),
never the canonical verb.
Drag the swirl into the swarm — particles orbit rather than fall in.
A body can blow a current.
A stream emits a constant force along a heading — a fan, a jet, a prevailing wind. The swarm combs into parallel flow.
Drag the jet and watch matter streak into lanes downwind.
A body can tether the field at a fixed distance.
A tether has a rest length. Matter that crowds in is pushed out; matter that strays is reeled in — the swarm settles into an orbiting shell.
Drag the tether — matter springs back to its radius.
A body can thicken the medium.
A viscosity body neither pulls nor pushes — it bleeds momentum, as if the field turned to honey. Paired with an attractor it turns a slingshot into a settled orbit.
Agitate, then watch the rush die inside the zone.
A body can hold matter — and give it back.
A sink captures particles at its core. They aren’t deleted — they’re held inside, and the element inflates as it fills. When it saturates it goes supernova: the exact particles are released radially.
Nothing is conjured from thin air, and nothing vanishes. Matter changes hands.
A body can be a fountain.
A jet draws surrounding matter into its nozzle and relaunches it as a hot jet — the field is recycled into a stream, nothing conjured.
Agitate to feed it, then watch the jet stream off along its heading.
Designed-extended
Further designed forces, and the modifiers that wrap a sibling.
A link that bends a passing flow into caustics — no capture.
Rotates velocity, preserving speed — bends paths without adding energy.
A one-way membrane: matter passes through but not back.
A one-way membrane — passes along its heading, reflects the reverse.
A feed where light/hot items rise and dense ones settle.
A constant lift/sink by density — light matter rises, dense settles.
A divider with laminar flow — layers slide past each other.
A laminar velocity gradient — flow grows with perpendicular offset.
A "cool" section where matter snaps onto a lattice.
Snaps cool matter onto a lattice; melts and frees it when hot.
A nav where particles flock to a shared heading.
Steers toward a heading, preserving speed — flock alignment.
A hero with divergence-free turbulence drifting through it.
Divergence-free curl-noise turbulence.
A tag group that behaves like a droplet — a swarm with a skin.
Short-range pressure + mid-range pull — surface tension.
A dense cluster that relaxes to an even fill, like a settling fluid.
SPH density relaxation — incompressible even-fill via mutual repulsion.
A two-species swarm that chases and scatters — a living ecosystem.
Two-species pursuit — predators seek prey, prey flee predators.
A nozzle that jets matter into the field — a literal fountain or a star seeding the void.
A source [S] — creates matter along the heading, budgeted by a lifespan + pool ceiling.
A cluster that holds together like cloth — a soft structure that ropes and drapes.
A Verlet distance constraint — ropes, chains, cloth, soft structures.
A logo or chart that assembles from drifting matter — a mark, never words.
Matter assembles into a mark / chart / logo — never words (§11).
Pair with attract: a well that breathes (pulsing strength).
Pulses its sibling forces with a time-varying strength.
Pair with stream: a directed beam confined to a cone.
A directional gate — confines sibling forces to a beam.
A reading column the field quiets down around — text shielded from a noisy page.
A quiet zone — attenuates other bodies' forces inside its radius (shield, never global).
A section that stains passing matter its own color, carried away.
Conserved color transport — matter takes on and carries a tint.
A magnet or charge whose field lines the swarm threads, like plasma along a solar prominence.
Follow the field lines — steer onto and stream down the net field a body radiates.
A pair of portals: matter that enters one throat emerges from its partner, conserved.
A wormhole throat — relocates matter (conserved) to its data-pair body, twisted/scaled.
Presets
Cosmology as composition — named arrangements of the primitives.
A dramatic focal element — the field pours in, circles, and is swallowed.
A well, an accretion disk, an event horizon, and lensing.
A source that only emits — the field is pushed away and downwind.
An emission horizon that throws matter out.
A balanced body — gravity’s pull held off by thermal pressure.
Hydrostatic equilibrium — gravity balanced by thermal pressure.
An accreting core with bright jets firing from its poles.
An accreting black hole with polar jets.
A spiral that winds the field into arms and settles into a disk.
A spiral disk that settles into a plane.
A warm, slow cloud — the field churns and light wisps rise.
A warm, slow cloud with rising wisps.
A funnel that swirls the field up its axis, ragged at the edges.
A funnel with an updraft, calmed at the edges.
A literal fountain — matter sprays upward and falls back in an arc.
A class-[S] source jetting matter up, arcing home under gravity.
Conditions
When a force decides to act, and on which matter.
A force can choose what it touches.
Any body can carry a condition — gated on being engaged, or on a particle’s speed or heat. A selective force reads every free agent and acts only on those that match.
The catcher below only grips hot particles. Heat the field and the excited matter is pulled in while the calm passes through.
System
What emerges when the parts interact.
The field changes the element back.
The element bends the field — and the field’s local density bends the element in return. As particles gather on a word, it gains weight, brightness, and lift.
Hover the word — it pulls the field, the field piles up, and the
pile makes the word heavier. A closed loop. (--d is the compact
compatibility alias of
--field-density.)
The page can’t emphasize two things at once.
There is one finite budget of force for the whole page. Engage a word and it pulls force off every other — so as one gathers matter and grows heavier, the rest give theirs up. Focus isn’t styled; it’s conserved.
Hover one word — watch the others surrender their weight to it.
Engaging one body wires the set.
Engage an element in a group and the field draws living threads between it and its siblings. A list stops being a list and shows itself as a connected system.
Hover any line.
Density doesn’t stop at the edge.
When a body saturates, the excess spills to its neighbours — weighted by nearness, and conserved. Engage one tile and the ones beside it light up on their own. The wiring between elements appears because matter actually flows between them.
Hover the middle tile — watch its neighbours catch, the far ones faintly.
The whole field can change its mind.
Forces act locally. A formation acts on every particle at once — a single global bias. As you scrolled, each chapter quietly switched it.
Ambient — calm brownian drift, the resting state.
Type is a readout of mass.
The word is a body. It pulls the field, matter
pools beneath it, and its whole appearance — weight, optical size,
tracking, bloom, color — is a live readout of how much has
gathered. One value, --field-density, drives every axis
at once.
Disturb it — the burst scatters the pile, the type goes light and pale, then it thickens back as the field resettles under its own pull. Type as a material, not a style.
The page arranges itself.
These nodes aren’t pinned by CSS. Each one pushes off the others and drifts away from crowded field, settling into an equilibrium — and re-settling when the field is disturbed or the window resizes. Layout as a physical process, not fixed coordinates.
Drag the attractor through them, or resize the window — the constellation scatters and re-settles like a physical object.
Gallery
Live examples that explore more of what the field can do — a working bench, to curate.
A body takes matter in — and gives it back.
Drag the vessel through the swarm: it captures nearby particles,
holds them as it fills, and releases the exact count on
supernova. These are the real field:captured / field:released
events the engine dispatches — counted live, off the running field.
Capture, hold, release — nothing conjured, nothing deleted. Matter just changes hands.
data-* in, --field-* out — the actual number.
This word is a body — data-body="attract" with data-feedback on.
The engine measures the density of matter gathered on it and writes it back as
--field-density, the same variable you'd style with. Drag it into the swarm and
watch the value — and its weight — climb.
--field-density is read straight off the element's computed style each frame — no tricks.
--field-density = 0.00One field, every reading.
The same particles, the same physics — only the reading changes. The matter row is the
underlay switch (field.setRender): one way of drawing the substance at a time.
The readings row is the overlay (field.setOverlay): line-drawn diagnostics
in front of the content — and they are additive. Stack a deformation grid over traced
paths over a temperature contour and read the field three ways at once.
Scoped to this panel: the modes play across the whole-page field while it is in view, then
restore to dots / off.
dots — The default — each particle a soft dot, cool centre → warm edge → accent.
plays across the whole page field behind the content while in viewCharge it with attention.
The contour-charge recipe: the word below is a real text body —
sink attract, gated on engagement — wearing its generated glyph outlines as a
bound representation. Hold your pointer on it and it pulls matter in, captures it, and the
contour rings thicken and glow as --load rises. Take your attention away and it
discharges — the engine releases exactly the matter it held, in a burst.
The vessel charges only while attended (data-when="active"); release fires on the
falling edge of attention. Conserved end to end — the same particles return to the field.
Charge
Seven forces, side by side.
Each frame is its own little field — a live <field-cell> rendering a
single force over its own particle pool, paused when off-screen. Move your cursor through one
to push the matter. This is a slice of the catalog’s 36 forces; the rest
compose on the page field above. Designed verbs, each bounded and legible — an attractor is
not gravity; a repeller is not charge.
The whole field can change its mind.
A formation is a global arrangement the matter falls into —
field.setFormation(name). Pick one and the entire page field re-organizes:
resting drift, gravity wells, directional lanes, scattered energy, or everything gathering in.
Active only while this panel is in view, then it restores to ambient.
Records become bodies; relevance becomes gravity.
These rows aren’t markup — they’re data, bound to the field with
bindData(records, mapper, { recipe: "search-relevance-field" }). Each
record becomes a body whose pull scales with its relevance; the field (behind the list) reads
the data and the rows organize around it. Re-rank, and the bodies re-settle.
The same call powers a real search surface — data drives the field, the field renders the data.
The active item pulls focus.
A plain nav, but every item is a body. The current one runs hot — it gathers matter, so its
--field-density stays high and it reads heaviest. Hover another and it pulls the
weight over. Emphasis isn’t a class you toggle; it’s where the field is densest.
An ordinary pattern, made reciprocal — the same trick behind priority, search, and reading surfaces.
Everything above shows the field. These twelve never do.
Twelve ordinary page types — an inbox, a market, a backlog, a front page — run as fields over real data: no particle swarm, the measurements come back as type, ink, and anchor. Each ships its data as a committed snapshot, upgrades itself to live counts when the source is reachable, and says which mode it's in.