feat(ui): atlas generation overlays — Layer-1 rivers/basins/attractors (#960)

Render the proxied Layer1Output (D-225) as toggleable Atlas overlays. The
viewer stores the decoded Layer1Output via set_generation_layer1() and the
marker overlay draws three new layers gated by their visibility flags:

  RVR  river_cells as dots, confluences as small circles, mouths as
       double-ring sea-terminus markers
  BAS  drainage-basin boundaries as thin closed polylines + faint fill
  ATR  geographic attractors — shape by attractor_type (Araminta's 7-shape
       vocabulary), color by sub_biome, size by strength; <0.15 culled

Layer-1 positions are [row, col] in the 512x256 working grid, which matches
the viewer's grid_to_canvas transform, so they project directly onto the
heightmap. OVERLAY_DEFS gains gen_l1_rivers/basins/attractors (toggle group)
so AtlasOverlayBar auto-exposes them as toggle buttons.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-24 19:02:02 +02:00
co-authored by Claude Opus 4.7
parent 03d0264eb0
commit 33a2ed6aae
3 changed files with 208 additions and 5 deletions
+25
View File
@@ -0,0 +1,25 @@
## Tests for the Phase-4 generation overlays in the Atlas viewer (#960, D-225).
## Referencing AtlasViewer forces both it and AtlasMarkerOverlay to compile, so
## this also guards against parse errors in the overlay rendering code.
class_name TestAtlasOverlays
extends GdUnitTestSuite
func test_generation_overlays_registered() -> void:
var ids: Array = []
for d: Dictionary in AtlasViewer.OVERLAY_DEFS:
ids.append(d["id"])
assert_that(ids).contains(["gen_l1_rivers", "gen_l1_basins", "gen_l1_attractors"])
func test_generation_data_round_trips() -> void:
var v: AtlasViewer = auto_free(AtlasViewer.new())
assert_that(v.get_generation_layer1()).is_null()
var mock := {
"body_id": "GJ1c",
"river_network": {"river_cells": [], "confluences": [], "mouths": []},
"drainage_basins": [],
"attractors": [],
}
v.set_generation_layer1(mock)
assert_that(v.get_generation_layer1()).is_equal(mock)