water
Skill4 starsChanged 16 days agoMITView on GitHub
Create realistic procedural water and wet surfaces with Three.js TSL on WebGPU. Use for lakes, rivers, reservoirs, canals, puddles, drainage, fountains and wet materials.
In this repository28 other files it gives its agents.
- character-cameraSkill
- character-inputSkill
- character-kitSkill
- character-modelSkill
- character-walkingSkill
- engineered-environmentsSkill
- megacitySkill
- station-maglevSkill
- greenhouseSkill
- pipesSkill
- procedural-geometrySkill
- signageSkill
- indirect-lightingSkill
- lightingSkill
- glassSkill
- interior-mappingSkill
- material-compositionSkill
- metalSkill
- paintSkill
- rustSkill
- tsl-materialsSkill
- threejs-directorSkill
- card-grassSkill
- far-shadeSkill
- ocean-waterSkill
- photo-skySkill
- snow-weatherSkill
- jolt-drivingSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 5 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 27
Do not make all water bright blue.
- Distinctive: line 45
Use layered wave scales:
- Distinctive: line 51
Do not use high-frequency displacement everywhere.
- Distinctive: line 59
Place foam where physically plausible:
- Distinctive: line 67
Do not distribute foam uniformly.
- Very specific: line 121
Material: Use a MeshStandardNodeMaterial or MeshPhysicalNodeMaterial for SSR water so metalness and roughness reach the attachment.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Water
Target: Three.js 0.187.0, three/webgpu and TSL node materials from three/tsl; WebGPU only, no WebGL fallback, no GLSL strings.
Water response
Think in terms of:
- reflection
- transmission/refraction
- Fresnel
- depth-dependent absorption
- roughness
- normal waves
- surface displacement
- ripples
- foam
- shoreline effects
- flow direction
- interaction with objects
Do not make all water bright blue.
Scale-specific variants
Distinguish:
- large reservoir/lake water
- canal/river water
- shallow drainage
- puddles
- fountains
- wet concrete
- wet metal
Each has different wave scale, roughness, depth and reflection behaviour.
Surface
Use layered wave scales:
- large gentle waves for silhouette and broad reflection
- medium waves for visible surface structure
- small normal-scale ripples for highlights
Do not use high-frequency displacement everywhere.
Depth
Water should generally become visually deeper with depth. Use attenuation and colour response rather than a flat colour overlay.
Foam
Place foam where physically plausible:
- shorelines
- obstacles
- strong flow
- turbulence
- waterfalls
Do not distribute foam uniformly.
Wet surfaces
Wet concrete, rails and metal are not the same thing as standing water. For wet surfaces, primarily alter roughness/specular response and add subtle darkening/reflection rather than turning the entire surface transparent.
Reflections
Three ways, cheapest first. Pick by what has to appear in the water.
| Need | Use |
| the sky and a general sense of surroundings | scene.environment only: the PMREM from photo-sky; nothing on screen reflects |
| the quay, the boats, the bridge above: what is on screen, seen from a low camera | screen-space reflections (below) |
| a horizon view, the sky dome and a distant coast, exact reflections of hidden geometry | the planar mirror in ocean-water (one extra scene render per frame) |
Screen-space reflections on r187 are a post pass fed by a multi-target scene pass. Water is a
dielectric, so reflectNonMetals: true is required; without it the pass skips every non-metal
surface and the water stays matte. Ripples reach the reflection only through the normal
attachment, so the water material must write its perturbed normal into normalNode.
import * as THREE from 'three/webgpu';
import { pass, mrt, output, normalView, metalness, roughness, packNormalToRGB, unpackRGBToNormal, sample, vec2 } from 'three/tsl';
import { ssr } from 'three/addons/tsl/display/SSRNode.js';
const pipeline = new THREE.RenderPipeline(renderer);
const scenePass = pass(scene, camera);
scenePass.setMRT(mrt({ output, normal: packNormalToRGB(normalView), metalrough: vec2(metalness, roughness) }));
scenePass.getTexture('normal').type = THREE.UnsignedByteType; // bandwidth; optional
const color = scenePass.getTextureNode('output'), depth = scenePass.getTextureNode('depth');
const normalTex = scenePass.getTextureNode('normal'), mr = scenePass.getTextureNode('metalrough');
const normal = sample((uv) => unpackRGBToNormal(normalTex.sample(uv).rgb));
const reflections = ssr(color, depth, normal, { metalnessNode: mr.r, roughnessNode: mr.g, reflectNonMetals: true });
reflections.maxDistance.value = 1; // view units a ray may travel; raise for a wide river
reflections.thickness.value = 0.1; // depth tolerance of a hit
reflections.quality.value = 0.5; // ray-march steps, 0..1; 0.5 is enough for most scenes
pipeline.outputNode = color.add(reflections.rgb);
// each frame: pipeline.render() instead of renderer.render(scene, camera)- Roughness is the blur. The pass blurs by the roughness attachment (
blurQuality1 to 3). Still water at 0.05 to 0.15 reads as a mirror; wind-ruffled water at 0.3 and above becomes a smear, and the mirror inocean-wateris cheaper per visible pixel there. - Rough water, better.
stochastic: truetraces GGX rays instead of one mirror ray and needs a denoiser: addvelocityto the MRT and chaintemporalReproject(..., { mode: 'specular', accumulate: false })thenrecurrentDenoise(..., { mode: 'specular', accumulate: true })fromthree/addons/tsl/display/, feeding the denoised result back withsetHistory. This is the r187 denoise example; it costs several passes and is for a hero shot, not a default. - Limits. Nothing off screen reflects: the sky beyond the frame, the camera's own side of a
bridge, the coast behind the viewer. The edge fade (
screenEdgeFade, 0.2) hides the cut andscene.environmentfills the rest. TheenvironmentNodeoption wants an equirectangular HDR with CPU-side pixels, not the PMREM, so it is of no use withphoto-sky. - Material. Use a
MeshStandardNodeMaterialorMeshPhysicalNodeMaterialfor SSR water sometalnessandroughnessreach the attachment; an unlit sheet gives the pass nothing to work with. Not run in this catalog; the values are the r187 example's defaults.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

