NatureGL Islandv1.1.0

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

naturegl-island/
├── 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:

  1. 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.
  2. Shadow frustum. The sun's shadow camera follows the camera, snapped to shadow-map texels to stop shimmer.
  3. Sky. sky.update(dt): sun, capped exposure, clouds. The game derives its night factor from the sun elevation.
  4. Water exposure. water.params.exposure = preset base × HUD bias × the underwater pin.
  5. Land. Village animation, vegetation LOD, grass.update(), scatter layers.
  6. Wildlife. Birds, crabs, fish and whale (unless the Wildlife layer is off).
  7. Rain. NatureGL Weather lighting and weather.update(), if rain mode was ever switched on.
  8. Water. water.update(dt). Buoyancy moves the boat here.
  9. Boat camera. In the boat, the cockpit or chase pose is computed after buoyancy.
  10. 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>static

opts.renderer (required), opts.quality ('high'), opts.assetsUrl ('./', the folder containing models/pirate-kit/), opts.domElement (the renderer canvas), opts.onProgress(msg).

#game.update(dt): voidmethod

Runs one frame of gameplay and every library update, in the frame order above.

#game.render(): voidmethod

Renders through NatureGL Water (or through NatureGL Sky's post pass when setSkyPost(true)).

#game.resize(width, height): voidmethod

Updates the camera aspect and resizes the sky and water targets.

#game.applyScenario(name): voidmethod

Deterministic 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?): voidmethod

Sets the sky's time of day. game.clockRunning and game.clockSpeed (in-game hours per real second) control the clock.

#game.setSkyLook(name, { immediate }?): voidmethod

A key of SKY_LOOKS. Keeps the time of day and the island's sun orientation.

#game.setWaterLook(name, { immediate }?): voidmethod

A key of WATER_LOOKS, with the lagoon tuning applied on top.

#game.setSkyPost(on): voidmethod

Runs NatureGL Sky's post pass over water.renderHDR(). Off by default.

#game.rain.toggle(on): Promise<void>method

Rain 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.