Endless Procedural Terrain in Three.js · Part 2 of 3
THREE.JS NOISE TERRAIN TUTORIAL:
fBm, RIDGED MOUNTAINS + DOMAIN WARPING
By Shane Brumback · · Intermediate Three.js tutorial · about 45 minutes
One new height function on the Part 1 chunks: seeded noise, fBm octaves, ridged mountains, domain warping, carved valleys and flat combat zones. Add ?seed=42 for a whole new world.
SEE IT LIVE
The ridged mountains and winding valleys rolling past behind this page are a live run of this tutorial's noise terrain: fBm hills, ridged peaks and domain-warped valleys streaming in around the capsule. Launch the full-screen demo to drive it yourself with WASD and Space.
WASD move, Space jump, drag to turn the camera, G tints alternate chunks, Esc exits.
What Is a Noise Terrain Heightmap? (Beginner Definition)
A noise terrain heightmap is a height function, heightAt(x, z), that turns any point into a height using noise. One layer of noise gives soft, samey bumps. Stacking layers (fBm), flipping noise into ridged crests, bending the input with domain warping, and carving valleys and flat zones with masks is what turns those bumps into real-looking, playable land.
Introduction
This is the hands-on half of Procedural Terrain in Three.js, Part 2 of 3. Part 1 made the ground endless with streaming chunks and a WASD character. Part 2 swaps in one new heightAt(x, z): seeded noise, fBm octaves, ridged mountains, domain warping, carved valleys and seeded flat combat zones. The chunks, trees and character from Part 1 stay exactly as they were. Add ?seed=42 for a whole new world. The Part 2 article explains the why. This tutorial is the code.
What You'll Learn
- How to stack fBm octaves for hills with natural detail
- How to make sharp mountain crests with ridged noise (
1 - |noise|) under a slow mask - How domain warping bends ridges and valleys into natural curves
- How to carve valleys and blend flat combat zones with masks
- How to drive the whole map from one seed so every player gets the same world
- How this one new
heightAt(x, z)drops straight into the Part 1 chunks
Prerequisites
- The Part 1 chunk code (this swaps in only the height function)
- Basic Three.js: scene, camera, mesh, render loop
- A local web server (any static server works) and a modern browser
- Three.js r160 loaded with an importmap (shown in the full code)
Frequently Asked Questions
What is a terrain heightmap in Three.js?
A terrain heightmap is a grid of heights that shapes a flat mesh into hills. In Three.js you take a PlaneGeometry, lay it flat, and set each vertex's y from either a grayscale image or a height function like heightAt(x, z). A function-based heightmap built from noise never runs out, so it suits endless terrain.
What is fBm in noise terrain?
fBm (fractal Brownian motion) means adding several layers of noise, called octaves. Each octave usually has double the frequency and half the height of the one before, so the first octave makes big hills and later octaves add smaller and smaller detail. Four to six octaves is typical for game terrain.
How does ridged noise make mountains?
Ridged noise takes 1 minus the absolute value of the noise. Normal noise crosses zero along smooth lines, and that flip turns each zero line into a sharp crest, so you get mountain ridges instead of round hills. Squaring the result and weighting each octave by the previous one makes the ridges crisper.
What is domain warping?
Domain warping offsets the coordinates you feed into the noise using another, slower noise. Instead of heightAt(x, z) you sample at (x + warpX, z + warpZ). Straight, repetitive features bend into twisting ridges and winding valleys, which looks much more natural.
How do multiplayer games give every player the same procedural map?
They share a seed instead of the map. The noise and every random choice are driven by a seeded generator, so the same seed always produces the same heights. The server sends one number, and each client builds identical terrain locally without downloading a heightmap.
Does this noise terrain work with older Three.js versions?
Yes. The demo targets r160 with an importmap, but the heightmap math (fBm, ridged noise and domain warping) is plain JavaScript and works with any version. The chunk streaming and capsule character come from Part 1; CapsuleGeometry needs r139+, so on older builds swap the capsule for a cylinder or a model.
How It Works
- Start from a flat grid — Lay a PlaneGeometry flat and set every vertex's y from heightAt(x, z) using world coordinates.
- Stack fBm octaves — Add 4 to 6 noise octaves, each at double frequency and half height, for hills with detail.
- Add ridged mountains — Use 1 - |noise| octaves under a slow mask so ranges appear in some regions only.
- Warp the domain — Offset x and z with a slower noise before sampling so ridges and valleys bend naturally.
- Carve valleys and flat zones — Pull the height down along a noise zero line and blend seeded discs to a flat height for arenas.
- Drive it all from one seed — Seed the noise and every random choice so every player builds the same map.
That's the shape of the build. The detailed code breakdown and the full copy-paste file are below — members unlock them (become a member to get every premium tutorial and the source code).
How To Use It
- Reseed the world. Add
?seed=42to the URL. The same seed always builds the same mountains, valleys and arenas, so it's the one number multiplayer sends. - Tune the shaping. Change the octave count, ridged weight, warp strength or mask thresholds to go from rolling hills to jagged ranges.
- It drops into Part 1. Only
heightAtchanged. The chunk Map, pooling, trees, WASD character and follow camera are untouched. - Mobile. Pair it with my mobile on-screen character controller to drive the same
keysstate from touch. - Grass next. My endless procedural grass field (the one with the rigged capybara) recenters grass around the player. In Part 3 we sample this terrain's height so the grass follows the hills.
Coming up: Part 3 adds LOD, seam fixes, texture blending and the endless grass growing on this terrain. (Planned, not yet published.)
START WITH THE FREE ARTICLE
The Part 2 article explains the why: what a terrain heightmap is, how fBm, ridged noise and domain warping shape it, and where Super Soldier Battle's terrain is today. It's free to read.
Read the Terrain Heightmap ArticlePlay It and Keep Learning
See where this terrain is headed: play Super Soldier Battle free in your browser. Today's map is a fixed island, and endless procedural terrain is the next planned feature.
Need Three.js terrain, a game prototype or performance help on your project? I take freelance and contract work: contact me.
Play Game