---
title: "Terrain basics ground heightmap and sculpting"
description: "You need a real outdoor ground the player walks on with elevation, not a flat box. `TerrainComponent` is a placement/binding component: the geometry lives in a canonical terrain resource asset, and the component points an entity at it."
engineVersion: v1.0.234
date: 2026-09-28
license: "(c) Gessa, proprietary. Cite with attribution to https://gessa.ai/docs/. Terms: https://gessa.ai/terms/."
canonical: https://gessa.ai/docs/knowledge/playbooks/terrain-basics/
---

# Terrain basics ground heightmap and sculpting

## When to use

You need a real outdoor ground the player walks on with elevation, not a flat
box. `TerrainComponent` is a placement/binding component: the geometry lives in a
canonical terrain resource asset, and the component points an entity at it.

## The recipe

1. Create or obtain a terrain resource asset (prefer the catalog first, see
   asset-acquisition-strategy). The dedicated `terrain.resource.create` action
   is `planned` (no AI/MCP tool is mapped for it yet); today an asset created via
   `project_create_asset` (`project.asset.create`) backs the binding.
2. Sculpt the heightmap: `project_apply_terrain_semantic_patch`
   (`terrain.patch.apply`) applies a terrain semantic patch (raise, lower,
   flatten, paint layers) to the resource. This is the active, AI-exposed
   editing verb.
3. Build the render and collision artifacts: `terrain_build_artifacts`
   (`terrain.artifacts.build`) turns the sculpted resource into the LOD meshes
   and collision the runtime consumes.
4. Bind it to an entity: attach `TerrainComponent`
   `{ "type":"TerrainComponent", "enabled": true, "terrainAssetId": <asset id> }`
   with `project_add_component`. `terrainAssetId` is required and must be a valid
   asset id.
5. Sample the terrain from scripts with the `rendering.v1` host ops:
   `ctx.terrain.heightAt`, `ctx.terrain.normalAt`, `ctx.terrain.slopeAt`,
   `ctx.terrain.raycastDown`, `ctx.terrain.sampleLayerWeights` (for placing props
   on the surface or gating steep slopes).

## Pitfalls

- `TerrainComponent` alone renders nothing without a built `terrainAssetId`;
  sculpt and build the resource first, then bind.
- `terrainAssetId` is required (not optional) and pattern-checked as an asset id;
  a bad id fails validation.
- Do not expect terrain to add feature depth beyond placement/projection; the
  component contract is intentionally thin.
- Nav agents (see npc-enemy-navigation) need the terrain's collision artifacts
  built to path over it.

## Verify

- `engine_get_component_schema` on `TerrainComponent` (two fields: `enabled`,
  `terrainAssetId`).
- `project_get_graph_snapshot` to confirm the entity carries the terrain binding.
- `qa_capture_renderer_viewport` to confirm the landscape renders with elevation.
