Terrain Architecture
This note defines the clean terrain model for space.
The intended user is an end user editing terrain live while using the world, not only a designer in a separate authoring mode.
Design Decision
The terrain system should have:
- terrain objects as the persistent things in the world
- terrain tools as actions that mutate those objects
- terrain runtimes as derived render/physics state
The first real terrain object kind should be heightfield-terrain.
flat-terrain and perlin-terrain should not remain as terrain object kinds in the long-term design. They are terrain tools for heightfield-terrain, not peer terrain objects.
Core Model
Worlds contain multiple terrain objects.
Each terrain object is single-kind forever.
Examples of future terrain kinds:
heightfield-terrain- later
voxel-terrain - later
sdf-terrain - later
mesh-terrain
Each terrain object has three responsibilities:
1. Terrain Object
Persistent world data.
Responsibilities:
- id
- name
- kind
- transform
- appearance settings
- physics settings
- terrain-domain configuration
- canonical terrain data
2. Canonical Terrain Data
Editable source of truth.
Examples:
- heightfield sample grid
- voxel field
- signed-distance field
- mesh patch data
For the first implementation, canonical data is chunked heightfield data in terrain-local space.
3. Terrain Runtime
Derived runtime state.
Responsibilities:
- render mesh chunks
- collision chunks
- picking / raycast helpers
- dirty-chunk tracking
Runtime is disposable. It is never authoritative.
Canonical State
The terrain system should persist final terrain data, not tool history.
That means:
flat,perlin,raise,smooth, and future tools modify terrain data directly- the world persists only the resulting terrain
- if the user wants different perlin parameters later, they run the perlin tool again on the target region
This matches the live in-context editing model and avoids unnecessary complexity around recipes, operator stacks, baking, or history replay.
Terrain Objects vs Tools
Terrain objects answer:
- what terrain exists in the world?
- where is it?
- what kind is it?
- what are its physical/render properties?
Tools answer:
- how does the user change this terrain right now?
Examples of heightfield-terrain tools:
Initialize FlatApply Perlin- later
Raise - later
Lower - later
Smooth - later
Flatten - later
Stamp Heightmap
Tools are not persistent model objects. They are UI/actions that mutate canonical terrain data.
Graph Model
The graph should present terrain objects, not terrain history.
Recommended shape:
TerrainsTerrain
That is enough for the first clean implementation.
The generic Terrain node should be generic.
Its label should be:
- terrain name if present
- otherwise
terrain
It should not use terrain kind as the node label.
The generic terrain node view should show:
- name
- kind
- transform summary
- terrain-domain summary
- appearance summary
- physics summary
- available tools list
kind is metadata in the view, not the node label.
Terrain Editors
Terrain properties and terrain tools are different concepts and should have different UIs.
Terrain Properties Editor
Each terrain kind can have one kind-specific terrain-properties editor.
For heightfield-terrain, this editor should own:
- name
- position
- rotation
- sample spacing
- chunk/sample configuration
- appearance settings
- physics settings
This editor changes terrain object properties.
It should not embed terrain tools like perlin or flatten.
Terrain Tools List
The generic terrain node view should show a searchable list of tools applicable to the terrain kind.
For heightfield-terrain, the first list should include:
Initialize FlatApply Perlin
Later:
RaiseLowerSmoothFlatten
Clicking a tool should open that tool's own dedicated view or node.
That keeps the terrain-properties editor clean and allows many tools without turning one view into a dumping ground.
Tool UI Semantics
Terrain property editing and tool application should not share exactly the same button behavior.
Property Editors
For terrain properties:
Applyshould require valid inputApplyshould be enabled only when the form is dirty
Tools
For terrain tools:
Applyshould require valid inputApplyshould stay enabled even if the params are unchanged- repeated apply with unchanged params is valid
This matters especially for tools like perlin, where a user may want to re-run the tool repeatedly without changing the form.
Tool Target Model
All terrain tools should operate on an explicit target.
The first clean target modes are:
- whole terrain
- rectangle
Later:
- brush
Suggested target representation:
{:mode :whole}and
{:mode :rect
:x0 local-x0
:z0 local-z0
:x1 local-x1
:z1 local-z1}This is enough for:
- whole-terrain initialization
- whole-terrain perlin generation
- rectangular perlin application
- rectangular flatten
For the first pass, rectangle selection can be form-driven by numeric inputs. A friendlier interactive selection mechanism can come later.
Interactive Editing Primitives
Manual live editing still needs shared infrastructure.
Required primitives:
- world ray hit to terrain-local coordinates
- region preview overlay
- brush cursor preview
- pointer drag lifecycle
- localized dirty-chunk update path
These primitives should be built only after rectangular form-based tools exist and the terrain mutation path is stable.
Heightfield First
heightfield-terrain is the right first terrain kind because it supports:
- procedural generation like flat/perlin
- direct local edits
- simple chunking
- practical Bullet integration
Canonical heightfield data should be:
- chunk-based
- sparse-capable
- terrain-local
- independent of Bullet representation
Bullet Integration
Bullet should sit behind the terrain runtime, not inside the terrain object model.
Rules:
- terrain data is authoritative
- render/physics are derived
- only dirty chunks rebuild
For heightfield-terrain, collision can use whichever runtime representation is simplest, as long as:
- it is chunk-local
- it does not force terrain data to mirror Bullet data structures
Non-Goals
Avoid these in the clean design:
- old
flat-terrain/perlin-terrainobject kinds as part of the new path - persistent operator lists
- persisted tool history
- bake-first authoring workflows
- terrain kind in the generic terrain node label
- embedding many tool forms into the terrain-properties editor
- special fallback compatibility structures in the new model
Clean Direction
The clean direction from here is:
heightfield-terrainbecomes the only active terrain path for new work.- The generic terrain node stays generic.
- A dedicated heightfield properties editor handles terrain object settings.
- Terrain tools are listed separately and opened separately.
- Tools operate on explicit targets.
- Form-driven rectangular targeting comes before interactive selection.
- Interactive brush primitives come after the rectangular tool path is clean.
