Heightfield Terrain Implementation Plan
This note turns the terrain architecture into a concrete implementation order.
The goal is to move to the clean model:
- one real terrain object path for new work:
heightfield-terrain - one generic terrain object in the graph
- one terrain-properties editor for
heightfield-terrain - separate terrain tools
- form-based region targeting first
- interactive selection and brushes later
Immediate Corrections
Before building more tools, the graph model should be corrected.
Required corrections:
- The generic terrain node must stop using terrain kind as its label.
- The
heightfield-terraineditor must become a terrain-properties editor only. Initialize FlatandApply Perlinmust move out of the terrain-properties editor and become terrain tools.- Old
flat-terrainandperlin-terrainterrain-object integration should be removed from the new path.
Those are structural fixes, not optional cleanup.
Target Runtime and Data Model
The canonical terrain record should remain final chunked heightfield data.
Suggested persistent shape:
{:id "<uuid>"
:name "terrain"
:kind "heightfield-terrain"
:transform
{:position [0 0 0]
:rotation [1 0 0 0]}
:appearance
{:opacity 1.0
:material nil}
:physics
{:enabled true}
:domain
{:sample-spacing [1 1]
:chunk-samples [33 33]
:default-height 0}
:chunks
[{:coord [0 0]
:heights [0 0 0 ...]}]}Notes:
namebelongs on the terrain object, not inferred from kind.transform,appearance,physics, anddomainshould become explicit sections instead of a catch-all options blob.coordshould allow negative terrain-local chunk coordinates.- the canonical model stays chunk-based and final-data-based
The current code does not need to reach this exact schema in one jump, but all new work should move toward it.
Graph Structure
The graph should be terrain-centered and simple.
Recommended shape:
TerrainsTerrainTerrain PropertiesTerrain Tool
Meaning:
Terrainis the generic object nodeTerrain Propertiesis the kind-specific object editorTerrain Toolis an invoked tool UI for one terrain
The Terrain node view should show:
- name
- kind
- summary of transform/domain/appearance/physics
- searchable list of tools available for the terrain kind
The Terrain node should not directly embed tool forms.
Heightfield Terrain Properties Editor
heightfield-terrain needs a dedicated properties editor node/view.
It should own only object properties:
- name
- position
- rotation
- sample spacing
- chunk sample size
- appearance settings
- physics settings
Not tool actions.
This editor should behave like a normal record editor:
- validate
- enable
Applyonly when dirty - update active scene terrain in place
Tool Registry
Add a dedicated tool registry for terrain kinds.
For heightfield-terrain, initial tool list:
Initialize FlatApply Perlin
Later:
Flatten RegionRaiseLowerSmooth
The terrain view should use this registry to populate a searchable list of tools.
Clicking one tool should open that tool’s dedicated node/view.
Tool Nodes and Views
Each tool should own:
- its params
- its target mode
- its validation
- its apply behavior
The tool node is not a terrain object. It is a UI/action node scoped to one terrain.
First tool nodes:
heightfield-flat-toolheightfield-perlin-tool
Each node should reference:
- world id
- terrain id
- tool name
Tool Button Semantics
Tool UIs should not behave like record editors.
For tool nodes:
Applyis enabled whenever the tool is valid- it remains enabled after apply
- it may keep the last-used params in local view state
That gives the correct behavior for tools like perlin, where repeated apply with the same params is useful.
Target Region Model
All terrain tools should take a target.
First supported target modes:
wholerect
Suggested representation:
{:mode :whole}and
{:mode :rect
:x0 0
:z0 0
:x1 128
:z1 128}Interpretation:
- local terrain-space coordinates
- axis-aligned rectangle
- normalized by the tool validation layer before apply
This region model should be shared across heightfield tools.
First Tool Forms
For now, region selection should be form-driven.
That means:
- whole-terrain toggle or selector
- rectangle coordinate inputs
Example perlin tool form:
- target mode
- rectangle bounds if
:rect - seed
n1divn2divn3divn1scalen2scalen3scalezrootzpowerApply
Example flat tool form:
- target mode
- rectangle bounds if
:rect - target height
Apply
This is enough to prove the target model and the data mutation path before building friendlier selection UI.
Shared Data Mutation API
Terrain data helpers should move to explicit target-aware APIs.
Recommended first write surface:
apply-flat!(record target params)apply-perlin!(record target params)
Lower-level support:
- iterate samples in target region
- ensure touched chunks exist
- mutate touched samples
- return touched chunk coordinates
Scene/runtime sync should then rebuild only affected chunks.
Even if chunk-local rebuild is not fully implemented yet, the API should already report touched chunks so the runtime can evolve cleanly.
Interactive Selection Later
After form-based rectangle tools exist and feel stable, add selection primitives:
- terrain hit query from cursor
- rectangular drag preview in world space
- brush cursor preview
- drag lifecycle
Those primitives should feed the same target model:
- drag rectangle produces
{:mode :rect ...} - brush stroke later produces
{:mode :brush ...}
Do not build a separate parallel targeting system.
Delivery Order
Recommended order from here:
Slice 1: Graph cleanup
- generic terrain node label becomes generic again
- generic terrain node view shows tool list, not embedded tool forms
- add dedicated
heightfield-terrainproperties editor - remove old
flat-terrain/perlin-terrainterrain-object integration from the active terrain path
Slice 2: Tool registry and tool nodes
- add terrain tool registry
- add searchable tools list for
heightfield-terrain - add dedicated flat tool node/view
- add dedicated perlin tool node/view
- keep tool apply re-clickable
Slice 3: Region-aware data APIs
- target model
- flat whole/rect apply
- perlin whole/rect apply
- validation and tests
Slice 4: Heightfield properties coverage
- name
- transform
- domain settings
- appearance
- physics
Slice 5: Interactive selection primitives
- world hit query
- rectangle selection preview
- brush preview
Slice 6: First interactive edit tool
Raise/LowerorFlatten
Tests Needed
New tests should cover:
Graph semantics
- generic terrain node label stays generic
- terrain view lists tools
- tool click opens dedicated tool node
Tool semantics
- tool apply stays enabled when valid after apply
- tool keeps last-used params locally
- tool validate/apply paths work for both
:wholeand:rect
Data semantics
- rectangular target only changes intended samples
- untouched chunks remain unchanged
- negative chunk coordinates still work
Properties editor semantics
- terrain properties are editable independently of tools
- active scene terrain updates in place
What Not To Do
Do not continue with:
- tool forms inside the heightfield terrain editor
- treating old
flat-terrain/perlin-terrainobject kinds as part of the new path - whole-terrain-only tool APIs as the long-term surface
- building brush UI before target-aware form tools exist
Next Concrete Step
The next implementation step should be:
- fix the generic terrain node label and semantics
- split the current
heightfield-terraineditor into:- terrain-properties editor
- dedicated flat/perlin tool nodes
- add the shared whole/rect target form model
That is the smallest clean step that aligns the code with the intended terrain design.
