Waterfall material
<WaterfallMaterial> is the material of the mesh it sits in. The mesh is a drawn part, so it stands inside <Views> in a Landscape, as Logic and views says. It draws the mesh as falling water: streaks that run down it, a band of foam at its lip and one at its foot where the water lands. The streaks run on the effects’ clock, as the water material’s waves do: the devtools’ pause and a pausing modal hold them, and the devtools’ speed leaves them at the wall clock’s pace.
Its props are in WaterfallMaterialProps.
The sheet’s texture coordinates say which way the water falls. u runs across the sheet, and the water falls from the lip at v = 1 to the foot at v = 0, as a planeGeometry stood upright has them. A curved sheet that keeps those coordinates bends the fall with it. The streaks and the foam bands are sized in metres, measured off the mesh as it draws, its scale included, so a sheet stretched taller keeps its streaks’ size. The foot’s foam follows v = 0 wherever the sheet ends. A mesh with no texture coordinates throws in development, naming the fix.
The material is three’s standard material with its colour and roughness spliced in, as the water material’s is. The scene’s sun, fill, fog, exposure and tone mapping fall on it, and the sheet keeps its own normals. It is opaque and draws both sides, in one pass. The material prop takes a ModelMaterial, the game’s function over it, the way a map’s sea takes one, to make it see-through or to draw one side. Under WebGPU the fall draws nothing, as the WebGPU page lists.
Unity’s production water sample and Unreal’s water examples draw a fall as a material on a mesh, with particles beside it, and Roblox draws one with a scrolling Beam. Here the fall is a material on the game’s own sheet, so the game shapes the fall and the engine lights it as it lights its water. A round pool to land in is a water material with round, and a moat or a river one without it. A splash and a mist at the foot are particles: the asset library’s waterfall-splash and waterfall-mist effects play under an Emitter at the foot, or a game’s own.
Speed and flow
Section titled “Speed and flow”fallSpeed’s default of 4 m a second suits a fall of a metre or two. Water reaches about 10 m a second after a 5 m drop, so a tall fall reads right at 7 to 10.
The material has no flow amount. To turn a fall on, off or down to a trickle, scale its sheet, or a group it hangs from with the pivot at the lip: the streaks keep their size, since they are measured in metres as the sheet draws. A frame callback that scales it runs on the frame’s own time, not the effects’ clock, so the devtools’ pause holds the streaks but not the scaling.
Streaks
Section titled “Streaks”streakWidth and streakLength size the streaks in metres. Left out, a streak is five times as long as it is wide, which reads as broken water up close. A fall seen from far, such as from a tycoon or strategy camera, reads as long white lines: Juice Island’s draws streaks 0.16 m wide and 2.6 m long on a fall 11 m tall. The length changes no work the shader does, so it costs nothing to set.
A fall is one draw, and its pool another. Juice Island’s fall, 9.2 m tall, and its pool, 5 m across, were measured on 2026-10-14 from its core camera at Low, on an 852 by 393 page with an RTX 3070:
- With them: a frame’s mean time of 7.11 ms, and the main thread’s 3.74 ms.
- Without them: 7.06 ms and 3.29 ms.
Both differences sit inside one run’s noise with vsync on.
A splash and a mist cost more than the sheet. Juice Island’s fall with the library’s splash and mist, and its fountain’s streams, three pools, jet and glints, were measured on and off on 2026-10-15, from the same camera with vsync off, interleaved twice on a bench 54 to 67% busy:
- With them: 73 draws, a GPU frame of 2.92 and 3.46 ms mean, and a main thread of 4.18 and 4.97 ms.
- Without them: 63 draws, 2.27 and 2.63 ms, and 3.30 and 3.89 ms.
Sample
Section titled “Sample”A fall down a cliff face into a round pool. The engine’s tests mount this file:
import { Views, WaterfallMaterial, WaterMaterial } from "@spawnite/engine";
// A waterfall down a cliff face into a round pool at its foot: a sheet// 4 m tall stood upright, its lip at the top of its v, and a pond plane// laid flat just over the ground.
export function FallPool() { return ( <Views> <mesh position={[0, 2, -1]}> <planeGeometry args={[2, 4]} /> <WaterfallMaterial fallSpeed={3} bottomFoamHeight={0.8} /> </mesh> <mesh position={[0, 0.05, 0.5]} rotation={[-Math.PI / 2, 0, 0]}> <planeGeometry args={[4, 4]} /> <WaterMaterial round rippleSize={0.4} /> </mesh> </Views> );}Where it runs
Section titled “Where it runs”Client. The fall changes nothing in the world; each player’s browser draws its own. It has no collider: a player walks through it.