How it's built
Architecture
One facade class, IslandGame, owns the scene, the camera, the four NatureGL systems and the gameplay. The world is built by small modules that all read one shared layout and one baked heightfield. The DOM HUD is separate.
#Source layout
├── src/│ ├── IslandGame.jsthe game facade: scene, camera, the four NatureGL systems, modes, scenarios, per-frame update│ ├── index.jspublic exports│ ├── config/│ │ ├── QualityLevels.jsgame tiers → library tiers + budgets│ │ └── scenarios.jsnamed viewpoints│ ├── core/│ │ ├── Input.jskeyboard, mouse (pointer lock), wheel│ │ └── noise.jsseeded rng, value noise, fbm│ ├── world/terrain, vegetation, village, reef, boat, props, rain…│ ├── life/birds.js, crabs.js, sea.js│ ├── modes/│ │ └── controllers.jswalk/swim, boat and drone controllers + the camera rig│ └── ui/│ └── Hud.jsDOM HUD: fps, mode chip, instruments, panels├── demo/│ ├── index.html│ ├── main.jsthe page; exposes window.__pro│ └── public/models/Kenney Pirate Kit props (CC0)├── lib/vendored prebuilt Sky, Water, Grass and NatureGL Weather bundles├── scripts/smoke.mjs, shot.mjs, play-test.mjs, sync-libs.mjs├── docs/LIBRARY-ISSUES.md└── vite.config.jsaliases the library names to lib/
See The world for what each world/ and life/ module builds.
#Start-up
IslandGame.create(opts) is async. It reports each stage through onProgress, which the demo shows on the loading screen:
#Shaping the island
Bakes the analytic island height into a 1024² grid (IslandTerrain). Everything after this reads that grid.
#Building the sky
SkySystem.create() with the tier's sky quality, the partlyCloudy preset and the exposure caps. Binds the sun and hemisphere lights.
#Filling the ocean
WaterSystem.create() with the tropical preset and the island's bathymetry, then water.setSky(sky).
#Laying the ground
The terrain mesh and deep-sea skirt, with NatureGL Sky cloud shadows and NatureGL Water caustics patched into their materials.
#Growing grass
GrassSystem.create() over the grass mask, with the wind, lights, cloud shadow and terrain colour blending.
#Planting palms
Palms and jungle trees, then the undergrowth scatter layers.
#Building the village
Village, pier, reef, sea grass, marine snow, the boat and the Kenney props.
#Waking the wildlife
Gulls, crabs, fish and the whale; the rain mode (created lazily); input, controllers, buoyancy and wake.
#Frame order
game.update(dt) clamps dt to 0.1 s and runs, in this order:
- Input and controllers. Mode keys, then the walk or drone controller, then the boat physics (always, moored or driven). The camera rig applies the pose.
- Shadow frustum. The sun's shadow camera follows the camera, snapped to shadow-map texels to stop shimmer.
- Sky.
sky.update(dt): sun, capped exposure, clouds. The game derives itsnightfactor from the sun elevation. - Water exposure.
water.params.exposure= preset base × HUD bias × the underwater pin. - Land. Village animation, vegetation LOD,
grass.update(), scatter layers. - Wildlife. Birds, crabs, fish and whale (unless the Wildlife layer is off).
- Rain. NatureGL Weather lighting and
weather.update(), if rain mode was ever switched on. - Water.
water.update(dt). Buoyancy moves the boat here. - Boat camera. In the boat, the cockpit or chase pose is computed after buoyancy.
- Under water. Sea-grass sway and the underwater colour grade.
game.render() is water.render(): NatureGL Water draws the scene into its HDR target, adds the ocean, the underwater effects and bloom, and tone-maps with the sky's display exposure. See Composing the libraries.
#Modes and the camera rig
There are three controllers in src/modes/controllers.js: WalkController (walking and swimming), BoatController and DroneController. Each one writes a camera pose. CameraRig blends from the previous pose to the new one with a smoothstep, over 1.4 s when the drone is involved and 0.9 s otherwise. Scenarios switch instantly.
game.mode is 'walk', 'boat' or 'drone'. Swimming is part of walk mode (game.walker.swimming).
#IslandGame API
The methods the demo page, the HUD and the test scripts use.
IslandGame.create(opts): Promise<IslandGame>staticopts.renderer (required), opts.quality ('high'), opts.assetsUrl ('./', the folder containing models/pirate-kit/), opts.domElement (the renderer canvas), opts.onProgress(msg).
game.update(dt): voidmethodRuns one frame of gameplay and every library update, in the frame order above.
game.render(): voidmethodRenders through NatureGL Water (or through NatureGL Sky's post pass when setSkyPost(true)).
game.resize(width, height): voidmethodUpdates the camera aspect and resizes the sky and water targets.
game.applyScenario(name): voidmethodDeterministic viewpoint: mode, camera, time. Pauses the clock and re-seeds the wildlife. See Scenarios.
game.setMode(mode, { instant }?): voidmethod'walk', 'boat' or 'drone', with a blended camera unless instant.
game.setQuality(level): voidmethod'low', 'medium', 'high' or 'ultra'. Switches every library's tier, the shadow map and the pixel ratio.
game.setTime(hours, immediate?): voidmethodSets the sky's time of day. game.clockRunning and game.clockSpeed (in-game hours per real second) control the clock.
game.setSkyLook(name, { immediate }?): voidmethodA key of SKY_LOOKS. Keeps the time of day and the island's sun orientation.
game.setWaterLook(name, { immediate }?): voidmethodA key of WATER_LOOKS, with the lagoon tuning applied on top.
game.setSkyPost(on): voidmethodRuns NatureGL Sky's post pass over water.renderHDR(). Off by default.
game.rain.toggle(on): Promise<void>methodRain mode through NatureGL Weather.
Other useful properties: game.sky, game.water, game.grass (the library systems), game.walker, game.boatCtl, game.drone, game.mode, game.modeLabel, game.prompt, game.exposureBias, game.lifeEnabled.
IslandGame is a THREE.EventDispatcher and fires mode, scenario and quality events.