From 45c3351d7d0e27fa07192cf726e91e864875b9ad Mon Sep 17 00:00:00 2001 From: Serkyo Date: Tue, 7 Jul 2026 20:06:09 +0200 Subject: [PATCH] docs(workspace): add adr for split-coordinate entity positions --- docs/README.md | 1 + .../0008-split-coordinate-entity-positions.md | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 docs/adr/0008-split-coordinate-entity-positions.md diff --git a/docs/README.md b/docs/README.md index a1d608c..03f9ace 100644 --- a/docs/README.md +++ b/docs/README.md @@ -37,6 +37,7 @@ Each subsystem note should name the design topic it implements (by title, e.g. " - [`adr/0005-namespaced-content-ids.md`](adr/0005-namespaced-content-ids.md): namespaced content IDs. - [`adr/0006-base-game-on-modding-api.md`](adr/0006-base-game-on-modding-api.md): base game built on the modding API. - [`adr/0007-declarative-content-via-modding-api.md`](adr/0007-declarative-content-via-modding-api.md): declarative content loads through the modding API. + - [`adr/0008-split-coordinate-entity-positions.md`](adr/0008-split-coordinate-entity-positions.md): split-coordinate entity positions. - [`adr/template.md`](adr/template.md): template for new decisions. Subsystem notes: diff --git a/docs/adr/0008-split-coordinate-entity-positions.md b/docs/adr/0008-split-coordinate-entity-positions.md new file mode 100644 index 0000000..4d21a44 --- /dev/null +++ b/docs/adr/0008-split-coordinate-entity-positions.md @@ -0,0 +1,26 @@ +# 0008. Split-coordinate entity positions + +- **Status:** Accepted +- **Date:** 2026-07-07 + +## Context + +In a procedurally generated voxel world, an entity's position cannot be robustly represented by a single global single-precision floating-point vector (`f32` or `Vec3`). At large distances from the origin, the spacing between representable floating-point numbers increases, leading to spatial jitter, physics instability, and rendering artifacts. + +While double-precision floats (`f64`) postpone this issue, they double the data size and are not uniformly or natively supported on GPUs, which expect `f32` vertices and transforms. The engine requires a spatial representation that maintains sub-millimeter precision universally across a theoretically unbounded world, without coupling the simulation state directly to GPU limitations or paying the cost of `f64` everywhere. + +## Decision + +The engine uses a split-coordinate representation for entity positions, encapsulated by the `EntityPos` type. An entity's absolute position is defined by two discrete components: + +1. A `chunk` anchor (`ChunkPos`): The integer coordinates of the chunk containing the entity. +2. A `local` offset (`Vec3`): A single-precision floating-point vector describing the entity's exact position relative to the chunk's minimum corner. + +When an entity moves, the movement is applied to the `local` offset. A normalization step (`EntityPos::renormalize`) then carries any overflow beyond the chunk boundaries into the integer `chunk` anchor, ensuring the `local` offset always remains strictly within the bounding box of a single chunk (`[0.0, CHUNK_SIZE)`). + +## Consequences + +- **Uniform Precision:** Entities maintain exact `f32` precision regardless of how far they travel from the world origin, as the active floating-point magnitude is strictly bounded by the size of a single chunk. +- **Rendering Stability:** The renderer can compute relative matrices by defining the camera's current chunk as the origin. This allows the GPU to process all vertex data and transforms in standard `f32` without any spatial jitter. +- **Math Complexity:** Code manipulating spatial positions (like physics integration and distance checks) becomes more complex. It is no longer possible to simply subtract two global vectors; logic must handle both the chunk offset and the local offset simultaneously. +- **Serialization:** `EntityPos` serializes as a compound struct, ensuring save files do not lose coordinate precision for distant entities.