# Fundamental — full documentation corpus Created by Zach Shallbetter (zachshallbetter.com). Repository: https://github.com/zachshallbetter/fundamental-engine Engine version 0.11.1 · commit c923a9f · generated 2026-11-03 by apps/site/scripts/gen-llms.mjs Contents (in order): 1. CANONICAL DOCUMENTS docs/canonical/ — the authority on concepts, terminology, contracts (37) 2. ENGINE REFERENCE docs/engine-reference/ — the deep as-built engine spec (10) 3. RESEARCH PAPERS docs/research/ — the arXiv-style paper family (33) 4. PLANNING & FRONTIER docs/planning/ — forward-looking design (the archive is excluded) (40) 5. PROJECT FILES README · CLAUDE · ROADMAP · BACKLOG · CHANGELOG (2) 6. API REFERENCE TABLES the data-driven /docs/api tables (options, methods, attrs, forces) 7. SITE DOCUMENTATION PAGES apps/site/src/pages/docs/ — authored prose (50) 8. OTHER SITE PAGES non-/docs pages that carry knowledge (30) 9. WRITINGS & ESSAYS the standalone essays (numbered papers dedup to §3) (16) 10. FIELD RECIPES the 64-recipe catalog The live site map is https://fundamental-engine.com/llms.txt. ======================================================================== ## CANONICAL DOCUMENTS ======================================================================== ======================================================================== FILE: docs/canonical/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. `@fundamental-engine/core` computes renderer-agnostic field behavior; host adapters bind that field to concrete platforms. `@fundamental-engine/dom` is the web host adapter (`elements`/`react` are authoring surfaces on top of it). The DOM is the first host, not the boundary. Canvas is one render surface, not the whole system. > Concepts describe. Dimensions hold state. Fields structure. Relationships associate. Forces couple. > Tokens execute. Metrics measure. Diagnostics explain. Conditions activate. Lenses read. > Projections reveal. Field Patterns compose. FieldPattern represents. Field Contracts execute. > No word lives in two lanes. | Document | Role | |---|---| | [`substrate-overview.md`](substrate-overview.md) | The one-page mental model — the substrate in five verbs (Declare → Influence → Read → Reveal → Govern); links out to the authoritative doc for each. Read first | | [`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 | | [`designed-vs-natural-map.md`](designed-vs-natural-map.md) | Why the engine is shaped as it is — every concept tagged Faithful / Idealization / Departure / No-analog against what nature does; the Departures are the flexibility | | [`dimensional-coupling.md`](dimensional-coupling.md) | The Dimensional Coupling Doctrine — dimensions are orthogonal by default; association ≠ coupling; forces are the only coupling mechanism; projections, body-authority modes (Anchored/Kinematic/Dynamic), Field Patterns, and the construction rule for restoring collapsed dimensions (depth/time/orientation) | | [`system-contracts.md`](system-contracts.md) | The hard contracts: bodies, fields, forces, agents, events, feedback, patterns, 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 | | [`host-model.md`](host-model.md) | The host model (the **Declare** verb): the `FieldHost` SPI, `MinimalFieldHost`, the capability ladder, and the host-conformance checklist — how any environment (DOM, headless, native, custom renderer) becomes a surface the field runs on | | [`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 | | [`body-lifecycle.md`](body-lifecycle.md) | The body lifecycle for non-DOM / programmatic bodies (declare → measure → participate → … → remove); DOM vs synthetic/data bodies; stable identity across the life | | [`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 | | [`feedback-channels.md`](feedback-channels.md) | The canonical, correct feedback-vars reference (the **Read** channel): engine-written vs host-supplied; `--d`/`--field-density` (consistent, not aliased), `--load`, `--lit`, the measured thermodynamics (`--entropy`/`--coherence`/`--temperature`), the nine `--field-` pattern lanes and their provenance | | [`time.md`](time.md) | Time in the field: the three clocks (simulation / experiential / world), the five time senses, 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 FieldPattern system | | [`testing-and-conformance.md`](testing-and-conformance.md) | Test contracts and the conformance framework (the Lab-as-detector) | | [`stability-and-convergence.md`](stability-and-convergence.md) | The force-directed failure canon, per-mechanism: what the field damps or side-steps (seeded RNG, friction, DOM-owned placement, plausibility-over-accuracy) vs what it owns (`dynamic`-body jitter, tuning brittleness) — and the arguments we deliberately do NOT make | | [`api-stability.md`](api-stability.md) | The removal-protection contract: the protected surface, what carries no guarantee, the 0.x compatibility rules | | [`coupling-discipline.md`](coupling-discipline.md) | How to connect a system to the field **at scale**: the three rungs, sampling cadences, when *not* to make something a body, and the reproducibility envelope. | | [`substrate-api.md`](substrate-api.md) | The shipped substrate read API (EXPERIMENTAL): `query` / `snapshot` / `diff` / `replay` / `projections` + governance lint, body authority + dynamic recoil, integrator modes, accumulator channels, first-class body identity | | [`agent-safety-model.md`](agent-safety-model.md) | The **Govern** verb: the safety/governance model for agents reading a field — three invariants (agent-readable ≠ agent-writable; snapshots withhold opaque `body.data` by default; projections reveal, never mutate) linking outward to `substrate-api.md` (EXPERIMENTAL) | | [`wallpaper-rule.md`](wallpaper-rule.md) | **"Substrate, not wallpaper" made operational** — the three-prong wallpaper test, the remedy order (derive → declare → demote → sugar; never deletion), the corollaries (injected-rng determinism, one writer per reading, proofs must be produced), and the per-plane guards | | [`coordinate-spaces.md`](coordinate-spaces.md) | The five coordinate spaces (field / host / projection / screen / semantic) and their one-way conversions; semantic-not-spatial discipline for non-DOM hosts | | [`causality-and-truth.md`](causality-and-truth.md) | The causality ladder (Observed → Attributed → Explained → Replayed → Predicted), the dimension / metric / channel / projection lock, and implementation-facing truth labels | | [`deprecation-plan.md`](deprecation-plan.md) | The migration alias surface: each living alias, its deprecation status, and the proposed removal version (timings pending maintainer sign-off) | | [`field-possibilities.md`](field-possibilities.md) | The full possibility space — what new kinds of interfaces become possible when meaning has field behavior (36 sections, from patterns and input agents to temporal fields, matter primitives, and the field as semantic medium) | | [`use-cases.md`](use-cases.md) | Concrete use cases across eight domains — the product-level translation of the possibility space into real UI problems and solutions | | [`computational-interaction-alignment.md`](computational-interaction-alignment.md) | How Fundamental relates to **Foundations of Computational Interaction (FCI)**, an external research framework: the concept mapping, the shared epistemic doctrines, and the bounded "neither proves the other" claim — plus why FCI vocabulary is deliberately **not** forced into the protected API | 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 design history — do not cite as current). Planned work lives on the RC1 board (user Project #24); shipped work is in `CHANGELOG.md` and per-version `docs/release-notes/`. ======================================================================== FILE: docs/canonical/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/engine/field.ts`, `packages/dom`) 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), > [substrate-api](substrate-api.md). > **Agent-readable surface (shipped, experimental — unfrozen).** A software/AI agent no longer has to > scrape the DOM or read per-body `--field-*` channels to understand the field: `field.query()` and > `field.snapshot()` return the live model — bodies, metrics, relationships, and per-force influence — > as plain structured data, and the projection registry's `agent-json` surface lets a Field Pattern > expose a tailored reading. `query()` is *the* substrate's agent-/tool-readable surface; see > [substrate-api.md](substrate-api.md). (Shipped and callable, but not on the protected list — its > shape may change.) > > **Field Agent vs Software Agent — don't conflate them.** A **Field Agent** is a *runtime participant > that consumes influence* (particle, DOM element, event sink — the subject of this document). A > **Software Agent** is an *external actor/tool* that reads or operates on field state via > `query()`/`snapshot()`. A software agent may *read* Field Agents; it is not itself a Field Agent > unless registered as a body/consumer. **Agent-readable does not imply agent-writable** — reads never > mutate the field, and any future write path is an explicit, permissioned host action (frontier). > > **The scoped read surface — `field.forAgent({ capabilities, redactions? })`.** A Software Agent should > read the field through a **capability-scoped, read-only facade**, not the raw handle. `forAgent` returns > an `AgentFieldView` that exposes *only* a scoped `query()` (plus `snapshot()` when `read:snapshots` is > granted and `replay()` when `read:replay` is granted) and carries **no** mutation methods at all — the "agent-readable is not > agent-writable" rule made structural. Capabilities (`read:metrics`, `read:relationships`, > `read:influences`, `read:body-data`, `read:projections`, `read:replay`, …) are an allow-list that > *tightens* every reading; `redactions` strip dotted paths (`body.data`, `host.user`); and snapshot > **profiles** (`'debug' | 'agent' | 'bug-report' | 'public'`) pick a privacy-appropriate shape. All of it > composes with the runtime `FieldPolicy` privacy + `agentRead` budget, always resolving to the *tightest* > result — an agent view can never widen past what policy already permits. See > [`substrate-api.md` § Agent permissions](substrate-api.md#agent-permissions--snapshot-profiles). # 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 via `data-class` — **shipped** | 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`), emit (`data-emit`), and trigger (`data-class`). 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 element `trigger` *class toggle* is `data-class="dense:lit, captured:full"`: the same `trigger:value` grammar `data-on` uses, but the value is a class name added while the trigger holds and removed when it releases (the no-JS counterpart of a `data-on` handler calling `classList.toggle`). 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`) and uses canonical `field:*` names. **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. - `field:saturated` — a sink hit its capacity (fired from `supernova`, the saturation transition); `field:released` is its paired down-edge. - `field:entered` / `field:exited` — a body's own gathered density crossed the 0.6 / 0.2 levels (hysteretic + debounced; distinct from `field:lit`/`field:dim`, which carry the neighbour-spillover lit channel). - `field:attention-shifted` / `field:attention-settled` — a body's conserved-attention multiplier crossed (only when attention is on). - `field:entropy-warning` / `field:entropy-cleared` — a body's measured local entropy crossed. - `field:memory-threshold` / `field:memory-faded` — an `addEdge` relationship's `memory` crossed (dispatched on the source body's element). - **any event name you bind via `data-on`** — e.g. `data-on="captured:field:dock, dense:field:lit"`. Use the canonical `field:*` names in docs and consumers. **Names reserved, not yet dispatched (planned):** `field:relationship-strengthened` — the designed relationship-strength dynamics rarely cross a fixed level cleanly, so it is left reserved until a use case lands. **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) **ships** as the font-agnostic Contour Sink primitive (`contours.ts`: `contourPathData` / `contourSvgFor`, any parsed font); only automatic CSS font-binary discovery and complex-script shaping remain future work. ```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; all cells now shipped) 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. --- ## Headless runtime *Status: shipped (0.8.1).* The engine runs outside the DOM — in a Node.js service, a native sidecar, an OS-level agent, a test — using the same physics and signals surface. No browser, no `canvas`, no `requestAnimationFrame`. The two pieces that gate this: ### `headlessHost` — a DOM-free `FieldHost` ```ts import { createField, headlessHost } from '@fundamental-engine/core'; const host = headlessHost({ width: 1920, height: 1080 }); const field = createField(undefined, { host, render: 'none' }); // caller drives the clock: host.tick(); // one frame at ~16.6 ms cadence host.tick(performanceNow); // or explicit ms timestamp host.resize(w, h); // when workspace bounds change ``` `render: 'none'` is signals-first mode (#538, now the engine default): full simulation, no drawing, all feedback channels live. `headlessHost` stubs every DOM dependency — `root` scans empty (all bodies come via `addBody`), `createCanvas` throws, all `on*` subscriptions are no-ops. **Swift:** `OSFieldHost` in Jellybean is the direct equivalent (`OSFieldHost.tick(at:)` drives the clock). **Kotlin/Android:** the pure `:fundamental-core` is host-free by construction — `createField(…)` / `FieldController.tick(dt)` run the full simulation with no view or renderer (the JVM tests and desktop FieldLab drive it headlessly); `:fundamental-platform` injects a `FieldHost` when a host is present. ### `addBody` + `onFeedback` — entities as bodies ```ts const body = field.addBody({ tokens: ['attract'], strength: 1.4, // drive from the entity's live importance range: 300, data: { kind: 'window', id: 'figma-1' }, // echoed back in readEdges() rect: () => screenRectOf('figma-1'), // sampled every frame onFeedback: (ch) => { // per-body channels: density, load, lit, entropy, coherence, temperature }, }); body.set({ strength: 2.0 }); // live, no rescan body.channels; // latest snapshot (also pushed to onFeedback) body.remove(); ``` **Swift parity:** `BodySpec.onFeedback` was added alongside the TS version — programmatic bodies now receive `FeedbackChannels` per frame even when `view == nil`. `BodyHandle.set(strength:)` exists in both runtimes. **Kotlin/Android parity:** `BodyHandle.set(strength = …)` exists, and programmatic bodies build with `feedback = true` so their density `d` is measured each frame; a per-frame `onFeedback` callback is **not yet** exposed on the Kotlin `BodySpec` (follow-up). ### `addEdge` / `readEdges` — relationships with memory A relationship is not a physics coupling (v1 caveat: strengthening A↔B does not yet make A's salience physically pull B's matter — that transfer is a deliberate follow-up). It is a **dynamics layer** over the body graph: strength responds to salience on fast timescales; memory accretes longitudinally. ```ts const edge = field.addEdge(meetingBody, fileBody, { type: 'opened-during', strength: 0.5, direction: 'bidirectional', // 'from-to' | 'to-from' | 'bidirectional' }); edge.set({ strength: 0.8, type: 'references' }); edge.remove(); field.readEdges(); // ReadonlyArray<{ // from: unknown, // source body's `data` record, verbatim // to: unknown, // type: string, // strength: number, // 0..1; rises ~1.5/s while source salient, decays ~0.3/s idle // memory: number, // 0..1; slow longitudinal "warmth" — the accretion signal // active: boolean, // source density > 0.08 this tick // }> ``` Removing either endpoint body drops the edge automatically. Edges survive `scan()` (they're programmatic, not DOM-derived). **Swift parity:** `FieldHandle.addEdge`/`readEdges` added alongside the TS API; the same dynamics (dt-scaled strength/memory updates) run in `FieldEngine.swift`. **Kotlin/Android parity:** `FieldHandle.addEdge`/`readEdges` ported with identical per-tick dynamics in `FieldController.kt` (strength `+1.5·dt` while the source is salient, `−0.3·dt` idle; memory `+0.2·dt`, holding on idle); removing an endpoint drops the edge. ### The agent tick loop ```ts const host = headlessHost({ width, height }); const field = createField(undefined, { host, render: 'none' }); const bodies = new Map(); function tick(osState) { // 1. reconcile entities → bodies for (const e of osState.entities) { const b = bodies.get(e.id) ?? bodies.set(e.id, field.addBody({ tokens: [e.importanceToken], data: e, rect: () => e.rect, })).get(e.id)!; b.set({ strength: e.importance * (e.frontmost ? 2 : 1) }); } // 2. reconcile relationships → edges (addEdge / edge.remove as they appear/vanish) // 3. advance the field host.tick(); // 4. read the situational model back const salience = [...bodies].map(([id, b]) => ({ id, ...b.channels })); const graph = field.readEdges(); // strength + memory per relationship return { salience, graph }; } ``` **Availability:** Status: shipped (0.8.1). `headlessHost` (#602) and `addEdge` (#603) are in the npm `@fundamental-engine/*` 0.8.1 release. The Swift implementations shipped alongside, in `FundamentalCore`/`FundamentalVanilla`. The Kotlin/Android implementations mirror the same surface in the `android/` tree (`:fundamental-core` `FieldHandle` incl. edges, the `:fundamental-platform` host layer), held to the shared cross-plane golden — riding the Android port branch, not yet a published release. ======================================================================== FILE: docs/canonical/agent-safety-model.md ======================================================================== > **Status: canonical.** > The authoritative statement of the safety/governance model for **Software Agents** and other > consumers that *read* a field — the **Govern** verb of the substrate (Declare → Influence → Read > → Reveal → **Govern**). It is an overview: the mechanisms and their code live in > [`substrate-api.md`](substrate-api.md), which this doc links outward to. That surface is **shipped > and code-confirmed but EXPERIMENTAL / unprotected** (0.x) — it may change; it is not part of the protected > stable baseline. # The agent safety model — the Govern verb Fundamental is an inspectable relational substrate. The host owns domain truth; Fundamental owns the relational **field state**; **policy decides what field state may be read, by whom.** Govern is the verb that draws that line. An agent can be handed a window onto a live field and learn its shape, metrics, relationships, and influence attribution — without ever being able to change it, and without seeing what it was not granted. Three invariants are load-bearing. Everything else is a mechanism that upholds one of them. ## The three invariants **1. Agent-readable does NOT imply agent-writable.** `field.forAgent({ capabilities, redactions })` returns a **read-only** `AgentFieldView`: it exposes only a scoped `query()` (plus `snapshot()` only when `read:snapshots` is granted, and `replay()` only when `read:replay` is granted — a withheld surface capability leaves the method off the facade entirely). There is no `applyForce`, no `addBody`, no `setPolicy` — not blocked by a runtime check, but absent from the facade's *shape*. Its `capabilities` and `redactions` are returned frozen, and `field.policy` hands back a frozen clone, so a holder of a view (or of the policy) can inspect the rules but cannot mutate the live field or the live policy. An agent view exposes **readings, never mutation.** **2. Snapshots exclude opaque / private data by default.** Snapshot profiles resolve to the **tightest** inclusion. The `agent` and `public` profiles withhold per-body opaque `data` (`body.data`); you must explicitly opt in — the `debug` profile **and** `includeData: true` — to obtain it, and even then the field's own privacy policy still applies. Capabilities are an allow-list that only tightens: without `read:body-data`, opaque `data` is withheld even if a profile or `includeData` asked for it. **Redactions** then strip dotted paths (e.g. `body.data`, `metrics.bodies`) from every reading, *after* capability scoping. Opting **in** widens; nothing an agent asks for can widen past what policy already permits. **3. Projection mutation is forbidden.** A **projection reveals** field state through an output surface (CSS, a DOM attribute, agent-readable JSON, a reduced-motion equivalent, …). It **MAY NOT** mutate bodies, create couplings, alter metrics, or change relationship strength. *Projection reveals state; coupling changes state* — a reveal that writes back into the field is a coupling wearing a projection's clothes, and is out of contract. This keeps the read/reveal path incapable of becoming an influence path behind the reader's back. > Lane discipline (do not blur): **projections reveal · forces couple · relationships associate · > policy limits.** No word crosses lanes. ## The mechanisms (each upholds an invariant above) Each is a one-line summary; the detailed contract, types, and examples are in `substrate-api.md`. - **Capabilities allow-list** — an agent view is scoped to explicit `read:*` grants; ungranted dimensions are stripped from every reading (identity/shape is the base grant). Tightens, never widens. → [Agent permissions + snapshot profiles](substrate-api.md#agent-permissions--snapshot-profiles) - **Redactions** — dotted paths (`body.data`, `metrics.bodies`, …) removed from every reading *after* capability scoping. → [Agent permissions + snapshot profiles](substrate-api.md#agent-permissions--snapshot-profiles) - **Snapshot profiles** — `public` / `agent` / `debug` resolve to the tightest inclusion; opaque `data` is opt-in, never default. → [Snapshot + Diff](substrate-api.md#snapshot--diff--snapshotopts-fieldsnapshot--diffa-b-fielddiff) - **FieldPolicy + budgets** — the live, replaceable policy that limits what may be read. A closed `budgets.agentRead` collapses the agent surface to ids + shape only; a **fractional** `0 < b < 1` grants a partial read of `b` of the body population, dropping every edge that names a withheld body (#915). The admitted subset is deterministic and **stable**, so it cannot be unioned back to the whole field by reading repeatedly. Returned as a frozen clone. → [Runtime Field Policy + Budgets](substrate-api.md#runtime-field-policy--budgets--createfield-policy---setpolicyp--fieldpolicy) - **Projection purity** — the `lintProjections`-style contract that keeps reveals from mutating the field. → [Projection Registry](substrate-api.md#projection-registry--fieldprojections-a-property) ## Related - [`substrate-api.md`](substrate-api.md) — the shipped substrate read API and every mechanism above, in full. - [`agent-consumption-model.md`](agent-consumption-model.md) — how different consumers read one influence differently. - [`api-stability.md`](api-stability.md) — the removal-protection contract; why this surface is EXPERIMENTAL, not protected. ======================================================================== FILE: docs/canonical/api-stability.md ======================================================================== > **Status: canonical.** > This document defines the **removal-protected public API surface** and the compatibility rules that > govern it: what CI protects, what carries no guarantee, how versions move, and how the alias window > works. It is **not** a freeze — see below. 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 **This is not a freeze, and calling it one was inaccurate.** Pre-1.0 the surface evolves; the list below has been edited dozens of times as the engine improved, and it should be. A promise of stability that is revised whenever it becomes inconvenient is not a promise — it is a claim that quietly stops being true. What the list actually does is narrower and worth keeping. A symbol on it is **protected from silent removal**: if it stops being exported, stops being declared, or stops registering, `pnpm check:api` fails the build. Nothing else. **The check never fails on an addition** — new exports, new optional fields and new patterns land freely, and always have. The point is not to prevent removals. It is to make them *deliberate*: a removed export should be a decision recorded in the CHANGELOG, not something a consumer discovers before we do. **Removing or renaming a listed symbol is allowed and expected.** Do it in one change: drop the entry from [`scripts/api-surface.data.mjs`](../../scripts/api-surface.data.mjs), and add a CHANGELOG migration note so consumers get told. > Package npm names: core is published as **`@fundamental-engine/core`**; the rest are > `@fundamental-engine/dom`, `@fundamental-engine/elements`, `@fundamental-engine/react`, `@fundamental-engine/vanilla`, > `@fundamental-engine/three`. The `@fundamental-engine/kit` / `fundamental-engine` umbrella packages were > **retired in 0.7.0** — install the specific package you need. > > **0.7.0 migration — `@fundamental-engine/platform` → `@fundamental-engine/dom`.** The DOM-binding > package was renamed (it *is* the DOM layer); the protected symbols `browserHost`, `createFieldPlatform`, > `applyRecipe`, `bindData`, and the `FieldPlatform` type now live in `@fundamental-engine/dom`. This is > the one sanctioned cross-package move of the `0.x` line, gated by the minor bump. `@fundamental-engine/platform` > stays published as a **deprecated alias** that re-exports `dom`, so existing imports keep working; > migrate to `dom` and the alias will be removed in a later release. ## 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/dom` | 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/dom` | value | Wires the six native-first registries on a root. | | `applyPattern` | `@fundamental-engine/dom` | value | Applies a Field Pattern to a live platform. `applyRecipe` is the protected `@deprecated` alias (removed at `1.0`). | | `bindData` | `@fundamental-engine/dom` | value | Binds records → bodies; data drives the field. | | `compilePattern` | `@fundamental-engine/core` | value | Pure `FieldPattern` → compiled plan (no DOM). `compileRecipe` is the protected `@deprecated` alias (removed at `1.0`). | `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 protected; the vanilla door must keep auto-supplying `browserHost()`. ### Types | Type | Package | What it is | | --- | --- | --- | | `FieldPattern` | `@fundamental-engine/core` | The Field Pattern schema. `FieldRecipe` is the protected `@deprecated` alias (removed at `1.0`). | | `FieldHost` | `@fundamental-engine/core` | The renderer-agnostic host contract `createField` requires; `browserHost` implements it. | | `FieldPlatform` | `@fundamental-engine/dom` | 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 `` (also registered as ``) and ``; the pre-rename ``/`` tags are **not** registered (the rename left no element aliases). ## The unprotected surface 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 protected as a type. Entry points that return it (`createField`, `createBrowserField`) are protected, but new methods may be added in any patch. | | `FieldHandle` diagnostic accessors | shipped-unprotected | `particleCount(): number` and `energy(): { kinetic, thermal, total, count }` ship in `@fundamental-engine/core` and are proxied on ``. Safe to use; not on the protected list. | | Substrate read API | shipped-unprotected · EXPERIMENTAL | `query` / `snapshot` / `diff` / `replay` / `projections` (+ `lint`), `data-authority` / `Body.authority`, `createField({ integrator: 'fixed' })`, and the accumulator channels — all shipped across the surfaces but **not** on the protected list, and may change shape or be removed. Full reference: [substrate-api.md](substrate-api.md). | | Advanced diagnostics | partial | `DIAGNOSTICS` / `DIAGNOSTIC_LENS` / `draw*` primitives ship but are unfrozen. | | Performance budget | shipped-unprotected | `inspectBudget()`, `withinBudget()`, `DEFAULT_BUDGET`, `BudgetFinding` ship in `@fundamental-engine/core`; `FieldPerf` (frame-duration split, adaptive governor) ships shipped-but-unfrozen in `@fundamental-engine/dom` as `createFieldPerf` + `QualityGovernor`. | | Visual recipe editor | absent | No editor UI; the authoring toolkit is the substrate to build one on. | | GPU / WebGPU backend | planned | A named direction; every shipped render mode (the 20 in `RENDER_MODES`) is 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 protected 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 protected 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.** Protected symbols do not move between packages within `0.x` (`compilePattern`/`FieldPattern`/`FieldHost` → core; `createFieldPlatform`/`applyPattern`/ `bindData`/`FieldPlatform`/`browserHost` → dom; `field-root`/`field-cell` → elements). The old `compileRecipe`/`FieldRecipe`/`applyRecipe` names are protected `@deprecated` aliases of these, same package, removed at `1.0`. 5. **Bodies are an attribute contract.** `[data-body]` on ordinary elements is the protected authoring surface; there is no body element. 6. **The `forces-*` compatibility layer was removed — there is no `forces:*` event compatibility contract.** The `forces-ui → field-ui → Fundamental` rename was a **hard** rename: the ``/`` tags, the `ForcesField`/`ForcesController`/`useForcesField` exports, the `--forces-*` CSS vars, and the `compat-*` packages are **gone** (the test suite asserts their absence). Event naming is canonicalized as `field:*`. The one *current* deprecated alias is the **package** rename `@fundamental-engine/platform → @fundamental-engine/dom` (above) — a thin re-export of `dom`, excluded from the additive-only guarantee and **scheduled for removal at `1.0`** (it emits a one-time dev-only import warning). Note `--d` / `--field-density` and `--load` are **canonical dual names, kept permanently — not deprecated.** 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. ## Deprecation & removal policy A few names are migration-era aliases from the `forces-ui → field-ui → Fundamental` rename. They keep working through RC1 and are **removed at `1.0`**. Two var pairs that look like migration cruft are not — they are canonical dual naming and are kept permanently. The full per-alias inventory (file:line, warn vs. doc-only, replacement) lives in [`deprecation-plan.md`](deprecation-plan.md); this is the contract summary. ### Kept permanently — NOT deprecated - **`--d` and `--field-density`** — the canonical dual density-var naming. Both are permanent; author CSS may read either. This is intentional dual naming, not a deprecated alias. - **`--load`** — the canonical sink-load channel. Permanent. (It is `--mass` that is the deprecated alias of `--load`, not the reverse — see below.) ### Deprecated — shipped through RC1, removed at `1.0` | Alias | Replacement | Where it lives | Dev warn? | |---|---|---|---| | `--mass` CSS var | `--load` | `packages/core/src/engine/feedback-sink.ts`; mirrored in `packages/elements/src/platform-runtime.ts` | No — a CSS-var write is not runtime-observable to JS; doc-only | | `--forces-*` CSS vars | `--field-*` | *already removed* (`0.7.0`) — listed for the record | n/a | | `compat-*` packages (`compat-core`/`-elements`/`-react`/`-vanilla`) | the real `@fundamental-engine/*` packages | *already removed* (`0.7.0`); the only living compat package is `@fundamental-engine/platform` → `@fundamental-engine/dom`, which warns on import | Platform alias: **Yes** — one-time dev-only warn on import | **Sunset:** the above aliases ship through RC1. The runtime-observable one (`@fundamental-engine/platform` package) emits a **dev-only** (`NODE_ENV !== 'production'`) `console.warn`, deduped so it warns at most once. CSS-var aliases cannot be intercepted (CSS reads are invisible to JS), so they are doc-only. Everything here is **removed at `1.0`**. ## How the check is enforced - [`scripts/api-surface.ts`](../../scripts/api-surface.ts) imports every protected value and type from its owning package. Removing, renaming, or changing the kind of a protected 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 protected value resolves at runtime in the built dist, each protected 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 protected 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-engine` scope (`@fundamental-engine/core` and the five adapters: dom, elements, react, vanilla, three). This list defines what CI protects from silent removal consumers build against; the publish steps and order are in [`docs/meta/publishing.md`](../meta/publishing.md). ======================================================================== FILE: docs/canonical/authoring-and-recipes.md ======================================================================== > **Status: canonical.** > Authoring levels, the intent compiler, the pattern 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 Patterns ## Related Documents | Document | Role | |---|---| | [`README.md`](./README.md) | Documentation map | | [`definition-document.md`](definition-document.md) | Concept | | [`system-contracts.md`](system-contracts.md) | Pattern contract | | [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md) | Interaction patterns | | [`testing-and-conformance.md`](testing-and-conformance.md) | Pattern tests | ## Purpose This document defines how authors use `Fundamental` on the web. `Fundamental` is a platform-native relational field runtime: `@fundamental-engine/core` computes renderer-agnostic field behavior, and its web host adapter `@fundamental-engine/dom` binds the field to the DOM (measurement, state, feedback, relationships, visual bindings, overlays, scheduling, linting); 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, patterns | | 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 Patterns | portable field programs (current API: `FieldPattern`) | | 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 `--d` feedback channel (its expressive long form is `--field-density`), 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` | shadow hosts only — component-side vocabulary forwarded as `scope` on the registration detail (`"nearest"` / `"global"`); the engine does not read it from light-DOM bodies ([shadow-dom.md §18](../engine-reference/shadow-dom.md#18-field-scopes)) | | `data-field` | shadow hosts only — forwarded as `field`, the explicit field target / portal (`"root"`, a selector, or an element); not read from light-DOM bodies ([shadow-dom.md §19](../engine-reference/shadow-dom.md#19-field-portals)) | | `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 (`engine/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. FieldPattern Schema ### Field Pattern vs. FieldPattern A **Field Pattern** is the canonical concept: an authored arrangement of semantic intent, dimensions, bodies, fields, forces, relationships, metrics, diagnostics, projections, and accessibility equivalents. `FieldPattern` is the current API representation of a Field Pattern. Use "Field Pattern" when explaining the model. Use `FieldPattern`, `compileRecipe`, `applyRecipe`, and `FIELD_RECIPES` when referring to the current TypeScript schema, compiler, validator, catalog, routes, and API. Do not use "Configuration" for this concept — reserve configuration for ordinary settings/options (render configuration, host configuration, engine configuration). Do not use "Matter" for this concept — Matter is the participant/substance lane. Do not rename any API symbols. > **Implemented.** `FieldPattern` (`packages/core/src/recipes/schema.ts`). A `FieldPattern` is the current > API representation of a portable, serializable, inspectable Field Pattern — 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 `FieldPattern`.) ```ts type FieldPattern = { 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 pattern author who wants an edge in the live graph must author it in HTML with `data-field-relation`, not in the pattern 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 pattern can't reference anything the engine doesn't have, and no pattern is motion-only. **Patterns 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, pattern, { 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 pattern carries its own engagement gate this way. Without a `field` option, patterns 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. Pattern Types | Pattern | Purpose | |---|---| | `FieldPattern` | 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 Patterns > **Implemented.** All **sixty-four** ship as validated `FieldPattern`s in > `packages/core/src/recipes/catalog.ts` (`FIELD_RECIPES`; `gallery.ts` re-exports it), grouped into four tiers (`RECIPE_TIERS`), > live on [`/patterns`](https://fundamental-engine.com/patterns). 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. ### Pattern language vs engine vocabulary Pattern **prose** is expressive; pattern **runtime fields** are strict. A pattern can say "completion releases pressure and decays into memory," while its runtime fields stay `primitives: [morph, memory, gravity]`. The conformance gate rejects any pattern 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 patterns — only pattern records, conformance, mappings, and docs. ### Tier 1 — Core interface & accessibility (the first-release set is starred) | # | Pattern | 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 pattern 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 This list records the build order, all of which has now shipped (file pointers below). ```txt 1. SceneRecipe schema — shipped (recipes/schema.ts; FieldPattern, SceneRecipe alias) 2. VisualizationPreset schema — shipped (visual/visualization.ts; VISUALIZATION_PRESETS) 3. ForceRecipe schema — shipped (recipes/schema.ts) 4. Intent compiler — shipped (recipes/intent.ts; compileIntent) 5. Authoring lint rules — shipped (visual/lint.ts) 6. Essential patterns — shipped (recipes/catalog.ts; 64 patterns, 8 first-release) 7. Material presets — shipped (semantic/materials.ts; INTERACTION_MATERIALS) 8. Field state presets — shipped (semantic/states.ts; FIELD_STATES) 9. Explain This Field output — shipped (explainScene) 10. Field Diff ``` ======================================================================== FILE: docs/canonical/body-lifecycle.md ======================================================================== > **Status: canonical.** > The lifecycle a body passes through — from declaration to removal — stated for **programmatic / > non-DOM bodies** (added via `addBody`, e.g. on a headless [`MinimalFieldHost`](platform-architecture.md), > or over data records), so non-DOM usage is *official*, not bolted on. DOM bodies have this same > lifecycle *implicitly* (the scanner runs it); this doc makes it explicit for bodies with no element to > rescan. Follows the [status rule](documentation-standards.md): nothing here is called shipped unless > code confirms it (`packages/core/src/engine/types.ts` — `BodySpec`/`BodyHandle`; `field.ts` — `addBody`). # Body lifecycle A **body** is any element or object that becomes a participant in the field — it bends the field, and the field's local density bends it back (reciprocity). The engine imports zero DOM, so a body is never *intrinsically* a DOM node: the DOM adapter is one way bodies enter the field, and `addBody` is another. Both produce the same kind of participant and pass through the same lifecycle. > **Terminology (locked, see [documentation-standards.md](documentation-standards.md)):** a *data body* > is a body whose host object is a semantic record (a claim / task / file); `body.data` is opaque > metadata attachable to *any* body — attaching `data: {…}` does not by itself make a body a data body. ## The general lifecycle Every body — DOM or programmatic — moves through seven phases: | Phase | What happens | |---|---| | **declare** | The body is introduced to the field and given a stable [identity](substrate-api.md#query--queryq-fieldqueryresult). DOM: discovered by the scanner from `[data-body]`. Programmatic: `field.addBody(spec)` returns a `BodyHandle`. | | **measure** | The body's box is resolved in **field space**. DOM: `getBoundingClientRect()` each rescan. Programmatic: the supplied `rect()` thunk is sampled each frame. | | **participate** | The body's tokens emit force into the field — it bends the field (`sample(x, y)` near it reads a force toward/around it). | | **receive** | Reciprocity: the field's local density is written back to the body as feedback channels (`--load`, `--field-*`, `--d` on a DOM body; the `onFeedback` callback / `handle.channels` on a programmatic one). | | **project** | Body state is *revealed* through a registered [projection](substrate-api.md#projection-registry--fieldprojections-a-property) — CSS, a DOM attribute, agent-readable JSON. A projection reveals; it never writes back into the field. | | **snapshot** | The body is captured — `query()` reads it live; `snapshot()`/`diff()`/`replay()` capture and compare it across frames. All key on the body's stable `identity.id`. | | **remove** | The body leaves the field. DOM: the scanner drops it when the element leaves the tree on the next rescan. Programmatic: `handle.remove()` — after which it exerts no force. | `participate` → `receive` repeat every frame for the body's whole life; `project` and `snapshot` are read-side taps that never mutate the body. `declare` and `remove` are the endpoints. ## The data / headless-host variant The same lifecycle, told over a **data record** on a headless host (no canvas, no DOM — the [`MinimalFieldHost`](platform-architecture.md) floor of geometry + time is enough): 1. **record enters the field** — a semantic record (claim / task / file / mesh) is declared as a body via `addBody`, carrying the record on `spec.data` and a stable `identity`. 2. **rect / provider resolves** — the body has no element, so it supplies its own geometry: `spec.rect()` is a thunk the host projects its record/mesh/view position through, sampled each frame. 3. **relationships attach** — edges between bodies (`addEdge`) key on identity, so a data body wires to others by `identity.id`, not by object reference. 4. **metrics update** — the body participates and receives: its per-body feedback arrives on the `onFeedback` callback (or `handle.channels`), demultiplexed from the global sink. 5. **query reads** — a software agent reads the live body through `query()` (identity, rect, tokens, metrics, authority) — read-only; reading never changes the field. 6. **snapshot captures** — `snapshot()` freezes the body (opt into `includeData` to carry its record); `diff()`/`replay()` narrate how it changed, all keyed on `identity.id`. 7. **body leaves the field** — `handle.remove()` retires it; the record's field participation ends. ```ts const claim = field.addBody({ tokens: ['attract'], identity: { id: 'claim-3', namespace: 'evidence', kind: 'claim' }, rect: () => projectRecordBox(record), // record → field space, sampled each frame data: record, // the semantic host object → a *data body* onFeedback: (ch) => applyDensityToRecord(record, ch), }); // …live for many frames: query()/snapshot() read it by identity… claim.remove(); // record leaves the field ``` ## Identity is assigned at declare, and MUST be stable for the whole life Identity is a **first-class, structured key** — not display text, not an object reference: ```ts interface FieldBodyIdentity { id: string; // stable primary key — unique in the field, constant for the body's life namespace?: string; // optional grouping (app/module); opaque to the engine kind?: string; // optional type tag ('card', 'claim', 'agent'); opaque host?: string; // optional owner tag; opaque } ``` It is fixed at **declare** and must not change through `measure`/`participate`/`receive`/`project`/ `snapshot`/`remove`, because **`snapshot`/`diff`/`replay` and relationships all key on `identity.id`**. If the id shifted mid-life, a diff would read as *remove old + add new* and causal replay would lose the thread. Rules: - **Supply it at declare.** `addBody({ identity })` takes a `FieldBodyIdentity` (a bare string is shorthand for `{ id }`). This is the norm for data bodies — the record already has a stable key. - **Or let the engine derive one — deterministically.** With no supplied identity the engine assigns a stable synthetic id (a monotonic `body-N`, **never** `Math.random`), so identity is always present. - **Words are not identity.** A claim's text can change while its identity holds; a DOM `id` is one *source* of a stable id, not the concept itself. Full contract: [substrate-api.md → identity](substrate-api.md#query--queryq-fieldqueryresult). ## DOM body vs synthetic / data body The lifecycle is identical; the **measure** phase is where the two diverge: | | **DOM body** | **Synthetic / data body** | |---|---|---| | Enters via | the scanner, from `[data-body]` | `field.addBody(spec)` → `BodyHandle` | | Geometry source | measured from the element (`getBoundingClientRect`) each rescan | the supplied `rect()` thunk, sampled each frame — **no element to rescan** | | Coordinate origin | host (DOM) space, mapped to field space by the adapter | the caller supplies geometry directly; a non-DOM host projects its own space → field space (see [coordinate-spaces.md](coordinate-spaces.md)) | | Feedback delivery | CSS vars on the element (`--load`, `--field-*`, `--d`) | `onFeedback(channels)` callback / `handle.channels` | | Survives a rescan? | re-discovered if still in the tree; dropped when it leaves | **yes** — programmatic bodies are invisible to the DOM scan; only `handle.remove()` retires one | | Live param edits | via reactive `data-*` attributes | `handle.set({ strength, range, angle, spin, color })` — no rescan | A DOM body is *re-measured from its element* every rescan, so the element is the position authority. A synthetic body has **no DOM to rescan** — its `rect()` thunk is the sole position source, which is exactly why a headless host (mesh, native view, or a bare data record) can be a full field participant. Both are subject to [body-authority modes](substrate-api.md#body-authority--dynamic-recoil--data-authority--bodyauthority): `anchored` (rect authoritative), `kinematic` (engine writes the transform), or `dynamic` (engine owns position and the body recoils under the net field). ## Related documents | Document | Role | |---|---| | [`platform-architecture.md`](platform-architecture.md) | `MinimalFieldHost` — the geometry+time floor a headless body runs against | | [`substrate-api.md`](substrate-api.md) | `FieldBodyIdentity`, `query`/`snapshot`/`diff`/`replay`, body authority — the read surface the lifecycle feeds | | [`coordinate-spaces.md`](coordinate-spaces.md) | Host space vs field space — where a synthetic body's supplied geometry is resolved | | [`documentation-standards.md`](documentation-standards.md) | The terminology locks — *data body* vs `body.data`, *Field Agent* vs *Software Agent* | ======================================================================== FILE: docs/canonical/causality-and-truth.md ======================================================================== > **Status: canonical (concept).** > Two disciplines that keep the substrate honest: the **causality ladder** (how much a replay is > allowed to claim) and the **dimension / metric / channel / projection lock** (four naming lanes that > must never collapse). Plus the implementation-facing **truth labels** that sit next to the six truth > modes. This is *framing* over the [substrate API](substrate-api.md); it introduces no new engine > behavior. Follows the [status rule](documentation-standards.md). # Causality and truth The substrate can `query`, `snapshot`, `diff`, and `replay` a field as plain data ([substrate-api.md](substrate-api.md)). That power invites over-claiming: a narrated replay *feels* like it proves causation, and a measured metric *feels* interchangeable with the dimension it measures. This document draws the two lines that keep those honest. ## Part A — the causality ladder `replay()` derives an ordered account of *how* a field changed between two snapshots. It reads the two snapshots; **it does not re-run the sim.** So a replay is an explanation, not a proof. The ladder names five levels of claim, from what we directly saw to what we merely project. Each level asserts strictly more than the one below — and each has a hard ceiling on what it does **not** say. | Level | Asserts | Does **not** assert | Substrate source | |---|---|---|---| | **Observed** | "this value was X at frame N" | why it was X | `snapshot()`, `query()` | | **Attributed** | "force `attract` contributed +0.42 linear to this body" | that `attract` *caused* the outcome alone | `Env.accum` attribution / `FieldInfluenceReading` | | **Explained** | "density rose because these attributions net positive" | that no unmodeled factor mattered | `diff()` | | **Replayed** | "in order: formation activated, then relationship strengthened, then density rose" | that re-running would reproduce it identically | `replay()` | | **Predicted** | "under the same field, this body will move toward here" | that it *will* happen — the world may change | prediction diagnostic | **Do not call any of this "causality" unqualified.** The engine's own caveat canon applies: energy and momentum are not conserved by design, and only particle *count* is a strong invariant — so an attribution is a faithful record of *what the accumulator summed*, not a physical proof of cause. `replay()` steps carry the `diagnostic` lane precisely because they *explain*, they do not *measure*. Practical rule: **quote the highest level your data supports, and no higher.** - Only Observed if you have one snapshot. - Only Attributed/Explained if snapshots were captured with `includeInfluences` (otherwise `cause: 'force'` steps are not even emitted). - Predicted is always conditional — label it as such. ## Part B — the dimension / metric / channel / projection lock Four words describe four different things about one axis of a field. Collapsing any two of them is the recurring conceptual bug. They lock in this order: | Lane | Definition | Example | |---|---|---| | **Dimension** | an *axis of state* a body can have | `attention` | | **Metric** | a *measured reading* of a dimension (+ its live channel var) | `--d` / `--field-attention` | | **Channel** | an *accumulator lane* force accumulates in | `linear` (or `thermal`, `angular`, `temporal`, `semantic`) | | **Projection** | a *host expression* of the state | `outline-weight` (a CSS write) | ### Worked example > A body has the **dimension** `attention`. Its current value is read as the **metric** exposed on the > `--d` / `--field-attention` channel var. Forces that move it accumulate in the `linear` **channel** of > the impulse accumulator. A registered **projection** expresses it as `outline-weight` on screen. One axis, four lanes: `attention` (dimension) · `--d` (metric channel var) · `linear` (accumulator channel) · `outline-weight` (projection). None of these words may stand in for another: - A dimension is not its metric — the axis exists even when nothing reads it (headless, `render: 'none'`). - A metric is not the accumulator channel — the metric is the *reading*; the channel is *where force summed to produce it*. - A projection is not the state — *projection reveals state; coupling changes state* (the substrate-05 governance principle). A projection never writes back into a dimension. This is the naming canon (*no word lives in two lanes*) applied to the substrate's measurement surface, and `lintWordLanes()` ([substrate-api.md](substrate-api.md)) guards it mechanically. Note "channel" is doubly loaded in casual speech — the **accumulator channel** (`linear`/`thermal`/…) and the **metric channel var** (`--field-*`) are different lanes; this table keeps them apart. ## Part C — truth labels (adjacent to the six truth modes) The six **truth modes** ([passport](../../packages/core/src/contracts/passport.ts): physical, designed, hybrid, diagnostic, poetic, semantic) describe *what kind of statement a force makes*. Alongside them, implementation needs **truth labels** describing *how a reading was produced* — the epistemic status of a number, not the rhetorical mode of a force: | Label | The reading is… | Reproducible? | |---|---|---| | **deterministic** | a fixed function of field state | yes — same input, same output | | **stochastic** | sampled with randomness | only in distribution | | **heuristic** | an approximation / rule of thumb | yes, but not exact truth | | **semantic** | derived from meaning/data, not physics | as stable as its source data | | **diagnostic** | an explanation *about* the field | it describes, it does not measure | These labels map onto the causality ladder: Observed/Attributed values are typically **deterministic** (at `dt === 1` the integrator is byte-identical); a **stochastic** reading can never climb above Explained; **diagnostic** is the lane of every `replay()` step. A serialized record (see the frontier [Field Protocol](../planning/field-protocol.md)) should carry its truth label so a consumer never over-reads a heuristic or a narrated replay as measured cause. ## Related documents | Document | Role | |---|---| | [`substrate-api.md`](substrate-api.md) | `replay()` + snapshot trio + the accumulator channels this doc constrains | | [`documentation-standards.md`](documentation-standards.md) | The naming canon + status rule this lock enforces | | [`dimensional-coupling.md`](dimensional-coupling.md) | The coupling passport — how a channel-crossing force must declare itself | | [`fundamental-field-behavior-table.md`](fundamental-field-behavior-table.md) | The six truth modes these labels sit beside | ======================================================================== FILE: docs/canonical/common-mistakes.md ======================================================================== # Common mistakes — don't guess > **Status: reference.** The first-contact mistakes an agent or developer makes about Fundamental — and > the correct answer. If you are about to guess at the API or the behavior, check here first; the truth > is cheaper than a wrong guess. Fundamental's surface is small but its mental model is unusual, so confident wrong guesses are common. Each item below is a mistake we have actually seen, paired with the fact and where to verify it. ## 1. "It's a particle background." **No — it is a behavior layer.** A field reads each `[data-body]` element's position every frame and writes the local field back as `--field-*` CSS variables (`--field-density` / its alias `--d`, `--load`, `--lit`) your own styles consume. It reacts to *your* layout and engagement, not to a cursor over a decorative canvas. Particles are **one optional render surface**, not the system. See [invisible-fields.md](invisible-fields.md). ## 2. "`render` defaults to particles." **No — since [#538](https://github.com/zachshallbetter/fundamental-engine/issues/538) `render` defaults to `'none'` (signals-first).** A field created without an explicit `render` runs the full simulation and emits signals but **draws nothing**. Opt into a visible surface explicitly: `render: 'dots'` (particles), `'trails'`, `'streamlines'`, or the warped `grid` overlay. If "nothing is showing," that is the default — add `render: 'dots'`, or read the `--field-*` variables (which are already live). ## 3. "There are three different `createField`s." **No — there is one `createField`.** The `@fundamental-engine/core` export is the renderer-agnostic primitive and **requires `opts.host`**. The `@fundamental-engine/vanilla` export is the *same function* with `browserHost()` bundled for you (plus a `bounds` option). Use the vanilla door (`createField(canvas, opts)` or `new FieldField(opts)`) unless you are wiring your own renderer. You do not need to find a different package because one "needs a host" — that is the core primitive; reach for vanilla. ## 4. "To scope the field to a component I have to roll my own." **No — pass `bounds`.** `new FieldField({ bounds: el })` ([#540](https://github.com/zachshallbetter/fundamental-engine/issues/540)) runs a *contained* field whose bodies and coordinates live inside the element, not the window. Contained is a vanilla option, **not** an attribute on `` (the web component is window-scoped) and **not** `` (that is a standalone per-force demo pool). ## 5. "I'll poll the particles to read the field state." **Read the signals, not the particles.** The field's output is the `--field-*` CSS variables on `[data-feedback]` bodies and the discrete event bus (`field.on('captured' | 'released' | 'enter' | 'exit' | 'met', …)`). For sampled scalars use `field.sampleScalar(x, y)` / `sampleGradient(x, y)` (these need `heatmap: true` — they warn in dev if it is off). `readParticles()` exists for renderers, not for reading state. ## 6. "`attract` is gravity; `absorb` is a token." **Mind the naming lanes.** Natural Fields (Gravity→importance, Electromagnetic→polarity, Strong→binding, Weak→transformation) are **concepts**, not tokens. The runtime tokens are `attract`, `gravity`, `charge`, `sink`, `cohesion`, … — and `attract` is a *designed UI well*, deliberately **not** gravity. `absorb` is concept language; the token is `sink`. Concepts describe, tokens execute — never mix them. See the naming canon in [definition-document.md](definition-document.md). ## 7. "I can infer the API from the name." **Don't infer — the surface is small and documented.** Entry points and the which-`createField` map are on the [docs overview](https://fundamental-engine.com/docs); every option is in [/docs/api/imperative#options](https://fundamental-engine.com/docs/api/imperative#options); the protected 0.x surface is `scripts/api-surface.data.mjs` (CI-enforced). If a method or option is not in those, it does not exist — do not invent it. ## 8. "Reduced motion breaks it." **No — reduced motion loses motion, not meaning.** The simulation and the `--field-*` signals still track under `prefers-reduced-motion`; only the CSS easing and the drawn surface drop. Style your reactive states so they read without animation. See [accessibility](https://fundamental-engine.com/docs/accessibility). ## What not to build Because the system is expressive, the failure modes are mostly misuse. Don't: - Use Fundamental as a **decorative particle background** only (it's a behavior/signals layer; particles are optional). - Make **motion the only carrier of meaning** — it must survive reduced motion (see #8). - Turn **every relationship into a coupling** — association is not coupling; forces couple, a Field Pattern decides which associations become couplings. - Let a **projection mutate field state** — projections reveal, they never write back (projection purity). - **Expose body data to agents by default** — `body.data` stays opaque unless deliberately included. - Say **"formation"** when you mean a *global formation mode* (`wells`/`lanes`/…), or **"Configuration"** when you mean a *Field Pattern*. - Use **"Matter"** when you mean authored behavior. - Create a **force token for every concept** — most concepts are metrics, dimensions, or projections, not new forces (the recipe/force canon is locked). ## Field failure modes When a field misbehaves, name the shape of the failure — each has a distinct cause and fix. 1. **Dead field** — no bodies, or no measurable region: nothing is `[data-body]` in bounds, so the field has nothing to measure and emits nothing. 2. **Silent field** — the sim runs but no feedback or projection is attached; signals are written but nothing consumes them (the silent-contract gap). See [causality-and-truth.md](causality-and-truth.md). 3. **Haunted field** — a projection *appears* to change field state because coupling/projection boundaries are unclear; projections reveal, they never write back (projection purity). 4. **Leaky field** — a snapshot or query unexpectedly exposes opaque body data; `body.data` should stay opaque unless deliberately included. See [substrate-api.md](substrate-api.md). 5. **Overcoupled field** — relationships produce dynamics with no declared Field Pattern; associations became couplings without a formation deciding they should. 6. **Motion-only field** — meaning disappears under reduced motion because motion was the only carrier (see #8). 7. **Drifting field** — host geometry and field coordinates diverge; the adapter's space no longer matches the field's. See [coordinate-spaces.md](coordinate-spaces.md). 8. **Unstable field** — forces inject energy with no damping, cap, or budget, so the sim heats up unbounded. 9. **Ambiguous field** — a term is used in two lanes at once (e.g. "formation" for both a global formation mode and a Field Pattern); pick one lane. ## Field smells Lint-candidate heuristics — each points at a likely mistake, not a guaranteed one. 1. **Raw force soup** — many force tokens stacked on one body with no Field Pattern to organize them. 2. **Metric without provenance** — a metric reported with no trace of where it came from. See [causality-and-truth.md](causality-and-truth.md). 3. **Projection without a reduced-motion / semantic equivalent** — a projection that only reads under animation. 4. **Relationship pretending to be a force** — an association wired as if it couples, with no formation behind it. 5. **Agent overread** — a Software Agent reads more field data than its task needs. See [substrate-api.md](substrate-api.md). 6. **Body without identity** — a body that can't be tracked across snapshots (`FieldBodyIdentity` now addresses this). 7. **Host mismatch** — the adapter supplies a different coordinate space than the projections expect. See [coordinate-spaces.md](coordinate-spaces.md). ======================================================================== FILE: docs/canonical/computational-interaction-alignment.md ======================================================================== > **Status: canonical (relationship doc).** > How Fundamental relates to **Foundations of Computational Interaction (FCI)**, an external research > framework maintained separately. This doc records the concept mapping and the **bounded** claim that > connects them. It introduces no engine behavior and asserts no new API. Where a mapping names a > Fundamental capability, the maturity column is verified against code as of the platform-runtime phase; > when code and this doc disagree, the code wins — fix the doc. # Fundamental and Foundations of Computational Interaction ## Historical relationship Fundamental began with a physics question: what happens when a field is placed around the DOM and interface elements participate in it? The engine developed as a concrete runtime for that reciprocal field model. FCI grew later from a communication problem. In trying to explain Fundamental to other people, its author found that no shared scientific vocabulary made interaction itself clear. That need prompted the broader Foundations of Computational Interaction research program. FCI is now maintained as a separate program with a scope wider than Fundamental; this origin does not make Fundamental an implementation of FCI as a whole. - **FCI** is a research program prompted by the need to explain Fundamental. It studies interaction as an explanatory target by separating declared *domain commitments, state, semantics, projection, representation, interpretation, opportunity, coupling, behavior, measurement, similarity, strategy, and evidence* so their relationships can be examined rather than assumed. FCI is pre-empirical and says so. - **Fundamental** is a runtime (bottom-up, from code). It turns host objects into bodies in a shared field, applies forces, and exposes the running field as inspectable, queryable, replayable data. Their connection is historical and methodological, not a claim that one validates the other. Both refuse the same shortcut: **presentation is not the system.** FCI separates projection from meaning from behavior so confounds can be isolated; Fundamental separates `FieldHost` / state / operational semantics / projection so a representation change does not silently change the modeled system. This document maps one onto the other and — just as importantly — fences the relationship so neither overclaims the other. ## Related documents | Document | Role | |---|---| | [`definition-document.md`](definition-document.md) | What Fundamental *is* ("substrate, not wallpaper") | | [`substrate-api.md`](substrate-api.md) | The shipped substrate read API (EXPERIMENTAL): `query` / `snapshot` / `diff` / `replay` / `projections` | | [`causality-and-truth.md`](causality-and-truth.md) | The causality ladder and truth labels — Fundamental's evidence discipline | | [`agent-safety-model.md`](agent-safety-model.md) | Agent-readable ≠ agent-writable; projections reveal, never mutate | | [`system-contracts.md`](system-contracts.md) | Bodies, forces, passports, truth modes | | [`api-stability.md`](api-stability.md) | The removal-protection contract — why FCI vocabulary is **not** forced into the public surface | | [`../research/README.md`](../research/README.md) | Fundamental's own paper family (the FCI-adjacent, self-authored research) | ## 1. The bounded claim The relationship is **methodological, not evidential**. Stated the way FCI states it: > Foundations of Computational Interaction studies the relations among declared systems, projections, > interpretation, opportunity, coupling, behavior, measurement, similarity, and strategy; Fundamental > makes a bounded subset of those relations executable, replayable, and inspectable. And the constraint that keeps it honest: > **Neither proves the other.** Fundamental is one possible research instrument for FCI; running a field > is not evidence that FCI's account is correct, and FCI's account is not evidence that Fundamental's > physics is right. Fundamental can make a *subset* of FCI's distinctions executable — projection, opportunity structure, interaction state, snapshot, replay, and comparison inputs. It cannot make the empirical ones (human interpretation, behavior, trust, accessibility outcomes, construct validity, causal identification) executable; those remain research claims that no implementation can manufacture. ## 2. Concept alignment Each row: an FCI concept, the Fundamental primitive that instantiates a bounded part of it, the file, and the current maturity. `protected` = on the removal-protected public surface (`scripts/api-surface.data.mjs`); `experimental` = shipped and callable but explicitly unfrozen; `planned` = designed, not built. | FCI concept | Fundamental primitive | Where | Maturity | |---|---|---|---| | Domain commitments | Body contract (`data-body`) + force **passports** | `contracts/passport.ts`; `system-contracts.md` | `data-body` protected; passports shipped | | System state / operational semantics | Field state + integrator + force pass | `engine/field.ts`, `engine/integrator.ts` | shipped | | Projection (governed transform to a representation) | **Projection Registry** + `setRender` / `setOverlay` | `engine/field.ts` (`projectionRegistry`); `substrate-api.md` | registry experimental; render protected entry, unprotected shape | | Projection contract (preserve / transform / omit / introduce) | Governance lint + accessibility-equivalent rules | `engine/governance.ts`; `05-projection-registry-governance.md` | MVP shipped; most rules planned | | Representation | Render surfaces (underlay / overlay / typographic) | `visualization-methods-taxonomy.md` | shipped | | Interpretation | *Out of scope for the runtime* — requires empirical study | — | not runtime | | Opportunity / affordance / action availability | **Field Agent Consumption Model** (influence → consumer) | `agent-consumption-model.md`; `forAgent` in `engine/field.ts` | model shipped; `forAgent` experimental | | Coupling (pathway that changes another's transitions) | **Forces** (the only coupling mechanism) | `dimensional-coupling.md`; `contracts/passport.ts` | shipped | | Interaction episode / trace | Snapshot + diff over frames | `engine/field-snapshot.ts` | experimental | | Measurement contract / truth modes | **Six truth modes** + truth labels | `contracts/passport.ts`; `causality-and-truth.md` | shipped | | Similarity / comparison | `diff()` + cross-plane conformance golden | `engine/field-snapshot.ts`; `parity-matrix.md` | experimental / shipped | | Scoped invariance (typed preservation across projections) | Cross-plane conformance golden + parity matrix (API / math / host) | `testing-and-conformance.md`; `parity-matrix.md` | shipped | | Evidence discipline (claim only the level your data supports) | **Causality ladder** (Observed → Attributed → Explained → Replayed → Predicted) | `causality-and-truth.md` | shipped framing | | Strategy | *Out of scope for the runtime* — latent, needs rival models | — | not runtime | | Representation-independence | `FieldHost` SPI + empty-allowlist boundary test | `engine/host.ts`; `engine/dom-boundary.test.ts` | shipped | | Field Query API (FCI names this as the readable surface) | `query()` — "the substrate's agent-/tool-readable surface" | `engine/field.ts`; `02-field-query-api.md` | experimental | Two names line up exactly rather than merely mapping: **projection** ("reveal state, never mutate it") and **coupling** ("the mechanism that changes another body's transitions"). Fundamental's lane discipline ("no word lives in two lanes") and FCI's ontology independently assigned these words the same meaning. That is the strongest single point of convergence. ## 3. Shared epistemic doctrines Beyond vocabulary, the two frameworks adopted the same governing rules under different names: | Doctrine | FCI form | Fundamental form | |---|---|---| | Presentation ≠ system | "semantic equivalence does not imply opportunity or behavioral equivalence" | "substrate, not wallpaper"; "projection reveals state; coupling changes state" | | Metric ≠ construct | "a metric is not a construct" | truth modes separate physical / designed / hybrid; a reading is not the thing | | Bounded claims | evidence ladder; "claims may stop at any level, must not skip levels" | causality ladder; "quote the highest level your data supports, and no higher" | | Comparison honesty | incomparability over a forced score | conformance golden with calibrated tolerance; parity is typed, not scalar | | Instrument ≠ proof | "Fundamental does not validate FCI" | this doc; `agent-safety-model.md` invariants | ## 4. What "sync" means — and what it does not **Sync means:** the concepts are documented as related; Fundamental's primitives carry an explicit FCI mapping; the public research framing (the `/writings` family, `/eli5` disclaimers) stays honest about what is built versus predicted. **Sync does not mean** importing FCI's vocabulary into Fundamental's public API. Three reasons, all already ratified in this repo: 1. **The removal-protection contract** ([`api-stability.md`](api-stability.md)) keeps the stable surface tiny (`createField`, patterns, hosts, `data-body`). Renaming or adding `opportunity` / `coupling` / `interaction-episode` as public symbols is a semver-relevant, opinionated decision, not a doc fix. 2. **FCI's own separation** — "neither proves the other" — is violated if Fundamental rebrands itself as "the FCI runtime." Fundamental is *one* instrument FCI may use. 3. **Lane discipline** — Fundamental already owns `projection` and `coupling` with FCI-compatible meanings. Adding more research nouns risks collapsing lanes the engine deliberately keeps separate. The alignment therefore lives in documentation and in the (already convergent) architecture, not in a rename of the running code. ## 5. Falsification Narrow or drop the claimed relationship if: - projection and source model cannot be separated in practice in the engine; - ports fail to preserve declared operational semantics (the conformance golden breaks); - projection contracts / governance lint add no diagnostic or experimental value; - opportunity structure cannot be enumerated reliably from `query()` / `forAgent()`; - a simpler architecture controls the same variables with less complexity. These mirror the falsification conditions in FCI's own framework statement. If any holds, this document should be revised before the relationship is repeated elsewhere. ======================================================================== FILE: docs/canonical/coordinate-spaces.md ======================================================================== > **Status: canonical (concept).** > The coordinate-space vocabulary: the distinct spaces field state lives in, and the one-way > conversions between them. This is *framing* — it names lanes so docs and code stop conflating > "screen pixels" with "field state." The host-boundary mechanics are in > [platform-architecture.md](platform-architecture.md); the substrate results that carry these > coordinates are in [substrate-api.md](substrate-api.md). Follows the > [status rule](documentation-standards.md). # Coordinate spaces A field is computed once and expressed many ways. That only stays coherent if we are precise about *which space* a coordinate is in. Fundamental keeps five spaces separate, and the conversions between them run **one direction each** — an adapter carries the host into the field; a projection carries the field back out. Never assume a number is in "the" coordinate space; ask which one. The canonical architecture statement ([documentation-standards.md](documentation-standards.md)) says the core imports zero DOM and routes the environment through an injected `FieldHost`. Coordinate spaces are the *why*: the host adapter is exactly the boundary where host space becomes field space, so the engine never sees pixels, points, world units, or rows — only field space. ## The five spaces | Space | What lives here | Owner | |---|---|---| | **Host space** | the raw units of whatever the field is bound to — CSS px, native points, Three.js world units, data rows, graph nodes | the host | | **Field space** | the single internal coordinate system the engine computes in — bodies, matter, forces, metrics | `Fundamental` (the core) | | **Projection space** | a named output surface's own units — a CSS custom property, a font-weight step, an aria string, an audio gain, a haptic level | a registered projection | | **Screen space** | device pixels actually composited — DPR-scaled, the canvas render surface | the render surface | | **Semantic space** | non-spatial axes of state — attention, confidence, memory, polarity | the semantic model | **Field space is the hub.** Everything converts *to* it on the way in and *from* it on the way out. The engine only ever reasons in field space; that is what lets one core drive a DOM canvas, a native `Canvas`, a Three.js scene, or a headless test with the same physics. **The consumer-facing consequence.** The position-taking handle methods — `flowTo(x, y)`, `burst(x, y)`, and the sampling reads (`sample`, `sampleField`, `atomAt`, `focusAt`) — all take their arguments in **field space**, and do **not** convert for you (they store/compare the raw `x, y` against particle positions directly). What field space *is* in host units follows straight from the adapter's origin: - A **window field** (`browserHost` / ``) has a zero origin, so field space **equals viewport space** — pass viewport pixels (a pointer event's `clientX`/`clientY` drop straight in). A document element's `getBoundingClientRect()` is viewport-relative, so a focus pinned to it must be **recomputed on scroll** as the element moves under the fixed field. - A **contained field** (`containerHost(el)` / `bounds`) carries the container's `left,top` as its origin, which the engine subtracts when it measures bodies — so args must be **container-local** (`clientX − rect.left`), not viewport. These local coordinates are **scroll-invariant**: the container and its contents move together, so a pinned focus stays put without recompute. The per-method contract, the "the methods don't translate for you" caveat, and worked window/contained examples live on the API page: [/docs/api/imperative#coordinate-space](https://fundamental-engine.com/docs/api/imperative#coordinate-space). ## The conversions (each one-way) ```txt host space ── adapter ──▶ field space ── projection ──▶ projection space └─ render ─────▶ screen space semantic space ── (only when mapped) ─▶ field space ``` - **Adapters convert host → field.** A `FieldHost` adapter measures the host (a DOM `getBoundingClientRect`, a native rect, a world-space bounds, a data row's derived position) and hands the engine field-space bodies. This is the *only* place host units enter. The DOM adapter is `browserHost()`; contained fields use `containerHost(el)`; native ports mirror it (`UIKitFieldHost`, the Android `View`/`Canvas` host). See [platform-architecture.md](platform-architecture.md). - **Projections convert field → projection.** A registered projection ([substrate-api.md](substrate-api.md)) reads field-space channels and writes a projection-space value: density → a `--field-*` CSS var, confidence → a font-weight step, attention → an aria description. A projection **reveals** state; it never writes back into field space (the substrate-05 governance principle: *projection reveals state; coupling changes state*). - **Render converts field → screen.** The render surface takes field-space positions and composites device pixels, applying DPR. Screen space is where fill-rate cost lives — never do physics here. - **Semantic → field only when explicitly mapped.** See below. The conversions do not compose into a round trip you can trust: field → screen → field loses precision (DPR, subpixel), and field → projection is often lossy on purpose (a continuous density becomes a three-step weight). Treat each arrow as one-way. ## Semantic dimensions are not spatial A dimension like **attention** or **confidence** is an *axis of state*, not a position. It has no x/y until a mapping gives it one. **Semantic space must not pretend to be spatial** unless a projection or adapter explicitly maps it: - Reading a body's `attention` as if it were a y-coordinate is a category error — it will "work" and be quietly wrong. - A semantic axis enters field space only through a declared mapping (an adapter that positions bodies by a data value, or a projection that expresses a dimension as motion/weight/color). - The accumulator's `semantic` channel ([substrate-api.md](substrate-api.md)) carries these axes as *contributions*, deliberately kept out of the `linear` (x/y/z) channel so nothing assumes force is spatial. This is the same discipline as the naming canon (*no word lives in two lanes*): a coordinate lives in exactly one space, and crossing spaces is always an explicit, named conversion. ## Why five spaces (the hosts that motivate them) | Host | Host space | Adapter's job | |---|---|---| | **DOM** | CSS px (layout viewport) | `getBoundingClientRect` → field bodies; write `--field-*` back | | **Native (UIKit/AppKit)** | points | measure native rects → field bodies | | **Three.js / RealityKit** | world units (3D) | project world bounds → field space; may keep a z channel | | **Headless** | none — synthetic bounds | supply bounds directly; no render/screen space at all | | **OS / desktop** | window/display px | window rects → field bodies | | **Data** | rows/records | derive a position or feed a semantic dimension | | **Graph** | nodes/edges | node → body, edge → relationship | The headless case is the clarifying one: with `render: 'none'` there is **no screen space**, yet field space, projection space, and semantic space all still exist and are fully inspectable. Coordinate spaces are a property of the *field*, not of the *pixels*. ## Related documents | Document | Role | |---|---| | [`platform-architecture.md`](platform-architecture.md) | The `FieldHost` boundary — where host space becomes field space | | [/docs/api/imperative#coordinate-space](https://fundamental-engine.com/docs/api/imperative#coordinate-space) | The consumer-facing contract for `flowTo`/`burst`/`sample` — window vs contained, scroll behavior, worked examples | | [`substrate-api.md`](substrate-api.md) | Field-space readings + projections that convert to projection space | | [`definition-document.md`](definition-document.md) | The operating model these spaces serve | | [`causality-and-truth.md`](causality-and-truth.md) | The dimension/metric/channel/projection lock these spaces depend on | ======================================================================== FILE: docs/canonical/coupling-discipline.md ======================================================================== > **Status: canonical.** > How to connect a system to the field **at scale** — the rung discipline, the sampling cadences, and > when *not* to make something a body. Measurements live in > [`../engine-reference/performance.md`](../engine-reference/performance.md); this document is the > decision procedure that sits on top of them. Related: > [`platform-architecture.md`](platform-architecture.md), [`system-contracts.md`](system-contracts.md). # Coupling discipline This is not theory. It was arrived at independently by two consumer projects — an ecological simulation and an operational airspace tracker — that each hit the same wall and each converged on the same rule. It is written down here because both had to discover it from scratch. ## The rule > **Couple through the field, but at the lowest rung that achieves the effect.** Adding or moving a body forces field work. Most things that *look* like they want to be bodies do not need to be — they need to *read* the field, which is far cheaper. Reserve emission for the few elements whose presence must change what everything else does. --- ## The three rungs ### Rung 1 — published global signals One value computed once per frame and read by everything. **Use when** the effect is uniform across the scene: a time-of-day term, a global wind vector, an ambient pressure that shifts every actor's baseline. **Cost:** one write, N cheap reads. This is nearly free and is the correct home for anything that does not vary by position. ### Rung 2 — local sensing (sample and cache) A moving agent asks the field what conditions are *at its own coordinates*, then interpolates between samples. **Use when** an actor must react to local conditions but need not change them — an aircraft reading wind, a particle reading density, a cursor reading attention. **Cost:** one sample per agent per *sampling interval*, not per frame. The interval is the whole point: sample at 8Hz, cache, and interpolate on the render tick. The engine already does this internally — body re-measurement runs on a **6-frame cadence**, and the quality governor stretches it to every 2nd frame at tier 2 and every 4th at tier 3 under load. **This is where most systems belong**, and where most systems mistakenly reach for rung 3. ### Rung 3 — persistent field emitters A body that alters the field, changing how everything else behaves. **Use when** the element's *presence* is the point: an attractor that pulls, a repulsor that deflects, a sink that absorbs. **Cost:** the highest, and it scales with count. Reconcile only when state actually changes — never rebuild an emitter per frame because its position moved a subpixel. --- ## Choosing a rung | The thing… | Rung | Why | |---|---|---| | affects everything uniformly | **1** | position-independent, so a body buys nothing | | reacts to local conditions | **2** | reading is orders of magnitude cheaper than emitting | | changes what others do | **3** | only emission propagates through the field | | is a high-frequency data point | **none** | keep it in your own arrays — see below | ## When not to use the field at all The field models **interface behaviour** — elements responding to each other in a composed layout. It is not a general simulation substrate, and pushing high-frequency telemetry through it is a category error rather than a performance bug. If you have hundreds of moving data points whose motion is determined by *your* domain math — flight paths, market ticks, sensor streams — keep them in plain arrays and render them directly to instanced geometry. Couple to the field only where the two genuinely meet: an attractor at a destination, a repulsor at a hazard, an attention term on selection. **For WebGL scenes specifically**, [`@fundamental-engine/three`](../../packages/three) runs the engine headless and renders its swarm as a `THREE.Points` layer, so field coupling and instanced telemetry coexist without either passing through the DOM. ## What the field costs, measured From [`performance.md`](../engine-reference/performance.md): the field is **fill-rate-bound, not particle-bound**. Drawing dominates; the math has enormous headroom — body re-measurement amortizes to roughly **1ms against a 16.7ms frame budget** across the density sweep, with no per-6th-frame spike. The practical consequence: adding bodies is rarely what makes a scene slow. Drawing them is. Reach for resolution and overdraw before you reach for body count. ## Reproducibility Anything built on rungs 2 or 3 that must replay identically has to respect the runtime's determinism envelope. Read it from the handle rather than inferring it: ```js field.guarantees // → { determinism: 'conditionally-deterministic', // controlledInputs: ['injected-rng', 'clock'], // uncontrolledInputs: ['host-geometry', 'body-ordering'], // requirements: [...], crossPlaneTolerance: 1e-6 } ``` `host-geometry` being uncontrolled is the one that surprises people: a scene replayed at a different viewport size is not guaranteed to reproduce. Pin geometry, inject the RNG, and hold `dt === 1` if replay parity matters. Cross-plane agreement is a **tolerance**, never bit-equality. ======================================================================== FILE: docs/canonical/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 patterns | | [`testing-and-conformance.md`](testing-and-conformance.md) | Testing and conformance | | [`wallpaper-rule.md`](wallpaper-rule.md) | The substrate-not-wallpaper rule made operational | ## 1. Definition ### Origin: putting a field around the DOM Fundamental began with a physics question: **what happens when a field surrounds the DOM and interface elements participate in it?** The DOM was the first host because it made the question concrete: the field could be shaped by actual interface elements, then return measurements that affect those same elements. This is the origin of the reciprocal principle, not a requirement that every field draw particles or imitate natural physics. The force catalog distinguishes modeled physical laws from designed interface behavior and semantic translations; see [truth modes](causality-and-truth.md) and the [field behavior table](fundamental-field-behavior-table.md). `Fundamental` is an inspectable field language for interfaces — and that inspection is now concrete: the running field is directly queryable, snapshot-able, diff-able, and replay-able as plain data (the [substrate API](substrate-api.md)), not only observed through CSS variables and render surfaces. 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. `@fundamental-engine/core` computes renderer-agnostic field behavior; host adapters bind that field to concrete platforms. `@fundamental-engine/dom` is the web host adapter, binding the field to the DOM (measurement, state, feedback, relationships, visual bindings, overlays, scheduling, linting); `@fundamental-engine/elements` and `@fundamental-engine/react` are authoring surfaces on top of it. The DOM is the first host, not the boundary — the same core runs headlessly and in the native Swift/Kotlin ports. 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. Its scope is additive to the host application. Fundamental can centralize cross-element relationships and field behavior that would otherwise be re-derived as view-specific glue; the application remains the authority for its records, domain rules, and permissions, while semantic HTML remains the canonical document for web content. Fundamental does not replace component frameworks or local state where those are the right model. **A field can render nothing, contain no particles, and still be complete:** if it has bodies, relationships, metrics, queryable state, and projections or feedback, it is a field. The runtime hierarchy makes this precise: ```txt Bodies REQUIRED participants Metrics REQUIRED readings Relationships OPTIONAL associations Particles OPTIONAL matter (one agent type, not the substrate) Projections OPTIONAL host surfaces ``` **The default field is calm.** No render surface, no surprise motion, no coupling, no body movement, no body-data exposure, and no projection mutation of field state — every one of those is opt-in. Calm is the baseline; expressiveness is chosen. **"Field" resolves at three levels — don't collapse them:** ```txt Computational Field the live runtime model: bodies, forces, metrics, relationships, particles, influences, state — it EXECUTES. Semantic Field the meaning layer: claims, sources, priorities, confidence, attention, risk, provenance — it EXPLAINS what the execution means. Projection Field the host-visible expression: CSS, native state, SVG, Canvas, haptics, sound, annotations, agent JSON — it REVEALS it. ``` ## 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/dom` owns DOM participation: it measures bodies, accumulates state, writes feedback, registers Shadow DOM, and resolves relationships. The legacy `engine/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); the engine loop has no direct CSS-variable write branch left — feedback flows through the registries (or the internal default sink). The one remaining element write-back in `engine/field.ts` is the layout-mode transform write for `data-move="layout"` bodies. `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/dom`, `@fundamental-engine/elements`, `@fundamental-engine/react`, `@fundamental-engine/vanilla`. The hard rename left no `compat-*` alias packages for the prior names — they are gone, and the test suite asserts their absence (see [api-stability.md](api-stability.md) §6). 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 ``` The `--forces-*` CSS-variable mirroring has been removed; `FeedbackRegistry` writes `--field-*` vars directly, and events are documented under the canonical `field:*` namespace. `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, patterns | | 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 `--d` as the primary feedback var and `--field-density` as its expressive long form (`--forces-density` has been removed). ## 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: docs/canonical/deprecation-plan.md ======================================================================== > **Status: canonical (policy) — the kept-vs-deprecated split and the `1.0` removal target are the > maintainer's recorded decision (#709).** > This document enumerates the **migration-era alias surface** still shipping for back-compat, gives > each alias a deprecation status, and pins its removal to `1.0`, consistent with the > [`SUPPORT.md`](../../SUPPORT.md) deprecation window. It exists so the "temporary" compat surface does > not silently become a permanent, forever-maintained API. Closes #709 (parent #738). > > Nothing is removed by this document — RC1 / `1.0` **ships every living alias**. This is the record of > what is intentionally temporary and where it goes. Related: [`api-stability.md`](api-stability.md) > (the removal-protection contract + the "Deprecation & removal policy" section), [`SUPPORT.md`](../../SUPPORT.md) > (the support/versioning policy). # Migration alias surface — deprecation & removal plan The `forces-ui → field-ui → Fundamental` rename was a **hard** rename: most of the old surface (``/`` tags, the `ForcesField`/`ForcesController`/`useForcesField` exports, the `--forces-*` CSS vars, and the `compat-core`/`compat-elements`/`compat-react`/`compat-vanilla` packages) is **already gone** — the test suite asserts its absence. What remains is a small set of **living aliases** kept so that consumers who migrated to `field`/`field-*` naming but still read old var names or import the old package name do not break. This plan covers those survivors. It does **not** reopen anything already removed. ## Kept permanently — NOT migration surface, NOT deprecated Two var pairs read like duplicates but are **canonical dual naming**, decided (#709) to be kept forever. They are not migration cruft and get **no** deprecation warning: - **`--d` and `--field-density`** — the canonical dual density naming. `--d` is the terse authoring name; `--field-density` is the spelled-out mirror. Both are permanent; author CSS may use either. - **`--load`** — the canonical sink-load channel. (It is `--mass` that is the deprecated alias *of* `--load` — see the table below — not the other way around.) ## The deprecation window (from `SUPPORT.md`) - A stable symbol is **deprecated** (kept working; marked in docs + a dev-only `console.warn` where it is a runtime call) for at least one release before it may be removed. - These aliases have shipped across the whole pre-`1.0` line (protected-and-additive), which satisfies the notice window. The decision (#709): **keep them through RC1, remove at `1.0`.** Because they are *passive mirrors* (an extra event, an extra var write, a re-export) rather than primary API, a consumer on canonical naming (`field:*`, `--d`/`--field-density`, `--load`, `@fundamental-engine/dom`) is unaffected by their removal. ## The living aliases (removed at `1.0`) | # | Alias | Canonical form | Where it lives | Dev warn? | Removal | |---|---|---|---|---|---| | 1 | `--mass` CSS var — *written* alongside `--load` (back-compat alias) | `--load` | `packages/core/src/engine/feedback-sink.ts` (~L47); also mirrored by `packages/elements/src/platform-runtime.ts` | No — a CSS var write is not runtime-observable to JS (CSS reads can't be intercepted); docs + release notes are the signal | **`1.0`** — stop writing `--mass` | | 2 | `` custom element — *registered* alongside `` | `` | `packages/elements/src/index.ts` (~L702) | Feasible (a `connectedCallback` warn) but not wired — low-cost registration mirror | **`1.0`** — stop registering (maintainer may bless it as permanent instead; call it at `1.0`) | | 3 | `@fundamental-engine/platform` package — re-exports `@fundamental-engine/dom` | `@fundamental-engine/dom` | `packages/platform/` (thin alias; `package.json` `description` says DEPRECATED) | **Yes** — one-time dev-only `console.warn` from the entry module on import | **`1.0`** — stop publishing | | 4 | `FieldRecipe` / `SceneRecipe` type — alias of `FieldPattern` (recipe → Pattern rename) | `FieldPattern` | `packages/core/src/recipes/schema.ts` | No — a `type` re-export has no runtime; the `@deprecated` JSDoc + docs are the signal | **`1.0`** — remove the alias | | 5 | `compileRecipe` value — alias of `compilePattern` | `compilePattern` | `packages/core/src/recipes/compile.ts` | No — a `const` re-export, no wrapper (matches the codebase's `@deprecated`-only convention); JSDoc + docs are the signal | **`1.0`** — remove | | 6 | `CompiledRecipe` type — alias of `CompiledPattern` | `CompiledPattern` | `packages/core/src/recipes/compile.ts` | No — `@deprecated` JSDoc | **`1.0`** — remove | | 7 | `FIELD_RECIPES` / `ESSENTIAL_RECIPES` / `FIRST_RELEASE_RECIPE_IDS` consts — aliases of `FIELD_PATTERNS` / `FIRST_RELEASE_PATTERN_IDS` | `FIELD_PATTERNS` / `FIRST_RELEASE_PATTERN_IDS` | `packages/core/src/recipes/catalog.ts` | No — `@deprecated` JSDoc | **`1.0`** — remove | | 8 | `EXPERIMENTAL_RECIPES` const — alias of `EXPERIMENTAL_PATTERNS` | `EXPERIMENTAL_PATTERNS` | `packages/core/src/recipes/wayfinding.ts` | No — `@deprecated` JSDoc | **`1.0`** — remove | | 9 | `applyRecipe` value + `ApplyRecipeOptions` / `AppliedRecipe` / `AppliedRecipeInspection` types — aliases of `applyPattern` / `ApplyPatternOptions` / `AppliedPattern` / `AppliedPatternInspection` | `applyPattern` (+ the `Pattern` types) | `packages/dom/src/apply-recipe.ts` | No — `const`/`type` re-exports, `@deprecated` JSDoc | **`1.0`** — remove | | 10 | phase-4 helper aliases — `BodyRecipe` / `RelationshipRecipe` / `AccessibilityRecipe` / `RecipeTier` / `RecipeStatus` / `RecipeProblem` / `RecipeTierGroup` / `RecipeRenderPlan` / `Recipe{Body,Relationship}Registration` / `RecipeFeedbackBinding` / `RecipeReducedMotionPlan` / `RecipeAuthoring` / `RecipeFieldTarget` (types); `RECIPE_TIERS` / `RECIPE_CONTRACTS` (consts); `validateRecipe` / `serializeRecipe` / `recipeById` / `recipeBodyAttributes` / `recipeRenderPlan` / `recipeToMarkup` / `recipeAuthoring` (fns); `bindData({ recipe })` option | the `Pattern`-named equivalents (`BodyPattern`, `PatternTier`, `validatePattern`, `patternById`, …; `bindData({ pattern })`) | `packages/core/src/recipes/*`, `packages/dom/src/{apply-recipe,bind-data}.ts` | No — `@deprecated` JSDoc / `const` re-exports | **`1.0`** — remove | > **Rows 4–9 (the recipe → Pattern rename, phase 1).** The concept "recipe" is renamed to **Pattern** > end-to-end; the protected public API (`FieldRecipe`/`compileRecipe`/`applyRecipe`) and the documented data > consts gain `FieldPattern`/`compilePattern`/`applyPattern`/`FIELD_PATTERNS`/… canonical names, with the > old names kept as `@deprecated` aliases (the same no-runtime-warn convention `SceneRecipe`/ > `ESSENTIAL_RECIPES` already use). Additive — nothing breaks pre-`1.0`. > > **Row #10 (phase 4).** The remaining internal helper surface (`BodyRecipe`→`BodyPattern`, > `RecipeTier`→`PatternTier`, `RECIPE_TIERS`→`PATTERN_TIERS`, `validateRecipe`→`validatePattern`, …) is > renamed with `@deprecated` aliases, and `bindData` gains a `pattern` option. The Swift + Kotlin ports > mirror the rename as a **clean rename (no aliases)** — they have no external consumers. Intentionally > kept as invisible plumbing (not concept surface): the `recipes/` source folder, `apply-recipe.ts`, the > `data/recipes.json` filename, and the `RelationshipSource` `'recipe'` value tag. **On row #1 (`--mass`) and CSS vars generally:** the engine *writes* the var; a CSS `var(--mass)` read happens entirely in the style engine and is invisible to JS, so there is no interception point for a runtime warning. This is doc-only by necessity (same for any CSS-var alias). The `--forces-*` vars are **already gone** (below), so `--mass` is the only CSS-var alias still shipping. ### Already removed (for the record — do not re-add) - `` / `` tags — not registered. - `ForcesField` / `ForcesController` / `useForcesField` exports — gone. - `--forces-*` CSS vars — gone. - `@fundamental-engine/compat-core` / `-elements` / `-react` / `-vanilla` packages — gone (removed at `0.7.0`). The `compat-*` "packages" the RC1 brief referenced no longer exist; the only living compat *package* is `@fundamental-engine/platform` (row #3). The absence of the above is asserted by the test suite; this plan does not change that. ### Event namespace note For the record: event names are canonicalized as `field:*`. The Shadow-DOM body-registration events (`REGISTER_BODY` = `field:register-body`, `UNREGISTER_BODY`, `UPDATE_BODY` in `packages/core/src/engine/shadow.ts`) were introduced under the `field:*` namespace and should stay there. ## Console-deprecation path (what warns at runtime vs. doc-only) `SUPPORT.md` says deprecation is "marked in docs + a dev-only `console.warn` **where it is a runtime call**." Some of these aliases are *passive mirrors* with no interception point, so only the observable ones warn: - **`--mass` CSS var (row #1) — doc-only.** The engine *writes* the var; a `var(--mass)` read happens in the style engine and is invisible to JS, so there is no interception point. Docs + release notes are the signal. (True for any CSS-var alias.) - **`` (row #2) — doc-only for now.** A `console.warn` on `connectedCallback` is feasible and is the one place a dev log would reach a consumer, but it is not wired (the tag may be blessed as a permanent secondary registration; decide at `1.0`). - **`@fundamental-engine/platform` (row #3) — WARNS.** The entry module emits a one-time dev-only `console.warn` on import, gated to `process.env.NODE_ENV !== 'production'`. ## RC1 / `1.0` shipping decision RC1 **ships all living aliases** — none are removed. The observable one (`@fundamental-engine/platform` package) carries a dev-only deprecation warning; the CSS-var alias (`--mass`) and the `` tag are doc-only. All are **removed at `1.0`**. This document, alongside the "Deprecation & removal policy" section of [`api-stability.md`](api-stability.md), is the record that they are *intentionally temporary*, not permanent API. The **consumer** upgrade guide (old form → new form, per alias) is [`migration-0.x-to-1.0.md`](../analysis/migration-0.x-to-1.0.md); the **maintainer** file-level removal inventory for the human cut (source sites, tests, cross-plane status) is [`1.0-removal-checklist.md`](../planning/1.0-removal-checklist.md). ======================================================================== FILE: docs/canonical/designed-vs-natural-map.md ======================================================================== # Designed vs. Natural — the shortcut map > **Status: canonical.** > This document is the foundational statement of *why the engine is shaped the way it is.* Every engine > concept stands in some relationship to what nature does: it either matches it, simplifies it the way > real simulators do, deliberately departs from it, or invents something with no physical analog. The > **departures are the source of the engine's flexibility** — a force unbound by a conservation law can > be bounded, calm, composable, and cheap. This map names the relationship for each concept so the > [truth-mode system](fundamental-field-behavior-table.md#truth-modes) (`physical` / `designed` / > `hybrid` / `semantic` / `poetic`) has a rationale, not just a label. It is descriptive of the shipped > engine; where it disagrees with the code, the code wins. The roadmap reading — which departures > become opt-in *Faithful* modes — lives in > [`../planning/substrate-architecture-frontier.md`](../planning/substrate-architecture-frontier.md). The > composition rules — how dimensions, fields, forces, relationships, and Field Patterns combine > (orthogonal-by-default, association ≠ coupling), plus the five-question method for reading any force — live in > [`dimensional-coupling.md`](dimensional-coupling.md). ## The four relationships Not every concept is a shortcut. Each cell below is tagged with one of: - **Faithful** — the engine does what nature does. This is where physics and good interface behavior happen to agree, and the engine gets physics' intuitive legibility for free. - **Idealization** — a legitimate physical simplification that real simulators (N-body codes, molecular dynamics) also make: point masses, infinite-mass anchors, force softening, neighbor cutoffs, 2D. - **Departure** — a deliberate, tuned break from physical law, for legibility, calm, or performance. **This column is the flexibility.** - **No analog** — behavioral or semantic; nature has no such force. Pure interface invention. ## A. The dynamics core (the integration loop) | Engine concept | What nature does | Relationship | What it buys | |---|---|---|---| | Force combination = linear sum | Superposition `F_net = ΣFᵢ` | **Faithful** | Correct by construction (why prioritized *allocation* would be the un-physical choice) | | Integrator (default semi-implicit Euler, opt-in `fixed` / `velocity-verlet`) | Continuous ODE; symplectic/Hamiltonian flow | **Departure** (default) / **idealization/partial** (opt-in Verlet) | Semi-implicit Euler (`v` first, then `x += v·dt`) is cheap and good enough; the per-step friction/decay makes it non-symplectic and non-conserving by design (count is the invariant); Verlet gives stable orbits. `legacy` ≡ `fixed` at `dt === 1`. | | Friction = ×0.95 post-step | Dissipative forces (Coulomb/viscous/quadratic) → heat (2nd law) | **Departure** | An interface that always settles; no static-threshold bookkeeping | | Velocity cap `|v|≤c` (12) | Relativistic limit; or terminal velocity from drag balance | **Departure** | A hard anti-blow-up rail; a non-physical clip | | Mass = nominal 1 (opt-in `a=F/m`) | Inertia always: `a=F/m`, `m ∝ matter` | **Departure** (default) / **Faithful** (opt-in) | Authors tune `strength` directly without reasoning about mass | | Recoil: absent by default, opt-in for dynamic bodies | Newton's 3rd law; momentum conserved | **Idealization** (default = infinite mass) / **partial** (opt-in) | Default: a body is a stable layout reference. A `data-authority="dynamic"` body recoils under the net field (shipped); own-emission reaction + inertial-mass ∝ area are the momentum frontier (#871) | | dt tied to rAF; compute every 6th frame | Continuous time | **Departure** | Large perf win; couples physics to render cadence | ## B. The force laws | Engine concept | What nature does | Relationship | What it buys | |---|---|---|---| | `attract`/`repel` bounded `(1−d/r)ⁿ` | Gravity/Coulomb unbounded `1/r²` | **Departure** | Finite range, no singularity — the flagship designed/natural split | | `gravity` softened `−GM r̂/(r²+ε²)` | True `1/r²` (singular) | **Idealization** | Plummer softening — a standard N-body technique | | `charge` signed `1/r²` | Coulomb's law | **Faithful** | Real polarity intuition | | `magnetism` 2D Lorentz (out-of-plane B) | Full 3D `F=q(v×B)` | **Idealization** | Dimensional reduction to the canvas; speed-preserving | | `collide` pairwise impulse + restitution | Elastic/inelastic collision | **Faithful** | Real momentum exchange — the one place recoil already lives | | `thermal` random kicks | Langevin / Brownian (fluctuation-dissipation) | **Faithful** | Genuine stochastic dynamics | | `pressure` SPH density relaxation | Fluid pressure / equation of state | **Faithful** (SPH is a real method) | Incompressible fill | | `propagate` wave radiation push | Wave equation / radiation pressure | **Faithful-ish** | Real wavefront behavior | | `viscosity` velocity damp | Viscous shear stress (Navier–Stokes) | **Departure** | A local "thickness" dial, not a stress tensor | | `swirl` tangential + 0.12 inward | Vortex / angular momentum (fluid) | **Departure** | A designed *spin* that reads as intent | | `tether`/`link` capped, damped spring | Hooke's law `F=−kx` | **Departure** | Bounded so it can't explode in a layout | | `lens` velocity rotation, speed-preserved | Gravitational lensing (spacetime curvature) | **Departure** | "Bending" without GR — a path deflector | | `wall` kinematic reflect ×0.85 | Rigid-boundary elastic collision | **Idealization** | A boundary with a restitution coefficient | | `sink` capture (count-conserving) | Gravitational accretion / absorption | **Departure** | Accretion without losing the count invariant | | `align` neighbor velocity match | — (flocking is biological) | **No analog** | Boids alignment as a verb | | `hunt` predator/prey | Lotka–Volterra population dynamics | **No analog** (ecology math, not a force) | Behavioral pursuit/evasion | | `diffuse` pheromone gradient | Fick's law / stigmergy | **Faithful-ish** (Fick) | Ant-trail emergence | | `memory` decaying deposit grid | — (hysteresis/sediment, no fundamental force) | **No analog** (semantic) | The field *remembers* | | `warp` teleport | — (wormholes speculative) | **No analog** (poetic) | An effect with no obligation to physics | ## C. The matter model | Engine concept | What nature does | Relationship | What it buys | |---|---|---|---| | Particle = point (optional z) | Matter has extent, shape | **Idealization** | Cheap; the classic point-mass abstraction | | No rotation / angular momentum / torque (angular *lane* exists, no producer) | Rigid bodies spin; angular momentum conserved | **Departure** | Particles have an opt-in `orient`/`spin` lane the accumulator captures (#855), but no shipped force writes spin (a public `torque` is deferred) — so nothing tumbles in practice yet (the *collapsed dimension* is restorable) | | Count = the one strong invariant | Conservation of mass / number | **Faithful-ish** | A guarantee the engine *can* keep, unlike energy/momentum | | Body position = DOM rect, re-measured | Position is evolved state | **Departure** | The body stays locked to its element — keeps layout coherent (and what recoil collides with) | | Body ≠ Particle (source vs consumer) | A body is just heavy matter | **Departure** (softening) | Lets an immovable emitter exist by default; a `data-authority="dynamic"` body already dissolves this (it moves under the field), and own-emission recoil (#871) closes the rest | ## D. Fields & representation | Engine concept | What nature does | Relationship | What it buys | |---|---|---|---| | Scalar grids (memory/heat/density) | Continuous fields (PDEs) | **Idealization** | Discretization — every field sim does it | | `relief` transport down a declared potential Φ = G·h | Gravity restricted to a surface: `a = −g∇h`, mass-independent | **Idealization** | The law is right, the mass model is not: the engine rescales an additive force's Δv by 1/m, so heavy matter slides slower than a slope allows. Also planar (phase 1) and read off a discretized raster of the host's channel. Deliberately not "Faithful" | | Neighbor cutoff radius (spatial hash) | Forces act at all distances | **Idealization** | O(N) not O(N²); screening/Debye length is even physically real | | Reciprocity via CSS-feedback loop | Direct mutual force (3rd law) | **Departure** | The field talks to the DOM through *style*, not motion — the platform-native trick | | Render optional / signals-first (`render:'none'`) | Phenomena are always "rendered" (physical) | **Departure** | Behavioral model as substrate, not spectacle — motion is one view | ## E. Conservation, units, space | Engine concept | What nature does | Relationship | What it buys | |---|---|---|---| | Energy not conserved (driven-damped) | 1st law: conserved in closed systems | **Departure** | Calm — the field always relaxes; energy *accounted* as heat/sparks | | Momentum partial (collide only) | Always conserved | **Departure** | Stable references | | Nominal units (`c=12`, `0.95`, px/frame) | SI; dimensional consistency | **Departure** | No unit reasoning for authors; blocks meaningful momentum *exchange* until fixed | | 2D default (z optional) | 3D + time | **Idealization** | The DOM/canvas is 2D; native planes prove 3D is possible when the surface allows | ## The thesis Read the **Departure** column top to bottom — bounded falloffs, post-step friction, the velocity clip, immovable bodies, the CSS-feedback loop, optional rendering, nominal units. **That column is the flexibility.** Each is a place the engine refused to be bound by physical law so it could be bound by *interface law* instead — legible, calm, composable, cheap, platform-native. A physics engine cannot make a button's importance a bounded well that vanishes at 240px; Fundamental can, precisely because `attract` is a *Departure*, not gravity. - **Faithful** rows borrow physics' credibility and legibility for free (charge polarity, collisions, thermal jitter, superposition). - **Idealizations** are ordinary simulation economics — the same ones real N-body codes make. - **No-analog** rows (`memory`, `warp`, `align`, `hunt`) are pure interface invention wearing physics' clothing. The truth-mode system is the engine being **honest about which column each force is in.** And the substrate roadmap is, in one sentence: *move a few of the highest-value Departures into opt-in Faithful versions* (a real integrator, real mass, real recoil) — **without losing the Departures that make this an interface engine rather than a physics toy.** See [`../planning/substrate-architecture-frontier.md`](../planning/substrate-architecture-frontier.md). ======================================================================== FILE: docs/canonical/dimensional-coupling.md ======================================================================== # Dimensional Coupling Doctrine > **Status: canonical / doctrine.** > How dimensions, fields, forces, relationships, metrics, diagnostics, and projections relate — and the > guardrails that keep the system *authorable* rather than *magical*. This is the construction rule for > re-expanding the [collapsed dimensions](designed-vs-natural-map.md) (depth, time, orientation). It sits > beside [`natural-fields.md`](natural-fields.md) (the conceptual grammar), > [`designed-vs-natural-map.md`](designed-vs-natural-map.md) (the truth relationship), the > [behavior table](fundamental-field-behavior-table.md) (the executable contract), and > [`feedback-channels.md`](feedback-channels.md) (the DOM output). Descriptive of intent; where it > disagrees with the code, the code wins. ## At a glance ```mermaid flowchart LR D["Dimension
axis of state"] --> F["Fields
structure over that axis"] F --> S["Superposition
net influence"] S --> A["Agents consume influence"] A --> R["Forces
reaction / state change"] X["Relationships
association"] --> Y{"Mapped by a Field Pattern?"} Y -->|No| Z["No dynamical effect"] Y -->|Yes| C["Coupling"] C --> R R --> M["Metrics
measured state"] M --> G["Diagnostics
explain cause"] M --> P["Projection
visible output"] CFG["Field Pattern / FieldPattern"] --> F CFG --> X CFG --> R CFG --> M CFG --> G CFG --> P ``` ## Association is not coupling The single most important distinction in the model: ```txt Association says two things are related. Coupling says one thing changes the other. ``` A **relationship** is a statement of association — it does **not** exert force just because it exists. A **force** is a dynamical effect — it couples state and causes change. A relationship may *later* feed a force, but only when a **Field Pattern** says so, explicitly. ```txt Citation A supports Claim B. ← association alone. Moves nothing. Evidence Field formation: ← the Field Pattern turns association into coupling. support relation → cohesion contradiction relation → charge separation confidence metric → gravity strength ``` This guardrail is what keeps the system **semantic and authorable rather than haunted.** Relationships are non-causal by default. ## The dimensional model A **dimension is an axis of state** — not a behavior, not a force. Each dimension may *host* fields, metrics, diagnostics, and response laws, but coexisting in the same runtime does not make dimensions affect one another. Dimensions include: `x/y` position · `z`/depth · time · orientation/rotation (θ) · and the semantic axes the field already carries — attention · memory · confidence. **The default rules:** ```txt Dimensions are orthogonal by default. Fields superpose within a dimension. Agents consume the net influence at their state. Relationships associate state without causing dynamical effect. Forces couple state and cause change. Cross-dimensional coupling is opt-in and must be named. ``` Said as a progression: **default independence → declared coupling → observable association → composed response.** Adding a dimension should not disturb existing behavior; it should only add *possible* couplings. ### A dimension is not a force Keep the layers distinct, or `time`, `memory`, `decay`, `prediction`, and `history` collapse into one fuzzy bucket: ```txt dimension the axis of state field structure over that axis force response to that structure (and the only mechanism of coupling) metric measurement from that axis diagnostic visualization / explanation of that axis projection how that axis is made visible in the interface ``` ### Within a dimension vs. across dimensions ```txt Within a dimension, fields superpose. Across dimensions, axes remain independent unless a coupling force connects them. Agents respond to the net influence at their state. Relationships can associate state without causing motion or mutation. ``` Note the sharpened claim: fields **do not usually affect fields** — they *accumulate into net influence*, and matter/agents respond to that net. (Field-affecting-field is nonlinear physics; the engine's linear superposition is what makes forces composable.) ## The concept table | Concept | Meaning | Example | |---|---|---| | **Dimension** | Axis of state | `x/y`, `z`, time, θ, attention | | **Field** | Structure over state | gravity well, charge field, memory grid | | **Force** | Response law (the coupling mechanism) | `F = ma`, `qE`, torque | | **Relationship** | Association without required motion | citation supports claim | | **Coupling** | Declared cross-axis effect | torque links translation to rotation | | **Metric** | Measured output | density, load, coherence | | **Diagnostic** | Explanation layer | field lines, causality, topology | | **Projection** | Makes a dimension visible | 3D → scale/blur/occlusion; time → trail/decay | ## The full picture ```mermaid flowchart TD A["Dimension
axis of state"] --> A1["Examples
x/y · z · time · orientation · attention · memory · confidence"] A --> B["Fields
structure over a dimension"] B --> B1["Examples
gravity well · charge field · memory grid · temporal kernel · orientation field"] B --> C["Superposition
fields add into net influence"] C --> D["Net influence at agent state"] D --> E["Agent / Consumer
thing that receives influence"] E --> E1["Particle
velocity · heat · capture"] E --> E2["Element
CSS vars · transform · events"] E --> E3["Relationship
strength · tension · memory"] E --> E4["Data record
salience · confidence · decay"] E --> E5["User / input
focus · pointer · selection"] D --> F["Force
reaction law / the coupling mechanism"] F --> F1["Changes state
motion · rotation · heat · decay · charge · capture"] G["Relationship
association"] --> G1["Relates without forcing"] G1 --> G2["claim supports source"] G1 --> G3["heading relates to section"] G1 --> G4["event relates to moment"] G1 --> G5["body relates to depth"] G --> H{"Does a Field Pattern
map relation into force?"} H -->|No| I["Association only
no dynamical effect"] H -->|Yes| J["Coupling
relation becomes force input"] J --> F K["Cross-dimensional effects
explicit and named"] --> K2["translation to rotation
torque (coupling)"] K --> K3["time to strength
decay / memory (coupling)"] K --> K5["confidence to gravity
semantic mass (coupling)"] K --> K4["depth to projection
scale / blur / occlusion (projection, not coupling)"] K2 --> F K3 --> F K5 --> F K4 --> L M["Field Pattern / FieldPattern"] --> M1["Authored mapping"] M1 --> B M1 --> G M1 --> F M1 --> N["Metrics"] M1 --> O["Diagnostics"] M1 --> L["Projection"] M1 --> P["Accessibility equivalent"] N --> N1["Expose state
density · load · coherence · confidence · memory"] O --> O1["Explain cause
field lines · causality · topology · prediction"] L --> L1["Make dimensions visible
CSS vars · SVG · Canvas · transform · typography"] P --> P1["Meaning survives without motion"] ``` > One correction from the source sketch: `depth → projection` is a **projection** (visual), not a > coupling (dynamical) — projection is deliberately *separate* from coupling, so it routes to Projection, > not Force. The rest of the cross-dimensional arrows are genuine couplings and route through Force. ## Coupling requires a passport declaration If a force couples dimensions, it declares so — the same way truth mode is declared — so the system stays **inspectable**. A new passport field: ```txt Couples dimensions: - none - x/y - x/y/z - translation → rotation - time → strength - memory → gravity - relation → charge ``` This is what makes the answer to *"why did this rotate?"* not "because the field did it" but: ```txt This body rotated because torque coupled translational force into angular velocity. ``` **Shipped (experimental):** `couplesDimensions?: readonly string[]` on the force passport, plus the `lintDimensionCoupling()` governance lint (`field/no-dimension-coupling-without-passport`) that enforces this declaration — a force that conserves speed (so it necessarily redirects velocity) must declare its coupling, or the lint errors. See [substrate-api.md](substrate-api.md). ## Dimensions need projections (separate from coupling) The DOM is mostly 2D and present-tense, so every added dimension needs an explicit **projection rule** — how its state renders back into the interface. **Projection is separate from coupling:** you can *visualize* a dimension without letting it *affect* another. ```txt 3D → screen position, scale, blur, occlusion, layering time → trail, heat, decay, ghost, replay, sediment orientation → transform, glyph axis, flow direction, alignment, torque indicator confidence → opacity, density, stability, topology, annotation ``` ## Construction rule for the collapsed dimensions The next frontier is **not another token — it is restoring dimensions of state the interface engine collapsed.** Each is built the same way: add the axis, keep it independent by default, name the coupling. - **Orientation.** Add θ and angular velocity as their own lane. Keep them independent by default. Introduce **torque** (`τ = r × F`) as the *explicit* coupling between translation and rotation. - **Time.** Add temporal coordinates and temporal fields. Do **not** let time "push back" by default (it is the independent evolution parameter — no closed timelike loops). Use decay, memory, prediction, replay, and scheduling as explicit **temporal kernels**. - **Depth.** Promote `z` from an optional lane to first-class state. Keep `x/y` behavior unchanged unless a 3D field, perspective projection, occlusion, or depth-aware force is enabled. ## Body-authority modes A body's *position authority* is itself a small truth-mode set — not one irreversible architecture choice. Three modes, each already partly present: | Mode | Authority | Status | |---|---|---| | **Anchored Body** | The DOM rect is authoritative; the body is a stable source / boundary / infinite-mass reference. | **Shipped** — the default (`element.getBoundingClientRect()` each frame; `definition-document.md`). | | **Kinematic Body** | The engine writes a transform; the DOM object moves *visually*, but motion is mediated through the platform layer. | **Shipped** — `data-move` (element impulse → `translate`; `agent-consumption-model.md`). | | **Dynamic Body** | The engine owns position, velocity, and possibly mass; DOM measurement *initializes or constrains*, but does not fully define body state. | **Future** — required for fully physical recoil. | The current system is therefore not *wrong* — it is **Anchored interface mode.** Recoil requires Dynamic mode (or Kinematic-with-readback), which is why the body-authority decision gates recoil (see the [substrate frontier](../planning/substrate-architecture-frontier.md)). ## On Field Pattern (without renaming the API) After this physics framing, "pattern" reads as casual — a cooking metaphor in a physics substrate. So the concept is being renamed end-to-end: the authored arrangement of forces is a **Field Pattern** (replacing the former "Field Pattern," which collided with the `setFormation` modes). The API `FieldPattern`/`compileRecipe`/`applyRecipe` ([`api-stability.md`](api-stability.md)) is renamed to `FieldPattern`/`compilePattern`/`applyPattern` with one-cycle **deprecation aliases** (the old names re-export and dev-warn, removed at 1.0 — see the Pattern rename epic). Lane separation still holds: ```txt Pattern the human-facing reusable behavior name Field Pattern the canonical field-native authored arrangement FieldPattern the current API representation of a Field Pattern Field Contract the compiled executable plan Configuration ordinary settings/options only Matter participants/substance only ``` > A `FieldPattern` is the API representation of a Field Pattern: a declared arrangement of semantic > intent, dimensions, bodies, fields, forces, relationships, metrics, diagnostics, projections, and > accessibility equivalents. A Field Pattern is more than a bundle of tokens. It is the authored arrangement that decides which associations become couplings, which dimensions participate, which forces act, which metrics are exposed, which diagnostics explain cause, and which projections preserve meaning. This terminology change does not rename any API symbol, route, catalog identifier, validator, or check. (The terminology decision — "Field Pattern" canonical, no API rename before a major-version migration — is tracked as a **board decision**.) ## Reading any force (the five-question method) To understand any force, ask: ```txt 1. Which Natural Field, if any, does it translate? (natural-fields.md) 2. What truth mode does it claim? (behavior table) 3. Is it faithful, an idealization, a departure, or no-analog? (designed-vs-natural map) 4. What does field() expose? (invisible structure) 5. What does apply() change — and does it couple dimensions? (the cause + the coupling passport) ``` `field()` returns invisible structure; `apply()` causes change. That distinction is load-bearing — keep it visible. ## The core doctrine ```txt Fields describe structure. Forces create coupling. Relationships declare association. Metrics expose state. Diagnostics explain cause. Projections make dimensions visible. Field Patterns decide which associations become couplings. ``` ```mermaid flowchart TD A["Fields describe structure"] --> B["Forces create coupling"] C["Relationships declare association"] --> D["Field Patterns decide whether association becomes coupling"] E["Metrics expose state"] --> F["Diagnostics explain cause"] G["Projections make dimensions visible"] D --> B B --> E E --> G ``` ======================================================================== FILE: docs/canonical/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. @fundamental-engine/core computes renderer-agnostic field behavior. Host adapters bind field behavior to concrete platforms. @fundamental-engine/dom is the web host adapter: it binds the field to the DOM through measurement, state, feedback, relationships, visual bindings, overlays, linting, and scheduling. Canvas is one render surface, not the whole system. ``` `@fundamental-engine/elements` and `@fundamental-engine/react` are authoring surfaces **on the DOM host** — reserve "for the DOM" for the web host adapter and the surfaces built on it, not for the runtime as a whole. The DOM is the first host, not the boundary of the system: the same core can run headlessly, in native views (the Swift/Kotlin ports), or against any host adapter that supplies body geometry, identity, a tick, and a feedback sink. Fundamental creates **one shared field context** across bodies, agents, relationships, measurements, metrics, feedback, particles, and render surfaces. Canvas, SVG overlays, and DOM feedback are each a render surface; a host adapter is the participation layer for its platform; 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 **host ⇄ field runtime** (on the web, **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`. **The substrate-not-wallpaper line is enforceable doctrine, not a slogan** — the test, remedies (derive → declare → demote → sugar; never deletion), corollaries (injected-rng determinism, one-writer-per-reading, proofs-must-be-produced), and per-plane guards live in [the Wallpaper Rule](wallpaper-rule.md). Run any new default-on or field-expressing feature through its three prongs before shipping it. ## 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/dom · @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/concepts#natural-fields) ``` `Fundamental` imports **zero DOM** — the engine routes the environment through an injected `FieldHost`; `browserHost()` lives in `@fundamental-engine/dom`, 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 `--forces-*` CSS-variable mirroring has been **removed** — `--d` and the `--field-*` family are the live vars. Event naming is canonicalized as `field:*` in docs and examples. The density channel has a canonical raw form and an expressive long form — do not invert them: ```txt --d canonical raw live density channel (engine writes it; prefer it in examples) --field-density the field-namespaced expressive long-form alias of --d --load canonical sink fill --mass legacy alias of --load ``` Write `--d, with --field-density as the field-namespaced alias` — never `--field-density, alias --d`. 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. **The four words mean different things — never let one imply another:** ```txt Shipped callable and code-confirmed Shipped-unprotected / experimental callable and code-confirmed, but NOT on the protected surface — shape may change Canonical conceptually authoritative (a concept/term/doctrine), which says nothing about API stability Stable on the removal-protected public API (check:api gates it) ``` "Canonical" never implies "stable"; "shipped" never implies "protected." The substrate read API (`query`/`snapshot`/`diff`/`replay`, the projection registry, body authority, dynamic recoil, integrator modes, accumulator channels) is **shipped and documented, but experimental and unfrozen** — repeat that phrasing everywhere it appears. **Section-level labels.** Prefer a status label at the *section* level, not only the document level, so a mostly-canonical doc can carry a `Status: frontier` subsection without misleading the reader. Label vocabulary: `shipped` · `shipped-unfrozen` · `experimental` · `canonical concept` · `planned` · `frontier` · `speculative`. ## Source-of-truth hierarchy When two descriptions disagree, this is the authority order (higher wins): ```txt 1. Code + tests determine shipped behavior 2. api-stability.md determines the protected surface 3. Canonical docs determine concepts, terminology, contracts 4. Generated site docs mirror canonical docs + code (not a source) 5. llms.txt / llms-full generated reference, never a source 6. Planning / archive non-authoritative (history and forward-looking) ``` Generated artifacts (`llms.txt`, site pages) must be regenerated from source, never hand-edited to diverge from the canon they mirror. ## Terminology locks Words that sit close enough to collide. Keep them apart: ```txt Lens how the field is READ (scopes/filters a reading; pure, over any FieldQueryResult) Projection how the field is REVEALED (writes to a declared host output surface; never to a force) Pattern how the field is AUTHORED (a Field Pattern — the composed arrangement of forces) Contract how the Pattern EXECUTES (a Field Contract — the compiled plan; API type FieldRecipe, mid-rename → FieldPattern) ``` - **Field Pattern** vs **formation mode.** The authored concept — a named composed arrangement of forces that yields a characteristic behavior — is a **Field Pattern** (renamed from the former "Field Formation," which collided with the modes below; the colloquial "recipe" is retired too, end-to-end — the API `FieldRecipe`/`compileRecipe` become `FieldPattern`/`compilePattern` with deprecation aliases, see the Pattern rename epic). Separately, `ambient`/`wells`/`lanes`/`scatter`/`accretion` are *formation modes* set via `setFormation(...)`. With the concept now "Pattern," the bare word "formation" refers only to these global modes — the collision is gone. - **Field Agent** vs **Software Agent.** A *Field Agent* is a runtime participant that consumes influence (particles are the lightest). A *Software Agent* is an external actor/tool that reads or operates on field state. A software agent may read Field Agents through `query()`/`snapshot()`; it is not itself a Field Agent unless registered as a body/consumer. Agent-readable does **not** imply agent-writable. - **data body** vs **`body.data`.** `body.data` is opaque metadata attachable to *any* body. A *data body* is a body whose primary host object is a semantic record (claim/task/file/…). Attaching `data: {…}` does not by itself make a body a data body. - **Field Contract** vs **system contract.** A *Field Contract* is the compiled executable plan from a `FieldRecipe`. A *system contract* is a broader platform invariant/guarantee. "Contracts execute" refers to Field Contracts only. ## The frame ``` The old story: Fundamental is a particle field behind the DOM. The new story: Fundamental is a platform-native relational field runtime; the DOM is its first host. Natural fields: Four fields. Many expressions. One field runtime, many hosts. ``` ======================================================================== FILE: docs/canonical/feedback-channels.md ======================================================================== # Feedback Channels **Status:** Shipped (0.9.x). Authoritative specification. This is the canonical feedback-vars reference — the one place the density story is told correctly. CSS custom properties are the engine's primary output channel. The engine writes values onto elements during the `write` phase of every frame; the page's own CSS reads them to produce visible reactions. No polling, no event listeners, no separate state — the engine is a CSS property writer and the page is a CSS property reader. > **Density is one value on two variables — they are CONSISTENT.** `--d` and `--field-density` > hold the **same** eased live-density number, written together by the feedback sink > (`packages/core/src/engine/feedback-sink.ts` — both `setProperty` off the one `ch.density`). > `--d` is the canonical, compact working channel; `--field-density` is its namespaced twin. > Read **either** — they never disagree. > > `--field-density` is **not** a "legacy alias," and neither is `--d`. There was a real bug > (now fixed): `applyRecipe()`'s metric pipeline used to bind a pattern's `density` metric onto > `--field-density`, overwriting the engine's live write with the host-supplied > `data-field-density` attribute (absent → `0`), so `var(--field-density)` read `0` while `--d` > held the value. The fix (`packages/dom/src/apply-recipe.ts` — the `ENGINE_OWNED_METRICS` set) > **excludes `density` from the pattern metric pipeline**, so the engine's live write is > authoritative and `--field-density === --d` on every element, recipe-driven or not. The old > advice "prefer `--field-density`; `--d` is the legacy alias" was doubly wrong — it named the > broken variable as primary *and* mislabelled the working one as legacy. Neither is legacy; > both are current; use whichever reads better in your stylesheet. --- ## 1. Channel types There are three categories of engine-written CSS properties: | Category | Where written | Driven by | |---|---|---| | **Body feedback** | `[data-feedback]` elements | Engine per-body particle density | | **Pattern metric** | `[data-feedback]` elements | Declared pattern metric pipeline | | **Environment / root** | `:root` | Scroll state, global field presence | --- ## 2. Body feedback channels Written on every element carrying `[data-feedback]`, every frame: | Variable | Range | Semantics | |---|---|---| | `--d` | 0 → 1 | Live local particle density gathered around this body, eased. **The canonical reaction variable.** Rises toward 1 when a `data-hot` body is held; eases back on release. | | `--field-density` | 0 → 1 | The namespaced twin of `--d` — **the same value**, written in the same sink call. Consistent, not legacy; read either (see the density note above). | | `--field-heatmap-density` | 0 → 1 | The heatmap ambient density *under* this body — where matter pools around it globally, distinct from the body's own `--d`. Only present when the heatmap overlay is active. | | `--load` | 0 → 1 | A sink body's accretion fill fraction. 0 = empty, 1 = saturated. Written when the body has `data-absorb`. | | `--mass` | — | **Retired.** A former alias of `--load`; **no engine path writes it any more** (neither `defaultFeedbackSink` in core nor `makeFeedbackSink` in the platform runtime — both write `--load` only). `var(--mass)` therefore reads its CSS fallback, never a live value. The name is still reserved in `ENGINE_OWNED_FEEDBACK_VARS` so a *binding* that sets it is linted. Style off `--load`. | | `--lit` | 0 → 1 | Spillover-lit density when a saturated neighbouring sink bleeds density across a boundary (causality). | | `--entropy` | 0 → 1 | Local disorder — velocity-direction dispersion, gated by agitation. Distinct from the platform-inferred `--field-entropy` pattern lane. | | `--coherence` | 0 → 1 | Local order (= 1 − entropy; velocity alignment). Numeric value — not the `--coherence` palette colour on `:root`. | | `--temperature` | 0 → 1 | Local agitation — half mean heat, half normalised kinetic energy. | **Enabling feedback on an element:** ```html

