Guides
Lightning and thunder
Branching bolts, multi-pulse flashes that light your scene and the fog, and thunder that arrives when sound would. Strikes fire on their own at a rate you set, or on demand, and every one raises an event.
thunderstorm at night: three weather.strike() calls at 140, 260 and 190 m on top of the preset's automatic strikes. The flash lights the cobbles, the rain and the fog around the bolt.#Automatic strikes
weather.set({ lightning: 0.5 }); // 0 = manual strikes only, 1 = a stormlightning (0–1) is the strike frequency. Above 0.05, strikes fire automatically. The gap between them is lerp(22, 2.5, lightning) seconds, randomised ×0.4 to ×1.6: about every 22 s at the low end and every 2.5 s at 1. thunderstorm uses 0.85. Loading a preset with lightning > 0 arms the first strike 1.5 s later, so a storm starts promptly.
Lightning also raises state.cloud to at least state.lightning.
#Strike on demand
weather.strike(); // random, roughly ahead of the camera
weather.strike({ distance: 150 }); // random direction, 150 m away
weather.strike({ position: new THREE.Vector3(80, 0, -200) }); // this ground pointWithout a position, the bolt lands 110–370 m from the camera (lightning.minDistance / maxDistance), within about ±46° of where the camera faces. Its top is 85–125 m above the ground point. strike() works at any lightning value, including 0.
#Events
const off = weather.on('strike', e => {
console.log(`strike ${e.distance.toFixed(0)} m away, thunder in ${e.delay.toFixed(1)} s`);
});
weather.on('thunder', e => shakeCamera(120 / e.distance)); // when the sound arrives
off(); // unsubscribeBoth events carry the same StrikeEvent:
| Field | |
|---|---|
position | Ground point of the bolt (Vector3) |
top | Cloud end of the bolt |
direction | Unit vector from the camera to top |
distance | Metres from the camera, horizontally |
delay | Seconds until the thunder: distance / 343 |
'strike' fires immediately. 'thunder' fires delay seconds later, from inside update().
#The flash
Each strike is four pulses over about half a second: full strength, then 0.55, 0.85 and a random last one, each decaying fast. The flash ends 1.5 s after the strike.
| Output | |
|---|---|
weather.lightning.flash | Current flash, 0 to about 1.5 |
weather.lightning.flashDirection | Unit vector from the camera to the last bolt's top |
weather.lightning.thunderIn | Seconds until the last strike's thunder (negative once it has arrived) |
weather.lightning.lastStrike | The last StrikeEvent, or null |
weather.lightning.flashLight | The flash DirectionalLight (intensity = flash × 7), or null |
weather.lightning.flashHemi | The flash HemisphereLight (intensity = flash × 2.2), or null |
The flash also lights the rain and snow, and in weather.render() it lights the fog volume around the bolt.
#Flash your own lights
Pass lights: false to create() if you'd rather light the scene yourself. Then read flash every frame:
const weather = await WeatherSystem.create({ renderer, scene, camera, lights: false });
renderer.setAnimationLoop(() => {
weather.update(dt);
stormLight.intensity = weather.lightning.flash * 5;
skyMaterial.uniforms.flash.value = weather.lightning.flash; // light your own clouds
weather.render();
});The demo sky does exactly this with sky.setFlash(weather.lightning.flash, weather.lightning.flashDirection).
#Thunder
Thunder audio is synthesized noise, low-passed more for distant strikes, and quieter with distance. It needs a user gesture before the browser will play it:
button.addEventListener('click', () => weather.audio.unmute());
weather.audio.volume = 0.5; // master volume, default 0.7
weather.audio.mute();The same WeatherAudio plays the rain hiss and the gusting wind. It's muted by default.
drizzle to thunderstorm with one loadPreset call. The wind picks up, the time eases to 21:30, and the first automatic strike follows 1.5 s after the call.