Fundamental · a physics engine for interfaces
Elements have mass.
Elements attract, repel and settle like real matter, so a layout shows its
relationships instead of listing them. Nothing on this page is animated — every motion
you can see is the field resolving. You add a data-body attribute; the
runtime measures and hands back live --field-* variables you style with.
You can label everything urgent. You cannot make everything heavy. Priority becomes a force, not a flag — emphasize one thing, and the rest yield.
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 →Built on this, running now.
Four doors into one core. Not ports — the same engine, reached differently.
@fundamental-engine/three Ascent Adaptive CAPM® prep on iPhone, on the App Store. The field drives readiness and pacing. <field-root> · elements zachshallbetter.com A personal site where the writing itself is the field — typographic, no particle swarm. @fundamental-engine/vanilla Native parity Six forces reproduce identical output across JavaScript, Swift and Kotlin — checked on every commit. js · swift · kotlin Change a data-* and watch the field answer.
Every control rewrites one attribute on the real element to the right — the same
data-* you'd author. The engine re-reads it and the field responds. That's the
whole surface: attributes in, motion out. Move your cursor through it, too.
data-body="attract"
Make model output you can read at a glance.
A model hands you answers; it rarely shows how sure it is. Make each claim a body in the
field, and confidence becomes weight, agreement becomes proximity, and contradictions pull
apart — so a shaky answer looks shaky and its sources are one hop away, before anyone
acts on it. The interface projects that state as type and layout; an agent reads the same field as JSON through field.query(). The same deterministic math drives the Evidence and Search studies.
Declare, influence, read, reveal, govern.
Five verbs are the whole loop. You declare host objects into the field; forces influence them through declared channels; you read the state back; projections reveal it; policy governs what may run and what an agent may read.
- DeclareHost objects become bodies — a
data-bodyattribute,addBody(), or a declared edge. - InfluenceForces act through declared channels, accumulated centrally — deterministic and replayable.
- Read
query()andsnapshot()expose the field as plain, serializable state. - RevealProjections express that state through CSS variables, DOM attributes, JSON, native views, or overlays.
- GovernPolicies, budgets, redactions, lane lints, and reduced-motion rules constrain what runs and what an agent reads.
Want the exact API? Read the docs. Want the live engine? Open the manual. Want the substrate proof? One field, two readings →
Most interfaces store meaning, then fake its effects.
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. Fundamental 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 live field reading (
--d, with--field-densityas the field-namespaced alias), 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 can read. Declared associations become field-visible structure — a Field Pattern decides when association becomes coupling, not adjacency lists and graph traversal you maintain by hand. 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 →
Fundamental 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.
Add it to the stack you already have.
One package per framework — pick the one for your stack and you’re done. Each bundles the
engine (core + the DOM binding) for you; there’s nothing to wire together.
npm i @fundamental-engine/vanilla Plain TS / JS, no framework — the typed FieldField class; one call mounts a field. This card is itself a live field body: it accretes the swarm and fills as it gathers. Guide → npm i @fundamental-engine/react React — the <FieldField> component + useFieldField hook. Guide → npm i @fundamental-engine/elements Any framework or plain HTML — the <field-root> web component. Guide → npm i @fundamental-engine/three Three.js / WebGL — the swarm as a THREE.Points layer. Guide →
Own the canvas / building your own renderer? @fundamental-engine/core is the
renderer-agnostic engine — you supply a host (Core guide). You
don’t install @fundamental-engine/dom directly — the packages above already
bundle it for you.
No build step? Import from a CDN (playground / prototyping only):
import { createField } from 'https://esm.sh/@fundamental-engine/vanilla'
The full package map and an install-to-reacting-headline walkthrough live in the docs.
One engine, many hosts.
The core computes the field against plain data and imports zero DOM. A thin host binds it to a host — so the same physics runs on the web, natively, in your renderer, or headless:
- Web —
@fundamental-engine/dombinds the engine to the page: every[data-body]element a body, feedback returned as--field-*variables. The primary surface — and what this page runs on. - Native — a Swift port runs the same field on Apple platforms (Metal / SwiftUI), and a
Kotlin port runs it on Android (Jetpack Compose, plus a non-Compose
View/Canvashost) — both free of the browser’s compositing ceiling. The Field Lab is the showcase: a native app to explore every force live. - Your renderer —
@fundamental-engine/threedrives aTHREE.Pointsswarm in your own WebGL scene; the read primitives (sample,readParticles,addField) bind the engine to anything that draws. - Headless — no DOM, no canvas: records become bodies and relationships become edges,
and a tool reads the field through
query()andsnapshot(). The smallest conformant host — for servers, tests, and agents.
How the hosts relate — and what’s at parity across them — in Implementations.
Built to be inspected.
- Zero runtime dependencies. The core engine ships with none.
- Signals-first by default. A field renders nothing unless you ask for it — the invisible field is the baseline.
- Accessible by construction. Semantic HTML stays the source of meaning; reduced motion removes motion, not meaning — enforced and linted.
- Measured, not guessed. Sub-millisecond compute per frame at real-page scale; fill-rate is the real budget and is measured on real hardware.
- Stable 0.x surface, cross-plane conformance. Code-verified docs, a frozen public API, and shared-physics conformance across web, Apple, and Android.
36 forces. 64 patterns. 8 presets. One 0.x API.
Everything above is built from one contract: data-* in, --field-* out.
The complete force-by-force manual — every force, preset, and system behaviour, each demo running
live on the real engine — now has its own page, so the homepage can stay about the substrate.
Or jump straight to a surface: the API · patterns · the force catalog.
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.