> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eucaengine.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Terrain & foliage

> Create a heightmap terrain, sculpt it with raise/lower/flatten/smooth brushes, and scatter instanced foliage — building the world's ground end to end on a local server.

Euca's terrain (`euca-terrain`) is a chunked heightmap: a grid of height samples you create flat and
then **sculpt with brushes** — raise, lower, flatten, smooth — each applied at a world position with a
radius and amount. Foliage scatters instanced meshes across an area in one layer. The terrain *data*
(the heightmap component and its edits) is fully headless and works on the bare server; the *mesh* —
and the foliage — need a render host's mesh assets. This page builds and sculpts a terrain end to end;
every command is real and runnable against a [local server](/quickstart), with output captured from one.

## Sculpt a heightmap

**1. Create a flat terrain.** You give it a grid size and cell size; it spawns a terrain entity and
reports the resulting world extents. Note the extents are `(cells − 1) × cell_size` — a 64-cell grid
spans 63 world units:

```bash theme={null}
curl -s -X POST http://localhost:3917/terrain/create -H 'Content-Type: application/json' \
  -d '{"width":64,"height":64,"cell_size":1.0}'
# {"ok":true,"entity_id":1,"width":64,"height":64,"cell_size":1.0,
#  "world_width":63.0,"world_depth":63.0}
```

**2. Raise a hill.** `/terrain/edit` applies one of four brush ops at `(x, z)` with a `radius` and
`amount`. The edit lands immediately on the heightmap of the first terrain entity — no `/step`:

```bash theme={null}
curl -s -X POST http://localhost:3917/terrain/edit -H 'Content-Type: application/json' \
  -d '{"op":"raise","x":32,"z":32,"radius":6,"amount":2.0}'
# {"ok":true,"message":"raise terrain at (32, 32) r=6"}
```

**3. Use the other three brushes.** `lower` digs, `flatten` pulls toward a target level, `smooth`
averages neighbours — all the same request shape:

```bash theme={null}
curl -s -X POST http://localhost:3917/terrain/edit -H 'Content-Type: application/json' \
  -d '{"op":"lower","x":10,"z":10,"radius":4,"amount":1.0}'
# {"ok":true,"message":"lower terrain at (10, 10) r=4"}

curl -s -X POST http://localhost:3917/terrain/edit -H 'Content-Type: application/json' \
  -d '{"op":"flatten","x":20,"z":20,"radius":5,"amount":0.5}'
# {"ok":true,"message":"flatten terrain at (20, 20) r=5"}

curl -s -X POST http://localhost:3917/terrain/edit -H 'Content-Type: application/json' \
  -d '{"op":"smooth","x":32,"z":32,"radius":6,"amount":0.5}'
# {"ok":true,"message":"smooth terrain at (32, 32) r=6"}
```

## Scatter foliage

`/foliage/scatter` places an instanced layer of a named mesh across an area. The scatter is
deterministic (fixed seed) — but it needs the host's **`DefaultAssets`** to resolve the mesh and
material. The minimal server doesn't register them, so on it the call honestly reports the missing
resource and the layer list stays empty:

```bash theme={null}
curl -s -X POST http://localhost:3917/foliage/scatter -H 'Content-Type: application/json' \
  -d '{"mesh_name":"cube","density":0.5,"area_min":[-20,0,-20],"area_max":[20,0,20]}'
# {"ok":false,"error":"DefaultAssets resource not found"}

curl -s http://localhost:3917/foliage/list
# {"count":0,"layers":[]}
```

On a host with `DefaultAssets` registered, the same scatter returns
`{"ok":true,"instance_count":N,"mesh":"cube","density":0.5}` and `/foliage/list` reports each layer's
index, instance count, density, and max render distance.

## Behavior and gotchas

The things you only find out by running it:

* **`/terrain/create` stores a heightmap component, not a rendered mesh.** It builds a CPU
  `Heightmap::flat` and spawns it; building the displayable mesh (CPU or GPU) is the render host's job.
  Creating terrain bumps `entity_count` on `GET /`; reading the rendered surface needs a host.
* **Edits are immediate — no `/step`.** Unlike combat events, a brush op mutates the heightmap on the
  call. Read-back is via the host (the heightmap isn't exposed as JSON), but the op itself succeeds
  synchronously.
* **`/terrain/edit` acts on the *first* terrain entity.** It queries for any `TerrainComponent` and
  edits the first one found. With no terrain, or an unknown op, it returns
  `{"ok":false,"message":"No terrain entity found or invalid operation"}`.
* **World extents are `(cells − 1) × cell_size`.** A `width:64, cell_size:1.0` terrain has
  `world_width:63.0`, not 64 — the grid has 64 vertices spanning 63 cells.
* **Brush coordinates are world-space `(x, z)`**, not grid indices; `radius` and `amount` shape the
  falloff and strength. The four ops dispatch identically — only the math on the heightmap differs.
* **Foliage scatter needs host mesh assets.** Without `DefaultAssets` it can't resolve `mesh_name`
  (`{"ok":false,"error":"DefaultAssets resource not found"}`); an unknown mesh name on a host returns
  `{"ok":false,"error":"Unknown mesh name"}`.

## Endpoints

| Method | Path               | Description                                                             |
| ------ | ------------------ | ----------------------------------------------------------------------- |
| `POST` | `/terrain/create`  | Create a flat heightmap terrain (returns the entity id + world extents) |
| `POST` | `/terrain/edit`    | Apply a `raise` / `lower` / `flatten` / `smooth` brush at `(x, z)`      |
| `POST` | `/foliage/scatter` | Scatter an instanced foliage layer (needs host `DefaultAssets`)         |
| `GET`  | `/foliage/list`    | List scattered foliage layers with instance counts                      |

## Status

* **Shipped & headless** — the CPU heightmap, the four brush ops, the terrain entity, and deterministic
  foliage scatter logic. Terrain create and edit work fully on the bare server.
* **Host-dependent** — the terrain *mesh* and foliage *placement* need render-side assets:
  `/foliage/scatter` requires a registered `DefaultAssets`; displaying terrain or foliage needs a render
  host.
* **GPU terrain generation** — a real compute-shader mesh generator (`GpuTerrainGenerator`) ships behind
  the `gpu-terrain` feature flag and needs a live `RenderDevice`. It is *not* the path the HTTP endpoint
  uses; the endpoint builds the heightmap on the CPU.

<Card title="Terrain & foliage endpoints" icon="mountain-sun" href="/api-reference/introduction" horizontal>
  Create, edit, scatter, and list endpoints, with request and response schemas.
</Card>
