islaApocalypse-v2/Core
beezm 35b4818e9e Phase 2a: the faithful redistribution curve, re-measured against v2's own output
Ports the reference's v5 height curve and shelf-detail passes onto Phase 1's shape
and re-calibrates them against this repo's actual pass-1 distribution. This is the
BASELINE the reshape gets judged against, not the reshape.

Core (engine-free, D-060):
- WorldScale — THE vertical yardstick. One metres/raw number (251), replacing the
  prototype's three duplicate M_PER_UNIT constants and ~20 bare literals. The
  chunk-height coupling it had there is recorded as a DEFERRED vault decision, not
  inherited. RawFromMetres divides, matching the reference bit-for-bit.
- HeightCurve — the 7 bands, the frozen corner-fix blends, the per-seed spike
  normalization, the 24-corner monotonicity sweep that throws and refuses.
  Identity at and below sea, which everything downstream rests on.
- CurveKnots / CurveAnchors — input knots (measured percentiles) and output anchors
  (storm ladder) split apart and both made parameters, so the anchors are A/B-able
  without editing source. The reference's shipped knots are kept beside the measured
  ones as the fidelity yardstick.
- TerrainDetailPass — micro-relief skin plus the shelf-edge KNOT warp (which slides
  K3/K4/K5, not height — that is what keeps monotonicity structural). The crater
  exclusion is ported and inert until the carve lands.

Tools:
- Shaping — pass 2a, producing the two height fields. classify is bit-for-bit the
  raw pass-1 field; render is curved and detailed. Aliased when the curve is off,
  as the reference did. Pass1Result is left immutable so the oracle can compare.
- LandHistogram — the calibration engine AND the diagnostic. The reference shipped
  six knot literals and threw the measuring instrument away; this rebuilds it.
- ShapingOracle + CurveBaselineTool — four automatic checks before anything is
  looked at, and the batch that runs them.

Measured, not assumed:
- Knots re-measured over a 6-seed / 12.8M-sample pool. They differ from the
  reference's by at most 5.6 m of world height, against a 44.7 m per-seed spread —
  the pass-1 port is faithful.
- Oracle all pass, including pass 1 bit-identical to Phase 1's own .f32 dump.
- Band shares land on 60/13/10/5/8/3/1 to 0.00 pp.
- Knots hold across map size: the 8K delta (5.8 m) sits inside seed noise.

The finding the histograms deliver: 83% of land ends below 100 m and 96% below
220 m, with the median column at 13 m. That is the share targets doing exactly what
they say, not a bug — and it is the developer's call, which is why nothing here
reshapes it and the palette was deliberately left mis-fitted rather than recalibrated
to disguise it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCWNaDZPfTiAy3meGNGgqt
2026-08-20 01:38:10 -04:00
..
Scripts Phase 2a: the faithful redistribution curve, re-measured against v2's own output 2026-08-20 01:38:10 -04:00
README.md Phase 2a: the faithful redistribution curve, re-measured against v2's own output 2026-08-20 01:38:10 -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, the two frequency conventions.
Scripts/WorldScale.cs The vertical yardstick. The ONE metres↔raw conversion (251 m/unit). No literal 251f anywhere else.
Scripts/HeightCurve.cs The height-redistribution curve (v5), 7 bands. Identity at and below sea.
Scripts/CurveKnots.cs The six INPUT knots — percentiles of the measured land CDF, plus the reference's for comparison.
Scripts/CurveAnchors.cs The OUTPUT anchors — the storm-ladder elevations each band lands at.
Scripts/TerrainDetailPass.cs Shelf micro-relief + the shelf-edge knot warp. Output-height only.
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.
  4. There is one metres-per-raw-unit number. The prototype scattered 251 across three duplicate constants and ~20 literals, and the generator never used the derived one at all. → Scripts/WorldScale.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 beyond the height curve. Phase 2 added HeightCurve and TerrainDetailPass here because they are pure, engine-free, C++-candidate math that defines the world's elevation profile — a contract, not a tool's dial. Stratigraphy, feature passes, meshing and run-splitting on dig are still later phases.
  • No erosion, rivers, water bodies, crater carve, coast shelf or offshore islets. Later chat2 tasks; the curve is deliberately the only pass-2 element present.

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