The pack
vectorTerrain
function vectorTerrain(): Pack<{ vecTerrain: VecTerrainApi }>
The vector-terrain pack. Pure maths, so it needs no backend and runs headless.
Helpers
climbableX
function climbableX(terrain: readonly Vec2[], fromX: number, toX: number, maxClimbSlope: number): number
Slope-limited horizontal step along a heightfield. Returns the ALLOWED x: toX
if the step's uphill slope is within maxClimbSlope (rise/run — ~1 is 45°),
otherwise fromX (refused). Downhill is always allowed.
craterHeightfield
function craterHeightfield(polyline: Vec2[], cx: number, cy: number, radius: number, floorY: number, opts: CraterOptions = {}): void
Blow a crater into a heightfield polyline, in place — destructible terrain.
Lowers the surface within radius of (cx, cy) following a circular bowl, ONLY
ever pushing the ground down and clamping to floorY, so the surface stays
single-valued and heightAtX stays valid. With step, vertices are added under
the crater first so it keeps its shape however coarse the terrain is.
flattenTerrain
function flattenTerrain(polyline: Vec2[], fromX: number, toX: number, y?: number): { x0: number; x1: number; y: number }
Flatten the ground between fromX and toX to height y, IN PLACE: a landing pad, a plateau, a runway, a
firing position. Vertices are added at both edges so the flat runs exactly from fromX to toX, and the
vertices between are set to y, raised or lowered, so the field stays single-valued. y defaults to the
ground height at the middle of the span. Returns the pad as { x0, x1, y }, clamped to the polyline's span.
generateTerrain
function generateTerrain(opts: HeightfieldOptions): Vec2[]
Midpoint-displacement terrain as a polyline, sorted left-to-right and single-valued in x, ready for
heightAtX, flattenTerrain, craterHeightfield, game.vector.shape(points, { closed: false }) and
vector-hit's polylineSegments. Deterministic: the same seed (or rng stream) gives the same ground.
Generate once per level; never per frame.
Throws on a width that is not positive or a pass count past TERRAIN_MAX_ITERATIONS.
heightAtX
function heightAtX(polyline: readonly Vec2[], x: number): number
Sample the y of a terrain polyline at world x, linearly interpolating between the two vertices spanning x. Points must be sorted by x ascending (every function here keeps them so). A binary search, so it is cheap to call per body per frame. Returns Infinity if x is outside the polyline (treat as: no ground here).
refineTerrain
function refineTerrain(polyline: Vec2[], fromX: number, toX: number, maxSpacing: number): number
Add vertices to a terrain polyline, IN PLACE, so no segment between fromX and toX is longer than
maxSpacing world units. The shape does not change (each new vertex sits on the old line); what changes is
how finely a crater or a pad can then bend it. Clamped to the polyline's own span. Returns the number of
vertices added. Throws on a maxSpacing that is not positive.
TERRAIN_MAX_ITERATIONS
const TERRAIN_MAX_ITERATIONS: 16
The most subdivision passes generateTerrain runs: 2^16 + 1 vertices, a bound on memory and time.
Types
CraterOptions
interface CraterOptions
Options for craterHeightfield.
step?: number— Refine the ground under the crater first, so no segment within it is longer than this, world units. A crater narrower than the terrain's own vertex spacing then carves a real bowl instead of a notch. Default unset: only the vertices already there move.
HeightfieldOptions
interface HeightfieldOptions
Options for generateTerrain: the span, ground level, roughness, resolution, clamps and seed of a midpoint-displacement heightfield.
width: number— Span on x, world units: the terrain runs 0..width. Must be positive.baseY: number— Average ground height (screen y; larger = lower on screen). Both ends sit exactly here.amplitude?: number— Initial vertical displacement, world units. DefaultbaseY * 0.4.roughness?: number— 0..1: how much amplitude survives each subdivision. Default 0.5; higher is more jagged.iterations?: number— Subdivision passes:2^iterations + 1points. Default 6. Ignored whenspacingis set.spacing?: number— The widest gap between neighbouring vertices, world units: the fewest passes whose spacing is at most this (width / 2^n <= spacing), so the resolution follows the world rather than a pass count. Generate it finer than the smallest crater or pad. Default unset, which usesiterations.minY?: number— Clamp ceiling: the highest the ground may rise (smallest y). Default 0.maxY?: number— Clamp floor: the lowest the ground may sink (largest y). DefaultbaseY * 2.seed?: number— Seed for the displacement: the same seed and options give the same landscape. Default 1. Ignored whenrngis given.rng?: () => number— A random source returning [0, 1), such as() => game.rng.next(). Default a stream seeded byseed.
Vec2
interface Vec2
A 2D point or vector. Plain data, so anything can produce one.
x: number— Horizontal coordinate, in world units, increasing to the right.y: number— Vertical coordinate, in world units; the 2D world is Y-down, so larger is lower on screen.
VecPt
type VecPt = Vec2
A point on a path — the same shape, named for what it is used as.
VecTerrainApi
type VecTerrainApi = typeof kit
game.vecTerrain — every function this pack carries, as one namespace. Its generateTerrain draws from
game.rng when the options give neither seed nor rng, so a game's terrain replays with the game's seed.


