world.terrain#
The ground itself, the same relief the terrain tool paints.
Use it to
- read the ground height to put something on the ground
- raise, lower, flatten or smooth the ground from a script
local world = require("world") local h = world.terrain:height(10, -4)world.terrain:raise(10, -4, 6, 2)Reading is free and public. Writing uses the same brush the creator's terrain tool uses: same limits, same falloff, same result.
height#
world.terrain:height(x, z) → metres
The ground height at a world position.
Never fails. A flat world reads 0, and so does nonsense input, so you can use it straight in maths without guarding it.
-- put something on the ground rather than in itlocal ground = world.terrain:height(x, z)world:spawn({ model = "crate", pos = { x = x, y = ground + 0.5, z = z } })Note that it answers for the terrain, not for whatever is standing on it. For "what is under this point, including objects", cast a ray downward with world:raycast.
The four brushes#
All four take the same arguments and answer true, or nil plus a reason.
world.terrain:raise(x, z, radius, strength) world.terrain:lower(x, z, radius, strength) world.terrain:flatten(x, z, radius, strength) world.terrain:smooth(x, z, radius, strength)
| Argument | Default | Range |
|---|---|---|
x, z | required | the centre of the stroke, in world coordinates |
radius | 4 | 0.5 to 64 metres |
strength | 1 | 0 to 8 metres at the centre |
The stroke falls off smoothly to its rim, so overlapping strokes blend rather than leaving steps.
| Brush | What it does |
|---|---|
raise | pushes the ground up |
lower | digs down |
flatten | pulls the area toward the height at the brush centre, for terraces and building pads |
smooth | neighbourhood average, which softens spikes and the seams between strokes |
flatten is the one worth understanding: it does not flatten to zero, it flattens to whatever is under the middle of your brush. Put the centre where you want the floor to be.
Refusals#
| Reason | Meaning |
|---|---|
permission | the script's owner does not hold Terraform in this world |
invalid brush | radius or strength outside the range |
too many commands | more than 8 world effects in this event |
A worked example: a crater#
--!strictlocal self = require("self")local world = require("world") local function crater(cx: number, cz: number) world.terrain:lower(cx, cz, 8, 4) world.terrain:raise(cx, cz, 12, 0.6) -- the rim thrown up around it world.terrain:smooth(cx, cz, 14, 1) -- soften the joinend self:on_touch(function() local here = self:position() crater(here.x, here.z)end)Three strokes is three effects, comfortably inside the eight-per-event ceiling. A hundred strokes is not, so spread those over a timer:
local queue = {}local i = 0 self:on_timer(0.1, function() for _ = 1, 4 do -- four strokes per tick i += 1 local s = queue[i] if not s then return end world.terrain:raise(s.x, s.z, s.r, s.h) endend)See also#
- world.blocks is the cubic volume that lives alongside this
Updated 17 October 2026