API reference

Platform parity matrix

Which FieldHandle methods ship on each surface. JS is the source of truth. @fundamental-engine/three delegates all 44 methods to the wrapped engine — 44/44. Swift and Kotlin are native ports at full parity — 44/44. The cross-plane physics is identical (the 36-force conformance suite asserts it). This matrix tracks API surface parity.

Three distinct axes — don't conflate them. API parity (this matrix): the FieldHandle method surface exists — 44/44/44. Conformance: the force math matches, asserted by the shared cross-plane golden (the 36-force suite). 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
50/50 (100%)
Swift
49/50 (98%)
Kotlin
50/50 (100%)
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)
projections projection registry — JS core + web + Kotlin (agent-json + callback surfaces); Swift port in progress; css/dom/svg surfaces are web-first
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/particleCapture/supernova); 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

Platform notes

All three platforms ship 44/44 as of June 2026 (#822 Swift, #823 Kotlin). Some methods behave differently across platforms by design:

Three.js — 44/44, host-context notes
@fundamental-engine/three delegates all 44 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.