The field is around me.
``` Without `[data-feedback]`, the engine scanner does not register the element as a feedback target and the vars are never written onto it. --- ## 3. The `--field-` pattern lanes — and their provenance When a pattern declares `metric` lanes, `applyRecipe()` writes each as `--field-` on the bound `[data-feedback]` element during the `write` phase — **alongside** (never instead of) the engine body-feedback vars in §2. The `--field-` namespace is reserved for these lanes; don't author custom properties into it on the same elements. There are **nine** metric lanes (`METRIC_KINDS`, `packages/dom/src/metrics.ts`), and they split by **provenance** — this is the engine-written vs host-supplied distinction that governs the whole feedback surface: | Lane (`--field-`) | Provenance | Written by | |---|---|---| | `--field-attention` | **computed** | The engine each frame — proximity + engagement. | | `--field-memory` | **computed** | The engine each frame — engagement decay. | | `--field-coherence` | **computed** | The engine each frame — from relationship resolution + age. *(Distinct from the engine-measured `--coherence` in §2, which is velocity alignment on the body.)* | | `--field-entropy` | **computed** | The engine each frame — inferred disorder. *(Distinct from the measured `--entropy` in §2.)* | | `--field-pressure` | **computed** | The engine each frame — relationship/age pressure. | | `--field-recency` | **computed** | The engine each frame — interaction recency, **grounded** to world time when the body declares `data-field-at` (then `freshness(at, now, halfLife)`). | | `--field-priority` | **computed** | The engine each frame — derived importance. | | `--field-confidence` | **supplied-only** | The **host** — present ONLY when supplied (`data-field-confidence` / pattern option / domain model). The engine never infers it: a citation is not certainty. | | `--field-risk` | **supplied-only** | The **host** — present ONLY when supplied. Never defaulted to `0`: "no risk" is a claim, not a safe blank. | A third provenance class, **designed**, covers any *other* `--field-` a pattern references (e.g. `signal`, `route-strength`, `sync`): the host must supply it via `data-field-`, and with neither a supply nor a computed source the lane is **inert** — declared but never written. `classifyMetric(name)` returns `computed` / `supplied-only` / `designed`, and the `lintInertFeedback` rule (in `lintPlatform`) flags a binding to a designed lane the host never supplies — the same silent-contract class as `lintSinkFeedback`. **The rule of thumb:** if a var is engine-**written**, style off it directly. If it is host-**supplied** (`confidence` / `risk` / any designed lane), you must feed it — reading it without supplying it gets you the CSS fallback, never a live value. --- ## 4. Environment / root channels Written on `:root` by the platform's write phase: | Variable | Semantics | |---|---| | `--field-scroll-v` | Eased scroll velocity (px/frame). Used to gate conditions (`< 2.0` = reading pace). Updated every frame; deduped when unchanged. | | `--field-presence` | 1 when the page field is active, 0 when it is paused (backgrounded tab, reduced motion). Use to fade field-only decorations gracefully. | --- ## 5. Consuming feedback — patterns ### 5a. The amplification pattern `--d` is a fraction in [0, 1] — small by design. Scale it before driving visual properties: ```css [data-feedback] { /* scale the raw fraction into a usable 0..1 range with a hard ceiling */ --d-amp: clamp(0, calc(var(--d, 0) * 12), 1); } .hero-mass { /* react off the amplified value, not the raw fraction */ transform: translateY(calc(var(--d-amp) * -8px)); opacity: calc(0.4 + var(--d-amp) * 0.6); } ``` Don't bake the magic-12 amplifier into every consumer — keep it in one `[data-feedback]` rule so tuning it in one place tunes every reaction. ### 5b. Sink fill A sink body with `data-absorb` and `data-max` exposes `--load`: ```html
``` ```css .queue-indicator::after { content: ''; width: calc(var(--load, 0) * 100%); /* grows as the sink fills */ background: var(--accent); } ``` ### 5c. Reading-pace gate Gate a progressive behaviour on slow scroll (the reading-pace condition): ```css /* hide ambient glow while scrolling fast; reveal it only at reading pace */ .ambient-glow { opacity: 0; transition: opacity 0.4s; } @supports (animation-timeline: scroll()) { .ambient-glow { /* the field writes --field-scroll-v on :root every frame */ opacity: calc(max(0, 1 - var(--field-scroll-v, 99) / 2)); } } ``` Or in markup with `data-when` (engine-evaluated): ```html
``` --- ## 6. The data-feedback requirement Only elements with `[data-feedback]` receive per-body CSS-var writes. This is by design: writing CSS properties on every `[data-body]` would be expensive at scale. **Common mistake:** adding `data-body` and expecting `--d` to arrive — it won't without `[data-feedback]`. The lintPlatform check (`pnpm check:cem`) catches the missing attribute. A body can be a force source (`[data-body]`) and a feedback receiver (`[data-feedback]`) on the same element, or they can be separate elements in the same region: ```html
``` --- ## 7. Platform vs engine writes — the split | Written by | Source | Cadence | |---|---|---| | Engine (core) | Particle density computation | Every frame (frame-rate) | | Platform (dom) | `[data-feedback]` write registry | Every frame, write phase only | | Pattern pipeline | `applyRecipe()` metric lanes | On pattern apply + body re-measurement | | Root platform | Scroll velocity, field presence | Every frame, deduped | The six-phase scheduler enforces the split: the `write` phase happens after `compute` and `state`, so CSS properties are always written from a stable, post-simulation snapshot. **`density` is engine-owned, not a pattern lane.** Even when a pattern declares a `density` metric, `applyRecipe()` **does not** bind it into the metric pipeline — the `ENGINE_OWNED_METRICS` set (`packages/dom/src/apply-recipe.ts`) excludes it, so the engine's live per-frame write to `--d` / `--field-density` stays authoritative. This is the fix behind the density note at the top: a pattern can no longer clobber the live density value with a host attribute default. --- **Two writers, one var — linted.** The engine-written vars (`--d` / `--field-density` / `--field-heatmap-density` / `--load` / `--lit` / `--entropy` / `--coherence` / `--temperature` — plus the retired `--mass`, kept in the set so an old binding to it is still caught) have exactly one writer. A feedback *binding* that routes any state key onto one of them (`platform.feedback.bind(el, { density: '--field-density' })`) is a second writer, and the bound state value shadows the engine's live reading — the `--field-density`-reads-0-while-`--d`-is-live collision, from a route `ENGINE_OWNED_METRICS` does not cover. The `feedback-var-engine-owned` platform lint (`lintFeedbackEngineOwned`, run by `lintPlatform()`) flags every such binding; the fix is to bind a `--field-` lane of your own. The set is exported as `ENGINE_OWNED_FEEDBACK_VARS`. ## 8. The same channels on Swift and Kotlin This document is written in CSS because the web *delivers* feedback as CSS custom properties. The **channels themselves are not a web concept.** The engine produces one plain-data record per opted-in body per frame — `FeedbackChannels` — and every plane produces the *same seven fields*: | Channel | Web CSS variable(s) | Swift | Kotlin | |---|---|---|---| | `density` | `--d` + `--field-density` | ✓ | ✓ | | `heatmapDensity` | `--field-heatmap-density` | ✓ | ✓ | | `load` | `--load` | ✓ | ✓ | | `lit` | `--lit` | ✓ | ✓ | | `entropy` | `--entropy` | ✓ | ✓ | | `coherence` | `--coherence` | ✓ | ✓ | | `temperature` | `--temperature` | ✓ | ✓ | Sources: `packages/core/src/engine/types.ts` (`FeedbackChannels`), `swift/Sources/FundamentalCore/Engine/FieldHandle.swift`, `android/fundamental-platform/.../Registries.kt`. The set is generated into the `feedback-channels` dimension of `data/parity-matrix.json` and rendered as support rows on [`/docs/api/declarative`](https://fundamental-engine.com/docs/api/declarative); `pnpm check:docs` fails if a plane gains or loses one. **What differs is DELIVERY, and it is the thing to know before porting a design:** | Plane | How the channels reach you | |---|---| | **JS / DOM** | CSS custom properties written onto the element (`defaultFeedbackSink`), or your own `feedbackSink`. A reaction is written in CSS and never touches JavaScript. | | **Swift** | The `onFeedback: (FeedbackChannels) -> Void` closure — on `BodySpec`, and directly on the `.fieldBody(…)` SwiftUI modifier — or a `FeedbackSink`. | | **Kotlin** | A `FeedbackSink` / the `StateRegistry` on the platform layer. **`Modifier.fieldBody` carries no per-body callback and `BodySpec` has no `onFeedback` field** — this is a real gap, not an idiom difference: Compose has no per-body feedback seam today. | The practical consequence: a web design that leans on "the engine writes, my CSS reads" has no one-line Compose equivalent. Route the Kotlin side through the platform `FeedbackSink` and drive your own state from it. ## 9. Related documents - `docs/canonical/invisible-fields.md` — the invisible-fields pattern: the two-field architecture, data-hot + data-active engagement, relationship edges, provenance chips. - `docs/canonical/platform-architecture.md` — the six-phase scheduler and six registries. - `docs/engine-reference/forces-system.md` §19 — the write phase specification. - `apps/site/src/lib/docs-api.ts` → `WRITEBACK[]` — the live enumeration of all feedback vars. - `/docs/api/declarative` — the declarative authoring reference; the channels with generated per-platform support rows, alongside the rest of the markup surface. ======================================================================== FILE: docs/canonical/field-possibilities.md ======================================================================== # Field Possibilities > **Status: canonical / possibility space.** > This document describes what Fundamental can become beyond the current implementation. It is not the > source of truth for shipped behavior — that lives in the package code, conformance tests, and the > other canonical docs. This document exists to keep the wider idea space coherent and to give the > shipped use cases their conceptual grounding. > > **Relationship to use-cases.md.** [`use-cases.md`](use-cases.md) is the shipped, narrative tier — > concrete UI problems and how the field solves them today. This document is the conceptual framework > beneath it: conditions, formations, pattern families, natural field translations, matter primitives, > temporal fields, and alternative output surfaces. When a section here has a concrete shipped > implementation, it links to the relevant use-cases section. Sections §26–§36 are > **`[frontier]`** — not yet shipped; they define the research and long-range possibility space. > > **Vocabulary note (concepts vs runtime tokens).** Possibility language here is not the engine token > set. The 36 real runtime tokens live in the [forces catalog](../engine-reference/forces-system.md). > Concept words map to them: `vortex→swirl`, `drag→viscosity`, `emitter→spawn`, `spring→tether`, > `reflect→wall`, `absorb→sink`, `phase`/`decay`→`morph`/`memory`. `mass` is a metric, `potential` a > diagnostic; `fuse`/`fission` are not yet implemented (`warp` ships the wormhole-throat behavior). ## 0. Purpose Fundamental is not a particle background. It is a platform-native relational field runtime; the DOM is its first host, not its boundary. The system lets semantic HTML, DOM elements, particles, relationships, measurements, metrics, feedback, visual layers, and user interaction participate in one shared field context. The purpose of this document is to describe the possibility space opened by that model. Not just: ```txt What forces can we add? ``` But: ```txt What new kinds of interfaces become possible when meaning has field behavior? ``` ## 1. The paradigm shift Most interface systems are organized around isolated component state. ```txt component owns state state changes class class changes style animation decorates transition ``` Fundamental introduces a different model: ```txt interface owns a shared field bodies emit influence agents respond metrics accumulate diagnostics explain feedback returns state to the DOM ``` The possibility space begins there. A button can still be a button. A heading can still be a heading. A citation can still be a citation. A form can still be semantic HTML. But those elements can also participate in a field. They can have priority, polarity, binding, transformation, memory, coherence, pressure, entropy, heat, attention, and relationship strength. The interface becomes a shared, inspectable field of meaning. ## 2. Current doctrine The current architecture should guide every possibility. ```txt Fundamental host-driven, renderer-agnostic field engine @fundamental-engine/dom browser host, DOM participation, measurement, state, feedback, relationships, visual bindings, overlays, scheduling, linting @fundamental-engine/elements native HTML and web component authoring @fundamental-engine/react React adapter over the same contracts ``` Canvas is one render surface. SVG overlays are one render surface. DOM feedback is one render surface. Diagnostics are one explanation surface. The system is larger than the canvas. ## 3. The Natural Field Translation System The old language of “natural primitives” is too flat for the current model. The possibility space should start from the four natural fields: ```txt Gravity Electromagnetic Strong Weak ``` Translated into interface behavior: ```txt Gravity -> priority, convergence, hierarchy Electromagnetic -> polarity, signal, field lines, flow Strong -> binding, cohesion, structure Weak -> transformation, decay, release ``` This is the organizing frame. Natural fields are conceptual. Engine primitives are translations. Canonical forces are designed verbs. Derived behaviors are not additional fundamental forces. Fieldflow is transport along field structure. Diagnostics reveal invisible structure. Field Patterns compose behavior into interface meaning. FieldPattern is the current API representation of a Field Pattern. Short version: ```txt Natural fields are not tokens. Tokens are translations. ``` ## 4. Designed forces and natural translations The system should preserve the distinction between designed interface forces and natural translations. Designed UI forces exist because interfaces need readable, bounded behavior. Real designed tokens (shipped): ```txt attract repel swirl stream viscosity jet tether wall sink ``` Concept words map onto them (a concept is not a token): `vortex→swirl`, `drag→viscosity`, `spring→tether`, `reflect→wall`, `absorb→sink`, `emitter→spawn`. These are interface verbs. They are stable, legible, and composable. Natural translations exist because some behaviors benefit from physical coherence. Examples: ```txt gravity charge magnetism cohesion morph memory propagate fieldflow ``` These express the four natural fields or their derived effects. (`morph` is the shipped transformation token; `phase`/`decay` are concept words for it.) Important distinctions: ```txt attract is not gravity repel is not charge charge and magnetism are electromagnetic expressions fieldflow is not magnetism fieldflow is transport ``` Preserve the electromagnetic rule: ```txt Electric fields push. Magnetic fields bend. Fieldflow carries. ``` ## 5. Possibility categories The old possibilities document was mostly a force, formation, condition, and render menu. The new version should be broader. The possibility categories are: ```txt conditions formations patterns relationships input agents data fields render surfaces diagnostics accessibility equivalents platform bridges natural-field expansions AI evidence fields authoring tools research artifacts ``` Each possibility should answer: ```txt What relation does this reveal? Which natural field does it translate? Which engine primitives might express it? Which platform registry owns it? How is it inspected? What is the reduced-motion equivalent? ``` ## 6. Conditions → *Shipped use cases: [use-cases.md §I](use-cases.md#i-universal-ui-patterns) (error gravity — `coherent`; reading weight — `dwell`; completion momentum — `coherent`), §II (urgency sorting — `stale`, `thresholded`; anomaly field — `thresholded`), §IX (staleness gradient — `stale`; dwell-driven mastery — `dwell`), §X (trust gradient — `trusted`; evidence field — `trusted`).* Conditions decide when a body, pattern, or relationship becomes active. The older condition list remains useful, but it should be renamed into field-state language. Possible conditions: ```txt near dense sparse aligned aging charged species dwell pointer-fast schedule inview focused selected related trusted conflicted stale unstable coherent thresholded ``` Examples: ### dwell A section, card, or control becomes active after sustained attention. Use for: ```txt Reading Field Ambient Tutor Memory Trace Context Halo ``` ### related A body acts only when the active element is related to it through the RelationshipRegistry. Use for: ```txt Citation Thread Evidence Field Relationship Bond Relation Lens ``` ### trusted A claim, source, or result acts only when it passes a confidence or verification threshold. Use for: ```txt Trust Gradient Evidence Field Source Constellation AI review surfaces ``` ### stale A document, data record, task, or notification acts when age or recency decay crosses a threshold. Use for: ```txt Staleness Drift Review Pressure Decay Notice Priority Tide ``` ### coherent A workflow, form, or group acts when enough of its relationships stabilize. Use for: ```txt Coherence Field Form Stability Field Completion Release Consensus Well ``` Conditions should not spam DOM events. Continuous state belongs in CSS variables and platform state. Discrete transitions belong in thresholded events. ## 7. Global formation modes > Two senses of "formation" live nearby — keep them apart. A **global formation mode** (a.k.a. > *field-shape mode*) is a whole-field bias set via `setFormation(...)`: `ambient`, `wells`, `lanes`, > `scatter`, `accretion`. A **Field Pattern** is the authored, recipe-backed conceptual arrangement > named by *meaning* (`reading`, `evidence`, `conflict`, …). This section is about the *modes*; the > named `reading`/`evidence`/… Field Patterns below map to `FieldPattern` records. → *Shipped use cases: [use-cases.md §I](use-cases.md#i-universal-ui-patterns) (reading weight — `reading` Field Pattern; completion momentum — `coherence` Field Pattern), §IV (article topography — `reading` Field Pattern), §VII (kanban physics — `pressure` Field Pattern), §X (evidence field — `evidence` Field Pattern; conflict field — `conflict` Field Pattern), §XI (presence field — `presence` Field Pattern).* A global formation mode is a whole-field arrangement. Global formation modes do not replace force tokens. They bias the whole field. Current and future global formation modes can include: ```txt ambient wells lanes scatter accretion gravity tide lattice flock spiral turbulence pressure shatter magnetic reading evidence coherence conflict presence ``` ### reading A formation for long-form content. Sections gain attention near viewport center. Dwelled sections accumulate memory. Citations and related concepts become relationship paths. Use for: ```txt Reading Field Field Tutorial Natural Fields docs research articles legal documents ``` ### evidence A formation for claims, sources, and support. Claims become bodies. Sources bind or repel. Contradictions add entropy. Verified claims gain coherence. Use for: ```txt Evidence Field Trust Gradient Source Constellation Citation Thread Provenance Trail Conflict Field Disagreement Charge Risk Horizon Field Contract Preview ``` ### coherence A formation for completion and stability. Valid, aligned, or mutually supporting elements pull into a stable structure. Missing or contradictory elements add pressure. Use for: ```txt Form Stability Field Coherence Field Calibration Field Consensus Well ``` ### conflict A formation for contradiction, incompatibility, and unresolved difference. Opposing states separate, unstable zones heat, and unresolved conflict remains inspectable. Use for: ```txt Conflict Field Disagreement Charge Error Pressure merge conflict UIs ``` ### presence A formation for collaborative systems. Collaborators are not just avatars. They emit local attention, recency, and interaction signal. Use for: ```txt Presence Field Review Constellation Handoff Stream Consensus Well Disagreement Charge Change Shockwave Dependency Tension Recovery Path ``` ## 8. Patterns as the main possibility unit → *Shipped use cases: All concrete use cases in [use-cases.md](use-cases.md) map to named patterns — `Evidence Field`, `Trust Gradient`, `Presence Field`, `Memory Trace`, `Guided Flow`, `System Pulse`, `Relation Lens`, `Staleness Drift`, `Provenance Trail`, and more.* The most important product frontier is not another force. It is Field Patterns. A Field Pattern is a portable field program; a `FieldPattern` is its current API representation. It connects: ```txt intent natural field translation engine primitives DOM bodies relationships metrics feedback diagnostics accessibility equivalent ``` A pattern should answer: ```txt What is this for? What field relation does it translate? Which primitives does it use? Which bodies must exist? Which relationships matter? What metrics does it write? What diagnostics explain it? What happens in reduced motion? ``` Candidate pattern families: ```txt Core interface fields Reading, memory, accessibility Product and workflow patterns Trust, collaboration, inspection, teaching Professional systems, safety, provenance, governance Enterprise, collaborative, adaptive, operational fields ``` The pattern catalog should become a primary authoring surface. ## 9. The 64-recipe possibility map The current pattern universe can be organized as: ```txt 1-16: Core interface and accessibility fields 17-32: Product, workflow, trust, collaboration 33-48: Professional systems, safety, provenance, governance 49-64: Enterprise, collaborative, adaptive, operational fields ``` Examples: ```txt Priority Well Signal Path Relationship Bond Reading Field Evidence Field Coherence Field Memory Trace Guided Flow Attention Weather Navigation Current Citation Thread Form Stability Field Command Intent Field Dependency Tension Trust Gradient Handoff Stream Semantic Gravity Map Polarity Filter Source Constellation Boundary Field Threshold Bloom Latency Ripple Provenance Trail Relation Lens Field Contract Preview Presence Field Consensus Well Disagreement Charge Change Shockwave Permission Boundary Risk Horizon System Pulse ``` The pattern set is the clearest way to make Fundamental usable. It turns field theory into product patterns. ## 10. Data-bound fields → *Shipped use cases: [use-cases.md §II](use-cases.md#ii-data--dashboards) (anomaly field — `System Pulse` pattern; live data streams; relationship graphs) and §III (product gravity).* A major possibility is turning records into field participants. The field should be able to bind to arrays, graphs, search results, events, claims, files, tasks, calendar slots, or source documents. Possible API: ```ts const binding = bindData(container, records, mapper, options); binding.update(nextRecords); binding.destroy(); ``` Mapper: ```ts record => ({ id, body, role, strength, range, color, relationships, metrics, status }) ``` Examples: ### Search results High relevance becomes gravity. Recency becomes memory. Low confidence creates distance. Recipe: ```txt Search Relevance Field ``` ### Claims and sources Claims become bodies. Sources bind to claims. Contradictions repel or destabilize. Recipe: ```txt Evidence Field Source Constellation Trust Gradient ``` ### Calendar blocks Busy blocks create pressure. Available spaces remain low pressure. Deadlines create wells. Recipe: ```txt Availability Pressure Risk Horizon Priority Tide ``` ### Review queues Pending work develops review pressure. Resolved items cool and become memory. Recipe: ```txt Review Pressure Completion Release Review Constellation ``` ## 11. Relationship possibilities → *Shipped use cases: [use-cases.md §II](use-cases.md#ii-data--dashboards) (relationship graphs — `Relation Lens` pattern), §X (evidence field — source binding).* The DOM is a tree, but interfaces are graphs. Fundamental should continue moving toward relationship-native interface behavior. Relationship sources: ```txt href="#id" label[for] aria-controls aria-describedby aria-labelledby form ownership figure / figcaption details / summary popover target data-field-relation runtime pattern relationships data-bound graph edges ``` Relationship behaviors: ```txt support contradiction dependency ownership definition example control description evidence sequence handoff grouping conflict ``` Relationship diagnostics: ```txt topology causality relationship overlay source strength tension memory active path ``` Possibility: relationships should become first-class interface material. Not just lines. Not just graph edges. They can pull, resist, decay, strengthen, route signal, carry memory, and explain state. ## 12. Input agents User input should become part of the field. Candidate input agents: ```txt FocusAgent PointerAgent KeyboardAgent SelectionAgent DwellAgent ScrollAgent PresenceAgent IntentAgent ``` ### FocusAgent Focus becomes current. Tab order can emit signal. Reduced motion should use lit state without travel. ### PointerAgent Pointer velocity can become temporary influence. Fast movement can impart momentum if enabled. ### KeyboardAgent Directional navigation can act as flow. Shortcut targets can emit signal to affected regions. ### SelectionAgent Selected text, cards, rows, or nodes become temporary bodies. ### DwellAgent Dwell becomes attention and memory. ### PresenceAgent A collaborator’s focus emits local signal and recency. ### IntentAgent Likely next actions gain gravity from current context. All input agents must be opt-in, inspectable, and reduced-motion safe. ## 13. Render possibilities Render modes should not be treated as visual skins. Each render mode should answer: ```txt What invisible relation does this reveal? ``` Existing and possible render surfaces: ```txt particles trails metaballs links streamlines field lines potential energy contours velocity vectors force vectors topology inspector causality prediction depth knockout flow-field LIC relationship ribbons glyph interior fields field shadows volumetric density ``` Render doctrine: ```txt Renders reveal. They do not define behavior. ``` Canvas, SVG, and DOM overlays are surfaces. Semantic HTML remains the source of meaning. ## 14. Diagnostic possibilities Diagnostics are not developer-only extras. They are part of the trust model. A mature Fundamental surface should be able to answer: ```txt Why is this moving? Why is this emphasized? Why are these connected? What caused this warning? What accumulated here? Which source supports this claim? Which relationship is active? Which pattern wrote this CSS variable? ``` Diagnostic surfaces: ```txt Platform Inspector Field Contract Preview Diagnostic Lens Relation Lens Pattern Debugger Causality Overlay Prediction Overlay Topology View Memory Heatmap Energy View ``` The possibility is an interface that can explain itself. ## 15. Accessibility possibilities → *Shipped use cases: [use-cases.md §V](use-cases.md#v-the-invisible-field--signals-only) (focus-weight accessibility — the signals-only field is inherently reduced-motion safe; state without animation).* Every field behavior must survive without motion. Potential accessibility equivalents: ```txt motion trail -> static memory mark fieldflow ribbon -> path contour particle bloom -> badge or outline relationship pulse -> persistent thread heat bloom -> tone and status rail orbit -> grouped related items prediction path -> next-step marker conflict separation -> conflict list ``` The accessibility system should be recipe-aware. Every shipped pattern should define: ```txt semantic source motion behavior reduced-motion behavior keyboard behavior screen-reader source visual binding requirement ``` Possibility: accessibility becomes a field contract, not a late audit. ## 16. AI and evidence possibilities → *Shipped use cases: [use-cases.md §X](use-cases.md#x-ai--evidence-fields) (evidence field, trust gradient, provenance trail, conflict field) — "one of the strongest product directions."* AI interfaces need field behavior more than most UI categories. AI outputs contain: ```txt claims sources confidence uncertainty contradiction revision memory provenance risk ``` Field patterns can make these visible: ```txt Evidence Field Trust Gradient Source Constellation Citation Thread Provenance Trail Conflict Field Disagreement Charge Risk Horizon Field Contract Preview ``` Possible AI field behaviors: ```txt unsupported claims remain unstable verified claims gain coherence contradictions create charge separation source support creates binding corrections overwrite memory high-risk claims gain pressure generated drafts show provenance ``` This is one of the strongest product directions. ## 17. Collaboration possibilities → *Shipped use cases: [use-cases.md §XI](use-cases.md#xi-collaboration--shared-fields) (presence field, consensus well, handoff stream) and §VII (document co-presence).* Collaboration can move beyond cursors and avatars. Patterns: ```txt Presence Field Review Constellation Handoff Stream Consensus Well Disagreement Charge Change Shockwave Dependency Tension Recovery Path ``` Possible behaviors: ```txt collaborator focus emits signal recent edits leave memory reviewers bind to artifacts open comments create tension resolved comments cool handoffs flow from source to target consensus gains mass disagreement remains inspectable ``` The interface can show not just who is present, but how presence changes the field. ## 18. Authoring possibilities The system should eventually support visual authoring. Candidate tools: ```txt pattern editor force card editor relationship graph editor diagnostic lens parameter tuning panel reduced-motion equivalent editor field contract preview copyable HTML / web component / React snippets ``` Authoring principle: ```txt Designers should compose relational behavior without editing engine force code. ``` A pattern editor should make these visible: ```txt bodies natural field translation primitives relationships metrics feedback variables diagnostics accessibility equivalent status ``` ## 19. Platform possibilities The web platform already gives Fundamental the raw materials. But Fundamental also points toward missing platform primitives: ```txt native relationship graph typed element state channels low-cost layout snapshots coordinate-space conversion visual-semantic pairing thresholded state observers connection rendering reading state attention state field-aware DevTools ``` Fundamental can implement these today as a platform-adjacent layer. Long-term, it can also serve as a working argument for what the web platform itself could grow. The *runtime / host* expansion of this section — running the engine behind the `FieldHost` seam on other languages, embedded targets, and the GPU, plus non-visual output surfaces — is catalogued in [`../planning/platforms-and-use-cases-frontier.md`](../planning/platforms-and-use-cases-frontier.md) (with dispatchable briefs on RC1 board #24). ## 20. Research possibilities Fundamental can become a research artifact. Possible research frame: ```txt Fundamental: A Field Translation Runtime for Relational DOM Interfaces ``` Claims to evaluate: ```txt Does Reading Field improve orientation in long documents? Does relationship visibility improve source recall? Does Evidence Field improve trust calibration? Does reduced-motion equivalence preserve meaning? Does diagnostic visibility improve author trust? Does field-based priority reduce alert fatigue? ``` Evaluation targets: ```txt section relocation speed concept relationship recall source support recognition perceived distraction debuggability authoring time accessibility preference ``` ## 21. Product possibilities Potential product surfaces: ```txt docs site pattern gallery platform inspector Lab visual authoring tool pattern contract preview AI evidence viewer reading-field article template collaboration dashboard design-system plugin DevTools extension ``` The strongest near-term product arc: ```txt 1. Platform-backed runtime 2. Platform Inspector 3. Pattern system 4. Executable Pattern Gallery 5. Reading Field and Evidence Field demos 6. Accessibility conformance ``` Do not start by adding more spectacle. Start by making the system coherent, inspectable, and authorable. Longer-range product/runtime surfaces — new-language cores, headless/non-visual applications (force-directed layout, embeddings clustering, agent steering), and new host platforms — are catalogued in [`../planning/platforms-and-use-cases-frontier.md`](../planning/platforms-and-use-cases-frontier.md). ## 22. Field cells and local fields The global field should remain the default. But local cells are useful for demos, previews, pattern cards, educational blocks, and isolated experiments. Local field cells should obey these rules: ```txt local cells are explicit local cells do not accidentally fragment the global field local cells are paused when offscreen local cells are low-particle by default local cells are semantic-safe local cells expose their purpose ``` Examples: ```html ``` The possibility is a documentation system where every concept can carry its own small executable field. ## 23. Boundary and container possibilities Containers should be able to express scope. Patterns: ```txt Boundary Field Permission Boundary Scope Lens Availability Pressure Field Contract Preview ``` Container behaviors: ```txt valid items enter cleanly invalid items resist or reflect protected regions become visible on approach scope is inspectable before mutation drop zones communicate meaning through field pressure ``` This is especially useful for editors, admin tools, design systems, and enterprise apps. ## 24. Memory possibilities → *Shipped use cases: [use-cases.md §IX](use-cases.md#ix-memory--temporal-fields) (reading history, dwell-driven mastery, interrupted path recovery, staleness gradient) and §IV (playlist gravity — accretion/`--load`).* Memory is one of the most important non-visual field concepts. Memory can describe: ```txt where the user paused what was read what was visited what was recently edited which source was used where an error happened where a process was interrupted which path recovered state ``` Patterns: ```txt Memory Trace Reading Field Selection Wake Staleness Drift Provenance Trail Recovery Path Version Gravity Ambient Tutor ``` Possibility: software can remember in a visible, local, respectful way without turning everything into analytics. ## 25. The final possibility The old model: ```txt UI as isolated components with decorative transitions. ``` The Fundamental model: ```txt UI as a shared, inspectable field of meaning. ``` The possibility is not just better animation. It is a new interface layer. A layer where: ```txt priority has gravity difference has polarity relationships have binding change has decay attention has memory trust has coherence conflict has charge state has pressure motion has cause visuals have semantic sources behavior can explain itself ``` That is the point of Fundamental. Not a physics toy. Not a background effect. A field model for interface meaning. ## 26. Matter primitives beyond particles `[frontier]` > **Gated on the substrate-architecture frontier.** The richer matter primitives below (fluid, fabric, > sand) and several later frontier sections (§29 alternative output surfaces, §30 the machine-readable > layer, §32–§33 accumulating/temporal fields, §35 emergent semantics) depend on engine-internals > changes — first-class mass, a conserving integrator, fields-as-medium, and decoupling the simulation > from the DOM loop. That program is mapped in > [`../planning/substrate-architecture-frontier.md`](../planning/substrate-architecture-frontier.md), > with momentum as its root (see research [Paper 31](../research/31-behavioral-models-after-boids.md)). Particles are one way to sample the field. They are not the only way. The field is a continuous function over space. At any point there is a force vector, a density, a flow direction. Anything that can read a position and respond to a value can replace or augment particles. Alternative matter primitives: ```txt fluid grid-based simulation (SPH or Eulerian); the field drives pressure and viscosity fabric a mesh of connected nodes; the field applies tension and compression across a surface sand granular matter that stacks, piles, and avalanches; bodies displace and settle light ray paths that bend through the field; strong bodies create gravitational lensing effects ``` ### fluid Instead of discrete particles, continuous fluid that pools, flows, and swirls around bodies. Content sits in actual fluid. The field drives viscosity, not just direction. ### fabric A membrane of connected nodes. Elements sit on a surface that physically deforms around heavy bodies. Priority becomes visible as depression, not motion. ### sand Granular matter that settles into heaps. High-mass elements leave dunes. Weak-field bodies erode. Matter is displaced, not absorbed. ### light Ray paths that curve through the field. A strong gravity body bends light around it. The field becomes visible through distortion of what is behind it, not through matter in front of it. Each primitive answers a different question about the field. Particles ask: where does matter flow? Fluid asks: what is the pressure? Fabric asks: how does the surface deform? Sand asks: where does matter accumulate? Light asks: how does the field distort what is already there? ## 27. Spatial representations beyond particles `[frontier]` Render modes should not be limited to matter. The field is a mathematical object. It has topology, gradients, equipotential surfaces, and flow lines. These can be rendered directly without any particle simulation. Possible spatial representations: ```txt vector field glyphs arrows at grid cells showing direction and magnitude; no particles isosurfaces equipotential contour lines around bodies; a topographic map of semantic weight Voronoi territories each body claims the nearest space, weighted by strength; living territory map pure density heatmap color encoding field intensity at every point; thermal imaging of semantic weight interference patterns multiple bodies emit waves; constructive interference becomes visible streamline LIC line integral convolution showing continuous flow structure ``` ### vector field glyphs The raw field topology made visible. No particles. No simulation. Just direction and magnitude at every cell. Like wind maps, but for semantic space. ### isosurfaces Bodies sit at the centers of concentric rings. The field becomes a landscape. Bodies are mountains and valleys. Proximity and strength are visible as elevation, not position. ### Voronoi territories The field becomes a living territory map. Boundaries shift as bodies move or change strength. Conflict becomes a visible contested boundary, not a separate visual layer. Render doctrine still holds: ```txt Renders reveal. They do not define behavior. ``` The topology of the field exists whether or not it is drawn. ## 28. Time-based representations `[frontier]` The field currently exists in the present frame. But time is a dimension of the field too. Time-based render modes: ```txt traces accumulated particle paths; where matter has been, not where it is history bloom density of past positions; high-traffic corridors become bright lines interference wave emissions from multiple bodies; bands of constructive and destructive interference cellular each grid cell updates based on neighbors and local field value; bodies perturb the rules decay maps field intensity weighted by recency; recent influence is bright, old influence fades ``` ### traces Instead of where particles are now, show where they have been. The field's history becomes visible as accumulated paths. High-traffic corridors show up as bright lines. Bodies that have moved leave contrails. ### interference Multiple bodies emit waves. Where waves constructively interfere, bright bands form. Where they cancel, dark bands form. The field becomes a diffraction pattern. Semantically related bodies that emit in phase produce coherence. Conflicting bodies produce visible destructive bands. ### cellular automata Each cell of a grid updates based on its neighbors and the local field value. The field drives the evolution rules. Bodies are perturbations in the rules, not only force sources. This is not a particle system. It is a different class of emergence. ## 29. Alternative output surfaces `[frontier]` The field does not have to be visual. The field is a continuous function over space with vector values. Any transducer that maps a value to a perceivable output can render the field. Alternative output surfaces: ```txt sound field density maps to synthesis parameters; the field becomes audible haptics field intensity maps to vibration on mobile; the field is felt, not seen typography characters in the field deform based on local force; the words physically inhabit the field AR / spatial field extends into 3D space; physical objects become bodies; field bridges digital and physical ``` ### sound High-gravity zones produce low drones. Electromagnetic regions create oscillating tones. Weak-field zones produce release and silence. The field becomes an ambient semantic soundscape. This is not audio decoration. It is a genuine accessibility and ambient awareness channel. ### haptics Moving a finger through a strong-gravity region has physical resistance. Crossing a boundary field creates a perceivable threshold. The field is felt before it is seen. ### typography as matter Characters are not glyphs on a grid. They are matter in the field. In a high-charge zone, characters spread. In a gravity well, they compress. The words physically inhabit the field. This is not a CSS filter. It is actual glyph-level deformation driven by field state. ### AR / spatial The field extends into 3D space. Physical objects tracked by the camera become bodies. A real book on a desk creates a gravity well in the AR overlay. The field bridges digital and physical. Semantic relationships become visible in the room. ## 30. The field as machine-readable semantic layer `[frontier]` Every element on the page has a position in pixel-space. In a field page, every element also has a position in field-space. Field-space encodes: ```txt semantic weight relational tension dynamic state flow direction field density influence range ``` This is a shared coordinate system that is spatially queryable and continuously maintained. ### The field as a communication protocol Not between humans and UI. Between agents. An AI system, a service, or an autonomous process can query the field and understand the page without parsing the DOM. Field queries: ```txt What is the most important thing on this page right now? find the deepest gravity well What is this element most related to? follow the strong-force bonds from it What path should I take through this content? follow field flow at minimum resistance What is in conflict here? find regions of high charge separation What is the current trust state of this claim? read coherence at that body's position ``` This is not metadata. It is not schema.org tags. It is live, continuous, physics-based meaning that is always current because it is computed every frame. ### The field as a live knowledge graph A database has an index. A search engine has a vector space. The field is a spatial index of semantic state — continuously maintained, instantly queryable. Possible programmatic API: ```txt field.queryAt(x, y) → { density, direction, intensity, dominantBody } field.pathBetween(a, b) → minimum-resistance path through field space field.dominantBody() → body at the current global field minimum field.bondsFrom(element) → strong-force bonds from a given body field.conflictsNear(element) → charge separation and opposing domains ``` The field as infrastructure for entirely new kinds of interface intelligence. ## 31. The field as social substrate `[frontier]` One field per page is a constraint, not a law. ### Shared fields A shared field has multiple participants, each contributing bodies. A collaborator's cursor is a body. A collaborator's reading position is a body. A selection is a body. Everyone's presence creates field contributions that sum. ### Collective semantic gravity What emerges is not cursor chat. It is collective semantic gravity. Where many people are reading, a gravity well forms. Where attention flows, streamlines emerge. A controversial paragraph shows electromagnetic polarity — people polarized into two charge domains, their competing attention visible in field topology. You can see what a document means to a room of people. Not as a click heatmap. As a live field where meaning and attention are physics. ### Presence as field contribution Collaborative behaviors: ```txt collaborator focus emits signal reading position creates local density dwell time increases mass at that region disagreement creates charge separation consensus creates coherence and mass departure leaves a cooling memory trace ``` This extends section 17 (collaboration possibilities) from cursors and avatars to field participants. ## 32. The field as accumulating memory `[frontier]` The field currently exists only in the present frame. Particles have no history. But a field that accumulates — that remembers where attention has been, where matter has flowed, where bodies have moved — becomes a semantic sediment. ### Pages that deform under use High-traffic corridors develop lower resistance. Neglected regions gradually lose charge. The page ages in a physically meaningful way, shaped by how it has been inhabited. This is not analytics. Analytics are external, discrete, and after-the-fact. Semantic sediment is local, continuous, and immediately legible. ### Memory as field state Memory behaviors: ```txt frequently visited regions develop lower resistance dwelled sections gain mass neglected regions cool and lose charge read paths leave visible traces recovered paths return to warmth interrupted paths show where attention broke ``` Bring a user back to a page and the field is already warm in the places they have been. Cold in the places they have not. The field is a map of prior attention. Possibility: software can remember in a visible, local, respectful way without turning everything into analytics. This extends section 24 (memory possibilities) from discrete markers to continuous field state. ## 33. The field applied to time `[frontier]` The field currently spans 2D space. But time is a dimension too. ### Temporal fields A temporal field has bodies not just at positions but at moments. An event has a position in time-space. Related events are bound by strong force. Causal chains follow field flow. Concurrent events repel or attract based on semantic relationship. ### Navigating time as a field A timeline is not a line. It is a field over time. Navigating it means following force gradients. Zoom into a high-density region and you are zooming into a moment of high semantic activity. Pull back and the field coarsens into epochs. Temporal field behaviors: ```txt causal chains form flow paths concurrent events attract or repel based on semantic relationship high-activity moments create gravity wells long spans with few events become low-density sparse regions corrections and revisions overwrite memory at a position in time contested moments show charge separation ``` This is a genuinely different way to encode temporal relationships. Proximity in time-space means something based on meaning, not calendar distance. ## 34. The field as authoring primitive `[frontier]` Right now designers work in static space. They arrange elements, define transitions, write rules. The field inverts this. You define the physics. The layout emerges. ### Authoring relationships, not positions Old model: ```txt where should this go? ``` New model: ```txt how should this relate? ``` You do not position a sidebar. You give the main content high gravity and the sidebar moderate gravity. They find their equilibrium. You do not animate a menu opening. You give it a charge that, when activated, repels its children into visible positions. ### Responsive as field response Different viewport sizes produce different field configurations. The same semantic forces produce different spatial equilibria at different scales. Responsive design becomes field response. The author writes the meaning relationships. The field solves the geometry. ### Implications for design tooling A field-native authoring tool would expose: ```txt body mass and range sliders natural field type selector relationship graph editor formation picker equilibrium preview accessibility equivalent preview ``` Not: ```txt x position y position margin padding animation timing ``` This extends section 18 (authoring possibilities) from a pattern editor to a fully field-native design model. ## 35. Emergent semantics `[frontier]` A simple field has a few bodies and produces simple dynamics. A complex field — many bodies, many forces, feedback loops between field state and body behavior — can produce emergent semantic behavior. Patterns that were not programmed. Attractor states that correspond to meaningful configurations. Phase transitions when a new body enters or leaves. ### What emergence looks like in a field Possible emergent behaviors: ```txt attractor states the field settles into stable configurations around certain body arrangements phase transitions a new body tips the field into a different global organization self-organizing structure bodies find equilibrium arrangements without explicit positioning rules resonance bodies at compatible ranges and strengths amplify each other's effects cascading release a sink body reaching capacity triggers a chain of redistribution events ``` ### Not artificial intelligence Artificial intelligence encodes meaning in weights. Emergent semantics is different. It is a medium that organizes meaning through physics. Structure arises from interaction, not from encoding. Not artificial intelligence. Not a simulation. A field model where meaning has dynamics. ## 36. The projection problem `[frontier]` Every interface ever built is a projection. A flat map of a high-dimensional semantic space. Menus are projections. Search is a projection. Feeds are projections. ### What projections lose The projection loses information: ```txt the relationship between the thing being read and the thing searched three days ago the tension between two articles that contradict each other the gravity of something important that has been avoided the path that was most traveled and the path that was never taken the coherence building across a form that is almost complete the conflict that has been accumulating in a document over multiple edits ``` This information exists. It is recoverable. It is not stored anywhere visible. ### What the field recovers The field is a substrate that makes this information perceptible. Not inferable. Perceptible. ```txt priority becomes gravity relationship becomes binding conflict becomes charge separation importance becomes convergence change becomes decay and transformation attention becomes density and memory trust becomes coherence risk becomes pressure ``` The field does not add new information. It makes existing semantic structure visible as physics. That is a different claim than most UI systems make. Most systems claim to present information. Fundamental claims to reveal the structure underneath it. ### The new medium Every new medium recovered information that previous media lost. Writing recovered speech across time. Maps recovered spatial relationships across scale. Photography recovered visual appearance across memory. The field recovers semantic relationships across the interface surface. Not a particle system. Not a background effect. Not a physics toy. A medium for semantic structure — where meaning has forces, relationships have dynamics, and the interface can explain itself because it has physics. ======================================================================== FILE: docs/canonical/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`. ## Avoidance: radial brakes, tangential routes A second mental model, for any force whose job is to *keep matter away* from something: ```txt Radial forces brake. Tangential forces route. ``` A purely **radial** repulsion (`repel`, `charge`, `pressure`, `cohesion`'s short-range push) applied to a body heading *straight at* its source can only decelerate it — it adds no sideways component, so matter piles up or freezes in front of the source rather than going *around* it. To route matter around an obstacle you need a **tangential** component: `swirl` (mostly perpendicular, ~8× tangential to 0.12 inward) or `lens` (speed-preserving path rotation). This is why the canonical "deflector" pattern uses a swirl/lens, not a stronger `repel` — and why stacking `attract` against a radial `repel`/`separation` tends to clump (the opposing radial urges cancel under linear superposition and friction freezes the residue). > This is the field-native echo of a classic result in behavioral animation (Reynolds, *Boids*, 1987): > a radial repulsion field hit head-on "serves only to slow the [agent]... provides no side thrust at > all." Reynolds' answer was predictive lateral steering; ours is a tangential force. See > [`../planning/boids-2026-comparison.md`](../planning/boids-2026-comparison.md). ## 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: docs/canonical/host-model.md ======================================================================== > **Status: canonical (overview).** > The host model: how any environment — DOM, headless, native, custom renderer — becomes a > surface the field runs on. This document is the **Declare** verb's foundation and the single > home of the [host-conformance checklist](#host-conformance-checklist); for the rest it is a > map — it states the contract and links outward to the detailed docs rather than restating > them. The platform mechanics (registries, scheduler, runtime) live in > [platform-architecture.md](platform-architecture.md); the coordinate lanes in > [coordinate-spaces.md](coordinate-spaces.md); the per-body lifecycle in > [body-lifecycle.md](body-lifecycle.md). Follows the [status rule](documentation-standards.md). # The host model Two claims frame this document, both true in shipped code: 1. **Non-DOM hosts have an explicit contract.** The engine reaches its environment only through an injected interface, `FieldHost` — a pure-types SPI in `@fundamental-engine/core`. Any environment that satisfies it can drive the field. A new host author has a written checklist, not a reverse-engineering task. 2. **Headless, native, and custom renderers are first-class.** The DOM is the *first* host and the best-documented one, but it is not the boundary. The same core runs against a `headlessHost` (core), a `threeHost` (a WebGL custom renderer), and the Swift/Kotlin native ports — each held to the same contract, not a lesser one. The doctrine, stated once: **the host owns domain truth; Fundamental owns relational field state.** The host supplies geometry, time, and — where it can — scroll, visibility, and input; the field computes behavior on top and hands results back. The host model is neither an OS nor a database; it is the **Declare** seam where an environment is introduced to the field. ## The Host Adapter Contract — the `FieldHost` SPI `FieldHost` is the renderer/environment seam. Every DOM-global touchpoint the engine would otherwise reach for — viewport size, scroll, `requestAnimationFrame`, reduced-motion, visibility, the scan root, event wiring — is routed through this injected interface instead of `window` / `document` directly. Because the interface is pure types with no globals, the core imports **zero DOM** (enforced by `packages/core/src/engine/dom-boundary.test.ts`, empty allowlist). The SPI itself is the **stable injection seam** — the mechanism by which the engine is renderer-agnostic. The interface lives in `packages/core/src/engine/host.ts`. ## MinimalFieldHost — the smallest conformant host `MinimalFieldHost` is the smallest surface a host must supply for the engine to run. It requires exactly **four members**, in two categories: - **geometry** — `root` (the subtree scanned for bodies) + `viewport()` (size + DPR + optional origin): *where* the field lives and in what coordinate space. - **time** — `raf()` / `cancelRaf()`: how the frame loop is scheduled (a real `requestAnimationFrame`, a manual `tick`, a native display link). A host that supplies only these four members runs the **full simulation + feedback pipeline headlessly** — it just never scrolls, never pauses on visibility, and cannot draw a heatmap. This floor is pinned by `packages/core/src/engine/minimal-host.test.ts` (a field runs against a host with none of the optional capabilities). The native ports mirror it: `swift/Sources/FundamentalCore/Engine/FieldHost.swift` and `android/fundamental-core/src/main/kotlin/com/fundamental/core/engine/FieldHost.kt`. ## The capability ladder Everything beyond the four required members is an **optional capability** the engine consumes when a host offers it and degrades gracefully around when absent (scroll → 0, reduced-motion / hidden → false, subscriptions → no-op, a heatmap draw mode that needs `createCanvas` → a clear thrown error). Each rung unlocks a behavior: | Capability | Member(s) | Unlocks | Absent ⇒ | |---|---|---|---| | scroll | `scrollY` / `scrollHeight` | scroll-driven readouts | scroll reads 0 | | canvas | `createCanvas` | heatmap draw modes | those modes throw; `render: 'none'` unaffected | | reduced motion | `reducedMotion` | freeze the sim on preference | motion always allowed | | visibility | `hidden` / `onVisibility` | auto-pause on a backgrounded surface | loop never auto-pauses | | events | `onResize` / `onScroll` / `onInput` | resize / scroll / input signals | no such signals | | body events | `onBodyEvent` | DOM body-event registration | programmatic bodies only (`addBody`) | `hostCapabilities(host)` returns the machine-readable read-out (`{ geometry, time, scroll, canvas, reducedMotion, visibility, events, bodyEvents }`); `defineHost(minimal & partial)` builds a full `FieldHost` from a minimal host plus whatever capabilities you choose, filling no-op defaults for the rest — the sanctioned way to author a host without hand-writing the subscription boilerplate. Both live in `host.ts`. The shipped hosts span the ladder: `browserHost` / `containerHost` (`@fundamental-engine/dom`), `threeHost` (`@fundamental-engine/three`, a custom renderer), `headlessHost` (core). The substrate surface these hosts serve is EXPERIMENTAL / unfrozen; the `FieldHost` SPI itself is the stable seam. ## Host conformance checklist This section is the checklist's **one home** — other docs link here rather than carrying their own copy. Host conformance is the third parity/testing category alongside **API-surface parity** (the public surface exists on every plane) and **mathematical conformance** (the shared cross-plane golden at `depth: 0`): *does this environment adapter supply the capabilities the field expects, and degrade cleanly where it does not?* A new host is first-class when it answers each question below (the optional rows are the capability ladder above, restated as certification questions): | Question | Capability | Absent ⇒ | |---|---|---| | Provides geometry? | `root` + `viewport()` — bodies resolve in field space | **required** — a host without it is not a host | | Ticks time? | `raf` / `cancelRaf` | **required** | | Reports scroll? | `scrollY` / `scrollHeight` | scroll readouts read 0 | | Accepts a heatmap canvas? | `createCanvas` | heatmap draw modes throw; `render: 'none'` unaffected | | Honors reduced motion? | `reducedMotion` | motion always allowed | | Auto-pauses when hidden? | `hidden` / `onVisibility` | the loop never auto-pauses | | Emits events? | `onResize` / `onScroll` / `onInput` | no resize/scroll/input signals | | Relays DOM body events? | `onBodyEvent` | programmatic bodies only (`addBody`) | | Preserves an a11y equivalent? | host-specific | the embedder wires ARIA/semantics on its plane | `hostCapabilities(host)` is the machine-readable form of this checklist; the graceful-degradation floor is pinned by `packages/core/src/engine/minimal-host.test.ts` (a field runs against a host with **none** of the optional capabilities). The accessibility row is host-specific by design: the field state is a behavior layer over the host's source of meaning, not a replacement for it — wire ARIA / semantics on your plane. Beyond the capability rows, four contract disciplines complete the checklist: 1. **Coordinate mapping** — return a `viewport` origin (`originX` / `originY`) if the field is container-scoped rather than window-scoped, so bodies, canvas, and readouts share one space. 2. **Body identity** — respect stable `FieldBodyIdentity` across a rescan (see below); do not re-key a body on re-measure. 3. **Lifecycle** — support declare → measure → participate → remove for the bodies your environment introduces (DOM scan, or programmatic `addBody` / `handle.remove()`). 4. **Teardown** — every subscription you return (`onResize` / `onScroll` / …) hands back an unsubscribe; honor it so the field tears down cleanly. ## Coordinate spaces A host measures in its own coordinates (CSS px for the DOM, points for a native view, world units for a 3-D renderer); the field computes in **field space**. The `viewport()` origin (`originX` / `originY`) is what reconciles them for a container-scoped field. Keep the lanes separate — do not conflate "screen pixels" with "field state." Full model (five spaces, one-way conversions, and the semantic-not-spatial discipline for non-DOM hosts): → [coordinate-spaces.md](coordinate-spaces.md). ## Body identity `FieldBodyIdentity` (`packages/core/src/engine/types.ts`) is a body's first-class identity: a stable primary `id` (unique in the field, constant for the body's life) plus optional `namespace`, `kind`, and `host` tags (free-form, opaque to the engine). Snapshots, diffs, replay, and relationships all key on `identity.id`; when a body carries no supplied identity the engine derives one deterministically (never `Math.random`). Identity is assigned at **declare** and must not shift mid-life. ## Body lifecycle A body moves through **declare → measure → participate → remove** (with `participate` → `receive` repeating every frame for its whole life). DOM bodies are discovered by the scanner from `[data-body]`; programmatic bodies enter via `field.addBody(spec)` and leave via `handle.remove()`. This is what lets a non-DOM host carry synthetic or data bodies as first-class field participants. Full lifecycle, including DOM-vs-synthetic differences and the identity-stability rule: → [body-lifecycle.md](body-lifecycle.md). --- See also: [platform-architecture.md](platform-architecture.md) (registries, scheduler, runtime), [system-contracts.md](system-contracts.md) (the hard platform contract), and [substrate-api.md](substrate-api.md) (the read APIs the host's field state feeds). ======================================================================== FILE: docs/canonical/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) | Patterns | | [`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. `@fundamental-engine/core` computes renderer-agnostic field behavior; host adapters bind that field to concrete platforms. `@fundamental-engine/dom` is the web host adapter, binding the field 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. > **Association is not coupling.** Relationships associate by default. Forces couple. A Field Pattern > decides which associations become couplings. A relationship edge does **not** cause a force on its > own — this matters most for evidence, research, and knowledge-graph use, where readers otherwise > assume every edge exerts a pull. 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 field:entered field:exited field:lit field:dim field:saturated field:captured field:released field:attention-shifted field:relationship-strengthened field:memory-threshold field:entropy-warning ``` The canonical names are `field:*` (per `FIELD_EVENTS` in `packages/core/src/agents/event-agent.ts`). Use canonical `field:*` names in docs and consumers. 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 — shipped (agents/index.ts) 2. ElementAgent responder variables beyond density — shipped (element-agent.ts) 3. RelationshipAgent model — shipped (RelationshipRegistry) 4. Attention budget 5. UserAgent model for pointer/focus/selection — shipped (user-agent.ts) 6. Thresholded field events — shipped 7. Relationship heatmaps 8. Navigation/search patterns 9. Form state patterns 10. Reading/editorial patterns — shipped (Reading Field, /docs/reading-field) 11. Collaborative presence experiments 12. AI state visualization patterns ``` ======================================================================== FILE: docs/canonical/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**. Stated plainly: **a field can render nothing, contain no particles, and still be complete — if it has bodies, relationships, metrics, queryable state, and projections or feedback, it is a field.** > **The claim is about matter, not readings.** An invisible field paints no particles; that is the > whole of it. It may still carry an overlay **reading** — a diagnostic drawn on its own front > surface — without ceasing to be one, because a reading represents the field rather than being it > (`agent-consumption-model.md`). Until the Field Surfaces amendment to > [forces-system.md §13.7](../engine-reference/forces-system.md), `render: 'none'` suppressed both > surfaces; it now suppresses only the matter one. A field that declares no reading — the default — > is unchanged: nothing is drawn anywhere. 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. > **As of [#538](https://github.com/zachshallbetter/fundamental-engine/issues/538), this is the default.** > The engine's `render` mode defaults to `'none'`, so a field created without an explicit render mode IS > an invisible field — full simulation + feedback, no canvas. You opt *into* a drawn surface > (`render: 'dots'`, …), not out of it. The two mechanisms below remain the ways to get a signals-only > field while a drawn one exists elsewhere (draw-skip a visible field; run a render-less pattern). 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/engine/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. - **Pattern, render-less** — `applyRecipe(root, { ...recipe, render: [] }, { bodies })` runs the platform's metric pipeline over explicit bodies with no engine canvas at all (`packages/dom/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 pattern declares (the examples extend the evidence-field pattern 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). **Keyboard parity (a11y):** engagement is bound with the *bubbling* `focusin`/`focusout` (not `focus`/`blur`), so a keyboard user tabbing to a `[data-hot]` container — or to any focusable descendant inside it (a card's ``, a row's ` ``` `data-strength`, `data-range`, `data-spin`, `data-angle`, `data-when` (a condition gate: `active`/`fast`/`slow`/`hot`/`cool`), `data-feedback` (opt into the reverse write-back), `data-color`, `data-absorb`/`data-max` (sink capacity), and `data-preset` (expand a named composite) round out the common cases. Engaging an element — hover, focus, tap — widens its range and amplifies its strength, so *the field answers interaction.* ### 7.2 Three surfaces, one compiled contract The same markup is authored three ways, and all three *compile to identical `[data-body]` markup, drive the same `--field-density` feedback variable, and are measured, fed back, and related through the same platform registries:* - **Native HTML** — the platform runtime attaches to any element with `data-body`; the same markup works unchanged in Astro, Svelte, Vue, or static HTML. - **Web component** — `` (with `` as an equivalent alias; prefer `` in new code) wraps content and scans for bodies; the platform runtime is the default. - **React** — `` renders the same contract and maps props to `data-*` tokens; `useFieldField(options)` returns the field handle directly. That the three surfaces converge on one contract is the practical expression of the architectural claim in §4: the authoring surface is an adapter, and field behavior is independent of it. ### 7.3 Intent compilation and patterns Two higher-level authoring layers sit above raw tokens. The **intent compiler** translates a designer-level `data-intent` (with `data-intensity` / `data-risk`) into force tokens and parameters: `draw-focus` compiles to `attract + feedback`, `warn` to `repel + thermal` (with feedback), and so on. A **pattern** is the reusable unit: *a portable, serializable, inspectable field program*. A `FieldPattern` declares an id, a human intent, an optional natural-field classification, its `primitives` (real tokens), its `bodies` and `relationships`, its `render` layers, its `metrics` and `diagnostics`, a *required* accessibility fallback, and an optional performance budget and expected metrics. Sixty-four patterns ship as validated programs. The decisive property is the *conformance gate*: it rejects any pattern whose primitives are not real passported tokens, whose render layers or diagnostics are not real modes, or whose declared primitives drift from its body tokens. Pattern *prose* may be expressive ("completion releases pressure and decays into memory") while pattern *runtime fields* stay strict (`primitives: [morph, memory, gravity]`), and concept words never invent tokens (spring→`tether`, drag→`viscosity`, reflect→`wall`). Patterns are thus *auditable against the engine's actual capabilities* — the same epistemic discipline as passports, applied to composition. The three authoring *levels* map cleanly onto these layers: a **designer** works in intents and presets; a **developer** works in `data-body`, render modes, and patterns; an **engine author** writes custom `field()` / `apply()` implementations with conformance. --- ## 8. The reverse half: emergent interface primitives The forward half of the loop (elements → field) is force application. The *reverse* half (field → elements) is where Fundamental produces behaviors with no direct analogue in CSS or component state. All four primitives below are consequences of the same reciprocal loop, surfaced through the `FeedbackRegistry`. ### 8.1 Conserved attention Attention is treated as a *continuous, conserved* field rather than a per-element boolean: > Selection is a decision. Attention is a field. In conserved-attention mode, a single finite force budget is shared across the page, `Σ attention_i = A_total`, so engaging one element *pulls* force off the others — emphasis becomes genuinely zero-sum and transfer is *felt* rather than fabricated. This is a direct expression of the conservation invariant (§3.2) at the level of emphasis, and it is the substrate for the alert-fatigue question raised by the System Weather case study (§8.6). ### 8.2 Material typography Because the reverse write-back is a continuous scalar (`--field-density`, with `--load` and `--lit` for accretion fill and cross-boundary spill), a *single* density value can drive variable-font weight and optical size, tracking, glow, and color *simultaneously*, in pure CSS: ```css .field-text { font-variation-settings: "wght" calc(300 + var(--field-density, 0) * 500); text-shadow: 0 0 calc(var(--field-heat, 0) * 18px) currentColor; } ``` The governing sentence is: *the field does not decorate the interface; it parameterizes it.* A critical design law accompanies this — the **punctuation rule**: do not assemble particles into words or letterforms (it reads as noisy); reserve particle-into-shape effects for punctuation and marks, and make *words* feel alive by acting on the type and the field around them. *Words are bodies the field decorates; marks are where matter assembles.* Typography, color, shape, and pattern mappings are the subject of the visual-language canon and are summarized in Paper 2. ### 8.3 Cross-boundary causality A saturated body spills density to its neighbors, weighted by nearness, surfaced as `--lit`. Emphasis is therefore not strictly contained within an element's own box: a region under heavy attention *lights* its surroundings, producing a spatial, causal coupling between adjacent elements that a purely local state model cannot express. Every such effect remains *traceable to a field cause* — the diagnostic story of §6 and Paper 8 — so the spill can be inspected and explained, not just seen. ### 8.4 Memory fields User movement leaves a decaying deposit on a scalar grid, `M(x, y, t+dt) = M(x, y, t)·decay + deposit`, so the interface accumulates *a memory of approach, not just a record of clicks.* Read paragraphs, visited routes, and refined search paths become worn trails that bias future attention. Memory is classified as a *metric* (semantic truth), not a fundamental force — an example of the truth-mode taxonomy keeping the vocabulary honest. These four are not a closed list; they are the most legible members of a larger possibility space (relationship bonds, evidence fields, presence auras, system "weather") that Papers 2 and 3 develop. ### 8.5 Reduced-motion equivalence (overview) A field that expresses meaning through motion would be inaccessible if motion were the *source* of meaning. Fundamental's stance is that **motion is one representation of state, not the meaning itself**, so reduced motion is the *same field differently revealed* rather than a degraded fallback path. Under `prefers-reduced-motion` the runtime swaps travel for state: particles freeze or fade, sparks become static highlights, flow ribbons become static field lines, and heat trails become a soft wash — while the underlying state (attention, memory, relationship) still tracks and is still written to the DOM. Two invariants hold throughout: *meaning is never motion-only*, and *color is never the sole carrier of meaning.* An accessibility preview renders any composition as its reduced surface, which makes these rules verifiable rather than aspirational. We give only the overview here; the formal conformance model — semantic source, visual–semantic binding, motion behavior, static equivalent, and the lint rules that enforce them — is the subject of Paper 4. ### 8.6 Case studies (overview) The paradigm is most convincing not in a blank playground but applied to pages users already understand: *here is a page you already know; watch what happens when its meaning becomes a field.* Three case studies anchor the family: - **Reading Field** (shipped; `/docs/reading-field`). An ordinary long-form article — sections, headings, citations, a table of contents — wired to `createFieldPlatform` and exercising all six registries on the scheduler. Sections are measured bodies; viewport-centre proximity becomes attention; attention accumulates into memory over dwell; the table of contents reflects the field state; citations resolve into typed relationships. The reduced-motion path preserves the declared signals in the demo. It demonstrates that the substrate runs on prose, *without spectacle*; it does not establish a reader benefit. Paper 2 turns the case into a planned empirical study. - **Evidence Field.** Claims, sources, contradictions, confidence, and provenance modeled as inspectable field relationships — support as binding, contradiction as charge, uncertainty as entropy, correction as memory overwrite. The target domain is AI answers and other source-backed systems where trust primitives are weakest. Paper 3 develops the model and a study. - **System Weather.** A dashboard whose aggregate field state — urgency, risk, anomaly, coherence — surfaces as "weather" over the interface, with field-based priority as a candidate antidote to alert fatigue. Together these show the same runtime spanning reading, trust, and operations, each on a familiar interface archetype rather than a bespoke demo. ### 8.7 Signals-first mode: the field as pure computation layer The logical extreme of this principle is the **signals-first mode**: `render="none"` (now the engine default, #538) runs the full simulation — forces, registries, feedback, all six scheduler phases — and writes all semantic signals to the DOM (`data-field-density`, `data-field-attention`, `data-field-temperature`, and the corresponding CSS custom properties) *while drawing nothing at all.* The field becomes a pure computation layer: attention measured, memory accreted, relationships tracked, all without a single particle on screen. Visual representation then becomes explicitly opt-in (`render="dots"`, `render="trails"`, etc.) rather than the default. This is not a degraded path — it is a first-class consumer posture. A data-driven agent, a server-side renderer, or any non-visual surface reads the same field state as the visual user sees animated; the physics is the common substrate, representation is a choice above it. --- ## 9. Implementation status and limitations A preprint earns trust by being precise about what is real. We separate shipped behavior from aspirational behavior and then state the model's deliberate limitations. ### 9.1 Shipped versus aspirational **Shipped** (verifiable in the registry, the manual config, the render-mode catalog, the tests, and the package exports): the five packages; the `FrameScheduler` and all six registries plus `lintPlatform()`; the platform runtime as the default for `` (Phase D) with the guarded renderer-agnostic core; all 36 forces and all 16+ render/diagnostic modes (including `topology`, `inspector`, `causality`, `prediction`); signals-first mode (`render="none"` as the engine default, #538 — full simulation with no visual output); the `field.flowTo()`/`clearFlow()` controlled flow API; the Reading Field demo, accessibility preview, narrative reveal, and PNG/SVG diagnostic export; the native-HTML / web-component / React authoring surfaces; and the Natural Field Translation classification. **Aspirational or opt-in**, and labeled as such throughout: first-class inertial mass (opt-in; see below); several "weak-field" transformations (phase, fission) that are conceptual rather than implemented as forces; and the forward-looking frontiers (input agents, GPU compute, multi-root fields, visual authoring tools) that are roadmap items, not shipped behavior. ### 9.2 Deliberate limitations (the caveat canon) The following are *design decisions*, not defects, but a paper must state them plainly: 1. **Mass is nominal by default.** The default integrator advances `v += F` (unit mass), so "heavier particles swing wider" is aspirational; first-class inertial mass (`a = F/m`, `m ∝ size`) is opt-in via `FieldOptions.mass`. 2. **Energy is intentionally not conserved.** Friction and heat decay keep the interface calm. The dissipated energy is *accounted for* — rendered as micro-reactions (sparks scaled to the kinetic energy lost, `ΔE`) rather than silently dropped — but the ambient field is a *driven, damped* system by design. 3. **Momentum is only partially conserved** (pairwise in `collide`; the ambient field is damped). 4. **Designed ≠ natural, on purpose.** Bounded designed falloff is not inverse-square; the two registers are kept explicit rather than unified (§6.3). 5. **Particle count is the one strong invariant**, conserved except through explicitly budgeted sources/sinks. The system promises count, not energy or momentum. 6. **No user-study evidence yet.** The interface-benefit claims in this series are framed as designs and hypotheses (Paper 3), never as measured outcomes, pending an actual study. We consider stating these as part of the contribution: the value of an *inspectable* field language is partly that its honesty is mechanical — truth modes, passports, conformance, and lint exist precisely so that the boundary between physics, design, and expression is checkable rather than rhetorical. --- ## 10. Discussion **What the layering buys.** The empty-allowlist DOM boundary (§4.2) is more than hygiene: it means the *concept* of Fundamental (a field over participants) is genuinely separable from *the web* as a render target. The same engine could drive a native canvas, a WebGPU compute backend, or a headless analysis. The platform layer is then "just" one — important, carefully disciplined — binding of that engine to one substrate. **What the scheduler buys.** Read/write phase separation is the difference between a physics overlay that fights the browser's layout and one that rides it. By reading all geometry once into an immutable snapshot and flushing all writes together, the synchronization invariant holds at animation rates without forced reflow, which is what makes "animating the DOM animates the simulation" tractable rather than pathological. **What the epistemics buy.** Truth modes, passports, conformance, and lint are unusual for an interface library. Their payoff is that Fundamental can make *auditable* claims: a reviewer can check that magnetism does no work, that a pattern references only real tokens, that no overlay mutates physics, and that the core reaches no DOM global — by running tests, not by trusting prose. We argue this is the right posture for a system that asks designers to reason about *cause* ("why did this move?") rather than only appearance. **Threats to the framing.** The reciprocal model is most compelling on content that *has* latent relational structure (long documents, evidence, dashboards, graphs). On simple, flat interfaces the overhead of bodies and fields may not pay for itself, and the risk of "spectacle over meaning" is real — which is exactly why the roadmap prioritizes coherence, authorability, inspectability, and trust over new visual effects. Whether the model measurably helps users is an open empirical question that Paper 3 is designed to answer. --- ## 11. Conclusion Fundamental reframes interface state from local and binary to spatial, relational, and reciprocal: *elements bend the field, and the field bends them back.* The system that realizes this reframe is a strictly layered, provably renderer-agnostic engine; a six-phase scheduler and six single-concern registries that keep the DOM⇄field loop consistent without layout thrashing; a force model that separates structure from cause and classifies every behavior by truth mode and passport; and a uniform authoring contract that compiles identically across native HTML, web components, and React. The reciprocal loop yields interface primitives — conserved attention, material typography, cross-boundary causality, and memory fields — that local component state cannot express. We have been explicit about the boundary between what is shipped and what is aspirational, and about the model's deliberate physical limitations. The companion papers develop and operationalize bounded claims in reading (Paper 2), evidence and trust in AI interfaces (Paper 3), reduced-motion equivalence (Paper 4), host-driven runtime architecture (Paper 5), portable pattern authoring (Paper 6), data binding (Paper 7), and explainable diagnostics (Paper 8). Proposed evaluations remain proposals until they are run and their results reported. --- ## Appendix A. Reproducibility and verification Every architectural claim in this paper is checkable against the repository. The load-bearing anchors: - Renderer-agnostic core: `packages/core/src/engine/dom-boundary.test.ts` (empty allowlist). - The scheduler and registries: `packages/dom/src/schedule.ts`, `platform.ts`, `measurement.ts`, `state.ts`, `feedback.ts`, `relationships.ts`, `visual-bindings.ts`, `overlays.ts`, `lint.ts`. - The force contract and passports: `packages/core/src/engine/registry.ts`, `packages/core/src/contracts/passport.ts`. - The integrator and the unit-mass / opt-in-mass behavior: `packages/core/src/engine/integrator.ts`. - The canonical force/feedback catalog: `packages/core/src/config/manual.ts`. - Authoring/scan and the `[data-body]` contract: `packages/core/src/engine/scanner.ts`. The canonical design documents corroborate the framing: the system contracts, the platform architecture, the fundamental field-behavior table, and the natural-fields classification under `docs/canonical/`, and the as-built engine record under `docs/engine-reference/`. ## Appendix B. Conversion notes (markdown → preprint) Notation is kept LaTeX-compatible (inline math and fenced blocks translate directly). Figures referenced in prose but not yet drawn — the package dependency graph (§4.1), the reciprocal loop (§3.1), the six-phase scheduler timeline (§5.1), and a field-vs-particle-path diagram (§3.3) — are produced at conversion time. External citations and bibliography keys are resolved in [`references.md`](references.md) must be resolved and verified before submission. ======================================================================== FILE: docs/research/02-reading-field.md ======================================================================== # Reading Field: Attention, Memory, and Relationship Awareness in Long-Form Web Documents > **Status: research draft (preprint, work in progress).** Paper 2 of the Fundamental family — the > reading / long-form document validator. Claims verified against the codebase and canonical docs as > of 2026-06-07. See the [series index](README.md) and *the caveat canon* therein. This is a preprint > draft, not canonical product documentation. **Author:** Zach Shallbetter **Series:** Fundamental Research Papers, Paper 2 of 8 (the reading / long-form document case study) **Companion papers:** [Field Translation Runtime](01-field-translation-runtime.md) (the flagship paradigm paper, whose vocabulary this paper assumes); [Evidence Fields](03-evidence-fields.md) (AI trust and provenance). See the [series index](README.md). --- ## Abstract Long-form web documents — reference articles, specifications, legal text, research papers — are semantically rich but interactively flat. A reader scrolling through ten screens of prose has almost no machine-supported sense of *where they are*, *what they have already read*, *which sections relate to which*, or *where a citation leads*. The platform gives them a scrollbar and the browser history; the document itself stays inert. We propose the **Reading Field**: a treatment in which the parts of an ordinary document — its sections, its citations and cross-references, its table of contents, and the reader's own attention — participate in a single measured field of memory and relation, while the underlying markup remains plain, selectable, accessible, semantic HTML. Sections become *bodies* whose proximity to the viewport centre produces an *attention* well; sustained attention (dwell) deposits into a decaying *memory* field; the document's `href` and ARIA cross-references resolve into a typed *relationship* graph; and the table of contents becomes a live memory-and-attention map. The single claim of this paper is narrow and falsifiable: **long-form documents become easier to navigate and orient within when sections, citations, references, and reader attention participate in a measured field of memory and relation — without sacrificing semantic HTML.** We make two contributions: (1) a field model for reading, expressed in the shared vocabulary of the flagship paper and grounded in the *shipped* Reading Field demo at `/docs/reading-field`, which exercises all six scheduler phases — across the four platform registries it needs (measurement, state, feedback, relationships); and (2) a full, pre-registerable user-study design — research questions, hypotheses, conditions (a plain semantic baseline, the full Reading Field, and the Reading Field under reduced motion), materials, primary and secondary measures mapped to the project's own evaluation targets, a power estimate, an analysis plan, and threats to validity. Honoring the family's caveat canon, **no study has been run; every empirical statement here is a hypothesis or a design, never a finding.** --- ## 1. Introduction ### 1.1 The problem: orientation in long documents Reading a long document on a screen is a navigation problem wearing the costume of a reading problem. A printed book gives the reader a thick, tangible sense of position: the wedge of pages in each hand, the physical thumb in a remembered place, the dog-ear, the marginal note. A scrolled web document gives almost none of this. The reader's *position* is a thin scrollbar thumb. Their *history* — what they have already read versus merely scrolled past — is nowhere recorded. The *relationships* between parts of the document (this section defines the term that section uses; this claim rests on that citation) are present in the markup as `href`s and ARIA references but are not surfaced as anything a reader can feel or follow. And a *citation* is, interactively, a dead-end: a superscript that, when followed, drops the reader somewhere else with no thread back. Concretely, four failures recur: 1. **"Where am I?"** Readers lose track of their position in the document's structure. The active table-of-contents entry, if one is highlighted at all, marks a scroll position, not a *reading* position — it cannot distinguish a section read carefully from one scrolled past in a second. 2. **Losing the thread.** After following a link, switching tabs, or returning the next day, the reader must reconstruct where they were and what they had covered. The document does not remember. 3. **Re-finding a seen section.** "I read something about X a few sections back" is a common, costly operation. The reader scrolls, hunts headings, and re-scans — an act of manual search over content they have already seen. 4. **Weak relationship awareness.** Which concepts depend on which? Which claim does this source support? The answer exists in the document's structure but is not legible; the reader builds a weak mental model of the document's relational shape, or none at all. These are not failures of content. They are failures of *the interface to the content*: the document is treated as a single long scroll surface rather than as a structured field a reader moves through and remembers. ### 1.2 The Reading Field idea The flagship paper (Paper 1) argues that an interface is not only a layout of components but **a shared, inspectable field of meaning**, and that the way to realize this is reciprocal: *elements bend the field; the field bends them back.* The Reading Field applies that thesis to the single most ordinary kind of web page — an article — and to the single most ordinary reader activity — reading it top to bottom. The move is to treat the document's own parts as field participants. In the vocabulary of Paper 1 (§3): each **section** is a *body* — a registered origin of influence whose geometry is its bounding rectangle. The reader's viewport is a probe; a section's proximity to the viewport centre, scaled by how much of it is visible, is its **attention** — a continuous, momentary signal that rises as the reader arrives and falls as they leave. Attention integrated over time deposits into a **memory** field — the *memory field* primitive of Paper 1 (§8.4) — so a section the reader genuinely dwelled on stays warm while a skimmed one does not. The document's cross-references resolve, through the `RelationshipRegistry`, into a typed **relationship** graph: *a document is a tree, but meaning is a graph,* and the graph is exactly the one the markup already implies. Finally, the table of contents becomes a live **memory map** — each entry carrying the trace of how much of that section has been read, and the current section marked from the live attention field rather than from a raw scroll position. Crucially, none of this replaces the document. The HTML stays semantic, selectable, translatable, and accessible; the field is a *second layer* — orientation, relationship, and memory — laid over content that loses nothing if the field never starts. This is the discipline of the live-examples plan: *here is a page you already know; now watch what happens when its meaning becomes a field* — and the page *remains readable with no field effects enabled.* ### 1.3 Contributions and scope This paper contributes: 1. **A field model for reading** (§3): a precise account of how an ordinary semantic document becomes a Reading Field — sections as bodies, viewport-centre proximity as attention, dwell as memory deposit, cross-references as typed relationships, the table of contents as a memory map — stated in the shared vocabulary of Paper 1 and grounded in the shipped demo (§4). 2. **A full user-study design** (§5): research questions, hypotheses, conditions, materials, tasks, primary and secondary measures, a power estimate, a procedure, an analysis plan, threats to validity, and a pre-registration note — a protocol another lab could run. The scope is deliberately narrow, per the family's *one-claim-per-paper* rule. This paper concerns **reading and long-form documents only.** It does *not* re-explain the runtime architecture (deferred to Paper 5), the reduced-motion conformance model (Paper 4 — we use reduced motion here as an experimental *condition*, not as a contribution), pattern authoring (Paper 6), data binding (Paper 7), or diagnostics (Paper 8). Where those systems are load-bearing for a claim, we cross-reference rather than re-derive. --- ## 2. Background and related work The Reading Field sits at the intersection of several literatures. We position Fundamental against each and, following the family's convention, every external citation below uses a stable key assembled in [`references.md`](references.md) (the *Reading on screen, navigation, and document orientation* section already reserves space for them). **Reading on screen.** A substantial literature compares reading on screens to reading on paper and documents the orientation costs of scrolling — the loss of the spatial, kinesthetic cues that print affords, and their effect on comprehension and the sense of position. The Reading Field is, in part, an attempt to *re-supply* a spatial sense of place to a scrolled document. [mangen2013; ackerman2011; clinton2019] **Document navigation, orientation, and wayfinding.** Hypertext and document-UX research treats "where am I / where can I go / where have I been" as the canonical wayfinding questions, and studies table-of-contents design, fisheye and overview+detail navigation, and progress indicators as answers. The Reading Field's table-of-contents-as-memory-map is a direct descendant of overview navigation, but it is driven by *measured reading attention* rather than by scroll position alone. [conklin1987; nielsen1990hypertext] [furnas1986; shneiderman1996] **Information scent.** Information-foraging theory frames navigation as following "scent" toward likely-relevant content. A memory-and-attention-weighted table of contents can be read as making the *already-foraged* terrain legible — marking trails the reader has worn — which is the reading-time analogue of the *memory field* (worn paths attract attention) that Paper 1 inherits from stigmergy. [pirolli1999] **Citation and reference behavior.** How readers use citations, footnotes, and cross-references — when they follow them, how often they return, and how reference structure affects comprehension — bears directly on the citation-as-dead-end problem and on the relationship-awareness claim. [jurgens2016; boyack2018] **Memory of place.** Spatial memory for document location ("it was near the top of the right-hand page") is well attested for paper and degraded for scrolled text. The Reading Field's *memory* deposit is an explicit, externalized model of "I have been here," and the question of whether externalizing it helps re-finding is one of this paper's central hypotheses (§5). [mangen2013; ackerman2011] **Attention and salience.** As in Paper 1 (§2), computational saliency models *where* the eye is drawn; Fundamental instead treats attention as a *conserved, continuous field* over interface elements — *"selection is a decision; attention is a field"* (Paper 1, §8.1). In the reading case, attention is operationalized as viewport-centre proximity scaled by visibility, and its budgetary / conserved character (emphasis as zero-sum across sections) is inherited from the flagship model. The relevant HCI work on attention, distraction, and reading interruption frames the *perceived-distraction* measure of §5. [bailey2006; mark2008] The distinguishing stance, across all of these, is the one Paper 1 makes general: Fundamental does not add a navigation widget *beside* the document; it makes the document's own structure — sections, references, table of contents — and the reader's own attention into measured participants in one field, while keeping the semantic substrate intact and authoritative. --- ## 3. The Reading Field model This section states how an ordinary document becomes a field. It reuses Paper 1's model wholesale and specializes it to reading; the reader is referred to Paper 1 (§3, §5, §8) for the general loop, scheduler, and primitives. ### 3.1 Sections as bodies; viewport proximity as an attention well A section is a *body* in exactly the sense of Paper 1 (§3.1): a registered origin of influence whose geometry is its bounding rectangle, measured once per frame in the scheduler's **read** phase by the `MeasurementRegistry`. In the shipped demo, registration is literal — `platform.measure.register(section, { role: 'section' })` — and every `
` in the article becomes a measured body. A section radiates a **gravity-like priority** in the sense of the Natural Field Translation System (Paper 1, §6.5): *gravity → priority*. But the *cause* that produces emphasis at reading time is the reader's viewport. Let a section's measured centre be $c_y$, the viewport height $v_h$, and its viewport centre $v_h/2$. The section's **attention** is $$ A_i \;=\; \max\!\Big(0,\; 1 - \frac{|c_{y,i} - v_h/2|}{r\,v_h}\Big)\,\cdot\,\mathrm{vis}_i, \qquad r \approx 0.55, $$ where $\mathrm{vis}_i \in [0,1]$ is the fraction of the section currently visible. This is an *attention well* centred on the viewport: a section pinned at the centre of the reader's screen, and fully visible, attains $A_i \to 1$; a section drifting toward the edge, or partly scrolled off, decays toward $0$. The form mirrors Paper 1's general attention definition ($\text{attention}_i = \text{density}_i \cdot \text{engagement}_i \cdot \text{relevance}_i \cdot \text{visibility}_i$) specialized to the case where "engagement" is *being where the reader is looking*. Under conserved-attention mode (Paper 1, §8.1), the well is zero-sum: $\sum_i A_i = A_\text{total}$, so a section gaining the reader's attention *pulls* it off the others — emphasis is transferred, not fabricated. Attention is computed in the **compute** phase against the immutable measurement snapshot, never by reading layout mid-write — the scheduler discipline of Paper 1 (§5) is what makes the well cheap to maintain while the reader scrolls. ### 3.2 Dwell as memory deposit Attention is momentary. **Memory** is its slow integral: the worn-trail primitive of Paper 1 (§8.4), realized on a per-section scalar. Where attention rises and falls as the reader passes, memory only accumulates, and decays slowly, so the document accrues *a memory of approach, not just a record of clicks.* The deposit rule is the family's standard memory-field update, $$ M_i(t + \mathrm{d}t) \;=\; M_i(t)\cdot\text{decay} \;+\; \text{deposit}_i(t), $$ where the deposit is gated on *sustained* attention — only a section the reader actually dwells on (attention above a threshold) deposits, and only a small increment per frame, so memory reflects *reading*, not a glance. In the shipped demo this is the rule `next = min(1, prev + (attention > 0.7 ? 0.006 : 0))`, an explicit, inspectable realization of the gated deposit with a near-unity decay; a skimmed section never crosses the gate and so never warms. Memory is classified, per Paper 1's truth-mode taxonomy (§6.3), as a *metric* with *semantic* truth — a persistence signal, not a force — which keeps the vocabulary honest: nothing here pretends to be physics. The reading consequence is the one the introduction asked for: the document can answer *what have I already read?* — distinguishing a carefully read section ($M_i$ high) from one scrolled past ($M_i \approx 0$) — and can carry that answer forward across interruptions, because memory is state, not an event stream. ### 3.3 Citations and references as typed relationships A document's cross-references are not decoration; they are *relationships with history* (Paper 1, §5; canonical interaction model §7). The `RelationshipRegistry` reads them from the **native** signals the markup already carries — `a[href^="#…"]`, `label[for]`, `aria-controls` / `-describedby` / `-labelledby` / `-flowto`, and explicit `data-field-relation` / `data-field-target` — and resolves them into one typed relationship graph mapped onto core `RelationshipAgent`s. In the shipped demo, every in-page cross-reference is authored as, e.g., `memory`, and the discover phase calls `platform.relationships.discover(article)` once to build the graph; the same graph the topology overlay would draw. This is the foundation of *relationship awareness*. A citation ceases to be a dead-end superscript and becomes an edge the field can pull along, light up, and remember: hovering or focusing a source can light the claim it supports, and hovering a claim can reveal its source path (the *Citation Thread* pattern of the live-examples plan). The `relation-target-missing` lint rule (Paper 1, §5.3) flags any cross-reference whose target body is not registered, so the authored relational structure stays consistent with what the runtime sees — a quiet data pathology surfaced rather than silently dropped. The reading model here is deliberately conservative: the relationship *graph* is recovered from structure the author already wrote. Richer relational semantics for source support, contradiction, and confidence — *support as binding, contradiction as charge, correction as memory overwrite* — are the subject of the Evidence Field (Paper 3) and are explicitly *out of scope* here. The Reading Field claims only that making the document's existing reference graph legible, as relationships, aids orientation and recall. ### 3.4 The table of contents as a memory-and-attention map The table of contents is the document's natural overview surface, and in the Reading Field it is driven by the field rather than by scroll position. Two signals flow into it, in the scheduler's **render** phase (read-only over state): - **The current section** is the table-of-contents entry whose section currently holds the highest attention $A_i$ — a *reading* position, not merely a scroll position, so it does not flicker on a fast scroll-through (the entry is chosen from the eased attention field, and the underlying `field:lit` state has hysteresis — see §3.6). - **Each entry's memory** is its section's $M_i$, written as a custom property the entry's CSS reads, so the contents list *fills in* as the reader reads: a high-memory section's entry is brighter and carries a fuller rail than a skimmed one. The result is a *memory map*: a glance at the table of contents answers *where am I* (the current entry) and *what have I covered* (the brightness/fill of each entry) at once. In the shipped demo a small status line additionally reports a derived *read* count — sections whose $M_i$ exceeds a threshold — as a coarse "you have read N of M sections" signal. This is the live-examples plan's *the table of contents becomes a memory and attention map,* made literal. ### 3.5 What writes back to the DOM The reverse half of the loop (Paper 1, §8) surfaces through the `FeedbackRegistry`, which is the *single writer* permitted to turn internal state into DOM-visible output, in the scheduler's **write** phase. For the Reading Field the write-back is small and explicit. Per section: - `--field-attention` — the live attention $A_i \in [0,1]$. - `--field-memory` — the accumulated memory $M_i \in [0,1]$ (also written to the section's table-of- contents entry, so the contents list carries the same trace). - A thresholded `field:lit` event when attention crosses an enter threshold (and `field:dim` on exit), with hysteresis (enter $\approx 0.7$, exit $\approx 0.45$) so the *current section* state is stable rather than chattering. These are the *only* fields the reading treatment writes. (The family's general per-element density variable `--field-density`, with `--load` and `--lit` for accretion and cross-boundary spill, is the broader feedback vocabulary of Paper 1 §8; the Reading Field uses the attention/memory subset.) The write is continuous and scalar, which is exactly what lets a *single* value parameterize typography and rule weight in pure CSS — **material typography** in the sense of Paper 1 (§8.2): a section's heading opacity tracks `--field-attention`, and a left rail's color tracks `--field-memory`, *the field parameterizing the document rather than decorating it.* The **punctuation rule** of Paper 1 (§8.2) governs the reading case strictly: *words are bodies the field decorates; marks are where matter assembles* — the Reading Field never assembles particles into letterforms or prose; it acts on the type and the space around it. ### 3.6 Semantic HTML stays live The load-bearing constraint, and the second half of the paper's claim — *without sacrificing semantic HTML* — is that everything above is a *second layer*. The document is authored as ordinary semantic markup: `
`, `
`, `

`, `

`, ``, `