Concepts

How the field thinks.

Shipped · every claim here runs on this page

Fundamental is a platform-native relational field runtime; the DOM is its first host. Elements are bodies in one shared field context — they bend the field; its density bends them back. A renderer-agnostic core computes the field; a host adapter binds it to a platform (on the web, to the DOM). The visible canvas is one render surface, not the whole system.

Bodies

A body is any element you mark with data-body. Its value is one or more force tokens, space-separated — they compose, so a single element can attract and swirl at once. The engine re-reads each body's bounding box every frame, so moving the element moves the force.

HTML
<a
  data-body="attract swirl"  // forces compose, space-separated
  data-strength="0.9"
  data-range="320"
  data-color="#4da3ff"
  data-when="active"         // gate: only acts while engaged
  data-feedback              // opt into density write-back
>link</a>

Common attributes — data-strength, data-range, data-color, data-spin, data-angle — are read by the forces that use them; each force ignores the ones it doesn't. See the attribute reference for the full matrix.

Data attributes are the contract. You make semantic HTML participate in the field by adding attributes to it — there is no special body element. <field-root> only hosts the field; applyPattern() frozen · @fundamental-engine/dom and bindData() frozen · @fundamental-engine/dom adapt it to patterns and data; and the <field-cell> frames lower down are just isolated single-force microscopes. The system is the markup, not the components.

The shared field context

Bodies, particles, relationships, measurements, metrics, feedback, and overlays all share one field context. The visible particle layer is a conserved pool (~130 at default density) drawn on a full-viewport <canvas> — one render surface among several (SVG overlays and DOM feedback are others). Particles are one agent type, not the whole substrate. The conserved pool carries a central law: nothing is created from nothing — matter is moved, captured, and released; a sink that swallows particles must later release them, so the count stays constant. That is what makes the field feel physical rather than decorative.

The platform layer

@fundamental-engine/core (the core) computes the field against plain data and stays renderer-agnostic. @fundamental-engine/dom binds it to the DOM through six registries — measurement (frame-stable geometry), state (typed element state), feedback (CSS variables + thresholded events), relationships (the native href/aria/data graph), visual bindings (visual ↔ semantic pairing), and overlays (render layers) — all driven by one frame scheduler with explicit phases:

discover → read → compute → state → write → render

Reads happen in the read phase and writes in the write phase, so geometry reads never thrash against DOM writes. Since the runtime-unification phase the platform is the default for <field-root>; the core engine still renders the canvas. See the platform layer for the registries, scheduler, and lint.

The DOM ⇄ field runtime binding

The rarest property of the system is a two-way binding between layout and a physics runtime. Fundamental is not a particle background: those are one-way (a canvas reacts to the mouse). Here the DOM is the runtime's geometry, and the runtime writes back into layout and type — a shared field context, not a decorative layer. Two flows, on the scheduler's read and write phases:

Per frame
// read phase — DOM → field (platform MeasurementRegistry, once per frame, per body)
cx = (rect.left + rect.width / 2) * DPR
cy = (rect.top  + rect.height / 2) * DPR

// write phase — field → DOM (platform FeedbackRegistry, per data-feedback body)
element.style.setProperty('--d', density)   // d ∈ [0, 1], canonical raw channel
// (the field-namespaced --field-density is written too, same value)

Read (geometry in): any DOM change — reflow, transform, resize — is an instantaneous change to the force geometry, so animating the DOM animates the runtime for free. Write (feedback out): the field samples how much matter pooled on each data-feedback body and writes it back as --d (with the field-namespaced --field-density holding the same value).

Reciprocity & --field-density

Reciprocity is the payoff. Opt a body in with data-feedback and the FeedbackRegistry eases the gathered density into a CSS custom property --d ∈ [0, 1] on the element — the canonical raw density channel (its field-namespaced form --field-density is written alongside it, same value). Your styles turn that number into anything — weight, glow, scale, color:

