6.3 KiB
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_gen.rswithTerrainGenerationSpec,TerrainGenerationSettings, andDeterministicTerrainGenerator, pluscargo test terrain_gencoverage for the determinism/seed note. -
src/terrain.rswith immutableHeightGridstorage, safe indexing, min/max, and deterministicplane/radial_hillfixtures. -
src/render.rswith a deterministic top-down preview and a CPU perspective spike that only depends onHeightGrid+Scene. -
src/scene.rsandsrc/app_state.rsfor scene controls and preview wiring. -
src/import.rsfor the open-format import boundary. -
docs/plans/initial-roadmap.mdanddocs/plans/phase-4-formats-scripts-ui.mdfor the broader project sequence.
The core seeded procedural terrain pipeline now exists; the remaining work in this roadmap is about future generator variants and richer presets, not the first shipped fractal slice.
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 likeplaneandradial_hill.- New generator module, e.g.
src/terrain/generation.rsorsrc/generation.rs: procedural generation logic, seed handling, interpolation/noise helpers, and generator presets. - Public API should return
HeightGridand nothing renderer-specific. - Any generator metadata should live in a separate spec/config type, not in the grid itself.
A good minimal boundary is:
TerrainGenerationSpecor 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:
HeightGridstays 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 amplitudeisland/continentalprofile with a radial falloff maskmountainprofile with stronger octave contrastfractal/noisepreset exposed through the app shell and CLI as the first shipped procedural family
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:
cargo fmt --check
cargo test terrain
cargo test
cargo clippy --all-targets -- -D warnings
cargo run -- render --preset fractal --seed 1337 --width 64 --height 64 --output /tmp/openvistapro-fractal-plan.png
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