The bare TerrainGenConfig defaults did NOT reproduce the terrain the developer
locked, so "run the default generator" was not "the terrain in the gallery" —
the single most expensive fact in the codebase, and the reason a fresh chat
would spend an afternoon chasing differences that were CONFIGURATION, not
regression. This is the deliberate task that ends that, before any river work.
A1 — the defaults ARE the locked shape now. Five fields actually move:
SpeckRevert false->true, MinLandComponentFrac 3e-5->2.5e-7 (120x smaller; the
config default would have eaten real islands, not specks), SouthStretch 0->2,
FragmentAmp 0->0.5, Erosion false->true. Seven more were already correct via
SouthernStretch.Default* / CoastalFragment.Default* and are now pinned as
literals, because TerrainShapeV1 used to do that pinning and this default set
inherits the job. CoastShelf stays OFF — the locked shape has no shelf, and
evaluating it (D-041) is its own later task once water renders. Offshore stays
Off permanently (D-063): islands are organic-only, made by the stretch +
fragmentation and identified by the region layer, never placed.
A2 — the preserve mechanism. The curve knots are percentiles of the FAMILY-OFF
land distribution; flipping the defaults would have moved the pool, the knots,
and with them the render field of every batch including terrain-shape-v1
itself. So the pool is pinned family-off (TerrainGenConfig.WithFamilyOff /
CalibrationPool) rather than the knots being baked: calibration stays live, its
INPUT distribution is held still. The pin was a no-op by construction — it sets
the values the defaults carried the instant before the flip — and re-measuring
after confirms it: pool, all six knots, per-seed spread, shaped max,
monotonicity spikeMax and all seven band shares identical.
Applied wider than "in CalibrateCurve": OffshoreIslandsTool,
RegionLabelingTool and SouthernStretchTool generate their own family-off
field for the Phase-1 anchor, so the pool pin alone would NOT have covered
them and their a1 would have failed for a configuration reason. TerrainGenTool
too — it AUTHORED 02_pass1_port and must stay able to regenerate its own
anchor.
Recorded as a judged-and-parked property: knots measured family-off, applied
family-on. Deliberate, not an oversight. Same disposition as the mid-slope
feather.
A4 — no oracle may pass against a superseded baseline. Six anchors retired
(01/03/04/06/08/09) with their checks and ISLA_T0x_SOURCE defaults; three kept
(chat1/02_pass1_port as the family-off pass-1 guard, chat2/10 and chat2/11 as
the shape and erosion acceptance anchors). Two invariants were RE-POINTED
rather than lost — the southern stretch's north-lock and the coastal-fragment
interior-lock now compare against SAME-RUN fields, which is scale-free and
cannot be invalidated by a moved dump. The retired dumps are kept, not deleted,
and marked superseded in their INDEX.md.
A missing anchor is now LOUD. The old pattern skipped silently, so a moved
anchor did not make its oracle fail — it made it not RUN, and a batch with a
skipped check prints an all-PASS table that reads like a clean one. That is
the INVERSE of the hazard the re-baseline guards against, and the migration
below is exactly the event that would have triggered it, on nine anchors at
once. ShapingOracle.LoadAnchor now separates the two cases: absent -> throw;
present at another size -> loud INCONCLUSIVE, which is a fail, never a pass.
TerrainShapeV1 inverted from PRESET to GUARD and moved to its own file.
Apply() is gone — stamping the values on top of the defaults would MASK a
drift instead of catching it. Its constants are now the assertion target, and
Assert() refuses a run whose defaults have drifted off the locked shape.
B/C — batches are namespaced by chat: batches/<chat>/NN_slug/. Task numbers
restart at 00 per chat, so a flat root collided the moment a second chat
existed — four colliding prefixes across 25 batches, separable only by slug.
ToolingPaths.ChatSlug is REQUIRED (throws if unset) and defaults per tool to
its authoring chat, so re-running reproduces a batch in place while ISLA_CHAT
redirects — which is also what stops an acceptance run from overwriting the
very anchor it checks against. Writes go through BatchRoot; historical READS
compose against BatchesRoot and so carry the prefix in their own source string
("chat1/02_pass1_port"). The 25 existing batches were migrated moves-only.
ACCEPTANCE — 16 of 16 byte-identical, 0 failed. All 8 gallery seeds at 8192
from the bare defaults are byte-identical to chat2/10_frag4_seed_gallery
(= terrain-shape-v1,
|
||
|---|---|---|
| .. | ||
| Scripts | ||
| README.md | ||
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# — noNode, noGD.Print, noProjectSettings, 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.Vector2cannot 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/HydraulicErosion.cs |
⭐⭐ Droplet (hydraulic) erosion (chat2/11) — the reference's pass ported VERBATIM: four governors (count, lifetime, carve cap, deposit cap) on a net-displacement ledger proven on exit, the sea clamp (below-sea read-only both ways), the cone brush shared by erode and deposit, the crater exclusion (inert until the carve exists). Engine-free, own PCG32, WorldScale-denominated (no literal 251). Render-map only — the caller (Tools/ErosionPass) owns the split and the flood guard. |
Scripts/DrainageAnalysis.cs |
⭐⭐ Drainage analysis (chat2/12) — the reference's river-PLAN pass ported verbatim: priority-flood routing fill (one ulp above the parent, terrain never written), D8 flow directions FOR ANALYSIS ONLY (D8 was reverted as a carving technique), Kahn accumulation, outlets ranked by drainage area, endorheic terminals credited TOTAL inflow, promoted giants. Engine-free, WorldScale-denominated. "The sea" = the ocean body from RegionLabeling.OceanMask. |
Scripts/RegionLabeling.cs |
⭐⭐ The region-labeling layer (chat2/07) — shared infrastructure. 8-connected land components on the CLASSIFY field; mainland = the centre component; per component id / size / centroid / hemisphere (by centroid) / isMainland. Pure, engine-free, C++-candidate; a contract downstream phases consume (islands first; biomes, placement, rivers, the crater later). The hemisphere convention lives here. |
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
- Air is the top run. There is no "air vs solid" height branch, anywhere, ever.
→
Scripts/Column.cs. - Properties come from the registry, never from storage. A run stores an identity.
→
Scripts/MaterialRegistry.cs. - Nothing uses a raw pixel number. Every distance is a fraction of
MapSize. →Scripts/GenerationScale.cs. - There is one metres-per-raw-unit number. The prototype scattered
251across 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 and the region layer. Phase 2 added
HeightCurveandTerrainDetailPasshere because they are pure, engine-free, C++-candidate math that defines the world's elevation profile — a contract, not a tool's dial. chat2/07 addedRegionLabelingon the same grounds: region identity is a contract every later phase reads, and the flood fill is a hot path. (The speck REVERT that uses it is a pass, and lives inTools/—RegionPass.) 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