CSS
.headline {
  /* the field writes the density channel; CSS turns density into weight + glow.
     --d is the canonical raw channel; --field-density is its field-namespaced form. */
  font-variation-settings: 'wght' calc(380 + var(--field-density, 0) * 420);
  text-shadow: 0 0 calc(var(--field-density, 0) * 40px) rgba(77, 163, 255, var(--field-density, 0));
}

The value is low-pass filtered (a ~0.2s time constant), so it eases rather than jitters. This is the sanctioned way to make type react — words gain weight where matter collects. (The engine never assembles particles into letterforms; words glow and grow, they are not drawn from dots.)

Metrics, and the lanes that stay separate

Density is one channel. The field also computes higher-level metrics — attention, priority, coherence, entropy — and writes each back as a --field-<metric> custom property. A pattern declares which metrics it tracks; the runtime writes them. Below, real elements carry a runtime token (data-body="attract") and a supplied priority; applyPattern() writes it back as --field-priority, and the CSS reads it — no canvas, no cursor needed:

Primary — ship the runtime

Secondary — write the guide

Later — tidy the changelog

data-body="attract" + supplied priority → applyPattern() → --field-priority → this element Each row supplies a different value, so the field's feedback is visible at a glance — the readout shows what the field actually wrote back.

The vocabulary works because each word lives in exactly one lane, and the lanes never bleed into each other:

  • Concept describes (priority, polarity, binding) — it is never executed.
  • Token executes (attract, gravity) — the only thing a data-body runs.
  • Metric measures (--field-priority, --field-attention) — state the field writes back, not a force.
  • Diagnostic explains (potential, topology, causality) — it inspects behavior, it does not cause it.
  • Condition activates (data-when="active") — when a token is allowed to act.

So: a concept is not a token, a token is not a metric, and a diagnostic is not behavior. The pattern model composes these lanes without ever inventing a new force.

The orthogonal axes

The vocabulary stays small by separating four independent dimensions:

  • Forces — what a body does to nearby matter (attract, swirl, gravity, lens…). They compose. Reference →
  • Conditions — when a force acts, via data-when (active, fast, slow, hot, cool, scrolling). Reference →
  • Formations — a single global bias applied to every particle at once (ambient, wells, lanes, scatter, accretion). Reference →
  • Render modes — the same physics drawn differently. render values: dots, trails, links, metaballs, voronoi, streamlines, flow, knockout, redshift, blackbody, depth. Overlay readings (setOverlay): field-lines, force-vectors, energy and more; setHeatmap() for the density heatmap. Diagnostic helpers you call on your own canvas (draw*()): contours, potential, topology, inspector, causality, prediction. Diagnostics →

The natural model: four fields

Fundamental does not copy physics into the interface. It translates the four fundamental fields into interface behavior. Every interface already has priority, polarity, binding, and transformation — physics already has a language for those relations.

Natural fields are conceptual. Engine primitives are translations. Canonical forces are designed verbs. Natural fields are not tokens; tokens are translations. This reframe changes nothing the particles do — it only gives each behavior a clean place in the hierarchy:

field → translation → runtime token → metric → diagnostic → pattern

The vocabulary lanes

Fundamental keeps these categories separate on purpose. A reader should never have to guess whether a word is a runtime token, a metric, or a diagnostic — the lane says so:

Natural field
conceptual translation — gravity, electromagnetic, strong, weak
Runtime token
a real passported engine force (attract, gravity, fieldflow…) — strict, conformance-gated
Concept
human-facing product language (orbit, spring, trust, staleness) — not a token
Metric
measured / semantic state (mass, attention, pressure, confidence)
Diagnostic
inspection or render mode (potential, topology, causality, field-lines)
Condition
activation logic (dwell, threshold, stale, in-view, focused)
Scheduler phase
runtime step — discover → read → compute → state → write → render
Compatibility alias
older naming (--d, --mass) — kept, but not the primary path

The four fields

Gravity

priority, convergence, hierarchy

