Skip to content

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:

  1. The generic terrain node must stop using terrain kind as its label.
  2. The heightfield-terrain editor must become a terrain-properties editor only.
  3. Initialize Flat and Apply Perlin must move out of the terrain-properties editor and become terrain tools.
  4. Old flat-terrain and perlin-terrain terrain-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:

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

  • name belongs on the terrain object, not inferred from kind.
  • transform, appearance, physics, and domain should become explicit sections instead of a catch-all options blob.
  • coord should 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:

  • Terrains
  • Terrain
  • Terrain Properties
  • Terrain Tool

Meaning:

  • Terrain is the generic object node
  • Terrain Properties is the kind-specific object editor
  • Terrain Tool is 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 Apply only 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 Flat
  • Apply Perlin

Later:

  • Flatten Region
  • Raise
  • Lower
  • Smooth

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-tool
  • heightfield-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:

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

  • whole
  • rect

Suggested representation:

fennel
{:mode :whole}

and

fennel
{: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
  • n1div
  • n2div
  • n3div
  • n1scale
  • n2scale
  • n3scale
  • zroot
  • zpower
  • Apply

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-terrain properties editor
  • remove old flat-terrain / perlin-terrain terrain-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/Lower or Flatten

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 :whole and :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-terrain object 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:

  1. fix the generic terrain node label and semantics
  2. split the current heightfield-terrain editor into:
    • terrain-properties editor
    • dedicated flat/perlin tool nodes
  3. add the shared whole/rect target form model

That is the smallest clean step that aligns the code with the intended terrain design.

See also ​