Add:
• Footprints on the sand
• Drivable boat
• Swimming mechanics
• Ability to lie down to sleep
• Functional backpack / inventory
• Bug fixes
Far Cry Lagoon — Stage 11* (out-of-plan mechanics) + Stage 12 (swimming, boat, open sea)
Context: browser-based first-person Three.js game (ES modules, no build step for dev, node build.mjs bundles everything for file://). Stages 1–11 are done: flagship water (Gerstner ×7 + GPU FFT, planar reflections, caustics, ripple simulation), terrain with 5 ground layers and footprints, outpost props from Meshy models, day/night + weather, procedural audio. Now extend gameplay beyond standing on the beach.
━━━━━━━━━━━━━━━━━━━━━━━━
STAGE 11* — Backpack, carried lamp, sleeping
━━━━━━━━━━━━━━━━━━━━━━━━
1. Backpack: next to the cot, E → "Take backpack". It disappears from the deck together with its collider and contact shadow; the inventory gets "Backpack" plus the items found inside.
2. Kerosene lamp:
- First fix the bug where inspecting the lamp turns the screen black (probably a bad emissive value blown up by bloom, so check how inspected objects are cloned).
- Make the lamp pickable (E). It hangs in the left hand and stays lit. At night its light really moves with the player: reuse the existing PointLight (no new lights, no shader recompiles) and pass it the glass position in camera space every frame.
- Key 4 = take the lamp in hand / put it away. When the AK is equipped the lamp hangs on the belt. E on the empty spot on the table puts it back.
- Physical pendulum swing in world space (damped, clamped to about 35°). If the left hand holds the lamp, pickups use the right hand.
3. Sleep: E on the cot opens a "Sleep until" panel (morning / noon / sunset / night, click or keys 1–4, Esc cancels). The camera blends into a lying pose on the cot, the screen fades to black, time of day switches while it's dark, then you wake up lying down and get up. About 7 seconds in total.
━━━━━━━━━━━━━━━━━━━━━━━━
STAGE 12 — Swimming, boat, open sea (Extra-high effort)
━━━━━━━━━━━━━━━━━━━━━━━━
Goal: leave the shallows. Swim, dive, climb into the boat and drive it across the lagoon and past the reef. Everything must feel physical, not "camera on rails", and the water 200+ m offshore must look as good as it does at the beach.
12.1 Swimming (controller.js + new player/swim.js)
- Remove the 1.25 m wading limit. Wading turns into swimming smoothly with depth (about chest height). At the surface the head rides a spring on the wave height, so swells lift and drop you.
- Slower inertial movement. Shift = fast crawl (uses stamina), Space = surface / stroke up, C/Ctrl = dive, W underwater follows your view, slow buoyancy when idle.
- Air supply (~45 s). A HUD bar shows only when submerged or below 100%. At zero: choking, blackout, pushed up to the surface. The Stage 7 underwater mode becomes normal gameplay, with a lowpass on audio.
- Weapons and lamp are hidden in water (the lamp goes out) and come back on shore. Every stroke makes a ripple, a splash and a sound.
- Exit: walk out on the beach, or E at a ledge to pull yourself up onto the pier or into the boat. After exiting: water drops running down the "lens" (post pass), wet hands that dry in about a minute. No footprints in water, splashy footsteps in the shallows.
12.2 Boat physics (new systems/boat.js, existing boat.glb)
- Full 6-DOF rigid body: mass (~270 kg hull + 80 kg player where they sit or stand), inertia tensor from the hull bounds.
- Buoyancy from ~10 pontoon points along the hull bottom, each pushed by its own submersion under the water height. Heave, pitch and roll must come from this, not from animation.
- Drag differs along the hull and across it (the keel stops sideways sliding), plus angular damping.
- Stern outboard: smooth throttle on W/S (weaker reverse), tiller on A/D rotates the thrust vector. Turning depends on speed. Drag curve with a planing hump, bow lift and stern squat at speed. Bow slams into waves (thump, spray, camera kick).
- Collisions: runs aground on the seabed (grinding sound), impulse response against pier piles and rocks, pushes a swimmer. A thrown stone or a bullet hit gives a sound and a nudge.
- Mooring lines from Stage 7 become springs. Tap E to cast off or tie up. If you forget to untie, the line snaps with a hint. With no driver the boat drifts with wind and swell, and the surf washes it ashore.
- Fixed 60 Hz physics step with render interpolation.
12.3 Boat controls and feel
- E near the boat (from the pier, the shallows or the water) → sit at the stern.
- Seated camera on a spring that lags the hull motion. Free look limited to about ±130°.
- The left hand is on the tiller and you see it turn. The right hand stays free, so you can still fire the AK or throw a stone.
- Hold E to get off: onto the pier if close, else the beach, else into the water.
- Speed feel: slight FOV increase, horizon tilt in turns, engine vibration, louder wind with a whistle, bow spray, drops on the lens when slammin…
# Task: a flyable, enterable, film-quality bush seaplane for a Three.js first-person game
You are building a **self-contained module** that will later be dropped into an existing browser game ("FarCry Lagoon": a first-person tropical island game in Three.js). You do **not** have access to the game's code. Another engineer (who knows the game) will integrate your module, so your job is to deliver:
1. **The seaplane module** — model, cockpit interior, flight + water physics, controls, interactions, sound, effects — written to the strict technical contract below so it can be pasted into the game with minimal glue.
2. **A sandbox page** that shows it off and lets you test everything: a small island, open sea with waves, a wooden pier, a first-person walker, and a chase/free camera. The sandbox is a test bench only; it will not be integrated.
3. **A short `INTEGRATION.md`** describing the public API, the coordinate frame, the env callbacks, keymap and anything the integrator must know.
The reference image is attached (`seaplane_ref.webp`). Save it in the repo as `reference/seaplane_ref.webp` and keep comparing your renders against it. Quality bar: it should look like a hero vehicle from Far Cry / Just Cause, not a programmer-art prop. Take your time — correctness and visual quality matter more than speed. Work in iterations: build → screenshot from several angles → compare with the reference → fix.
---
## 1. Hard technical contract (non-negotiable — integration depends on it)
- **Three.js r169 exactly** (`three@0.169.0`) as ES modules from the CDN via importmap:
```html
<script type="importmap">{"imports":{"three":"https://t.co/kfT5n2bgSY","three/addons/":"https://t.co/PGZ03dZk8R"}}</script>
```
No npm runtime dependencies, no bundler, no TypeScript, no Vite. Plain `.js` ES modules that run from any static server (e.g. `npx serve` / a tiny node server).
- **Module syntax restrictions** (the game has a custom bundler that inlines modules):
- Only `export function name`, `export class Name`, `export const/let name = ...`. **No** `export default`, **no** `export { a, b }` lists, **no** re-exports.
- **No** default imports (`import X from`), only `import * as THREE from 'three'` and named imports `import { A } from '...'`.
- **No** dynamic `import()`, **no** `import.meta`, **no** top-level `await`, **no** circular imports between your files.
- Allowed externals: `three` and `three/addons/...` only (e.g. `BufferGeometryUtils`, `RoundedBoxGeometry` are fine).
- **Zero external assets.** No downloaded textures, models, HDRIs, fonts or sound files. Everything is procedural:
- geometry built in code (lathe / extrude / tube / custom BufferGeometry / CSG-like manual modelling),
- textures generated at startup on canvas (`CanvasTexture`, `DataTexture`) or in shaders, deterministically from a seed,
- sound synthesized with WebAudio.
- **Never patch `THREE.ShaderChunk` globally** and don't replace three's lighting/fog/shadow chunks — the game already patches them (cascaded shadows, custom fog). Use stock `MeshStandardMaterial` / `MeshPhysicalMaterial`; if you need custom shading, use `onBeforeCompile` locally on your own materials only, with a unique `customProgramCacheKey`, and keep `fog: true` working.
- **No real lights added at runtime.** Changing the number of lights recompiles every shader in the game (a visible freeze). Nav lights, instrument backlight, landing light, exhaust glow = emissive materials + additive sprites / light cones / a projected fake light pool on the water. Optionally ONE `SpotLight` for the landing light, created once at construction (intensity 0 when off, never shadow-casting), behind an option `realLandingLight: false` by default.
- **No mid-game shader compiles.** Every material / define variant the plane can ever use must exist from the start. Don't toggle `transparent`, `defines`, `vertexColors`, `side` etc. at runtime; switch visibility or uniforms instead. Provide `plane.prewarm(renderer, camera)` that compiles all programs (incl. LODs, interior, broken parts, effects) up front.
- **Units / frame:** metres, kilograms, seconds, radians, **+Y up**, sea level **y = 0**. Plane local frame: **nose toward −Z, right wing toward +X, up +Y**, origin at the centre of gravity at rest. Document it in `INTEGRATION.md`.
- **Don't touch globals:** no `window` listeners inside the module except through an explicit `attachInput(domElement)` / `detachInput()` pair; no pointer-lock requests in the module (the game owns pointer lock; the sandbox may request it itself); no `requestAnimationFrame` in the module (the host calls `update(dt)`); no `renderer.setAnimationLoop`, no changing renderer settings.
- **Desktop only**, keyboard + mouse. No touch / mobile / gamepad code.
- **Performance budget** (the game is already GPU-heavy; target 60 FPS at 1080p on a mid-range GPU):
- LOD0 (camera ≤ ~30 m): exterior ≤ ~120k triangles and ≤ ~30 draw calls; interior ≤ ~80…