the field of what matters — important bodies bend attention and gather related matter into stable wells.

Use for priority · ranking · search relevance · centrality · anchoring · settling · attention wells

Expressions gravity

Electromagnetic

polarity, signal, field lines, flow

the field of difference and signal. Electric fields push; magnetic fields bend; fieldflow carries.

Use for polarity · contrast · signal · routing · state opposition · field lines · guided flow · activation

Expressions chargemagnetismpropagate

Strong

binding, cohesion, structure

the field of what holds together — groups, clusters, bonds, constraints, and durable local structure.

Use for grouping · relationship strength · clusters · bonds · constraints · local structure · material integrity

Expressions crystallizealigncohesionpressurelink

Weak

transformation, decay, release

the field of change — fading, mutation, release, phase shift, expiration, and handoff.

Use for state change · release · decay · expiration · handoff · transformation · instability

Expressions morph

Electric fields push. Magnetic fields bend. Fieldflow carries. Do not make magnetism.apply() follow magnetic field lines — field-aligned transport belongs to fieldflow. And attract is not gravity; repel is not charge — those are designed UI verbs.

Author each field — the data-attribute patterns

You express a field's translation with data attributes on semantic HTML, using honest runtime tokens only. A token's field is its classification, not a separate API — there is no <gravity> element, only data-body="gravity". Strong binding is the clearest case: a native href (or data-field-relation / data-field-target) is the relationship — the graph is discovered from the DOM, not declared in code.

<!-- Gravity → priority: the element converges attention -->
<section data-body="gravity" data-field-role="source" data-strength="0.9">
  <h2>What matters most</h2>
</section>

