A whole valley, built in code.
No 3D models, no HDRIs, no audio files. Terrain, trees, architecture, water, sky, mountains, particles and sound are all generated at load time — which made performance and art direction the same problem.
01 — World Building
Procedural terrain and forests
The valley is carved from layered noise around the river's path, then dressed with deterministic scatter — the same seed always grows the same forest. Trees are built as branching geometry with foliage cards painted onto a canvas atlas at load time, so deodars, pines, oaks and flowering burans each get their own silhouette without a single image download.
Layered noise
Deterministic scatter
Canvas-painted atlas
0 models
02 — Water
A river that reflects the valley
The river is a custom GLSL shader on top of a planar Reflector: depth-based colour from jade to turquoise, flowing normals, foam around rocks, sun glints and fog-matched edges. Phones fall back to sky-only reflections so the shot still reads without the extra render pass.
Planar reflections
Custom GLSL
Rock foam
GLSL
03 — Atmosphere
Mist instead of post-processing
Rather than a heavy post-processing stack, a global patch to three.js's fog chunk adds height-based mist and sun scattering to every material at once. Subtle billboard light shafts, drifting petals, tone mapping, a vignette and film grain do the rest of the cinematic work.
Fog-chunk patch
Height mist
Light shafts
1 patch
04 — Sound
A soundtrack synthesised live
The soundscape is procedural WebAudio: filtered noise for the river and wind, synthesised birdsong, a tanpura-like drone with a jawari shimmer, and a temple bell near the ghat. It starts muted and fades in only when the visitor asks for it.
WebAudio
Tanpura drone
Muted by default
0 files
05 — Performance
Adaptive on every device
Quality tiers decide shadows, reflection resolution and density up front, and a PerformanceMonitor steps the pixel ratio down live when frames drop. An error boundary and WebGL context-loss handling swap in a static fallback instead of a blank screen, and a ridge-line loader with a rising sun covers the 5–10 seconds it takes to build the world.
Quality tiers
Adaptive DPR
Context-loss fallback
2 tiers