Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,39 @@ a git tag (see [RELEASING.md](RELEASING.md)).

## [Unreleased]

- **Android artifacts publish from CI on a release tag, at a tag-derived version.** `android.yml` gains a `publish` job (`if: refs/tags/v*`, `packages: write`, Actions `GITHUB_TOKEN` — no personal token) that runs `:fundamental-core:publish :fundamental-compose:publish`. The version is derived from the tag via `-PreleaseVersion` and defaults to a `SNAPSHOT` locally — the hardcoded `version = "0.9.5"` is gone, so a publish can never silently overwrite a release with different code. One `git tag vX.Y.Z` now releases every plane at one version: npm via `release.yml`, Swift via the SPM tag, Kotlin via this. Publication config verified against the local Maven repo before merge.
- **Positioning made consistent site-wide.** The homepage rewrite changed the hero, title and description, but the footer — which renders on *every* page — still read "a readable behavior layer for host objects", so the homepage contradicted itself on the same screen. The `Base.astro` default title carried it too. Both now say "a physics engine for interfaces". The only surviving instance is the changelog entry above, which quotes the old phrase to explain why it was retired; historical records that cite a former term are left intact.
## [0.10.0] — 2026-07-21

- **Finished retiring the freeze vocabulary across `docs/canonical/`.** The earlier change corrected the authoritative sources but left the wording in nine other canonical documents, where "the freeze contract" and "the frozen surface" still described a promise the project had stopped making. All now say *protected* / *removal-protection*. Four uses of the word are deliberately untouched because they mean something else entirely — `Object.freeze`'d policy clones, "freeze the sim" for reduced motion, "frozen particles" in the poster render mode, and "frozen design history" for the planning archive. A pattern-matched sweep would have broken all four.
The reproducibility envelope ships, and cross-plane publishing is complete: **one `git tag v0.10.0`
now releases npm, Swift (SPM) and Kotlin (Maven/GitHub Packages) in lockstep at a single version.**

