islaApocalypse-v2/Core
beezm fdf52f61ee Phase 1 review: raw grayscale, the wide gradient as hero, fixed batch naming
Presentation only. No generation file is touched — Topography, TerrainNoise,
IslandFalloff, Pass1Result, TerrainGenConfig and GenerationScale are all unchanged.

Batch naming, fixed in code. The prefix is the AUTHORING TASK number, not a running
counter: 04_review means "the batch task 04 authored", not "the fifth batch". It had
already drifted — tasks 02 and 03 produced 00_smoke through 05_trophy_10240 across
two tasks, so no folder name said which task made what. Now the task number is an
explicit argument to ToolingPaths.BatchRoot(taskNumber, descriptor), which composes
the prefix itself and REFUSES a descriptor that carries its own. All three tools
take it as ISLA_TASK. Verified: ISLA_BATCH=05_foo is refused with a stated reason
and exit 2, and creates no folder.

Also fixed: an exception out of _Ready does not stop Godot — it logs and the process
sits there with no main loop, so a misconfigured run HUNG rather than failing. A
hang looks like slow work, which is worse than a crash. The batch tools now catch,
print what was refused, and exit non-zero.

Grayscale mode: normalize a field to its own [min,max]. This is the one place
per-image normalization is correct — everywhere else anchors are fixed so images
compare, but here the point is to see one field at full contrast. The range is
printed and indexed so a shade reads back to a height. You cannot judge noise
through a palette: a ramp bends the distribution, a hillshade adds shape the data
does not have.

The wide Costa-Rica palette, and the reframing the developer asked for: the pretty
map is the WIDE GRADIENT RENDERED FLAT, and relief is no longer the hero. On raw
pass-1 noise a hillshade has nothing coherent to shade, so it renders fine fractal
bumpiness as fuzz that actively hides the elevation the colour is showing. Strong
hillshade is retained as diagnostic_relief and labelled a dev view — its bumpiness
is exaggerated slope, not extra terrain. Subtle relief is kept for comparison, with
the honest note that it still fuzzes until Phase 2 carves coherent landforms.

Legend: a colour bar with ticks drawn from the palette's own ramp, so it cannot
drift from the map beside it. Ticks are RELATIVE height and the image says NOT
METRES — the conversion is Phase 2's, and labelling it "m" would invent a fact in
the artefact a reader most trusts. Text comes from a 5x7 bitmap font written for
this, specifically so a legend does not drag in the SubViewport capture path.
2026-08-19 22:55:53 -04:00
..
Scripts Phase 1 review: raw grayscale, the wide gradient as hero, fixed batch naming 2026-08-19 22:55:53 -04:00
README.md Phase 0: clean project skeleton for the v2 rewrite 2026-08-19 20:21:12 -04:00

Core — math and data only

Holds: the column model, the material schemas, the scaling discipline, tooling path resolution and the file-safety rails. Constants and contracts.

Boundary: Core depends on nothing above it. Not on Server/, not on Client/, not on Tools/. The dependency arrow points one way into this folder and never out of it.

⚠ Additional boundary, tighter than the layer rule: Core is engine-free.

No using Godot; anywhere in this folder. Core is plain C# — no Node, no GD.Print, no ProjectSettings, no engine types in any signature.

Two reasons, both load-bearing. (1) D-049 commits to "C# for fast iteration, with C++-ready seams… port path-by-path when settled and hot" — the hot paths that get ported first are exactly the ones in here, and a type that names Godot.Vector2 cannot cross that seam. (2) It keeps the column model testable and reviewable without standing up an engine.

Where Core genuinely needs something the engine knows — the resolved user:// directory — the engine layer hands it in (ToolingPaths.Configure), rather than Core reaching for it. If you find yourself wanting an engine type here, the type belongs one layer up.

What is in here

File What it is
Scripts/Column.cs ★★ The load-bearing contract (D-053). A column as run-length bands; MaterialRun; RunOrigin. Read its header before touching anything that stores world data.
Scripts/ColumnGrid.cs The 2D grid of columns. Shape only — chunking and streaming are later phases.
Scripts/MaterialKey.cs Material identity — a registry key, never an ordinal.
Scripts/TerrainMaterial.cs A row in the terrain schema (D-054).
Scripts/BuildingMaterial.cs A row in the building schema (D-054).
Scripts/MaterialRegistry.cs Both registries, append-only, seed rows only.
Scripts/RecipeRegistry.cs The transformation seam — deliberately empty.
Scripts/GenerationScale.cs The scaling discipline. MapSize, ScaleFactor, normalized offsets.
Scripts/ToolingPaths.cs Every tooling path, env-overridable, resolved in one place.
Scripts/FileSafety.cs The permanent file-safety rules, as throws rather than sentences.

The three rules this layer exists to make unbreakable

  1. Air is the top run. There is no "air vs solid" height branch, anywhere, ever. → Scripts/Column.cs.
  2. Properties come from the registry, never from storage. A run stores an identity. → Scripts/MaterialRegistry.cs.
  3. Nothing uses a raw pixel number. Every distance is a fraction of MapSize. → Scripts/GenerationScale.cs.

Not here, and not by accident

  • No water. Water is an overlay over the columns (levels-not-cells), never a band.
  • No biomes. Biomes are a later classification of finished shape, not an input to it (D-049).
  • No algorithms. Phase 0 is shape. Stratigraphy, feature passes, meshing and run-splitting on dig are later phases.

Design - Data - Column Model.md, Design - Data - Material Schema.md, Design - Tooling - Scaling Discipline.md