# Fundamental — full canonical documentation Source: docs/canonical/ in https://github.com/zachshallbetter/fundamental-engine Generated: 2026-06-17 by apps/site/scripts/gen-llms.mjs Files: 16 These are the project's canonical documents — the authority on concepts, terminology, and contracts — concatenated in filename order. The live site map is https://fundamental-engine.com/llms.txt. ======================================================================== FILE: README.md ======================================================================== > **Status: canonical.** > The documentation map for `docs/canonical/` — one line per document and its role. These > documents are the **authority**: read the relevant one before changing concepts, terminology, > or contracts. The status rule and framing policy live in > [documentation-standards.md](documentation-standards.md). # Canonical documentation map Fundamental is a platform-native relational field runtime for the DOM. `Fundamental` (core) computes renderer-agnostic field behavior; `@fundamental-engine/platform` binds it to the DOM; `elements`/`react` are authoring surfaces. Canvas is one render surface, not the whole system. > Concepts describe. Tokens execute. Metrics measure. Diagnostics explain. Conditions activate. > Recipes compose. No word lives in two lanes. | Document | Role | |---|---| | [`definition-document.md`](definition-document.md) | The operating model — what Fundamental *is* ("substrate, not wallpaper") | | [`documentation-standards.md`](documentation-standards.md) | How Fundamental is described everywhere: the architecture statement, the status taxonomy, the naming policy, the verify-against-code rule | | [`natural-fields.md`](natural-fields.md) | The four Natural Fields (gravity→importance, electromagnetic→polarity, strong→binding, weak→transformation) — concepts, not tokens | | [`fundamental-field-behavior-table.md`](fundamental-field-behavior-table.md) | The six truth modes + the per-force behavior table | | [`system-contracts.md`](system-contracts.md) | The hard contracts: bodies, fields, forces, agents, events, feedback, recipes, accessibility, performance, conformance, platform | | [`platform-architecture.md`](platform-architecture.md) | The platform layer: the six registries, the six-phase scheduler, the runtime (attachHandle, QualityGovernor), linting | | [`agent-consumption-model.md`](agent-consumption-model.md) | How consumers (particles, DOM elements, event sinks, visual layers) read one influence differently; Body Matter Interaction → Sink/Accretion | | [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md) | The agent model: element, relationship, user, layout, and data agents | | [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Render + diagnostic methods, and **Surfaces & Placement** (underlay / overlay / typographic) | | [`invisible-fields.md`](invisible-fields.md) | The typographic (invisible) placement: two-field page architecture, live channels, engagement contracts, declared relationships, data provenance | | [`time.md`](time.md) | Time in the field: the three clocks (simulation / experiential / world), the temporal kernels, the `data-field-at` contract | | [`visual-language-and-geometry.md`](visual-language-and-geometry.md) | The visual language layer: metric→appearance mappings and geometry | | [`authoring-and-recipes.md`](authoring-and-recipes.md) | Authoring surfaces and the FieldRecipe system | | [`testing-and-conformance.md`](testing-and-conformance.md) | Test contracts and the conformance framework (the Lab-as-detector) | | [`api-stability.md`](api-stability.md) | The freeze contract: the frozen surface, the experimental surface, the 0.x compatibility rules | Deeper references live beside this directory: `docs/engine-reference/` (the engine spec — `forces-system.md` is the big one), `docs/research/` (the paper family, with its caveat canon in its own README), and `docs/planning-archive/` (frozen history — do not cite as current). Planned work lives in `ROADMAP.md` / `BACKLOG.md` at the repo root and on the RC1 board. ======================================================================== FILE: agent-consumption-model.md ======================================================================== > **Status: canonical.** > The Field Agent Consumption Model: the unified account of *what a force acts on* and *how each > target consumes the influence*. Particles, DOM elements, and event sinks are all **agents**; each > owns a **consumer** that turns one influence into its own kind of change. Body Matter Interaction > (the sink/accretion behavior) is a submodel here, not a separate model. Every status label below was > verified against the code (`packages/core/src/agents`, `packages/core/src/forces`, > `packages/core/src/core/field.ts`, `packages/platform`) and follows the > [documentation standards](documentation-standards.md) status rule: nothing is called > *shipped* unless code confirms it. Deeper references: > [system-contracts §5–§9](system-contracts.md), > [interaction-and-relationship-model](interaction-and-relationship-model.md), > [forces-system §22](../engine-reference/forces-system.md). # Field Agent Consumption Model A force does not "move particles." A force produces an **influence at a location**; whatever sits there — a particle, a DOM element, an event sink — decides how to consume it. Particles are just the **lightest** agents. An element is a *heavy* body with a DOM consumer; an event sink is a *write-only* agent. One DOM body can be all three at once: sourcing force, being pushed by neighbors, and firing events. This is the correct framing. It is **not** a new "Body Matter Interaction" model — that older, narrower idea (bodies absorb particles) is one **submodel** of this one. The general statement is: ``` A field body can be more than a force source. It can be a particle source/receiver, a density receiver, a force target, and an event host. Particles, elements, and event sinks can consume the same influence in different ways. ``` ## Agent types `FieldAgentKind` (`packages/core/src/agents/index.ts`) — seven kinds, all present in code with concrete modules and agent contracts (`AGENT_CONTRACTS`, same file): | Agent | What it is | Consumes / does | Status | |---|---|---|---| | **particle** | visual matter | velocity impulse + heat; held in a sink core | **shipped** | | **element** | a DOM responder | metrics → `--field-*` vars + `data-field-*` bands; moved as a transform (`data-move`) | **shipped** | | **relationship** | an active connection | strength/tension/memory; strengthens with use, decays idle; transfers attention | **shipped** | | **user** | pointer / focus / selection | projects a field source (wake + accessible focus); respects reduced motion | **shipped** | | **layout** | a region-level responder | aggregates contained body metrics over a rect; writes back like an element | **shipped** | | **data** | a semantic record | salience ∈ [0,1] that decays unless reinforced | **shipped** | | **event** | a threshold trigger | hysteretic, debounced edge detection → one clean edge per crossing | **shipped** | Two things the broader framing sometimes calls "agents" are **not** field agents — they are platform concerns, and the distinction matters: - **visual layer** — the [VisualBindingRegistry](platform-architecture.md) pairs an expressive visual (SVG/Canvas) with its semantic source for linting and inspection. It participates in accessibility, not physics. See [Text and the visual layer](#text-and-the-visual-layer). - **event sink** — not a distinct agent kind; it is the **event-host role** a body plays through `data-on` (the `event` agent above provides the threshold machinery). ## Influence kinds → how each agent consumes them Every force emits one of a few **influence kinds**. The matrix is the spec, and each cell carries its own status. *This corrects the older unannotated matrix in [forces-system §22.3](../engine-reference/forces-system.md), which once presented unbuilt cells as if equal to shipped ones.* | Influence (from force) | Particle | Element | Event sink | |---|---|---|---| | **impulse** `Δv` (attract, repel, wind, stream…) | `v += F/m` — **shipped** | `o_v += F/m_el` → `translate(o)` via `data-move` — **shipped** | — | | **constraint** (tether, wall, gate) | clamp pos/vel — **shipped** | anchor tether + offset clamp (`maxOffset`) — **shipped** | — | | **capture** (sink) | `p.cap = b`, held then released — **shipped** | dock / collapse the element via `data-dock` — **shipped** | fire `field:captured` / `field:released` — **shipped** | | **relocate** (warp) | `warp` throat → paired body, conserved — **shipped** | teleport offset to the pair via `data-warp` — **shipped** | — | | **emit** (spawn) | new particle — **shipped** | clone a decorative template via `data-emit` — **shipped** | — | | **trigger** (threshold) | sets heat / state — **shipped** | toggle a class — **planned** (no built-in; do it in a `data-on` handler) | dispatch a `CustomEvent` via `data-on` — **shipped** | | **feedback** (gathered field → output) | `--d` / density — **shipped** | `--field-*` vars + `data-field-*` bands — **shipped** | — | "Apply a force to a DOM element" = it consumes the *same* impulse a particle would, but as a **transform** (with element mass `m_el`) instead of raw velocity. "Apply a force to an event" = the influence, on crossing a threshold, becomes a **signal**. **The honest summary:** every influence kind is now wired for particles, and elements consume impulse, constraint, feedback, capture (`data-dock`), relocate (`data-warp`), and emit (`data-emit`). The element consumers are **opt-in by attribute**, so they never surprise existing `data-move` content, and they stay accessible — docked elements are restored on release, emitted clones are `aria-hidden`. The one still-planned cell is the element `trigger` *class toggle* (do it in a `data-on` handler today). Element relocate is a **transform teleport**, not a DOM-tree reorder: reordering nodes would disrupt focus and reading order, so it is intentionally avoided. ## Body roles A single DOM body can play up to four roles at once. All four are **shipped** ([forces-system §22.1](../engine-reference/forces-system.md)): | Role | Mechanism | Status | |---|---|---| | **source** | `data-body` tokens emit force onto particles | **shipped** | | **density receiver** | gathered field → `--field-density` (alias `--d`), gated by `data-feedback` | **shipped** | | **force target** | `data-move` integrates net force into a transform | **shipped** | | **event host** | `data-on` binds field state to `CustomEvent`s; saturated bodies fire `field:lit`/`field:dim` | **shipped** | ## Body Matter Interaction (submodel) The concrete, fully shipped particle-level case. A `sink` body captures matter into an accretion core, **holds** it (it is not deleted), and **releases exactly what it held** when saturated. ```html
Accretion body
``` | Piece | Meaning | Code | Status | |---|---|---|---| | `sink` token | the only capture token | `packages/core/src/forces/index.ts` | **shipped** | | `attract` | pulls particles toward the body | `forces/index.ts` | **shipped** | | `data-absorb` | capture radius (`absorbR`, default 64) | `scanner.ts` | **shipped** | | `data-max` | capacity (`capacity`, default 60) | `scanner.ts` | **shipped** | | capture | `p.cap = b`; the particle stays in the pool, drifts to the core | `integrator.ts` | **shipped** | | `--load` | `accreted / capacity` ∈ [0,1], written each frame | `field.ts` | **shipped** | | `--mass` | back-compat **alias** of `--load` (identical value) | `field.ts` | **legacy** alias | | release | saturation → `supernova` releases exactly the held particles, then resets | `field.ts` | **shipped** | | discharge | an engagement-gated sink (`data-when="active"`) releases on the FALLING edge of attention — same conserved ritual, same events (#365) | `accretion.ts` `dischargeDisengaged` | **shipped** | Terminology, per the [status rule](documentation-standards.md): **`sink` is the runtime token.** `absorb` is **not** a token — only the `data-absorb` *attribute* exists. Treat `absorb` as concept/legacy language. `--load` is canonical; `--mass` is the alias. **Test coverage:** capture-within-radius and saturation-triggers-supernova are unit-tested (`forces.test.ts`), and the full hold → release cycle — captured matter stays in the pool, drifts to the core, then the *same* particles are released (conserved, count unchanged) — is covered end-to-end through the real integrator in `accretion.test.ts`. The release core is the pure, DOM-free `releaseCaptured` (`accretion.ts`), shared by `field.ts` and the test. **Element capture (dock).** A `[data-move][data-dock]` element that drifts into a sink's `absorbR` docks: it collapses toward the core (translate + scale → 0) and is held until the sink releases (supernova), which restores it. Docked elements become `aria-hidden` while collapsed and are restored on release and on teardown — element capture is conserved like particle capture. The collapse math is the pure `dock.ts` (`withinCapture` / `stepDock` / `dockTransform`), tested in `dock.test.ts`. ### The sink tiers (one contract, four surfaces) The law that orders the whole hierarchy: > **The element absorbs field matter. The visual layer shows what that absorption means. The > semantic text remains the source of meaning.** One sentence for the combined concept: *a body-sink lets a semantic element act as a vessel — it captures field matter, exposes its load as feedback, and may release that matter back into the field, while any SVG, Canvas, or vector layer remains a bound visual representation of the semantic source.* ``` Body Matter Interaction Sink / Accretion Element Sink — any DOM element as the vessel (the base contract above) Text Sink — the same contract on real text; the heading stays real text, CSS reads --d / --load for field-responsive typography Bound Visual Sink — an authored aria-hidden visual (SVG/Canvas) beside the body, bound via data-field-visual-for; the platform MIRRORS the body's feedback channels onto it (visual-bindings.ts, MIRRORED_CHANNELS), so var(--load) works on the sibling Contour Sink — the text/vector form: glyph outlines as the expressive boundary of a Text Sink. The platform primitive is font-agnostic (contours.ts: contourPathData / contourSvgFor — the caller supplies ANY parsed font; opentype.js fits the ContourFont contract), usable at runtime or build time (the site commits its output) — live at /docs/contour-typography ``` | Tier | Contract | Status | |---|---|---| | Element Sink | `data-body="sink …"` + `data-absorb`/`data-max`/`data-feedback` → `--load` | **shipped** | | Text Sink | identical — text elements are ordinary bodies; a11y rule: the text stays real | **shipped** | | Bound Visual Sink | `data-field-visual-for` + platform state mirroring (`setMirroring`, default on) | **shipped** | | Contour Sink | font-agnostic platform primitive (`contourSvgFor` — any parsed font) + Bound Visual mirroring; demo on /docs/contour-typography | **shipped** | Naming discipline: the tiers are *surfaces of one contract*, not new tokens — the token is `sink` in every tier, and a chip or doc that prints `ABSORB` instead of `SINK` is wrong (absorb is the attribute/concept lane). The visual layer never becomes the body; it represents the body. ## Events Field events are thresholded and debounced — never per-frame by default. The canonical catalog is `FIELD_EVENTS` (`packages/core/src/agents/event-agent.ts`); `field:*` mirrors to `forces:*` during the alias window (`FeedbackRegistry`, `shadow.ts`). **Dispatched today (shipped):** - `field:lit` / `field:dim` — density crosses the lit threshold (`field.ts`; also `FeedbackRegistry`). - `field:register-body` / `field:unregister-body` / `field:update-body` — body lifecycle (`shadow.ts`). - `field:captured` / `field:released` — a sink begins accreting (rising edge of `accreted > 0`) and releases on supernova (falling edge); also fired on a docked element when it docks / is restored. - `field:relocated` — a `[data-warp]` element teleports through a warp throat to its pair. - **any event name you bind via `data-on`** — e.g. `data-on="captured:field:dock, dense:field:lit"`. Every `field:*` here mirrors to its `forces:*` twin during the alias window. **Names reserved, not yet dispatched (planned):** `field:saturated`, `field:entered`, `field:exited`, `field:attention-shifted`, `field:relationship-strengthened`, `field:memory-threshold`, `field:entropy-warning` — the agent-threshold events, still wiring up. **Edge nuance.** `field:captured`/`released` are edge-debounced on `accreted > 0`. Release is fired directly from `supernova` so a same-frame fill-and-release never drops it; the rising-edge capture is sampled after the force pass (the same model as the `captured` `data-on` trigger). ## Text and the visual layer Text is a special case of the same model, governed by a design law ([forces-system §11](../engine-reference/forces-system.md), [visual-language-and-geometry](visual-language-and-geometry.md)): > Words are bodies the field decorates; punctuation is where matter assembles. - The semantic text stays **real HTML** — the source of meaning, in the accessibility tree. - A text element can register as a **field body**: source, density receiver, capture (sink), or event host like any other. - **Density drives type**, not particles: `--field-density` (alias `--d`) feeds variable-font weight (`data-fmin`/`data-fmax`/`data-opsz`), glow, and color. **shipped.** - **Do not assemble words out of particles** — it reads as noisy. Reserve glyph/particle assembly for punctuation and marks (a `.`, `—`, a logo glyph), where the silhouette is simple. (design law) - A vector/SVG/Canvas layer may **represent** the text, but it is **not** the source of meaning. Bind it declaratively with `data-field-visual-for` + `data-field-visual-role="representation"` and keep it `aria-hidden` — the [VisualBindingRegistry](platform-architecture.md) discovers, binds, and lints the pairing. **shipped** (binding + lint). Generating glyph geometry *from* text (outline extraction, text → SVG path) is **planned**, tracked as a frontier. ```html

Contour Field

