Reference
API reference
Everything exported from src/index.js and build/index.js. Types are in build/*.d.ts. Units are metres, seconds and radians, and colours are linear RGB.
import {
WeatherSystem,
RainSystem, SnowSystem, LightningSystem, FogSystem,
SurfaceWeather, WeatherAudio, OcclusionMap, WeatherPipeline,
createWeatherUniforms, MAX_LOCAL_LIGHTS,
PRESETS, PRESET_LABELS, getPresetParams, QUALITY_LEVELS,
} from 'naturegl-weather';Wherever a colour is accepted (ColorLike), you can pass a THREE.Color, a THREE.Vector3 or an [r, g, b] array.
#WeatherSystem
WeatherSystem.create(options): Promise<WeatherSystem>static asyncBuilds every subsystem, adds the particle meshes (and, by default, the flash lights) to options.scene, applies the quality level and applies the preset instantly. new WeatherSystem(options) does the same synchronously.
| Option | Type | Default | |
|---|---|---|---|
renderer | THREE.WebGLRenderer | — | Required. WebGL2 with EXT_color_buffer_float for render() |
scene | THREE.Scene | — | Required. Particles, the bolt and the flash lights are added here |
camera | THREE.PerspectiveCamera | — | Required. Rain and snow follow it |
quality | 'low', 'medium', 'high', 'ultra' | 'high' | See Quality levels |
preset | string or WeatherPreset | 'clear' | Applied instantly |
lights | boolean | true | Add a flash DirectionalLight and HemisphereLight for lightning |
occlusion | { size, resolution, follow, floor } | 80, 512, true, 0 | The top-down occlusion map |
managePixelRatio | boolean | false | Let setQualityLevel() cap renderer.setPixelRatio() at the tier's pixelRatio |
layer | number | — | 1.1 Render layer for the particle meshes. See setLayer |
#Frame
weather.update(dt): voidmethodCall once per frame, after moving the camera. dt is in seconds and clamped to 0.1. It reads the camera's current transform, eases the weather toward the targets, gusts the wind, accumulates wetness and snow, fires automatic strikes and the thunder events, drives the fog and the audio, and re-renders the occlusion map when it needs it.
weather.render(target?): voidmethodRenders scene through the weather pipeline: HDR scene → volumetric fog at reduced resolution → puddle SSR and fog composite → bloom → exposure × ACES → target (a WebGLRenderTarget) or the screen when null. It replaces renderer.render(scene, camera) and is optional. Leave renderer.toneMapping at its default when you use it. See Render paths.
weather.resize(): voidmethodCall after the canvas size or pixel ratio changes. render() also detects size changes on its own.
weather.dispose(): voidmethodRemoves the meshes and lights, frees GPU resources and closes the audio context.
#Parameters and presets
weather.loadPreset(preset, { instant? }): voidmethodEases to a built-in preset by name, or to a partial WeatherPreset (missing keys come from clear). wetness and snowCover ease over about 4.5 s, then natural accumulation resumes. A preset with lightning > 0 arms a strike 1.5 s later. instant: true snaps everything. Throws on unknown names.
weather.set(values, { instant? }): voidmethodSets any subset of the targets. wetness and snowCover go through wetness.force() (or setImmediate() with instant).
weather.getParams(): WeatherPresetmethodThe targets plus the current wetness and snow cover, rounded to 3 decimals. JSON-ready, and usable as a preset.
weather.setQualityLevel(level): voidmethodSwitches tier at runtime: particle counts, fog and SSR steps, fog resolution, shelter taps and the shadowLight's shadow map size. Throws on unknown levels. Read the current level from weather.quality.
| Property | |
|---|---|
params: WeatherPreset | The targets |
state: WeatherPreset & { gust, daylight } | The eased values in use |
transitionRate: number | Easing speed in 1/s (default 0.9) |
exposure: number | Base exposure for render() (default 1.4), multiplied by the preset's exposure |
quality: string | Current quality level |
time: number | Seconds of weather time, advanced by update |
#Composition
weather.patchMaterial(material, { ground?, sway? }): MaterialmethodAdds wetness, raindrop ripples, snow cover and shelter to a MeshStandardMaterial or MeshPhysicalMaterial, and returns it. ground: true adds puddles, the full snow blanket and SSR reflectivity. sway: true bends vertices above y = 0.6 m with the wind. Chains an existing onBeforeCompile, and is idempotent. See Wet surfaces.
weather.setOccluders(objects): voidmethodThe objects that block rain and snow: an array, one object, or null for every visible mesh. They must be in the scene. Objects with userData.weatherOccluder = false are always skipped. Re-renders the occlusion map.
weather.setLayer(layer): thismethodsince 1.1Calls layers.set(layer) on the particle meshes (layer 0–31). The same as the layer option of create(). Next to NatureGL Water use water.overlayLayer. The camera must see that layer if you render with renderer.render() or weather.render() yourself.
weather.setLighting(lighting): voidmethodFeeds your scene's light to the particles, the fog and the snow glints. Every field is optional, and it's cheap enough to call every frame.
| Field | |
|---|---|
sunDirection | Unit vector toward the key light (sun or moon) |
sunColor, sunIntensity | Key light radiance. sunIntensity defaults to 1 |
ambient | Ambient radiance for the particles, and for the fog when no sky colours are given |
skyHorizon, skyZenith | Sky colours for SSR misses, the fog tint and a derived ambient. Only applied as a pair |
daylight | 0–1 drying speed. Defaults to a value derived from sunDirection.y |
localLights | Up to 4 THREE.PointLights or { position, color, intensity }, read every frame. Contribution = colour × intensity × localLightScale (1/14) |
shadowLight | A shadow-casting DirectionalLight for shadowed fog shafts. Its shadow map size follows the quality tier |
weather.strike(options?): StrikeEventmethodA lightning strike now. options.position is a ground point, or options.distance a distance in a random direction roughly ahead of the camera. See LightningSystem.
weather.on(type, callback): () => voidmethodSubscribes to 'strike' (immediately) or 'thunder' (when the sound arrives). Returns an unsubscribe function.
| Property | |
|---|---|
particleMeshes: Object3D[] | 1.1 Rain streaks, splashes, snow and the bolt |
uniforms | The shared uniform block, bound by reference in every weather shader and patched material (advanced) |
localLightScale: number | Local light contribution scale (default 1/14) |
pipeline: WeatherPipeline | null | Created by the first render() |
rain, snow, lightning, fog, wetness, audio, occlusion | The subsystems, below |
#Subsystems
Each subsystem can be constructed on its own. It then creates its own uniforms with createWeatherUniforms() and needs the camera in update(dt, camera). Inside a WeatherSystem they share the facade's uniforms and are updated for you.
#RainSystem
new RainSystem({ scene, uniforms?, maxDrops?, maxSplashes? })classInstanced streaks in a 36 × 26 × 36 m box around the camera, and splashes on the occlusion surface within 16 m. maxDrops defaults to 90000 and maxSplashes to 2400.
| Member | |
|---|---|
intensity | 0–1 (set by the facade from state.rain) |
dropCount, splashCount | Instances at intensity 1, from the tier |
splashes | Splashes on or off |
snowCover | 0–1. Splashes fade with it and hide above 0.9 |
opacity | Streak brightness (default 0.32) |
streakLength | Streak length multiplier (default 0.55) |
mesh, splashMesh | The two instanced meshes |
setQuality(q), update(dt, camera?), dispose() |
#SnowSystem
new SnowSystem({ scene, uniforms?, maxFlakes? })classSwaying billboard flakes in a 34 × 22 × 34 m box. maxFlakes defaults to 42000.
| Member | |
|---|---|
intensity | 0–1 |
flakeCount | Flakes at intensity 1, from the tier |
flakeSize | Flake radius in metres (default 0.022) |
mesh | The instanced mesh |
setQuality(q), update(dt, camera?), dispose() |
#LightningSystem
new LightningSystem({ scene, camera, uniforms?, lights? })classBranching bolts, multi-pulse flashes, automatic strikes and thunder timing. lights defaults to true.
| Member | |
|---|---|
frequency | 0–1 automatic strike rate. Off at 0.05 and below |
minDistance, maxDistance | Random strike range, 110 / 370 m |
strike({ position?, distance? }) | Strike now. Returns the StrikeEvent |
on('strike' | 'thunder', cb), off(type, cb) | Events. on returns an unsubscribe function |
flash | Current flash, 0 to about 1.5 |
flashDirection | Unit vector from the camera to the last bolt's top |
thunderIn | Seconds until the last thunder (negative once it has arrived) |
lastStrike | The last StrikeEvent, or null |
flashLight, flashHemi | The flash lights, or null with lights: false |
scheduleSoon(seconds = 1.5) | Arm the next automatic strike |
mesh | The bolt mesh |
StrikeEvent is { position, top, direction, distance, delay }, with delay = distance / 343.
#FogSystem
new FogSystem({ scene?, uniforms? })classMaps the weather to height-fog values, and drives scene.fog when the pipeline isn't used.
| Member | |
|---|---|
density | Extinction at the fog base, 1/m |
height | Exponential height falloff, m |
baseHeight | World height where the fog is densest (default 0) |
lightIntensity | In-scattering multiplier (from fogLight) |
rays | Shadowed shafts on or off |
maxDistance | Raymarch distance (default 170 m) |
visibility | Read-only: 3 / density, in metres |
sceneFog | 'auto' (default), true or false |
windOffset | Fog drift, advanced by the wind |
#SurfaceWeather
new SurfaceWeather({ uniforms? })classThe wetness and snow model, and the material patch behind weather.patchMaterial.
| Member | |
|---|---|
wetness, snowCover | 0–1, current |
puddles | Puddles on or off |
rate | Accumulation speed multiplier (default 1) |
force(wetness, snowCover = null, seconds = 4.5) | Ease toward these values, then resume. null leaves one alone |
setImmediate(wetness, snowCover) | Jump there now |
patchMaterial(material, options) | See weather.patchMaterial |
setQuality({ shelterTaps }) | Recompiles the patched materials |
materials | Set of patched materials |
#WeatherAudio
new WeatherAudio()classSynthesized rain hiss, gusting wind and distance-filtered thunder (WebAudio, no assets). Muted by default.
| Member | |
|---|---|
unmute() | Start or resume. Call from a user gesture |
mute(), setEnabled(on) | |
muted | true until unmute() |
volume | Master volume, 0–1 (default 0.7) |
update(rain, wind, gust), thunder(delay, distance) | Called by the facade |
context | The AudioContext, created on the first unmute() |
dispose() |
#OcclusionMap
new OcclusionMap({ renderer, scene, uniforms?, size?, resolution?, top?, depth?, follow?, floor? })classA top-down depth map around the camera. Defaults: size 80 m, resolution 512, top 40 m, depth 60 m, follow true, floor 0.
| Member | |
|---|---|
setOccluders(objects) | Restrict the map to these objects, or null for the whole scene |
exclude | Set of objects never drawn into the map |
needsUpdate | Set true to re-render on the next update |
render() | Re-render now |
update(camera) | Re-centres when the camera leaves the middle 40 % |
setFloor(y) | Height returned where nothing was drawn |
center, baseY, depthTexture |
#WeatherPipeline
weather.pipelineWeatherPipelinepropertyCreated by the first weather.render().
| Member | |
|---|---|
exposure | Written by weather.render() every frame: set weather.exposure instead |
exposureAdapt | Exposure easing, 1/s. weather.render() keeps it at 2 |
bloomStrength, bloomThreshold | 0.35, 1.2 |
ssr | Puddle SSR on or off |
shadowLight | From setLighting |
skyHorizon, skyZenith | Vector3 sky colours for SSR misses |
setQuality(q), resize(), render(scene, camera, dt, target) |
#Other exports
| Export | |
|---|---|
PRESETS | Record<string, WeatherPreset>, the seven built-in presets |
PRESET_LABELS | Display names, such as 'Foggy Dawn' |
getPresetParams(name) | A deep clone. Throws on unknown names |
QUALITY_LEVELS | Record<level, QualitySettings>. See Quality levels |
MAX_LOCAL_LIGHTS | 4 |
createWeatherUniforms() | A fresh shared uniform block, for standalone subsystems |