feat(client): invert the Atlas rung relation — rung sets extent, not spacing

A rung used to fix the gridunit SPACING, with the canvas extent falling out
of spacing x cell count. That is why the top of the ladder was unusable: at
REGION_M spacing a viewport-sized canvas spanned ~251,658 km — six times
around a rocky body — so the Region rung capped to the body and redrew the
Global picture pixel-for-pixel. "Global and region look the same" was not a
rendering bug; it was this relation, stated in metres.

Inverted: a rung fixes the EXTENT and the spacing falls out of the canvas
size. The shorter viewport axis spans exactly one cell of the rung's level,
so a widescreen window shows more ground on the long axis rather than less
on the short one. Every rung now shows the ground its name promises —
Region 262x466 km, District 4.1x7.3 km — and the canvas cell count is
viewport-driven and identical at every rung, so derive cost no longer varies
with depth and resize is free.

Consequences that fell out of the inversion rather than being chosen:

- Region leaves the orbital derive set. It was envelope-only because at
  251,658 km nothing finer made sense; at 262 km it is a genuine provincial
  map and takes the full courses-aware derive. Region having no rivers at
  all was much of why the top of the ladder read flat. It also joins the
  deep display ratio for the same reason.
- The S2 station-spacing floor is deleted, not retuned. It guarded an
  O(1/spacing) blowup that the inversion makes structurally impossible (the
  canvas cell count is now constant across rungs, so stations-per-course is
  bounded however deep you scroll). Kept, it would do active harm in the
  opposite direction: a 2,048 m pitch across a 3.6 km District canvas places
  two stations and draws every river as a straight line. Station placement
  gets its own generator pass.
- cap_extent_to_body is superseded and now a documented no-op. A canvas can
  no longer over-request a body by construction. The residual question —
  whether a rung's cell exceeds the whole body — is liveness, not capping,
  and is_rung_live_on_body() answers it by omitting the rung. Empirically it
  never fires on inhabited content: all six rungs are live on all 271
  populated bodies with a radius.
- snap_to_gridunit no longer truncates its multiplier to int. Post-inversion
  the deep rungs run sub-metre (Chunk ~0.12 m at a 1080 px short axis), where
  int(spacing) floors to zero and would collapse every request centre onto
  the origin.

Both sides derive spacing from the same three inputs (rung, echoed cell
extent, body radius) rather than one telling the other, so there is nothing
to keep in sync beyond the constant table itself. Body radius already
reaches the viewer via enter(); no wire change.

