Building an open world in the browser, part 27: An island from noise, ground that looks like ground
By Oleg Sidorkin, CTO and Co-Founder of Cinevva
New here? Use the series guide. It explains what a spike is and links all parts.
Part 26 put water on the world. This part builds the land under it, in two stages that mirror how a real place comes to be. Spike 54 is the terrain itself: not sculpted by hand but grown from noise, then weathered until it has the drainage and the coastline of somewhere that water has actually run across. Spike 55 is the skin on that terrain: solving the problem that defeats almost every procedural ground, which is that a tiled texture looks tiled. The two together answer one question, can a creator get a plausible island and ground that reads as ground without an artist touching either, and the answer is yes if you copy the right recipes.
A coastline that noise alone won't give you
Open Spike 54 in a new tab ↗ · View source
The heightmap follows the Red Blob Games recipes, which are a stack of small transforms each fixing a specific flaw in raw noise. Fractional Brownian motion sums several octaves of Perlin noise so the terrain has both broad hills and fine detail, but plain FBM looks soft and grid-aligned, so the sample point gets domain-warped first: you offset each coordinate by another noise field,
That gets you a shape, but it's a noise shape. It has no rivers, no valleys cut by water, no sediment fans, because nothing has ever flowed across it. The fix is hydraulic erosion, ported from Sebastian Lague's MIT-licensed implementation. Thousands of water droplets spawn at random and roll downhill, each carrying inertia so it doesn't make hard right-angle turns, picking up sediment when it speeds up and depositing it when it slows or pools, with a precomputed circular brush spreading each erosion event over a small radius so the carve is smooth rather than a one-pixel scratch, and evaporation that retires the droplet over its lifetime. Run enough droplets and the terrain grows the thing noise can't fake: drainage networks that converge, valleys that widen downstream, and flats where sediment settled.
Erosion on the GPU, and rivers that know where they are
The CPU erosion is correct but slow, so the spike also ports it to a WebGPU compute shader, and the interesting part is what GPU atomics force on you. Heights are stored as fixed-point i32 with a scale of one million, because WGSL has no atomic add on floats, and the only way thousands of droplets can deposit and remove sediment from the same cell in parallel without races is atomicAdd and atomicSub on integers. The fixed-point round-trip means a cell can occasionally go slightly negative under heavy concurrent drag, which is harmless and clamped on readback. The CPU version precomputes a per-cell brush table, but at a
Two more passes turn weathered terrain into a readable map. Drainage uses the Red Blob D8 flow-accumulation method: drop one unit of rain on every cell, sort all cells by elevation descending, and pass each cell's accumulated water to its single lowest neighbor, so water piles up along the natural valleys, and any cell whose accumulation crosses a threshold is marked river. The catch is that an eroded heightmap has pits, local depressions with no downhill exit, and water entering a pit just stops, breaking the accumulation. So before drainage runs, Planchon-Darboux pit filling raises each pit to just above its lowest neighbor,
The tile that won't stop repeating
Open Spike 55 in a new tab ↗ · View source
A terrain needs a material that covers kilometers from a texture that's a couple of meters across, and the moment you scale a tile up to cover ground, the eye locks onto the repetition. Spike 55 is an A/B bench of four sampling modes on the same geometry and lighting, so the only variable is how the texture is read. The baseline is plain: one sample at the scaled UV, which tiles obviously every few meters and exists only as the thing to beat. The free PBR layers come from Poly Haven over their CDN, diffuse plus the packed ARM map (ambient occlusion, roughness, metalness) plus a GL normal, all CC0, loaded with anisotropy 8 and mipmaps.
The interesting three are different attacks on the repeat. The hex-linear mode is the Heitz-Neyret triangle grid: lay a skewed triangular lattice over the surface, and each fragment sits inside one triangle whose three vertices each take a randomly offset tap, blended by barycentric weights so neighboring regions sample different parts of the texture and the large-scale tiling dissolves. But a plain linear blend of three taps averages their colors at the triangle edges, which leaves a visible triangular pattern, the exact artifact spike 48 ran into. The hex-vp mode is the published fix from the same 2018 paper: after the barycentric sum, subtract the texture's mean color, rescale by the inverse square root of the sum of squared weights to hold variance constant, then add the mean back. That keeps contrast steady across the blend so the triangles vanish, which is why the material does a 1-by-1 readback of each loaded texture to estimate its mean color up front. The fourth mode, iq-untiled, is Inigo Quilez's Texture Repetition technique 3: two offset taps blended by a low-frequency variation pattern, only two samples instead of three and no triangle structure to begin with, the cheap option that holds up.
On top of any mode sits optional triplanar projection, which is what lets the same material wrap a cliff without stretching. Instead of one UV, the shader samples three world-axis projections, the X-facing surfaces read the YZ plane, Y reads ZX, Z reads XY, and blends them by abs(normalWorld) raised to a sharpening power between four and eight so a 45-degree slope doesn't ghost all three projections into mush. The bench makes the tradeoff legible: variance-preserving hex blending is the quality winner and Quilez's two-tap is the performance-conscious one, and both beat plain by a wide enough margin that no creator should ever ship the plain tile.
Technology referenced in this chapter
Recipe-stacked heightmap generation. Red Blob Games recipes compose raw noise into terrain: domain-warped FBM (
Hydraulic erosion, CPU and GPU. Sebastian Lague's droplet model (inertia, carrying capacity, a precomputed circular deposit brush, evaporation) carves real drainage that noise can't fake. The WebGPU compute port stores heights as fixed-point i32 at a scale of one million so droplets can atomicAdd/atomicSub the same cell in parallel, recomputes each droplet's brush on the fly to avoid a ~100 MB table at
D8 drainage with pit filling. Red Blob D8 flow accumulation drops one unit of rain per cell, sorts cells by descending elevation, and passes water to each cell's lowest neighbor, marking rivers above a threshold. Planchon-Darboux pit filling first raises every local depression to
Breaking texture tiling four ways. On identical geometry and lighting: plain (one tap, tiles obviously), hex-linear (Heitz-Neyret triangle grid, linear blend leaves a triangle pattern), hex-vp (the EGSR 2018 §3.3 variance-preserving fix that subtracts the mean, rescales by inverse-sqrt of squared weights, and re-adds the mean, needing a 1×1 mean readback per texture), and iq-untiled (Inigo Quilez two-tap technique 3). Triplanar projection samples three world-axis planes blended by abs(normalWorld) to a power of 4-8 so cliffs don't stretch. Variance-preserving wins on quality, two-tap on cost. See terrain materials.
Part 27 of 29. Previous: Part 26 - Three ways to make water Next: Part 28 - Grass to the horizon, and ground that hides itself Series guide: /blog/2026-02-25-open-world-browser-series-guide