Skip to content

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 Flat
  • Apply 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:

  • Terrains
  • Terrain

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 Flat
  • Apply Perlin

Later:

  • Raise
  • Lower
  • Smooth
  • Flatten

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:

  • Apply should require valid input
  • Apply should be enabled only when the form is dirty

Tools ​

For terrain tools:

  • Apply should require valid input
  • Apply should 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:

fennel
{:mode :whole}

and

fennel
{: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-terrain object 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:

  1. heightfield-terrain becomes the only active terrain path for new work.
  2. The generic terrain node stays generic.
  3. A dedicated heightfield properties editor handles terrain object settings.
  4. Terrain tools are listed separately and opened separately.
  5. Tools operate on explicit targets.
  6. Form-driven rectangular targeting comes before interactive selection.
  7. Interactive brush primitives come after the rectangular tool path is clean.

See also ​