# Fundamental — full canonical documentation
Source: docs/canonical/ in https://github.com/zachshallbetter/fundamental-engine
Generated: 2026-06-17 by apps/site/scripts/gen-llms.mjs
Files: 16
These are the project's canonical documents — the authority on concepts, terminology, and
contracts — concatenated in filename order. The live site map is https://fundamental-engine.com/llms.txt.
========================================================================
FILE: README.md
========================================================================
> **Status: canonical.**
> The documentation map for `docs/canonical/` — one line per document and its role. These
> documents are the **authority**: read the relevant one before changing concepts, terminology,
> or contracts. The status rule and framing policy live in
> [documentation-standards.md](documentation-standards.md).
# Canonical documentation map
Fundamental is a platform-native relational field runtime for the DOM. `Fundamental` (core) computes
renderer-agnostic field behavior; `@fundamental-engine/platform` binds it to the DOM; `elements`/`react`
are authoring surfaces. Canvas is one render surface, not the whole system.
> Concepts describe. Tokens execute. Metrics measure. Diagnostics explain. Conditions activate.
> Recipes compose. No word lives in two lanes.
| Document | Role |
|---|---|
| [`definition-document.md`](definition-document.md) | The operating model — what Fundamental *is* ("substrate, not wallpaper") |
| [`documentation-standards.md`](documentation-standards.md) | How Fundamental is described everywhere: the architecture statement, the status taxonomy, the naming policy, the verify-against-code rule |
| [`natural-fields.md`](natural-fields.md) | The four Natural Fields (gravity→importance, electromagnetic→polarity, strong→binding, weak→transformation) — concepts, not tokens |
| [`fundamental-field-behavior-table.md`](fundamental-field-behavior-table.md) | The six truth modes + the per-force behavior table |
| [`system-contracts.md`](system-contracts.md) | The hard contracts: bodies, fields, forces, agents, events, feedback, recipes, accessibility, performance, conformance, platform |
| [`platform-architecture.md`](platform-architecture.md) | The platform layer: the six registries, the six-phase scheduler, the runtime (attachHandle, QualityGovernor), linting |
| [`agent-consumption-model.md`](agent-consumption-model.md) | How consumers (particles, DOM elements, event sinks, visual layers) read one influence differently; Body Matter Interaction → Sink/Accretion |
| [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md) | The agent model: element, relationship, user, layout, and data agents |
| [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Render + diagnostic methods, and **Surfaces & Placement** (underlay / overlay / typographic) |
| [`invisible-fields.md`](invisible-fields.md) | The typographic (invisible) placement: two-field page architecture, live channels, engagement contracts, declared relationships, data provenance |
| [`time.md`](time.md) | Time in the field: the three clocks (simulation / experiential / world), the temporal kernels, the `data-field-at` contract |
| [`visual-language-and-geometry.md`](visual-language-and-geometry.md) | The visual language layer: metric→appearance mappings and geometry |
| [`authoring-and-recipes.md`](authoring-and-recipes.md) | Authoring surfaces and the FieldRecipe system |
| [`testing-and-conformance.md`](testing-and-conformance.md) | Test contracts and the conformance framework (the Lab-as-detector) |
| [`api-stability.md`](api-stability.md) | The freeze contract: the frozen surface, the experimental surface, the 0.x compatibility rules |
Deeper references live beside this directory: `docs/engine-reference/` (the engine spec —
`forces-system.md` is the big one), `docs/research/` (the paper family, with its caveat canon in
its own README), and `docs/planning-archive/` (frozen history — do not cite as current).
Planned work lives in `ROADMAP.md` / `BACKLOG.md` at the repo root and on the RC1 board.
========================================================================
FILE: agent-consumption-model.md
========================================================================
> **Status: canonical.**
> The Field Agent Consumption Model: the unified account of *what a force acts on* and *how each
> target consumes the influence*. Particles, DOM elements, and event sinks are all **agents**; each
> owns a **consumer** that turns one influence into its own kind of change. Body Matter Interaction
> (the sink/accretion behavior) is a submodel here, not a separate model. Every status label below was
> verified against the code (`packages/core/src/agents`, `packages/core/src/forces`,
> `packages/core/src/core/field.ts`, `packages/platform`) and follows the
> [documentation standards](documentation-standards.md) status rule: nothing is called
> *shipped* unless code confirms it. Deeper references:
> [system-contracts §5–§9](system-contracts.md),
> [interaction-and-relationship-model](interaction-and-relationship-model.md),
> [forces-system §22](../engine-reference/forces-system.md).
# Field Agent Consumption Model
A force does not "move particles." A force produces an **influence at a location**; whatever sits
there — a particle, a DOM element, an event sink — decides how to consume it. Particles are just the
**lightest** agents. An element is a *heavy* body with a DOM consumer; an event sink is a *write-only*
agent. One DOM body can be all three at once: sourcing force, being pushed by neighbors, and firing
events.
This is the correct framing. It is **not** a new "Body Matter Interaction" model — that older, narrower
idea (bodies absorb particles) is one **submodel** of this one. The general statement is:
```
A field body can be more than a force source.
It can be a particle source/receiver, a density receiver, a force target, and an event host.
Particles, elements, and event sinks can consume the same influence in different ways.
```
## Agent types
`FieldAgentKind` (`packages/core/src/agents/index.ts`) — seven kinds, all present in code with concrete
modules and agent contracts (`AGENT_CONTRACTS`, same file):
| Agent | What it is | Consumes / does | Status |
|---|---|---|---|
| **particle** | visual matter | velocity impulse + heat; held in a sink core | **shipped** |
| **element** | a DOM responder | metrics → `--field-*` vars + `data-field-*` bands; moved as a transform (`data-move`) | **shipped** |
| **relationship** | an active connection | strength/tension/memory; strengthens with use, decays idle; transfers attention | **shipped** |
| **user** | pointer / focus / selection | projects a field source (wake + accessible focus); respects reduced motion | **shipped** |
| **layout** | a region-level responder | aggregates contained body metrics over a rect; writes back like an element | **shipped** |
| **data** | a semantic record | salience ∈ [0,1] that decays unless reinforced | **shipped** |
| **event** | a threshold trigger | hysteretic, debounced edge detection → one clean edge per crossing | **shipped** |
Two things the broader framing sometimes calls "agents" are **not** field agents — they are platform
concerns, and the distinction matters:
- **visual layer** — the [VisualBindingRegistry](platform-architecture.md) pairs an expressive
visual (SVG/Canvas) with its semantic source for linting and inspection. It participates in
accessibility, not physics. See [Text and the visual layer](#text-and-the-visual-layer).
- **event sink** — not a distinct agent kind; it is the **event-host role** a body plays through
`data-on` (the `event` agent above provides the threshold machinery).
## Influence kinds → how each agent consumes them
Every force emits one of a few **influence kinds**. The matrix is the spec, and each cell carries its
own status. *This corrects the older unannotated matrix in
[forces-system §22.3](../engine-reference/forces-system.md), which once presented unbuilt cells as if
equal to shipped ones.*
| Influence (from force) | Particle | Element | Event sink |
|---|---|---|---|
| **impulse** `Δv` (attract, repel, wind, stream…) | `v += F/m` — **shipped** | `o_v += F/m_el` → `translate(o)` via `data-move` — **shipped** | — |
| **constraint** (tether, wall, gate) | clamp pos/vel — **shipped** | anchor tether + offset clamp (`maxOffset`) — **shipped** | — |
| **capture** (sink) | `p.cap = b`, held then released — **shipped** | dock / collapse the element via `data-dock` — **shipped** | fire `field:captured` / `field:released` — **shipped** |
| **relocate** (warp) | `warp` throat → paired body, conserved — **shipped** | teleport offset to the pair via `data-warp` — **shipped** | — |
| **emit** (spawn) | new particle — **shipped** | clone a decorative template via `data-emit` — **shipped** | — |
| **trigger** (threshold) | sets heat / state — **shipped** | toggle a class — **planned** (no built-in; do it in a `data-on` handler) | dispatch a `CustomEvent` via `data-on` — **shipped** |
| **feedback** (gathered field → output) | `--d` / density — **shipped** | `--field-*` vars + `data-field-*` bands — **shipped** | — |
"Apply a force to a DOM element" = it consumes the *same* impulse a particle would, but as a
**transform** (with element mass `m_el`) instead of raw velocity. "Apply a force to an event" = the
influence, on crossing a threshold, becomes a **signal**.
**The honest summary:** every influence kind is now wired for particles, and elements consume impulse,
constraint, feedback, capture (`data-dock`), relocate (`data-warp`), and emit (`data-emit`). The
element consumers are **opt-in by attribute**, so they never surprise existing `data-move` content, and
they stay accessible — docked elements are restored on release, emitted clones are `aria-hidden`. The
one still-planned cell is the element `trigger` *class toggle* (do it in a `data-on` handler today).
Element relocate is a **transform teleport**, not a DOM-tree reorder: reordering nodes would disrupt
focus and reading order, so it is intentionally avoided.
## Body roles
A single DOM body can play up to four roles at once. All four are **shipped**
([forces-system §22.1](../engine-reference/forces-system.md)):
| Role | Mechanism | Status |
|---|---|---|
| **source** | `data-body` tokens emit force onto particles | **shipped** |
| **density receiver** | gathered field → `--field-density` (alias `--d`), gated by `data-feedback` | **shipped** |
| **force target** | `data-move` integrates net force into a transform | **shipped** |
| **event host** | `data-on` binds field state to `CustomEvent`s; saturated bodies fire `field:lit`/`field:dim` | **shipped** |
## Body Matter Interaction (submodel)
The concrete, fully shipped particle-level case. A `sink` body captures matter into an accretion core,
**holds** it (it is not deleted), and **releases exactly what it held** when saturated.
```html
Accretion body
```
| Piece | Meaning | Code | Status |
|---|---|---|---|
| `sink` token | the only capture token | `packages/core/src/forces/index.ts` | **shipped** |
| `attract` | pulls particles toward the body | `forces/index.ts` | **shipped** |
| `data-absorb` | capture radius (`absorbR`, default 64) | `scanner.ts` | **shipped** |
| `data-max` | capacity (`capacity`, default 60) | `scanner.ts` | **shipped** |
| capture | `p.cap = b`; the particle stays in the pool, drifts to the core | `integrator.ts` | **shipped** |
| `--load` | `accreted / capacity` ∈ [0,1], written each frame | `field.ts` | **shipped** |
| `--mass` | back-compat **alias** of `--load` (identical value) | `field.ts` | **legacy** alias |
| release | saturation → `supernova` releases exactly the held particles, then resets | `field.ts` | **shipped** |
| discharge | an engagement-gated sink (`data-when="active"`) releases on the FALLING edge of attention — same conserved ritual, same events (#365) | `accretion.ts` `dischargeDisengaged` | **shipped** |
Terminology, per the [status rule](documentation-standards.md): **`sink` is the runtime
token.** `absorb` is **not** a token — only the `data-absorb` *attribute* exists. Treat `absorb` as
concept/legacy language. `--load` is canonical; `--mass` is the alias.
**Test coverage:** capture-within-radius and saturation-triggers-supernova are unit-tested
(`forces.test.ts`), and the full hold → release cycle — captured matter stays in the pool, drifts to
the core, then the *same* particles are released (conserved, count unchanged) — is covered end-to-end
through the real integrator in `accretion.test.ts`. The release core is the pure, DOM-free
`releaseCaptured` (`accretion.ts`), shared by `field.ts` and the test.
**Element capture (dock).** A `[data-move][data-dock]` element that drifts into a sink's `absorbR`
docks: it collapses toward the core (translate + scale → 0) and is held until the sink releases
(supernova), which restores it. Docked elements become `aria-hidden` while collapsed and are restored
on release and on teardown — element capture is conserved like particle capture. The collapse math is
the pure `dock.ts` (`withinCapture` / `stepDock` / `dockTransform`), tested in `dock.test.ts`.
### The sink tiers (one contract, four surfaces)
The law that orders the whole hierarchy:
> **The element absorbs field matter. The visual layer shows what that absorption means. The
> semantic text remains the source of meaning.**
One sentence for the combined concept: *a body-sink lets a semantic element act as a vessel — it
captures field matter, exposes its load as feedback, and may release that matter back into the
field, while any SVG, Canvas, or vector layer remains a bound visual representation of the semantic
source.*
```
Body Matter Interaction
Sink / Accretion
Element Sink — any DOM element as the vessel (the base contract above)
Text Sink — the same contract on real text; the heading stays real text,
CSS reads --d / --load for field-responsive typography
Bound Visual Sink — an authored aria-hidden visual (SVG/Canvas) beside the body,
bound via data-field-visual-for; the platform MIRRORS the
body's feedback channels onto it (visual-bindings.ts,
MIRRORED_CHANNELS), so var(--load) works on the sibling
Contour Sink — the text/vector form: glyph outlines as the expressive
boundary of a Text Sink. The platform primitive is
font-agnostic (contours.ts: contourPathData / contourSvgFor —
the caller supplies ANY parsed font; opentype.js fits the
ContourFont contract), usable at runtime or build time (the
site commits its output) — live at /docs/contour-typography
```
| Tier | Contract | Status |
|---|---|---|
| Element Sink | `data-body="sink …"` + `data-absorb`/`data-max`/`data-feedback` → `--load` | **shipped** |
| Text Sink | identical — text elements are ordinary bodies; a11y rule: the text stays real | **shipped** |
| Bound Visual Sink | `data-field-visual-for` + platform state mirroring (`setMirroring`, default on) | **shipped** |
| Contour Sink | font-agnostic platform primitive (`contourSvgFor` — any parsed font) + Bound Visual mirroring; demo on /docs/contour-typography | **shipped** |
Naming discipline: the tiers are *surfaces of one contract*, not new tokens — the token is `sink`
in every tier, and a chip or doc that prints `ABSORB` instead of `SINK` is wrong (absorb is the
attribute/concept lane). The visual layer never becomes the body; it represents the body.
## Events
Field events are thresholded and debounced — never per-frame by default. The canonical catalog is
`FIELD_EVENTS` (`packages/core/src/agents/event-agent.ts`); `field:*` mirrors to `forces:*` during the
alias window (`FeedbackRegistry`, `shadow.ts`).
**Dispatched today (shipped):**
- `field:lit` / `field:dim` — density crosses the lit threshold (`field.ts`; also `FeedbackRegistry`).
- `field:register-body` / `field:unregister-body` / `field:update-body` — body lifecycle (`shadow.ts`).
- `field:captured` / `field:released` — a sink begins accreting (rising edge of `accreted > 0`) and
releases on supernova (falling edge); also fired on a docked element when it docks / is restored.
- `field:relocated` — a `[data-warp]` element teleports through a warp throat to its pair.
- **any event name you bind via `data-on`** — e.g. `data-on="captured:field:dock, dense:field:lit"`.
Every `field:*` here mirrors to its `forces:*` twin during the alias window.
**Names reserved, not yet dispatched (planned):** `field:saturated`, `field:entered`, `field:exited`,
`field:attention-shifted`, `field:relationship-strengthened`, `field:memory-threshold`,
`field:entropy-warning` — the agent-threshold events, still wiring up.
**Edge nuance.** `field:captured`/`released` are edge-debounced on `accreted > 0`. Release is fired
directly from `supernova` so a same-frame fill-and-release never drops it; the rising-edge capture is
sampled after the force pass (the same model as the `captured` `data-on` trigger).
## Text and the visual layer
Text is a special case of the same model, governed by a design law
([forces-system §11](../engine-reference/forces-system.md),
[visual-language-and-geometry](visual-language-and-geometry.md)):
> Words are bodies the field decorates; punctuation is where matter assembles.
- The semantic text stays **real HTML** — the source of meaning, in the accessibility tree.
- A text element can register as a **field body**: source, density receiver, capture (sink), or event
host like any other.
- **Density drives type**, not particles: `--field-density` (alias `--d`) feeds variable-font weight
(`data-fmin`/`data-fmax`/`data-opsz`), glow, and color. **shipped.**
- **Do not assemble words out of particles** — it reads as noisy. Reserve glyph/particle assembly for
punctuation and marks (a `.`, `—`, a logo glyph), where the silhouette is simple. (design law)
- A vector/SVG/Canvas layer may **represent** the text, but it is **not** the source of meaning. Bind
it declaratively with `data-field-visual-for` + `data-field-visual-role="representation"` and keep it
`aria-hidden` — the [VisualBindingRegistry](platform-architecture.md) discovers, binds, and
lints the pairing. **shipped** (binding + lint). Generating glyph geometry *from* text
(outline extraction, text → SVG path) is **planned**, tracked as a frontier.
```html
Contour Field
```
The `h1` is the semantic source **and** a field body; `--field-density` / `--load` expose its state; the
SVG is a bound representation, not the meaning. Particles and contours are **expression**.
## Hierarchy at a glance
```
Field Agent Consumption Model
Agent types: particle · element · relationship · user · layout · data · event (all shipped)
Influence kinds: impulse · constraint · capture · relocate · emit · trigger · feedback
(per-agent status in the matrix; only the element trigger class-toggle is planned)
Body roles: source · density receiver · force target · event host (all shipped)
Submodel — Body Matter Interaction:
source · attract/repel/shape · capture (sink) · hold · release · expose feedback (shipped)
dock an element (data-dock) · emit a node (data-emit) · relocate/teleport (data-warp) (shipped)
```
> **Body-carried data (addBody).** A programmatic body created with `FieldHandle.addBody(spec)` carries an opaque `data` record — the Body-level analog of a particle's `atom`. It extends this model from *matter that carries records* to *sources that carry records*: an emitter is itself an addressable agent with attached data and per-body feedback (`onFeedback`), surfaced on its `BodyHandle`.
>
> **El-less bodies and the callback consumer.** A programmatic body has no DOM element. The model's element-agent has a *DOM consumer* (the engine writes `--d`/`--load`/`--field-*` onto the element, author CSS reads them); an `addBody` body has a **callback consumer** instead — its feedback channels arrive at `onFeedback(channels)` (and the live `BodyHandle.channels`), the non-DOM consumer for a non-DOM host (a Three.js mesh, a native view). Its force params are **reactive**: `BodyHandle.set({ strength, range, angle, spin, color })` mutates them on the measure cadence with no rescan — the same live-param path a scanned `[data-body]` gets from a `data-*` change, surfaced on the handle.
========================================================================
FILE: api-stability.md
========================================================================
> **Status: canonical.**
> This document defines the **frozen public API surface for Fundamental `0.x`** and the compatibility
> rules that govern it: what is stable, what is experimental, how versions move, and how the alias
> window works. It is enforced in code by `scripts/api-surface.ts` (typechecked) and
> `scripts/check-api-surface.mjs` (runtime), both run by `pnpm check:api` in CI. The shared machine
> data is [`scripts/api-surface.data.mjs`](../../scripts/api-surface.data.mjs); the live reference page
> is [`/docs/api/stability`](../../apps/site/src/pages/docs/api/stability.astro). Related contracts:
> [system-contracts.md](system-contracts.md),
> [platform-architecture.md](platform-architecture.md).
# Fundamental API stability
The architecture has stopped being fluid. Recipes execute, data binds, the inspector reads the live
runtime, the gallery runs, the starter installs, the studies are data-driven. Before adding more
capability, the public surface is **frozen for `0.x`** so consumers can build against it without the
ground shifting.
A symbol is "frozen" when it appears in the table below. Freezing means: it stays exported, from the
same package, with the same kind (value / type / element), and its shape does not break, for the life
of the `0.x` line. The freeze is mechanically enforced — `pnpm check:api` fails the build if a frozen
symbol is removed, renamed, moved between packages, or changes kind.
> Package npm names: core is published as **`@fundamental-engine/core`**; the rest are
> `@fundamental-engine/platform`, `@fundamental-engine/elements`, `@fundamental-engine/react`, `@fundamental-engine/vanilla`. The umbrella
> **`@fundamental-engine/kit`** installs the whole suite in one dependency (`fundamental-engine` is a thin alias
> for it); these are convenience meta-packages, not part of the frozen API surface.
## The stable surface (`0.x`)
### Entry points and runtime
| Symbol | Package | Kind | What it is |
| --- | --- | --- | --- |
| `createField` | `@fundamental-engine/core` | value | The renderer-agnostic primitive. **Requires `opts.host`** and throws without it. |
| `createField` | `@fundamental-engine/vanilla` | value | The host-bundled convenience door (= `createBrowserField`); auto-supplies `browserHost()`. |
| `browserHost` | `@fundamental-engine/platform` | value | The canonical DOM `FieldHost` for `createField`. |
| `browserHost` | `@fundamental-engine/vanilla` | value | Re-export of the platform host for the no-framework path. |
| `createFieldPlatform` | `@fundamental-engine/platform` | value | Wires the six native-first registries on a root. |
| `applyRecipe` | `@fundamental-engine/platform` | value | Applies a recipe to a live platform. |
| `bindData` | `@fundamental-engine/platform` | value | Binds records → bodies; data drives the field. |
| `compileRecipe` | `@fundamental-engine/core` | value | Pure `FieldRecipe` → compiled plan (no DOM). |
`createField` has **two doors on purpose**: the core primitive is renderer-agnostic and host-required;
`@fundamental-engine/vanilla` re-exports the host-bundled convenience so the no-framework path stays one call.
Both are frozen; the vanilla door must keep auto-supplying `browserHost()`.
### Types
| Type | Package | What it is |
| --- | --- | --- |
| `FieldRecipe` | `@fundamental-engine/core` | The recipe schema. |
| `FieldHost` | `@fundamental-engine/core` | The renderer-agnostic host contract `createField` requires; `browserHost` implements it. |
| `FieldPlatform` | `@fundamental-engine/platform` | The surface `createFieldPlatform` returns. |
### Elements and the body contract
| Surface | Package | What it is |
| --- | --- | --- |
| `` | `@fundamental-engine/elements` | One background field per page; scans the document for `[data-body]`. |
| `` | `@fundamental-engine/elements` | A scoped local field region. |
| `data-body` (attribute) | core `BODY_SELECTOR` | **The body contract.** "Every element is a body" via the `data-body` attribute on ordinary elements. |
**There is no `` element.** Bodies are an attribute on ordinary elements, not a tag, and
none will be introduced as the body mechanism. The custom elements are the field-`*` names;
`` / `` are deprecated aliases (see the alias window).
## The experimental surface (not frozen)
These carry **no** stability guarantee and may change shape or be removed in any release. Some have
exported building blocks today — those are *shipped-but-unfrozen*: present in the package, but not part
of the contract until they are added to the table above.
| Area | Status | Notes |
| --- | --- | --- |
| `FieldHandle` (full surface) | partial | The handle shape is not frozen as a type. Entry points that return it (`createField`, `createBrowserField`) are frozen, but new methods may be added in any patch. |
| `FieldHandle` diagnostic accessors | shipped-unfrozen | `particleCount(): number` and `energy(): { kinetic, thermal, total, count }` ship in `@fundamental-engine/core` and are proxied on ``. Safe to use; not frozen until 1.0. |
| Advanced diagnostics | partial | `DIAGNOSTICS` / `DIAGNOSTIC_LENS` / `draw*` primitives ship but are unfrozen. |
| Performance budget | shipped-unfrozen | `inspectBudget()`, `withinBudget()`, `DEFAULT_BUDGET`, `BudgetFinding` ship in `@fundamental-engine/core`; `FieldPerf` (frame-duration split, adaptive governor) is designed but not yet implemented. |
| Visual recipe editor | absent | No editor UI; the authoring toolkit is the substrate to build one on. |
| GPU / WebGPU backend | planned | A named direction; the six shipped render modes are CPU/canvas. |
| Multi-root bridge | absent | No API for coordinating multiple `` instances yet. |
| AI evidence fields | partial | `EVIDENCE_FIELD` + the agent API ship as a substrate, but no packaged feature. |
| Custom render backends | partial | Possible via `opts.host`; no stable backend-registration API. |
## Compatibility rules
1. **Pre-1.0 semver.** In `0.x` the **minor** is the breaking position. A breaking change to a frozen
symbol bumps `0.MINOR` (`0.2 → 0.3`); additive and fix-only changes bump the patch. Consumers
should pin to `~0.MINOR`.
2. **Additive-only within a minor.** New exports, new optional fields, and new recipes/modes may land
in a patch. Renaming, removing, or changing the signature/shape of a frozen symbol requires a minor
bump and a migration note.
3. **`createField` keeps both doors.** The host-required core primitive and the host-bundled vanilla
convenience are both preserved; the vanilla door must keep auto-supplying `browserHost()`.
4. **Package ownership is part of the contract.** Frozen symbols do not move between packages within
`0.x` (`compileRecipe`/`FieldRecipe`/`FieldHost` → core; `createFieldPlatform`/`applyRecipe`/
`bindData`/`FieldPlatform`/`browserHost` → platform; `field-root`/`field-cell` → elements).
5. **Bodies are an attribute contract.** `[data-body]` on ordinary elements is the frozen authoring
surface; there is no body element.
6. **`forces-*` → `field-*` alias window (deprecated, removal-gated).** ``/``,
`ForcesField`/`ForcesCell`/`ForcesController`, `useForcesField`, `forces:*` events, `--forces-*`
CSS vars, and the `compat-*` packages keep working behavior-identically through `0.x` and carry
`@deprecated` guidance, but are **excluded from the additive-only guarantee** and scheduled for
removal on a minor bump with a CHANGELOG entry.
7. **The experimental surface carries no guarantee.** Diagnostics/agent/render-mode exports that happen
to ship today are *shipped-but-unfrozen* until explicitly added to the stable table.
## How the freeze is enforced
- [`scripts/api-surface.ts`](../../scripts/api-surface.ts) imports every frozen value and type from its
owning package. Removing, renaming, or changing the kind of a frozen symbol is a **compile error**
there (a value-import of a type, or vice versa, also fails — so the *kind* is locked, not just the
name).
- [`scripts/check-api-surface.mjs`](../../scripts/check-api-surface.mjs) verifies the parts tsc can't
see: each frozen value resolves at runtime in the built dist, each frozen type is exported in source,
each element tag is registered (`customElements.define`), `data-body` is still in core's
`BODY_SELECTOR`, and the data file and the type gate name the same symbols.
- Both run via `pnpm check:api`, in CI right after `pnpm check:dist`.
Changing the frozen surface on purpose means editing
[`scripts/api-surface.data.mjs`](../../scripts/api-surface.data.mjs) **and**
[`scripts/api-surface.ts`](../../scripts/api-surface.ts) **and** this document together, with a
migration note and a `0.MINOR` bump.
## Status
The packages are **published to npm** under the `@Fundamental` scope (`@fundamental-engine/core` and the four
adapters). This freeze defines the `0.x` contract consumers build against; the publish steps and
order are in [`PUBLISHING.md`](../../PUBLISHING.md).
========================================================================
FILE: authoring-and-recipes.md
========================================================================
> **Status: canonical.**
> Authoring levels, the intent compiler, the recipe schema, examples, and precedence rules. Current as of the platform-runtime phase (Phase D). See [platform-architecture.md](platform-architecture.md) and [system-contracts.md](system-contracts.md).
# Fundamental Authoring and Recipes
## Related Documents
| Document | Role |
|---|---|
| [`README.md`](./README.md) | Documentation map |
| [`definition-document.md`](definition-document.md) | Concept |
| [`system-contracts.md`](system-contracts.md) | Recipe contract |
| [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md) | Interaction recipes |
| [`testing-and-conformance.md`](testing-and-conformance.md) | Recipe tests |
## Purpose
This document defines how authors use `Fundamental`. `Fundamental` is a platform-native relational field
runtime for the DOM: `Fundamental` computes renderer-agnostic field behavior, `@fundamental-engine/platform`
binds it to the DOM (measurement, state, feedback, relationships, visual bindings, overlays,
scheduling, linting), and the elements/React surfaces are how authors declare bodies into that shared
field context. Authors write the same `[data-body]` contract regardless of surface.
The system supports three authoring levels:
| Level | User | API |
|---|---|---|
| Level 1 | designer | intents and presets |
| Level 2 | developer | `data-body`, render modes, recipes |
| Level 3 | engine author | custom `field()` / `apply()` / conformance |
## 1. Authoring Surfaces
| Surface | Use |
|---|---|
| HTML attributes | direct declarative authoring |
| Web Components | encapsulated field participation |
| React props | framework integration |
| Core API | engine-level control |
| Field recipes | portable field programs |
| Composer | visual authoring and copy-code tool |
| Lab | executable spec and tuning |
| Inspector | debugging and reciprocity view |
### Authoring across surfaces (shipped)
The three authoring surfaces all compile to the same `[data-body]` contract, so a body authored in
native HTML, as a web component, or in React participates identically in the shared field context. See
the live walkthrough at `/docs/authoring`.
Native HTML — the platform runtime attaches to any element carrying `data-body`:
```html
Living headline
```
Web component — `` wraps content and registers each `[data-body]` with the field; the
platform runtime is the default participation path:
```html
Living headline
```
React — `` renders the same contract; props map onto the same `data-*` tokens:
```tsx
import { FieldField } from "@fundamental-engine/react";
function Headline() {
return (
Living headline
);
}
```
All three forms emit identical `[data-body]` markup, drive the same `--field-density` feedback
variable, and are measured, fed back, and related to one another through the same platform registries.
## 2. Core Attributes
| Attribute | Purpose |
|---|---|
| `data-body` | force tokens |
| `data-intent` | high-level author intent |
| `data-field-role` | semantic role |
| `data-field-state` | current field state |
| `data-render` | render layers |
| `data-feedback` | enable DOM write-back |
| `data-field-source` | source field for transport |
| `data-scope` | local/global participation |
| `data-field` | explicit field target |
| `data-strength` | force intensity |
| `data-range` | effective radius |
| `data-when` | activation condition |
## 3. Precedence Rules
```txt
explicit force token beats intent defaults
component props beat inherited field state
local cell settings beat global settings
reduced motion overrides visual travel
accessibility overrides animation
lint warnings do not block unless severity is error
source budgets override spawn intensity
debug render layers do not mutate physics
```
## 4. Intent Compiler
> **Implemented + runtime-wired.** `compileIntent` (`packages/core/src/recipes/intent.ts`) and the
> scanner (`core/scanner.ts`): an element with `data-intent` (and `data-intensity` / `data-risk`),
> and no explicit `data-body`, becomes a body from the compiled tokens. Explicit `data-*` wins over
> intent defaults (precedence §3).
Authors may describe intent instead of raw tokens.
Example:
```html
```
Compiled output:
```html
```
Intent presets:
| Intent | Concept | Runtime tokens | Render / feedback | Notes |
|---|---|---|---|---|
| `draw-focus` | draw attention to a focus | `attract` | feedback (`--field-density`) | range 280 |
| `clear-space` | open a keep-clear region | `repel` | — | range 240; `screen` is not a token |
| `show-motion` | flow along a heading | `stream` | render: `trails` | `trails` is a render mode, not a token |
| `show-relationship` | link related things | `memory` | render: `links` | `links` is a render mode; `threads` is not a token |
| `contain-energy` | damp + bound a region | `viscosity`, `wall` | — | `drag`→`viscosity`, `reflect`→`wall`; `screen` is not a token |
| `ignite` | energize / heat | `thermal`, `fieldflow` | render: `heatmap`, `particles` | `heatmap` is a render mode, not a token |
| `stabilize` | calm + hold together | `viscosity`, `cohesion` | — | `drag`→`viscosity`; `coherence` is a metric, not a token |
| `warn` | warning / instability | `repel`, `thermal` | feedback | `entropy` is a metric, not a token |
The **Runtime tokens** column holds real, passported engine forces only. Render modes, metrics, and
human concepts live in their own columns and are never executed as forces: `screen`, `drag`,
`reflect`, and `threads` are not tokens; `entropy` and `coherence` are metrics; `trails`, `links`,
and `heatmap` are render modes. The machine-readable source of truth is `compileIntent` in
`packages/core/src/recipes/intent.ts`.
The compiler must be inspectable. Authors should be able to see the generated force tokens and render layers.
## 5. FieldRecipe Schema
> **Implemented.** `FieldRecipe` (`packages/core/src/recipes/schema.ts`). A recipe is a portable,
> serializable, inspectable field program — the reusable unit that connects the natural-field model,
> engine primitives, DOM authoring, platform feedback, diagnostics, and the accessibility fallback.
> `validateRecipe` enforces every reference against the engine catalog. (`SceneRecipe` is a deprecated
> alias of `FieldRecipe`.)
```ts
type FieldRecipe = {
id: string // stable kebab-case id (e.g. "priority-well")
name: string
intent: string
tier?: RecipeTier // core | applied | systems | operational
naturalField?: "gravity" | "electromagnetic" | "strong" | "weak"
translation?: string // the field→interface translation phrase (concept lane)
primitives: string[] // the distinct body tokens, in first-seen order
concepts?: string[] // product-language lane — describes; never executed
metrics: string[] // signal names; --field-density is the one written today
diagnostics: string[] // render/diagnostic modes that reveal the behavior
conditions?: string[] // activation vocabulary — when the behavior applies
bodies: BodyRecipe[] // each body may carry `when` — the EXECUTABLE gate (data-when)
relationships?: RelationshipRecipe[] // compiled metadata only — used for the reduced-motion static display;
// NOT registered as live edges into RelationshipRegistry
render: RenderLayer[] // compiled to a render PLAN; executes when applyRecipe gets a field
accessibility: AccessibilityRecipe // required: reducedMotion + meaningWithoutMotion
status?: RecipeStatus // implementation status
budget?: Partial
expected?: ExpectedMetrics
notes?: string
}
```
The lanes stay separate: `primitives` (runtime tokens) execute, `concepts` / `translation` describe,
`metrics` measure, `diagnostics` explain, `conditions` activate. `validateRecipe` rejects a token that
appears in more than one lane.
`relationships` is **compiled metadata, not a live-graph registration**. `compileRecipe` preserves
the declared `from → to` pairs for one purpose only: populating the reduced-motion static display
(`applyRecipe` renders them as a `
` list when `prefers-reduced-motion` is set).
The `RelationshipRegistry`'s live graph is built solely by `RelationshipRegistry.discover()`,
which reads native DOM signals — `a[href^="#"]`, `label[for]`, ARIA references, and
`data-field-relation` / `data-field-target` attributes. A recipe author who wants an edge in the
live graph must author it in HTML with `data-field-relation`, not in the recipe schema.
`validateRecipe` returns a problem for any unknown force token, unknown render layer, unknown
diagnostic mode, unknown fundamental field, an unknown per-body `when` condition id (an unregistered
gate would silently never pass — rejected instead), declared `primitives` that drift from the body
tokens, or a missing accessibility equivalent. A recipe can't reference anything the engine doesn't
have, and no recipe is motion-only.
**Recipes execute their declarations (#370).** `compileRecipe` derives an executable render plan from
`render` — one underlay matter mode (`particles` → `dots`), the additive overlay reading stack, and
the heatmap toggle; layers with no executable surface are NAMED in `plan.unapplied`, never silently
dropped. `applyRecipe(root, recipe, { field })` drives a live field with the plan (a `FieldHandle` or
`` both satisfy the structural target) and releases the surfaces on `destroy()`;
`renderless` and reduced motion skip the drive. Per-body `when` compiles to `data-when` on the body —
the contour-charge recipe carries its own engagement gate this way. Without a `field` option, recipes
remain signals-only, exactly as before.
Example:
```json
{
"id": "guided-flow",
"name": "Guided Flow",
"intent": "move particles or attention along field lines, relationships, or paths",
"naturalField": "electromagnetic",
"primitives": ["magnetism", "fieldflow", "stream", "propagate"],
"bodies": [
{ "body": "magnetism", "strength": 1, "range": 420, "spin": 1 },
{ "body": "fieldflow", "strength": 0.8, "range": 0 },
{ "body": "stream", "strength": 0.6, "range": 320, "angle": 0 },
{ "body": "propagate", "strength": 0.5, "range": 300 }
],
"render": ["streamlines", "field-lines", "trails", "particles"],
"metrics": ["flow", "velocity", "density"],
"diagnostics": ["field-lines", "force-vectors", "prediction"],
"accessibility": {
"reducedMotion": "a static path contour with a numbered route and direction markers",
"meaningWithoutMotion": "the route is an ordered list of steps with direction labels"
},
"notes": "Magnetism bends, fieldflow carries — the recipe-level expression of field.flowTo()."
}
```
## 6. Recipe Types
| Recipe | Purpose |
|---|---|
| `FieldRecipe` | full field program (bodies, render, metrics, diagnostics, a11y) |
| `ForceRecipe` | reusable force configuration |
| `InteractionRecipe` | behavior tied to user input |
| `VisualizationPreset` | render stack |
| `MaterialPreset` | feel/material behavior |
| `StatePreset` | field state configuration |
## 7. Field Recipes
> **Implemented.** All **sixty-four** ship as validated `FieldRecipe`s in
> `packages/core/src/recipes/catalog.ts` (`FIELD_RECIPES`; `gallery.ts` re-exports it), grouped into four tiers (`RECIPE_TIERS`),
> live on [`/docs/gallery`](https://fundamental-engine.com/docs/gallery). They are the four-field translation
> model made practical — and classification/authoring artifacts only: they **compose existing
> primitives and add no new engine behavior**. Eight are the recommended first-release set
> (`FIRST_RELEASE_RECIPE_IDS`).
The four tiers (16 each): **Core — interface & accessibility** (1–16), **Applied — product, workflow &
collaboration** (17–32), **Systems — safety, provenance & governance** (33–48), **Operational —
multi-actor, adaptive & live** (49–64). The keys are a complexity ladder (`core` → `applied` →
`systems` → `operational`), not access tiers — nothing is gated.
### Recipe language vs engine vocabulary
Recipe **prose** is expressive; recipe **runtime fields** are strict. A recipe can say "completion
releases pressure and decays into memory," while its runtime fields stay
`primitives: [morph, memory, gravity]`. The conformance gate rejects any recipe whose primitives are
not real passported tokens, whose render layers / diagnostics are not real modes, or whose declared
primitives drift from the body tokens. Conceptual words map as follows (never invent a force token):
| Concept | Goes to | Real token / mode |
|---|---|---|
| `mass`, `risk`, `trust`, `confidence`, `priority`, `entropy` | `metrics` | — (free-form labels) |
| `potential`, `velocity vectors`, `relationship overlay`, `wavefront contours` | `diagnostics` | `potential`, `force-vectors`, `topology`, `contours` |
| `spring` | `primitives`/`bodies` | `tether` |
| `drag` / `friction` | `primitives`/`bodies` | `viscosity` |
| `reflect` | `primitives`/`bodies` | `wall` |
| `absorb` | `primitives`/`bodies` | `sink` |
| `threshold` | `primitives`/`bodies` | `gate` |
| `emitter` / `source` | `primitives`/`bodies` | `spawn` |
| `phase` / `transform` / `decay` | `primitives`/`bodies` | `morph` / `memory` |
| `orbit` | `primitives`/`bodies` | `magnetism` + `tether` (+ `gravity`) |
No new force tokens are added for recipes — only recipe records, conformance, mappings, and docs.
### Tier 1 — Core interface & accessibility (the first-release set is starred)
| # | Recipe | Natural field | Purpose |
|---|---|---|---|
| 1 | **Priority Well** ★ | gravity | make important elements feel naturally weighted without shouting |
| 2 | Focus Orbit | gravity (+ electromagnetic) | keep related options moving around the active item |
| 3 | Search Relevance Field | gravity | let results settle by relevance, confidence, and recency |
| 4 | **Signal Path** ★ | electromagnetic | show information flowing through citations, dependencies, routes |
| 5 | **Evidence Field** ★ | electromagnetic (+ strong) | show how sources support, weaken, or contradict a claim |
| 6 | Conflict Field | weak (+ electromagnetic) | make contradiction, uncertainty, and unstable state visible |
| 7 | **Relationship Bond** ★ | strong | keep related elements visually and behaviorally connected |
| 8 | Concept Cluster | strong | group related terms or sections without hard layout changes |
| 9 | **Coherence Field** ★ | strong | show whether a form, workflow, or dataset is becoming stable |
| 10 | **Reading Field** ★ | gravity (+ memory + relationships) | reveal attention, memory, and concept links in long content |
| 11 | **Memory Trace** ★ | weak | show where a user has been, paused, returned, or accumulated attention |
| 12 | Decay Notice | weak | let stale, temporary, or completed state fade gracefully |
| 13 | Phase Shift | weak | show a state transition (draft → published, pending → complete) |
| 14 | **Guided Flow** ★ | electromagnetic (+ transport) | move particles or attention along field lines, relationships, paths |
| 15 | Diagnostic Lens | diagnostic | reveal field lines, causality, prediction, topology, energy, overlays |
| 16 | Accessibility Equivalence | platform / semantic | convert motion-heavy behavior into static, semantic equivalents |
★ = the recommended first-release set: Priority Well, Signal Path, Relationship Bond, Reading Field,
Evidence Field, Coherence Field, Memory Trace, Guided Flow. Those eight explain the system quickly; the
full catalog gives the project its range.
### Tier 2 — Applied: product, workflow & collaboration (17–32)
Attention Weather (gravity), Navigation Current (EM), Citation Thread (EM), Form Stability Field
(strong), Command Intent Field (gravity), Selection Wake (weak), Availability Pressure (gravity),
Dependency Tension (strong), Staleness Drift (weak), Trust Gradient (EM), Completion Release (weak),
Group Magnet (strong), Error Pressure (weak), Handoff Stream (EM), Context Halo (gravity), Field
Tutorial (diagnostic).
### Tier 3 — Systems: safety, provenance & governance (33–48)
Semantic Gravity Map (gravity), Polarity Filter (EM), Source Constellation (strong), Drift Correction
(weak), Resonance Match (EM), Friction Gate (derived), Boundary Field (strong), Threshold Bloom (weak),
Latency Ripple (EM), Provenance Trail (strong), Review Pressure (gravity), Semantic Snap (strong),
Ambient Tutor (gravity), Relation Lens (strong), Priority Tide (gravity), Field Contract Preview
(platform).
### Tier 4 — Operational: multi-actor, adaptive & live (49–64)
Presence Field (EM), Consensus Well (gravity), Disagreement Charge (EM), Change Shockwave (EM),
Permission Boundary (strong), Risk Horizon (gravity), Intent Magnet (gravity), Flow Checkpoint
(strong), Version Gravity (gravity), Review Constellation (strong), Anomaly Bloom (weak), Scope Lens
(diagnostic), Calibration Field (gravity), Semantic Drag (derived), Recovery Path (weak), System Pulse
(EM).
Each recipe declares its natural field, primitives, bodies, render stack, metrics, diagnostics, and an
accessibility equivalent. See the executable cards (intent, primitives, diagnostics, reduced-motion
equivalent, copyable JSON) on the gallery page, and the per-recipe plain-language explanation from
`explainScene`.
## 8. Material Presets
Forces define behavior. Materials define feel.
| Material | Behavior |
|---|---|
| glass | lens + reflect + low drag |
| rubber | spring + damping |
| liquid | cohesion + pressure |
| plasma | fieldflow + thermal + trails |
| dust | diffuse + low mass |
| metal | magnetism + reflect |
| fabric | link + shear |
| paper | low motion + memory |
| stone | high mass + low response |
| smoke | diffuse + stream + entropy |
## 9. Field States
```ts
type FieldState =
| "idle"
| "focused"
| "searching"
| "navigating"
| "reading"
| "warning"
| "critical"
| "celebrating";
```
Example:
```json
{
"searching": {
"formation": "scatter",
"render": ["particles", "memory"],
"attention": "distributed"
},
"focused": {
"formation": "wells",
"render": ["particles", "density"],
"attention": "conserved"
}
}
```
## 10. Authoring Lint Rules
```txt
Warning: magnetism without charged or moving particles may appear inactive.
Warning: fieldflow has no field source nearby.
Warning: source force has no budget.
Warning: local cell particle count too high.
Warning: field lines enabled but no registered field() hooks exist.
Warning: data-body="gravity attract" may duplicate pull behavior.
Warning: reduced motion fallback missing.
```
## 11. Explain This Field
Every scene should be explainable.
Example:
```txt
This scene has one magnetic source defining loop geometry, one fieldflow transport layer carrying neutral matter along that geometry, and one thermal layer adding excitation. Particles follow the magnetic structure because of fieldflow, not magnetism. The active render stack is particles, field-lines, trails, and heatmap.
```
## 12. Field Diff
When parameters change, explain the difference.
Example:
```txt
Before: entropy 0.22, average speed 1.4, density center 0.61
After: entropy 0.37, average speed 2.1, density center 0.44
Change: stronger fieldflow increases velocity and lowers center density.
```
## 13. Implementation Priority
```txt
1. SceneRecipe schema
2. VisualizationPreset schema
3. ForceRecipe schema
4. Intent compiler
5. Authoring lint rules
6. Essential recipes
7. Material presets
8. Field state presets
9. Explain This Field output
10. Field Diff
```
========================================================================
FILE: definition-document.md
========================================================================
> **Status: canonical.**
> The canonical concept and operating model. Current as of the platform-runtime phase (Phase D). See [platform-architecture.md](platform-architecture.md) and [system-contracts.md](system-contracts.md).
# Fundamental Definition Document
## Related Documents
| Document | Role |
|---|---|
| [`README.md`](./README.md) | Documentation map and authority order |
| [`system-contracts.md`](system-contracts.md) | Canonical contracts |
| [`fundamental-field-behavior-table.md`](fundamental-field-behavior-table.md) | Field laws and `fieldflow` |
| [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md) | Agents beyond particles |
| [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Visualization and diagnostics |
| [`authoring-and-recipes.md`](authoring-and-recipes.md) | Authoring and recipes |
| [`testing-and-conformance.md`](testing-and-conformance.md) | Testing and conformance |
## 1. Definition
`Fundamental` is an inspectable field language for interfaces.
It turns DOM elements, custom components, data records, relationships, events, users, and layout regions into participants inside a shared field context. Those participants can emit fields, apply forces, guide matter, receive density, write state back to the DOM, trigger events, form relationships, and expose their behavior through visualization, metrics, and tests. The shared context spans bodies, agents, relationships, measurements, metrics, feedback, and every render surface — particles are one agent type within it, not the whole substrate.
`Fundamental` is a platform-native relational field runtime for the DOM. `Fundamental` computes renderer-agnostic field behavior; `@fundamental-engine/platform` binds it to the DOM (measurement, state, feedback, relationships, visual bindings, overlays, scheduling, linting); `@fundamental-engine/elements` and `@fundamental-engine/react` are authoring surfaces. Canvas is one render surface, not the whole system.
Core principle:
```txt
Elements bend the field.
The field bends them back.
```
`Fundamental` is not a particle background.
It is a relational behavior layer for the web.
## 2. Interface Physics
Interface physics is the use of spatial, temporal, and relational forces to express state, meaning, attention, and interaction in a user interface.
```txt
HTML = structure
CSS = presentation
JavaScript = behavior
Fundamental = relational behavior
```
`Fundamental` maps semantic state to physical behavior and physical behavior to visual styling.
```txt
Data becomes force.
Force becomes motion.
Motion becomes metric.
Metric becomes style.
Style becomes meaning.
```
## 3. Core Thesis
Traditional UI state is local.
```txt
hover / not hover
focused / not focused
selected / not selected
open / closed
```
`Fundamental` state is spatial, relational, and reciprocal.
```txt
near
approaching
cooling
saturating
remembered
related
unstable
coherent
```
The interface becomes a shared context layer. Components no longer behave only in isolation. Attention can transfer. Relationships can pull. Memory can accumulate. Data can become physical.
## 4. Foundational Loop
```txt
DOM body
-> emits field / applies force
-> moves or influences agents
-> accumulates density, heat, memory, entropy, attention
-> writes metrics back to DOM
-> changes element style, behavior, or state
-> reshapes the field
```
This loop is the core product.
The loop runs on the platform runtime, which is the default for ``. `@fundamental-engine/platform` owns DOM participation: it measures bodies, accumulates state, writes feedback, registers Shadow DOM, and resolves relationships. The legacy `core/field.ts` still simulates the field and draws the canvas render surface, while the platform owns DOM participation (measurement, feedback writes, Shadow-DOM registration, relationships); a legacy element write-back path in `core/field.ts` (CSS-variable and transform writes) is still being migrated behind the platform registries. `Fundamental` imports no DOM globals — a boundary guarded by `core/dom-boundary.test.ts`. You can opt back to pure-legacy behavior with `experimental-platform="off"` or `usePlatformRuntime(false)`.
The package set: `Fundamental`, `@fundamental-engine/platform`, `@fundamental-engine/elements`, `@fundamental-engine/react`, `@fundamental-engine/vanilla`, plus `compat-*` alias packages for the prior names. The project is native-platform-first, dependency-light, and framework-agnostic; `Fundamental` specifically carries zero runtime dependencies.
### Platform layer
`createFieldPlatform(root)` binds a root to the field runtime. The platform ships a `FrameScheduler` with explicit phases that order every frame:
```txt
discover -> read -> compute -> state -> write -> render
```
It also ships six registries, each owning one kind of DOM participation:
```txt
MeasurementRegistry measures body geometry in the read phase
StateRegistry accumulates and holds body state
FeedbackRegistry writes --field-* CSS vars and field:* events back to the DOM
RelationshipRegistry resolves links and constraints between bodies
VisualBindingRegistry binds field metrics to hidden visual elements
OverlayRegistry manages overlay surfaces over linked bodies
```
`FeedbackRegistry` auto-mirrors `--field-*` to the legacy `--forces-*` vars and `field:*` events to `forces:*`. `lintPlatform()` reports authoring mistakes: `relation-target-missing`, `state-unregistered`, `overlay-without-links`, `feedback-non-css-var`, `measurement-off-phase`, `visual-orphan`, and `visual-not-hidden`.
The Reading Field demo (`/docs/reading-field`) exercises all six scheduler phases across four registries (measurement, state, feedback, relationships) in a normal content page: sections are bodies, viewport proximity drives attention, accumulation becomes memory, the table of contents reflects state, citations form relationships, and reduced motion preserves meaning.
## 5. What Counts as a Body
A body is a registered interface object that can originate influence or participate in the field.
A body may be:
```txt
HTML element
custom element host
Shadow DOM component
React-rendered node
canvas-local virtual body
data record
layout region
event sink
mark or glyph
relationship node
```
A body must expose:
```txt
identity
geometry or geometry provider
force attributes or registered behavior
field target
write-back target
debug metadata
conformance path
```
Default:
```txt
body = element.getBoundingClientRect()
```
For Shadow DOM:
```txt
body = custom element host
```
Presentation can be private. Physics must be public, registered, measurable, and testable.
## 6. What Counts as an Agent
An agent is anything that can receive influence, hold state, change behavior, or affect another thing in the field.
```ts
type FieldAgent =
| ParticleAgent
| ElementAgent
| RelationshipAgent
| EventAgent
| UserAgent
| LayoutAgent
| DataAgent;
```
Particles are only one class of field participant.
Users, elements, relationships, events, layout, and data can also be agents.
See [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md).
## 7. Field vs Force
Every field-like behavior must separate structure from cause.
```txt
field(b, x, y) = invisible structure
apply(b, p, env) = actual effect
```
`field()` is used for:
```txt
field-line rendering
streamline tracing
heatmaps
Lab probes
fieldflow transport
debug overlays
topology analysis
```
`apply()` is used for:
```txt
velocity changes
acceleration
curvature
capture
binding
emission
decay
state change
heat
```
A field line is not always a particle path.
## 8. Electromagnetic Rule
The electromagnetic layer must keep three behaviors separate.
```txt
Electric fields push.
Magnetic fields bend.
Fieldflow carries.
```
Expanded:
```txt
Electric fields push charged matter along or against field lines.
Magnetic fields bend moving charged matter across field lines.
Fieldflow transports matter along field geometry.
```
Do not make `magnetism.apply()` follow magnetic field lines. Use `fieldflow` for solar prominences, auroras, plasma ribbons, and field-aligned transport.
See [`fundamental-field-behavior-table.md`](fundamental-field-behavior-table.md).
## 9. Field Grammar
A `Fundamental` scene is a sentence written in bodies, fields, forces, flows, metrics, renders, and feedback.
```txt
Body = where influence originates
Field = invisible structure
Force = how matter responds
Flow = how matter is transported
Metric = what the system measures
Render = how the invisible becomes visible
Feedback = how the field writes back to the DOM
```
Complete sentence:
```txt
Bodies emit fields.
Forces act on agents.
Flows transport matter along structure.
Metrics measure accumulation.
Renders reveal invisible state.
Feedback writes the field back into the interface.
```
## 10. Composition Laws
```txt
Fields superpose.
Forces accumulate.
Modifiers transform context.
Sources require budgets.
Metrics observe.
Renders do not mutate.
Feedback writes to DOM.
```
Execution order:
```txt
1. measure bodies
2. resolve conditions
3. build field context
4. apply modifiers
5. apply forces
6. apply transport
7. integrate particles
8. update scalar grids
9. sample metrics
10. write DOM feedback
11. render layers
```
## 11. Truth Modes
Every behavior should be classified by truth mode.
| Truth mode | Meaning | Examples |
|---|---|---|
| Physical truth | modeled after a real law | `gravity`, `charge`, `magnetism` |
| Designed truth | shaped for readable UI behavior | `attract`, `repel`, `tether` |
| Hybrid truth | a designed primitive operating over natural field geometry | `fieldflow` |
| Diagnostic truth | reveals internal state | force vectors, heatmaps, inspectors |
| Poetic truth | expressive composite from stable primitives | `blackhole`, `star`, `nebula` |
| Semantic truth | maps data/interface meaning into physics | attention, memory, relation fields |
This makes the project honest about which parts are physics, which are design, and which are expressive composites.
> **Implemented.** The `TruthMode` union + `TRUTH_MODES` catalog ship in `contracts/passport.ts`
> (Physical → `physical`); each force passport declares its mode.
## 12. Visualization Grammar
Visualization is how the system explains itself.
```txt
Particles show matter.
Field lines show structure.
Force vectors show cause.
Trails show history.
Heatmaps show accumulation.
Contours show terrain.
Energy views show cost.
Topology shows relationships.
DOM state shows reciprocity.
```
See [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md).
## 13. Attention as a Field
Selection is a decision. Attention is a field.
Attention should be continuous before it becomes selected. It may be local, shared, or conserved.
```txt
Σ attention_i = A_total
```
When one element gains emphasis, others can surrender emphasis. This creates a spatial attention system rather than isolated hover states.
## 14. Relationships as Agents
A relationship is not only an edge. It is a physical constraint with history.
Relationships can:
```txt
pull
resist
decay
strengthen
route attention
carry memory
become paths
pulse with activity
```
See [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md).
## 15. Authoring Levels
| Level | User | API |
|---|---|---|
| Level 1 | designer | intents and presets |
| Level 2 | developer | `data-body`, render modes, recipes |
| Level 3 | engine author | custom `field()` / `apply()` / conformance |
See [`authoring-and-recipes.md`](authoring-and-recipes.md).
## 16. World Model Diagram
```txt
DOM bodies
-> field()
Field structure
-> fieldflow / visualization
Agents
-> density / metrics
Scalar grids
-> sample
--field-* vars + field:* events
-> DOM bodies
```
The runtime drives this loop through the `FrameScheduler` phases (`discover -> read -> compute -> state -> write -> render`); the `FeedbackRegistry` performs the write step, with `--field-density` as the primary feedback var (`--d` and `--forces-density` are legacy/compat aliases).
## 17. Design Philosophy
```txt
1. State should be spatial when relationships matter.
2. Motion should be caused, not decorative.
3. Visualizations should reveal truth, not invent it.
4. Field lines are structure, not always paths.
5. Attention is continuous before it is selected.
6. Relationships are active agents.
7. Meaning should survive reduced motion.
8. Every source needs a budget.
9. Every force needs a passport.
10. Every visible behavior should be explainable.
```
## 18. Final Definition
`Fundamental` is an inspectable field language for interfaces.
It is built from:
```txt
bodies
agents
fields
forces
flows
metrics
renders
feedback
contracts
conformance
```
It is a way to make interface meaning physical, measurable, inspectable, and composable.
Final operating principle:
```txt
field() is structure.
apply() is cause.
fieldflow carries matter along structure.
agents respond to influence.
metrics measure accumulation.
renders reveal invisible state.
feedback returns the field to the DOM.
```
========================================================================
FILE: documentation-standards.md
========================================================================
> **Status: canonical.**
> This document governs how Fundamental is described across the docs, the site, and the Lab: the canonical
> architecture statement, the core doctrine, the document-status taxonomy, the naming policy, and the
> "verify against code" rule. It is the source of truth for *framing*; the deep topic references are
> [platform-architecture.md](platform-architecture.md),
> [natural-fields.md](natural-fields.md),
> [system-contracts.md](system-contracts.md), and
> [definition-document.md](definition-document.md).
# Fundamental documentation standards
This began as a documentation truth-pass brief; the work it described has shipped, so it is recorded
here as the governing standard rather than a to-do. When docs, pages, force/Lab labels, or examples
are written or revised, they follow the framing below.
## Canonical architecture statement
```
Fundamental is a platform-native relational field runtime for the DOM.
Fundamental computes renderer-agnostic field behavior.
@fundamental-engine/platform binds field behavior to the DOM through measurement, state, feedback,
relationships, visual bindings, overlays, linting, and scheduling.
@fundamental-engine/elements exposes native HTML and web-component authoring.
@fundamental-engine/react adapts the same contracts for React.
Canvas is one render surface, not the whole system.
```
Fundamental creates **one shared field context** across DOM bodies, agents, relationships, measurements,
metrics, feedback, particles, and render surfaces. Canvas, SVG overlays, and DOM feedback are each a
render surface; the platform layer is the DOM participation layer; the core engine stays
renderer-agnostic.
Do not describe Fundamental as only "one canvas", "one particle field", "a particle background", or a
"DOM ⇄ canvas binding". Those phrases are fine when specifically discussing the canvas render surface,
but they must not define the whole product. The binding is **DOM ⇄ field runtime**.
## Core doctrine
```
field() is structure. apply() is cause. fieldflow carries matter along structure.
agents respond to influence. metrics measure accumulation. renders reveal invisible state.
feedback returns the field to the DOM.
```
Preserve: **Electric fields push. Magnetic fields bend. Fieldflow carries.** Do not make
`magnetism.apply()` follow magnetic field lines — field-aligned transport belongs to `fieldflow`.
## Natural Field Translation System
Fundamental does not copy physics into the interface; it **translates** the four fundamental fields into
interface behavior: gravity → priority, electromagnetic → polarity/signal, strong → binding, weak →
transformation. **Natural fields are not tokens; tokens are translations.** Canonical forces
(`attract`, `repel`, …) are designed verbs, not natural translations (`attract` ≠ gravity, `repel` ≠
charge). The classification is data — `FORCE_KIND` / `FORCE_FIELD` / `NATURAL_FIELDS` in
`packages/core/src/config/manual.ts` — and the full model is in
[natural-fields.md](natural-fields.md). It changes no particle/engine behavior; it
only organizes how each token is explained.
## Current implementation truth
These are shipped and may be described in the present tense (verify specifics against code before
asserting anything new):
```
Fundamental · @fundamental-engine/platform · @fundamental-engine/elements · @fundamental-engine/react · @fundamental-engine/vanilla
FrameScheduler (discover → read → compute → state → write → render)
MeasurementRegistry · StateRegistry · FeedbackRegistry · RelationshipRegistry ·
VisualBindingRegistry · OverlayRegistry · lintPlatform()
the platform runtime is the default for (Phase D); core is guarded renderer-agnostic
all render modes (incl. topology, inspector, causality, prediction)
field.flowTo() / clearFlow() controlled flow-field API
Reading Field demo · Accessibility Preview · Narrative Reveal · PNG/SVG diagnostic export
native HTML / web component / React authoring examples
the Natural Field Translation System (four-field classification + /docs/natural-fields)
```
`Fundamental` imports **zero DOM** — the engine routes the environment through an injected
`FieldHost`; `browserHost()` lives in `@fundamental-engine/platform`, and `createField` requires a host (the
framework entry points wire it). `core/dom-boundary.test.ts` enforces this with an empty allowlist.
## Document-status taxonomy
Every markdown doc carries a status banner, and the folders mirror it:
- **canonical** (`docs/canonical/`) — current source of truth for product, architecture, contracts, framing.
- **as-built reference** (`docs/engine-reference/`) — accurate engine record, narrower than the whole product.
- **legacy / superseded** (`docs/planning-archive/`) — design history; not authoritative.
- **planning / roadmap** (`docs/planning-archive/`) — forward-looking; must not describe planned work as shipped.
## Naming policy
New code and docs use `--field-*` CSS variables and `field:*` events. The compact `--d` and the
`--forces-*` / `forces:*` families remain as compatibility aliases (the FeedbackRegistry auto-mirrors
`--field-*` → `--forces-*` and `field:*` → `forces:*`). Prefer `--field-density` in examples; mention
`--d` / `--forces-*` only as aliases. Use `Fundamental` for the project, packages, and docs.
## Status rule
Do not label anything "shipped" unless the code verifies it. Check the force registry, the manual
config, the render-mode catalog, tests, package exports, the Lab labels, and the docs navigation
before changing a status. Labels: shipped · experimental · planned · conceptual · legacy.
## The frame
```
The old story: Fundamental is a particle field behind the DOM.
The new story: Fundamental is a platform-native relational field runtime for the DOM.
Natural fields: Four fields. Many expressions. One DOM runtime.
```
========================================================================
FILE: fundamental-field-behavior-table.md
========================================================================
> **Status: canonical.**
> Field/force laws, the electromagnetic split, fieldflow, and truth modes. Current as of the platform-runtime phase (Phase D). See [platform-architecture.md](platform-architecture.md) and [system-contracts.md](system-contracts.md).
# Fundamental Field Behavior Table for Fundamental
## Related Documents
| Document | Role |
|---|---|
| [`README.md`](./README.md) | Documentation map |
| [`definition-document.md`](definition-document.md) | Concept |
| [`system-contracts.md`](system-contracts.md) | Contracts |
| [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Field rendering and diagnostics |
| [`testing-and-conformance.md`](testing-and-conformance.md) | Tests |
## Core Distinction
Every field-like force must separate:
```txt
field(b, x, y)
```
from:
```txt
apply(b, p, env)
```
`field()` returns invisible structure.
`apply()` causes change.
A field line is not always a particle path.
## Field Grammar Reference
```txt
Body = where influence originates
Field = invisible structure
Force = how matter responds
Flow = how matter is transported
Metric = what the system measures
Render = how the invisible becomes visible
Feedback = how the field writes back to the DOM
```
## Truth Modes
| Truth mode | Meaning | Examples |
|---|---|---|
| Physical truth | modeled after a recognizable physical law | `gravity`, `charge`, `magnetism` |
| Designed truth | shaped for stable UI behavior | `attract`, `repel`, `spring` |
| Hybrid truth | a designed primitive operating over natural geometry | `fieldflow` |
| Diagnostic truth | reveals internal state | force vectors, heatmaps |
| Poetic truth | expressive composite | `blackhole`, `nebula` |
| Semantic truth | maps meaning into physics | attention, memory |
> **Implemented.** These are the `TruthMode` union + `TRUTH_MODES` catalog in
> `packages/core/src/contracts/passport.ts`. Forces classify as `physical` / `designed` / `hybrid`
> (fieldflow); `diagnostic` / `poetic` / `semantic` classify visualizations, composite presets, and
> the meaning→metric mappings respectively.
> **Diagnostic truth is read-only.** All diagnostic render modes — including `causality` and
> `prediction`, both shipped and live at `/docs/diagnostics` — only *visualize* field state. They
> read the field and draw on a render surface; they never feed back into `apply()` or mutate physics.
> Visualization and physics stay separate: a diagnostic overlay reveals internal structure without
> changing how matter responds.
## Fundamental Table
| Field / interaction | Field structure | `field(b, x, y)` should return | `apply(b, p, env)` should do | Particle relationship to field lines | Render expectation | Correct Fundamental role |
|---|---|---|---|---|---|---|
| **Gravity** | radial monopole well around mass-energy | gravitational vector field `g(x,y)` pointing toward source mass | softened gravitational acceleration: `g = -GM r̂ / (r² + ε²)` and `F = m g` | particles generally accelerate along the field; sideways velocity can create orbits | radial wells, falling paths, orbital arcs, accretion | `gravity`, natural primitive |
| **Electric / Charge** | signed radial monopole field | electric vector `E(x,y)` outward from positive, inward toward negative | Coulomb force: `F = qE` | positive particles move along `E`; negative particles move opposite; neutral particles ignore it | radial lines, attraction/repulsion, demixing | `charge`, natural primitive |
| **Magnetic** | loop, dipole, or pole-pair field | magnetic vector `B(x,y)`, derived from pole position, geometry, orientation, strength, and feedback | Lorentz magnetic force: `F = q(v × B)` | particles do not naturally stream along magnetic field lines; force is perpendicular to velocity and field | field loops plus curved charged tracks | `magnetism`, natural primitive |
| **Electromagnetic combined** | coupled electric and magnetic field | compound `{ E(x,y), B(x,y) }` | full Lorentz force: `F = q(E + v × B)` | electric pushes along/opposite `E`; magnetic bends across `B` | spirals, arcs, plasma motion when paired with `fieldflow` | future composite |
| **Field-aligned transport** | reads existing net field geometry | reads `env.fieldAt(x,y)` or `netField(...)` | steers velocity onto the field line and accelerates along it | particles intentionally follow field lines | solar prominences, auroras, routed plasma | `fieldflow`, label `Flux` |
| **Strong / Binding** | short-range confinement or string tension | local binding field or pair potential | binds, links, fuses, resists separation | not line-following | clusters, bonds, nuclei-like structures | `cohesion`, `link`, `fuse` |
| **Weak / Transformation** | instability or probability field | scalar instability or none | decay, split, transmute, emit secondaries | not path-based | state mutation, splitting | `decay`, `fission` |
## Electromagnetic Behavior Split
| Behavior | Token | Owns field geometry? | Motion law | Does work? | Particle path relative to field lines |
|---|---|---:|---|---:|---|
| Electric charge | `charge` | yes | `F = qE` | yes | along `E` for positive, opposite for negative |
| Magnetic Lorentz force | `magnetism` | yes | `F = q(v × B)` | no in ideal mode | across/around field lines |
| Field-aligned transport | `fieldflow` | no, reads net field | steer + accelerate along `normalize(fieldAt(x,y))` | yes | along existing field lines |
## Required Mental Model
```txt
Electric fields push.
Magnetic fields bend.
Fieldflow carries.
```
Do not make `magnetism.apply()` follow magnetic field lines.
That behavior belongs to `fieldflow`.
## Gravity
> **Implemented.** `gravity.field()` now ships (`packages/core/src/forces/natural.ts`,
> `bodyGravityField`): a radial inward field so gravity owns `field()`, renders as field lines, and
> can be followed by `fieldflow`. `gravity.apply()` is unchanged — adding the field only makes the
> structure visible/followable (a field line is not always a particle path). The passport's
> `ownsField` is now `true`.
### Field
```txt
r = (x - cx, y - cy)
d = max(length(r), ε)
r̂ = r / d
g = -GM * r̂ / (d² + ε²)
```
### Apply
```txt
F = m * g
a = F / m
v += a * dt
```
Simplifies to:
```txt
a = g
```
## Charge
### Field
```txt
r = (x - cx, y - cy)
d = max(length(r), ε)
r̂ = r / d
E = kQ * r̂ / (d² + ε²)
```
Bounded UI-safe mode:
```txt
falloff = max(0, 1 - d / range)^n
E = sign * strength * r̂ * falloff
```
### Apply
```txt
F = qE
a = F / m
v += a * dt
```
## Magnetism
### Field
For a simple visual loop:
```txt
r = (x - cx, y - cy)
d = max(length(r), ε)
r̂ = r / d
tangent = (-r̂.y, r̂.x)
falloff = max(0, 1 - d / range)^n
B = tangent * strength * spin * falloff
```
For production, prefer pole-derived field geometry:
```txt
B = bodyDipole(body, x, y)
```
or:
```txt
B = polePair(body.poles, x, y)
```
The field should respond to:
```txt
pole position
element geometry
orientation
strength
range
spin/polarity
live charge feedback
```
### Apply
```txt
F = q(v × B)
```
For 2D canvas motion with out-of-plane magnetic strength:
```txt
Fx = -q * Bz * vy
Fy = q * Bz * vx
a = F / m
v += a * dt
```
### Required Tests
```txt
neutral particles ignore magnetism
still charged particles receive no magnetic force
moving charged particles curve
force is perpendicular to velocity
speed is preserved in ideal mode
charge reversal flips curvature
spin reversal flips curvature
no effect beyond range
```
## Fieldflow / Flux
`fieldflow` is field-aligned transport.
It does not define a fundamental field. It reads the net field created by other bodies.
### Apply
```txt
F_net = env.fieldAt(p.x, p.y)
h = normalize(F_net)
gain = strength * max(0, 1 - d / range)
v = steerToward(v, h, steer * gain)
v += h * accel * gain
```
Recommended tunable version:
```txt
h = normalize(env.fieldAt(p.x, p.y)) * direction
targetVelocity = h * flowSpeed
v += (targetVelocity - v) * flowSteer * gain
v += h * flowAccel * gain
```
### Recommended Attributes
```html
```
### Behavior
```txt
acts on neutral matter
does work
follows net field superposition
routes matter between linked poles
range 0 can mean global field-following formation
creates solar prominence / aurora / plasma behavior
```
## Implementation Matrix
| Token | Owns `field()`? | Uses `env.fieldAt()`? | Moves particles? | Moves along field lines? | Does work? | Main law / behavior |
|---|---:|---:|---:|---:|---:|---|
| `gravity` | yes | no | yes | mostly | yes | `g = -GM r̂ / (r² + ε²)` |
| `charge` | yes | no | yes | sign-dependent | yes | `F = qE` |
| `magnetism` | yes | no | yes | no | no ideal | `F = q(v × B)` |
| `fieldflow` | no | yes | yes | yes | yes | steer + accelerate along `fieldAt` |
| `cohesion` | optional/local | no | yes | n/a | yes | surface tension |
| `pressure` | optional/scalar | no | yes | n/a | yes | density relaxation |
| `link` | optional/local | no | yes | n/a | constraint | distance constraint |
| `fuse` | local | no | state/count | n/a | releases heat | conservation |
| `fission` | local | no | state/count | n/a | releases heat | budgeted split |
| `decay` | optional scalar | no | state/count | n/a | not motion-first | timed transformation |
| `spawn` | no | no | creates particles | n/a | source | budgeted source |
## Force Passport Template
Every force should include:
```txt
Token:
Category:
Truth mode:
Owns field():
Uses env.fieldAt():
Moves particles:
Does work:
Conserves speed:
Requires charge:
Requires velocity:
Affects neutral matter:
Can be visualized as field lines:
Can be visualized as force vectors:
Best render modes:
Conformance tests:
Common composites:
Design use:
Physics note:
```
## Future Flux-Linkage Layer
Flux-linkage is a future pairwise relationship metric.
```txt
Φ_AB = amount of field from body A that connects to or passes through body B
```
Do not implement flux-linkage before baseline `fieldflow`, field-line, and probe systems are stable.
========================================================================
FILE: interaction-and-relationship-model.md
========================================================================
> **Status: canonical.**
> Agents beyond particles: users, elements, relationships, events, layout, data, attention, and the interaction grammar. Current as of the platform-runtime phase (Phase D). See [platform-architecture.md](platform-architecture.md) and [system-contracts.md](system-contracts.md).
# Fundamental Interaction and Relationship Model
## Related Documents
| Document | Role |
|---|---|
| [`README.md`](./README.md) | Documentation map |
| [`definition-document.md`](definition-document.md) | Concept |
| [`system-contracts.md`](system-contracts.md) | Agent contracts |
| [`authoring-and-recipes.md`](authoring-and-recipes.md) | Recipes |
| [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Relationship visualization |
## Purpose
This document expands `Fundamental` beyond particles.
`Fundamental` is a platform-native relational field runtime for the DOM. `Fundamental` computes renderer-agnostic field behavior; `@fundamental-engine/platform` binds it to the DOM through measurement, state, feedback, relationships, visual bindings, overlays, scheduling, and linting. Particles are one agent type, not the whole substrate; canvas is one render surface, not the whole system.
Particles are only one class of field participant. Users, elements, relationships, events, layouts, and data can also be agents.
Core expansion:
```txt
Bodies emit influence.
Agents respond to influence.
Metrics record the result.
The interface adapts.
```
## 1. Core Definition
An agent is anything that can receive influence, hold state, change behavior, or affect another thing in the field.
```txt
Agent = influence receiver + state holder + possible responder
```
A body is where influence originates.
A body can also be an agent.
## 2. Expanded Agent Model
```ts
type FieldAgent =
| ParticleAgent
| ElementAgent
| RelationshipAgent
| EventAgent
| UserAgent
| LayoutAgent
| DataAgent;
```
| Agent type | Represents | Responds through |
|---|---|---|
| ParticleAgent | visual matter | velocity, heat, phase |
| ElementAgent | DOM element | CSS variables, transforms, events |
| RelationshipAgent | connection | tension, thickness, pulse, memory |
| EventAgent | behavior trigger | threshold event |
| UserAgent | pointer/focus/selection | wake, attention, memory |
| LayoutAgent | region/panel | spacing, grouping, ordering |
| DataAgent | semantic record | strength, category, state |
The `FieldAgent` union above is the conceptual model. At runtime the discriminant is the lowercase
`FieldAgentKind` string union (`'particle' | 'element' | 'relationship' | 'event' | 'user' | 'layout'
| 'data'`) in `packages/core/src/agents/`; the per-kind shapes (e.g. `RelationshipAgent`, `UserAgent`)
are the agent state those kinds carry.
## 3. Shared Context Layer
Traditional UI state is local.
`Fundamental` state is spatial, relational, and reciprocal.
Recommended positioning:
```txt
Fundamental treats the interface as a shared field context — one shared context across bodies, agents, relationships, measurements, metrics, feedback, and render surfaces — not a collection of isolated components.
```
## 4. Interaction as Continuity
Most UI interaction is binary.
`Fundamental` can represent:
```txt
near
approaching
cooling
saturating
remembered
related
unstable
coherent
```
Recommended phrase:
```txt
Fundamental gives interfaces a memory of approach, not just a record of clicks.
```
## 5. Attention as a Field
Attention is continuous before it is selected.
```txt
attention_i = density_i * engagement_i * relevance_i * visibility_i
```
Conserved attention mode:
```txt
Σ attention_i = A_total
```
Suggested DOM variables:
```css
--field-attention
--field-attention-share
--field-attention-rank
--field-related-attention
```
Key phrase:
```txt
Selection is a decision.
Attention is a field.
```
## 6. Attention vs Focus vs Selection
| State | Meaning | Field behavior |
|---|---|---|
| Attention | user is near or interested | density, glow, weak pull |
| Focus | user is actively navigating | accessible attention well |
| Selection | user has chosen | capture, lock, orbit |
| Memory | user has been here before | path trace, higher future gain |
| Relation | connected to what matters | secondary attention/thread |
| Confidence | system believes relevance | coherence |
| Priority | deserves emphasis | strength/rank |
## 7. RelationshipAgent
A relationship is not only an edge. It is a physical constraint with history.
```ts
type RelationshipAgent = {
id: string
from: BodyId
to: BodyId
type: string
strength: number
tension: number
memory: number
active: boolean
}
```
A relationship can:
```txt
pull
resist
decay
strengthen
route attention
carry memory
become a path
pulse with activity
```
Relationship types:
| Relationship | Physical behavior |
|---|---|
| parent/child | gravitational hierarchy |
| related content | elastic thread |
| dependency | directional tension |
| conflict | repulsion |
| sequence | stream/current |
| similarity | cohesion |
| history | memory path |
| active relation | pulsing field link |
### Platform binding
On the platform runtime (Phase D), the `RelationshipAgent` model is backed by the **`RelationshipRegistry`**. The registry reads native DOM signals — `href`, ARIA references (`aria-controls`, `aria-describedby`, `aria-labelledby`), and `data-field-relation` — and resolves them into a typed relationship graph between registered bodies. Relationships become edges the field can pull, resist, decay, strengthen, route attention along, and carry memory through, exactly as described above. The `relation-target-missing` lint rule flags edges whose target body is not registered, so the authored graph stays consistent with what the runtime sees.
## 8. UserAgent
```ts
type UserAgent = {
pointer?: Vec2
focus?: Element
selection?: Element[]
velocity?: Vec2
memoryTrail?: ScalarGrid
intent?: "browse" | "search" | "read" | "drag" | "select"
}
```
User signals:
| Signal | Field behavior |
|---|---|
| pointer | moving attractor / wake |
| pointer velocity | stream direction |
| hover | local attention |
| focus | accessible attention |
| selection | capture |
| drag | constraint + wake |
| scroll | current |
| edit | heat deposit |
| correction | memory overwrite |
| return visit | memory amplification |
## 9. Interaction Grammar
```txt
hover = local attention
focus = accessible attention
press = compression
drag = constraint + wake
scroll = current
select = capture
release = emission
search = scatter then converge
navigate = stream
return = memory
```
## 10. Pointer, Focus, and Accessibility
The system must not be pointer-only.
Focus is a first-class field source.
| Interaction | Field behavior |
|---|---|
| `hover` | local activation |
| `focus` | accessible attention well |
| `focus-visible` | visible field activation |
| `active` | compression/capture |
| `selected` | stable orbit/lock |
| `visited` | memory trace |
| `disabled` | screen/low response |
| `invalid` | entropy/warning heat |
| `loading` | stream/vortex/fieldflow |
| `success` | release |
| `error` | repel/thermal/pulse |
Reduced-motion fallback:
```txt
focus creates state, not travel
```
## 11. User Movement as Memory
```txt
M(x, y, t + dt) = M(x, y, t) * decay + userInputDeposit
```
Use cases:
```txt
cursor wake
reading trail
visited content paths
search refinement path
workflow routes
desire paths
```
Suggested outputs:
```css
--field-memory
--field-path-use
--field-user-wake
```
## 12. Events as Field Thresholds
Events:
```txt
forces:entered
forces:exited
forces:lit
forces:dim
forces:saturated
forces:captured
forces:released
forces:attention-shifted
forces:relationship-strengthened
forces:memory-threshold
forces:entropy-warning
```
Rule:
```txt
Field events should be thresholded, debounced, and inspectable.
```
## 13. ElementAgent Responders
Possible outputs:
```css
--field-density
--field-attention
--field-pressure
--field-coherence
--field-entropy
--field-memory
--field-pull-x
--field-pull-y
--field-layout-shift
```
Example:
```css
.card {
transform:
translate(
calc(var(--field-pull-x, 0) * 12px),
calc(var(--field-pull-y, 0) * 12px)
)
scale(calc(1 + var(--field-attention, 0) * 0.04));
}
```
## 14. LayoutAgent
Layout can respond to field conditions.
```txt
spacing opens under pressure
related items cluster
unrelated items drift apart
active region gains z-depth
search results settle into relevance wells
dense sections create screen zones
overloaded regions dampen motion
```
Use sparingly. Prefer reversible, inspectable behavior.
## 15. DataAgent
Data records can become field agents.
| Data property | Field mapping |
|---|---|
| importance | strength |
| category | force token / color |
| recency | heat |
| confidence | coherence |
| uncertainty | entropy |
| relation count | range |
| status | phase |
| user interest | memory |
| priority | attention share |
> **Implemented.** `SEMANTIC_LAYERS` + `semanticToMetrics()` in `packages/core/src/semantic/layers.ts`
> map each meaning to its field metric.
## 16. Relationship Heatmaps
| Heatmap | Meaning |
|---|---|
| attention | where the user is focused |
| relation | linked content clusters |
| path | repeated movement |
| conflict | opposing forces |
| workload | interface density |
| comprehension | repeated docs/examples attention |
| conversion | CTA attention concentration |
## 17. Interface Weather
| Weather | Meaning | UI response |
|---|---|---|
| Calm | low entropy, low velocity | subtle particles |
| Focused | high attention, low entropy | clear emphasis |
| Turbulent | high entropy, high velocity | reduce motion/dampen |
| Dense | high concentration | open spacing/screen text |
| Charged | high heat/activity | highlight active state |
| Remembered | high memory | show paths/history |
| Critical | budget/energy threshold | reduce sources/warn |
## 18. Collaborative Fields
| User signal | Field behavior |
|---|---|
| cursor | moving attractor/wake |
| selection | attention well |
| edit | heat deposit |
| comment | anchored source |
| presence | aura |
| conflict | repulsion/entropy |
| agreement | coherence |
| handoff | stream |
## 19. Forms and Validation
| Form state | Field behavior |
|---|---|
| empty | low density |
| focused | attract |
| valid | coherence/glow |
| invalid | entropy/repel/heat |
| required | attention well |
| optional | lower strength |
| submitting | stream/fieldflow |
| success | release |
| error | thermal pulse |
## 20. Navigation as Current
| Navigation state | Field behavior |
|---|---|
| current page | attractor well |
| previous page | memory trail |
| next likely page | stream direction |
| related page | thread |
| breadcrumb | stable path |
| disabled route | screen |
| external link | emitter |
## 21. Search and Filtering
| Search signal | Field mapping |
|---|---|
| relevance | strength |
| exact match | attract |
| semantic match | cohesion |
| excluded result | repel |
| recent result | heat |
| clicked result | memory |
| category | formation |
| uncertainty | entropy |
Search can transition:
```txt
formation = scatter -> wells
```
## 22. Reading and Editorial Experiences
Reading is the flagship normal-content use case for this model: an ordinary article, not a particle demo. The **Reading Field** demo (shipped, at `/docs/reading-field`) is a plain content page that exercises all six phases of the `FrameScheduler` across four platform registries (it does not use the visual-binding or overlay registries). Sections become bodies (`MeasurementRegistry`); viewport proximity becomes attention (`StateRegistry`); dwell accumulates into memory; the table of contents reflects the field state (`FeedbackRegistry`); and citations resolve into typed relationships (`RelationshipRegistry`) via the native-signal binding described in section 7. Under reduced motion the meaning is preserved — emphasis and state survive even when travel does not.
| Reading signal | Field behavior |
|---|---|
| viewport center | attention well |
| read paragraphs | memory trail |
| footnotes | threads |
| important terms | attractors |
| citations | link tension |
| unresolved concept | entropy |
| summary | coherence sink |
## 23. State Machines as Physical Scenes
Example:
```ts
type ButtonFieldState =
| "idle"
| "hovered"
| "focused"
| "pressed"
| "loading"
| "success"
| "error"
```
| State | Field |
|---|---|
| idle | ambient |
| hovered | attract |
| focused | attract + feedback |
| pressed | absorb |
| loading | stream/vortex |
| success | release |
| error | repel + thermal |
> **Implemented.** `FieldState` + `FIELD_STATES` in `packages/core/src/semantic/states.ts`.
## 24. Interaction Materials
Forces define behavior. Materials define feel.
| Material | Behavior |
|---|---|
| glass | lens + reflect + low drag |
| rubber | spring + damping |
| liquid | cohesion + pressure |
| plasma | fieldflow + thermal + trails |
| dust | diffuse + low mass |
| metal | magnetism + reflect |
| fabric | link + shear |
| paper | low motion + memory |
| stone | high mass + low response |
| smoke | diffuse + stream + entropy |
> **Implemented.** `INTERACTION_MATERIALS` + `materialBody()` in
> `packages/core/src/semantic/materials.ts`, composed from real force tokens.
## 25. Field Affordances
| Affordance | Field expression |
|---|---|
| clickable | weak attractor |
| draggable | spring/link response |
| related | thread or memory path |
| dangerous | heat/repel |
| completed | coherence |
| loading | stream |
| disabled | screened |
| selected | captured |
| recommended | attention well |
| historical | memory glow |
## 26. AI Interface Use Cases
| AI state | Field behavior |
|---|---|
| candidate answer | attractor |
| uncertainty | entropy |
| source support | relationship tension |
| contradiction | repulsion |
| user correction | memory overwrite |
| synthesis | cohesion |
| hallucination risk | instability/heat |
| verified claim | coherence |
| active generation | stream/fieldflow |
## 27. Explainable Interaction
The system should answer:
```txt
Why is this emphasized?
Why did this move?
Why are these connected?
Why did the page calm down?
Why did this warning appear?
```
Principle:
```txt
Every visible behavior should be traceable to a field cause.
```
## 28. Implementation Priority
Several items below have shipped on the platform runtime (Phase D). The `RelationshipAgent` model is backed by the `RelationshipRegistry`; the reading/editorial use case ships as the Reading Field demo (section 22). Remaining items stay as authoring priorities and experiments.
```txt
1. Formal FieldAgent model
2. ElementAgent responder variables beyond density
3. RelationshipAgent model — shipped (RelationshipRegistry)
4. Attention budget
5. UserAgent model for pointer/focus/selection
6. Thresholded field events
7. Relationship heatmaps
8. Navigation/search recipes
9. Form state recipes
10. Reading/editorial recipes — shipped (Reading Field, /docs/reading-field)
11. Collaborative presence experiments
12. AI state visualization recipes
```
========================================================================
FILE: invisible-fields.md
========================================================================
> **Status: canonical.**
> The invisible-fields pattern: running the field with **no drawn surface at all**, so its
> measurements come back as typography, ink, and anchor. Defines the third placement (after
> underlay and overlay), the two-field page architecture, the live feedback channels, the
> engagement contracts (`data-hot`, `data-active`), declared relationships
> (`data-field-relation`), and the data-provenance honesty pattern. Everything here is shipped
> and verified against code; the reference implementation is the example family at
> `apps/site/src/pages/evidence*` (twelve pages, e2e-tested in `apps/site/e2e/`).
# Fundamental Invisible Fields
## Related Documents
| Document | Role |
|---|---|
| [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Surfaces & Placement (underlay / overlay) — this doc adds the third |
| [`system-contracts.md`](system-contracts.md) | The hard contracts (bodies, feedback, relationships) |
| [`platform-architecture.md`](platform-architecture.md) | The platform runtime, registries, scheduler |
| [`agent-consumption-model.md`](agent-consumption-model.md) | How consumers read one influence differently |
| [`definition-document.md`](definition-document.md) | The operating model ("substrate, not wallpaper") |
## 1. What an invisible field is
The definition document says the field is a **substrate, not wallpaper**. An invisible field is
that claim taken literally: the engine runs, bodies participate, matter flows — and **nothing is
drawn**. The only output is the feedback the platform writes back to the DOM (CSS variables,
thresholded events), and the only render surface is the page's own type and ink, styled by CSS
that reads those variables.
This is the third **placement** in the Surfaces & Placement taxonomy:
| Surface | Placement | Drawn on | Status |
|---|---|---|---|
| Underlay | behind content | the `` canvas | shipped |
| Overlay | in front of content | a second light-DOM canvas | shipped |
| **Typographic (invisible)** | **in the content itself** | **nothing — feedback variables styled by author CSS** | **shipped** |
Two shipped mechanisms produce it:
- **Engine, draw-skipped** — `FieldHandle.setVisible(false)` keeps the full simulation and its
feedback live while skipping all draw work (`packages/core/src/core/field.ts`). The
`` element wires this automatically from an IntersectionObserver, so a page that
hides the element with CSS (`display: none`) gets a signals-only engine for free.
- **Recipe, render-less** — `applyRecipe(root, { ...recipe, render: [] }, { bodies })` runs the
platform's metric pipeline over explicit bodies with no engine canvas at all
(`packages/platform/src/apply-recipe.ts`).
Formalizing the first mechanism as a named engine mode is filed as
[#297](https://github.com/zachshallbetter/fundamental-engine/issues/297).
## 2. The two-field page architecture
Every invisible-fields example page runs **both** mechanisms at once, and they are not redundant
— they write different lanes:
```txt
the PAGE ENGINE (hidden , setVisible(false) via IO)
real particle simulation over every [data-body] on the page
writes: --d (live local density), --load/--mass (sink fill), --lit,
capture/release events, field:* thresholded events
honors: data-hot engagement (hover/focus -> the body activates,
the spine bends to it, density gathers -> --d rises toward 1)
the SCOPED RECIPE PIPELINE (applyRecipe, render: [])
geometric metric computation over the page's explicit record bodies
writes: --field- for every metric the recipe declares
(the examples extend the evidence-field recipe with "attention")
inputs per frame: viewport-center proximity, visibility ratio,
engaged (:hover, :focus, :focus-within, [data-active]),
relationship resolution/conflict, host-supplied data-field-
```
A record on an example page therefore carries **four live channels** plus its server data:
| Variable | Written by | Semantics | Movement |
|---|---|---|---|
| `--w` (page-local, e.g. `--trust`) | server / page runtime | the data's normalized weight | on lens/weight change |
| `--cat` | server / page runtime | the active lens color | on lens change |
| `--d` | the page engine | live local particle density (0..1) | every frame; gathers to ~1 on `data-hot` hold |
| `--field-attention` | the scoped pipeline | eased blend of engagement + proximity + visibility | every frame; follows scroll and hover |
CSS composes them: weight drives `font-variation-settings`/opacity; the live channels drive a
glow and background lift that is **felt, not loud** — and `main[data-field="off"]` zeroes the
live channels, so "field off" is honest.
## 3. Engagement contracts
Two attributes make engagement programmable; both are shipped and verified:
- **`data-hot`** (engine) — the engine's scanner wires hover/focus listeners on `[data-hot]`
elements at scan time; engaging one activates its body (`b.on`), bends the wave spine to it,
and gathers matter — its `--d` rises toward 1 and eases back on release. The attribute must be
present **at scan time** (ship it in markup; a rescan picks up late additions).
- **`data-active`** (metric pipeline) — the recipe pipeline's `engaged` input is
`el.matches(':hover, :focus, :focus-within') || el.hasAttribute('data-active')`. Setting
`data-active` programmatically is the sanctioned way to tell the field "this element is in
hand": the backlog example sets it on a card for the duration of a drag (the field re-measures
work in flight), and the fleet example holds it ~3 s on a live status change (the field
notices the change).
Canon-doc coverage of these two attributes is the substance of
[#298](https://github.com/zachshallbetter/fundamental-engine/issues/298); this section is that
documentation.
## 4. Declared relationships
The `RelationshipRegistry` builds the live relationship graph from DOM signals only. Its
`discover()` scan matches native link semantics (`a[href^="#"]`, `label[for]`,
`aria-controls/-describedby/-labelledby/-flowto`) and one declarative attribute form:
```html
```
A body **contains** its declaration elements, so a record can declare many edges through hidden
child spans. The metric pipeline counts, per body, the touching relationships that resolve
on-page versus those declared-but-unresolved — that ratio is what `--field-coherence` reads.
The evidence example renders its real citation edges this way: the same edges its hover threads
draw are the graph the platform measures, and connected findings read `--field-coherence: 1.000`
while unconnected ones read `0.000` (verified live).
The `relationships?: RelationshipRecipe[]` field in the `FieldRecipe` schema is **not** a live-graph
input. It is compiled metadata used exclusively for the reduced-motion static display — `applyRecipe`
renders declared pairs as a `