Browser game · Three.js · ES Modules

Wander land.

A modular 3D open-world browser game set in Neo Valley — ginkgo groves, retro-futuristic chrome spires, a living day/night cycle, and 20 spirit lights lost across the map. Built entirely in vanilla Three.js, no game engine.

Three.jsRenderer
14ES Modules
ACESTone Mapping
16kGrass Instances
0Dependencies

What's in the world.

🌿
Flora

Ginkgo Biloba Groves

380 instanced ginkgo trees with fan-shaped leaf geometry — ~9,900 individual leaf fans in autumn gold and chartreuse. Golden leaves drift down around you during the day.

Instanced Mesh 9,900 fan leaves
🏙️
Settlement

Retro-Futuristic City

The Aurora Spire — a chrome tripod tower with a glass saucer crown, neon rings, and a pulsing beacon. Six glass dome habitats, a monorail ring with an orbiting tram pod, and three relay pylons across the map.

PBR Chrome Neon emissives
🌅
Atmosphere

Dynamic Day / Night

A custom sky shader with a real sun disc, corona glow, and low-angle atmospheric haze. The sun moves on a 5-minute cycle. Clouds drift, stars fade in at dusk, and city windows light up at night.

GLSL shader 300s cycle
💡
Rendering

Filmic PBR Pipeline

ACES filmic tone mapping, 4K shadow maps with normal bias, PBR MeshStandardMaterial throughout, and procedurally generated detail + roughness textures for close-up ground realism.

ACES filmic 4K shadows sRGB encoding
🌊
Water

Real Specular Waves

Water is a subdivided plane with vertices displaced by three overlapping sine waves every frame. Normals recomputed live so the PBR material produces real sun glints across the surface.

CPU wave sim Live normals
🪂
Gameplay

Glider + Stamina

Hold Space while falling to deploy a paraglider and drift off cliff edges. Sprint drains a stamina wheel; hit a relay pylon to recharge. Gliding also drains stamina, turning red when exhausted.

Stamina ring HUD Relay recharge
🌱
Flora

16k Wind Grass

16,000 instanced grass blades with a custom GLSL vertex shader that drives per-blade sway based on world position and time — no texture, pure geometry and shader math.

GLSL wind shader 16,000 instances
Collectibles

20 Spirit Lights

Glowing orbs scattered across the map — some near relay pylons to reward exploration. Each has a point light, a pulsing halo, and bobs on a sine curve. Collect all 20 to restore the valley.

Point lights Additive halo

Neo Valley — the map.

Neo Valley · 620m radius island · procedurally generated ╔══════════════════════════════════════════════════════╗ [ Relay Pylon β ] 🌿 ginkgo grove x: -180 z: 150 🌊 ocean ╔══════════════╗ surrounds ║ SETTLEMENT ║ the island ║ x:40 z:-60 ║ ║ Aurora Spire║ ║ 6 domes ║ ║ monorail ║ ⛰ highlands ╚══════════════╝ [ Relay Pylon α ] 🟡 spawn x:0 z:0 x: 220 z: 180 [ Relay Pylon γ ] 🌿 sand beaches x: -120 z: -260 ╚══════════════════════════════════════════════════════╝ Biomes Sand h < 2.2m — beaches ringing the coast Grass h < 19.0m — main valley floor, ginkgo groves, grass fields Rock h < 32.0m — exposed cliff faces and highland ridges Snow h > 32.0m — summit caps

14 ES modules. One shared context.

Every system exposes init(ctx) and update(ctx). They never import each other's internals — communication happens only through the shared ctx object. Adding a new system means writing one file and registering two lines in main.js.

Module Responsibility Key exports / ctx contract
config.js All tunables single source World size, speeds, counts, day length — change here, everything updates
noise.js Procedural math pure hash, fbm, terrainHeight, makeNoiseTexture, scatterSpots
engine.js Renderer + lighting rig ctx.scene, ctx.camera, ctx.renderer, ctx.sun, ctx.hemi
sky.js Sky dome, stars, clouds, day/night ctx.time · { timeOfDay, sunUp, duskAmt, night }
terrain.js Heightmap mesh + biome colors Reads terrainHeight, writes PBR terrain mesh to scene
water.js Animated wave surface CPU wave sim, recomputes normals every frame
flora.js Trees, grass, rocks, particles Instanced ginkgos, wind shader grass, leaf/firefly clouds
settlement.js Spire, domes, monorail, relays Window glow reacts to ctx.time.sunUp, relay checks ctx.player.pos
player.js Physics, stamina, keyboard ctx.player · { pos, vel, facing, stamina, gliding, onGround }
character.js Hero mesh + procedural animation Reads ctx.player state, drives limb rotations and glider visibility
camera.js Third-person orbit follow ctx.cam · { yaw, pitch, dist } — mouse + scroll input
collectibles.js Spirit lights + pickup Reads ctx.player.pos, calls ctx.hud.toast on collect
hud.js All DOM ctx.hud · { toast, setStamina, setClock, setOrbs }
main.js Composition root + game loop entry Inits systems in order, calls update(ctx) on each per frame
~ cat src/main.js
// init order — engine first, player before systems that read ctx.player
const systems = [
engine, hud, player, camera, sky, terrain,
water, flora, settlement, character, collectibles
];
for (const s of systems) s.init(ctx);
 
// game loop
function loop() {
requestAnimationFrame(loop);
ctx.frame = { dt: Math.min(clock.getDelta(), 0.05), t: clock.elapsedTime };
for (const s of updaters) s.update(ctx);
engine.render(ctx);
}
~ python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 ...

Built with.

Renderer
  • Three.js r128
  • ACES filmic tone mapping
  • sRGB output encoding
  • PCFSoft shadow maps
  • 4K shadow resolution
Shaders (GLSL)
  • Sky dome + sun disc
  • Wind grass vertex shader
  • Procedural noise textures
  • Additive glow blending
Performance
  • Instanced meshes throughout
  • 16k grass instances
  • ~10k leaf fan instances
  • Frustum culling via Three.js
Architecture
  • Native ES Modules
  • Shared ctx pattern
  • Zero build step
  • Zero npm dependencies
Procedural
  • fBm noise terrain
  • Island falloff mask
  • Biome vertex coloring
  • Deterministic scatter

How to play.

W A S DMove around the world
SHIFTSprint — drains stamina
SPACEJump
SPACE holdDeploy glider while falling
MouseOrbit camera around player
ScrollZoom camera in / out
ESCRelease mouse cursor
Relay pylonWalk up to recharge stamina

Sprint up the plateau to the Aurora Spire and glide off the edge at dusk — the orange sun disc over the water, the ginkgo canopies catching the last light, and the spire's neon starting to glow is the best view in the valley. Run the game locally with python3 -m http.server 8000 from the project folder.