Files
Ransom-s-wake/docs/superpowers/plans/2026-10-06-terrain-varied-landforms.md
2026-10-06 21:33:57 +02:00

57 lines
4.6 KiB
Markdown

# Formes de relief variées — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Extend the bake tool with polyline canyons, noise-edged outcrops, boulder fields, polyline escarpments and a strata modifier, then bake a `terrain_showcase` site that demonstrates all five reference landforms and is covered by geometric contract tests.
**Architecture:** `tools/site_terrain_baker.gd` gains a `Modifier` phase (after the primitive sum, with the local gradient) and a per-primitive material override hook. New primitives are nested classes next to the existing ones. A new recipe `tools/sites/terrain_showcase_recipe.gd` and its baked `content/sites/terrain_showcase*.{tres,res}` are the demonstration site. Nothing under `game/` changes.
**Tech Stack:** Godot 4.7.2 headless, GDScript, `bash scripts/quality_gate.sh`.
**Spec:** `docs/briefs/terrain-varied-landforms.md`.
## Global Constraints
- Godot binary (Git Bash): `export GODOT_BIN="/c/Users/olivi/Downloads/Godot_v4.7.2-stable_win64.exe/Godot_v4.7.2-stable_win64_console.exe"`; ripgrep: `export PATH="$PATH:/c/Users/olivi/AppData/Local/Programs/Microsoft VS Code/resources/app/node_modules/@vscode/ripgrep/bin"`.
- `tools/` depends on `game/domain/` only; nothing under `game/` or `content/` references `res://tools/` (architecture check).
- Determinism: every random element is a seeded `FastNoiseLite` or `RandomNumberGenerator`; the same recipe bakes byte-identical arrays.
- `content/sites/zone1_vigilant_terrain.res` must not change (re-bake and `git diff --stat` empty for it).
- Test runners: `TEST_COUNT` equals the number of `_expect` calls.
- Never hand-edit `.tres`/`.res`.
- Commits end with `Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>`.
## Tasks
### Task 1: Modifier phase and per-primitive material hook
- `Primitive.material_at(x, z) -> int` returning `NO_MATERIAL := -1`.
- `Modifier.modify(x, z, elevation, gradient: Vector2) -> float`.
- `Recipe.modifiers: Array[Modifier]`.
- `bake()` order: sum → modifiers (gradient by central differences on the current array) → floor → slope material → primitive material → patches.
- Unit tests: a modifier that adds 1 m everywhere shifts the field; a primitive forcing ROCK on a flat plane wins over the slope rule; zone 1 recipe bakes identical to the checked-in `.res`.
### Task 2: `Canyon` and `Escarpment` (polyline primitives)
- Shared static `distance_to_path(point, path) -> float`, `arc_position(point, path) -> Vector2(along_m, total_m)` and `signed_distance_to_path` (sign from the nearest segment's cross product, positive on the right of travel).
- Edge noise: `FastNoiseLite` seeded, `TYPE_SIMPLEX_SMOOTH`, frequency 0.05, amplitude `edge_amplitude_m`.
- Tests: Canyon depth on the flat floor, zero far away, follows a corner, closes over one half-width at the ends; Escarpment right side lower by `drop_m`, left side unchanged.
### Task 3: `Outcrop` and `BoulderField`
- Outcrop: `e = (sqrt((dx/rx)² + (dz/rz)²) - 1) * mean_radius + noise`, `delta = height * (1 - smoothstep(-wall_width, 0, e))`, rock where `delta > 0.3 * height` and `rock_top`.
- BoulderField: `RandomNumberGenerator` seeded; disc sampling `r = radius * sqrt(u)`, angle `TAU * v`; per boulder `h = r_b * height_ratio`, profile `h * sqrt(max(0, 1 - (d / r_b)²))`; combine by `maxf`; early reject outside `radius + max_r`; rock where profile > 0.
- Tests: plateau height, rock on top, zero at two radii; boulder field deterministic, zero outside, rock on a boulder, two overlapping boulders do not sum.
### Task 4: `Strata` modifier
- Formula from the brief §4.3. Tests: a 45° plane with 2 m layers and sharpness 0.9 produces at least two flat runs (|gradient| < 0.1) on a transect; a flat plane is unchanged; sharpness 0 is identity.
### Task 5: `terrain_showcase` recipe, bake, registry
- Recipe per brief §5; `bake_site_terrain.gd` RECIPES gains `terrain_showcase`; bake; preview PNG under `docs/briefs/captures/`.
- Verify zone 1 re-bake identical.
### Task 6: Contract and integration tests for the showcase
- `tests/contract/run_site_content_tests.gd`: new `_test_showcase_content()` per brief §6.
- `tests/integration/run_site_terrain_integration.gd`: showcase loads < 3 s, canyon ray lower than mesa ray, scan reads rock and sand.
- Foundation test: `select_dive_site` on the showcase is not required.
### Task 7: Docs
- ADR 0012 amendment, `content/README.md`, `tests/README.md`, technical plan status line, brief status.
- Full gate green.