Live — gravity bodies carrying a supplied priority; applyPattern() frozen · @fundamental-engine/dom writes it back as --field-priority and the CSS reads it (gravity's interface translation, running):

Headline — converges attention

Supporting detail

Fine print

data-body="gravity" + supplied priority → applyPattern() → --field-priority → this element Each row supplies a different value, so the field's feedback is visible at a glance — the readout shows what the field actually wrote back.

Fields vs primitives vs forces

Every catalog token has a place. This grouping is read straight from the engine's classification:

Field primitive
gravitychargemagnetismpropagate
Material analogue
crystallizealigncohesionpressurelinkmorph
Transport
pigmentfieldflowrelief
Derived behavior
thermalcollidediffuse
Metric
memory
Designed UI verb
attractrepelswirlstreamviscosityjettetherwallsinklensgatebuoyancyshearwindhuntspawnresonatespotlightscreenwarp

Interface translation table

One need, separated into lanes: the runtime tokens that execute it, the metrics it measures, and the diagnostics that reveal it.

Interface needNatural fieldRuntime tokensMetricsDiagnostics
Show importance Gravity gravity attract mass priority attention potential prediction
Route signal Electromagnetic charge propagate fieldflow stream signal strength field-lines force-vectors
Show relationship Strong + EM link cohesion relation-strength topology causality
Keep things grouped Strong cohesion crystallize align cluster density topology heatmap
Show change / decay Weak morph memory decay age causality contours
Show flow through structure EM + transport fieldflow stream flow velocity field-lines prediction
Show reading history Memory (metric) memory attention recency heatmap inspector

Diagnostics by field

Each diagnostic answers “which invisible relation am I revealing?” — each one ships, as an overlay reading or a draw*() helper rather than a render value (see them live). Diagnostics are inspection modes, not runtime tokens.

DiagnosticRevealsField
Potential wells and energy landscapeGravity
Field lines electromagnetic structureElectromagnetic
Topology binding and relationshipsStrong
Causality which primitive caused changeany
Prediction near-future pathGravity / flow
Contours scalar fieldsderived
Four fields. Many expressions. One DOM runtime. Every interface has priority, polarity, binding, and transformation. Fundamental gives those relations a field model.

One element, revealed as a field participant

Everything above, on a single element, one layer at a time — the way the runtime sees it. The same ordinary HTML gains a layer per step, from plain markup to a body the field measures, drives and feeds back. Step through it; the feedback stage prints the value the field actually wrote.

1 / 9

Semantic DOM

Start with real, accessible HTML — a heading and a note. No field yet, nothing to undo. Whatever happens next, this stays selectable, focusable, and readable.

<article>
  <h3>Reciprocal interfaces</h3>
</article>

See the primitives move

Each frame below is a live <field-cell> running one force — the lightweight demo surface with its own small particle pool, not the page field. Move your cursor through a frame to push the matter around.

These are posters, not the detector. A cell uses a simplified centre-of-frame model so the motion reads at a glance. To fire a particle into the canonical force math and check it against its law, open the Lab.

Force systems also carry a known canon of failure modes — jitter, oscillation, local minima, tuning brittleness. Which of those the field damps by construction (seeded RNG, per-step friction, anchored bodies so the DOM owns placement) and which it still owns for bodies the engine actually drives is stated per mechanism in stability-and-convergence.md.

Agents: particles, elements, events

A force doesn't only push particles — it produces an influence at a location, and whatever sits there decides how to consume it. A particle consumes it as motion (the lightest agent); a DOM element consumes it as a transform offset with an anchor tether; an event sink consumes a density threshold by firing a CustomEvent you can listen for. One influence, three kinds of consumer — so the field can drive real app behaviour, not just pixels.

Fundamental calls this the Field Agent Consumption Model. A single DOM body can play several roles at once — force source, density receiver, force target, and event host. Its capture-hold-release behaviour (the sink token, data-absorb, data-max, --load) is the Body Matter Interaction submodel — sink is the token; absorb is concept language, not a runtime token.

Composites, not new code. Bigger ideas — blackhole, galaxy, tornado — are presets that expand to several co-located bodies, one primitive each. The engine never grows to add a preset.

Engine-stepped agents, tagged matter, and the scalar field

Three engine capabilities turn the swarm from a backdrop into a population you can program. They live in the core, so they work under any renderer — and the Three.js layer binds a mesh over each one.

  • Engine-stepped agents — addAgent(spec) experimental adds a participant the integrator moves (vs an agent that samples the field and integrates itself). It lives in the conserved pool, so it feels every force the swarm feels — body forces and the particle-level hunt/align/cohesion — and each step its report(p) fires so an external object (a mesh, a label) can follow it. maxSpeed clamps it; it edge-bounces rather than wrapping; it's counted by particleCount() but excluded from readParticles().
  • Matter tagging — a body stamps the matter it emits with data-species and acts selectively via data-affects (a species set). Matter outside the set feels no force and is skipped in the density sample, so several ecologies — pollen, seeds, spores — share one field with no cross-talk. Tags are read once at scan, allocation-free per frame.
  • The scalar field — sampleScalar(x, y) experimental returns the smooth diffused density ∈ [0, 1] at a point (the heatmap grid, bilinear-sampled). Its gradient stays meaningful right at a source — unlike a nearest-body readout — so a creature can forage by gradient, always reading which way is "more". Enable it with createField({ heatmap: true }); it runs even under render: 'none'.

These extend the consumption model rather than adding forces: an agent is a particle the engine drives, tagging scopes which matter a force sees, and the scalar is a read channel — no new data-body verb. The FieldHandle reference has the exact signatures.

Relationship to research

These concepts didn't only fall out of building the runtime. An external research framework — Foundations of Computational Interaction (FCI) — reaches the same distinctions from the other direction, and names Fundamental as a computational substrate for a bounded subset of them. The two converged independently: projection and coupling carry the same meaning in both, and both hold that a metric is not a construct and that a claim may only rise to the level its evidence supports.

The relationship is bounded on purpose. Fundamental is one instrument the research can use, and neither proves the other — running a field is not evidence that the account is correct. FCI is a pre-empirical program; the research papers here design the studies and make predictions rather than reporting results. The full concept map lives in the repository's canonical docs.