islaApocalypse-v2/Tools/Scripts/CoastalFragment.cs
beezm bddd3636dd chat2/09: coastal fragmentation — a perimeter-wide, band-limited noise, amplitude laddered at a fixed stretch
A dedicated term, not the edge noise scaled: pass 1's edge noise is positive-only, squircle-
modulated, 2.5x the base frequency - the coastline's jitter; scaling it would roughen the whole
rim and bias the coast inward. CoastalFragment adds, to the PRE-power falloff, amp * window(f) *
noise(x + off, y + off) with its own deterministic field (seed offset 9109, coordinate offset
0.37 map widths - D-059), zero-mean, at 12 periods per map width (the lobe/neck scale, chosen by
probe against 20 and 32: 20 climbs into smalls, 32 is fuzz), weighted by a smooth window on the
falloff value itself, centred 0.66 (the coast's falloff for a median base noise, from the 08
diagnosis), half-width 0.18, EXACTLY ZERO beyond - so the interior, the massif and the deep sea
are bit-identical by construction. Thin necks of barely-land flip first; nothing is detected,
nothing is stamped. FragmentBitesOnly is exposed (probed: it erodes the coast inward - mainland
-3/-8/-14 % at 0.06/0.15/0.30 - rather than detaching pieces; off by default).

Batch: BatchRoot(9, "coastal_fragment") - 4 amplitudes (0.06, 0.15, 0.30, 0.50) x task 08's two
seeds at 4096, stretch fixed at 2 (08's stretch_3 rung, whose dump is the bit-identical baseline,
a8), sinker untouched, speck revert at < 4 cells, offshore/shelf off; lean render (regions overlay
+ relief + .f32), the hemisphere-split count/size table with largest-three and histograms.

Oracle, all passing: a1 (the curve untouched), a8 x2 (frag OFF at stretch 2 == the 08 field,
16.8 M cells each), interior locked (r: every cell clear of the window bit-identical, 8/8),
high-ground report (s, informational), centre is land, tag/coastline, classify == raw, ids and
heights deterministic.

The read: both hemispheres fragment; the north more readily (N 10 -> 28, 13 -> 40 islands across
the ladder; S 4 -> 31, 14 -> 28) and the south's big stretch pieces are the zero-mean noise's
other edge: on 999999937 the 83k-cell southern fragment is BRIDGED back onto the mainland at amp
0.50 (mainland +183k). The working range is amp 0.15-0.30; 0.50 is the bookend. Graduation held.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EY3ZTF6NwzF8ukBHQXSK7
2026-08-22 07:09:27 -04:00

60 lines
3.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
namespace IslaApocalypse.Tools
{
/// <summary>
/// ⭐ COASTAL FRAGMENTATION (chat2/09, EXPLORATION) — a perimeter-wide, band-limited, zero-mean noise
/// on the PRE-power falloff, applied only inside the coastal window.
///
/// ═══ WHY A DEDICATED TERM AND NOT THE EDGE NOISE SCALED ═══
///
/// Pass 1's edge noise is <c>(noise+1)/2 · 0.15 · squircle</c>: positive-only (it only ever PUSHES
/// the falloff up), modulated by the squircle (strongest at the rim, zero at the centre), sampled at
/// 2.5× the base frequency. Scaling it would roughen the whole rim and bias the coast inward; it is
/// the coastline's jitter, not a margin-targeted cutter. This term is separate: its own deterministic
/// field (seed offset + a coordinate offset in map widths), its own frequency (the neck/lobe scale),
/// zero-mean (it bites AND builds, so the coast is redrawn rather than eroded), and weighted by a
/// smooth WINDOW on the falloff value itself:
///
/// w(f) = 1 smoothstep(|f centre| / halfWidth) (exactly 0 beyond ± halfWidth)
/// falloff += amp · w(f) · noise(x + off, y + off) noise ∈ [1, 1]
///
/// The coast sits where rawBase falloff^2.5 crosses sea, i.e. near f ≈ 0.66 for a median rawBase
/// (chat2/08 diagnosis), so a window centred there covers the barely-land / barely-sea margin
/// around the whole perimeter, north and south. Cells whose falloff is clear of the window — the
/// interior, the massif, the deep sea — get w = 0 and are bit-identical by construction (asserted).
///
/// SELF-TARGETING: every lobe hangs off a neck of barely-land, cells whose height sits a hair above
/// sea. A bite of the same Δfalloff flips those first; solid land inside the window (a coastal hill)
/// moves in height but does not flip. No neck is detected; the margin selects itself. Amplitude is
/// the ladder; frequency is fixed and exposed as the secondary dial.
/// </summary>
public static class CoastalFragment
{
/// <summary>Periods per map width. The base noise is ≈ 4/map, the edge noise ≈ 10/map; lobes in the 08 plates are 27 % of the map. Chosen by the chat2/09 probe.</summary>
public const float DefaultFreqPerMapWidth = 12f;
/// <summary>The coastal window's centre in pre-power falloff units (the coast's falloff for a median base noise).</summary>
public const float DefaultBandCentre = 0.66f;
/// <summary>Half-width of the window. 0.18 spans f ∈ [0.48, 0.84] — the whole fringe, nothing of the interior.</summary>
public const float DefaultBandHalfWidth = 0.18f;
/// <summary>Bites only by default? Set by the chat2/09 probe (see the report): zero-mean redraws the margin and can bridge islands back; bites-only only cuts.</summary>
public const bool DefaultBitesOnly = false;
/// <summary>The field's seed offset (a SEED offset, like the islet layer's 7607).</summary>
public const int SeedOffset = 9109;
/// <summary>The field's coordinate offset, IN MAP WIDTHS (D-059) — decorrelates it from the base field's realization at every size.</summary>
public const float OffsetMapWidths = 0.37f;
/// <summary>The window weight for a pre-power falloff value.</summary>
public static float Window(float falloff, float centre, float halfWidth)
{
float t = MathF.Abs(falloff - centre) / halfWidth;
if (t >= 1f) return 0f;
return 1f - t * t * (3f - 2f * t);
}
}
}