> For the complete documentation index, see [llms.txt](https://cityweft.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cityweft.gitbook.io/docs/geometry/infrastructure/trees-and-vegetation.md).

# Trees & Vegetation

The generation API returns trees in two ways, controlled by the **`treeSource`** setting: the default **`standard`** engine (surveyed points + procedural forest fill), or **canopy detection** (`hybrid` / `canopy`), which places individual trees from a global 1‑metre satellite canopy model, each with a measured height and crown diameter.

{% hint style="info" %}
Positions come from the real canopy surface (a 1‑metre satellite model), so they follow actual trees — accurate to **metres, not centimetres**.
{% endhint %}

### `treeSource`

| Value      | What you get                                                                                                                                                                                             |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `standard` | **Default.** Surveyed tree points + forest areas filled with procedurally scattered trees.                                                                                                               |
| `hybrid`   | **Recommended.** Surveyed tree positions **re‑heighted** from the canopy, procedural forest **replaced** by canopy‑detected trees, and remaining canopy gaps filled. Measured heights + crown diameters. |
| `canopy`   | Canopy‑detected trees only (surveyed points dropped). Measured heights + crown diameters.                                                                                                                |

`hybrid` is the usual choice for detailed vegetation.

### Request

Tree settings go in `settings` on the generation request:

```json
{
  "polygon": [[lat, lon], ...],
  "settings": {
    "treeSource": "hybrid"
  }
}
```

| Setting           | Meaning                                             | Default    | Notes                                   |
| ----------------- | --------------------------------------------------- | ---------- | --------------------------------------- |
| `treeSource`      | Tree engine (see above)                             | `standard` | `standard` · `hybrid` · `canopy`        |
| `canopyMinHeight` | **Optional.** Shortest canopy counted as a tree (m) | `3`        | Below this (shrubs, hedges) are ignored |

The `canopy*` tuning settings apply only when `treeSource` is `hybrid` or `canopy`; they're ignored for `standard`.

### Response

Trees are returned as nodes in the **`instances`** geometry group. Each tree node looks like:

```json
{
  "type": "instance",
  "instanceType": "tree",
  "x": -116.98, "y": 0, "z": -288.74,
  "scale": 12.4,
  "height": 12.4,
  "descriptor": {
    "type": "tree",
    "height": 12.4,
    "crownDiameter": 6.2,
    "source": "meta-canopy",
    "heightSource": "CHMv2"
  }
}
```

| Field                          | Meaning                                                       | When present                                                 |
| ------------------------------ | ------------------------------------------------------------- | ------------------------------------------------------------ |
| `x` / `y` / `z`                | Tree position in the model's local coordinate frame (metres)  | Every tree                                                   |
| `scale`                        | Tree height in metres (also drives rendered size).            | Every tree                                                   |
| `height` / `descriptor.height` | Tree height in metres                                         | Every tree in canopy mode, measured or estimated (see below) |
| `descriptor.crownDiameter`     | Measured crown width in metres                                | Canopy‑detected trees only                                   |
| `descriptor.source`            | Where the tree came from, e.g. `meta-canopy`                  | Canopy‑detected trees                                        |
| `descriptor.heightSource`      | Where the height came from, e.g. `Meta Canopy Height (CHMv2)` | When the height was measured from canopy data                |

#### Height — measured vs estimated

`descriptor.heightSource` tells you which reading a height came from:

* **Measured** from the canopy for every canopy‑detected tree, and for surveyed trees wherever the canopy model covers them.
* **Estimated / tagged** fallback where the canopy model has no usable reading — a data gap or a tree not represented in the canopy surface.

Coverage is global over land, so measured heights are available almost anywhere there is real tree canopy. There is no reading over water, bare ground, or below the height threshold.

#### Crown diameter

`descriptor.crownDiameter` is measured from the canopy — the crown's width out to the surrounding gap — so a broad, spreading tree and a narrow one of the same height report different sizes. Present on canopy‑detected trees only; use it to size a massing model by real crown width rather than by height alone.

### How detection works

For `hybrid` / `canopy`, Cityweft reads the 1‑metre canopy surface for the area and detects individual trees:

1. **Find treetops** — local peaks in the canopy become candidate trees.
2. **One tree per crown** — a bumpy single crown merges into one tree, while two crowns split by a real gap stay separate.
3. **Fill closed canopy** — continuous forest, where individual stems can't be told apart, is filled to match the canopy density.
4. **Measure & clean up** — height and crown diameter are measured, and trees that would fall on a building footprint, road or water are removed.

### Accuracy & limitations

{% hint style="warning" %}
Positions are **realistic, not survey‑grade** — derived from a 1‑metre satellite model, so treat them as accurate to **metres, not centimetres**.
{% endhint %}

* **Dense forest** — merged crowns can't be resolved into exact stems; trees there are placed to match canopy density rather than pinned to real stems.
* **Small vegetation** — canopy below `canopyMinHeight` (shrubs, hedges) are not returned.<br>

<figure><img src="/files/vvYKwDHHjhbn4rnD6Xhl" alt=""><figcaption></figcaption></figure>

\
Coverage is worldwide over land.
