import { Suspense, useCallback, useEffect } from "react"; import { Canvas, useThree } from "@react-three/fiber"; import { Physics } from "@react-three/rapier"; import * as THREE from "three"; import { DebugPerf } from "@/components/debug/DebugPerf"; import { RepairGame } from "@/components/three/gameplay/RepairGame"; import { logger } from "@/utils/core/Logger"; import type { RepairMissionId } from "@/types/gameplay/repairMission"; import type { Vector3Tuple } from "@/types/three/three"; // Isolated scene — no world offset, no terrain. The repair game runs // fully centred in its own context so the heavy map never loads here. const REPAIR_SCENE_POSITION: Vector3Tuple = [0, 0, 0]; // Background: very dark blue-grey to match Altera's night-time mood const REPAIR_SCENE_BG = "#0b0d14"; // Lighting tuned to match the main world defaults from lightingConfig.ts const AMBIENT_COLOR = "#dfe7d8"; const AMBIENT_INTENSITY = 0.9; const SUN_COLOR = "#ffe2bf"; const SUN_INTENSITY = 2.2; const SUN_POSITION: Vector3Tuple = [5, 8, 4]; // Mimic the first-person view from the main world: // - PLAYER_EYE_HEIGHT = 1.75 → camera Y // - Case floats at [0, 0.4, 1.8] (inspected) → [0, 1.05, 2.05] (repairing) // - Look-at target averaged between those two states const CAMERA_POSITION: Vector3Tuple = [5, 2, 2]; const CAMERA_LOOK_AT: Vector3Tuple = [0, 0.7, 1.9]; function RepairSceneCamera(): null { const { camera } = useThree(); useEffect(() => { camera.lookAt(...CAMERA_LOOK_AT); }, [camera]); return null; } interface RepairGameSceneProps { mission: RepairMissionId; } export function RepairGameScene({ mission, }: RepairGameSceneProps): React.JSX.Element { const handleCreated = useCallback(({ gl }: { gl: THREE.WebGLRenderer }) => { const canvas = gl.domElement; const loseContextExt = gl.getContext().getExtension("WEBGL_lose_context"); const handleContextLost = (event: Event) => { event.preventDefault(); logger.error("WebGL", "Repair scene context lost — attempting restore"); window.setTimeout(() => loseContextExt?.restoreContext(), 500); }; const handleContextRestored = () => { logger.info("WebGL", "Repair scene context restored"); }; canvas.addEventListener("webglcontextlost", handleContextLost); canvas.addEventListener("webglcontextrestored", handleContextRestored); }, []); return ( {/* Lighting — mirrors the game world defaults */} {/* Physics is required: TriggerObject and GrabbableObject both use RigidBody. The world is minimal — no octree, no character bodies. */} ); }