docs(decisions): address PR #129 review — D-191 §8 amendment + boundary notes
Blocking PR #129 items 1, 2 (plus polish 16 and 17): - D-191 §8 prose rewritten to match the code. The previous amendment said positions were `{x, y}` objects against a "typically 1024 × 512" grid, but the generator, the six hand-authored templates, and all 2394 procedural seed files ship `[row, col]` integer arrays against a `{"w": 512, "h": 256}` grid. The decision doc is now aligned with reality: positions are `[row, col]`, the storage grid is 512 × 256, and the row-first ordering is called out explicitly so readers can cross-reference NumPy/flood-fill/A*/cost-grid conventions. - §8 now follows the D-094 amendment pattern. The superseded 2026-04-10 prose is preserved verbatim as "Original (superseded)" with a dated Amendment block on top — future readers can see what changed and why instead of silently losing the history. - brands.toml header gains a short Phase 2 boundary note. The 4 anchor brands come from D-189 §5; the additional ~23 brands from D-189 §11 are deliberately deferred to Phase 3 — Phase 2 only needs the demand- node plumbing and V-B01..V-B06 validation exercised end-to-end. - systems-schema.sql `bodies.terrain_reference` comment now pins the repo-root-relative path convention (wiki/star-systems/<slug>/bodies/ <body_id>/heightmap.png) so the three downstream pipelines (populate, atlas generator, client loader) share a documented contract instead of drifting against an unwritten convention.
This commit is contained in:
@@ -710,9 +710,21 @@ Technical foundation decisions that constrain implementation: engine, client-ser
|
||||
- Maps to D-181 signal visibility ladder
|
||||
|
||||
**8. Settlement Data Model**
|
||||
- markers.json is stored in heightmap pixel space — every marker file declares a `grid: { w, h }` header (the heightmap dimensions, typically `1024 × 512`) and every position is `{ x, y }` integer pixels into that grid. This is the canonical storage format used by both the generator and the hand-authored template files (Edict, Vuurkloof, Røros, Cairnside, Estrade). Pixel space is what the heightmap analysis (flood-fill, A* cost grid, city placement) natively operates on; it is deterministic and avoids double-conversion through a projection.
|
||||
- markers.json schema per body: `grid: {w, h}`, `cities` (name, pos `{x,y}`, population_tier, primary_function, gate_terminal, continent_id), `roads` (path polylines as `[{x,y}, ...]`, connects), `railroads` (path polylines, connects), `pois` (name, kind, pos), plus existing rivers/oceans/mountains with names filled
|
||||
- Lat/lon strings are a **display-time derivation**, not a storage format. The atlas UI converts `{x, y}` + `grid: {w, h}` into an equirectangular `lat°N/S, lon°E/W` string for the city data panel and hover tooltips, using the body's radius for any great-circle distances it needs. This keeps the immersive surface without paying conversion cost in the generator, the DB, or the diff churn on hand-authored files.
|
||||
- **Amendment (2026-04-15):** The original §8 (below) described marker positions as lat/lon objects and city records keyed by `population_tier`/`primary_function`/`gate_terminal`/`continent_id`. That shape was aspirational — neither the generator nor the hand-authored templates ever emitted it. Both ended up writing pixel-space row/col arrays against a `512 × 256` storage grid, and PR #129 canonizes that shape so the code and the decision stop drifting. The original prose is preserved immediately below; the current shape follows.
|
||||
- **Original (2026-04-10, superseded):** markers.json schema per body: `cities` (name, lat/lon, population_tier, primary_function, gate_terminal, continent_id), `roads` (path polylines, connects), `railroads` (path polylines, connects), `pois` (name, kind, position), plus existing rivers/oceans/mountains with names filled. Population tier → city count: `floor(log10(pop/1M))`, modified by `settlement_pattern`. Gate terminal POI at largest population center, sometimes scattered to a smaller one. Moons: same depth as planets, scale with population.
|
||||
- **Current canonical format:** markers.json is stored in heightmap pixel space. Every marker file declares a `grid: { w, h }` header — the generator, the 6 hand-authored templates (Lendel, Edict, Vuurkloof, Røros, Cairnside, Estrade), and all 2394 procedural seed files ship `{"w": 512, "h": 256}`. Every position is a two-element **array** `[row, col]` of integer pixels into that grid, where `row ∈ [0, h)` and `col ∈ [0, w)` (row is the first axis to match NumPy convention and the flood-fill / A* / cost-grid code that `tooling/planet-gen/` already runs in). Polyline geometry (`roads[*].path`, `railroads[*].path`, `rivers[*].path`) is `[[row, col], [row, col], ...]`.
|
||||
- **markers.json top-level schema:**
|
||||
- `grid`: `{"w": 512, "h": 256}`
|
||||
- `cities[]`: `{id, name, kind, center: [row, col], population}` — `kind` is `capital` or `city`; `name` is empty when awaiting gemma_naming.py (#833).
|
||||
- `roads[]`: `{id, name, kind, path: [[row, col], …]}` — `kind` is `commercial` by default for generated roads; hand-authored roads use `highway`, `rural`, etc.
|
||||
- `railroads[]`: same shape as `roads[]`; generated default `kind` is `passenger_freight`.
|
||||
- `pois[]`: `{id, name, kind, center: [row, col]}` — generated POIs are `kind: "transit"`; hand-authored POIs use `institutional`, `cultural`, `corporate`, etc.
|
||||
- `rivers[]`: `{id, name, path: [[row, col], …]}`
|
||||
- `oceans[]`: `{id, name, kind, center: [row, col], area_fraction}` where `kind` is `lake` | `sea` | `ocean`.
|
||||
- `mountain_ranges[]`: `{id, name, center: [row, col], peak: [row, col], area_cells}`
|
||||
- Pixel space is what the heightmap analysis (flood-fill, A* cost grid, city placement) natively operates on; it is deterministic and avoids double-conversion through a projection.
|
||||
- Lat/lon strings are a **display-time derivation**, not a storage format. The atlas UI converts `[row, col]` + `grid: {w, h}` into an equirectangular `lat°N/S, lon°E/W` string for the city data panel and hover tooltips, using the body's radius for any great-circle distances it needs. This keeps the immersive surface without paying conversion cost in the generator, the DB, or the diff churn on hand-authored files.
|
||||
- Atlas DB index (`atlas_cities`, `atlas_roads`, `atlas_railroads`, `atlas_pois`, `atlas_rivers`, `atlas_oceans`, `atlas_mountain_ranges`, `atlas_body_grids`) mirrors these scalar fields row-by-row for implant-app and development queries; polyline geometry stays in the JSON files next to the heightmaps.
|
||||
- Population tier → city count: `floor(log10(pop/1M))`, modified by `settlement_pattern`
|
||||
- Gate terminal POI: at largest population center, sometimes scattered to a smaller one
|
||||
- Moons: same depth as planets, scale with population
|
||||
@@ -739,4 +751,4 @@ Technical foundation decisions that constrain implementation: engine, client-ser
|
||||
|
||||
---
|
||||
|
||||
*53 decisions. Last updated: 2026-04-14 (D-191 §8 — markers.json canonical format is pixel space `{x, y}` with a `grid: {w, h}` header; lat/lon is a display-time derivation)*
|
||||
*53 decisions. Last updated: 2026-04-15 (D-191 §8 amendment — markers.json canonical format is pixel space `[row, col]` arrays against a `512 × 256` grid, following the D-094 amendment pattern; lat/lon is a display-time derivation)*
|
||||
|
||||
Reference in New Issue
Block a user