API reference

Platform parity matrix

Which FieldHandle methods ship on each surface. JS is the source of truth. @fundamental-engine/three delegates all 52 methods to the wrapped engine — 52/52. Swift (50/52) and Kotlin (50/52) are native ports, mirrored but currently trailing the newest additions (see the table below for which methods and why). The cross-plane physics is held to a shared conformance golden (six canonical deterministic forces, within a stated tolerance) plus per-plane behavioral tests for the rest, regardless of API-surface gaps. This matrix tracks API surface parity.

Three distinct axes — don't conflate them. API parity (this matrix): the FieldHandle method surface — 52/52 Three.js, 50/52 Swift, 50/52 Kotlin. Conformance: the force math matches, asserted by the shared cross-plane golden for the six canonical deterministic forces, and by per-plane behavioral tests for the other 31. Production readiness: packaging, platform polish, and docs — this is Preview and differs by host. Native ports are at FieldHandle API parity, but packaging, platform polish, and production-readiness differ by host.
How to read this table. A green chip means the method ships on that platform. A grey chip means it is not yet implemented (or not applicable for that platform — see the note column for context). The counts below each platform header show what fraction is covered.

FieldHandle coverage

Method Three.js
52/52 (100%)
Swift
50/52 (96%)
Kotlin
50/52 (96%)
Notes
scan ✓ ✓ ✓
rescan ✓ ✓ ✓ alias of scan
setAccent ✓ ✓ ✓
setPalette ✓ ✓ ✓
setFormation ✓ ✓ ✓
setWaveStyle ✓ ✓ ✓
setWaveCenter ✓ ✓ ✓
setSeparation ✓ ✓ ✓ Kotlin fun setSeparation(Float) coexists with var separation via @JvmName on the property
setAttention ✓ ✓ ✓
setCausality ✓ ✓ ✓
setHeatmap ✓ ✓ ✓
setDprCap ✓ ✓ ✓ Three.js delegates but DPR is renderer-owned; native stores in FieldOptions / FieldHandle
setQualityTier ✓ ✓ ✓
setRender ✓ ✓ ✓ render surface is host-owned on native + Three.js; Kotlin host reads renderMode
setOverlay ✓ ✓ ✓ use threeBackend() for Three.js diagnostic overlays
setBackground ✓ ✓ ✓ web canvas clearing; native stores in FieldOptions.background
threads ✓ ✓ ✓ visual layer — glowing connector lines
burst ✓ ✓ ✓
flowTo ✓ ✓ ✓
clearFlow ✓ ✓ ✓
seed ✓ ✓ ✓
addAgent ✓ ✓ ✓ AgentSpec / AgentHandle; Kotlin init-block wires tickAgents() via onAfterTick; Swift uses UUID-keyed agent list
addBody ✓ ✓ ✓
addEdge ✓ ✓ ✓
readEdges ✓ ✓ ✓
addField ✓ ✓ ✓
sampleField ✓ ✓ ✓
atomAt ✓ ✓ ✓
focusAt ✓ ✓ ✓
clearFocus ✓ ✓ ✓
particleCount ✓ ✓ ✓
energy ✓ ✓ ✓
query ✓ ✓ ✓ structured read of bodies/metrics/relationships; the influences/projections/dimensions lanes stay empty on the ports until an accumulator/registry/dimension lane lands (JS field names kept)
snapshot ✓ ✓ ✓ point-in-time field capture; body data withheld by default (tightest-wins profile)
diff ✓ ✓ ✓ pure comparison of two snapshots — added/removed/changed bodies, metric deltas, relationship + formation changes
replay ✓ ✓ ✓ causal replay over a snapshot pair; force-attributed steps empty-for-now on the ports (no impulse accumulator yet)
forAgent ✓ ✓ ✓ capability-scoped, redacted, read-only agent view (agent-readable is not agent-writable)
sample ✓ ✓ ✓ force-probe at world point; Swift delegates to forceAt(); Kotlin delegates to controller.sample() → forceAt()
sampleScalar ✓ ✓ ✓
sampleGradient ✓ ✓ ✓
grid ✓ ✓ ✓ named ScalarGrid — lazy get/create, same grid as env.grid in the force system
on ✓ ✓ ✓ UUID-keyed subscriber bus; FieldEvent enum (tick/bodyAdd/bodyRemove + captured/released, the JS bus keys; #1020); returns Subscription
readParticles ✓ ✓ ✓
readParticleIds ✓ ✓ ✓ Particle.id (stable, auto-incremented by FieldStore.add); fills an Int buffer
readParticleChannels ✓ ✓ ✓ samples named ScalarGrids at each particle position; stride = names.count/size
registerOverlay ✓ ✓ ✓ OverlayRenderer protocol/interface; host reads overlayRegistry and calls render() each frame
scrollV ✓ ✓ ✓ DOM/UIKit scroll velocity; Kotlin: scrollV() + feedScrollV(); Three.js returns 0 in headless
setVisible ✓ ✓ ✓
destroy ✓ ✓ ✓
setPolicy ✓ ✓ ✓ runtime FieldPolicy (motion/privacy budgets); mirrored on all three planes
focus ✓ — — focus/attention substrate (EXPERIMENTAL, shipped 0.9.4) — operator/agent attention write; Swift + Kotlin ports are a batched follow-up
focusState ✓ — — focus/attention substrate (EXPERIMENTAL, shipped 0.9.4) — the ranked, thresholded attention read; Swift + Kotlin ports are a batched follow-up

Platform notes

All three platforms briefly shipped the full 44-method surface as of June 2026 (#822 Swift, #823 Kotlin) — the JS-side surface has grown since (now 52 methods; see the live counts above), and the ports have not fully caught up. Some methods behave differently across platforms by design:

Three.js — 52/52, host-context notes
@fundamental-engine/three delegates all 52 methods to the wrapped FieldHandle. Some are contextually different in a 3D scene: setRender / setOverlay / setBackground are owned by the Three.js renderer — use threeBackend() for diagnostic overlays. scrollV returns 0 (no DOM scroll). scan / rescan are called internally; in Three.js register bodies via layer.addBody(mesh, spec).
sample — force probe
Swift delegates to forceAt(bodies:forces:env:at:) in Streamlines.swift. Kotlin delegates to FieldController.sample() which calls the same forceAt() function used by the streamlines overlay. Both are safe to call between ticks.
on — event bus
Both platforms use a UUID-keyed subscriber registry (not closure equality, which doesn't hold across captures). FieldEvent.tick fires after every simulation step via an onAfterTick hook. bodyAdd / bodyRemove fire from the addBody / remove path. Returns a Subscription; call .cancel() to unsubscribe.
addAgent — autonomous consumers
AgentSpec carries a position closure sampled each tick; onInfluence receives the net force vector at that point. Agents are ticked via the same onAfterTick hook as the event bus, after each force step.
readParticleIds / readParticleChannels
Particle.id is assigned by FieldStore.add() via a monotonically increasing counter — stable for the lifetime of the pool. readParticleChannels samples each named ScalarGrid at each particle's position; the output stride equals the number of channel names.
registerOverlay
OverlayRenderer is a protocol (Swift) / interface (Kotlin). The FieldHandle keeps a [String: OverlayRenderer] registry the platform host frame loop reads to call render() after the underlay draw each frame. No deep engine integration — pure registry delegation.