Integrate a standalone seaplane module into an existing Three.js open-world game You're working on a browser game: a tropical lagoon open world built on Three.js (vanilla ES modules, a custom build script that inlines everything into one index.html). A separate session already built a self-contained bush seaplane module, a DHC-2 Beaver-style plane on twin floats. It has a cockpit, instruments, flight and water physics, a procedural engine sound and a test sandbox. Your job is to move it into the game and connect it to the game's systems without rebuilding the plane. Don't change its look, physics or sound unless you have to. Read INTEGRATION.md in full before you start. It covers the API, the coordinate system, env callbacks, events, controls and budgets. Requirements: Port: Copy the module as-is into js/world/seaplane/. Write one glue file, js/systems/seaplane.js, modeled on the existing jeep and boat systems. The plane's modules must never import anything from the game. No hitches at runtime: The plane builds asynchronously (~1 s), but the real hitch comes from shader compilation the first time it's on screen. Make boot() async and run await plane.ready plus plane.prewarm() under the loading screen, together with the game's own renderer.compile. Wrap the plane's materials with the game's fog, aerial perspective, cascaded shadow and wetness shader injections, keeping their own onBeforeCompile. Otherwise the plane won't match the rest of the scene. Verify: https://t.co/2EMJV3D3h7.programs.length must not grow during play. Fix the pilot doors: They open into the cabin. Flip the hinge angle so they swing outward, and check they don't clip the wing strut or the boarding camera path. Placement: Park it on wheel chocks on a beach behind the boulders near the hut, tail to the water so it can be pushed off. It must stay hidden from the opening camera shot (the start frame can't change), with 150–300 m of open water for a takeoff run. Env adapter: Connect the plane to the game world:waterHeight: the game's fine wave sampler near the camera, a cheaper one far away (measure the cost) groundHeight: terrain plus karst mountains and rock arches contact: sphere tests against the game's colliders through a spatial grid Wind, sun, night, rain and wetness from the game's globals A soft flight boundary (~1.5 km radius, ~800 m ceiling) Spray, splash and wake events become water ripples Boarding and exit: Show E prompts using the module's interactables and its scoring rules. While seated, hide the weapon, lamp and fishing rod and disable game interactions. Hold E to exit: onto the beach if you're on land, into the water (swimming) if you're at sea. Add collider cylinders for the floats and fuselage that move with the plane so the player can't walk through it. Controls: Route the game's key state into the module:W/S: pitch · A/D: roll · Z/X: rudder R/F or mouse wheel: throttle · G/B: flaps Q: engine (hold to start, tap to stop) U: water rudders · L: lights · RMB: mouse yoke · [ ]: trim Camera: Chase camera only for now. Mouse orbits around the plane; no cockpit view yet. Make sure it never dips into water or terrain and doesn't jitter on waves. Audio: Route it through the game's SFX bus with a world-space listener (the game moves ctx.listener itself), starting after the Play click. HUD: Context hint, a throttle bar and a stall warning. Nothing else. Altitude LOD: Fix only what visibly breaks from the air. Stop updating grass above ~30 m and turn off undergrowth above ~40 m. Show tree LOD0 only when the eye is less than ~15 m above the tree. Particles: If the module's spray shows up as streaks in the water refraction pass, disable its own effects for now and keep only the ripples. Debug key: Shift+P resets and repairs the plane and puts it back on the beach. Acceptance (one live run): walk to the plane → the doors open outward → get in → start the engine → push off and taxi → take off → fly over both islands → land on water → get out. No console errors, no new shader programs mid-game, the plane sits correctly in the game's fog and shadows, and the opening frame is unchanged.