``` The `h1` is the semantic source **and** a field body; `--field-density` / `--load` expose its state; the SVG is a bound representation, not the meaning. Particles and contours are **expression**. ## Hierarchy at a glance ``` Field Agent Consumption Model Agent types: particle · element · relationship · user · layout · data · event (all shipped) Influence kinds: impulse · constraint · capture · relocate · emit · trigger · feedback (per-agent status in the matrix; only the element trigger class-toggle is planned) Body roles: source · density receiver · force target · event host (all shipped) Submodel — Body Matter Interaction: source · attract/repel/shape · capture (sink) · hold · release · expose feedback (shipped) dock an element (data-dock) · emit a node (data-emit) · relocate/teleport (data-warp) (shipped) ``` > **Body-carried data (addBody).** A programmatic body created with `FieldHandle.addBody(spec)` carries an opaque `data` record — the Body-level analog of a particle's `atom`. It extends this model from *matter that carries records* to *sources that carry records*: an emitter is itself an addressable agent with attached data and per-body feedback (`onFeedback`), surfaced on its `BodyHandle`. > > **El-less bodies and the callback consumer.** A programmatic body has no DOM element. The model's element-agent has a *DOM consumer* (the engine writes `--d`/`--load`/`--field-*` onto the element, author CSS reads them); an `addBody` body has a **callback consumer** instead — its feedback channels arrive at `onFeedback(channels)` (and the live `BodyHandle.channels`), the non-DOM consumer for a non-DOM host (a Three.js mesh, a native view). Its force params are **reactive**: `BodyHandle.set({ strength, range, angle, spin, color })` mutates them on the measure cadence with no rescan — the same live-param path a scanned `[data-body]` gets from a `data-*` change, surfaced on the handle. ======================================================================== FILE: api-stability.md ======================================================================== > **Status: canonical.** > This document defines the **frozen public API surface for Fundamental `0.x`** and the compatibility > rules that govern it: what is stable, what is experimental, how versions move, and how the alias > window works. It is enforced in code by `scripts/api-surface.ts` (typechecked) and > `scripts/check-api-surface.mjs` (runtime), both run by `pnpm check:api` in CI. The shared machine > data is [`scripts/api-surface.data.mjs`](../../scripts/api-surface.data.mjs); the live reference page > is [`/docs/api/stability`](../../apps/site/src/pages/docs/api/stability.astro). Related contracts: > [system-contracts.md](system-contracts.md), > [platform-architecture.md](platform-architecture.md). # Fundamental API stability The architecture has stopped being fluid. Recipes execute, data binds, the inspector reads the live runtime, the gallery runs, the starter installs, the studies are data-driven. Before adding more capability, the public surface is **frozen for `0.x`** so consumers can build against it without the ground shifting. A symbol is "frozen" when it appears in the table below. Freezing means: it stays exported, from the same package, with the same kind (value / type / element), and its shape does not break, for the life of the `0.x` line. The freeze is mechanically enforced — `pnpm check:api` fails the build if a frozen symbol is removed, renamed, moved between packages, or changes kind. > Package npm names: core is published as **`@fundamental-engine/core`**; the rest are > `@fundamental-engine/platform`, `@fundamental-engine/elements`, `@fundamental-engine/react`, `@fundamental-engine/vanilla`. The umbrella > **`@fundamental-engine/kit`** installs the whole suite in one dependency (`fundamental-engine` is a thin alias > for it); these are convenience meta-packages, not part of the frozen API surface. ## The stable surface (`0.x`) ### Entry points and runtime | Symbol | Package | Kind | What it is | | --- | --- | --- | --- | | `createField` | `@fundamental-engine/core` | value | The renderer-agnostic primitive. **Requires `opts.host`** and throws without it. | | `createField` | `@fundamental-engine/vanilla` | value | The host-bundled convenience door (= `createBrowserField`); auto-supplies `browserHost()`. | | `browserHost` | `@fundamental-engine/platform` | value | The canonical DOM `FieldHost` for `createField`. | | `browserHost` | `@fundamental-engine/vanilla` | value | Re-export of the platform host for the no-framework path. | | `createFieldPlatform` | `@fundamental-engine/platform` | value | Wires the six native-first registries on a root. | | `applyRecipe` | `@fundamental-engine/platform` | value | Applies a recipe to a live platform. | | `bindData` | `@fundamental-engine/platform` | value | Binds records → bodies; data drives the field. | | `compileRecipe` | `@fundamental-engine/core` | value | Pure `FieldRecipe` → compiled plan (no DOM). | `createField` has **two doors on purpose**: the core primitive is renderer-agnostic and host-required; `@fundamental-engine/vanilla` re-exports the host-bundled convenience so the no-framework path stays one call. Both are frozen; the vanilla door must keep auto-supplying `browserHost()`. ### Types | Type | Package | What it is | | --- | --- | --- | | `FieldRecipe` | `@fundamental-engine/core` | The recipe schema. | | `FieldHost` | `@fundamental-engine/core` | The renderer-agnostic host contract `createField` requires; `browserHost` implements it. | | `FieldPlatform` | `@fundamental-engine/platform` | The surface `createFieldPlatform` returns. | ### Elements and the body contract | Surface | Package | What it is | | --- | --- | --- | | `` | `@fundamental-engine/elements` | One background field per page; scans the document for `[data-body]`. | | `` | `@fundamental-engine/elements` | A scoped local field region. | | `data-body` (attribute) | core `BODY_SELECTOR` | **The body contract.** "Every element is a body" via the `data-body` attribute on ordinary elements. | **There is no `` element.** Bodies are an attribute on ordinary elements, not a tag, and none will be introduced as the body mechanism. The custom elements are the field-`*` names; `` / `` are deprecated aliases (see the alias window). ## The experimental surface (not frozen) These carry **no** stability guarantee and may change shape or be removed in any release. Some have exported building blocks today — those are *shipped-but-unfrozen*: present in the package, but not part of the contract until they are added to the table above. | Area | Status | Notes | | --- | --- | --- | | `FieldHandle` (full surface) | partial | The handle shape is not frozen as a type. Entry points that return it (`createField`, `createBrowserField`) are frozen, but new methods may be added in any patch. | | `FieldHandle` diagnostic accessors | shipped-unfrozen | `particleCount(): number` and `energy(): { kinetic, thermal, total, count }` ship in `@fundamental-engine/core` and are proxied on ``. Safe to use; not frozen until 1.0. | | Advanced diagnostics | partial | `DIAGNOSTICS` / `DIAGNOSTIC_LENS` / `draw*` primitives ship but are unfrozen. | | Performance budget | shipped-unfrozen | `inspectBudget()`, `withinBudget()`, `DEFAULT_BUDGET`, `BudgetFinding` ship in `@fundamental-engine/core`; `FieldPerf` (frame-duration split, adaptive governor) is designed but not yet implemented. | | Visual recipe editor | absent | No editor UI; the authoring toolkit is the substrate to build one on. | | GPU / WebGPU backend | planned | A named direction; the six shipped render modes are CPU/canvas. | | Multi-root bridge | absent | No API for coordinating multiple `` instances yet. | | AI evidence fields | partial | `EVIDENCE_FIELD` + the agent API ship as a substrate, but no packaged feature. | | Custom render backends | partial | Possible via `opts.host`; no stable backend-registration API. | ## Compatibility rules 1. **Pre-1.0 semver.** In `0.x` the **minor** is the breaking position. A breaking change to a frozen symbol bumps `0.MINOR` (`0.2 → 0.3`); additive and fix-only changes bump the patch. Consumers should pin to `~0.MINOR`. 2. **Additive-only within a minor.** New exports, new optional fields, and new recipes/modes may land in a patch. Renaming, removing, or changing the signature/shape of a frozen symbol requires a minor bump and a migration note. 3. **`createField` keeps both doors.** The host-required core primitive and the host-bundled vanilla convenience are both preserved; the vanilla door must keep auto-supplying `browserHost()`. 4. **Package ownership is part of the contract.** Frozen symbols do not move between packages within `0.x` (`compileRecipe`/`FieldRecipe`/`FieldHost` → core; `createFieldPlatform`/`applyRecipe`/ `bindData`/`FieldPlatform`/`browserHost` → platform; `field-root`/`field-cell` → elements). 5. **Bodies are an attribute contract.** `[data-body]` on ordinary elements is the frozen authoring surface; there is no body element. 6. **`forces-*` → `field-*` alias window (deprecated, removal-gated).** ``/``, `ForcesField`/`ForcesCell`/`ForcesController`, `useForcesField`, `forces:*` events, `--forces-*` CSS vars, and the `compat-*` packages keep working behavior-identically through `0.x` and carry `@deprecated` guidance, but are **excluded from the additive-only guarantee** and scheduled for removal on a minor bump with a CHANGELOG entry. 7. **The experimental surface carries no guarantee.** Diagnostics/agent/render-mode exports that happen to ship today are *shipped-but-unfrozen* until explicitly added to the stable table. ## How the freeze is enforced - [`scripts/api-surface.ts`](../../scripts/api-surface.ts) imports every frozen value and type from its owning package. Removing, renaming, or changing the kind of a frozen symbol is a **compile error** there (a value-import of a type, or vice versa, also fails — so the *kind* is locked, not just the name). - [`scripts/check-api-surface.mjs`](../../scripts/check-api-surface.mjs) verifies the parts tsc can't see: each frozen value resolves at runtime in the built dist, each frozen type is exported in source, each element tag is registered (`customElements.define`), `data-body` is still in core's `BODY_SELECTOR`, and the data file and the type gate name the same symbols. - Both run via `pnpm check:api`, in CI right after `pnpm check:dist`. Changing the frozen surface on purpose means editing [`scripts/api-surface.data.mjs`](../../scripts/api-surface.data.mjs) **and** [`scripts/api-surface.ts`](../../scripts/api-surface.ts) **and** this document together, with a migration note and a `0.MINOR` bump. ## Status The packages are **published to npm** under the `@Fundamental` scope (`@fundamental-engine/core` and the four adapters). This freeze defines the `0.x` contract consumers build against; the publish steps and order are in [`PUBLISHING.md`](../../PUBLISHING.md). ======================================================================== FILE: authoring-and-recipes.md ======================================================================== > **Status: canonical.** > Authoring levels, the intent compiler, the recipe schema, examples, and precedence rules. Current as of the platform-runtime phase (Phase D). See [platform-architecture.md](platform-architecture.md) and [system-contracts.md](system-contracts.md). # Fundamental Authoring and Recipes ## Related Documents | Document | Role | |---|---| | [`README.md`](./README.md) | Documentation map | | [`definition-document.md`](definition-document.md) | Concept | | [`system-contracts.md`](system-contracts.md) | Recipe contract | | [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md) | Interaction recipes | | [`testing-and-conformance.md`](testing-and-conformance.md) | Recipe tests | ## Purpose This document defines how authors use `Fundamental`. `Fundamental` is a platform-native relational field runtime for the DOM: `Fundamental` computes renderer-agnostic field behavior, `@fundamental-engine/platform` binds it to the DOM (measurement, state, feedback, relationships, visual bindings, overlays, scheduling, linting), and the elements/React surfaces are how authors declare bodies into that shared field context. Authors write the same `[data-body]` contract regardless of surface. The system supports three authoring levels: | Level | User | API | |---|---|---| | Level 1 | designer | intents and presets | | Level 2 | developer | `data-body`, render modes, recipes | | Level 3 | engine author | custom `field()` / `apply()` / conformance | ## 1. Authoring Surfaces | Surface | Use | |---|---| | HTML attributes | direct declarative authoring | | Web Components | encapsulated field participation | | React props | framework integration | | Core API | engine-level control | | Field recipes | portable field programs | | Composer | visual authoring and copy-code tool | | Lab | executable spec and tuning | | Inspector | debugging and reciprocity view | ### Authoring across surfaces (shipped) The three authoring surfaces all compile to the same `[data-body]` contract, so a body authored in native HTML, as a web component, or in React participates identically in the shared field context. See the live walkthrough at `/docs/authoring`. Native HTML — the platform runtime attaches to any element carrying `data-body`: ```html
Living headline
``` Web component — `` wraps content and registers each `[data-body]` with the field; the platform runtime is the default participation path: ```html
Living headline
``` React — `` renders the same contract; props map onto the same `data-*` tokens: ```tsx import { FieldField } from "@fundamental-engine/react"; function Headline() { return (

Living headline

); } ``` All three forms emit identical `[data-body]` markup, drive the same `--field-density` feedback variable, and are measured, fed back, and related to one another through the same platform registries. ## 2. Core Attributes | Attribute | Purpose | |---|---| | `data-body` | force tokens | | `data-intent` | high-level author intent | | `data-field-role` | semantic role | | `data-field-state` | current field state | | `data-render` | render layers | | `data-feedback` | enable DOM write-back | | `data-field-source` | source field for transport | | `data-scope` | local/global participation | | `data-field` | explicit field target | | `data-strength` | force intensity | | `data-range` | effective radius | | `data-when` | activation condition | ## 3. Precedence Rules ```txt explicit force token beats intent defaults component props beat inherited field state local cell settings beat global settings reduced motion overrides visual travel accessibility overrides animation lint warnings do not block unless severity is error source budgets override spawn intensity debug render layers do not mutate physics ``` ## 4. Intent Compiler > **Implemented + runtime-wired.** `compileIntent` (`packages/core/src/recipes/intent.ts`) and the > scanner (`core/scanner.ts`): an element with `data-intent` (and `data-intensity` / `data-risk`), > and no explicit `data-body`, becomes a body from the compiled tokens. Explicit `data-*` wins over > intent defaults (precedence §3). Authors may describe intent instead of raw tokens. Example: ```html ``` Compiled output: ```html ``` Intent presets: | Intent | Concept | Runtime tokens | Render / feedback | Notes | |---|---|---|---|---| | `draw-focus` | draw attention to a focus | `attract` | feedback (`--field-density`) | range 280 | | `clear-space` | open a keep-clear region | `repel` | — | range 240; `screen` is not a token | | `show-motion` | flow along a heading | `stream` | render: `trails` | `trails` is a render mode, not a token | | `show-relationship` | link related things | `memory` | render: `links` | `links` is a render mode; `threads` is not a token | | `contain-energy` | damp + bound a region | `viscosity`, `wall` | — | `drag`→`viscosity`, `reflect`→`wall`; `screen` is not a token | | `ignite` | energize / heat | `thermal`, `fieldflow` | render: `heatmap`, `particles` | `heatmap` is a render mode, not a token | | `stabilize` | calm + hold together | `viscosity`, `cohesion` | — | `drag`→`viscosity`; `coherence` is a metric, not a token | | `warn` | warning / instability | `repel`, `thermal` | feedback | `entropy` is a metric, not a token | The **Runtime tokens** column holds real, passported engine forces only. Render modes, metrics, and human concepts live in their own columns and are never executed as forces: `screen`, `drag`, `reflect`, and `threads` are not tokens; `entropy` and `coherence` are metrics; `trails`, `links`, and `heatmap` are render modes. The machine-readable source of truth is `compileIntent` in `packages/core/src/recipes/intent.ts`. The compiler must be inspectable. Authors should be able to see the generated force tokens and render layers. ## 5. FieldRecipe Schema > **Implemented.** `FieldRecipe` (`packages/core/src/recipes/schema.ts`). A recipe is a portable, > serializable, inspectable field program — the reusable unit that connects the natural-field model, > engine primitives, DOM authoring, platform feedback, diagnostics, and the accessibility fallback. > `validateRecipe` enforces every reference against the engine catalog. (`SceneRecipe` is a deprecated > alias of `FieldRecipe`.) ```ts type FieldRecipe = { id: string // stable kebab-case id (e.g. "priority-well") name: string intent: string tier?: RecipeTier // core | applied | systems | operational naturalField?: "gravity" | "electromagnetic" | "strong" | "weak" translation?: string // the field→interface translation phrase (concept lane) primitives: string[] // the distinct body tokens, in first-seen order concepts?: string[] // product-language lane — describes; never executed metrics: string[] // signal names; --field-density is the one written today diagnostics: string[] // render/diagnostic modes that reveal the behavior conditions?: string[] // activation vocabulary — when the behavior applies bodies: BodyRecipe[] // each body may carry `when` — the EXECUTABLE gate (data-when) relationships?: RelationshipRecipe[] // compiled metadata only — used for the reduced-motion static display; // NOT registered as live edges into RelationshipRegistry render: RenderLayer[] // compiled to a render PLAN; executes when applyRecipe gets a field accessibility: AccessibilityRecipe // required: reducedMotion + meaningWithoutMotion status?: RecipeStatus // implementation status budget?: Partial expected?: ExpectedMetrics notes?: string } ``` The lanes stay separate: `primitives` (runtime tokens) execute, `concepts` / `translation` describe, `metrics` measure, `diagnostics` explain, `conditions` activate. `validateRecipe` rejects a token that appears in more than one lane. `relationships` is **compiled metadata, not a live-graph registration**. `compileRecipe` preserves the declared `from → to` pairs for one purpose only: populating the reduced-motion static display (`applyRecipe` renders them as a `

` list when `prefers-reduced-motion` is set). The `RelationshipRegistry`'s live graph is built solely by `RelationshipRegistry.discover()`, which reads native DOM signals — `a[href^="#"]`, `label[for]`, ARIA references, and `data-field-relation` / `data-field-target` attributes. A recipe author who wants an edge in the live graph must author it in HTML with `data-field-relation`, not in the recipe schema. `validateRecipe` returns a problem for any unknown force token, unknown render layer, unknown diagnostic mode, unknown fundamental field, an unknown per-body `when` condition id (an unregistered gate would silently never pass — rejected instead), declared `primitives` that drift from the body tokens, or a missing accessibility equivalent. A recipe can't reference anything the engine doesn't have, and no recipe is motion-only. **Recipes execute their declarations (#370).** `compileRecipe` derives an executable render plan from `render` — one underlay matter mode (`particles` → `dots`), the additive overlay reading stack, and the heatmap toggle; layers with no executable surface are NAMED in `plan.unapplied`, never silently dropped. `applyRecipe(root, recipe, { field })` drives a live field with the plan (a `FieldHandle` or `` both satisfy the structural target) and releases the surfaces on `destroy()`; `renderless` and reduced motion skip the drive. Per-body `when` compiles to `data-when` on the body — the contour-charge recipe carries its own engagement gate this way. Without a `field` option, recipes remain signals-only, exactly as before. Example: ```json { "id": "guided-flow", "name": "Guided Flow", "intent": "move particles or attention along field lines, relationships, or paths", "naturalField": "electromagnetic", "primitives": ["magnetism", "fieldflow", "stream", "propagate"], "bodies": [ { "body": "magnetism", "strength": 1, "range": 420, "spin": 1 }, { "body": "fieldflow", "strength": 0.8, "range": 0 }, { "body": "stream", "strength": 0.6, "range": 320, "angle": 0 }, { "body": "propagate", "strength": 0.5, "range": 300 } ], "render": ["streamlines", "field-lines", "trails", "particles"], "metrics": ["flow", "velocity", "density"], "diagnostics": ["field-lines", "force-vectors", "prediction"], "accessibility": { "reducedMotion": "a static path contour with a numbered route and direction markers", "meaningWithoutMotion": "the route is an ordered list of steps with direction labels" }, "notes": "Magnetism bends, fieldflow carries — the recipe-level expression of field.flowTo()." } ``` ## 6. Recipe Types | Recipe | Purpose | |---|---| | `FieldRecipe` | full field program (bodies, render, metrics, diagnostics, a11y) | | `ForceRecipe` | reusable force configuration | | `InteractionRecipe` | behavior tied to user input | | `VisualizationPreset` | render stack | | `MaterialPreset` | feel/material behavior | | `StatePreset` | field state configuration | ## 7. Field Recipes > **Implemented.** All **sixty-four** ship as validated `FieldRecipe`s in > `packages/core/src/recipes/catalog.ts` (`FIELD_RECIPES`; `gallery.ts` re-exports it), grouped into four tiers (`RECIPE_TIERS`), > live on [`/docs/gallery`](https://fundamental-engine.com/docs/gallery). They are the four-field translation > model made practical — and classification/authoring artifacts only: they **compose existing > primitives and add no new engine behavior**. Eight are the recommended first-release set > (`FIRST_RELEASE_RECIPE_IDS`). The four tiers (16 each): **Core — interface & accessibility** (1–16), **Applied — product, workflow & collaboration** (17–32), **Systems — safety, provenance & governance** (33–48), **Operational — multi-actor, adaptive & live** (49–64). The keys are a complexity ladder (`core` → `applied` → `systems` → `operational`), not access tiers — nothing is gated. ### Recipe language vs engine vocabulary Recipe **prose** is expressive; recipe **runtime fields** are strict. A recipe can say "completion releases pressure and decays into memory," while its runtime fields stay `primitives: [morph, memory, gravity]`. The conformance gate rejects any recipe whose primitives are not real passported tokens, whose render layers / diagnostics are not real modes, or whose declared primitives drift from the body tokens. Conceptual words map as follows (never invent a force token): | Concept | Goes to | Real token / mode | |---|---|---| | `mass`, `risk`, `trust`, `confidence`, `priority`, `entropy` | `metrics` | — (free-form labels) | | `potential`, `velocity vectors`, `relationship overlay`, `wavefront contours` | `diagnostics` | `potential`, `force-vectors`, `topology`, `contours` | | `spring` | `primitives`/`bodies` | `tether` | | `drag` / `friction` | `primitives`/`bodies` | `viscosity` | | `reflect` | `primitives`/`bodies` | `wall` | | `absorb` | `primitives`/`bodies` | `sink` | | `threshold` | `primitives`/`bodies` | `gate` | | `emitter` / `source` | `primitives`/`bodies` | `spawn` | | `phase` / `transform` / `decay` | `primitives`/`bodies` | `morph` / `memory` | | `orbit` | `primitives`/`bodies` | `magnetism` + `tether` (+ `gravity`) | No new force tokens are added for recipes — only recipe records, conformance, mappings, and docs. ### Tier 1 — Core interface & accessibility (the first-release set is starred) | # | Recipe | Natural field | Purpose | |---|---|---|---| | 1 | **Priority Well** ★ | gravity | make important elements feel naturally weighted without shouting | | 2 | Focus Orbit | gravity (+ electromagnetic) | keep related options moving around the active item | | 3 | Search Relevance Field | gravity | let results settle by relevance, confidence, and recency | | 4 | **Signal Path** ★ | electromagnetic | show information flowing through citations, dependencies, routes | | 5 | **Evidence Field** ★ | electromagnetic (+ strong) | show how sources support, weaken, or contradict a claim | | 6 | Conflict Field | weak (+ electromagnetic) | make contradiction, uncertainty, and unstable state visible | | 7 | **Relationship Bond** ★ | strong | keep related elements visually and behaviorally connected | | 8 | Concept Cluster | strong | group related terms or sections without hard layout changes | | 9 | **Coherence Field** ★ | strong | show whether a form, workflow, or dataset is becoming stable | | 10 | **Reading Field** ★ | gravity (+ memory + relationships) | reveal attention, memory, and concept links in long content | | 11 | **Memory Trace** ★ | weak | show where a user has been, paused, returned, or accumulated attention | | 12 | Decay Notice | weak | let stale, temporary, or completed state fade gracefully | | 13 | Phase Shift | weak | show a state transition (draft → published, pending → complete) | | 14 | **Guided Flow** ★ | electromagnetic (+ transport) | move particles or attention along field lines, relationships, paths | | 15 | Diagnostic Lens | diagnostic | reveal field lines, causality, prediction, topology, energy, overlays | | 16 | Accessibility Equivalence | platform / semantic | convert motion-heavy behavior into static, semantic equivalents | ★ = the recommended first-release set: Priority Well, Signal Path, Relationship Bond, Reading Field, Evidence Field, Coherence Field, Memory Trace, Guided Flow. Those eight explain the system quickly; the full catalog gives the project its range. ### Tier 2 — Applied: product, workflow & collaboration (17–32) Attention Weather (gravity), Navigation Current (EM), Citation Thread (EM), Form Stability Field (strong), Command Intent Field (gravity), Selection Wake (weak), Availability Pressure (gravity), Dependency Tension (strong), Staleness Drift (weak), Trust Gradient (EM), Completion Release (weak), Group Magnet (strong), Error Pressure (weak), Handoff Stream (EM), Context Halo (gravity), Field Tutorial (diagnostic). ### Tier 3 — Systems: safety, provenance & governance (33–48) Semantic Gravity Map (gravity), Polarity Filter (EM), Source Constellation (strong), Drift Correction (weak), Resonance Match (EM), Friction Gate (derived), Boundary Field (strong), Threshold Bloom (weak), Latency Ripple (EM), Provenance Trail (strong), Review Pressure (gravity), Semantic Snap (strong), Ambient Tutor (gravity), Relation Lens (strong), Priority Tide (gravity), Field Contract Preview (platform). ### Tier 4 — Operational: multi-actor, adaptive & live (49–64) Presence Field (EM), Consensus Well (gravity), Disagreement Charge (EM), Change Shockwave (EM), Permission Boundary (strong), Risk Horizon (gravity), Intent Magnet (gravity), Flow Checkpoint (strong), Version Gravity (gravity), Review Constellation (strong), Anomaly Bloom (weak), Scope Lens (diagnostic), Calibration Field (gravity), Semantic Drag (derived), Recovery Path (weak), System Pulse (EM). Each recipe declares its natural field, primitives, bodies, render stack, metrics, diagnostics, and an accessibility equivalent. See the executable cards (intent, primitives, diagnostics, reduced-motion equivalent, copyable JSON) on the gallery page, and the per-recipe plain-language explanation from `explainScene`. ## 8. Material Presets Forces define behavior. Materials define feel. | Material | Behavior | |---|---| | glass | lens + reflect + low drag | | rubber | spring + damping | | liquid | cohesion + pressure | | plasma | fieldflow + thermal + trails | | dust | diffuse + low mass | | metal | magnetism + reflect | | fabric | link + shear | | paper | low motion + memory | | stone | high mass + low response | | smoke | diffuse + stream + entropy | ## 9. Field States ```ts type FieldState = | "idle" | "focused" | "searching" | "navigating" | "reading" | "warning" | "critical" | "celebrating"; ``` Example: ```json { "searching": { "formation": "scatter", "render": ["particles", "memory"], "attention": "distributed" }, "focused": { "formation": "wells", "render": ["particles", "density"], "attention": "conserved" } } ``` ## 10. Authoring Lint Rules ```txt Warning: magnetism without charged or moving particles may appear inactive. Warning: fieldflow has no field source nearby. Warning: source force has no budget. Warning: local cell particle count too high. Warning: field lines enabled but no registered field() hooks exist. Warning: data-body="gravity attract" may duplicate pull behavior. Warning: reduced motion fallback missing. ``` ## 11. Explain This Field Every scene should be explainable. Example: ```txt This scene has one magnetic source defining loop geometry, one fieldflow transport layer carrying neutral matter along that geometry, and one thermal layer adding excitation. Particles follow the magnetic structure because of fieldflow, not magnetism. The active render stack is particles, field-lines, trails, and heatmap. ``` ## 12. Field Diff When parameters change, explain the difference. Example: ```txt Before: entropy 0.22, average speed 1.4, density center 0.61 After: entropy 0.37, average speed 2.1, density center 0.44 Change: stronger fieldflow increases velocity and lowers center density. ``` ## 13. Implementation Priority ```txt 1. SceneRecipe schema 2. VisualizationPreset schema 3. ForceRecipe schema 4. Intent compiler 5. Authoring lint rules 6. Essential recipes 7. Material presets 8. Field state presets 9. Explain This Field output 10. Field Diff ``` ======================================================================== FILE: definition-document.md ======================================================================== > **Status: canonical.** > The canonical concept and operating model. Current as of the platform-runtime phase (Phase D). See [platform-architecture.md](platform-architecture.md) and [system-contracts.md](system-contracts.md). # Fundamental Definition Document ## Related Documents | Document | Role | |---|---| | [`README.md`](./README.md) | Documentation map and authority order | | [`system-contracts.md`](system-contracts.md) | Canonical contracts | | [`fundamental-field-behavior-table.md`](fundamental-field-behavior-table.md) | Field laws and `fieldflow` | | [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md) | Agents beyond particles | | [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Visualization and diagnostics | | [`authoring-and-recipes.md`](authoring-and-recipes.md) | Authoring and recipes | | [`testing-and-conformance.md`](testing-and-conformance.md) | Testing and conformance | ## 1. Definition `Fundamental` is an inspectable field language for interfaces. It turns DOM elements, custom components, data records, relationships, events, users, and layout regions into participants inside a shared field context. Those participants can emit fields, apply forces, guide matter, receive density, write state back to the DOM, trigger events, form relationships, and expose their behavior through visualization, metrics, and tests. The shared context spans bodies, agents, relationships, measurements, metrics, feedback, and every render surface — particles are one agent type within it, not the whole substrate. `Fundamental` is a platform-native relational field runtime for the DOM. `Fundamental` computes renderer-agnostic field behavior; `@fundamental-engine/platform` binds it to the DOM (measurement, state, feedback, relationships, visual bindings, overlays, scheduling, linting); `@fundamental-engine/elements` and `@fundamental-engine/react` are authoring surfaces. Canvas is one render surface, not the whole system. Core principle: ```txt Elements bend the field. The field bends them back. ``` `Fundamental` is not a particle background. It is a relational behavior layer for the web. ## 2. Interface Physics Interface physics is the use of spatial, temporal, and relational forces to express state, meaning, attention, and interaction in a user interface. ```txt HTML = structure CSS = presentation JavaScript = behavior Fundamental = relational behavior ``` `Fundamental` maps semantic state to physical behavior and physical behavior to visual styling. ```txt Data becomes force. Force becomes motion. Motion becomes metric. Metric becomes style. Style becomes meaning. ``` ## 3. Core Thesis Traditional UI state is local. ```txt hover / not hover focused / not focused selected / not selected open / closed ``` `Fundamental` state is spatial, relational, and reciprocal. ```txt near approaching cooling saturating remembered related unstable coherent ``` The interface becomes a shared context layer. Components no longer behave only in isolation. Attention can transfer. Relationships can pull. Memory can accumulate. Data can become physical. ## 4. Foundational Loop ```txt DOM body -> emits field / applies force -> moves or influences agents -> accumulates density, heat, memory, entropy, attention -> writes metrics back to DOM -> changes element style, behavior, or state -> reshapes the field ``` This loop is the core product. The loop runs on the platform runtime, which is the default for ``. `@fundamental-engine/platform` owns DOM participation: it measures bodies, accumulates state, writes feedback, registers Shadow DOM, and resolves relationships. The legacy `core/field.ts` still simulates the field and draws the canvas render surface, while the platform owns DOM participation (measurement, feedback writes, Shadow-DOM registration, relationships); a legacy element write-back path in `core/field.ts` (CSS-variable and transform writes) is still being migrated behind the platform registries. `Fundamental` imports no DOM globals — a boundary guarded by `core/dom-boundary.test.ts`. You can opt back to pure-legacy behavior with `experimental-platform="off"` or `usePlatformRuntime(false)`. The package set: `Fundamental`, `@fundamental-engine/platform`, `@fundamental-engine/elements`, `@fundamental-engine/react`, `@fundamental-engine/vanilla`, plus `compat-*` alias packages for the prior names. The project is native-platform-first, dependency-light, and framework-agnostic; `Fundamental` specifically carries zero runtime dependencies. ### Platform layer `createFieldPlatform(root)` binds a root to the field runtime. The platform ships a `FrameScheduler` with explicit phases that order every frame: ```txt discover -> read -> compute -> state -> write -> render ``` It also ships six registries, each owning one kind of DOM participation: ```txt MeasurementRegistry measures body geometry in the read phase StateRegistry accumulates and holds body state FeedbackRegistry writes --field-* CSS vars and field:* events back to the DOM RelationshipRegistry resolves links and constraints between bodies VisualBindingRegistry binds field metrics to hidden visual elements OverlayRegistry manages overlay surfaces over linked bodies ``` `FeedbackRegistry` auto-mirrors `--field-*` to the legacy `--forces-*` vars and `field:*` events to `forces:*`. `lintPlatform()` reports authoring mistakes: `relation-target-missing`, `state-unregistered`, `overlay-without-links`, `feedback-non-css-var`, `measurement-off-phase`, `visual-orphan`, and `visual-not-hidden`. The Reading Field demo (`/docs/reading-field`) exercises all six scheduler phases across four registries (measurement, state, feedback, relationships) in a normal content page: sections are bodies, viewport proximity drives attention, accumulation becomes memory, the table of contents reflects state, citations form relationships, and reduced motion preserves meaning. ## 5. What Counts as a Body A body is a registered interface object that can originate influence or participate in the field. A body may be: ```txt HTML element custom element host Shadow DOM component React-rendered node canvas-local virtual body data record layout region event sink mark or glyph relationship node ``` A body must expose: ```txt identity geometry or geometry provider force attributes or registered behavior field target write-back target debug metadata conformance path ``` Default: ```txt body = element.getBoundingClientRect() ``` For Shadow DOM: ```txt body = custom element host ``` Presentation can be private. Physics must be public, registered, measurable, and testable. ## 6. What Counts as an Agent An agent is anything that can receive influence, hold state, change behavior, or affect another thing in the field. ```ts type FieldAgent = | ParticleAgent | ElementAgent | RelationshipAgent | EventAgent | UserAgent | LayoutAgent | DataAgent; ``` Particles are only one class of field participant. Users, elements, relationships, events, layout, and data can also be agents. See [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md). ## 7. Field vs Force Every field-like behavior must separate structure from cause. ```txt field(b, x, y) = invisible structure apply(b, p, env) = actual effect ``` `field()` is used for: ```txt field-line rendering streamline tracing heatmaps Lab probes fieldflow transport debug overlays topology analysis ``` `apply()` is used for: ```txt velocity changes acceleration curvature capture binding emission decay state change heat ``` A field line is not always a particle path. ## 8. Electromagnetic Rule The electromagnetic layer must keep three behaviors separate. ```txt Electric fields push. Magnetic fields bend. Fieldflow carries. ``` Expanded: ```txt Electric fields push charged matter along or against field lines. Magnetic fields bend moving charged matter across field lines. Fieldflow transports matter along field geometry. ``` Do not make `magnetism.apply()` follow magnetic field lines. Use `fieldflow` for solar prominences, auroras, plasma ribbons, and field-aligned transport. See [`fundamental-field-behavior-table.md`](fundamental-field-behavior-table.md). ## 9. Field Grammar A `Fundamental` scene is a sentence written in bodies, fields, forces, flows, metrics, renders, and feedback. ```txt Body = where influence originates Field = invisible structure Force = how matter responds Flow = how matter is transported Metric = what the system measures Render = how the invisible becomes visible Feedback = how the field writes back to the DOM ``` Complete sentence: ```txt Bodies emit fields. Forces act on agents. Flows transport matter along structure. Metrics measure accumulation. Renders reveal invisible state. Feedback writes the field back into the interface. ``` ## 10. Composition Laws ```txt Fields superpose. Forces accumulate. Modifiers transform context. Sources require budgets. Metrics observe. Renders do not mutate. Feedback writes to DOM. ``` Execution order: ```txt 1. measure bodies 2. resolve conditions 3. build field context 4. apply modifiers 5. apply forces 6. apply transport 7. integrate particles 8. update scalar grids 9. sample metrics 10. write DOM feedback 11. render layers ``` ## 11. Truth Modes Every behavior should be classified by truth mode. | Truth mode | Meaning | Examples | |---|---|---| | Physical truth | modeled after a real law | `gravity`, `charge`, `magnetism` | | Designed truth | shaped for readable UI behavior | `attract`, `repel`, `tether` | | Hybrid truth | a designed primitive operating over natural field geometry | `fieldflow` | | Diagnostic truth | reveals internal state | force vectors, heatmaps, inspectors | | Poetic truth | expressive composite from stable primitives | `blackhole`, `star`, `nebula` | | Semantic truth | maps data/interface meaning into physics | attention, memory, relation fields | This makes the project honest about which parts are physics, which are design, and which are expressive composites. > **Implemented.** The `TruthMode` union + `TRUTH_MODES` catalog ship in `contracts/passport.ts` > (Physical → `physical`); each force passport declares its mode. ## 12. Visualization Grammar Visualization is how the system explains itself. ```txt Particles show matter. Field lines show structure. Force vectors show cause. Trails show history. Heatmaps show accumulation. Contours show terrain. Energy views show cost. Topology shows relationships. DOM state shows reciprocity. ``` See [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md). ## 13. Attention as a Field Selection is a decision. Attention is a field. Attention should be continuous before it becomes selected. It may be local, shared, or conserved. ```txt Σ attention_i = A_total ``` When one element gains emphasis, others can surrender emphasis. This creates a spatial attention system rather than isolated hover states. ## 14. Relationships as Agents A relationship is not only an edge. It is a physical constraint with history. Relationships can: ```txt pull resist decay strengthen route attention carry memory become paths pulse with activity ``` See [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md). ## 15. Authoring Levels | Level | User | API | |---|---|---| | Level 1 | designer | intents and presets | | Level 2 | developer | `data-body`, render modes, recipes | | Level 3 | engine author | custom `field()` / `apply()` / conformance | See [`authoring-and-recipes.md`](authoring-and-recipes.md). ## 16. World Model Diagram ```txt DOM bodies -> field() Field structure -> fieldflow / visualization Agents -> density / metrics Scalar grids -> sample --field-* vars + field:* events -> DOM bodies ``` The runtime drives this loop through the `FrameScheduler` phases (`discover -> read -> compute -> state -> write -> render`); the `FeedbackRegistry` performs the write step, with `--field-density` as the primary feedback var (`--d` and `--forces-density` are legacy/compat aliases). ## 17. Design Philosophy ```txt 1. State should be spatial when relationships matter. 2. Motion should be caused, not decorative. 3. Visualizations should reveal truth, not invent it. 4. Field lines are structure, not always paths. 5. Attention is continuous before it is selected. 6. Relationships are active agents. 7. Meaning should survive reduced motion. 8. Every source needs a budget. 9. Every force needs a passport. 10. Every visible behavior should be explainable. ``` ## 18. Final Definition `Fundamental` is an inspectable field language for interfaces. It is built from: ```txt bodies agents fields forces flows metrics renders feedback contracts conformance ``` It is a way to make interface meaning physical, measurable, inspectable, and composable. Final operating principle: ```txt field() is structure. apply() is cause. fieldflow carries matter along structure. agents respond to influence. metrics measure accumulation. renders reveal invisible state. feedback returns the field to the DOM. ``` ======================================================================== FILE: documentation-standards.md ======================================================================== > **Status: canonical.** > This document governs how Fundamental is described across the docs, the site, and the Lab: the canonical > architecture statement, the core doctrine, the document-status taxonomy, the naming policy, and the > "verify against code" rule. It is the source of truth for *framing*; the deep topic references are > [platform-architecture.md](platform-architecture.md), > [natural-fields.md](natural-fields.md), > [system-contracts.md](system-contracts.md), and > [definition-document.md](definition-document.md). # Fundamental documentation standards This began as a documentation truth-pass brief; the work it described has shipped, so it is recorded here as the governing standard rather than a to-do. When docs, pages, force/Lab labels, or examples are written or revised, they follow the framing below. ## Canonical architecture statement ``` Fundamental is a platform-native relational field runtime for the DOM. Fundamental computes renderer-agnostic field behavior. @fundamental-engine/platform binds field behavior to the DOM through measurement, state, feedback, relationships, visual bindings, overlays, linting, and scheduling. @fundamental-engine/elements exposes native HTML and web-component authoring. @fundamental-engine/react adapts the same contracts for React. Canvas is one render surface, not the whole system. ``` Fundamental creates **one shared field context** across DOM bodies, agents, relationships, measurements, metrics, feedback, particles, and render surfaces. Canvas, SVG overlays, and DOM feedback are each a render surface; the platform layer is the DOM participation layer; the core engine stays renderer-agnostic. Do not describe Fundamental as only "one canvas", "one particle field", "a particle background", or a "DOM ⇄ canvas binding". Those phrases are fine when specifically discussing the canvas render surface, but they must not define the whole product. The binding is **DOM ⇄ field runtime**. ## Core doctrine ``` field() is structure. apply() is cause. fieldflow carries matter along structure. agents respond to influence. metrics measure accumulation. renders reveal invisible state. feedback returns the field to the DOM. ``` Preserve: **Electric fields push. Magnetic fields bend. Fieldflow carries.** Do not make `magnetism.apply()` follow magnetic field lines — field-aligned transport belongs to `fieldflow`. ## Natural Field Translation System Fundamental does not copy physics into the interface; it **translates** the four fundamental fields into interface behavior: gravity → priority, electromagnetic → polarity/signal, strong → binding, weak → transformation. **Natural fields are not tokens; tokens are translations.** Canonical forces (`attract`, `repel`, …) are designed verbs, not natural translations (`attract` ≠ gravity, `repel` ≠ charge). The classification is data — `FORCE_KIND` / `FORCE_FIELD` / `NATURAL_FIELDS` in `packages/core/src/config/manual.ts` — and the full model is in [natural-fields.md](natural-fields.md). It changes no particle/engine behavior; it only organizes how each token is explained. ## Current implementation truth These are shipped and may be described in the present tense (verify specifics against code before asserting anything new): ``` Fundamental · @fundamental-engine/platform · @fundamental-engine/elements · @fundamental-engine/react · @fundamental-engine/vanilla FrameScheduler (discover → read → compute → state → write → render) MeasurementRegistry · StateRegistry · FeedbackRegistry · RelationshipRegistry · VisualBindingRegistry · OverlayRegistry · lintPlatform() the platform runtime is the default for (Phase D); core is guarded renderer-agnostic all render modes (incl. topology, inspector, causality, prediction) field.flowTo() / clearFlow() controlled flow-field API Reading Field demo · Accessibility Preview · Narrative Reveal · PNG/SVG diagnostic export native HTML / web component / React authoring examples the Natural Field Translation System (four-field classification + /docs/natural-fields) ``` `Fundamental` imports **zero DOM** — the engine routes the environment through an injected `FieldHost`; `browserHost()` lives in `@fundamental-engine/platform`, and `createField` requires a host (the framework entry points wire it). `core/dom-boundary.test.ts` enforces this with an empty allowlist. ## Document-status taxonomy Every markdown doc carries a status banner, and the folders mirror it: - **canonical** (`docs/canonical/`) — current source of truth for product, architecture, contracts, framing. - **as-built reference** (`docs/engine-reference/`) — accurate engine record, narrower than the whole product. - **legacy / superseded** (`docs/planning-archive/`) — design history; not authoritative. - **planning / roadmap** (`docs/planning-archive/`) — forward-looking; must not describe planned work as shipped. ## Naming policy New code and docs use `--field-*` CSS variables and `field:*` events. The compact `--d` and the `--forces-*` / `forces:*` families remain as compatibility aliases (the FeedbackRegistry auto-mirrors `--field-*` → `--forces-*` and `field:*` → `forces:*`). Prefer `--field-density` in examples; mention `--d` / `--forces-*` only as aliases. Use `Fundamental` for the project, packages, and docs. ## Status rule Do not label anything "shipped" unless the code verifies it. Check the force registry, the manual config, the render-mode catalog, tests, package exports, the Lab labels, and the docs navigation before changing a status. Labels: shipped · experimental · planned · conceptual · legacy. ## The frame ``` The old story: Fundamental is a particle field behind the DOM. The new story: Fundamental is a platform-native relational field runtime for the DOM. Natural fields: Four fields. Many expressions. One DOM runtime. ``` ======================================================================== FILE: fundamental-field-behavior-table.md ======================================================================== > **Status: canonical.** > Field/force laws, the electromagnetic split, fieldflow, and truth modes. Current as of the platform-runtime phase (Phase D). See [platform-architecture.md](platform-architecture.md) and [system-contracts.md](system-contracts.md). # Fundamental Field Behavior Table for Fundamental ## Related Documents | Document | Role | |---|---| | [`README.md`](./README.md) | Documentation map | | [`definition-document.md`](definition-document.md) | Concept | | [`system-contracts.md`](system-contracts.md) | Contracts | | [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Field rendering and diagnostics | | [`testing-and-conformance.md`](testing-and-conformance.md) | Tests | ## Core Distinction Every field-like force must separate: ```txt field(b, x, y) ``` from: ```txt apply(b, p, env) ``` `field()` returns invisible structure. `apply()` causes change. A field line is not always a particle path. ## Field Grammar Reference ```txt Body = where influence originates Field = invisible structure Force = how matter responds Flow = how matter is transported Metric = what the system measures Render = how the invisible becomes visible Feedback = how the field writes back to the DOM ``` ## Truth Modes | Truth mode | Meaning | Examples | |---|---|---| | Physical truth | modeled after a recognizable physical law | `gravity`, `charge`, `magnetism` | | Designed truth | shaped for stable UI behavior | `attract`, `repel`, `spring` | | Hybrid truth | a designed primitive operating over natural geometry | `fieldflow` | | Diagnostic truth | reveals internal state | force vectors, heatmaps | | Poetic truth | expressive composite | `blackhole`, `nebula` | | Semantic truth | maps meaning into physics | attention, memory | > **Implemented.** These are the `TruthMode` union + `TRUTH_MODES` catalog in > `packages/core/src/contracts/passport.ts`. Forces classify as `physical` / `designed` / `hybrid` > (fieldflow); `diagnostic` / `poetic` / `semantic` classify visualizations, composite presets, and > the meaning→metric mappings respectively. > **Diagnostic truth is read-only.** All diagnostic render modes — including `causality` and > `prediction`, both shipped and live at `/docs/diagnostics` — only *visualize* field state. They > read the field and draw on a render surface; they never feed back into `apply()` or mutate physics. > Visualization and physics stay separate: a diagnostic overlay reveals internal structure without > changing how matter responds. ## Fundamental Table | Field / interaction | Field structure | `field(b, x, y)` should return | `apply(b, p, env)` should do | Particle relationship to field lines | Render expectation | Correct Fundamental role | |---|---|---|---|---|---|---| | **Gravity** | radial monopole well around mass-energy | gravitational vector field `g(x,y)` pointing toward source mass | softened gravitational acceleration: `g = -GM r̂ / (r² + ε²)` and `F = m g` | particles generally accelerate along the field; sideways velocity can create orbits | radial wells, falling paths, orbital arcs, accretion | `gravity`, natural primitive | | **Electric / Charge** | signed radial monopole field | electric vector `E(x,y)` outward from positive, inward toward negative | Coulomb force: `F = qE` | positive particles move along `E`; negative particles move opposite; neutral particles ignore it | radial lines, attraction/repulsion, demixing | `charge`, natural primitive | | **Magnetic** | loop, dipole, or pole-pair field | magnetic vector `B(x,y)`, derived from pole position, geometry, orientation, strength, and feedback | Lorentz magnetic force: `F = q(v × B)` | particles do not naturally stream along magnetic field lines; force is perpendicular to velocity and field | field loops plus curved charged tracks | `magnetism`, natural primitive | | **Electromagnetic combined** | coupled electric and magnetic field | compound `{ E(x,y), B(x,y) }` | full Lorentz force: `F = q(E + v × B)` | electric pushes along/opposite `E`; magnetic bends across `B` | spirals, arcs, plasma motion when paired with `fieldflow` | future composite | | **Field-aligned transport** | reads existing net field geometry | reads `env.fieldAt(x,y)` or `netField(...)` | steers velocity onto the field line and accelerates along it | particles intentionally follow field lines | solar prominences, auroras, routed plasma | `fieldflow`, label `Flux` | | **Strong / Binding** | short-range confinement or string tension | local binding field or pair potential | binds, links, fuses, resists separation | not line-following | clusters, bonds, nuclei-like structures | `cohesion`, `link`, `fuse` | | **Weak / Transformation** | instability or probability field | scalar instability or none | decay, split, transmute, emit secondaries | not path-based | state mutation, splitting | `decay`, `fission` | ## Electromagnetic Behavior Split | Behavior | Token | Owns field geometry? | Motion law | Does work? | Particle path relative to field lines | |---|---|---:|---|---:|---| | Electric charge | `charge` | yes | `F = qE` | yes | along `E` for positive, opposite for negative | | Magnetic Lorentz force | `magnetism` | yes | `F = q(v × B)` | no in ideal mode | across/around field lines | | Field-aligned transport | `fieldflow` | no, reads net field | steer + accelerate along `normalize(fieldAt(x,y))` | yes | along existing field lines | ## Required Mental Model ```txt Electric fields push. Magnetic fields bend. Fieldflow carries. ``` Do not make `magnetism.apply()` follow magnetic field lines. That behavior belongs to `fieldflow`. ## Gravity > **Implemented.** `gravity.field()` now ships (`packages/core/src/forces/natural.ts`, > `bodyGravityField`): a radial inward field so gravity owns `field()`, renders as field lines, and > can be followed by `fieldflow`. `gravity.apply()` is unchanged — adding the field only makes the > structure visible/followable (a field line is not always a particle path). The passport's > `ownsField` is now `true`. ### Field ```txt r = (x - cx, y - cy) d = max(length(r), ε) r̂ = r / d g = -GM * r̂ / (d² + ε²) ``` ### Apply ```txt F = m * g a = F / m v += a * dt ``` Simplifies to: ```txt a = g ``` ## Charge ### Field ```txt r = (x - cx, y - cy) d = max(length(r), ε) r̂ = r / d E = kQ * r̂ / (d² + ε²) ``` Bounded UI-safe mode: ```txt falloff = max(0, 1 - d / range)^n E = sign * strength * r̂ * falloff ``` ### Apply ```txt F = qE a = F / m v += a * dt ``` ## Magnetism ### Field For a simple visual loop: ```txt r = (x - cx, y - cy) d = max(length(r), ε) r̂ = r / d tangent = (-r̂.y, r̂.x) falloff = max(0, 1 - d / range)^n B = tangent * strength * spin * falloff ``` For production, prefer pole-derived field geometry: ```txt B = bodyDipole(body, x, y) ``` or: ```txt B = polePair(body.poles, x, y) ``` The field should respond to: ```txt pole position element geometry orientation strength range spin/polarity live charge feedback ``` ### Apply ```txt F = q(v × B) ``` For 2D canvas motion with out-of-plane magnetic strength: ```txt Fx = -q * Bz * vy Fy = q * Bz * vx a = F / m v += a * dt ``` ### Required Tests ```txt neutral particles ignore magnetism still charged particles receive no magnetic force moving charged particles curve force is perpendicular to velocity speed is preserved in ideal mode charge reversal flips curvature spin reversal flips curvature no effect beyond range ``` ## Fieldflow / Flux `fieldflow` is field-aligned transport. It does not define a fundamental field. It reads the net field created by other bodies. ### Apply ```txt F_net = env.fieldAt(p.x, p.y) h = normalize(F_net) gain = strength * max(0, 1 - d / range) v = steerToward(v, h, steer * gain) v += h * accel * gain ``` Recommended tunable version: ```txt h = normalize(env.fieldAt(p.x, p.y)) * direction targetVelocity = h * flowSpeed v += (targetVelocity - v) * flowSteer * gain v += h * flowAccel * gain ``` ### Recommended Attributes ```html

``` ### Behavior ```txt acts on neutral matter does work follows net field superposition routes matter between linked poles range 0 can mean global field-following formation creates solar prominence / aurora / plasma behavior ``` ## Implementation Matrix | Token | Owns `field()`? | Uses `env.fieldAt()`? | Moves particles? | Moves along field lines? | Does work? | Main law / behavior | |---|---:|---:|---:|---:|---:|---| | `gravity` | yes | no | yes | mostly | yes | `g = -GM r̂ / (r² + ε²)` | | `charge` | yes | no | yes | sign-dependent | yes | `F = qE` | | `magnetism` | yes | no | yes | no | no ideal | `F = q(v × B)` | | `fieldflow` | no | yes | yes | yes | yes | steer + accelerate along `fieldAt` | | `cohesion` | optional/local | no | yes | n/a | yes | surface tension | | `pressure` | optional/scalar | no | yes | n/a | yes | density relaxation | | `link` | optional/local | no | yes | n/a | constraint | distance constraint | | `fuse` | local | no | state/count | n/a | releases heat | conservation | | `fission` | local | no | state/count | n/a | releases heat | budgeted split | | `decay` | optional scalar | no | state/count | n/a | not motion-first | timed transformation | | `spawn` | no | no | creates particles | n/a | source | budgeted source | ## Force Passport Template Every force should include: ```txt Token: Category: Truth mode: Owns field(): Uses env.fieldAt(): Moves particles: Does work: Conserves speed: Requires charge: Requires velocity: Affects neutral matter: Can be visualized as field lines: Can be visualized as force vectors: Best render modes: Conformance tests: Common composites: Design use: Physics note: ``` ## Future Flux-Linkage Layer Flux-linkage is a future pairwise relationship metric. ```txt Φ_AB = amount of field from body A that connects to or passes through body B ``` Do not implement flux-linkage before baseline `fieldflow`, field-line, and probe systems are stable. ======================================================================== FILE: interaction-and-relationship-model.md ======================================================================== > **Status: canonical.** > Agents beyond particles: users, elements, relationships, events, layout, data, attention, and the interaction grammar. Current as of the platform-runtime phase (Phase D). See [platform-architecture.md](platform-architecture.md) and [system-contracts.md](system-contracts.md). # Fundamental Interaction and Relationship Model ## Related Documents | Document | Role | |---|---| | [`README.md`](./README.md) | Documentation map | | [`definition-document.md`](definition-document.md) | Concept | | [`system-contracts.md`](system-contracts.md) | Agent contracts | | [`authoring-and-recipes.md`](authoring-and-recipes.md) | Recipes | | [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Relationship visualization | ## Purpose This document expands `Fundamental` beyond particles. `Fundamental` is a platform-native relational field runtime for the DOM. `Fundamental` computes renderer-agnostic field behavior; `@fundamental-engine/platform` binds it to the DOM through measurement, state, feedback, relationships, visual bindings, overlays, scheduling, and linting. Particles are one agent type, not the whole substrate; canvas is one render surface, not the whole system. Particles are only one class of field participant. Users, elements, relationships, events, layouts, and data can also be agents. Core expansion: ```txt Bodies emit influence. Agents respond to influence. Metrics record the result. The interface adapts. ``` ## 1. Core Definition An agent is anything that can receive influence, hold state, change behavior, or affect another thing in the field. ```txt Agent = influence receiver + state holder + possible responder ``` A body is where influence originates. A body can also be an agent. ## 2. Expanded Agent Model ```ts type FieldAgent = | ParticleAgent | ElementAgent | RelationshipAgent | EventAgent | UserAgent | LayoutAgent | DataAgent; ``` | Agent type | Represents | Responds through | |---|---|---| | ParticleAgent | visual matter | velocity, heat, phase | | ElementAgent | DOM element | CSS variables, transforms, events | | RelationshipAgent | connection | tension, thickness, pulse, memory | | EventAgent | behavior trigger | threshold event | | UserAgent | pointer/focus/selection | wake, attention, memory | | LayoutAgent | region/panel | spacing, grouping, ordering | | DataAgent | semantic record | strength, category, state | The `FieldAgent` union above is the conceptual model. At runtime the discriminant is the lowercase `FieldAgentKind` string union (`'particle' | 'element' | 'relationship' | 'event' | 'user' | 'layout' | 'data'`) in `packages/core/src/agents/`; the per-kind shapes (e.g. `RelationshipAgent`, `UserAgent`) are the agent state those kinds carry. ## 3. Shared Context Layer Traditional UI state is local. `Fundamental` state is spatial, relational, and reciprocal. Recommended positioning: ```txt Fundamental treats the interface as a shared field context — one shared context across bodies, agents, relationships, measurements, metrics, feedback, and render surfaces — not a collection of isolated components. ``` ## 4. Interaction as Continuity Most UI interaction is binary. `Fundamental` can represent: ```txt near approaching cooling saturating remembered related unstable coherent ``` Recommended phrase: ```txt Fundamental gives interfaces a memory of approach, not just a record of clicks. ``` ## 5. Attention as a Field Attention is continuous before it is selected. ```txt attention_i = density_i * engagement_i * relevance_i * visibility_i ``` Conserved attention mode: ```txt Σ attention_i = A_total ``` Suggested DOM variables: ```css --field-attention --field-attention-share --field-attention-rank --field-related-attention ``` Key phrase: ```txt Selection is a decision. Attention is a field. ``` ## 6. Attention vs Focus vs Selection | State | Meaning | Field behavior | |---|---|---| | Attention | user is near or interested | density, glow, weak pull | | Focus | user is actively navigating | accessible attention well | | Selection | user has chosen | capture, lock, orbit | | Memory | user has been here before | path trace, higher future gain | | Relation | connected to what matters | secondary attention/thread | | Confidence | system believes relevance | coherence | | Priority | deserves emphasis | strength/rank | ## 7. RelationshipAgent A relationship is not only an edge. It is a physical constraint with history. ```ts type RelationshipAgent = { id: string from: BodyId to: BodyId type: string strength: number tension: number memory: number active: boolean } ``` A relationship can: ```txt pull resist decay strengthen route attention carry memory become a path pulse with activity ``` Relationship types: | Relationship | Physical behavior | |---|---| | parent/child | gravitational hierarchy | | related content | elastic thread | | dependency | directional tension | | conflict | repulsion | | sequence | stream/current | | similarity | cohesion | | history | memory path | | active relation | pulsing field link | ### Platform binding On the platform runtime (Phase D), the `RelationshipAgent` model is backed by the **`RelationshipRegistry`**. The registry reads native DOM signals — `href`, ARIA references (`aria-controls`, `aria-describedby`, `aria-labelledby`), and `data-field-relation` — and resolves them into a typed relationship graph between registered bodies. Relationships become edges the field can pull, resist, decay, strengthen, route attention along, and carry memory through, exactly as described above. The `relation-target-missing` lint rule flags edges whose target body is not registered, so the authored graph stays consistent with what the runtime sees. ## 8. UserAgent ```ts type UserAgent = { pointer?: Vec2 focus?: Element selection?: Element[] velocity?: Vec2 memoryTrail?: ScalarGrid intent?: "browse" | "search" | "read" | "drag" | "select" } ``` User signals: | Signal | Field behavior | |---|---| | pointer | moving attractor / wake | | pointer velocity | stream direction | | hover | local attention | | focus | accessible attention | | selection | capture | | drag | constraint + wake | | scroll | current | | edit | heat deposit | | correction | memory overwrite | | return visit | memory amplification | ## 9. Interaction Grammar ```txt hover = local attention focus = accessible attention press = compression drag = constraint + wake scroll = current select = capture release = emission search = scatter then converge navigate = stream return = memory ``` ## 10. Pointer, Focus, and Accessibility The system must not be pointer-only. Focus is a first-class field source. | Interaction | Field behavior | |---|---| | `hover` | local activation | | `focus` | accessible attention well | | `focus-visible` | visible field activation | | `active` | compression/capture | | `selected` | stable orbit/lock | | `visited` | memory trace | | `disabled` | screen/low response | | `invalid` | entropy/warning heat | | `loading` | stream/vortex/fieldflow | | `success` | release | | `error` | repel/thermal/pulse | Reduced-motion fallback: ```txt focus creates state, not travel ``` ## 11. User Movement as Memory ```txt M(x, y, t + dt) = M(x, y, t) * decay + userInputDeposit ``` Use cases: ```txt cursor wake reading trail visited content paths search refinement path workflow routes desire paths ``` Suggested outputs: ```css --field-memory --field-path-use --field-user-wake ``` ## 12. Events as Field Thresholds Events: ```txt forces:entered forces:exited forces:lit forces:dim forces:saturated forces:captured forces:released forces:attention-shifted forces:relationship-strengthened forces:memory-threshold forces:entropy-warning ``` Rule: ```txt Field events should be thresholded, debounced, and inspectable. ``` ## 13. ElementAgent Responders Possible outputs: ```css --field-density --field-attention --field-pressure --field-coherence --field-entropy --field-memory --field-pull-x --field-pull-y --field-layout-shift ``` Example: ```css .card { transform: translate( calc(var(--field-pull-x, 0) * 12px), calc(var(--field-pull-y, 0) * 12px) ) scale(calc(1 + var(--field-attention, 0) * 0.04)); } ``` ## 14. LayoutAgent Layout can respond to field conditions. ```txt spacing opens under pressure related items cluster unrelated items drift apart active region gains z-depth search results settle into relevance wells dense sections create screen zones overloaded regions dampen motion ``` Use sparingly. Prefer reversible, inspectable behavior. ## 15. DataAgent Data records can become field agents. | Data property | Field mapping | |---|---| | importance | strength | | category | force token / color | | recency | heat | | confidence | coherence | | uncertainty | entropy | | relation count | range | | status | phase | | user interest | memory | | priority | attention share | > **Implemented.** `SEMANTIC_LAYERS` + `semanticToMetrics()` in `packages/core/src/semantic/layers.ts` > map each meaning to its field metric. ## 16. Relationship Heatmaps | Heatmap | Meaning | |---|---| | attention | where the user is focused | | relation | linked content clusters | | path | repeated movement | | conflict | opposing forces | | workload | interface density | | comprehension | repeated docs/examples attention | | conversion | CTA attention concentration | ## 17. Interface Weather | Weather | Meaning | UI response | |---|---|---| | Calm | low entropy, low velocity | subtle particles | | Focused | high attention, low entropy | clear emphasis | | Turbulent | high entropy, high velocity | reduce motion/dampen | | Dense | high concentration | open spacing/screen text | | Charged | high heat/activity | highlight active state | | Remembered | high memory | show paths/history | | Critical | budget/energy threshold | reduce sources/warn | ## 18. Collaborative Fields | User signal | Field behavior | |---|---| | cursor | moving attractor/wake | | selection | attention well | | edit | heat deposit | | comment | anchored source | | presence | aura | | conflict | repulsion/entropy | | agreement | coherence | | handoff | stream | ## 19. Forms and Validation | Form state | Field behavior | |---|---| | empty | low density | | focused | attract | | valid | coherence/glow | | invalid | entropy/repel/heat | | required | attention well | | optional | lower strength | | submitting | stream/fieldflow | | success | release | | error | thermal pulse | ## 20. Navigation as Current | Navigation state | Field behavior | |---|---| | current page | attractor well | | previous page | memory trail | | next likely page | stream direction | | related page | thread | | breadcrumb | stable path | | disabled route | screen | | external link | emitter | ## 21. Search and Filtering | Search signal | Field mapping | |---|---| | relevance | strength | | exact match | attract | | semantic match | cohesion | | excluded result | repel | | recent result | heat | | clicked result | memory | | category | formation | | uncertainty | entropy | Search can transition: ```txt formation = scatter -> wells ``` ## 22. Reading and Editorial Experiences Reading is the flagship normal-content use case for this model: an ordinary article, not a particle demo. The **Reading Field** demo (shipped, at `/docs/reading-field`) is a plain content page that exercises all six phases of the `FrameScheduler` across four platform registries (it does not use the visual-binding or overlay registries). Sections become bodies (`MeasurementRegistry`); viewport proximity becomes attention (`StateRegistry`); dwell accumulates into memory; the table of contents reflects the field state (`FeedbackRegistry`); and citations resolve into typed relationships (`RelationshipRegistry`) via the native-signal binding described in section 7. Under reduced motion the meaning is preserved — emphasis and state survive even when travel does not. | Reading signal | Field behavior | |---|---| | viewport center | attention well | | read paragraphs | memory trail | | footnotes | threads | | important terms | attractors | | citations | link tension | | unresolved concept | entropy | | summary | coherence sink | ## 23. State Machines as Physical Scenes Example: ```ts type ButtonFieldState = | "idle" | "hovered" | "focused" | "pressed" | "loading" | "success" | "error" ``` | State | Field | |---|---| | idle | ambient | | hovered | attract | | focused | attract + feedback | | pressed | absorb | | loading | stream/vortex | | success | release | | error | repel + thermal | > **Implemented.** `FieldState` + `FIELD_STATES` in `packages/core/src/semantic/states.ts`. ## 24. Interaction Materials Forces define behavior. Materials define feel. | Material | Behavior | |---|---| | glass | lens + reflect + low drag | | rubber | spring + damping | | liquid | cohesion + pressure | | plasma | fieldflow + thermal + trails | | dust | diffuse + low mass | | metal | magnetism + reflect | | fabric | link + shear | | paper | low motion + memory | | stone | high mass + low response | | smoke | diffuse + stream + entropy | > **Implemented.** `INTERACTION_MATERIALS` + `materialBody()` in > `packages/core/src/semantic/materials.ts`, composed from real force tokens. ## 25. Field Affordances | Affordance | Field expression | |---|---| | clickable | weak attractor | | draggable | spring/link response | | related | thread or memory path | | dangerous | heat/repel | | completed | coherence | | loading | stream | | disabled | screened | | selected | captured | | recommended | attention well | | historical | memory glow | ## 26. AI Interface Use Cases | AI state | Field behavior | |---|---| | candidate answer | attractor | | uncertainty | entropy | | source support | relationship tension | | contradiction | repulsion | | user correction | memory overwrite | | synthesis | cohesion | | hallucination risk | instability/heat | | verified claim | coherence | | active generation | stream/fieldflow | ## 27. Explainable Interaction The system should answer: ```txt Why is this emphasized? Why did this move? Why are these connected? Why did the page calm down? Why did this warning appear? ``` Principle: ```txt Every visible behavior should be traceable to a field cause. ``` ## 28. Implementation Priority Several items below have shipped on the platform runtime (Phase D). The `RelationshipAgent` model is backed by the `RelationshipRegistry`; the reading/editorial use case ships as the Reading Field demo (section 22). Remaining items stay as authoring priorities and experiments. ```txt 1. Formal FieldAgent model 2. ElementAgent responder variables beyond density 3. RelationshipAgent model — shipped (RelationshipRegistry) 4. Attention budget 5. UserAgent model for pointer/focus/selection 6. Thresholded field events 7. Relationship heatmaps 8. Navigation/search recipes 9. Form state recipes 10. Reading/editorial recipes — shipped (Reading Field, /docs/reading-field) 11. Collaborative presence experiments 12. AI state visualization recipes ``` ======================================================================== FILE: invisible-fields.md ======================================================================== > **Status: canonical.** > The invisible-fields pattern: running the field with **no drawn surface at all**, so its > measurements come back as typography, ink, and anchor. Defines the third placement (after > underlay and overlay), the two-field page architecture, the live feedback channels, the > engagement contracts (`data-hot`, `data-active`), declared relationships > (`data-field-relation`), and the data-provenance honesty pattern. Everything here is shipped > and verified against code; the reference implementation is the example family at > `apps/site/src/pages/evidence*` (twelve pages, e2e-tested in `apps/site/e2e/`). # Fundamental Invisible Fields ## Related Documents | Document | Role | |---|---| | [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Surfaces & Placement (underlay / overlay) — this doc adds the third | | [`system-contracts.md`](system-contracts.md) | The hard contracts (bodies, feedback, relationships) | | [`platform-architecture.md`](platform-architecture.md) | The platform runtime, registries, scheduler | | [`agent-consumption-model.md`](agent-consumption-model.md) | How consumers read one influence differently | | [`definition-document.md`](definition-document.md) | The operating model ("substrate, not wallpaper") | ## 1. What an invisible field is The definition document says the field is a **substrate, not wallpaper**. An invisible field is that claim taken literally: the engine runs, bodies participate, matter flows — and **nothing is drawn**. The only output is the feedback the platform writes back to the DOM (CSS variables, thresholded events), and the only render surface is the page's own type and ink, styled by CSS that reads those variables. This is the third **placement** in the Surfaces & Placement taxonomy: | Surface | Placement | Drawn on | Status | |---|---|---|---| | Underlay | behind content | the `` canvas | shipped | | Overlay | in front of content | a second light-DOM canvas | shipped | | **Typographic (invisible)** | **in the content itself** | **nothing — feedback variables styled by author CSS** | **shipped** | Two shipped mechanisms produce it: - **Engine, draw-skipped** — `FieldHandle.setVisible(false)` keeps the full simulation and its feedback live while skipping all draw work (`packages/core/src/core/field.ts`). The `` element wires this automatically from an IntersectionObserver, so a page that hides the element with CSS (`display: none`) gets a signals-only engine for free. - **Recipe, render-less** — `applyRecipe(root, { ...recipe, render: [] }, { bodies })` runs the platform's metric pipeline over explicit bodies with no engine canvas at all (`packages/platform/src/apply-recipe.ts`). Formalizing the first mechanism as a named engine mode is filed as [#297](https://github.com/zachshallbetter/fundamental-engine/issues/297). ## 2. The two-field page architecture Every invisible-fields example page runs **both** mechanisms at once, and they are not redundant — they write different lanes: ```txt the PAGE ENGINE (hidden , setVisible(false) via IO) real particle simulation over every [data-body] on the page writes: --d (live local density), --load/--mass (sink fill), --lit, capture/release events, field:* thresholded events honors: data-hot engagement (hover/focus -> the body activates, the spine bends to it, density gathers -> --d rises toward 1) the SCOPED RECIPE PIPELINE (applyRecipe, render: []) geometric metric computation over the page's explicit record bodies writes: --field- for every metric the recipe declares (the examples extend the evidence-field recipe with "attention") inputs per frame: viewport-center proximity, visibility ratio, engaged (:hover, :focus, :focus-within, [data-active]), relationship resolution/conflict, host-supplied data-field- ``` A record on an example page therefore carries **four live channels** plus its server data: | Variable | Written by | Semantics | Movement | |---|---|---|---| | `--w` (page-local, e.g. `--trust`) | server / page runtime | the data's normalized weight | on lens/weight change | | `--cat` | server / page runtime | the active lens color | on lens change | | `--d` | the page engine | live local particle density (0..1) | every frame; gathers to ~1 on `data-hot` hold | | `--field-attention` | the scoped pipeline | eased blend of engagement + proximity + visibility | every frame; follows scroll and hover | CSS composes them: weight drives `font-variation-settings`/opacity; the live channels drive a glow and background lift that is **felt, not loud** — and `main[data-field="off"]` zeroes the live channels, so "field off" is honest. ## 3. Engagement contracts Two attributes make engagement programmable; both are shipped and verified: - **`data-hot`** (engine) — the engine's scanner wires hover/focus listeners on `[data-hot]` elements at scan time; engaging one activates its body (`b.on`), bends the wave spine to it, and gathers matter — its `--d` rises toward 1 and eases back on release. The attribute must be present **at scan time** (ship it in markup; a rescan picks up late additions). - **`data-active`** (metric pipeline) — the recipe pipeline's `engaged` input is `el.matches(':hover, :focus, :focus-within') || el.hasAttribute('data-active')`. Setting `data-active` programmatically is the sanctioned way to tell the field "this element is in hand": the backlog example sets it on a card for the duration of a drag (the field re-measures work in flight), and the fleet example holds it ~3 s on a live status change (the field notices the change). Canon-doc coverage of these two attributes is the substance of [#298](https://github.com/zachshallbetter/fundamental-engine/issues/298); this section is that documentation. ## 4. Declared relationships The `RelationshipRegistry` builds the live relationship graph from DOM signals only. Its `discover()` scan matches native link semantics (`a[href^="#"]`, `label[for]`, `aria-controls/-describedby/-labelledby/-flowto`) and one declarative attribute form: ```html ``` A body **contains** its declaration elements, so a record can declare many edges through hidden child spans. The metric pipeline counts, per body, the touching relationships that resolve on-page versus those declared-but-unresolved — that ratio is what `--field-coherence` reads. The evidence example renders its real citation edges this way: the same edges its hover threads draw are the graph the platform measures, and connected findings read `--field-coherence: 1.000` while unconnected ones read `0.000` (verified live). The `relationships?: RelationshipRecipe[]` field in the `FieldRecipe` schema is **not** a live-graph input. It is compiled metadata used exclusively for the reduced-motion static display — `applyRecipe` renders declared pairs as a `

` list when `prefers-reduced-motion` is set. To put an edge into the live graph, author it in the DOM with `data-field-relation` / `data-field-target`. ## 5. Conditions in the page: the reading-pace gate `--field-scroll-v` on `:root` is the engine's eased scroll velocity (px/frame; written by the platform write phase, deduped when unchanged). The invisible-fields pages use one shared condition built on it — **reading pace** (`< 2.0`) — to gate progressive behavior: - the evidence page's deferred-batch reveal (plus a sink-charge short-circuit: a sentinel `data-body="sink"` whose engine-written `--load` can pre-empt the dwell), - chart entry animations (sparkline dash draw-ins, bar sweeps, card staggers) — applied instantly, without animation, when the user is scanning fast or prefers reduced motion. The unit is px/frame at the display refresh rate (refresh-rate dependent; see the API note in `scripts/api-surface.data.mjs` — it may normalize to px/ms before 1.0). ## 6. Data honesty: snapshots, provenance chips, cadence The examples run on real data with a strict provenance contract: - **The committed snapshot is the baseline.** Every page ships a committed JSON snapshot (`apps/site/src/data/examples/`, regenerated by `apps/site/scripts/snapshot-examples.mjs`, refreshed weekly by `.github/workflows/snapshots.yml`). It is the SSR baseline and the no-JS truth; builds are deterministic. - **Pages upgrade themselves and say so.** A provenance chip states the mode: `live · checked Ns ago` after a successful refresh, `snapshot · ` before one or after failures. Client-diverged state is marked (`(local)` on the triaged backlog; `+N since snapshot` on refreshed citation counts). A page that can prove it is not lying is a feature, not a caveat. - **Cadence matches the source's real update rate.** 60 s for markets and fleet status, 5 min for the question feed (API backoff honored), **once per visit** for daily/weekly aggregates — polling a daily aggregate would be theater, and the pages say so in their how-built sections. - **The plumbing is shared.** `apps/site/src/lib/live-data.ts`: `politeLoop` (skips hidden tabs but **owes** the skipped attempt and catches up on `visibilitychange`; retires after 3 consecutive failures; cleans up on the page's AbortController) and `wireLiveChip` (the chip contract above). Failures are silent by design — the page keeps its snapshot. ## 7. The family (reference implementations) Twelve pages at `/evidence` and `/evidence/` (roster: `apps/site/src/lib/invisible-fields.ts`); each demonstrates a distinct capability, and the layout itself embodies the concept: | Example | Geometry | Demonstrates | |---|---|---| | Evidence | weighted list | trust as mass; declared relationships → live coherence; batched live refresh | | Inbox | focus split | **conserved attention** — Σw is exact through pin/unpin/arrivals; live arrivals enter the field | | Market | cap-weighted mosaic | mass is *area*; polarity lens; 60 s live polling; visual-bound sparklines | | Backlog | two-lane board | hand-rolled pointer drag; `data-active` engagement in flight; sink-backed cycle capacity; local-honesty markers | | Calendar | day / week / month | time itself as the field input (1 Hz imminence ramp); same bodies, three geometries | | Threads | indented tree | binding chains; subtree collapse with honest hidden counts | | Dependencies | graph strip + list | causality spill along real `usedBy` edges; staleness decay | | Fleet | grid + timeline | sink capture/release as incident accretion; live status diffing with `data-active` pulses | | Catalog | shelf grid | the evidence trust formula retargeted; shared-subject affinity | | Library | ranked bar ladder | a real sink-backed queue (engine `--load`) that fills and releases | | Memory | word-card grid | decay (forgetting curve) vs. anchoring; localStorage persistence | | Newsroom | newspaper front page | placement as encoding; rebuilds itself to the latest edition | The page-level lesson, stated on the calendar example and true of all twelve: **the field does not care about the layout; it measures whatever geometry you give it.** Their invariants are pinned by the e2e suite (`apps/site/e2e/` — 8 specs, 21 tests, network blocked to non-localhost so pages hold their snapshots), run in CI on PRs touching the site or packages. ## 8. What the pattern earned the platform Building twelve pages against the contracts above surfaced the platform's next API work, filed and boarded: [#295](https://github.com/zachshallbetter/fundamental-engine/issues/295) a platform FLIP helper (every runtime hand-rolls the same reflow), [#296](https://github.com/zachshallbetter/fundamental-engine/issues/296) `allocateAttention()` (the inbox's exact conserved water-filling belongs to the engine's attention concept), [#297](https://github.com/zachshallbetter/fundamental-engine/issues/297) a named signals-only engine mode, [#299](https://github.com/zachshallbetter/fundamental-engine/issues/299) a mobile/touch QA pass. ## 9. The same pattern, turned on the chrome (the navigation sweep) The invisible-field is not only for content — the site's own **navigation chrome** is a body set too. The nav sweep makes every navigation surface a field of its own links, each driven by an existing catalog recipe, all signals-only, all progressive enhancement (with the engine off or under reduced motion the `--field-*` lanes are unset and the links render as plain, reachable chrome): - top nav + footer → **`wayfinding-field`** ("where am I"); the home chapter rail → **`wayfinding-current`** ("where have I been"); docs/writings sidebars → **`priority-well`** (the current route pinned as the well); the on-this-page outline + examples spy → **`reading-field`** (a dwell-accreted read trail); search → **`search-relevance-field`**; breadcrumbs + prev/next pagers → **`navigation-current`**. - A cross-surface **visit log** grounds one "seen / visited" memory shared by search, breadcrumbs, and pagers. **What it earned the platform.** The navigation-chrome idiom — run a recipe `render: []` over the `` links, pin the current, mark the visited, return a teardown — lifted out of the site into **`bindFieldNav`** (`@fundamental-engine/platform`), the same way the example family earned FLIP and `allocateAttention` above. **The honesty it forced.** On a small nav (a two-link pager, a breadcrumb) "signals-only" is mostly a *grounded-metric transport*: the host supplies the signal (current / visited), the platform eases it, CSS consumes it — the recipe's physics forces are dormant. That is the same honesty as a declared `data-field-at` grounding the recency lane (§6), not a claim that physics drives the nav. It also exposed a real silent gap: a recipe may **declare a metric the platform can never produce**. `computeMetrics` writes seven **computed** lanes; `confidence`/`risk` are **supplied-only** (the engine never invents them); everything else a recipe lists is **designed** — the host must supply `data-field-` (or a domain model) or the `--field-` lane is *inert*: declared, bound, never written. The sweep hit this — `navigation-current` declares `signal` and `route-strength`, which no signals-only binding produces. `classifyMetric(name)` now names the split, and **`lintInertFeedback`** (in `lintPlatform`) flags a feedback binding to an inert designed lane — the same silent-contract class as `lintSinkFeedback` (a sink that captures but never reports). A lane you can read but the engine will never write is now a lint, not a surprise. ======================================================================== FILE: natural-fields.md ======================================================================== > **Status: canonical.** > This document defines the Natural Field Translation System — how Fundamental translates the four > fundamental fields into interface behavior. The classification here is data > (`FORCE_KIND` / `FORCE_FIELD` / `NATURAL_FIELDS` in `packages/core/src/config/manual.ts`), so the > force manual, the Lab badges, and `/docs/natural-fields` all read it and cannot drift. It changes > no particle/engine behavior — only how each token is explained and organized. See > [platform-architecture.md](platform-architecture.md) and > [../engine-reference/forces-system.md](../engine-reference/forces-system.md). # Natural Fields **How Fundamental translates the four fundamental fields into interface behavior.** Fundamental does not copy physics into the interface. It **translates** the four fundamental fields into interface behavior: - **Gravity** becomes priority. - **Electromagnetism** becomes polarity and signal. - **Strong interaction** becomes binding. - **Weak interaction** becomes transformation. The engine then exposes practical primitives that make those translations usable inside a DOM-native runtime. Every interface already has priority, polarity, binding, and transformation; physics already has a compact language for those relations. Fundamental borrows the language, not the literal physics. > **Four fields. Many expressions. One DOM runtime.** ## The governing doctrine ``` 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. Recipes compose behavior into interface meaning. ``` Short version: **natural fields are not tokens; tokens are translations.** So `gravity` is both a fundamental field and an implemented primitive; `charge` is not a fifth force but an electromagnetic translation; `magnetism` is the magnetic expression of electromagnetism; `thermal` is a derived energy behavior; `memory` is a persistence metric; `fieldflow` is transport along field structure. This does **not** reduce the particle engine. Particles still fall into wells, curve through magnetic fields, flow along field lines, scatter under thermal agitation, diffuse, collide, bind, and leave memory trails. The four-field model only gives each behavior a clean place in the hierarchy: ``` Natural field → interface translation → engine primitive → metric → diagnostic → recipe ``` ## The four fields ### Gravity — priority, convergence, hierarchy Gravity is the grammar of what matters. In physics it gathers mass, makes wells, and produces orbital structure. In Fundamental it translates into priority, weight, attraction, hierarchy, settling, and convergence. Reach for it for ranking, search relevance, centrality, anchoring, and attention wells. - Engine expressions: `gravity` (primitive); plus `mass`, `potential`, `prediction` as measurement. - Note: `attract` is **not** gravity — `attract` is a designed UI well; `gravity` is the natural translation. ### Electromagnetic — polarity, signal, field lines, flow The grammar of difference and signal. Electric fields push charged matter; magnetic fields bend moving charged matter. In Fundamental this becomes polarity, opposition, signal, routing, field lines, propagation, and guided flow — for contrast, state opposition, relationship currents, and plasma-like motion. - Engine expressions: `charge`, `magnetism`, `propagate` (primitives); `fieldflow` (transport). - The rule: **Electric fields push. Magnetic fields bend. Fieldflow carries.** Do not make `magnetism.apply()` follow magnetic field lines — field-aligned transport belongs to `fieldflow`. - Note: `repel` is **not** charge — `repel` is a designed UI verb. ### Strong — binding, cohesion, structure The grammar of what holds together: groups, clusters, relationships, constraints, bonds, lattices, durable local structure. Reach for it for grouping, relationship strength, clusters, and material integrity. - Engine expressions (analogues): `cohesion`, `link`, `crystallize`, `pressure`, `align`. ### Weak — transformation, decay, release The grammar of change: fading, mutation, release, conversion, instability, phase shifts, expiration, handoff. Reach for it for state change, decay, expiration, and transformation. - Engine expression (analogue): `morph`. Other weak behaviors (phase, decay, fission) are conceptual and not yet implemented as forces; the closest shipped persistence behavior is `memory` decay. ## Fields vs primitives vs forces | Type | Definition | Examples | |---|---|---| | **Natural field** | conceptual physical basis | gravity, electromagnetic, strong, weak | | **Engine primitive** | a direct field expression | `gravity`, `charge`, `magnetism`, `propagate` | | **Derived behavior** | effective behavior from many interactions / scalar fields | `thermal`, `collide`, `diffuse` | | **Material analogue** | a strong/weak structural analogue | `cohesion`, `link`, `crystallize`, `pressure`, `align`, `morph` | | **Transport** | motion along field structure | `fieldflow`, `pigment` | | **Metric** | a persistence/measurement signal, not physics | `memory` | | **Canonical force** | a designed UI verb with bounded behavior | `attract`, `repel`, `swirl`, `stream`, `viscosity`, `jet`, `tether`, `wall`, `sink` | | **Composite** | a recipe of tokens | `blackhole`, `galaxy`, `star`, … | This keeps the full implementation vocabulary while preventing the confusion of a flat "natural forces" list. (The machine-readable form is `FORCE_KIND` + `FORCE_FIELD` in `config/manual.ts`.) ## The interface translation table The lanes are kept separate: **runtime tokens** (strict, real engine forces), **metrics** (measured state), and **diagnostics** (inspection modes). A word's lane is never left to the reader to guess. | Interface need | Natural field | Runtime tokens | Metrics | Diagnostics | |---|---|---|---|---| | Show importance | Gravity | `gravity`, `attract` | mass, priority, attention | potential, prediction | | Draw attention | Gravity + EM | `gravity`, `charge`, `spawn` | attention, confidence | potential, causality | | Show opposition | Electromagnetic | `charge`, `repel` | polarity, conflict | field-lines, causality | | Route signal | Electromagnetic | `charge`, `propagate`, `fieldflow`, `stream` | signal, strength | field-lines, force-vectors | | Show relationship | Strong + EM | `link`, `cohesion` | relation-strength | topology, causality | | Keep things grouped | Strong | `cohesion`, `crystallize`, `align` | cluster, density | topology, heatmap | | Show instability / change | Weak | `morph` | entropy, conflict | causality, contours | | Let state fade | Weak + memory | `morph`, `memory` | decay, age | heatmap, inspector | | Show flow through structure | EM + transport | `fieldflow`, `stream` | flow, velocity | field-lines, prediction | | Show reading history | Memory (metric) | `memory` | attention, recency | heatmap, inspector | In every row the `code-styled` words are real runtime tokens; the unstyled words are metrics or diagnostics, never forces. `mass` is a metric, `potential` is a diagnostic — neither is a token. ## Diagnostics by field Each diagnostic answers "which invisible relation am I revealing?" | Diagnostic | Reveals | Field | |---|---|---| | Potential | wells and energy landscape | Gravity | | Field lines | electromagnetic structure | Electromagnetic | | Topology | binding and relationships | Strong | | Causality | which primitive caused change | any | | Prediction | near-future path | Gravity / flow | | Energy | activity level | derived (thermal) | | Contours | scalar fields | derived (diffuse, memory) | | Velocity vectors | actual motion | transport (fieldflow) | | Inspector | all of the above | system | All diagnostic render modes are shipped — see [visualization-methods-taxonomy.md](visualization-methods-taxonomy.md) and the live [/docs/diagnostics](https://fundamental-engine.com/docs/diagnostics). ## Recipes by meaning Interface-native recipes name the *meaning*, then map to a field: | Recipe | Field | Use | Primitives | |---|---|---|---| | Priority Well | Gravity | search, dashboards, navigation | `gravity`, potential, prediction | | Signal Path | Electromagnetic | citations, dependencies, evidence | `charge`, `propagate`, `fieldflow` | | Relationship Bond | Strong | groups, semantic clusters | `link`, `cohesion`, topology | | Memory Trace | Metric / weak decay | reading, history | `memory`, attention, feedback | | Reading Field | Gravity + memory + relationships | long content pages | measurement, state, feedback, relationships | | Evidence Field | Electromagnetic + strong | source support | `charge`, topology, causality | ## The frame The system should not say "we have physics-inspired UI effects." It says: every interface has priority, polarity, binding, and transformation; physics already has a compact language for those relations; Fundamental translates that language into DOM behavior. **Four fields. Many expressions. One DOM runtime.** ======================================================================== FILE: platform-architecture.md ======================================================================== > **Status: canonical.** > This document defines the current `@fundamental-engine/platform` architecture as of the runtime-platform > unification phase (Phase D): the FrameScheduler, the six registries, `lintPlatform()`, the live > `` runtime, and the platform→core boundary. For force/field math see > [forces-system.md](../engine-reference/forces-system.md); for the data model and contracts see > [definition-document.md](definition-document.md) and > [system-contracts.md](system-contracts.md). # Fundamental platform architecture Fundamental is a **platform-native relational field runtime for the DOM**. It lets semantic HTML, DOM elements, particles, relationships, measurements, visual layers, and user interaction participate in one shared field context. The visible particle canvas is **one render surface**, not the whole system. ## Package hierarchy ``` Fundamental renderer-agnostic field, force, particle, metric, diagnostic, and conformance logic. Computes field behavior against plain data. Touches no DOM globals (guarded by core/dom-boundary.test.ts; the canvas renderer in core/field.ts and the download helper in export.ts are the two allowlisted, quarantined exceptions). @fundamental-engine/platform DOM participation: measurement, state, feedback, relationships, visual bindings, overlays, scheduling, and linting. Depends on core for contracts; core never depends on it. @fundamental-engine/elements native web components — / and the [data-body] authoring contract. @fundamental-engine/react the React adapter over the same contracts (, useFieldField). @fundamental-engine/vanilla the FieldField class for plain TypeScript apps. @fundamental-engine/kit umbrella meta-package — installs the whole suite (core + platform + the three adapters) in one dependency. No code of its own; import from the specific package. fundamental-engine is a thin alias. apps/site · lab · docs product surfaces, executable documentation, diagnostics, examples, and previews. ``` Dependency direction is strict and uniform: `elements → platform → core`, `react → platform → core`, `vanilla → platform → core`. `Fundamental` is renderer-agnostic and imports **zero** DOM (enforced by `core/dom-boundary.test.ts` with an empty allowlist); the browser environment adapter — `browserHost()`, `createBrowserField()`, and the DOM download helpers — lives in `@fundamental-engine/platform`. `createField(canvas, opts)` requires `opts.host`; the framework entry points wire `browserHost()` for you. ## The FrameScheduler The platform runs one shared loop with explicit, ordered phases, so the registries never interleave reads and writes and thrash layout: ``` discover → read → compute → state → write → render ``` 1. **discover** — register/unregister bodies, relationships, and visual bindings (structure changes). 2. **read** — measure the DOM once: snapshot geometry and visibility. The only place layout is read. 3. **compute** — run field/force/agent logic against the immutable snapshot. No DOM. 4. **state** — fold results into the StateRegistry and thresholds. Internal truth, no DOM writes. 5. **write** — flush state to CSS variables, data attributes, ElementInternals, and thresholded events. 6. **render** — draw overlays, field lines, and heatmaps from the registries (read-only). The platform **owns discover through write**. `createFieldPlatform(root, { strict? })` wires only two phases by default — `measure → read` and `flush → write` — and installs a read-phase guard (a measurement requested off-phase is recorded, or thrown under `strict`). The remaining phases (`discover`, `compute`, `state`, `render`) are **caller-open**: the platform exposes `.on(phase, handler)` so callers attach handlers off the same loop without the platform owning their logic. The render phase in particular is not wired by the platform at all — it is a slot the legacy engine fills by running the canvas simulate-and-render loop; the platform observes and feeds back DOM state, it does not draw. `tick(now, viewport)` runs one full frame and returns a report of the phases that ran and any violations. ## The six registries 1. **MeasurementRegistry** — frame-stable geometry. Reads every registered element's box once per frame and returns an immutable snapshot, so the rest of the system works from one consistent set of rectangles. A `getRect` override supports closed Shadow roots and inner cores. Read-phase only. 2. **StateRegistry** — typed, observable element state (numeric / boolean / string / vector2). This is internal truth, distinct from ARIA. CSS and JS both consume it; only feedback writes it. 3. **FeedbackRegistry** — the write phase. Turns held state into CSS custom properties (continuous) and thresholded, debounced events (discrete, with hysteresis). Mirrors `--field-*` → `--forces-*` and `field:*` → `forces:*` during the alias window. Do not let other modules write CSS variables directly. `cssWritesLastFrame()` reports the actual `style.setProperty` calls made during the last `flush()` — a mirrored `--field-*`/`--forces-*` pair counts as 2 — which is the real per-frame DOM write cost (off-screen elements with active bindings still generate mutations). It is distinct from `boundVars().length`, which counts registrations, not writes; the DataConsole's write-cost metric reads it. 4. **RelationshipRegistry** — the DOM is a tree, but interfaces are graphs. Normalizes the relationships HTML/ARIA already express (`a[href#id]`, `label[for]`, `aria-controls` / `-describedby` / `-labelledby` / `-flowto`, `data-field-relation` / `-target`) into one typed graph, mapped onto core `RelationshipAgent`s. 5. **VisualBindingRegistry** — binds an expressive visual layer (SVG, Canvas, WebGL) to its semantic DOM source without duplicating meaning. The visual is `aria-hidden` unless it carries independent meaning; `lint()` flags orphan and un-hidden visuals. Bindings can be authored declaratively: mark the visual with `data-field-visual-for` (the source's id or selector) and `data-field-visual-role` (`decorative` · `representation` · `debug` · `relationship` · `measurement`), then call `platform.visuals.scan(root)`. `scan()` resolves each source, binds it, and returns `{ total, bound, unresolved, warnings }`. It is idempotent (keyed by the visual element, so re-scanning updates role/source and prunes disconnected visuals) — safe to re-run after navigation. `representation` and `relationship` roles require a resolved source; a missing one is reported as unresolved rather than throwing. **State mirroring (the Bound Visual Sink tier).** CSS custom properties don't cross to siblings, so the registry mirrors them: with `setMirroring(true)` — the `createFieldPlatform` default — every `representation`/`measurement` visual receives its source's feedback channels (`MIRRORED_CHANNELS`: `--d`/`--field-density`/`--forces-density`, `--load`/`--mass`, `--lit`, `--entropy`/`--coherence`/`--temperature`, `--field-heatmap-density`) copied onto its own inline style — an `aria-hidden` SVG beside a sink heading thickens its contours from `var(--load)` exactly as authored. Change-gated via a MutationObserver on the source's style attribute: a quiet field costs nothing. `decorative`/`debug` roles never mirror. The platform runtime (`startPlatformRuntime`) scans declarative visuals at start; dynamically added visuals need a `platform.visuals.scan()`. - **Implemented:** the registry, declarative binding via `data-field-visual-for` / `data-field-visual-role` (`scan()`), the accessibility lint, and source→visual state mirroring (`setMirroring` / `mirrorNow` / `MIRRORED_CHANNELS`). - **Glyph outlines (the Contour Sink tier):** `contours.ts` is the font-agnostic primitive — `contourPathData(font, text, size)` (pure layout: per-glyph + pair kerning, Latin display scope) and `contourSvgFor(el, font)` (generates the aria-hidden ring SVG from the element's OWN text and computed size, binds it via `data-field-visual-for`, receives mirrored state). The caller supplies the parsed font — any `ContourFont`-shaped object; opentype.js satisfies it directly — so the primitive works with whatever face the author applied to the body, and Fundamental keeps its zero-dependency rule. The same primitive runs at build time (the site's `gen-contours.mjs` commits its output). Automatic font-binary discovery from the element's CSS, complex-script shaping, and true offset contours (polygon offsetting) remain future work. 6. **OverlayRegistry** — relationship lines, field lines, debug layers. Render layers only: they read from the relationship + measurement registries and produce geometry to draw. They never own relationships or mutate physics. *Overlays reveal. They do not define.* ## Platform lint `lintPlatform(platform)` aggregates pure guardrail rules that surface the quiet failures of a field system: - `relation-target-missing` — `[data-field-relation]` with a missing or unresolvable target. - `state-unregistered` — an element holds field state but was never registered for measurement. - `overlay-without-links` — a relationship overlay with no relationships behind it. - `feedback-non-css-var` — a binding that writes ARIA/attributes instead of a `--field-*` variable. - `measurement-off-phase` — a layout read recorded outside the read phase. - `visual-orphan` / `visual-not-hidden` — accessibility hazards from `VisualBindingRegistry`. Lint reads. It never mutates state, physics, or the DOM. ## The live runtime (Phase D) Since Phase D the platform runtime is the **default** for every ``. The legacy engine (`core/field.ts`) still simulates and renders the canvas, while the platform owns DOM participation: - **D1** — a platform-backed `` path behind an experimental flag. - **D2** — body discovery/measurement routed through MeasurementRegistry (`bodyElements` is the one selector source of truth shared with the legacy scanner). - **D3** — CSS-variable + event feedback routed through FeedbackRegistry via a `feedbackSink` seam in `createField`; the eased density signal is unchanged, only the write target moves. Since #228 the sink contract is the engine's **only** feedback write path: when no platform sink is configured (raw `createField`, `@fundamental-engine/vanilla`, recipe-scoped engines), the engine installs an internal default sink (`core/feedback-sink.ts`) whose direct writes are byte-identical to the historical behavior — same variables (`--d`/`--forces-density`/`--field-density`, the heatmap mirror pair, `--load`/`--mass`, `--lit`), same three-decimal formatting, same `field:lit`/`field:dim` hysteresis. There is no direct-write branch left in the engine loop. - **D4** — Shadow-DOM host registration handled by the platform (the host's `getRect` flows into MeasurementRegistry). - **D5** — the relationship graph discovered and maintained in the running field-root. - **D6** — the platform runtime flipped to default after parity. Opt back to the pure-legacy path per element with `experimental-platform="off"`, or globally with `usePlatformRuntime(false)`. - **D7** — the legacy DOM glue quarantined behind a renderer-agnostic boundary guard (`core/dom-boundary.test.ts`), so core stays DOM-free outside the two allowlisted modules. **Frontier — done:** `core/field.ts` (the engine + canvas render loop) no longer touches any DOM globals. It routes every environment touchpoint (viewport, scroll, rAF, reduced-motion, visibility, scan root, events) through an injected `FieldHost`; `browserHost()` and the DOM download helpers moved to `@fundamental-engine/platform`. `core/dom-boundary.test.ts` now runs with an **empty allowlist** — every source file in `Fundamental` is provably DOM-global-free, so the engine is portable to any renderer (Canvas, WebGL, WebGPU, native, headless) via a custom host. ## Attaching the engine handle The platform runtime starts before the engine handle exists: `startPlatformRuntime(root)` begins scheduling as soon as `` connects, while `createField()` runs later in the element's start path. `PlatformRuntime.attachHandle(handle)` (`packages/elements/src/platform-runtime.ts`) wires the two post-hoc. Once a handle is attached: - The **write phase** writes `--field-scroll-v` — the handle's eased scroll velocity, `scrollV()`, formatted to three decimals — to `:root` each frame, deduped when the value is unchanged so idle frames stay mutation-free. It is written directly, **not** through FeedbackRegistry: it is a page-global, not a per-body channel, so it does not count toward `cssWritesLastFrame()`. - The **QualityGovernor** begins monitoring frame spacing (the governor is reset on attach, so detection starts from full quality). ## The QualityGovernor `QualityGovernor` (`packages/platform/src/governor.ts`) detects sustained frame-budget overruns and emits a coarse tier signal. The split is deliberate: the governor detects, the caller responds. | Tier | Meaning | Escalates after | |---|---|---| | 0 | full quality (default) | — | | 1 | effects reduced | 10 consecutive frames > 20 ms | | 2 | minimal | 5 consecutive frames > 33 ms | | 3 | paused | 3 consecutive frames > 50 ms | Recovery is asymmetric to avoid thrashing at the boundary: dropping back down requires **30 consecutive clean frames per tier step**. `reset()` returns to tier 0 and clears both streaks. The `` runtime feeds the governor rAF-to-rAF spacing, skips discontinuity frames (gaps > 500 ms — background tabs, system sleep, debugger pauses — are timing artifacts, not budget overruns), resets it on `visibilitychange`, and dispatches a `field:quality-tier` CustomEvent (bubbles, composed, `detail: { tier, durationMs }`) from the scan root whenever the tier changes. One consumer is built in: at tier 2 the platform tick — measurement, feedback writes, relationship discovery — runs every 2nd frame, at tier 3 every 4th. The engine keeps simulating at full rate; only the platform's DOM read/write cadence drops. Engine-side responses (render simplification, particle caps) are the embedder's to wire via the event — that surface is unfrozen/experimental. ## Reading Field [/docs/reading-field](https://fundamental-engine.com/docs/reading-field) is the flagship demonstration: an ordinary content page (sections, headings, citations, a table of contents) wired to `createFieldPlatform`, exercising every registry through the scheduler. Sections are measured bodies; viewport-centre proximity becomes attention; attention accumulates into memory; the table of contents reflects memory and the current section; citations become relationships. Reduced motion loses no meaning — state still tracks; only CSS easing drops. It proves the substrate on prose, without spectacle. ## Authoring across surfaces The same field body is authored three ways, all compiling to the same `[data-body]` contract: native HTML (`createField` + `[data-body]`), the web component (`` + `[data-body]`), and React (`` + `[data-body]`). See [authoring-and-recipes.md](authoring-and-recipes.md) and the live `/docs/authoring` page. ======================================================================== FILE: system-contracts.md ======================================================================== > **Status: canonical.** > Hard contracts for bodies, fields, forces, agents, events, feedback, recipes, accessibility, performance, conformance, and the platform. Current as of the platform-runtime phase (Phase D). See [platform-architecture.md](platform-architecture.md) and [system-contracts.md](system-contracts.md). # Fundamental System Contracts ## Related Documents | Document | Role | |---|---| | [`README.md`](./README.md) | Documentation map | | [`definition-document.md`](definition-document.md) | Canonical definition | | [`fundamental-field-behavior-table.md`](fundamental-field-behavior-table.md) | Field/force laws | | [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md) | Agent model | | [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Render contracts | | [`testing-and-conformance.md`](testing-and-conformance.md) | Test contracts | ## Purpose Fundamental is a platform-native relational field runtime for the DOM. `Fundamental` computes renderer-agnostic field behavior; `@fundamental-engine/platform` binds it to the DOM (measurement, state, feedback, relationships, visual bindings, overlays, scheduling, linting); `elements`/`react` are authoring surfaces. The contracts below bind these layers together — a shared field context across bodies, agents, relationships, measurements, metrics, feedback, and render surfaces. Canvas is one render surface, not the whole system. This document defines the hard contracts that bind the system together. Contracts answer: ```txt What must exist? What may mutate state? What must remain side-effect free? What must be testable? What must be inspectable? ``` ## 1. Body Contract A body is a registered origin of influence or field participation. A body must expose: ```txt id element or virtual owner geometry provider field target write-back target force tokens or behavior registration visibility state debug metadata lifecycle hooks ``` Required geometry: ```ts type BodyGeometry = { cx: number cy: number hw: number hh: number rect: DOMRect } ``` Default measurement: ```txt element.getBoundingClientRect() ``` Shadow DOM rule: ```txt Presentation may be private. Physical participation must be public. ``` The default registered body is the custom element host. ## 2. Field Contract A field is invisible structure. ```ts type FieldFn = (body: Body, x: number, y: number, env: Env) => Vec2 | ScalarField | CompoundField | null ``` A field function must: ```txt be side-effect free return stable values for a fixed state not mutate particles not mutate bodies be traceable for rendering when applicable declare whether it is vector, scalar, or compound ``` Field functions may be used by: ```txt field lines streamlines heatmaps fieldflow Lab probes debug overlays topology analysis ``` ### 2.1 External field channels (`addField`) A host may register its own scalar field as a named **channel** the engine samples on the same read path as its built-in field functions: ```ts addField(name: string, sampler: (x: number, y: number) => number): FieldChannelHandle sampleField(name: string, x: number, y: number): number ``` This is the open **input** analog of the render surfaces (`setRender`/`setOverlay` are bundled *output* layers; `addField` is an on-demand *input* channel) — the same shape as the `grid(name)` host-authorable buffer, but for a field the host already owns (terrain height, soil moisture, a temperature map). A channel sampler obeys the field-function contract above (side-effect free, stable for a fixed state); it is **pull-based** — called on demand, never cached — so it must stay cheap. The `FieldChannelHandle` swaps the sampler live or removes the channel. Reading a channel as a force *potential* is a separate, opt-in coupling — `addField` is the read substrate, not yet a cause. ## 3. Force Contract A force is cause. ```ts type ApplyFn = (body: Body, particle: Particle, env: Env, dt: number) => void ``` A force may mutate: ```txt particle velocity particle heat particle phase particle capture state particle identity particle life ``` A force must declare: ```txt whether it owns field() whether it uses env.fieldAt() whether it does work whether it requires charge whether it requires velocity whether it affects neutral matter whether it conserves speed whether it creates or destroys matter what conformance tests prove it ``` Every force needs a passport. ## 4. Transport Contract A transport primitive moves matter along field geometry or routes influence through a structure. `fieldflow` is the canonical transport primitive. Rules: ```txt Transport may do work. Transport may use env.fieldAt(). Transport must not replace the physical law of another force. Transport must declare whether it acts on neutral matter. Transport must define behavior for zero field. Transport must define range behavior. ``` Critical rule: ```txt magnetism.apply() must remain Lorentz curvature. fieldflow carries matter along magnetic geometry when needed. ``` ## 5. Agent Contract An agent is anything that can receive influence, hold state, change behavior, or affect another thing. ```ts type FieldAgent = | ParticleAgent | ElementAgent | RelationshipAgent | EventAgent | UserAgent | LayoutAgent | DataAgent; ``` Every agent type must define: ```txt identity state inputs outputs what influence it accepts what metrics it emits what visualizations apply what events it can dispatch what tests apply ``` ## 6. ElementAgent Contract An ElementAgent receives field metrics and writes DOM state. Inputs: ```txt density attention heat entropy coherence memory pressure pull-x pull-y relationship strength ``` Outputs: ```txt CSS variables data attributes thresholded events debug metadata ``` **The three metric-output lanes.** Not every `--field-*` variable flows automatically — the lane that produces a variable determines whether it arrives at all: - **Engine-computed** — written by core's feedback sink every frame, regardless of recipes or platform configuration: `--d` / `--field-density` (local particle density), `--load` / `--mass` (sink accretion fill), `--lit` (continuous engagement, paired with `field:lit` / `field:dim` hysteretic events), and the engine-measured thermodynamics `--entropy`, `--coherence`, `--temperature` (velocity alignment, agitation, heat — written to `data-feedback` bodies; these bare-named variables are distinct from the platform-inferred ones below). - **Platform-computed** — written by `applyRecipe` / `computeMetrics` when a recipe runs its metric pipeline: `--field-attention`, `--field-memory`, `--field-coherence`, `--field-entropy`, `--field-pressure`, `--field-recency`, `--field-priority`. These flow every frame that the recipe pipeline ticks. `--field-confidence` and `--field-risk` are supplied-only — the engine never invents them; they appear only when the host supplies `data-field-confidence` / `data-field-risk`. - **Data-supplied (designed)** — lanes a recipe declares but that neither the engine nor the platform metric pipeline computes. A recipe listing `signal`, `route-strength`, or any domain-specific metric must have the host supply `data-field-` (or a domain model) or the `--field-` lane stays **inert** — declared, bound, never written. The lint rule `lintInertFeedback` surfaces this gap: a binding to an inert designed lane is the same silent-contract class as a sink that captures but never reports. Recipe authors must not expect a designed lane to flow unless the host provides the data. The platform writes what it can compute; `classifyMetric(name)` returns `'computed'`, `'supplied-only'`, or `'designed'` for any metric name. Suggested CSS variables for the platform-computed lane (canonical `--field-*`; the `--forces-*` names are legacy/compat aliases the FeedbackRegistry auto-mirrors, and `--d` is the compact alias for density): ```css --field-density --field-attention --field-heat --field-entropy --field-coherence --field-memory --field-pressure --field-pull-x --field-pull-y ``` One shipped **page-global** variable lives on `:root`, not on bodies: `--field-scroll-v`, the engine's eased scroll velocity (px/frame), written by the platform write phase and deduped when unchanged. The engine-measured thermodynamics `--entropy`, `--coherence`, and `--temperature` are deliberately bare-named (distinct from the `--field-entropy` / `--field-coherence` platform-inferred interaction metrics — the two families must not be cross-written). (`--coherence` is additionally a palette *color* on `:root` via `cssTokens()` — the measured value is element-scoped and numeric.) Formulas: [`physics-workover.md`](../engine-reference/physics-workover.md) §"Metrics". **Engagement inputs** are part of this contract. The engine wires hover/focus engagement on `[data-hot]` elements at scan time (engaging one activates its body and gathers density — its `--d` rises). The platform metric pipeline reads `engaged` as `:hover | :focus | :focus-within | [data-active]` — setting `data-active` programmatically is the sanctioned way to mark an element "in hand" (a dragged card, a just-changed status). See [invisible-fields.md](invisible-fields.md) §3. ElementAgents should not directly mutate particle state unless they are also registered bodies. ## 7. RelationshipAgent Contract A RelationshipAgent represents an active connection. ```ts type RelationshipAgent = { id: string from: BodyId to: BodyId type: string strength: number tension: number memory: number active: boolean } ``` A relationship may: ```txt pull bodies transfer attention display tension carry memory strengthen or decay emit threshold events ``` A relationship is not merely a rendered line. ## 8. UserAgent Contract A UserAgent represents user input as field participation. Inputs: ```txt pointer position pointer velocity focus target selection scroll direction interaction intent memory trail ``` UserAgent behavior must respect: ```txt reduced motion keyboard accessibility privacy pointer absence touch input assistive technology ``` Focus must be a first-class field source. ## 9. Event Contract > **Implemented.** `FIELD_EVENTS` (`packages/core/src/agents/event-agent.ts`) names every event here > with its `field:*` canonical + `forces:*` alias and source metric; the `Thresholder` runtime makes > them hysteretic + debounced. `field:lit`/`dim` and the `*-body` lifecycle events dispatch today. Field events must be thresholded, debounced, and inspectable. Allowed event types (canonical `field:*`; each has a `forces:*` compat alias the FeedbackRegistry mirrors): ```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 ``` Rules: ```txt No noisy per-frame DOM events by default. Events must include useful detail payloads. Events must be traceable to field metrics. Events must respect accessibility. ``` ## 10. Feedback Contract Feedback writes field state back to DOM. Feedback may mutate: ```txt CSS variables data-state attributes ElementInternals state controlled events ``` Feedback must not: ```txt break readability require motion for meaning spam assistive tech depend on inaccessible pointer-only behavior ``` ## 11. Visualization Contract Visualization layers reveal state. They must not mutate physics unless explicitly declared as feedback. | Visualization | Reads from | Mutates physics? | |---|---|---:| | Field lines | `field()` | no | | Force vectors | `apply()` or probe | no | | Trails | particle history | no | | Heatmaps | scalar grids | optional | | Energy | particle + field state | no | | Topology | relationship agents | optional | | DOM state | feedback variables | visually yes | If a visualization mutates state, it must be reclassified as feedback or force behavior. ## 12. Source/Sink Contract Any source or sink must be budgeted. A source must define: ```txt spawn rate maximum particles particle life energy budget cooldown visibility behavior reduced-motion behavior ``` A sink must define: ```txt capacity release behavior destroy vs capture semantics saturation threshold events ``` No unbounded creation. ## 13. Scene Recipe Contract A recipe is a portable scene or behavior definition. Required fields: ```txt name intent bodies agents forces render layers metrics accessibility behavior performance budget expected conformance notes ``` Recipes must be serializable and inspectable. ## 14. Accessibility Contract > **Implemented.** Now a named entry in the `CONTRACTS` catalog (`contracts/index.ts`), enforced by > the reduced-motion guard, the UserAgent travel-gating, and the a11y lint rules, with a dedicated > test set (`contracts/a11y.test.ts`). ```txt Motion is optional. Meaning is never motion-only. Density feedback must not be required to read content. Reduced motion swaps travel for state. Field events should not spam assistive tech. Decorative fields may be hidden. Interactive fields need labels. ``` Reduced fallback examples: | Full mode | Reduced mode | |---|---| | particles travel | particles freeze or fade | | sparks | static highlight | | fieldflow ribbons | static field lines | | heat trails | soft wash | | body motion | CSS state only | | turbulence | contour snapshot | ## 15. Performance Contract Every field should have a budget. Suggested defaults: ```txt Particles: 600 max default Bodies: 80 max default Local cells: 3 active max Field-line traces: capped by viewport Heatmap resolution: 4-8 px/cell Debug overlays: disabled in production DPR: capped at 2 ``` Suggested type: ```ts type FieldBudget = { particles: number bodies: number localCells: number fieldLines: number heatmapResolution: number dprCap: number } ``` ## 16. Conformance Contract Every new force, render mode, agent type, source/sink, and recipe must define proof. Proof may include: ```txt golden math test behavioral scenario snapshot regression accessibility test performance budget test side-effect test event threshold test reduced-motion test ``` Core rule: ```txt If it affects behavior, it needs conformance. If it explains behavior, it needs truth-table classification. ``` ## 17. Error Taxonomy Named errors: | Error | Meaning | |---|---| | `NO_FIELD_SOURCE` | `fieldflow` has nothing to follow | | `UNBUDGETED_SOURCE` | source lacks cap or life | | `UNSTABLE_ENERGY` | energy grows beyond threshold | | `NAN_PARTICLE` | invalid particle state | | `SHADOW_BODY_UNMEASURABLE` | body has no valid rect | | `MISSING_REDUCED_MOTION` | no accessible fallback | | `VISUALIZATION_MUTATES_PHYSICS` | debug/render layer has side effects | ## 18. Agent Non-Negotiables ```txt Never change magnetism.apply() to follow field lines. Use fieldflow for field-aligned transport. Visualization layers must not mutate physics unless declared. Sources require budgets. Every new force requires conformance. Every field-like force should define field() if it can be visualized. Every force doc needs a passport. Every render mode needs a truth table entry. Every source/sink must be budgeted. Every Shadow DOM body must be registered, measurable, and testable. Every visible behavior should be traceable to a field cause. ``` ## 19. Visual Language Contract The visual language system is defined in [`visual-language-and-geometry.md`](visual-language-and-geometry.md). Rules: ```txt Visual form can become geometry. Semantic meaning must remain accessible. Field state can shape appearance. Appearance must not corrupt the field. Core implementation should use fundamental platform APIs without dependencies. ``` Every visual layer must declare: ```txt source metrics target properties whether it mutates physics whether it writes DOM state reduced-motion behavior accessibility fallback performance cost debug visibility ``` Typography rule: ```txt The visual layer may be vectorized, distorted, animated, or custom-rendered. The semantic layer should remain real HTML text. ``` ## 20. Platform Contract > **Implemented.** `@fundamental-engine/platform` ships `createFieldPlatform(root)` plus the six registries, the > `FrameScheduler`, and `lintPlatform()`. The platform runtime is the default for ``. `@fundamental-engine/platform` binds the renderer-agnostic field computed by `Fundamental` to the DOM. It owns DOM participation; core stays free of DOM side effects. The platform must: ```txt own measurement, state, feedback, relationships, visual bindings, and overlays schedule all DOM reads and writes through explicit phases register Shadow DOM bodies for physical participation keep Fundamental renderer-agnostic (imports no DOM globals) expose createFieldPlatform(root) to construct a runtime over a root expose lintPlatform() to validate registry usage ``` Construction: ```txt createFieldPlatform(root) -> a platform runtime bound to root ``` The platform must not move force-engine math into the DOM layer. Core computes field behavior; the platform observes and writes the DOM. ## 21. Registry Contract > **Implemented.** Six registries ship in `@fundamental-engine/platform`: `MeasurementRegistry`, > `StateRegistry`, `FeedbackRegistry`, `RelationshipRegistry`, `VisualBindingRegistry`, > `OverlayRegistry`. Each registry owns one concern and participates in the scheduler in its declared phase. | Registry | Concern | Phase ownership | |---|---|---| | `MeasurementRegistry` | geometry/rects for bodies | read | | `StateRegistry` | registered field/agent state | compute / state | | `FeedbackRegistry` | CSS-variable and event write-back | write | | `RelationshipRegistry` | active connections between bodies | compute | | `VisualBindingRegistry` | binding field metrics to visual properties | write | | `OverlayRegistry` | overlay/render-surface participation | render | Registry rules: ```txt A registry must declare which scheduler phase it runs in. Measurement must read geometry only in the read phase. Feedback must write only in the write phase. The FeedbackRegistry auto-mirrors --field-* -> --forces-* and field:* -> forces:*. Relationship targets must resolve to registered bodies. Visual bindings must target hidden, non-orphan elements. Overlays must reference real links. ``` ## 22. Scheduler Contract > **Implemented.** `FrameScheduler` in `@fundamental-engine/platform` runs the explicit phase pipeline below. The scheduler runs registries in a fixed phase order each frame. Reads never interleave with writes. The six phases, in order: ```txt discover -> find participants (bodies, agents, relationships) read -> measure geometry; no writes allowed compute -> evaluate field/relationship state; side-effect free state -> reconcile registered state write -> emit CSS variables, data attributes, feedback, events render -> draw render surfaces and overlays [caller-open; not wired by the platform] ``` The platform owns and wires discover through write. The render phase is caller-open — the platform defines the slot and its read-only contract, but does not install a handler; the legacy engine fills it by running the canvas simulate-and-render loop. The platform observes and feeds back DOM state; it does not draw. Scheduler rules: ```txt No DOM writes during read or compute. No geometry reads during write. Every registry declares its phase and runs only in that phase. The phase order is fixed; registries do not reorder it. Render-phase handlers are caller-supplied; the platform wires none by default. ``` ## 23. Platform-Lint Contract > **Implemented.** `lintPlatform()` in `@fundamental-engine/platform` enforces the rules below. Platform lint validates that registries are used correctly before behavior depends on them. | Rule | Catches | |---|---| | `relation-target-missing` | a relationship points at an unregistered body | | `state-unregistered` | state read or written without registration | | `overlay-without-links` | an overlay with no real links to reference | | `feedback-non-css-var` | feedback writing something other than a CSS variable | | `measurement-off-phase` | geometry read outside the read phase | | `visual-orphan` | a visual binding with no target | | `visual-not-hidden` | a visual binding whose target is not hidden | Lint must run against a constructed platform and report violations by rule name. ## 24. Phase D Runtime-Unification Note > **Implemented (Phase D).** The platform runtime is the default for ``. In the platform-runtime phase the layers are unified as follows: ```txt The platform runtime is the DEFAULT for . Fundamental is renderer-agnostic and imports no DOM globals (a legacy element write-back path still lives in core/field.ts, pending migration). The platform owns DOM participation: measurement, feedback writes, shadow registration, relationships. The legacy core path still simulates and renders the canvas surface. The DOM boundary is guarded by a test allowlist; core must not reach into the DOM outside it. ``` Opting back to the pure-legacy path: ```txt experimental-platform="off" on usePlatformRuntime(false) ``` The legacy path is quarantined, not removed: it remains the canvas simulate-and-render surface while the platform owns DOM participation. ## Migration and Alias Contract During the `force/` to `Fundamental/` migration, old and new public names must both resolve to the same behavior. CSS write-back should emit both: ```txt --field-density --forces-density --field-heat --forces-heat --field-entropy --forces-entropy --field-coherence --forces-coherence --field-attention --forces-attention ``` Events should support both: ```txt field:register-body forces:register-body field:unregister-body forces:unregister-body field:lit forces:lit ``` Component aliases should register the same body contract. Aliases may be deprecated only after: ```txt docs are updated tests pass examples use new names migration notes identify the removal version ``` Do not remove old names in the same pass that introduces new names. ======================================================================== FILE: testing-and-conformance.md ======================================================================== > **Status: canonical.** > The test matrix, conformance gates, force passports, and platform/scheduler/lint coverage. Current as of the platform-runtime phase (Phase D). See [platform-architecture.md](platform-architecture.md) and [system-contracts.md](system-contracts.md). # Fundamental Testing and Conformance ## Related Documents | Document | Role | |---|---| | [`README.md`](./README.md) | Documentation map | | [`system-contracts.md`](system-contracts.md) | Contract requirements | | [`fundamental-field-behavior-table.md`](fundamental-field-behavior-table.md) | Force law requirements | | [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Visualization tests | | [`authoring-and-recipes.md`](authoring-and-recipes.md) | Recipe tests | ## Purpose Conformance makes the system credible. Every force, field, visualization, source, sink, event, recipe, and agent behavior should declare what proves it works. Core principle: ```txt If it affects behavior, it needs conformance. If it explains behavior, it needs truth-table classification. ``` ## 1. Test Categories ```txt force math tests field geometry tests field/apply separation tests visualization side-effect tests agent response tests event threshold tests accessibility tests performance budget tests snapshot regression tests recipe conformance tests Shadow DOM registration tests reduced-motion tests platform registry tests scheduler phase-ordering tests platform lint tests diagnostic render-mode tests DOM-boundary (renderer-agnostic core) tests ``` ## 2. Force Passport Requirement > **Implemented.** `ForcePassport` (`packages/core/src/contracts/passport.ts`) carries all of these > fields — including `bestRenderModes` and `commonComposites` — and `conformanceTests(token)` derives > the proof list from the live conformance catalog so it never drifts. `validatePassports()` > cross-checks `family` / `klass` / `ownsField` against the registry + conformance. Every force needs: ```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: ``` ## 3. Required Magnetism Tests ```txt neutral particle ignored still charged particle unchanged moving charged particle curves force perpendicular to velocity speed preserved before damping charge reversal flips curvature spin reversal flips curvature no effect beyond range magnetism does no work in ideal mode ``` Rule: ```txt magnetism.apply() must remain Lorentz behavior. ``` ## 4. Required Fieldflow Tests > **Implemented.** `packages/core/src/forces/fieldflow.test.ts` covers does-work, moves-neutral- > matter, zero-field→no-motion, range-0-global, beyond-range-inert, and the speed-of-light cap; the > scenario catalog adds "neutral matter follows a charge field line". ```txt neutral matter moves fieldflow does work zero field produces no motion charge field routes matter radially magnetic field routes matter along loops beyond range produces no effect range 0 uses global field net field superposition routes between bodies ``` Rule: ```txt fieldflow carries matter along field geometry. ``` ## 5. Field vs Apply Separation Tests ```txt field lines trace field(), not apply() force vectors reflect apply(), not field() magnetism field lines differ from particle paths fieldflow particle paths align with field lines visualization does not alter physics ``` ## 6. Visualization Tests ```txt field line trace terminates correctly streamlines respect vector field force vectors use probes for velocity-dependent forces heatmaps decay correctly contours match scalar field levels energy view does not mutate physics debug overlays do not affect integration prediction mode does not mutate live state causality overlay matches force contribution ``` ### Diagnostic render-mode coverage All render modes ship and are exercised at `/docs/diagnostics`: dots, trails, links, streamlines, metaballs, voronoi, field-lines, heatmap, force-vectors, contours, potential, energy, topology, inspector, causality, and prediction. Canvas is one render surface among these; the field runtime can drive any of them from the same shared field context. Each mode needs: ```txt mode renders without throwing across the diagnostics gallery mode reads field state but does not mutate physics prediction / causality / inspector remain read-only over live state mode degrades to a static or meaning-preserving form under reduced motion mode respects its resolution / capping budget ``` ## 7. Agent Tests ### ElementAgent ```txt receives density receives attention writes CSS variables dispatches thresholded events does not directly mutate particles unless also body respects reduced motion ``` ### RelationshipAgent ```txt stores from/to bodies renders relationship transfers attention if configured strengthens with use decays over time emits thresholded events ``` ### UserAgent ```txt pointer creates wake focus creates accessible attention source selection creates capture state scroll creates current reduced motion disables travel-heavy response ``` ## 8. Event Tests ```txt events are thresholded events are debounced events include useful detail payload events do not fire every frame by default events respect accessibility constraints ``` ## 9. Source/Sink Tests ```txt source has budget source has max particles source has particle life source cannot create unbounded particles sink has capacity sink defines release behavior sink emits saturation event ``` ## 10. Accessibility Tests > **Implemented.** A dedicated set in `packages/core/src/contracts/a11y.test.ts` covers the > reduced-motion fallback (guard), meaning-without-motion (UserAgent keeps focus, drops travel; > emission flattens), thresholded events (no per-frame spam), and color/glyph-not-sole-carrier (lint). ```txt reduced motion fallback exists meaning survives without motion decorative fields can be hidden interactive fields have labels focus-visible works without pointer field events do not spam assistive tech ``` ## 11. Performance Tests ```txt particle count stays within budget body count stays within budget field-line tracing is capped heatmap resolution respects budget debug overlays disabled in production preset DPR is capped local cells clean up observers and loops ``` ## 12. Snapshot Regression A snapshot should include: ```json { "seed": 1234, "time": 4.2, "bodies": [], "agents": [], "particles": [], "metrics": {}, "expected": { "particleCount": 600, "entropyRange": [0.1, 0.3], "energyDriftMax": 0.02 } } ``` Desired command: ```txt forces test snapshot solar-prominence.json ``` ## 13. Recipe Conformance Every recipe should declare: ```txt expected metrics required forces required render modes accessibility behavior performance budget conformance scenario ``` Example: ```txt Solar prominence: - magnetism field lines visible - fieldflow moves neutral matter along field - magnetism alone does not move neutral matter - heat remains bounded - reduced mode shows static field lines ``` ## 14. Lint Rules > **Implemented.** All of these (including the `data-body="gravity attract"` duplicate-pull rule) > ship in `packages/core/src/visual/lint.ts` (`runVisualLint`), with `info`/`warning`/`error`/`fatal` > severities. ```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 field() hooks exist. Warning: data-body="gravity attract" may duplicate pull behavior. Warning: reduced motion fallback missing. ``` Severity levels: ```txt info warning error fatal ``` ## 15. Platform Tests `@fundamental-engine/platform` binds the renderer-agnostic core to the DOM. As of the platform-runtime phase (Phase D) it is the default runtime for ``: the platform owns DOM participation (measurement, feedback writes, shadow registration, relationships) while the legacy `core/field.ts` still simulates and renders the canvas. `createFieldPlatform(root)` wires the six registries onto the scheduler. Each registry needs coverage: ```txt MeasurementRegistry reads element geometry only in the read phase StateRegistry tracks registered state and flags unregistered access FeedbackRegistry writes CSS variables (--field-density primary) only in the write phase FeedbackRegistry mirrors --field-* to --forces-* and field:* to forces:* RelationshipRegistry resolves from/to targets and reports missing targets VisualBindingRegistry keeps decorative bindings hidden / non-orphaned OverlayRegistry attaches overlays only where links exist opting out (experimental-platform="off" / usePlatformRuntime(false)) restores pure-legacy behavior ``` ### DOM-boundary (renderer-agnostic core) `core/dom-boundary.test.ts` guards the boundary: core stays renderer-agnostic and only the allowlist (`core/field.ts`, `export.ts`) may touch DOM APIs. ```txt core modules outside the allowlist reference no DOM globals field behavior computes without a document present canvas is treated as one render surface, not a core dependency ``` ## 16. Scheduler Tests The `FrameScheduler` runs explicit phases in a fixed order: discover -> read -> compute -> state -> write -> render. Tests prove the ordering and the off-phase guard: ```txt phases run in order: discover, read, compute, state, write, render reads happen before writes within a frame (no read-after-write tearing) work registered to a phase only runs in that phase off-phase access is rejected (measurement-off-phase guard) a missing or empty phase does not stall the frame loop ``` ## 17. Platform Lint Tests `lintPlatform()` reports platform-level violations with the same info/warning/error/fatal severities. Each rule needs a positive and negative case: ```txt relation-target-missing fires when a relationship references an unknown target state-unregistered fires when state is read without registration overlay-without-links fires for an overlay with no links feedback-non-css-var fires when feedback writes something other than a CSS variable measurement-off-phase fires when measurement runs outside the read phase visual-orphan fires for a visual binding with no owner visual-not-hidden fires when a decorative visual binding is not hidden ``` ## 18. Reading Field Browser Verification `/docs/reading-field` is a normal content page that exercises all six scheduler phases across four registries (measurement, state, feedback, relationships) in the browser. It is the end-to-end check that the shared field context behaves on real content: ```txt sections register as bodies viewport proximity drives attention attention accumulates as memory over dwell the table of contents reflects current field state citations register as relationships reduced motion preserves meaning (state and structure survive without travel-heavy motion) ``` The authoring surfaces at `/docs/authoring` (native HTML, ``, ``) are verified to compile to the same `[data-body]` contract. ## 19. Acceptance Criteria A feature is acceptable when: ```txt it has a contract it has a passport if force-like it declares truth mode it has tests it has reduced-motion behavior if visual it has performance budget impact it has Inspector visibility it has docs it does not violate non-negotiables ``` ## Migration Validation The `force/` to `Fundamental/` migration is complete when: ```txt project runs from Fundamental/ typecheck passes test suite passes Lab still runs docs links resolve examples use new naming old public names still work as aliases CSS variables write both old and new names events support old and new names package metadata uses Fundamental no hardcoded force/ path remains except migration notes no accidental behavior changes occurred magnetism tests still prove Lorentz behavior fieldflow tests still prove field-aligned transport ``` Migration-specific test categories: ```txt directory/path tests package metadata tests component alias tests event alias tests CSS variable alias tests docs link tests example compatibility tests no behavior regression tests ``` Migration acceptance rule: ```txt A rename is not complete until the old and new names both work. ``` ======================================================================== FILE: time.md ======================================================================== > **Status: canonical.** > How Fundamental handles time: the three clocks (simulation, experiential, world), the temporal > kernels, and the declared-timestamp contract (`data-field-at`). Everything here is shipped > and verified against code except where marked; the kernels live in > `packages/core/src/core/temporal.ts`, the derivation in the platform metric pipeline, and > the reference consumers are the Calendar, Memory, Backlog, and Inbox examples. # Time in the Field ## Related Documents | Document | Role | |---|---| | [`system-contracts.md`](system-contracts.md) | The metric lanes (`recency`, `memory`) and feedback variables | | [`invisible-fields.md`](invisible-fields.md) | The live channels the clocks feed | | [`natural-fields.md`](natural-fields.md) | Weak → transformation: the conceptual home of decay | | [`fundamental-field-behavior-table.md`](fundamental-field-behavior-table.md) | Truth modes (the kernels are *designed*, not physical) | | [`../engine-reference/physics-workover.md`](../engine-reference/physics-workover.md) | v0.4: real `dt` seconds + the fixed-step accumulator (simulation time's future) | ## 1. The three clocks A field page experiences three kinds of time, and they must not be conflated: | Clock | What it measures | Where it lives | Status | |---|---|---|---| | **Simulation time** | the field's own evolution — frames, particle ages, wave phase | `env.t` (seconds since boot), `env.dt` (1/frame; 0 under reduced motion), `Particle.age` (frames-to-live for mortal matter) | shipped; v0.4 upgrades `dt` to real seconds with a fixed-step accumulator | | **Experiential time** | the *reader's* time — what has been attended, for how long, how recently | the platform metric lanes: `attention` (eased now), `memory` (slow integral of attention), `recency` (decays from the last engagement) | shipped (the metric pipeline) | | **World time** | the *data's* time — when things happened or will happen | `data-field-at` timestamps + the temporal kernels | shipped (this document) | The lanes stay separate the way all Fundamental lanes do: simulation time is physics, experiential time is *inferred* from interaction, world time is *declared* by the data. When both could apply, **declaration wins over inference** (§3). ## 2. The temporal kernels Temporal distance is a distance. The engine derives force from spatial distance; the kernels derive weight from temporal distance — pure, deterministic functions in `@fundamental-engine/core` (`core/temporal.ts`), all `(…, nowMs) → 0..1`, no `Date.now()` inside (callers supply `now`, which keeps them testable and frame-coherent): | Kernel | Shape | The question it answers | |---|---|---| | `imminence(atMs, nowMs, horizonMs)` | `1 − ln(until/h₀ + 1) / ln(horizon/h₀ + 1)`, clamped; 1 at/past the moment | *how soon?* — approach ramps weight (the Calendar's gravity) | | `freshness(atMs, nowMs, halfLifeMs)` | `2^(−since/halfLife)`; exactly ½ at one half-life | *how recent?* — newness decays (Backlog, Inbox). `staleness = 1 − freshness` | | `retention(anchor, sinceMs, opts?)` | `a · e^(−since/τ(a))`, τ growing with anchor strength | *how well held?* — the Ebbinghaus forgetting curve (Memory); deep anchors decay slower | | `phase(nowMs, periodMs, offsetMs?)` | cyclical position `[0, 1)` | *where in the rhythm?* — daily/weekly cycles. Shipped; consumer-less today (stated honestly in its JSDoc) | These are **designed** truth-mode functions (legible, monotone, parameterized), not physical claims. They were extracted, not invented: four example pages had hand-rolled four variants of "temporal distance → weight," and the kernels reproduce the originals bit-identically (the e2e suite pins the conversions). ## 3. The declared timestamp: `data-field-at` An element may declare *when it is*: ```html

  • data-field-halflife="86400000"> ``` When `data-field-at` is present (and `data-field-recency` is not explicitly supplied), the platform metric pipeline **grounds the `recency` lane in world time**: `recency = freshness(at, now, halfLife)`, with `now` sampled once per frame. Without a declared timestamp, the pipeline keeps its existing behavior — recency *inferred* from interaction (1 while engaged, easing down after). One lane, two sources, a strict precedence: ```txt explicit data-field-recency > declared data-field-at > inferred from interaction ``` Invalid timestamps parse as absent (no error — but note the silent-gap doctrine in [`../engineering-practices.md`](../engineering-practices.md): if this pair ever bites, it gets a lint rule). ## 4. What this is for The reference consumers show the intended division of labor — *the kernel shapes the weight, the page owns the semantics*: - **Calendar** — `imminence` drives `--w` on a 1 Hz tick: the next launch literally pulls hardest, and the ramp is now the same function any consumer can import. - **Memory** — `retention` is the forgetting curve; reviewing re-anchors (`retention(a, 0) = a`). - **Backlog / Inbox** — `freshness` grounds activity weights; both pages also declare `data-field-at` in markup, so their `--field-recency` lane is world-grounded for real (the Inbox's conserved budget is unaffected — allocation happens after weighting). ## 5. What time is NOT here - The kernels do not schedule anything — they map time to weight. Scheduling (polling cadence, reveal pacing) is the live-data plumbing (`apps/site/src/lib/live-data.ts`) and the reading-pace gate, documented in [`invisible-fields.md`](invisible-fields.md) §5–6. - Simulation `dt` is not wall time (until v0.4's fixed-step work); nothing in the engine consumes the kernels per-frame — pages and the platform pipeline do, at their own cadence. - Experiential `memory`/`recency` (inferred) and world-grounded `recency` (declared) are the same *lane* with different *sources*; the engine-measured thermodynamics (`--temperature` etc.) are a different thing entirely (workover v0.3) and share no naming. ======================================================================== FILE: visual-language-and-geometry.md ======================================================================== > **Status: canonical.** > Typography, color, shape, distance, pattern, emission, containers, surfaces, and visual semantics. Current as of the platform-runtime phase (Phase D). See [platform-architecture.md](platform-architecture.md) and [system-contracts.md](system-contracts.md). # Fundamental Visual Language and Geometry System ## Related Documents | Document | Role | |---|---| | [`README.md`](./README.md) | Documentation map | | [`definition-document.md`](definition-document.md) | Core concept | | [`system-contracts.md`](system-contracts.md) | Contracts | | [`visualization-methods-taxonomy.md`](visualization-methods-taxonomy.md) | Render and diagnostic layers | | [`interaction-and-relationship-model.md`](interaction-and-relationship-model.md) | User, relationship, and DOM agents | | [`authoring-and-recipes.md`](authoring-and-recipes.md) | Authoring model | ## Purpose This document defines how `Fundamental` should treat visual form as part of the field system. The field should not only move particles. It should be able to influence typography, color, shape, distance, pattern, emission, containers, surfaces, hierarchy, and semantic visual state. The visual system is native-platform-first, dependency-light, and framework-agnostic. The `Fundamental` package specifically carries zero runtime dependencies; visual layers prefer native web APIs and treat any external adapter as opt-in and outside core. These visual layers are render surfaces bound to the field runtime by `@fundamental-engine/platform`: canvas render modes, SVG overlays, and diagnostic overlays. `Fundamental` computes renderer-agnostic field behavior; the platform binds that behavior to the DOM through measurement, state, feedback, relationships, visual bindings, overlays, scheduling, and linting. Canvas is one render surface, not the whole system. Every visual layer here is a semantic-safe, accessibility-aware render surface over a shared field context. Implementation should use fundamental web APIs wherever possible: ```txt HTML CSS SVG Canvas 2D Web Animations API Custom Elements Shadow DOM ResizeObserver IntersectionObserver Pointer Events Keyboard / Focus Events CSS Custom Properties CSS Typed OM where available WebGL / WebGPU only when explicitly needed ``` Do not depend on external libraries for core behavior unless there is no practical alternative. ## 1. Core Visual Principle Visual behavior should be caused by field state. ```txt field metrics -> visual variables -> rendered form ``` Examples: ```txt density -> font weight attention -> color intensity heat -> emission/glow entropy -> irregularity coherence -> alignment memory -> trail/patina pressure -> compression distance -> spacing/falloff relationship -> tension/line weight ``` The core sentence: ```txt The field does not decorate the interface. It parameterizes the interface. ``` ## 2. Visual Parameters Every visual system can be expressed as a set of field-responsive parameters. | Parameter | Meaning | Field mapping | |---|---|---| | Font weight | typographic mass | density, attention | | Font width | compression / expansion | pressure, available space | | Font slant | directional force | velocity, pull vector | | Optical size | perceived scale/detail | distance, attention | | Tracking | breathing room | pressure, entropy | | Stroke width | visual force | strength, density | | Fill opacity | presence | attention, visibility | | Hue | categorical state | type, role, charge | | Saturation | intensity | heat, urgency | | Tone / lightness | hierarchy | depth, attention | | Alpha | certainty / presence | confidence, distance | | Blur | uncertainty / depth | entropy, distance | | Glow | emission / activation | heat, energy | | Radius | softness / phase | cohesion, pressure | | Scale | importance / proximity | attention, strength | | Rotation | torque / spin | vortex, magnetism | | Translation | field pull | force vector, attention | | Pattern density | information load | memory, relationship count | | Line spacing | reading calm | pressure, density | | Shadow | depth / lift | attention, z-field | | Mask | visibility window | spotlight, screen, gate | ## 3. Typography and Webfonts Webfonts are vector systems with semantic text constraints. A font contains glyph outlines, spacing, kerning, hinting, OpenType features, Unicode mappings, ligatures, variable axes, and rendering metadata. Glyphs can be treated as vector geometry, but live text should remain semantic whenever possible. `Fundamental` should support three typography layers. ## 3.1 Live Text Layer Live text remains selectable, accessible, searchable, translatable, and responsive. Use CSS custom properties and variable font axes where available. Example: ```css .field-text { /* --field-density is the primary feedback variable; --d is a compact legacy alias. */ --d: var(--field-density, 0); --a: var(--field-attention, 0); --h: var(--field-heat, 0); font-variation-settings: "wght" calc(300 + var(--field-density, 0) * 500), "wdth" calc(90 + var(--a) * 20), "slnt" calc(var(--field-pull-x, 0) * -8); letter-spacing: calc((1 - var(--a)) * 0.04em); text-shadow: 0 0 calc(var(--h) * 18px) currentColor; } ``` Use this path by default. ## 3.2 Vectorized Glyph Layer For highly expressive typography, text may be converted into SVG paths or Canvas path geometry. This enables: ```txt glyph deformation per-point distortion path animation field-driven outlines particle emission from glyph edges collision from glyph shape masking and clipping liquid or plasma typography ``` Accessibility rule: ```txt The visual layer can be vectorized, distorted, animated, shader-rendered, or fully custom. The semantic layer should remain real HTML text. ``` Pattern: ```html

    Liquid Typography System

    ``` For short labels: ```html

    ``` For longer text, hidden real text is preferred over large `aria-label` content. ## 3.3 Font Source Layer Editing a font file itself is a type-design workflow, not ordinary field rendering. `Fundamental` should not require font-file modification for runtime effects. Runtime behavior should prefer: ```txt CSS variable axes SVG paths generated from known glyph outlines Canvas text metrics and masks semantic HTML fallback ``` Font licensing rule: ```txt Do not convert, modify, redistribute, or embed altered commercial font glyph data unless the license explicitly permits it. ``` ## 4. Text as Geometry Text can participate as geometry in several ways. | Mode | Semantic text preserved? | Use | |---|---:|---| | CSS live text | yes | default typography | | SVG visual duplicate + hidden text | yes | expressive headings | | Canvas visual duplicate + hidden text | yes | particle/field effects | | Outlined glyph paths only | no unless fallback supplied | logos, non-semantic art | | Font-file modification | depends | custom typeface production | Recommended rule: ```txt Keep the semantic layer live. Let the visual layer become geometry. ``` ## 5. Color System Color should be field-driven but controlled. Separate color into independent channels. ```txt hue = categorical meaning saturation = intensity tone/lightness = hierarchy and depth alpha = presence/confidence temperature = heat/cool state contrast = accessibility requirement ``` Suggested variables: ```css :root { --field-hue: 210; --field-saturation: 80%; --field-tone: 55%; --field-alpha: 1; --field-heat: 0; --field-attention: 0; --field-entropy: 0; } ``` Example: ```css .field-color { color: hsl( calc(var(--field-hue) + var(--field-heat) * 24) calc(var(--field-saturation) + var(--field-attention) * 12%) calc(var(--field-tone) + var(--field-density) * 10%) / var(--field-alpha) ); } ``` ## 5.1 Color Channel Mapping | Field metric | Color response | |---|---| | density | deeper tone / stronger presence | | heat | warmer hue / higher glow | | entropy | hue instability / desaturation | | coherence | cleaner tone / stable hue | | attention | increased saturation / contrast | | memory | patina / persistent tint | | confidence | opacity and clarity | | uncertainty | lower saturation, higher blur | | danger | heat shift plus contrast | | disabled | low saturation and low alpha | ## 5.2 Accessibility Rules for Color ```txt Color must not be the only carrier of meaning. Contrast must remain readable. Motion and glow must not be required to understand state. Reduced mode should preserve state through static tone, outline, icon, text, or layout. ``` A field-driven color layer must be bounded. ```txt min contrast threshold max saturation threshold max glow threshold reduced-motion fallback prefers-contrast support ``` ## 6. Shape System Shape is the visible boundary of field response. Shape can respond through: ```txt scale aspect ratio corner radius stroke width outline offset mask shape clip path path deformation surface tension morph target container curvature ``` Suggested mappings: | Field metric | Shape response | |---|---| | pressure | compression | | density | mass/scale | | heat | expansion / bloom | | cohesion | rounding / liquid behavior | | entropy | irregular edges | | coherence | geometric regularity | | attention | lift / scale / sharper outline | | memory | worn edge / trail imprint | | collision | dent / rebound | | fieldflow | elongated along field direction | ## 6.1 Shape Modes | Mode | Description | Best for | |---|---|---| | Box geometry | rect-based body | cards, buttons | | Rounded surface | radius field | soft UI | | Path geometry | SVG path body | icons, glyphs | | Mask geometry | alpha mask | images, typography | | Particle boundary | sampled shape | complex silhouettes | | Container field | region behavior | sections/panels | ## 6.2 Shape Deformation Dependency-free deformation options: ```txt CSS transform CSS border-radius SVG path attributes SVG filters Canvas masks clip-path mask-image Canvas pixel sampling manual point interpolation ``` Rules: ```txt Use CSS for simple transforms. Use SVG for path-accurate shape. Use Canvas for dense particles, masks, and raster effects. Keep semantic DOM separate from expressive geometry. ``` ## 7. Distance and Spatial Hierarchy Distance is one of the most important visual variables. Distance can mean: ```txt physical distance between bodies semantic distance between concepts attention distance from user focus relationship distance in graph depth distance in interface hierarchy time distance from last interaction confidence distance from expected state ``` ## 7.1 Distance Mappings | Distance type | Visual expression | |---|---| | near | higher attention, stronger feedback | | far | lower alpha, lower force | | semantically close | thread, cohesion, reduced spacing | | semantically far | lower coupling, more spacing | | recently used | memory glow | | stale | cooling/fading | | high priority | lower potential well | | low confidence | blur/desaturation | ## 7.2 Falloff Use bounded falloffs for UI legibility. Linear: ```txt u = max(0, 1 - d / range) ``` Smooth: ```txt u = max(0, 1 - d² / range²)² ``` Gaussian-like: ```txt u = exp(-d² / (2σ²)) ``` Recommended default: ```txt u = max(0, 1 - d² / range²)² ``` Use inverse-square behavior for physical modes only, with softening. ## 8. Pattern System Patterns make accumulated field state visible. Pattern variables: ```txt frequency scale orientation phase density contrast grain spacing repetition interference ``` Field mappings: | Field metric | Pattern response | |---|---| | memory | persistent texture | | entropy | irregular pattern | | coherence | aligned pattern | | field direction | oriented stripes / flow lines | | relationship | linked pattern rhythm | | heat | higher frequency / glow | | pressure | tighter spacing | | distance | larger or softer pattern | Pattern sources: ```txt CSS repeating gradients SVG patterns Canvas procedural drawing CSS masks background layers border images inline SVG ``` No dependency is required. ## 8.1 Pattern Examples Memory grain: ```css .memory-surface { background-image: radial-gradient(circle at center, hsl(var(--field-hue) 40% 60% / calc(var(--field-memory) * 0.18)) 1px, transparent 1px); background-size: calc(18px - var(--field-memory) * 8px); } ``` Fieldflow stripes: ```css .flow-surface { background-image: repeating-linear-gradient( calc(var(--field-angle, 0deg)), currentColor 0, currentColor 1px, transparent 1px, transparent calc(12px - var(--field-density) * 6px) ); } ``` ## 9. Emission System Emission is visual energy leaving a body or surface. Emission can appear as: ```txt particles light/glow waves rings rays sparks heat blooms field lines sound-like pulses event pulses relationship pulses ``` ## 9.1 Emission Types | Type | Meaning | |---|---| | Matter emission | actual particles | | Light emission | glow only | | Event emission | pulse indicating threshold | | Relationship emission | signal along link | | Heat emission | thermal bloom | | Memory emission | persistent trail | | Semantic emission | state announcement | | Debug emission | visualized cause | ## 9.2 Emission Contract Any emission that creates particles or state must be budgeted. ```txt rate capacity lifetime energy cost cooldown reduced-motion behavior accessibility fallback ``` Emission that is purely visual should be classified as render/feedback, not source physics. ## 10. Containers and Surfaces A container is not only a layout wrapper. It can be a field region. Container roles: ```txt field scope boundary sensor emitter sink screen lens memory region pressure region weather region local cell ``` ## 10.1 Container Behaviors | Container behavior | Description | |---|---| | Scope | limits field participation | | Boundary | contains, reflects, gates | | Sensor | samples metrics | | Screen | attenuates forces | | Lens | bends field rendering | | Sink | absorbs/captures | | Emitter | produces matter/influence | | Reservoir | stores particles/attention | | Weather region | tracks aggregate field state | | Local cell | isolated simulation island | ## 10.2 Container Attributes ```html
    ...
    ``` Potential CSS outputs: ```css --field-density --field-pressure --field-weather --field-entropy --field-attention --field-memory ``` ## 11. Surface 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 | | gel | cohesion + stretch + damping | | mirror | reflect + inversion | | membrane | gate + pressure | | sponge | absorb + delayed release | ## 12. Icon and Glyph System Icons are compact field diagrams. A force icon should express: ```txt source direction field shape particle response boundary condition state change ``` Icon variables: ```txt stroke width = strength glow = heat dash pattern = instability arrow direction = flow curve = vortex/magnetism density = accumulation gap = gate/screen ``` Icons can be: ```txt inline SVG CSS masked SVG Canvas-rendered symbols live text glyphs custom vector marks ``` Avoid icon ambiguity. For magnetism, avoid implying “cartoon magnet pulls metal” unless the mode is explicitly ordinary magnet attraction. Prefer field loops and curved motion. ## 13. Image and Media Surfaces Images, videos, and canvases can act as field surfaces. Potential mappings: | Media property | Field behavior | |---|---| | brightness | mass / density | | contrast | field strength | | edges | collision / emission source | | dominant hue | category field | | motion | velocity field | | subject mask | body geometry | | depth map | potential surface | Dependency-free options: ```txt Canvas drawImage Canvas getImageData manual pixel sampling CSS masks SVG clip paths IntersectionObserver ``` Accessibility rule: ```txt Media-derived visual behavior must not replace alt text, captions, or semantic description. ``` ## 14. Layering and Compositing The render stack should be explicit. Suggested order: ```txt 1. background field wash 2. heatmaps / scalar fields 3. field lines / contours 4. particles / trails 5. relationship topology 6. DOM content 7. DOM feedback effects 8. inspector/debug overlays ``` Some experiences may place particles above DOM, but the default should protect readability. These layers are not a single canvas. The canvas render surface owns the field washes, scalar fields, field lines, particles, and topology; SVG overlays own path-accurate relationship lines and crisp diagnostic marks; and diagnostic overlays own the inspector and debug views. The `@fundamental-engine/platform` `OverlayRegistry` registers and orders the SVG and diagnostic overlays, while the `FrameScheduler` keeps each layer on its phase (`discover -> read -> compute -> state -> write -> render`) so render surfaces never measure or mutate physics mid-frame. The full set of render and diagnostic modes ships and is browsable at `/docs/diagnostics`: `dots`, `trails`, `links`, `streamlines`, `metaballs`, `voronoi`, `field-lines`, `heatmap`, `force-vectors`, `contours`, `potential`, `energy`, `topology`, `inspector`, `causality`, and `prediction`. None of these are planned; they are all live render surfaces over the shared field context. ## 15. Visual Semantics Visual state should carry meaning consistently. | Meaning | Visual channel | |---|---| | attention | saturation, weight, glow, scale | | uncertainty | entropy, blur, desaturation | | memory | patina, trail, pattern persistence | | danger | heat, contrast, repel pattern | | completion | coherence, alignment, calm | | relationship | thread, tension, shared pattern | | priority | strength, depth, larger range | | disabled | screen, desaturation, low response | | loading | stream, pulse, vortex | | success | release, coherence, cooling | ## 16. Accessibility and Semantic Layer Expressive visuals must not be the only source of meaning. Rules: ```txt Live semantic text remains in the DOM. Vectorized text must be paired with hidden or equivalent semantic text. Canvas visuals require semantic DOM fallback. Color is not the only carrier of meaning. Motion is optional. Reduced motion preserves state without travel. Field events should not spam assistive technologies. ``` Typography pattern: ```html

    The actual accessible heading text

    ``` ## 17. Dependency-Free Implementation Rule Core `Fundamental` should avoid dependencies. Use platform APIs first: ```txt Custom Elements Shadow DOM CSS Custom Properties CSS transforms CSS gradients CSS masks SVG paths SVG filters Canvas 2D Pointer Events Keyboard Events Focus Events ResizeObserver IntersectionObserver Web Animations API requestAnimationFrame ``` Rules: ```txt Do not require external libraries for core rendering. Do not require external font parsing for standard typography effects. Do not mutate commercial font files. Do not make SVG/Canvas the only semantic source of text. Do not make debug or visual layers mutate physics. ``` If an optional adapter exists, it should be outside the core. ## 18. Visual Contracts Every visual layer should declare: ```txt name source metrics target properties whether it mutates physics whether it writes DOM state reduced-motion behavior accessibility fallback performance cost debug visibility ``` Example: ```txt Layer: live typography density Source: --field-density, --field-attention Target: font-variation-settings, text-shadow Mutates physics: no Writes DOM state: no Reduced motion: unchanged Accessibility: semantic text remains live Performance: CSS only ``` ## 18.1 Visual Binding and Overlay Registries The `@fundamental-engine/platform` runtime makes the visual contract above operational. Two registries on the `FrameScheduler` own the visual-to-semantic boundary. `VisualBindingRegistry` pairs each visual layer with the semantic body it expresses. A binding declares its source metrics, its target properties, and the semantic element it must stay paired with, so an expressive canvas or SVG layer is never the sole carrier of meaning. The platform lint surfaces two relevant rules here: ```txt visual-orphan -> a visual binding with no semantic body to pair with visual-not-hidden -> a decorative visual layer not marked aria-hidden / non-semantic ``` `OverlayRegistry` registers and orders the SVG and diagnostic overlays that sit above the canvas render surface, and ties each overlay to the links or relationships it visualizes. Its lint rule: ```txt overlay-without-links -> a relationship overlay registered with no links to draw ``` Both registries run as scheduler phases (`discover -> read -> compute -> state -> write -> render`), so overlays read in the read phase and draw in the render phase and never mutate physics. `lintPlatform()` reports these rules alongside the other platform checks (`relation-target-missing`, `state-unregistered`, `feedback-non-css-var`, `measurement-off-phase`). ## 18.2 Accessibility Preview and Exported Diagnostics The visual layers are accessibility-aware render surfaces, and the platform exposes that property directly. An accessibility preview lets you view any composition as the reduced surface: motion stilled, glow bounded, and state preserved through static tone, outline, icon, text, or layout. This makes the "color is not the only carrier of meaning" and "reduced motion preserves state" rules verifiable rather than aspirational, by rendering the meaning-preserving fallback for a body and its visual bindings. Diagnostic overlays can be exported as SVG or PNG. SVG export captures the path-accurate overlay layers (relationship lines, contours, field lines, vector marks) as resolution-independent geometry; PNG export captures the rasterized canvas render surface for any of the modes at `/docs/diagnostics`. Exported diagnostics are render output only: they read field state, never mutate physics, and never replace the semantic DOM. ## 19. Visual Authoring Attributes Suggested attributes: ```html
    ``` Potential attributes: | Attribute | Purpose | |---|---| | `data-visual` | active visual systems | | `data-field-material` | material preset | | `data-color-mode` | color mapping | | `data-shape-mode` | shape mapping | | `data-pattern-mode` | pattern mapping | | `data-emission` | emission behavior | | `data-container-role` | container behavior | | `data-semantic-layer` | semantic mapping | | `data-reduced-visual` | reduced-mode fallback | ## 20. Useful Visual Recipes ### Living Typography ```txt density -> weight attention -> width / glow pull vector -> slant heat -> emission ``` ### Magnetic Logo Field ```txt glyph outlines -> field body magnetism -> field loops fieldflow -> plasma travel semantic text -> hidden accessible label ``` ### Relationship Pattern Map ```txt RelationshipAgent strength -> line weight memory -> pattern persistence attention -> glow conflict -> dashed entropy ``` ### Form Coherence Surface ```txt valid fields -> coherence invalid fields -> heat / entropy submit button -> attention only when coherent ``` ### Reading Memory Article ```txt read paragraphs -> memory pattern viewport center -> attention citations -> threads unresolved terms -> entropy ``` ### Container Weather ```txt section samples local density, heat, entropy, memory container changes tone/pattern based on field weather ``` ## 21. Implementation Priority The platform-runtime phase (Phase D) makes this layer the default for ``: the visual binding and overlay registries, the visual lint rules, the SVG glyph/path layer with semantic fallback, and relationship visualization all ship. The order below remains the recommended sequencing for any new visual layer built on the runtime. Build this visual layer in this order: ```txt 1. CSS variable output contract for visual metrics. 2. Live text mapping for density, attention, heat, pull. 3. Color channel mapping with accessibility bounds. 4. Shape mapping for scale, radius, pressure, entropy. 5. Container roles and scope visuals. 6. Pattern rendering through CSS gradients and SVG patterns. 7. Emission contract and budgeted source distinction. 8. SVG glyph/path visual layer with semantic text fallback. 9. Relationship pattern visualization. 10. Material presets. 11. Visual lint rules. 12. Visual recipes. ``` ## 22. Final Rule The visual system should make field state legible without sacrificing semantics. ```txt Visual form can become geometry. Semantic meaning must remain accessible. Field state can shape appearance. Appearance must not corrupt the field. ``` ======================================================================== FILE: visualization-methods-taxonomy.md ======================================================================== > **Status: canonical.** > Render layers, diagnostics, heatmaps, field lines, probes, energy, topology, causality, and prediction. Current as of the platform-runtime phase (Phase D). See [platform-architecture.md](platform-architecture.md) and [system-contracts.md](system-contracts.md). # Visualization Methods Taxonomy for Fundamental ## Related Documents | Document | Role | |---|---| | [`README.md`](./README.md) | Documentation map | | [`system-contracts.md`](system-contracts.md) | Visualization contract | | [`fundamental-field-behavior-table.md`](fundamental-field-behavior-table.md) | Field vs force laws | | [`testing-and-conformance.md`](testing-and-conformance.md) | Visualization tests | ## Purpose Visualization methods reveal fields, forces, energy, matter state, topology, heat, memory, attention, and reciprocal DOM state. Visualization is not decoration. It 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. ``` ## Visualization Truth Table | Visualization | Reads from | Mutates physics? | Shows truth about | |---|---|---:|---| | Particles | particle state | yes, particles are state | matter | | Field lines | `field()` | no | structure | | Streamlines | vector field | no | continuous direction | | Force vectors | `apply()` or probe | no | cause | | Trails | particle history | no | motion history | | Heatmaps | scalar grids | optional | accumulation | | Contours | scalar fields | no | terrain / equal values | | Potential | potential field | no | wells and gradients | | Energy | particle + field state | no | cost and conservation | | Topology | relationship agents | optional | coupling | | DOM state | CSS variables and events | yes, visually | reciprocity | | Causality | per-force contributions | no | why motion happened | | Prediction | deterministic ghost step | no | expected future path | > **Shipped (as data + renderers).** `VISUALIZATION_TRUTH_TABLE`, the `RENDER_MODES` catalog, and > `VISUALIZATION_PRESETS` live in `packages/core/src/visual/visualization.ts`. Every catalog mode is > `shipped` — none are planned. The matter/structure modes ship; the diagnostic modes force-vectors, > contours, potential and energy ship with canvas renderers in `diagnostics/render.ts` (C1); and > topology, inspector, causality and prediction ship in `diagnostics/modes.ts` (`drawTopology`, > `drawInspector`, `causalityAt` + `drawCausality`, `ghostTrajectory` + `drawPrediction`). All of these > are exercised on the live `/docs/diagnostics` page. The canvas is one render surface among these > layers, not the whole system: `Fundamental` computes renderer-agnostic field behavior and > `@fundamental-engine/platform` binds it to the DOM, while these overlays draw it onto the canvas surface. ## Render Modes Catalog The engine ships **16** render modes (`RENDER_MODES` in `packages/core/src/visual/visualization.ts`), split into matter/structure modes and diagnostic modes. All are shipped; set one with `field.setRender(mode)` (or the `render` option). The `` `render` *attribute* exposes a subset (`dots` / `trails` / `links` / `streamlines` / `metaballs` / `voronoi`); the rest are reached through `setRender()` / the core. | Render mode | Type | Shows | |---|---|---| | `dots` | matter | particle positions and heat | | `trails` | motion | path history | | `links` | structure | proximity links between near bodies | | `streamlines` | structure | continuous field paths | | `metaballs` | matter | merged density blobs | | `voronoi` | structure | region cells around bodies | | `field-lines` | structure | `field()` geometry | | `heatmap` | scalar | density, heat, force, entropy | | `force-vectors` | diagnostic | actual cause from `apply()` | | `contours` | diagnostic | equal-value isolines | | `potential` | diagnostic | wells and gradients | | `energy` | diagnostic | kinetic, potential, thermal | | `topology` | diagnostic | threads, flux links, relationships | | `inspector` | diagnostic | bodies, agents, metrics, contracts | | `causality` | diagnostic | contribution sources | | `prediction` | diagnostic | ghost trajectory | ## Visualization Presets | Preset | Layers | |---|---| | `beautiful` | particles + subtle trails | | `scientific` | field-lines + vectors + contours | | `diagnostic` | inspector + vectors + body rects | | `thermal` | heatmap + particle heat + energy | | `plasma` | field-lines + fieldflow + heat trails | | `topological` | field-lines + flux links + threads | | `reduced` | static contours + DOM state | | `poster` | frozen particles + field lines + composition-safe layout | | `causality` | particles + force vectors + contribution colors | | `prediction` | actual trails + ghost trails + divergence error | ## Surfaces & Placement The methods above answer *what* to draw. **Placement** answers *where* it composites relative to page content — an axis orthogonal to every visualization method. The visible particle canvas is one **surface**; Fundamental defines three: | Surface | Placement | Drawn on | Status | |---|---|---|---| | **Underlay** | behind content (`z-index:0`) | the `` canvas | shipped (the default) | | **Overlay** | in front of content (`pointer-events:none`, screen-blend, above content / below the nav) | a second light-DOM canvas the element owns | shipped | | **Typographic (invisible)** | in the content itself | nothing — the field's feedback variables (`--d`, `--load`, `--field-*`) styled by author CSS into type, ink, and anchor | shipped — see [invisible-fields.md](invisible-fields.md) | - **Immersive** = the same field drawn on *both* surfaces, so content sits **inside** the field. It is a composition, not a new primitive: set the underlay (`render`) and the overlay (`overlay`) together. - **Typographic (invisible)** = no surface at all: the engine runs draw-skipped (`FieldHandle.setVisible(false)`) and/or a recipe runs render-less (`render: []`), and the page's own type *is* the render surface. The full pattern — two-field architecture, live channels, engagement contracts, data provenance — is canonical in [invisible-fields.md](invisible-fields.md). - **Overlay-suitable methods** are the structure/vector visualizations that reveal field *shape* without occluding text: `streamlines`, `force-vectors`, `field-lines`, `grid` (the reference lattice displaced by the field — deformation), `temperature` / `energy` (iso-contour instances of the scalar `contours` method, reading heat and kinetic energy), `path` (streamline curves traced from seeded probes), and `data` (numeric per-body density readouts — the inspector method's lightest form). Particle/matter methods (`dots`, `trails`, `metaballs`, `voronoi`) stay on the **underlay** by design — drawn over text they would obscure it. - The overlay renders the **live** field (the engine's `forceAt` / `netField` samplers over the current bodies), not a static trace — so it tracks the page as bodies move, scroll, and engage. ### Surfaces API | Surface | Set live | Declarative (``) | createField option | |---|---|---|---| | Underlay | `setRender(mode)` | `render="…"` | `render` | | Overlay | `setOverlay(mode)` | `overlay="…"` | `overlay` (+ `overlayCanvas` for raw `createField`) | ```html ``` ```ts field.setRender('dots'); // underlay (behind content) field.setOverlay('field-lines'); // overlay (in front of content); 'off' clears the surface field.setOverlay(['grid', 'path', 'temperature']); // readings are ADDITIVE — a stack composes ``` **The input mirror — field channels.** Surfaces are *output*: the engine draws onto them. Their open *input* analog is a **field channel** — `addField(name, sampler)` registers an external scalar field (terrain, moisture, a heat map) the engine samples on its own read path, read back with `sampleField(name, x, y)`. A surface is a place the field draws; a channel is a field the engine reads. Channels obey the field-function contract and are pull-based — see [system-contracts.md §2.1](system-contracts.md). (The surface *set* is deliberately the three placements above, not an open registry; the open extension point on the output side is a registrable render/overlay mode, tracked separately.) Readings are **additive**: `setOverlay` takes one reading or a stack (an array; space-separated in the `overlay` attribute), drawn in order on the one front surface — so matter (underlay) + the heatmap layer + several overlay readings compose into a single legible picture of the same field. **Placement is orthogonal to mode** — any overlay-suitable method renders on either surface. `` owns the overlay canvas (created in the light DOM, since the shadow host is `z-index:0`); `createField` callers pass their own `overlayCanvas`. Core stays renderer-agnostic: it only draws to the canvases it is handed. > **Planned (named, not built):** per-element / `inline` placement (a surface scoped to one box), > `framed` placement (within a stage), the `potential` scalar overlay, and the graph overlays > (`topology` / `causality` / `prediction`). The `OverlayMode` union is additive, so these land > without a breaking change — exactly how `grid` / `temperature` / `energy` / `path` / `data` landed. ## 1. Particles Particles are visible matter. Methods: | Method | Description | Formula / data | |---|---|---| | Point particles | simple dots | `p.x`, `p.y`, `p.heat`, `p.phase` | | Heat-tinted particles | color shifts with excitation | `color = mix(base, accent, p.heat)` | | Velocity-stretched particles | faster particles elongate | `length ∝ |v|` | | Mass-scaled particles | heavier particles render bigger | `radius ∝ sqrt(p.m)` | | Phase particles | visual treatment by material state | gas/liquid/solid/plasma | | Pigment particles | particles carry color state | `p.color` | Recommended: ```txt particle radius = baseRadius * (1 + heat * 0.8) * sqrt(m) particle alpha = baseAlpha + heat * heatAlpha ``` ## 2. Field Lines Field lines visualize `field(b, x, y)`. They are not always particle paths. | Field | Field-line structure | Particle relationship | |---|---|---| | Gravity | inward radial lines | particles accelerate along field unless orbiting | | Charge | outward/inward radial lines | positive follows, negative moves opposite | | Magnetism | loops/dipoles | particles curve across lines | | Fieldflow | reads existing lines | particles follow them | | Memory | worn paths/gradients | agents may follow memory gradient | General tracing: ```txt p0 = seed point for step: F = fieldAt(p) dir = normalize(F) p = p + dir * stepSize ``` Trace forward and backward: ```txt p_forward += normalize(F) * stepSize p_backward -= normalize(F) * stepSize ``` Stop when: ```txt field strength < threshold point exits viewport line reaches max length line loops near start line approaches another line too closely ``` ## 3. Force Vectors Force vectors show actual cause from `apply()`. For velocity-dependent forces, use probes. Example for magnetism: ```txt probe = { q: 1, v: chosenVelocity, m: 1 } F = applyToProbe(probe) ``` Important distinction: ```txt field magnitude != force magnitude ``` A strong magnetic field can exert zero force on a neutral or still particle. ## 4. Probe Modes Probe particles are instruments. | Probe | Purpose | |---|---| | Neutral probe | fieldflow, transport, collision | | Positive charge probe | electric and magnetic behavior | | Negative charge probe | sign reversal | | Still charged probe | velocity requirement | | Fast probe | drag, magnetism, collision | | Hot probe | thermal, crystallize, fuse | | Massive probe | gravity and inertia | | Paired probes | divergence, attraction, collision | | Probe sheet | field distortion across a plane | The Lab should not only show demos. It should fire instruments into the field. ## 5. Heatmaps Heatmaps are scalar field buffers. | Heatmap | Measures | Formula | |---|---|---| | Density | particle concentration | `H = Σ K(|x - p.x|, r)` | | Heat | particle excitation | `H = Σ p.heat * K(d,r)` | | Force | force magnitude | `H = |Σ F_i(x,y)|` | | Velocity | motion intensity | `H = Σ |p.v| * K(d,r)` | | Entropy | disorder | weighted local variance | | Memory | repeated occupancy | `M = M * decay + occupancy` | | Attention | engagement concentration | body density + engagement | | Accretion | captured matter | `body.accreted / capacity` | | Relationship | linked content intensity | relationship weight | | Path | repeated user movement | user trail deposits | Recommended kernel: ```txt K(d, r) = max(0, 1 - d² / r²)² ``` Scalar grid: ```ts type ScalarGrid = { width: number height: number resolution: number values: Float32Array decay: number } ``` ## 6. Contours and Potential Contours show equal scalar values. Use for: ```txt potential density heat entropy memory pressure attention ``` Potential examples: ```txt Φ_gravity = -GM / sqrt(r² + ε²) Φ_charge = kQ / sqrt(r² + ε²) ``` Use marching squares for isolines. ## 7. Energy Visualization Energy views make the system accountable. | Energy | Formula | Meaning | |---|---|---| | Kinetic | `K = 0.5 * m * |v|²` | motion | | Potential | `U = mΦ` or `U = qΦ` | position in field | | Thermal | heat or velocity variance | agitation | | Binding | `0.5 * k * (d - L)²` | stored link energy | | Accretion | accreted/capacity | held matter | | Dissipation | `ΔE_lost` | drag/damping loss | | Source | emitted budget | spawn/supernova | Lab metrics: ```txt E_total ΔE per step energy injected energy dissipated energy conserved ``` ## 8. Topology and Relationship Visualization Topology views show relationships among agents. | Overlay | Meaning | |---|---| | Threads | explicit relationships | | Flux links | field-derived relationships | | Memory paths | repeated routes | | Attention bridges | attention transfer | | Graph edges | data relations | | Accretion ownership | captured matter ownership | Render: ```txt curved lines between bodies pulse along relationship thickness by coupling color by force type dashed inferred relations ``` ## 9. Boundary Visualization | Boundary | Visualization | |---|---| | Reflect | collision box and bounce normals | | Gate | one-way membrane arrows | | Screen | shield/attenuation field | | Spotlight | cone wedge | | Lens | refractive ring / caustic lines | | Absorb | capture horizon | | World edge | wrap/fade margin | | Morph target | target points/silhouette | ## 10. Phase and Material Visualization | Phase | Visual | |---|---| | Gas | sparse particles | | Liquid | metaballs/cohesion | | Solid | lattice/crystal | | Plasma | fieldflow + glow trails | | Memory-worn | persistent paths | | Accreted | captured core/meter | ## 11. Causality Overlay The system should answer: ```txt Why did that move? ``` Causal visuals: | Cause | Visual | |---|---| | Charge | electric accent | | Magnetism | curved blue/purple impulse | | Fieldflow | cyan stream | | Drag | gray resistance | | Collision | spark | | Gravity | deep well glow | | Screen | shield fade | | Reflect | bounce normal | ## 12. Prediction Mode Predict the next N frames without mutating live state. ```txt actual path = solid predicted path = ghost error = divergence ``` Use for: ```txt integrator debugging chaotic fields force comparison magnetism vs fieldflow stability testing education ``` ## 13. Field Narrative Mode A page can teach the system by progressively revealing layers. ```txt 1. particles only 2. bodies appear 3. field lines appear 4. forces move agents 5. density writes to DOM 6. heatmaps reveal accumulation 7. topology links bodies 8. inspector shows reciprocity ``` This narrative reveal ships: the diagnostics surface steps through the layers above, and the live `/docs/diagnostics` page walks the reveal in order. An accessible preview ships alongside it. Under `prefers-reduced-motion`, the narrative collapses to a static preview that still names each layer and shows its current state, so the explanation reaches keyboard and reduced-motion users without animation. Reduced motion preserves meaning rather than hiding it. ## 14. 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. ``` Compare: ```txt entropy coherence average speed energy drift density concentration attention share source budget particle count ``` ## 15. Exportable Field Snapshots Export formats: ```txt PNG SVG field lines JSON scene recipe Lab report conformance state debug trace poster image ``` Field export ships: the diagnostics surface exports the current field as an image — SVG (vector field lines and overlays) or PNG (rasterized canvas) — alongside the JSON scene recipe. Snapshots should become regression tests where possible. > **Diagnostics shipped (data layer + renderers).** The pure math behind these overlays ships in > `packages/core/src/diagnostics/`: energy accounting (§7), scalar `potentialAt` + grid sampling for > contours/potential (§6), probe `forceVectorAt` + `causalityAt` (§3/§4/§11), and heatmap-variant > samplers density/heat/velocity (§5). The canvas *drawing* of these overlays also ships in > `diagnostics/render.ts` and `diagnostics/modes.ts`, and the SVG/PNG field export above is wired up. > All of it is live and interactive on the `/docs/diagnostics` page. ## Implementation Priority This list records the build order that has now shipped; every item below is live (see `/docs/diagnostics`). ```txt 1. Visualization truth table 2. Field lines from every field() hook 3. Force vectors through probes 4. Probe modes 5. Density/heat/attention heatmaps 6. Energy dashboard 7. Boundary overlays 8. Reciprocity Inspector 9. Scene recipe export/import 10. Causality overlay 11. Prediction mode 12. Topology/flux-linkage after fieldflow stabilizes ```