- **Homepage leads with the artifact instead of the abstraction.** The hero opened with 227 words before anything moved, and asked a reader to hold six unfamiliar concepts — "a readable behavior layer for host objects" appeared in the kicker, the page title, the meta description *and* the first sentence, all before any evidence. The standfirst is now two sentences that are checkable on the page itself, the strongest of which is **"nothing on this page is animated."** Kicker and title become "a physics engine for interfaces" — a category people already have a slot for.
- **New `#shipped` section: four doors, one core.** [Habitat](https://habitat.fundamental-engine.com) (WebGL, `@fundamental-engine/three`), [Ascent](https://ascent.guide) (iOS, `<field-root>` + elements, on the App Store), [zachshallbetter.com](https://zachshallbetter.com) (`@fundamental-engine/vanilla`), and the [native parity matrix](https://fundamental-engine.com/docs/api/parity). The renderer-agnostic claim was previously asserted in prose; it is now four links you can open.
- **Cross-plane parity surfaced in the hero meta** — `js · swift · kotlin`, six forces, identical output, checked in CI. It was one clause in a dense paragraph and the word "parity" appeared once on the entire page, despite being the least common thing the project can claim.
- Maturity line corrected: it read *"no external users yet"* while shipping in a published iOS app and a live WebGL game. It now reads "shipping in production apps, no third-party adopters yet" — which is both truer and stronger.
### Breaking (pre-1.0)

- **`FieldHandle` gains a required `guarantees` member.** **Additive for every consumer** — reading
`field.guarantees` is a new capability and breaks no calling code. **Breaking only for third-party
code that *implements* `FieldHandle` itself**, which must now provide the member. **Migration:**
return the runtime's envelope, or delegate to a wrapped field — the in-repo implementers
`FieldLayer` (`@fundamental-engine/three`) and `FieldField` (`@fundamental-engine/vanilla`) both
delegate, and are the reference pattern. Per the pre-1.0 policy this is the `0.MINOR` position, hence
`0.10.0` rather than a patch.

### Added

- **`FieldHandle.guarantees` — the reproducibility envelope is now queryable.** The runtime's determinism classification, its controlled and **uncontrolled** inputs, the requirements for repeatability, and the cross-plane numeric tolerance were previously stated only inside an unexported experimental module. The first external integrator concluded the runtime was byte-identical across environments and designed replay and shared-state features on that — a reasonable inference from unavailable information. It is `conditionally-deterministic`, `host-geometry` and `body-ordering` are **not** controlled, and cross-plane agreement is a tolerance (`1e-6`), never bit-equality. A drift test asserts the published envelope matches the internal contract declaration, because two statements of one fact diverge unless something checks them.
- **New canonical doc: [`coupling-discipline.md`](docs/canonical/coupling-discipline.md).** The rung discipline — couple at the lowest rung that achieves the effect — arrived at independently by two consumer projects that each hit the same wall. Covers rung selection, sampling cadence, the measured cost (fill-rate-bound, not particle-bound; ~1ms against a 16.7ms budget), and **when not to use the field at all**: high-frequency domain telemetry belongs in your own arrays, not in bodies.
- **README: the WebGL door is signposted where architecture decisions get made.** `@fundamental-engine/three` was fully documented in the packages table three-quarters of the way down; two independent readers still recommended hand-building the headless-to-`THREE.Points` bridge that ships in it.

### Build & release

- **Android artifacts publish from CI on a release tag, at a tag-derived version.** `android.yml` gains a `publish` job (`if: refs/tags/v*`, `packages: write`, Actions `GITHUB_TOKEN` — no personal token) that runs `:fundamental-core:publish :fundamental-compose:publish`. The version is derived from the tag via `-PreleaseVersion` and defaults to a `SNAPSHOT` locally — the hardcoded `version = "0.9.5"` is gone, so a publish can never silently overwrite a release with different code. One `git tag vX.Y.Z` now releases every plane at one version: npm via `release.yml`, Swift via the SPM tag, Kotlin via this. Publication config verified against the local Maven repo before merge.

### Docs & site

- **Homepage leads with the artifact instead of the abstraction.** The hero opened with 227 words before anything moved, and asked a reader to hold six unfamiliar concepts — "a readable behavior layer for host objects" appeared in the kicker, the page title, the meta description *and* the first sentence, all before any evidence. The standfirst is now two sentences that are checkable on the page itself, the strongest of which is **"nothing on this page is animated."** Kicker and title become "a physics engine for interfaces" — a category people already have a slot for.
- **New `#shipped` section: four doors, one core.** [Habitat](https://habitat.fundamental-engine.com) (WebGL, `@fundamental-engine/three`), [Ascent](https://ascent.guide) (iOS, `<field-root>` + elements, on the App Store), [zachshallbetter.com](https://zachshallbetter.com) (`@fundamental-engine/vanilla`), and the [native parity matrix](https://fundamental-engine.com/docs/api/parity). The renderer-agnostic claim was previously asserted in prose; it is now four links you can open.
- **Cross-plane parity surfaced in the hero meta** — `js · swift · kotlin`, six forces, identical output, checked in CI.
- **Positioning made consistent site-wide.** The footer, which renders on every page, and the `Base.astro` default title still carried the old phrasing after the homepage rewrite; both now say "a physics engine for interfaces".
- **Finished retiring the freeze vocabulary across `docs/canonical/`.** Nine documents still described "the freeze contract" / "the frozen surface"; all now say *protected* / *removal-protection*. Four uses meaning something else entirely (`Object.freeze` clones, reduced-motion "freeze the sim", the poster "frozen particles", "frozen design history") are deliberately untouched.
- **README: the WebGL door is signposted where architecture decisions get made.** `@fundamental-engine/three` was documented three-quarters down the packages table; two independent readers still recommended hand-building the headless-to-`THREE.Points` bridge it already ships.
- Maturity line corrected: it read *"no external users yet"* while shipping in a published iOS app and a live WebGL game.

## [0.9.5] — 2026-07-20

Expand Down
2 changes: 1 addition & 1 deletion PUBLISHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pnpm --filter "@fundamental-engine/*" publish --access public --no-git-checks --

## Versioning

All seven published packages are versioned together (currently `0.9.2`). Bump them as one:
All seven published packages are versioned together (currently `0.10.0`). Bump them as one:

```sh
pnpm --filter "@fundamental-engine/*" exec npm version <patch|minor|major> --no-git-tag-version
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ build-time tool and ships no runtime JavaScript by default.

If you use this work, please cite it via its concept DOI (it always resolves to the latest release):

> Shallbetter, Z. (2026). *Fundamental* (Version 0.9.3) [Computer software].
> Shallbetter, Z. (2026). *Fundamental* (Version 0.10.0) [Computer software].
> Zenodo. https://doi.org/10.5281/zenodo.20989937

<details>
Expand All @@ -629,7 +629,7 @@ If you use this work, please cite it via its concept DOI (it always resolves to
title = {Fundamental},
year = {2026},
publisher = {Zenodo},
version = {0.9.3},
version = {0.10.0},
doi = {10.5281/zenodo.20989937},
url = {https://doi.org/10.5281/zenodo.20989937}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import com.fundamental.core.math.Vec3
* lockstep with the JS constant / the release version: `VersionLockstepTests` fails the build if this
* drifts from `packages/core/package.json` (#923) — update it here on every release bump.
*/
const val FIELD_VERSION: String = "0.9.5"
const val FIELD_VERSION: String = "0.10.0"

/**
* Options for [FieldHandle.snapshot] (JS `FieldSnapshotOptions`). Composes with the runtime privacy
Expand Down
33 changes: 33 additions & 0 deletions docs/release-notes/0.10.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# 0.10.0

The reproducibility envelope ships, and cross-plane publishing is complete.

## Headline

- **`FieldHandle.guarantees`** — the runtime's reproducibility envelope is now a readable property:
determinism classification, controlled and **uncontrolled** inputs, repeatability requirements, and
the cross-plane numeric tolerance. Read it before building replay, shareable state, or
server-authoritative simulation. The answer is `conditionally-deterministic`; `host-geometry` and
`body-ordering` are not controlled; cross-plane agreement is a `1e-6` tolerance, never bit-equality.

- **One tag, three platforms.** `git tag v0.10.0` now publishes npm (`release.yml`), resolves Swift via
the SPM tag, and publishes Kotlin to GitHub Packages (`android.yml`) — at one version, from CI.

## Breaking (pre-1.0)

`FieldHandle` gains a **required** `guarantees` member.

- **Additive for consumers** — reading `field.guarantees` breaks no calling code.
- **Breaking for third-party `FieldHandle` implementers** — they must provide the member.
- **Migration:** return the runtime envelope, or delegate to a wrapped field. `FieldLayer`
(`@fundamental-engine/three`) and `FieldField` (`@fundamental-engine/vanilla`) both delegate and are
the reference pattern.

Per the pre-1.0 policy a break to a protected symbol is the `0.MINOR` position — hence `0.10.0`.

## Also

- New canonical doc `coupling-discipline.md` (the rung discipline; when *not* to use the field).
- Homepage and canonical docs rewritten for accuracy; the WebGL door and cross-plane parity surfaced.

Full detail: [CHANGELOG](../../CHANGELOG.md#0100--2026-07-21).
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fundamental-engine/core",
"version": "0.9.5",
"version": "0.10.0",
"description": "A reciprocal DOM-physics field — elements bend the field; the field's density bends them back.",
"type": "module",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
* with `packages/core/package.json` by `version.test.ts` (the build fails if they drift), so the
* release bump is the single source of truth.
*/
export const FIELD_VERSION = '0.9.5';
export const FIELD_VERSION = '0.10.0';
2 changes: 1 addition & 1 deletion packages/create/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fundamental-engine/create",
"version": "0.9.5",
"version": "0.10.0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bump starter template ranges with the 0.10 release

When publishing @fundamental-engine/create as 0.10.0, the bundled templates under packages/create/templates still depend on @fundamental-engine/{vanilla,react,elements} as ^0.9.2; for 0.x semver that range is <0.10.0. In the npm create @fundamental-engine@latest flow, a freshly scaffolded app will therefore install the previous 0.9.x runtime even though the CLI reports 0.10.0, missing new 0.10 surface such as field.guarantees; update those template ranges (or intentionally exact-pin 0.10.0) with the release bump.

Useful? React with 👍 / 👎.

"type": "module",
"description": "Scaffold a Fundamental starter — `npm create @fundamental-engine` — vanilla, React, or web-component, contained and signals-first by default.",
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion packages/dom/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fundamental-engine/dom",
"version": "0.9.5",
"version": "0.10.0",
"description": "The platform-adjacent layer for Fundamental — native-first registries for measurement, semantic state, feedback, relationships, visual-semantic bindings, and overlays. The browser primitives Fundamental wishes existed, built on the ones it has.",
"type": "module",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/elements/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fundamental-engine/elements",
"version": "0.9.5",
"version": "0.10.0",
"description": "Web-component keystone for Fundamental — the <field-root> custom element + declarative data-body bodies.",
"type": "module",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fundamental-engine/react",
"version": "0.9.5",
"version": "0.10.0",
"description": "React adapter for Fundamental — a reciprocal DOM-physics field as a <FieldField> component + useFieldField hook.",
"type": "module",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/three/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fundamental-engine/three",
"version": "0.9.5",
"version": "0.10.0",
"description": "Three.js authoring surface for Fundamental — run the reciprocal field engine headless and render its swarm as a THREE.Points layer (the particle bridge), plus threeHost() and threeBackend() (a RenderBackend) for binding the engine to a WebGL scene.",
"type": "module",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/vanilla/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fundamental-engine/vanilla",
"version": "0.9.5",
"version": "0.10.0",
"description": "Framework-free TypeScript wrapper for Fundamental — the reciprocal DOM-physics field as a typed FieldField class + mountField(), with no custom-element registration and no framework dependency.",
"type": "module",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion swift/Sources/FundamentalCore/Engine/FieldSnapshot.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import Foundation
/// mirroring the Kotlin port. Kept in lockstep with the package version (npm `latest`) and the JS
/// `FIELD_VERSION`: `VersionLockstepTests` fails the suite if this drifts from
/// `packages/core/package.json` (#923) — update it here on every release bump.
public let FIELD_VERSION: String = "0.9.5"
public let FIELD_VERSION: String = "0.10.0"

/// Options for ``FieldHandle/snapshot(_:)`` (JS `FieldSnapshotOptions`). Composes with the runtime privacy
/// ``FieldPolicy`` and an optional ``SnapshotProfile``, always resolving to the TIGHTEST (most private)
Expand Down
Loading