relief_q now reaches the renderer, and the first pass spent it on brightness:
lighten where the ground is high, darken where it is low. That moved the numbers
(District 13.72 -> 77.01 lum spread) and still looked like moss, because the eye
does not read landform from absolute brightness. It reads it from light falling
ACROSS a gradient — height-shading gives a rise and a fall the same tone, so no
ridge ever reads as a ridge.
So relief drives a proper hillshade: the local gradient of the field dotted with
a light from the upper-left. The light direction is not a free choice; lit from
the lower-right the brain inverts the read and valleys pop out as ridges.
THE SCALE IS MEASURED PER CANVAS, not fixed, and the first attempt at this failed
exactly the way this file already warned a fixed gradient constant would (see
RUGGEDNESS_BASELINE_CELLS: "the same 4-cell delta reads 21.86 at Region and 0.08
at District"). With a constant full-scale of 8:
Region 81.72 but District 77.01 -> 20.01, Quarter 42.56 -> 16.44
because at District's 3.8 m per cell neighbouring cells barely differ. The
terrain layer now measures each canvas's own mean |gradient| once per rebuild and
the hillshade normalizes against it, so one constant works at every rung.
Ladder (tooling/atlas-flatness, lum p1-p99), flat -> shipped:
Global 145.69 -> 145.69 unchanged; relief_q is flat 50 at orbital
Region 33.59 -> 54.30
District 13.72 -> 74.43
Quarter 11.01 -> 73.72
District and Quarter now read as terrain — ridgelines, valleys, and the stipple
organised into contour-like bands. Judged by eye on the captures, not by the
metric alone.
Stipple full-scale 25 -> 60. The old value was calibrated against a relief_q that
never arrived, so it was tuned to the elev_q fallback; with the real plane nearly
every land cell earned a mark and Region read as static (17,599 distinct colours,
more than twice Global's, for a quarter of the legibility). Form comes from the
hillshade now; the stipple is grain on top of it.
REGION IS NOT FIXED, and the cause is T-1240 rather than this change. It renders
as fine uniform stucco: a Region cell is 379 m of ground while the relief field's
content sits in the 128-1024 m band, so the field is at or below Nyquist and the
gradient the hillshade reads is aliasing, not slope. min_wl_m defaults to 0 on
the served path, so nothing truncates the octaves Region cannot resolve — which
is precisely what T-1240 proposes to fix. That ticket said the stale cutoff was
"currently inert"; it is now the thing capping Region, and T-1240 is updated
with the measurement.
Three tests, on direction rather than magnitude so tuning does not rewrite them:
a hill's west flank lit and east flank shadowed, a uniform field shading nothing,
and the canvas edge not drawing a rim. That last one is a bug this nearly
shipped: `_l8_value` returns 0 out of bounds and 0 on relief_q means MAXIMUM
HOLLOW, so sampling off-canvas posts a full-scale false gradient all the way
round the frame. The sample position is clamped instead.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
105 lines
6.1 KiB
YAML
105 lines
6.1 KiB
YAML
name: The Settled Reach
|
|
# Version scheme: 0.{phase}.{n} — phase = active Development Cascade phase (D-166).
|
|
# Phase 4 (deterministic world generation) is active.
|
|
# 0.4.1-tagged step canvases carried lake_margin_q's flat absolute-ceiling
|
|
# semantics (pre-per-basin-normalization) and were written to real disk
|
|
# caches during T-1188 eyeball runs — 0.4.2 forces those entries to miss.
|
|
# 0.4.2-tagged Global/Region-rung step canvases sampled the coastline
|
|
# position raw (no coast_warp_px) — T-1160 applies the warp at orbital
|
|
# sampling, changing orbital-rung canvas bytes (elev_q/temperature_dc/
|
|
# moisture_q shift near coasts) — 0.4.3 forces those cached entries to miss.
|
|
# 0.4.3-tagged canvases predate the D-255 extent inversion (a rung now fixes
|
|
# the canvas EXTENT and the gridunit spacing falls out, rather than the
|
|
# reverse). District/Quarter/Block/Chunk kept the same 960x540 cell counts
|
|
# through that change, so their cache keys are byte-identical while a District
|
|
# canvas now covers 3.6 km of ground instead of 1,966 km — a warm cache would
|
|
# silently serve pre-inversion canvases. 0.4.4 forces those entries to miss.
|
|
# 0.4.4-tagged GLOBAL canvases are all 2x1 — `serve_step_canvas_request` was
|
|
# still zeroing Global's wire extent (a pre-extent-inversion sentinel), so
|
|
# every Global request resolved to a two-cell canvas regardless of viewport.
|
|
# Those entries were also cached under a key that ignored extent, so they
|
|
# answered every later request forever. 0.4.5 forces them to miss.
|
|
# 0.4.5-tagged canvases carry pre-T-1237 river courses: one course per D8 HOP
|
|
# rather than one per river (build_paths walks whole headwater->mouth rivers
|
|
# now). The hop-shaped entries survived that fix because it changed only server
|
|
# and client code, never this version — so Ferrath Global replayed 375 fragments
|
|
# with a 106 km longest run, all of them below D-261's read-as-a-line floor, and
|
|
# drew NOTHING, while a cold cache on the same build produced 73 whole rivers
|
|
# with a 1,644 km trunk and drew 18. Diagnosed as T-1239. 0.4.6 forces them to
|
|
# miss.
|
|
#
|
|
# THE PATTERN, now four bumps deep: a change to how a canvas is GENERATED is
|
|
# only half the change — the other half is this line. Nothing enforces the
|
|
# pairing, so a canvas-generation commit that leaves this version alone ships a
|
|
# silent regression that reproduces only on machines with a warm cache. The
|
|
# capture harness no longer hides it (tests/run-visual isolates user:// per run,
|
|
# T-1239), but a real player's cache is still governed by this number alone.
|
|
# 0.4.7 carries NO canvas-generation change — it is the gate that enforces the
|
|
# pairing described above, arriving (T-1242). tooling/canvas_sources.py lists the
|
|
# paths, tooling/check-canvas-version rejects a push that touches them without
|
|
# moving this line, and the registry includes ITSELF so that narrowing it and
|
|
# changing a canvas file in one push still demands a bump. That self-inclusion is
|
|
# why this bump exists: adding the registry trips its own rule. The version is
|
|
# spent rather than special-cased, because "this change is obviously harmless" is
|
|
# the reasoning that produced all five regressions above.
|
|
# 0.4.8 also carries NO canvas-generation change: a test-only edit to
|
|
# composition.rs (its conservation assertion was a tautology) tripped the T-1242
|
|
# gate, because that gate is path-based and cannot tell test code from generator
|
|
# code. Second no-op bump in two days — the false-positive rate is real, and is
|
|
# the price of the ruling that a false negative costs a week. Revisit if it
|
|
# becomes noise; do NOT add an override to dodge it.
|
|
# 0.4.9 is a REQUIRED bump, not a gate formality (T-1213). The disk cache stores
|
|
# the DECODED canvas, and the decode was silently dropping the `relief_q` plane —
|
|
# so every 0.4.8-and-earlier entry physically lacks the field, and would keep
|
|
# rendering the deep rungs as a flat wash even against a build that reads it.
|
|
# This is the first bump in the series where a warm cache is wrong about CONTENT
|
|
# rather than merely stale.
|
|
# 0.4.10 changes how a canvas is PAINTED, not how it is derived, so cached
|
|
# entries are still valid content — but the client step_canvas cluster is in the
|
|
# T-1242 registry and the rule is bump-when-touched, so it moves. Cheap: one
|
|
# round of misses against a map that now reads as terrain.
|
|
version: 0.4.10
|
|
repository: settled-reach
|
|
|
|
|
|
description: >
|
|
Top-down life-sim set in an original science fiction universe. Asymmetric
|
|
information and occlusion-based perception from a single-character
|
|
perspective, with a Rimworld-style storyteller. Systems interactions like
|
|
The Sims, combat and visuals like single-character Rimworld, world
|
|
generation inheriting from Dwarf Fortress and NMS, economy inspired by
|
|
X4/EVE. Every system is interactable but ignorable — the world is alive
|
|
for any given run.
|
|
|
|
setting: >
|
|
The Settled Reach — a network of star systems connected by Founder Gates.
|
|
Neural lattice technology enables soft immortality, forking, and
|
|
re-embodiment.
|
|
|
|
development: >
|
|
Built outside-in along the six-phase Development Cascade (D-166): wiki
|
|
content and star map, economics layer, planetary maps and atlas,
|
|
deterministic world generation (active), player control and in-world
|
|
rendering, room-level detail.
|
|
|
|
architecture:
|
|
client: Godot 4 (GDScript)
|
|
server: Rust with bevy_ecs (simulation server)
|
|
transport: subprocess/IPC via TCP with MessagePack serialization
|
|
protocol: length-prefixed MessagePack frames (4-byte big-endian)
|
|
determinism: ChaCha20 seeded RNG, deterministic tick processing
|
|
|
|
simulation:
|
|
tick_rate: 10 ticks per game-minute
|
|
time_model: 4 day phases (Morning, Afternoon, Evening, Night)
|
|
grid: dual-scale (0.5m simulation tiles, 1m visual tiles)
|
|
visibility: symmetric shadowcasting + forward/peripheral/blind vision cone
|
|
knowledge: per-entity knowledge graphs with confidence decay
|
|
|
|
content:
|
|
format: YAML with JSON Schema validation
|
|
structure: campaigns/systems/stations/districts hierarchy
|
|
npcs: 10-axis model (7 essential + 3 supporting) with CombatCapability
|
|
dialogue: tagged line pools with 4-layer relational filtering
|
|
population: 30% flat / 50% mundane triangles / 20% intrigue-entangled
|