Pair session with Jeroen, 2026-07-26. D-243/D-255 amendments to be backfiled.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-26 21:38:08 +02:00
co-authored by Claude
parent f5b34131b0
commit 0a0419abcc
8 changed files with 620 additions and 291 deletions
@@ -20,7 +20,7 @@ func test_set_frame_stores_the_frame_and_triggers_no_crash_on_draw() -> void:
"courses": [],
"settlement_id": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
}
layer.set_frame(canvas, Vector2(1000.0, 2000.0), "District", Vector2i(4, 4))
layer.set_frame(canvas, Vector2(1000.0, 2000.0), "District", Vector2i(4, 4), 0.0)
# No assertion beyond "did not crash" — set_frame()/queue_redraw() with a
# well-formed empty-feature canvas is the baseline no-op path every
# richer test below builds on.
@@ -30,7 +30,7 @@ func test_set_frame_stores_the_frame_and_triggers_no_crash_on_draw() -> void:
func test_clear_frame_drops_the_held_canvas() -> void:
var layer: StepCanvasAnnotationLayer = auto_free(StepCanvasAnnotationLayer.new())
add_child(layer)
layer.set_frame({"width": 1, "height": 1, "courses": []}, Vector2.ZERO, "Chunk", Vector2i(1, 1))
layer.set_frame({"width": 1, "height": 1, "courses": []}, Vector2.ZERO, "Chunk", Vector2i(1, 1), 0.0)
layer.clear_frame()
assert_that(layer._canvas).is_null()
@@ -42,7 +42,7 @@ func test_clear_frame_drops_the_held_canvas() -> void:
func test_cell_center_world_m_matches_the_servers_own_per_cell_placement() -> void:
var layer: StepCanvasAnnotationLayer = auto_free(StepCanvasAnnotationLayer.new())
add_child(layer)
layer.set_frame({"width": 4, "height": 4, "courses": []}, Vector2(0.0, 0.0), "District", Vector2i(4, 4))
layer.set_frame({"width": 4, "height": 4, "courses": []}, Vector2(0.0, 0.0), "District", Vector2i(4, 4), 0.0)
# half_w = half_h = 2; spacing = 2048. Cell (0,0) -> (0-2)*2048 = -4096 on
# both axes; cell (2,2) (the center-ish cell) -> (2-2)*2048 = 0.
@@ -54,9 +54,15 @@ func test_cell_center_world_m_offsets_by_the_frames_world_center() -> void:
var layer: StepCanvasAnnotationLayer = auto_free(StepCanvasAnnotationLayer.new())
add_child(layer)
layer.set_frame(
{"width": 2, "height": 2, "courses": []}, Vector2(10_000.0, 20_000.0), "Chunk", Vector2i(2, 2)
{"width": 2, "height": 2, "courses": []},
Vector2(10_000.0, 20_000.0),
"Chunk",
Vector2i(2, 2),
0.0
)
# half_w = half_h = 1; spacing = 64. Cell (1,1) -> center + (1-1)*64 = center.
# half_w = half_h = 1; spacing = CHUNK_M / short axis = 64/2 = 32 post-
# inversion. Cell (1,1) -> center + (1-1)*32 = center either way — this
# asserts the centre cell lands on the centre, not the pitch itself.
assert_that(layer._cell_center_world_m(1, 1)).is_equal(Vector2(10_000.0, 20_000.0))
@@ -71,7 +77,7 @@ func test_world_to_local_uses_the_held_frame() -> void:
layer.set_frame({"width": 32, "height": 32, "courses": []}, world_center, "Quarter", extent)
var expected: Vector2 = StepCanvasTransport.world_m_to_canvas_local(
world_center, world_center, "Quarter", extent
world_center, world_center, "Quarter", extent, 0.0
)
assert_that(layer._world_to_local(world_center)).is_equal_approx(expected, Vector2(0.01, 0.01))
@@ -307,7 +313,7 @@ func test_is_true_source_in_canvas_true_for_an_interior_point() -> void:
var layer: StepCanvasAnnotationLayer = auto_free(StepCanvasAnnotationLayer.new())
add_child(layer)
# District spacing 2048m, extent 4x4 -> half-extent 4096m on each axis.
layer.set_frame({"width": 4, "height": 4, "courses": []}, Vector2(1000.0, 2000.0), "District", Vector2i(4, 4))
layer.set_frame({"width": 4, "height": 4, "courses": []}, Vector2(1000.0, 2000.0), "District", Vector2i(4, 4), 0.0)
assert_bool(layer._is_true_source_in_canvas(Vector2(1000.0, 2000.0))).is_true()
@@ -317,7 +323,7 @@ func test_is_true_source_in_canvas_true_for_an_interior_point() -> void:
func test_is_true_source_in_canvas_false_for_a_point_outside_the_bounds() -> void:
var layer: StepCanvasAnnotationLayer = auto_free(StepCanvasAnnotationLayer.new())
add_child(layer)
layer.set_frame({"width": 4, "height": 4, "courses": []}, Vector2(1000.0, 2000.0), "District", Vector2i(4, 4))
layer.set_frame({"width": 4, "height": 4, "courses": []}, Vector2(1000.0, 2000.0), "District", Vector2i(4, 4), 0.0)
# Half-extent is 4096m; world center + 5000m on X is well outside.
assert_bool(layer._is_true_source_in_canvas(Vector2(1000.0 + 5000.0, 2000.0))).is_false()
@@ -327,7 +333,7 @@ func test_is_true_source_in_canvas_false_for_a_point_outside_the_bounds() -> voi
func test_is_true_source_in_canvas_is_conservative_at_the_exact_boundary() -> void:
var layer: StepCanvasAnnotationLayer = auto_free(StepCanvasAnnotationLayer.new())
add_child(layer)
layer.set_frame({"width": 4, "height": 4, "courses": []}, Vector2.ZERO, "District", Vector2i(4, 4))
layer.set_frame({"width": 4, "height": 4, "courses": []}, Vector2.ZERO, "District", Vector2i(4, 4), 0.0)
# Half-extent is 4096m exactly. A point AT the boundary (x=4096) is
# within epsilon of the edge -> conservatively NOT a true source.
assert_bool(layer._is_true_source_in_canvas(Vector2(4096.0, 0.0))).is_false()
@@ -338,7 +344,7 @@ func test_is_true_source_in_canvas_is_conservative_at_the_exact_boundary() -> vo
func test_is_true_source_in_canvas_false_for_null() -> void:
var layer: StepCanvasAnnotationLayer = auto_free(StepCanvasAnnotationLayer.new())
add_child(layer)
layer.set_frame({"width": 4, "height": 4, "courses": []}, Vector2.ZERO, "District", Vector2i(4, 4))
layer.set_frame({"width": 4, "height": 4, "courses": []}, Vector2.ZERO, "District", Vector2i(4, 4), 0.0)
assert_bool(layer._is_true_source_in_canvas(null)).is_false()
@@ -367,7 +373,7 @@ func test_set_frame_with_a_crop_passthrough_course_does_not_crash() -> void:
# overhang case (finding 1).
"courses": [{"class": 2, "points": [[-9000, 0], [0, 0], [10, 0]], "terminus": ""}],
}
layer.set_frame(canvas, Vector2.ZERO, "District", Vector2i(4, 4))
layer.set_frame(canvas, Vector2.ZERO, "District", Vector2i(4, 4), 0.0)
assert_object(layer).is_not_null()
@@ -381,5 +387,5 @@ func test_set_frame_with_an_interior_source_course_does_not_crash() -> void:
"height": 4,
"courses": [{"class": 2, "points": [[0, 0], [500, 0], [1000, 0], [1500, 0]], "terminus": "Mouth"}],
}
layer.set_frame(canvas, Vector2.ZERO, "District", Vector2i(4, 4))
layer.set_frame(canvas, Vector2.ZERO, "District", Vector2i(4, 4), 0.0)
assert_object(layer).is_not_null()