Layer System

Stack layers like a painter. Buildings first, then roads, then trees. Each layer respects the ones above it.

What Is a Layer?

A DecorationLayer is a single scatter operation: what to place, where, how many, and what rules to follow. A forest is one layer. A rock field is another. A row of fence posts is a third. Stack them to build a complete world.

Three-quarter aerial view of the green test terrain populated by three superimposed scatter layers — 30 oaks distributed via Poisson disk, 20 plumeria added on top of the oaks (also Poisson), and 15 pines added clustered to the right side. The result reads as a mixed forest with broad oak canopies in the center, bright-green plumeria patches, and tall conifer pines along one edge. Stats bar reads Objects 65, Tris 962,560, Draws 132.
Figure 1. Three layers, one canvas. Each scatter() call adds to what's already there — oaks, then plumeria, then pines — without disturbing earlier placements.

Layer Definition

{
  "id": "pine-forest",
  "name": "Pine Forest",
  "instanceTypes": [
    { "speciesId": "pine", "weight": 0.6, "scaleMin": 0.8, "scaleMax": 1.2 },
    { "speciesId": "spruce", "weight": 0.3, "scaleMin": 0.7, "scaleMax": 1.1 },
    { "speciesId": "fir", "weight": 0.1, "scaleMin": 0.9, "scaleMax": 1.3 }
  ],
  "algorithm": "poisson",
  "count": 200,
  "minDistance": 5,
  "constraints": [
    { "type": "slope", "maxDegrees": 30 },
    { "type": "height", "minHeight": 10, "maxHeight": 80 }
  ],
  "priority": 10,
  "excludesLayers": ["buildings"]
}

Layer Properties

PropertyTypeDescription
idstringUnique identifier for cross-layer references
namestringDisplay name shown in UI panels
instanceTypesarrayPool of object types with probability weights
algorithmstringpoisson, clustered, density, or grid
countnumberTarget number of instances to place
minDistancenumberMinimum spacing between instances (meters)
constraintsarrayTerrain-aware filters (slope, height, exclusion)
prioritynumberHigher priority layers place first
excludesLayersstring[]Layer IDs whose placements this layer avoids

Instance Types

Each layer defines a pool of instance types. When placing an object, one type is selected randomly based on weight. This creates natural variety — a forest layer might be 60% pine, 30% spruce, 10% fir.

PropertyTypeDescription
speciesIdstringSpecies registry lookup (e.g. "oak", "boulder")
generatorstringProcedural generator ID ("ez-tree", "rock")
assetPathstringPath to pre-made GLB model (alternative to generator)
weightnumberProbability weight (0–1). Weights are normalized per layer
scaleMinnumberMinimum random scale (default 0.8)
scaleMaxnumberMaximum random scale (default 1.2)
rotationRandomYbooleanRandomize Y-axis rotation (default true)
yOffsetnumberVertical offset from ground (e.g. floating objects)

Priority & Exclusion

Layers are processed in priority order — highest priority first. Each placed instance becomes an exclusion zone for subsequent layers that list it in excludesLayers. This ensures buildings get first pick of the terrain, roads fill in around them, and trees avoid both.

🚧
Priority ordering — buildings (100) → roads (50) → trees (10)
Recommended: 1920×1080
// Layer priority example
const layers = [
  { id: "buildings", priority: 100, ... },  // Place first
  { id: "roads",     priority: 50,  ... },  // Avoid buildings
  { id: "trees",     priority: 10,  excludesLayers: ["buildings", "roads"] },
  { id: "flowers",   priority: 5,   excludesLayers: ["buildings", "roads", "trees"] }
]

Multi-Layer Pipeline

  1. Sort by priority — Highest priority layers scatter first
  2. Generate candidates — Each layer runs its scatter algorithm independently
  3. Cross-layer exclusion — Remove candidates near higher-priority placements using spatial hash grid
  4. Apply constraints — Filter by slope, height, exclusion zones
  5. Select instance types — Weighted random selection from the layer's pool
  6. Randomize transforms — Scale range, Y rotation, Y offset
  7. Register placements — Store positions for lower-priority layers to avoid
ℹ Spatial Hash Grid

Cross-layer exclusion uses a spatial hash grid for O(n) performance. Cell size equals minDistance. For each candidate, only the 3×3 neighborhood of cells is checked — no need to compare against every placed object.

Biome Compositions

Layered scatters are how biomes are built. Each composition below uses 3–5 successive scatters — ground cover or rocks first, then mid-layer flora, then accent species — on the same procedural terrain, same camera. The variety comes from which species, which algorithm, which population, not from any biome-specific code path.

Single vs Multi-Layer

MethodUse CaseCross-Exclusion
scatter(layer)One layer in isolationNo
scatterLayers(layers)Multiple layers togetherYes