Guides

The Kotlin port

The same reciprocal field, native on Android. It is a port of the JS engine, not a reinterpretation: the package layout, the API surface, and the physics mirror the npm packages — and the Swift port — one-to-one. The two planes are held to the same shared cross-plane conformance golden (JS / Swift / Kotlin). Where they diverge, it is a bug or a documented platform difference.

Status: 44/44. The Kotlin port is conformance-checked against the JS engine (the same 36-force golden the Swift port runs) and ships all 44 FieldHandle methods as of #823. See Implementations for the full surface-by-surface status, and Parity below for platform-specific notes.

Install

Nothing is on Maven Central yet — consume it from source. The modules live in the repo's android/ directory; the recommended door is :fundamental-compose.

settings.gradle.kts
// settings.gradle.kts — depend on the modules from source.
// Preview: nothing is published to Maven Central yet, so include the repo's
// android/ build as a composite (a maven coordinate door comes later).
includeBuild("../fundamental-engine/android") {
  dependencySubstitution {
    substitute(module("com.fundamental:fundamental-compose"))
      .using(project(":fundamental-compose"))
  }
}

// build.gradle.kts (your app module)
dependencies {
  implementation("com.fundamental:fundamental-compose")
}

To see it run before wiring it into your own app, build the bundled desktop Field Lab: ./gradlew :lab:run from android/ — every engine pillar as a live, interactive scene.

Modules — one-to-one with npm

Four libraries, each the mirror of an npm package (and of a Swift target). fundamental-core imports zero platform code, exactly as @fundamental-engine/core imports zero DOM.

Gradle modulenpm equivalentWhat it is
:fundamental-core@fundamental-engine/coreThe pure physics — particles, bodies, the 36-force catalog, the integrator, formations, reactions. Zero platform imports.
:fundamental-platform@fundamental-engine/domThe six-phase frame scheduler (discover → read → compute → state → write → render) and the six registries.
:fundamental-android@fundamental-engine/vanillaThe imperative host — FieldFieldView, a plain Android View / Canvas with no Compose dependency.
:fundamental-compose@fundamental-engine/reactThe declarative adapter — FieldView, Modifier.fieldBody(), the FieldHandle exposed to descendants.

Compose — FieldView + Modifier.fieldBody()

The declarative door. FieldView mounts the field surface; any composable inside becomes a body with the Modifier.fieldBody(...) modifier — the Kotlin analogue of the data-body attribute (and of SwiftUI .fieldBody()). It accepts the same token vocabulary and tuning as the web.

Compose
import com.fundamental.compose.FieldView
import com.fundamental.compose.fieldBody

@Composable
fun ContentScreen() {
  Box {
    // the field surface — accepts the same tuning as the web / Swift hosts
    FieldView(accent = Color(0xFF4DA3FF), renderMode = RenderMode.DOTS)

    // any composable becomes a body — the Kotlin analogue of [data-body]
    Text(
      "pull me",
      modifier = Modifier.fieldBody(tokens = listOf("attract"), strength = 1.2f, range = 150f),
    )
  }
}

View / Canvas — the imperative host

For non-Compose apps, FieldFieldView is a plain Android View that runs the field on a Canvas and drives its own frame loop — the analogue of new FieldField() / mountField() from the vanilla JS API.

Kotlin
import com.fundamental.android.FieldFieldView

// imperative host — a plain Android View / Canvas, no Compose required.
val field = FieldFieldView(context)
parent.addView(field)                 // mounts and starts the frame loop
field.addBody(BodySpec(tokens = listOf("attract"), strength = 1.2f, range = 150f))
field.burst(tap.x, tap.y)             // a CGPoint analogue from a MotionEvent
// the loop stops automatically on detach from the window

Parity

The Kotlin port ships 44/44 FieldHandle methods — full parity with the JS engine as of #823. The core force set, the scheduler and registries, formations, the FieldHandle public API (relationship edges included), and all six advanced methods (addAgent, sample, on, readParticleIds, readParticleChannels, registerOverlay) are implemented and pass the cross-plane conformance gate.

The full method-by-method breakdown is on the parity matrix page. Some methods behave differently by platform design: Compose and the View/Canvas host own the draw loop, so setRender and setOverlay are read by the host rather than driving a native canvas directly. scrollV is fed by the platform via feedScrollV(). These platform differences are documented in the parity matrix notes.

The deeper architectural story — why the same engine can run on the web, in WebGL, headless, and natively on Apple platforms and Android behind one host seam — is the same one the Swift port tells. The seam itself is the platform layer; the runtime handle is the FieldHandle.