More
Troubleshooting
The common problems, what causes them, and the fix for each.
The image is washed out or looks tone-mapped twice
water.render() tone-maps in its own composite. Leave renderer.toneMapping at THREE.NoToneMapping. If you switch to NatureGL Sky's post pass over renderHDR(), that path needs ACESFilmicToneMapping on the renderer, so set it per path the way NatureGL Island does.
No refraction, no depth foam, no underwater fog
You're drawing with renderer.render(scene, camera). The ocean still appears, but refraction, depth foam, screen-space reflections, bloom and every underwater effect need water.render() (or water.renderHDR()).
Particles, rain or glass disappear under the water
The world pass draws your whole scene before the water, so transparent objects end up under the surface. Put them on the overlay layer: mesh.layers.set(water.overlayLayer). See Transparent objects and the overlay layer.
Floating objects lag behind the waves on high and ultra
On FFT tiers sampleHeight reads the swell cascade back from the GPU, 1–3 frames late, and doesn't include the small chop. That's expected. If you need exact sampling, use a Gerstner source: setQualityLevel('high', { waveSource: 'gerstner' }).
A floating object spins or won't turn
Buoyancy sets the object's Euler order to 'YXZ' and writes only height, pitch and roll. Steer with rotation.y and move it with position.x and position.z. Don't write position.y yourself.
A ship's wake points the wrong way
The wake assumes the bow is along local +Z. Pass headingOffset (radians) for models built facing another way, or useVelocityHeading: true to follow the direction of motion.
Only some ships have wakes
Up to MAX_HULLS (8) wakes are drawn, and the console warns about extra ones. Remove wakes from hulls that are out of view with water.removeWake(ship).
Foam rings over a shallow shelf, or rings round a small islet
Update to 1.1, which limits shore trains to breaking depths, turns flat shelves into depth-limited bores and skips small land masses (shoreTrainMinRadius, default 40 m). You can also lower shoreWaves or shoreFoam. See Wide shelves and small islets.
The beach has no surf
Check the bathymetry: heightAt must be positive on land and negative under water, and bounds must cover the shore. Swash foam only appears where the depth buffer agrees with the baked seabed, so bake the same function that builds your terrain mesh.
setSky(skySystem) threw a TypeError
That was a 1.0 bug with NatureGL Sky's ambient shape. It's fixed in 1.1.
Nights with NatureGL Sky are too bright
Cap the sky's exposure: SkySystem.create({ …, maxExposure: 2.4, nightExposure: 5 }). With syncExposure (the default), the water uses the sky's displayExposure, so it follows. See Exposure.
Reflections or cloud shadows broke after changing NatureGL Sky's quality
The sky creates new env and shadow textures on a tier change. Re-plug it on its quality event: sky.addEventListener('quality', () => water.setSky(sky)).
The high tier looks like the medium tier
Your device may lack EXT_color_buffer_float, and the FFT tiers fell back to Gerstner waves. The console warns EXT_color_buffer_float missing, falling back to Gerstner waves, and water.fft is null.
The ocean ends before the horizon, or the sky is clipped
The built-in sky dome scales to 0.9 × camera.far. Use a far plane of several kilometres, for example 12000 as in the examples.
It runs slowly
Turn on water.profiling and read water.gpuTimings. World-pass MSAA is the biggest single cost on high ({ msaa: 0 }). See Quality and performance.