The pack
watermax
function watermax(opts: WatermaxOptions = {}): Pack<{ watermax: WatermaxApi }>
An FFT ocean with a physically based surface, foam, wakes, buoyancy, caustics, an ocean floor, spray, rain and an underwater post.
Functions
applyWaterPatch
function applyWaterPatch(target: WaterParams, patch: WaterParamsPatch): void
Merges a patch into live params, one group at a time.
assignCascadeBands
function assignCascadeBands(scales: readonly number[], resolution: number): CascadeBand[]
Assigns band edges to cascades given in input order, coarsest first (the caller orders them; there is no
re-sort). Each seam is the coarser cascade's Nyquist over the cross-fade ratio, which maximises the finer
grid's mode index at the handoff. When a finer cascade cannot reach its seam the gap is reported with
console.warn rather than hidden — the wavenumbers in between are unrepresentable on either grid.
bakeDistortionNoise
function bakeDistortionNoise(size = NOISE_SIZE, period = NOISE_PERIOD): Uint8Array
Bakes the tileable gradient noise the underwater distortion scrolls, as r8 with 0.5 at zero.
bakeSource
function bakeSource(s: WakeSource, dt: number): BakedSource | null
Turn a WakeSource into the capsule the reference generator stamps. The reference sweeps a disc of
radius from the previous position to the current one; here the disc becomes the hull's half-width and the
segment is extended along the heading by the hull's extra half-length, so the capsule runs from last frame's
stern to this frame's bow. A hull no longer than it is wide degenerates to the reference swept disc exactly.
The stamp is -depth * speed * SOURCE_GAIN / radius, so over the footprint-crossing dwell the added
displacement totals about depth whatever the speed; a longer hull dwells longer, so the stamp is scaled by
radius / (extraHalfLength + radius) to keep that trough depth. Returns null when the hull is stationary or
swept further than TELEPORT_THRESHOLD (a teleport, not travel).
-
s - the source.
-
dt - the frame time in seconds the velocity is integrated over.
bakeVoronoi
function bakeVoronoi(size: number, cells: number, seed: number): Uint8Array<ArrayBuffer>
Bakes the caustic lookup: R = nearest-cell distance F1, G = 1 - (F2 - F1) the cell edges. Tiles seamlessly.
buildClipmap
function buildClipmap(levels: number, segments: number, baseSize: number, infinityExtent: number): ClipmapMesh
Builds the geometry clipmap: an inner square, square rings doubling in size, T-junction skirts between
them, and a flat infinity ring out to infinityExtent. Vertices lie on regular grids so the mesh snaps
to the coarsest spacing without swimming.
buildIWaveKernel
function buildIWaveKernel(P = KERNEL_HALF): IWaveKernel
Build the iWave kernel G(k,l) = [sum_n q_n^2 exp(-sigma q_n^2) J0(q_n r)] / G0 with r = sqrt(k^2 + l^2)
and G0 the same sum at r = 0, so G(0,0) = 1. The numerator is computed once per distinct r squared.
Tessendorf recommends P = 6 as the minimum, but that truncates the operator's tail enough to run the longest waves about 60% fast; P = 10 (the default) holds true dispersion across the wake band within a few percent for a 21 by 21 stencil.
- P - kernel half-size; default
KERNEL_HALF.
cloneWaterParams
function cloneWaterParams(p: WaterParams): WaterParams
Deep copy of a preset for live editing.
createWakeSim
function createWakeSim(device: GPUDevice, opts: WakeSimOptions = {}): WakeSim
Create a wake field on device. The kernel is built and factorised once here (a few hundred milliseconds
of Bessel quadrature at P = 10); everything else is rebuilt as configure demands.
createWaveSim
function createWaveSim(device: GPUDevice, opts: WaveSimOptions = {}): WaveSim
Creates the simulation on device. Compiles the pipelines and allocates every cascade up front; nothing runs
until update. Throws RangeError on invalid options.
crestTransmission
function crestTransmission(c: WaterColorPhysical, pathLength: number): [number, number, number]
Sunlight transmission through a wave crest of pathLength metres, integrated to RGB.
deriveCascadeScales
function deriveCascadeScales(maxScale: number, resolution: number, count: number): number[]
The tile size of cascade index for one shared resolution: see deriveCascadeScale.
foldWaveTime
function foldWaveTime(time: number): number
Folds an absolute time in seconds into [0, WAVE_TIME_PERIOD_SECONDS); negative times wrap the other way.
hexRgb
function hexRgb(css: string): [number, number, number]
Parses a css hex colour into linear-ish 0..1 floats, the way the engine treats colours.
hullPoseFromHeights
function hullPoseFromHeights(bow: number, stern: number, port: number, starboard: number, length: number, width: number, offset = 0): { y: number; pitch: number; roll: number }
The pose a hull takes from the surface heights at its bow, stern, port and starboard samples: y their mean plus
offset, pitch nose-down positive (negative when the bow is higher) and roll positive when port is higher, both
radians, as world-3d's handles take them.
hullSamples
function hullSamples(at: { x: number; z: number; rot: number }, length: number, width: number): Array<[number, number]>
The four places a hull samples the water, as [x, z] world points: bow, stern, port and starboard, in that order.
inScatterReflectance
function inScatterReflectance(c: WaterColorPhysical): [number, number, number]
Deep-water in-scatter reflectance (Morel), integrated to RGB.
jonswapSpectrum
function jonswapSpectrum(x: number, y: number, p: SpectrumCellParams): { kx: number; ky: number; variance: number }
The banded per-mode variance Ψ(k,θ)·Δk²·window of cell (x, y) — everything the init shader computes
before the random draw. Returns the wave vector too. The DC cell is floored to |k| = 1e-4, as the shader does.
separableKernel
function separableKernel(kernel: IWaveKernel, rank = SEPARABLE_RANK): SeparableKernel
Rank-r separable approximation of the kernel. The kernel matrix is symmetric and radial, so it is numerically near-rank-2 (at P = 10 the leading eigenvalues are about 1.97, 0.34, 0.026): the top eigenpairs reproduce the operator to about 1% at rank 2, turning 441 taps per texel into 84. Because the matrix is symmetric each term's row and column factor is the same vector, applied horizontally then vertically.
-
kernel - the dense kernel from
buildIWaveKernel. -
rank - number of terms; default
SEPARABLE_RANK.
snapOmega
function snapOmega(omega: number): number
Snaps a natural angular frequency (rad/s) to the nearest multiple of WAVE_TIME_OMEGA_STEP. The
perturbation is at most π / period ≈ 3.84e-4 rad/s, under 0.2% for any visible wave; wavelengths are
untouched.
transmittanceLUT
function transmittanceLUT(c: WaterColorPhysical, size: number, lengthScale: number): Float32Array
Broadband RGB transmittance over a non-linear path-length axis: entry i is path -lengthScale * ln(1 - i / size).
Constants
COLOR_LUT_LENGTH_SCALE
const COLOR_LUT_LENGTH_SCALE: 20
Path length in metres at which the LUT axis reaches 1 - 1/e.
COLOR_LUT_SIZE
const COLOR_LUT_SIZE: 256
The transmittance LUT size and its length scale, shared with the shader.
CREST_PATH
const CREST_PATH: 3
Crest path length in metres for the transmission colour.
DEFAULT_WAKE_OPTIONS
const DEFAULT_WAKE_OPTIONS: Readonly<Required<WakeSimOptions>>
Every option's default.
DEFAULT_WAVE_OPTIONS
const DEFAULT_WAVE_OPTIONS: ResolvedWaveOptions
The defaults: the sunset reference set with three cascades of 1024, 96 and 9 metres at 256.
STORM
const STORM: WaterParams
A grey storm sea: strong wind, steep chop, heavy whitecaps.
SUNSET
const SUNSET: WaterParams
Golden-hour sea under a low sun: the sunset look.
TROPICAL
const TROPICAL: WaterParams
Clear tropical water: physical Oceanic IB colour, gentle wind, bright foam.
WATER_PRESETS
const WATER_PRESETS: Readonly<Record<WaterPresetName, WaterParams>>
The bundled presets by name.
WATER_QUALITY
const WATER_QUALITY: Readonly<Record<'low' | 'medium' | 'high' | 'ultra', WaterQuality>>
The built-in tiers, one per cost band.
Types
ClipmapMesh
interface ClipmapMesh
The clipmap as vertex positions (x, z pairs, y is 0) and a triangle index list.
positions: Float32Array— Interleaved x, z per vertex.indices: Uint32Array— Triangle indices.totalSize: number— Size of the outermost level in world units.coarsestSpacing: number— Vertex spacing of the coarsest level, the snap grid.
Floater
interface Floater
A floated object's controller.
readonly target: { x: number; y: number; z: number; rot: number; pitch: number; roll: number }— The object being floated.readonly spec: FloatSpec— The footprint; edit it live.kill(): void— Stop floating it.readonly dead: boolean— True after kill.
FloatSpec
interface FloatSpec
What a floated object needs: its footprint on the water.
length: number— Hull length, bow to stern along the object's forward (local +z, as world-3d's yaw points it), metres.width: number— Hull beam, port to starboard, metres.offset?: number— How far below the deck the waterline sits, metres: the object's y is the surface plus this. Default 0.damping?: number— Smoothing 0..1 applied per frame to the height and tilt; 1 snaps. Default 0.25.wake?: boolean— Cast a wake as it moves. Default true.wakeStrength?: number— Wake strength 0..1. Default 0.6.
MaskHandle
interface MaskHandle
A registered hull mask.
remove(): void— Stop masking; the water closes back over the hull next frame.
ResolvedWaveOptions
type ResolvedWaveOptions = Readonly<Required<Omit<WaveSimOptions, 'cascades'>> & { cascades: readonly number[] }>
WaveSimOptions with every field present.
SprayEmitter
interface SprayEmitter
A registered spray source.
readonly index: number— Slot 0..MAX_SPRAY_EMITTERS-1.readonly params: SprayEmitterParams— Live; edit in place.enabled: boolean— Whether this emitter's probes can fire; a disabled emitter keeps its slot. Default true.setProbes(points: ReadonlyArray<readonly [number, number, number]>): void— Probe points in the emitter's LOCAL space; more than MAX_SPRAY_PROBES are dropped.setWorld(m: Float32Array): void— Column-major 4x4 local-to-world matrix (m[12..14] = translation). Call every frame the object moves.remove(): void— Frees this emitter's slot for reuse; later calls on it do nothing, and the emitter is dropped from the system'semitterslist.
SprayEmitterParams
interface SprayEmitterParams
Per-emitter tunables; every burst freezes a copy at spawn, so edits reach only later bursts.
bottomFadeStart: number— Bottom-fade start, 0..1 of the billboard height; alpha is zero at and below it.bottomFadeStop: number— Bottom-fade stop, 0..1 of the billboard height; alpha is full at and above it.duration: number— Burst lifetime in seconds.fadeOutTime: number— Alpha tail in seconds, measured back from death; the flipbook completes before it starts.opacity: number— Opacity multiplier, 0..1.respawnTime: number— Extra cooldown in seconds after a burst's life before its probe may fire again.size: number— Billboard side in metres.spawnJitterTime: number— Most random delay in seconds between the trigger and the visible spawn.stretchX: number— Width multiplier.stretchY: number— Height multiplier.submersionDepth: number— Metres below the displaced surface the billboard's bottom edge sits, hiding the seam.velocityHeightFactor: number— Height multiplier per m/s of impact speed over the threshold, capped at 2x; 0 disables.velocityScaleFactor: number— Uniform scale per m/s of impact speed over the threshold, capped at 2x; 0 disables.velocityThreshold: number— Least vertical closing speed in m/s at the crossing for a probe to fire.
SprayHandle
interface SprayHandle
A bow-spray emitter riding a world-3d object.
readonly params: SprayEmitterParams— The emitter's live parameters.enabled: boolean— Pause the bursts without dropping the emitter.probes(points: ReadonlyArray<readonly [number, number, number]>): void— Replace the probes.remove(): void— Drop the emitter; its droplets finish their lives.
SpraySpec
interface SpraySpec
What spray() takes: where on the hull the water is sensed, and any emitter fields to override the preset's.
probes?: ReadonlyArray<readonly [number, number, number]>— Probe points in the object's local space (before its scale). Omitted: derived from its mesh — bow, stern and pairs down each side at the origin's height, where a floated hull meets the water.params?: Partial<SprayEmitterParams>— Fields that overrideparams.sprayfor this emitter.
WakeSim
interface WakeSim
A live wake field on one GPU device.
readonly field: GPUTextureView— The rg16float field texture: r = wake height in metres (already clamped toMAX_WAKE_HEIGHT), g = wake foam 0..1. Sample atuv = (worldXZ - origin) / worldSize + 0.5withWakeSim.sampler; the rim is sponged to zero so clamp-to-edge never shows a seam. Re-read afterconfigurechanges the resolution, since the texture is rebuilt.readonly sampler: GPUSampler— Clamp-to-edge, linear sampler forWakeSim.field.readonly origin: { x: number; z: number }— Field centre in world xz, snapped to texel multiples so the field never swims; the contents shift with it. Updated by eachupdate.readonly worldSize: number— Field extent, metres per side.readonly resolution: number— Field resolution, texels per side.configure(opts: WakeSimOptions): void— Apply new options; unspecified fields keep their current values.update(encoder: GPUCommandEncoder, dt: number, centre: { x: number; z: number }, sources: ReadonlyArray<WakeSource>): void— Encode this frame's step: recentre oncentre, injectsources(at mostMAX_WAKE_SOURCES; extra ones are dropped), advance the solver bydtseconds (clamped to the stability limit), and update the foam. Call once per command encoder, before the encoder is submitted: the uniforms are written through the queue and a second call before submit would overwrite them.destroy(): void— Release every GPU resource. The sim stays usable: a laterupdateorfieldread rebuilds a blank field.
WakeSimOptions
interface WakeSimOptions
Construction and reconfiguration options for createWakeSim.
resolution?: number— Field resolution in texels per side; default 512. Changing it rebuilds the field.worldSize?: number— Field extent in world metres per side; default 100 (the reference quality-tier default). Changing it clears the field.friction?: number— Velocity-damping friction, at least 0; default 0.25. Required for stability and sets the trail length.foamPersistence?: number— Persistent foam decay per frame, 0..1; default 0.99. Closer to 1 keeps the foam trail longer.foamStrength?: number— Foam injection rate for the hull track and breaking crests; default 0.8.foamBreakThreshold?: number— Surface steepness (height gradient magnitude) at which crest foam begins; default 0.gravity?: number— Gravity in m/s^2 the dispersion follows; default 9.81. Pass the ocean's value so the wake speed matches the swell.
WakeSource
interface WakeSource
One hull disturbing the field this frame.
x: number— World x of the hull centre, metres.z: number— World z of the hull centre, metres.vx: number— World velocity x, m/s.vz: number— World velocity z, m/s.length: number— Hull half-length in metres, along the heading.width: number— Hull half-width in metres; the footprint radius of the swept capsule.yaw: number— Heading yaw in radians, 0 along +x, measured toward +z.strength: number— 0..1 strength: how deep the hull sits, as a fraction ofDEPTH_PER_WIDTH * widthmetres.
WaterColorCustom
interface WaterColorCustom
Artist-authored colour: per-channel Beer-Lambert absorption, the transmitted crest colour, and the body colour.
mode: 'custom'— Colour mode.absorptionColor: string— Per-channel absorption coefficient, as a css colour; red dies fastest in clear ocean.transmissionColor: string— Colour of light transmitted through a wave crest, css.waterColor: string— Intrinsic in-scattered body colour, css.
WaterColorPhysical
interface WaterColorPhysical
Physical colour from constituent concentrations, integrated over the visible spectrum.
mode: 'physical'— Colour mode.algae: number— Phytoplankton concentration; greens productive water.silt: number— Mineral suspended sediment; brightens and mutes turbid water.stain: number— Coloured dissolved organic matter; browns stained water.
WaterFloorParams
interface WaterFloorParams
The ocean floor: a camera-following plane below the surface, displaced by noise, sand blending to rock with height.
enabled: boolean— Draw it at all. Default true.depth: number— Metres below the water's rest level.meshResolution: number— Grid cells along each edge of the plane; the plane spans the clipmap.tileSize: number— Metres of world one repeat of the textures covers, beforetextureScale.displacementScale: number— Metres per unit of the terrain noise: larger is broader features.displacementStrength: number— Metres of vertical displacement the noise adds.lacunarity: number— Noise frequency multiplier per octave (two octaves).persistence: number— Noise amplitude multiplier per octave.normalScale: number— How strongly the texture normal maps tilt the terrain normal.blendThreshold: number— Normalised terrain height (0 low, 1 high) where sand gives way to rock.blendSoftness: number— Width of that transition.textureDisplacementStrength: number— Metres of extra displacement from the textures' own relief.textureScale: number— Repeats of the textures pertileSize.causticDepthAttenuation: number— How fast the caustics on the floor fade with depth (0 none).
WaterFoamLayer
interface WaterFoamLayer
One foam texture layer.
enabled: boolean— Whether this layer draws.opacity: number— Master opacity 0..1.color: string— Foam tint, css.size: number— Texture size in world units.texture: 1 | 2 | 3— Which bundled foam texture: 1, 2 or 3.
WaterFoamParams
interface WaterFoamParams
The three foam sources.
surface: WaterFoamLayer & { coverage: number }— Texture-thresholded foam everywhere.waves: WaterFoamLayer & { windStretch: number; persistence: { decayTime: number; windwardStrength: number; crestStrength: number } }— Persistent wave-crest foam from the energy field.shoreline: WaterFoamLayer & { coverage: number; range: number }— Foam in shallow water against geometry.
WaterFogParams
interface WaterFogParams
Atmospheric fog on the water surface, for when no sky pack is fogging the scene.
color: string— Near fog colour, css.enabled: boolean— Whether the surface fogs itself.fadeStart: number— Distance where fog begins.fadeEnd: number— Distance where fog is total.fadePower: number— Curve power; 1 = linear.skyBlendDistance: number— Distance over which the fog colour reaches the sky colour.
WatermaxApi
interface WatermaxApi
game.watermax.
readonly params: WaterParams— The live parameters. Edit fields in place; the water follows next frame.apply(patch: WaterParamsPatch): void— Merge a partial set of parameters.preset(name: WaterPresetName): void— Replace everything with a bundled preset.readonly presets: ReadonlyArray<WaterPresetName>— The bundled preset names.level: number— Still water level, world y.probe(x: number, z: number): WaterProbe— Track a point's height on the GPU. Up to 128 points are read back each frame, one or two frames late.heightAt(x: number, z: number): number— Height of the surface at a point, from the nearest probe, or the still level when nothing is close.readonly submerged: boolean— True when the camera is under the surface.float(target: { x: number; y: number; z: number; rot: number; pitch: number; roll: number }, spec: FloatSpec): Floater— Float a world-3d object on the waves: four probes under its hull set its height, pitch and roll, and it casts a wake. A handle's yaw is its rot.wake(source: WakeSource): void— Push a wake source for this frame only, for something that is not floated. Itsyawis the wake's own heading, 0 along +x towards +z: an engine yawrotisrot + Math.PI / 2.quality(tier: WaterQualityName): void— Switch quality tier.readonly qualityLevel: WaterQualityName— The active tier.windDirection: number— Wind direction in radians, the spectrum's and the foam's.mask(target: { x: number; y: number; z: number; rot: number; pitch: number; roll: number; sx: number; sy: number; sz: number }): MaskHandle— Cut the water out of a hull: the object's mesh is drawn into a screen-space mask each frame and the surface behind its nearest face is discarded, so a deck stays dry however low the boat rides. Up to 64.spray(target: { x: number; y: number; z: number; rot: number; pitch: number; roll: number; sx: number; sy: number; sz: number }, spec?: SpraySpec): SprayHandle— Bow spray off a world-3d object: probes at its waterline watch the surface, and where one is driven through the water fast enough a burst of droplet billboards is thrown up, the spray system. Up to 16 emitters, 32 probes each.readonly stats: { readonly cascades: number; readonly vertices: number; readonly triangles: number; readonly probes: number; readonly sprayEmitters: number; readonly rainStreaks: number; readonly masked: number }— Counts for a profiler.
WatermaxOptions
interface WatermaxOptions
Manifest options for watermax. All optional.
preset?: WaterPresetName— Which bundled look to start from. Default 'sunset'.quality?: WaterQualityName— Quality tier: cascades, clipmap density, foam and wake field sizes, SSR. Default 'medium'.level?: number— Still water level, world y. Default 0.seed?: number— Deterministic seed for the spectrum phases. Default 1.foamUrls?: string[]— Foam texture URLs, three of them. Default 'assets/watermax/foam1.jpg' and so on.caustics?: boolean— Publish the caustic pattern for render-3d. Default true.causticFade?: number— How deep below the surface the seabed caustics fade out, metres. Default 25.causticGain?: number— Extra multiplier on the published caustic strength; the engine's seabed tap is brighter than the floor material was tuned for, so the default halves it. Default 0.5.underwater?: boolean— Render the underwater post pass. Default true.floorUrls?: { sand: string; sandNormal: string; rock: string; rockNormal: string }— Ocean floor textures: sand colour, sand normal, rock colour, rock normal. Default 'assets/watermax/sand.jpg' and so on.sprayUrls?: string[]— Spray flipbooks, up to eight 7×7 sheets. Default 'assets/watermax/splash1.jpg' … 'splash8.jpg'.
WaterParams
interface WaterParams
The whole ocean, as a preset stores it.
waves: WaterWaveParams— The spectrum.color: WaterColorCustom | WaterColorPhysical— Body colour.foam: WaterFoamParams— Foam layers.fresnel: { iorRatio: number; refractionStrength: number }— Refraction and the interface.sss: { enabled: boolean; intensity: number; power: number }— Subsurface scattering at backlit crests.sparkle: { enabled: boolean; intensity: number; power: number; minDistance: number; fadeDistance: number }— Sun glints.ssr: { enabled: boolean; strength: number }— Screen-space reflections of geometry.caustics: { enabled: boolean; intensity: number; scale: number; waveDistortion: number }— Seabed caustics, published for render-3d.fog: WaterFogParams— Surface fog.underwater: { tintColor: string; distortionEnabled: boolean; distortionIntensity: number; distortionScale: number; distortionSpeed: number; sunShafts: boolean; sunShaftIntensity: number; absorption: number }— Under the surface.wake: { friction: number; foamPersistence: number; foamStrength: number; foamBreakThreshold: number }— Boat wakes.clipmap: { baseSize: number; levels: number }— The clipmap.environment: number— Environment reflection multiplier.sunScale: number— The sun's strength on the water, a multiplier on the lighting record's intensity.floor: WaterFloorParams— The ocean floor: a displaced sand-and-rock plane that follows the camera below the surface.rain: WaterRainParams— Rain: falling streaks and the analytic ripple rings they leave on the surface.spray: WaterSprayParams— Bow spray: the defaults every emitter starts from.
WaterParamsPatch
type WaterParamsPatch = Omit<DeepPartial<WaterParams>, 'color'> & { color?: WaterColorCustom | WaterColorPhysical }
A recursive partial of WaterParams; color is replaced whole because its shape depends on the mode.
WaterPresetName
type WaterPresetName = 'sunset' | 'tropical' | 'storm'
Preset names.
WaterProbe
interface WaterProbe
A point on the sea the GPU keeps a height for.
x: number— World x of the probe; move it freely.z: number— World z of the probe.readonly y: number— Surface height at the probe from the last readback, world y.readonly normal: { x: number; y: number; z: number }— Surface normal at the probe from the last readback.kill(): void— Stop tracking it.readonly dead: boolean— True after kill.
WaterQuality
interface WaterQuality
Quality tiers for the water.
segments: number— Clipmap vertices per side per level.cascades: number— FFT cascade count.resolution: number— FFT resolution per cascade.foamFieldResolution: number— Foam field texels per side.foamFieldWorldSize: number— Foam field extent in metres.wakeResolution: number— Wake field texels per side; 0 disables the wake.wakeWorldSize: number— Wake field extent in metres.ssr: boolean— Screen-space reflections on.ssrSteps: number— SSR march cap.ssrMaxDistance: number— SSR reach in metres.shaftDiv: number— Sun shaft pass divisor.
WaterQualityName
type WaterQualityName = 'low' | 'medium' | 'high' | 'ultra'
Quality tier names.
WaterRainParams
interface WaterRainParams
Rain over the sea: streaks in the air and ripple rings on the surface, flat, one record.
enabled: boolean— Whether rain is drawn (streaks and ripple rings); when false the streak intensity is forced to 0.color: string— Streak colour.intensity: number— How much of the streak pool falls, 0..1.fadeDistance: number— Metres from the camera where streaks are fully faded.streakLength: number— Streak length in metres.streakWidth: number— Streak width in metres.speed: number— Fall speed multiplier.opacity: number— Streak opacity.rippleDecay: number— How quickly rings fade, 0.1..5.rippleDensity: number— Rings per area, 0..1.rippleFadeEnd: number— Metres from the camera where rings are fully faded.rippleSize: number— Ring cell size in metres, 0.1..1.rippleStrength: number— How much the rings tilt the surface normal, 0..1.
WaterSprayParams
interface WaterSprayParams
Bow spray defaults: what every emitter is born with unless spray() overrides a field.
enabled: boolean— Master switch for all bow spray; when false no emitter fires, whatever its ownenabledsays.bottomFadeStart: number— Bottom-fade start, 0..1 of the billboard height; alpha is zero at and below it.bottomFadeStop: number— Bottom-fade stop, 0..1 of the billboard height; alpha is full at and above it.duration: number— Seconds a droplet lives.fadeOutTime: number— Seconds of the end of that life spent fading.opacity: number— Opacity multiplier, 0..1.respawnTime: number— Seconds a probe rests after a burst.size: number— Billboard height in metres.spawnJitterTime: number— Seconds of random delay before a burst.stretchX: number— Billboard width multiplier.stretchY: number— Billboard height multiplier.submersionDepth: number— Metres the billboard's foot sits below the surface.velocityHeightFactor: number— Height multiplier per m/s of impact speed over the threshold, capped at 2x; 0 disables.velocityScaleFactor: number— Uniform scale per m/s of impact speed over the threshold, capped at 2x; 0 disables.velocityThreshold: number— Impact speed (m/s) a probe must cross the surface at to burst.
WaterWaveParams
interface WaterWaveParams
The FFT ocean's spectrum knobs.
amplitude: number— Overall height multiplier. Default 1.animationSpeed: number— Time multiplier on the wave motion. Default 1.windSpeed: number— Wind speed in metres per second; energy and steepness at the peak wavelength.windDirection: number— Wind direction in radians, 0 = +x.choppiness: number— Horizontal displacement multiplier: sharper crests.peakWavelength: number— Dominant wavelength in metres, the JONSWAP spectral peak.spectralSharpness: number— Directional spread multiplier; above 1 narrows waves toward the wind.standingWaveRatio: number— 0 = travelling waves, 1 = standing.maxScale: number— Largest cascade tile in metres; the finer tiles derive from it.
WaveCascade
interface WaveCascade
One cascade's outputs. Sample both textures at uv = worldXZ / scale + 0.5 with the sim's repeat sampler.
readonly scale: number— Tile size in metres; the textures repeat everyscalemetres of world xz.readonly displacement: GPUTextureView— rgba16float, res×res, no mips.xyz= world displacement in metres of the grid point at that texel (x, y = height, z — y already negated for sharp crests, x/z already multiplied by choppiness),w = 1.readonly normal: GPUTextureView— rgba16float, res×res, full mip chain.rgb = worldNormal · 0.5 + 0.5(y up);ais the directional eigenvalue:1 − clamp(1 − λmin, 0, 1) · edgeFactorwhereλminis the smaller eigenvalue of the horizontal Jacobian andedgeFactorgates it to wind-facing slopes. 1 is unfolded;1 − ais foam.
WaveSim
interface WaveSim
A running FFT ocean. Create with createWaveSim.
readonly cascades: ReadonlyArray<WaveCascade>— The cascades, coarsest first. Replaced (new views) after aconfigurethat changes resolution or cascade count.readonly sampler: GPUSampler— Repeat both ways, linear mag/min, linear mipmaps, anisotropy 8.readonly resolution: number— Grid resolution of every cascade.readonly options: ResolvedWaveOptions— The options in force.readonly sharedFft: boolean— True when the FFT runs in workgroup memory on this device; false means the global-memory fallback.configure(opts: WaveSimOptions): void— Applies new options. Spectrum-shaping changes re-run the spectrum init on the nextupdate; a resolution or cascade-count change rebuilds every GPU resource (andcascades). Same values: no work. Throws RangeError on invalid values, likeresolveWaveOptions.update(encoder: GPUCommandEncoder, time: number): void— Encodes this frame: (init if dirty) → time evolution → FFT → normalise → normals → texture copies → mips, then the height sampler if points were requested.timein seconds;animationSpeedand theWAVE_TIME_PERIOD_SECONDSfold are applied inside. Also queues the uniform writes.requestHeights(points: Float32Array): void— Queues up toMAX_SAMPLE_POINTSworld xz points (x0, z0, x1, z1, …) for GPU sampling in the nextupdate. Extra points are dropped; a second call beforeupdatereplaces the first.readHeights(): Float32Array | null— The heights (y, metres) of the most recently landed request, one per point in order, or null before any lands.readSamples(): Float32Array | null— The full sample of the most recently landed request: 4 floats per point,height, nx, ny, nz, or null.afterSubmit(): void— Call afterqueue.submiteach frame: starts the async readback of any sample copied this frame. Never throws.destroy(): void— Releases every GPU resource; every later call is a no-op.
WaveSimOptions
interface WaveSimOptions
Configures a WaveSim. Every field is optional; see DEFAULT_WAVE_OPTIONS for the defaults.
resolution?: number— Grid resolution per cascade: a power of two in 128..512. Default 256. Throws RangeError otherwise.cascades?: number[]— Cascade tile sizes in metres, coarsest first, 1..4 of them. Default:deriveCascadeScales(1024, resolution, 3), i.e. 1024, 96, 9 at 256.windSpeed?: number— Wind speed in m/s; scales the JONSWAP energy at the peak wavelength. Default 2.5.windDirection?: number— Wind direction in radians (0blows along+x). Default 3.9618974020271276.choppiness?: number— Horizontal displacement multiplier; above ~1.5 crests fold and foam. Default 1.51.peakWavelength?: number— Dominant wavelength in metres — the spectral peak. Default 20.spectralSharpness?: number— Directional-spread multiplier: 1 physical, above narrows toward the wind. Default 1.46.standingWaveRatio?: number— 0 travelling waves … 1 standing waves. Default 0.23.amplitude?: number— Global height and displacement multiplier. Default 1.animationSpeed?: number— Multiplier on the time passed toupdate. Default 1.seed?: number— Deterministic seed of the Gaussian spectrum; cascadeiusesseed + i. Default 1.gravity?: number— Gravity in m/s². Default 9.81.jonswapGamma?: number— JONSWAP peak-enhancement γ. Default 3.3.foamWindBias?: number— 0 folds foam on both faces equally, 1 only on the wind-facing leading edge. Default 1.foamLeadingEdgeScale?: number— Sharpness of the leading-edge gate (the smoothstep width is0.1 ×this). Default 2.


