feat: wire shell placeholders to backend actions #12
@@ -0,0 +1,167 @@
|
|||||||
|
# Terrain Generation Roadmap
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Define the next terrain-generation workstream so future slices stay small, deterministic, and testable. This plan is intentionally clean-room: it uses only project-owned synthetic fixtures and open math/algorithm ideas, never proprietary VistaPro material.
|
||||||
|
|
||||||
|
## Current baseline
|
||||||
|
|
||||||
|
OpenVistaPro already has:
|
||||||
|
|
||||||
|
- `src/terrain.rs` with immutable `HeightGrid` storage, safe indexing, min/max, and deterministic `plane` / `radial_hill` fixtures.
|
||||||
|
- `src/render.rs` with a deterministic top-down preview and a CPU perspective spike that only depends on `HeightGrid` + `Scene`.
|
||||||
|
- `src/scene.rs` and `src/app_state.rs` for scene controls and preview wiring.
|
||||||
|
- `src/import.rs` for the open-format import boundary.
|
||||||
|
- `docs/plans/initial-roadmap.md` and `docs/plans/phase-4-formats-scripts-ui.md` for the broader project sequence.
|
||||||
|
|
||||||
|
The missing piece is a dedicated procedural terrain generator pipeline that can produce richer synthetic landscapes without mixing algorithm state into `HeightGrid`.
|
||||||
|
|
||||||
|
## Decision summary
|
||||||
|
|
||||||
|
### First generator family: seeded 2D value-noise fBm
|
||||||
|
|
||||||
|
Implement a deterministic, seedable fractal terrain family first, built from 2D value noise with fBm-style octaves.
|
||||||
|
|
||||||
|
Why this first:
|
||||||
|
|
||||||
|
- It is fully clean-room and easy to describe/test.
|
||||||
|
- It produces organic terrain that is more representative than the current plane/hill fixtures.
|
||||||
|
- It works well with tiny synthetic grids, which keeps tests fast and stable.
|
||||||
|
- It can grow into ridged / warped / terraced variants later without changing the external boundary.
|
||||||
|
|
||||||
|
Initial scope should stay modest: generate a single height grid from a seed, dimensions, and a small set of parameters. Do not add erosion, climate, or streaming at first.
|
||||||
|
|
||||||
|
## API boundary
|
||||||
|
|
||||||
|
Keep `HeightGrid` as pure data plus basic helpers.
|
||||||
|
|
||||||
|
Recommended split:
|
||||||
|
|
||||||
|
- `src/terrain.rs`: immutable grid storage, validation, indexing, min/max, and tiny deterministic fixtures like `plane` and `radial_hill`.
|
||||||
|
- New generator module, e.g. `src/terrain/generation.rs` or `src/generation.rs`: procedural generation logic, seed handling, interpolation/noise helpers, and generator presets.
|
||||||
|
- Public API should return `HeightGrid` and nothing renderer-specific.
|
||||||
|
- Any generator metadata should live in a separate spec/config type, not in the grid itself.
|
||||||
|
|
||||||
|
A good minimal boundary is:
|
||||||
|
|
||||||
|
- `TerrainGenerationSpec` or similar: dimensions, seed, octave count, lacunarity, gain, base frequency, amplitude.
|
||||||
|
- `generate(spec) -> Result<HeightGrid, TerrainError>`
|
||||||
|
|
||||||
|
If the implementation later needs richer provenance, add a lightweight wrapper beside the spec, but keep the renderer and scene code consuming `HeightGrid` only.
|
||||||
|
|
||||||
|
## Roadmap slices
|
||||||
|
|
||||||
|
### Slice 1: generator module skeleton
|
||||||
|
|
||||||
|
Goal: introduce the procedural terrain namespace without changing renderer behavior.
|
||||||
|
|
||||||
|
Deliverables:
|
||||||
|
|
||||||
|
- module scaffolding for generator code
|
||||||
|
- a small spec type with seed and size fields
|
||||||
|
- a deterministic construction path that still returns a `HeightGrid`
|
||||||
|
|
||||||
|
Acceptance:
|
||||||
|
|
||||||
|
- `HeightGrid` stays unchanged as a storage type
|
||||||
|
- generator tests compile without touching render code
|
||||||
|
|
||||||
|
### Slice 2: deterministic value-noise core
|
||||||
|
|
||||||
|
Goal: implement the smallest reusable noise primitive.
|
||||||
|
|
||||||
|
Deliverables:
|
||||||
|
|
||||||
|
- seeded lattice/value-noise helper
|
||||||
|
- interpolation across grid cells
|
||||||
|
- deterministic output for identical inputs
|
||||||
|
|
||||||
|
Acceptance:
|
||||||
|
|
||||||
|
- same seed + same spec always yields identical samples
|
||||||
|
- different seeds produce different grids
|
||||||
|
- tiny grids do not panic at edges
|
||||||
|
|
||||||
|
### Slice 3: fBm terrain composition
|
||||||
|
|
||||||
|
Goal: layer octaves into usable synthetic landscapes.
|
||||||
|
|
||||||
|
Deliverables:
|
||||||
|
|
||||||
|
- octave accumulation
|
||||||
|
- amplitude/frequency controls
|
||||||
|
- normalization into the range expected by the renderer/palette logic
|
||||||
|
|
||||||
|
Acceptance:
|
||||||
|
|
||||||
|
- output min/max remain bounded and predictable
|
||||||
|
- generated terrain exercises multiple elevation bands in the preview
|
||||||
|
|
||||||
|
### Slice 4: preset profiles
|
||||||
|
|
||||||
|
Goal: provide a few named generator presets for common shapes.
|
||||||
|
|
||||||
|
Suggested first presets:
|
||||||
|
|
||||||
|
- `plain`-like flat terrain via zeroed noise amplitude
|
||||||
|
- `island` / `continental` profile with a radial falloff mask
|
||||||
|
- `mountain` profile with stronger octave contrast
|
||||||
|
|
||||||
|
Acceptance:
|
||||||
|
|
||||||
|
- preset selection is deterministic
|
||||||
|
- presets remain thin wrappers around the shared generator core
|
||||||
|
|
||||||
|
### Slice 5: later enhancements
|
||||||
|
|
||||||
|
Only after the core is stable:
|
||||||
|
|
||||||
|
- ridged multifractal terrain
|
||||||
|
- domain warping
|
||||||
|
- terraces / plateaus
|
||||||
|
- simple erosion pass
|
||||||
|
- derived slope / normal helpers if the renderer needs them
|
||||||
|
- CLI/script integration so generated terrain can be rendered and scripted like imported terrain
|
||||||
|
|
||||||
|
## Test matrix
|
||||||
|
|
||||||
|
Use tiny synthetic fixtures only.
|
||||||
|
|
||||||
|
### Unit tests
|
||||||
|
|
||||||
|
- dimensions are preserved exactly
|
||||||
|
- zero dimensions are rejected
|
||||||
|
- identical seed/spec pairs produce identical grids
|
||||||
|
- different seeds change output
|
||||||
|
- sample access stays in-bounds and row-major expectations remain intact
|
||||||
|
- min/max are sane after normalization
|
||||||
|
- presets produce the expected broad shape characteristics
|
||||||
|
|
||||||
|
### Behavior tests
|
||||||
|
|
||||||
|
- a small generated grid renders successfully through the existing top-down path
|
||||||
|
- the perspective spike accepts generated grids without special-case code
|
||||||
|
- the generator does not mutate renderer or scene state
|
||||||
|
|
||||||
|
### Validation commands
|
||||||
|
|
||||||
|
Run these for each generator slice:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo fmt --check
|
||||||
|
cargo test terrain
|
||||||
|
cargo test
|
||||||
|
cargo clippy --all-targets -- -D warnings
|
||||||
|
```
|
||||||
|
|
||||||
|
Add one feature-specific smoke command for the slice once the generator has a public entry point, for example a tiny render or sample-generation command that writes to `/tmp` and proves the generated grid is usable end-to-end.
|
||||||
|
|
||||||
|
## Definition of done for the workstream
|
||||||
|
|
||||||
|
The terrain-generation workstream is ready to close when:
|
||||||
|
|
||||||
|
- the generator module is separate from `HeightGrid`
|
||||||
|
- at least one seeded procedural family exists
|
||||||
|
- tests prove determinism and shape invariants
|
||||||
|
- generated terrain can flow into the existing render pipeline without special handling
|
||||||
|
- future slices can add more generator families without changing the grid storage contract
|
||||||
Reference in New Issue
Block a user