Procedural terrain generation with fractal noise, hydraulic erosion and river extraction, backed by a Rust NIF.
The pipeline has four stages, each optional after the first:
- Base heightmap — fractal (fBm) OpenSimplex noise
- Island mask — radial falloff with noise-perturbed coastlines
- Hydraulic erosion — a droplet simulation that carves valleys and drainage networks
- Hydrology — flow routing over the eroded terrain; high-flow cells become rivers, filled depressions become lakes
Generation is fully deterministic for a given seed and option set, and runs on a dirty CPU scheduler so it never blocks the BEAM.
Examples
{:ok, terrain} = TerrainGenerator.generate(width: 512, height: 512, seed: 42)
TerrainGenerator.Terrain.height_at(terrain, 100, 100)
#=> 0.53
# render straight to a PNG file without keeping the data:
:ok = TerrainGenerator.render_png("map.png", seed: 42)Options
All functions take the same option list; omitted keys use the defaults.
:width,:height— map size in cells (default512 × 512), at most 4,294,967,295 cells in all:seed— generation seed (default0):sea_level— sea level in[0, 1)(default0.08):octaves— noise octaves (default8):frequency— number of large features across the map (default2.5):lacunarity— frequency multiplier between octaves (default2.0):persistence— amplitude multiplier between octaves (default0.5):island— island diameter as a fraction of the shorter map dimension,truefor the default size, orfalseto let terrain reach the borders (default1.0):coast_noise— coastline perturbation strength;0gives a perfectly round island (default1.0):erosion—true/false, or a droplet count to override the default of one droplet per cell (defaulttrue):rivers— approximate fraction of land covered by rivers,truefor the default density, orfalseto disable rivers and lakes (default0.01):river_min_upstream— absolute river threshold in cells of upstream catchment; overrides:riverswhen set (defaultfalse):archipelago— number of islands to place instead of a single island, orfalsefor one island (defaultfalse):islands_size,:islands_variation,:islands_spread,:islands_spacing— archipelago island size, per-island size variation, how far centres spread, and minimum centre spacing (defaults0.35,0.35,0.85,0.22):breach_basins— carve outlets from closed basins larger than this fraction of the map so they drain instead of becoming inland seas, orfalse(defaultfalse)
All options are validated; invalid values raise ArgumentError with a
descriptive message before any native code runs.
Summary
Functions
Generates a terrain and returns {:ok, %TerrainGenerator.Terrain{}}.
Generates a terrain and writes it to path as a PNG file.
Types
@type option() :: {:width, pos_integer()} | {:height, pos_integer()} | {:seed, non_neg_integer()} | {:sea_level, float()} | {:octaves, pos_integer()} | {:frequency, number()} | {:lacunarity, number()} | {:persistence, number()} | {:island, number() | boolean()} | {:coast_noise, number()} | {:archipelago, pos_integer() | false} | {:islands_size, number()} | {:islands_variation, number()} | {:islands_spread, number()} | {:islands_spacing, number()} | {:erosion, boolean() | pos_integer()} | {:breach_basins, number() | false} | {:rivers, number() | boolean()} | {:river_min_upstream, number() | false}
Functions
@spec generate([option()]) :: {:ok, TerrainGenerator.Terrain.t()}
Generates a terrain and returns {:ok, %TerrainGenerator.Terrain{}}.
Raises ArgumentError on unknown options.
{:ok, terrain} = TerrainGenerator.generate(seed: 7, width: 256, height: 256)
terrain.width
#=> 256
Generates a terrain and writes it to path as a PNG file.
style is :shaded (biome colours with hillshading, the default) or
:greyscale (plain heightmap).
Returns :ok, or {:error, reason} if the file cannot be written.
:ok = TerrainGenerator.render_png("map.png", seed: 3)
:ok = TerrainGenerator.render_png("height.png", [seed: 3], :greyscale)