@popaya/pgsg-viewer 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/viewers/three/pgsg-three-viewer.ts","../src/viewers/spark/SparkSplatRenderer.ts","../src/viewers/three/controls/RapierWalkCapsuleController.ts","../src/viewers/three/controls/OrbitCameraController.ts","../src/viewers/three/controls/MeasurementController.ts","../src/viewers/three/controls/FloorplanController.ts"],"sourcesContent":["import type { PGSGViewerOptions } from \"../../core/types\";\nimport * as THREE from \"three\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader.js\";\nimport { TransformControls } from \"three/examples/jsm/controls/TransformControls.js\";\nimport { EffectComposer } from \"three/examples/jsm/postprocessing/EffectComposer.js\";\nimport { RenderPass } from \"three/examples/jsm/postprocessing/RenderPass.js\";\nimport { OutlinePass } from \"three/examples/jsm/postprocessing/OutlinePass.js\";\nimport { OutputPass } from \"three/examples/jsm/postprocessing/OutputPass.js\";\nimport * as RAPIER from \"@dimforge/rapier3d-compat\";\nimport nipplejs from \"nipplejs\";\n\nimport { SparkSplatRenderer } from \"../spark/SparkSplatRenderer\";\nimport { RapierWalkController } from \"./controls/RapierWalkCapsuleController\";\nimport { OrbitCameraController } from \"./controls/OrbitCameraController\";\nimport { MeasurementController } from \"./controls/MeasurementController\";\nimport { FloorplanController } from \"./controls/FloorplanController\";\nimport { type CameraMode } from \"../types\";\n\nexport class PGSGThreeViewer {\n private scene = new THREE.Scene();\n private camera!: THREE.PerspectiveCamera;\n private renderer!: THREE.WebGLRenderer;\n private splats!: SparkSplatRenderer;\n\n private gltfLoader = new GLTFLoader();\n private pendingPlacementUrl?: string;\n private ghostModel?: THREE.Object3D;\n private raycaster = new THREE.Raycaster();\n private mouse = new THREE.Vector2();\n private placementRotation = 0;\n private transformControls?: TransformControls;\n private inputEnabled = true;\n private placementMouseMoved = false;\n private placedObjects: THREE.Object3D[] = [];\n private ghostYOffset = 0;\n\n private composer!: EffectComposer;\n private hoverOutline!: OutlinePass;\n private selectOutline!: OutlinePass;\n\n private selectedObject?: THREE.Object3D;\n private hoveredObject?: THREE.Object3D;\n\n private container: HTMLElement;\n private resizeObserver: ResizeObserver | null = null;\n\n private controls!:\n | RapierWalkController\n | OrbitCameraController\n | MeasurementController\n | FloorplanController;\n\n private running = false;\n private orbitTarget = new THREE.Vector3();\n private lastTime = performance.now();\n\n private persistentMeasurements: any[] = [];\n private measurementController: MeasurementController | null = null;\n\n private world!: RAPIER.World;\n\n // Roots\n private worldRoot = new THREE.Object3D(); // identity\n private cvRoot = new THREE.Object3D(); // ONLY place where we convert OpenCV->OpenGL\n private splatPivot = new THREE.Object3D();\n private colliderMesh?: THREE.Object3D;\n\n // For raycasting / measurement only\n private colliderMeshes: THREE.Object3D[] = [];\n\n private currentMode: CameraMode = \"orbit\";\n\n private acc = 0;\n private fixedDt = 1 / 60;\n\n private GLOBAL_SCALE = 0.7;\n\n constructor(private options: PGSGViewerOptions) {\n this.container = options.container;\n if (!this.container)\n throw new Error(\"[PGSGThreeViewer] Container is required\");\n }\n\n async load() {\n this.initRenderer();\n this.initCamera();\n this.initScene();\n\n this.initPostProcessing();\n\n this.bindResize();\n this.resize();\n\n this.transformControls = new TransformControls(\n this.camera,\n this.renderer.domElement,\n );\n\n this.scene.add(this.transformControls.getHelper());\n\n this.transformControls.getHelper().traverse((child: any) => {\n child.userData.ignoreOutline = true;\n });\n\n this.transformControls.addEventListener(\"dragging-changed\", (event) => {\n if (!this.controls) return;\n (this.controls as any).enabled = !event.value;\n });\n\n this.transformControls.addEventListener(\"mouseDown\", () => {\n document.exitPointerLock?.();\n (this.controls as any).enabled = false;\n });\n\n this.transformControls.addEventListener(\"mouseUp\", () => {\n (this.controls as any).enabled = true;\n });\n\n this.transformControls.setSize(0.75);\n this.transformControls.setSpace(\"local\");\n\n await RAPIER.init();\n\n this.world = new RAPIER.World({\n x: 0,\n y: -9.81 * this.GLOBAL_SCALE,\n z: 0,\n });\n\n // scene graph\n this.scene.add(this.worldRoot);\n\n // ✅ OpenCV -> OpenGL conversion happens ONCE here\n // This matches your observed bounds flip:\n // raw min/max: [-1.26, 0.75] => OpenGL min/max: [-0.75, 1.26]\n this.cvRoot.scale.set(1, -1, -1);\n this.worldRoot.add(this.cvRoot);\n\n // ===============================\n // Load Splats under cvRoot\n // ===============================\n this.splats = new SparkSplatRenderer();\n const { mesh } = await this.splats.load(this.options.source);\n\n // ✅ DO NOT flip the mesh separately\n this.splatPivot.clear();\n this.splatPivot.add(mesh);\n this.cvRoot.add(this.splatPivot);\n\n this.createNeutralEnvironment();\n\n // ===============================\n // Load Collider under cvRoot\n // ===============================\n if (this.options.colliderSource) {\n await this.loadCollider(this.options.colliderSource);\n }\n\n // update transforms after everything is added\n this.cvRoot.updateMatrixWorld(true);\n\n // Spawn camera using collider in the SAME space used by visuals + rapier\n this.placeInitialCamera();\n\n if (this.isMobile()) {\n this.initJoystick();\n this.switchToWalk();\n } else {\n this.switchToMeasure();\n }\n\n window.addEventListener(\"keydown\", this.onKeyToggle);\n window.addEventListener(\"keydown\", (e) => {\n if (!this.inputEnabled) return;\n if (!this.transformControls) return;\n\n if (e.key === \"r\") this.transformControls.setMode(\"rotate\");\n if (e.key === \"t\") this.transformControls.setMode(\"translate\");\n if (e.key === \"s\") this.transformControls.setMode(\"scale\");\n });\n this.renderer.domElement.addEventListener(\"mousedown\", () => {\n this.placementMouseMoved = false;\n });\n\n this.renderer.domElement.addEventListener(\"mousemove\", () => {\n this.placementMouseMoved = true;\n });\n\n this.renderer.domElement.addEventListener(\"mouseup\", (e) => {\n if (!this.placementMouseMoved) {\n this.onSceneClick(e as any);\n }\n });\n this.renderer.domElement.addEventListener(\"click\", this.onSelectObject);\n this.renderer.domElement.addEventListener(\"mousemove\", this.onHoverObject);\n window.addEventListener(\"keydown\", this.onDeleteObject);\n }\n\n start() {\n if (this.running) return;\n this.running = true;\n\n this.renderer.setAnimationLoop(() => {\n const now = performance.now();\n const delta = (now - this.lastTime) / 1000;\n this.lastTime = now;\n\n this.acc += delta;\n while (this.acc >= this.fixedDt) {\n this.world.timestep = this.fixedDt;\n this.world.step();\n this.acc -= this.fixedDt;\n }\n\n (this.controls as any)?.update?.(delta);\n this.composer.render();\n });\n }\n\n pause() {\n this.running = false;\n }\n\n resize() {\n if (!this.renderer || !this.camera) return;\n\n const w = Math.max(1, this.container.clientWidth);\n const h = Math.max(1, this.container.clientHeight);\n\n this.renderer.setSize(w, h);\n\n this.composer?.setSize(w, h);\n this.hoverOutline?.setSize(w, h);\n this.selectOutline?.setSize(w, h);\n\n this.camera.aspect = w / h;\n this.camera.updateProjectionMatrix();\n }\n\n destroy() {\n this.running = false;\n this.renderer.setAnimationLoop(null);\n this.renderer.domElement.removeEventListener(\"click\", this.onSceneClick);\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.controls?.dispose();\n this.renderer.dispose();\n window.removeEventListener(\"keydown\", this.onKeyToggle);\n }\n\n setCameraMode(mode: CameraMode) {\n this.currentMode = mode;\n\n if (this.controls instanceof MeasurementController) {\n this.persistentMeasurements = (this.controls as any).measurements;\n this.controls.setVisible(false);\n }\n\n switch (mode) {\n case \"measure\":\n document.exitPointerLock?.();\n this.switchToMeasure();\n if (this.controls instanceof MeasurementController)\n this.controls.setVisible(true);\n break;\n case \"orbit\":\n document.exitPointerLock?.();\n this.switchToOrbit();\n break;\n case \"walk\":\n this.switchToWalk();\n break;\n case \"floorplan\":\n this.switchToFloorplan();\n break;\n }\n }\n\n toggleCameraMode() {\n if (this.controls instanceof RapierWalkController) this.switchToOrbit();\n else this.switchToWalk();\n }\n\n getMeasurements() {\n return this.measurementController?.getMeasurements?.() ?? [];\n }\n\n clearMeasurements() {\n if (!this.measurementController) return;\n this.measurementController.clearAll();\n this.persistentMeasurements = [];\n }\n\n finalizePolyline() {\n if (this.controls instanceof MeasurementController)\n this.controls.finalizePolyline();\n }\n\n deleteMeasurement(index: number) {\n this.measurementController?.deleteMeasurement?.(index);\n }\n\n async enablePlacementMode(url: string) {\n this.pendingPlacementUrl = url;\n this.placementRotation = 0;\n\n console.log(\"[PGSG Viewer] Placement mode enabled\");\n (this.controls as any).enabled = false;\n\n const gltf = await this.gltfLoader.loadAsync(url);\n\n this.ghostModel = gltf.scene;\n\n // normalize scale\n const box = new THREE.Box3().setFromObject(this.ghostModel);\n const size = new THREE.Vector3();\n box.getSize(size);\n\n const maxDim = Math.max(size.x, size.y, size.z);\n const scale = 1.5 / maxDim;\n\n this.ghostModel.scale.multiplyScalar(scale);\n\n // transparent ghost material\n this.ghostModel.traverse((child: any) => {\n if (!child.isMesh) return;\n\n child.material = child.material.clone();\n child.material.transparent = true;\n child.material.opacity = 0.4;\n });\n\n this.scene.add(this.ghostModel);\n\n this.renderer.domElement.addEventListener(\n \"mousemove\",\n this.onPlacementMove,\n );\n this.renderer.domElement.addEventListener(\"wheel\", this.onPlacementWheel);\n window.addEventListener(\"keydown\", this.onPlacementCancel);\n\n // Force initial placement update\n const rect = this.renderer.domElement.getBoundingClientRect();\n\n this.mouse.set(0, 0); // center of screen\n this.raycaster.setFromCamera(this.mouse, this.camera);\n\n const intersects = this.raycaster.intersectObjects(\n this.colliderMeshes,\n true,\n );\n\n if (intersects.length) {\n this.ghostModel.position.copy(intersects[0].point);\n }\n }\n\n async addModelFromUrl(\n url: string,\n position?: THREE.Vector3,\n ): Promise<THREE.Object3D | null> {\n return new Promise((resolve, reject) => {\n this.gltfLoader.load(\n url,\n (gltf) => {\n const model = gltf.scene;\n\n const box = new THREE.Box3().setFromObject(model);\n const size = new THREE.Vector3();\n box.getSize(size);\n\n const maxDim = Math.max(size.x, size.y, size.z);\n const scale = 1.5 / maxDim;\n\n model.scale.multiplyScalar(scale);\n\n if (position) {\n model.position.copy(position);\n }\n\n const floorBox = new THREE.Box3().setFromObject(model);\n model.position.y -= floorBox.min.y;\n\n model.traverse((child: any) => {\n if (!child.isMesh) return;\n\n const mat = child.material;\n\n if (mat.isMeshStandardMaterial || mat.isMeshPhysicalMaterial) {\n mat.envMapIntensity = 0.8;\n mat.needsUpdate = true;\n }\n });\n\n this.cvRoot.add(model);\n\n resolve(model);\n },\n undefined,\n reject,\n );\n });\n }\n\n enableInput(enabled: boolean) {\n this.inputEnabled = enabled;\n }\n\n // ---------------------------\n // Init\n // ---------------------------\n\n private initRenderer() {\n if (this.renderer) return;\n\n this.renderer = new THREE.WebGLRenderer({\n antialias: this.options.renderer?.antialias ?? false,\n alpha: false,\n powerPreference: \"high-performance\",\n });\n\n this.renderer.setClearColor(0x111111, 1);\n this.renderer.outputColorSpace = THREE.SRGBColorSpace;\n\n this.renderer.setSize(\n this.container.clientWidth,\n this.container.clientHeight,\n );\n this.renderer.setPixelRatio(\n this.options.renderer?.pixelRatio ?? window.devicePixelRatio,\n );\n\n this.renderer.toneMapping = THREE.ACESFilmicToneMapping;\n this.renderer.toneMappingExposure = 0.85;\n\n this.renderer.localClippingEnabled = true;\n this.container.appendChild(this.renderer.domElement);\n }\n\n private initScene() {\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(0x111111);\n\n const hemi = new THREE.HemisphereLight(0xffffff, 0x444444, 0.25);\n this.scene.add(hemi);\n\n // const dir = new THREE.DirectionalLight(0xffffff, 2.5);\n // dir.position.set(5, 10, 5);\n // this.scene.add(dir);\n\n const amb = new THREE.AmbientLight(0xffffff, 0.35);\n this.scene.add(amb);\n }\n\n private initCamera() {\n this.camera = new THREE.PerspectiveCamera(\n this.options.camera?.fov ?? 60,\n this.container.clientWidth / this.container.clientHeight,\n this.options.camera?.near ?? 0.01,\n this.options.camera?.far ?? 10000,\n );\n this.camera.position.set(2, 2, 5);\n this.camera.lookAt(0, 0, 0);\n }\n\n private initPostProcessing() {\n this.composer = new EffectComposer(this.renderer);\n\n this.composer.addPass(new RenderPass(this.scene, this.camera));\n\n const size = new THREE.Vector2(\n this.container.clientWidth,\n this.container.clientHeight,\n );\n\n // Hover outline (cyan)\n this.hoverOutline = new OutlinePass(size, this.scene, this.camera);\n this.hoverOutline.edgeStrength = 6;\n this.hoverOutline.edgeGlow = 1.0;\n this.hoverOutline.edgeThickness = 2.0;\n this.hoverOutline.pulsePeriod = 0; // no pulsing\n this.hoverOutline.visibleEdgeColor.set(\"#00e5ff\");\n this.hoverOutline.hiddenEdgeColor.set(\"#00e5ff\");\n this.composer.addPass(this.hoverOutline);\n\n // Selected outline (yellow)\n this.selectOutline = new OutlinePass(size, this.scene, this.camera);\n this.selectOutline.edgeStrength = 8;\n this.selectOutline.edgeGlow = 1.2;\n this.selectOutline.edgeThickness = 2.5;\n this.selectOutline.pulsePeriod = 0;\n this.selectOutline.visibleEdgeColor.set(\"#ffd400\");\n this.selectOutline.hiddenEdgeColor.set(\"#ffd400\");\n this.composer.addPass(this.selectOutline);\n\n // ✅ IMPORTANT: final output pass\n // this.composer.addPass(new OutputPass());\n this.hoverOutline.clear = false;\n this.selectOutline.clear = false;\n }\n\n private bindResize() {\n this.resizeObserver?.disconnect();\n this.resizeObserver = new ResizeObserver(() => this.resize());\n this.resizeObserver.observe(this.container);\n }\n\n private isMobile(): boolean {\n return (\n \"ontouchstart\" in window ||\n navigator.maxTouchPoints > 0 ||\n window.innerWidth < 768\n );\n }\n\n // ---------------------------\n // Collider (visual + rapier)\n // ---------------------------\n\n private async loadCollider(url: string) {\n console.log(\"[PGSG Viewer] Loading collider:\", url);\n\n const loader = new GLTFLoader();\n const gltf = await loader.loadAsync(url);\n\n // Put collider under cvRoot so it matches splat space\n const colliderRoot = new THREE.Object3D();\n colliderRoot.name = \"colliderRoot\";\n colliderRoot.add(gltf.scene);\n\n this.colliderMesh = colliderRoot;\n this.cvRoot.add(colliderRoot);\n\n // update world matrices so geometry baking includes cvRoot flip\n this.cvRoot.updateMatrixWorld(true);\n colliderRoot.updateWorldMatrix(true, true);\n\n // For measurement/raycast (THREE)\n this.colliderMeshes.length = 0;\n\n // Build Rapier trimesh from FINAL transformed geometry\n colliderRoot.traverse((child: any) => {\n if (!child?.isMesh) return;\n\n // bake geometry into world space (including cvRoot scale flip)\n const geom = child.geometry.clone();\n child.updateWorldMatrix(true, false);\n geom.applyMatrix4(child.matrixWorld);\n\n const vertices = new Float32Array(geom.attributes.position.array as any);\n\n let indices: Uint32Array;\n if (geom.index) indices = new Uint32Array(geom.index.array as any);\n else {\n const count = geom.attributes.position.count;\n indices = new Uint32Array(count);\n for (let i = 0; i < count; i++) indices[i] = i;\n }\n\n const rb = this.world.createRigidBody(RAPIER.RigidBodyDesc.fixed());\n const cd = RAPIER.ColliderDesc.trimesh(vertices, indices);\n cd.setFriction(0.9);\n cd.setRestitution(0.0);\n this.world.createCollider(cd, rb);\n\n // optional debug material\n // child.material = new THREE.MeshNormalMaterial({ side: THREE.DoubleSide });\n child.visible = false;\n this.colliderMeshes.push(child);\n });\n\n // sanity logs\n const rawBox = new THREE.Box3().setFromObject(colliderRoot);\n console.log(\"OpenGL bounds Y:\", rawBox.min.y, rawBox.max.y);\n\n console.log(\"[PGSG Viewer] Colliders loaded:\", this.colliderMeshes.length);\n }\n\n // ---------------------------\n // Mode switching\n // ---------------------------\n\n private onKeyToggle = (e: KeyboardEvent) => {\n if (!this.inputEnabled) return;\n if (e.key !== \"v\") return;\n if (this.controls instanceof RapierWalkController) this.switchToOrbit();\n else this.switchToWalk();\n };\n\n private switchToMeasure() {\n this.controls?.dispose?.();\n this.measurementController = new MeasurementController({\n dom: this.renderer.domElement,\n camera: this.camera,\n scene: this.scene,\n colliders: this.colliderMeshes,\n });\n\n this.measurementController.restoreMeasurements?.(\n this.persistentMeasurements,\n );\n this.controls = this.measurementController;\n }\n\n private switchToWalk() {\n this.controls?.dispose?.();\n\n const walk = new RapierWalkController({\n camera: this.camera,\n dom: this.renderer.domElement,\n world: this.world,\n eyeHeight: 1.6,\n radius: 0.2,\n halfHeight: 0.6,\n moveSpeed: 3.0 * this.GLOBAL_SCALE,\n jumpSpeed: 6.0 * this.GLOBAL_SCALE,\n usePointerLock: !this.isMobile(),\n }) as any;\n\n this.controls = walk;\n\n // sync yaw/pitch from current camera\n const euler = new THREE.Euler().setFromQuaternion(\n this.camera.quaternion,\n \"YXZ\",\n );\n walk.setRotation(euler.y, euler.x);\n\n // place capsule under camera, then snap DOWN to nearest floor\n walk.setPositionFromCamera();\n walk.resetVelocity();\n walk.snapToGround?.();\n }\n\n private switchToOrbit() {\n this.controls?.dispose?.();\n\n this.camera.up.set(0, 1, 0);\n this.camera.updateMatrixWorld(true);\n\n // orbit around converted (OpenGL) content root\n const box = new THREE.Box3().setFromObject(this.cvRoot);\n const center = box.getCenter(new THREE.Vector3());\n this.orbitTarget.copy(center);\n\n const distance = Math.max(this.camera.position.distanceTo(center), 1);\n\n this.controls = new OrbitCameraController(\n this.camera,\n this.renderer.domElement,\n {\n target: this.orbitTarget.clone(),\n distance,\n usePointerLock: !this.isMobile(),\n },\n );\n }\n\n private switchToFloorplan() {\n this.controls?.dispose?.();\n\n const box = new THREE.Box3().setFromObject(this.cvRoot);\n const center = box.getCenter(new THREE.Vector3());\n const size = box.getSize(new THREE.Vector3());\n const height = Math.max(size.x, size.z) * 1.2;\n\n this.orbitTarget.copy(center);\n\n this.controls = new FloorplanController({\n dom: this.renderer.domElement,\n camera: this.camera,\n target: center,\n height,\n panSpeed: 0.0015,\n zoomSpeed: 1.15,\n });\n }\n\n // ---------------------------\n // Spawn\n // ---------------------------\n\n private placeInitialCamera() {\n const targetObj = this.colliderMesh ?? this.cvRoot;\n const box = new THREE.Box3().setFromObject(targetObj);\n const center = box.getCenter(new THREE.Vector3());\n const size = box.getSize(new THREE.Vector3());\n\n // start ray well above the whole scene\n const startY = box.max.y + 10;\n const maxDist = box.max.y - box.min.y + 50;\n\n // sample a small grid around center (helps when center is outside shell)\n const samples: Array<{ x: number; z: number }> = [];\n const sx = Math.max(0.2, size.x * 0.15);\n const sz = Math.max(0.2, size.z * 0.15);\n\n for (const dx of [-sx, 0, sx]) {\n for (const dz of [-sz, 0, sz]) {\n samples.push({ x: center.x + dx, z: center.z + dz });\n }\n }\n\n // pick best \"floor\" among all samples\n // Strategy:\n // - collect multiple hits along the down-ray\n // - ignore the first hit if it’s the outside ceiling\n // - select the deepest hit that is \"walkable-ish\"\n // (we don’t trust normal sign fully, so use abs(normalY))\n let bestFloorY: number | null = null;\n let bestXZ: { x: number; z: number } | null = null;\n\n for (const s of samples) {\n const hits = this.raycastDownMulti(s.x, s.z, startY, maxDist, 10);\n if (hits.length === 0) continue;\n\n // choose a candidate floor from the *later* hits (skip the first)\n // and require it to be roughly horizontal\n let candidate: { y: number; normalY: number } | null = null;\n\n for (let i = 1; i < hits.length; i++) {\n const h = hits[i];\n if (Math.abs(h.normalY) < 0.55) continue; // ~55deg slope limit\n candidate = h; // keep going, we want the deepest valid one\n }\n\n if (!candidate) continue;\n\n // choose the HIGHEST candidate floor among samples\n // (so we land on topmost interior floor, not a basement)\n if (bestFloorY == null || candidate.y > bestFloorY) {\n bestFloorY = candidate.y;\n bestXZ = s;\n }\n }\n\n const eye = 1.6;\n\n if (bestFloorY != null && bestXZ) {\n this.camera.position.set(bestXZ.x, bestFloorY + eye, bestXZ.z + 0.5);\n this.orbitTarget.set(bestXZ.x, bestFloorY, bestXZ.z);\n } else {\n // fallback\n this.camera.position.set(center.x, box.max.y + eye, center.z + 2);\n this.orbitTarget.copy(center);\n }\n\n this.camera.up.set(0, 1, 0);\n this.camera.lookAt(this.orbitTarget);\n this.camera.updateMatrixWorld(true);\n }\n\n private getWorldNormalSafe(hit: THREE.Intersection) {\n if (!hit.face) return null;\n const m3 = new THREE.Matrix3().getNormalMatrix(hit.object.matrixWorld);\n return hit.face.normal.clone().applyMatrix3(m3).normalize();\n }\n\n // ---------------------------\n // Mobile joystick\n // ---------------------------\n\n private initJoystick() {\n const zone = document.createElement(\"div\");\n zone.style.position = \"absolute\";\n zone.style.left = \"20px\";\n zone.style.bottom = \"20px\";\n zone.style.width = \"150px\";\n zone.style.height = \"150px\";\n zone.style.zIndex = \"1000\";\n this.container.appendChild(zone);\n\n const joystick = nipplejs.create({\n zone,\n mode: \"static\",\n position: { left: \"50px\", bottom: \"50px\" },\n color: \"white\",\n });\n\n joystick.on(\"move\", (_, data) => {\n const angle = data.angle.radian;\n const force = data.force;\n\n if (\n this.controls instanceof RapierWalkController ||\n this.controls instanceof OrbitCameraController\n ) {\n (this.controls as any).setMovementVector(\n Math.sin(angle) * force,\n Math.cos(angle) * force,\n );\n }\n });\n\n joystick.on(\"end\", () => {\n if (\n this.controls instanceof RapierWalkController ||\n this.controls instanceof OrbitCameraController\n ) {\n (this.controls as any).setMovementVector(0, 0);\n }\n });\n }\n\n private raycastDownMulti(\n x: number,\n z: number,\n startY: number,\n maxDist: number,\n maxHits = 8,\n ) {\n const hits: Array<{ y: number; normalY: number }> = [];\n\n let originY = startY;\n let remaining = maxDist;\n\n for (let i = 0; i < maxHits; i++) {\n const ray = new RAPIER.Ray({ x, y: originY, z }, { x: 0, y: -1, z: 0 });\n\n const hit = this.world.castRayAndGetNormal(ray, remaining, true);\n if (!hit) break;\n\n const y = originY - hit.timeOfImpact;\n const normalY = hit.normal?.y ?? 0;\n\n hits.push({ y, normalY });\n\n // Step just past the surface so the next cast finds the next intersection\n const eps = 0.02;\n originY = y - eps;\n remaining = remaining - hit.timeOfImpact - eps;\n if (remaining <= 0) break;\n }\n\n return hits;\n }\n\n private collectMeshes(obj: THREE.Object3D) {\n const meshes: THREE.Object3D[] = [];\n\n obj.traverse((c: any) => {\n if (c.isMesh && !c.userData.ignoreOutline) meshes.push(c);\n });\n\n return meshes;\n }\n\n private createNeutralEnvironment() {\n const pmrem = new THREE.PMREMGenerator(this.renderer);\n\n const envScene = new THREE.Scene();\n envScene.background = new THREE.Color(0xffffff);\n\n const light = new THREE.HemisphereLight(0xffffff, 0x444444, 1.0);\n envScene.add(light);\n\n const envMap = pmrem.fromScene(envScene).texture;\n\n this.scene.environment = envMap;\n\n pmrem.dispose();\n }\n\n private onSceneClick = async (event: MouseEvent) => {\n if (this.placementMouseMoved) return;\n if (!this.pendingPlacementUrl || !this.ghostModel) return;\n\n const position = this.ghostModel.position.clone();\n\n const placed = await this.addModelFromUrl(\n this.pendingPlacementUrl,\n position,\n );\n\n if (placed) {\n this.placedObjects.push(placed);\n }\n\n if (placed && this.transformControls) {\n placed.rotation.y = this.placementRotation;\n this.transformControls.attach(placed);\n }\n\n (this.controls as any).enabled = true;\n this.scene.remove(this.ghostModel);\n\n this.ghostModel = undefined;\n this.pendingPlacementUrl = undefined;\n\n this.renderer.domElement.removeEventListener(\n \"mousemove\",\n this.onPlacementMove,\n );\n\n this.renderer.domElement.removeEventListener(\n \"wheel\",\n this.onPlacementWheel,\n );\n\n window.removeEventListener(\"keydown\", this.onPlacementCancel);\n };\n\n private onPlacementMove = (event: MouseEvent) => {\n if (!this.pendingPlacementUrl || !this.ghostModel) return;\n\n const rect = this.renderer.domElement.getBoundingClientRect();\n\n this.mouse.set(\n ((event.clientX - rect.left) / rect.width) * 2 - 1,\n -((event.clientY - rect.top) / rect.height) * 2 + 1,\n );\n\n this.raycaster.setFromCamera(this.mouse, this.camera);\n\n const intersects = this.raycaster.intersectObjects(\n this.colliderMeshes,\n true,\n );\n\n if (!intersects.length) return;\n\n const hit = intersects[0];\n\n const box = new THREE.Box3().setFromObject(this.ghostModel);\n this.ghostYOffset = -box.min.y;\n this.ghostModel.position.copy(hit.point);\n this.ghostModel.position.y += this.ghostYOffset;\n\n // align to surface normal\n if (hit.face) {\n const normal = this.getWorldNormalSafe(hit);\n if (normal) {\n const up = new THREE.Vector3(0, 1, 0);\n const quat = new THREE.Quaternion().setFromUnitVectors(up, normal);\n this.ghostModel.quaternion.copy(quat);\n }\n }\n };\n\n private onPlacementWheel = (event: WheelEvent) => {\n event.preventDefault();\n event.stopPropagation();\n if (!this.ghostModel) return;\n\n event.preventDefault();\n\n const step = Math.PI / 12; // 15 degrees\n\n if (event.deltaY > 0) {\n this.placementRotation += step;\n } else {\n this.placementRotation -= step;\n }\n\n this.ghostModel.rotation.y = this.placementRotation;\n };\n\n private onPlacementCancel = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\") return;\n\n if (!this.ghostModel) return;\n\n console.log(\"[PGSG Viewer] Placement cancelled\");\n\n this.scene.remove(this.ghostModel);\n this.ghostModel = undefined;\n this.pendingPlacementUrl = undefined;\n\n this.renderer.domElement.style.cursor = \"default\";\n\n this.renderer.domElement.removeEventListener(\n \"mousemove\",\n this.onPlacementMove,\n );\n this.renderer.domElement.removeEventListener(\"click\", this.onSceneClick);\n this.renderer.domElement.removeEventListener(\n \"wheel\",\n this.onPlacementWheel,\n );\n\n window.removeEventListener(\"keydown\", this.onPlacementCancel);\n };\n\n private onSelectObject = (event: MouseEvent) => {\n if (this.pendingPlacementUrl) return;\n if (this.transformControls?.dragging) return; // avoid clicks during gizmo drag\n\n const rect = this.renderer.domElement.getBoundingClientRect();\n this.mouse.set(\n ((event.clientX - rect.left) / rect.width) * 2 - 1,\n -((event.clientY - rect.top) / rect.height) * 2 + 1,\n );\n\n this.raycaster.setFromCamera(this.mouse, this.camera);\n const hits = this.raycaster.intersectObjects(this.placedObjects, true);\n\n // ✅ Clicked empty space → deselect\n if (!hits.length) {\n this.selectedObject = undefined;\n this.transformControls?.detach();\n this.selectOutline.selectedObjects = [];\n return;\n }\n\n // find placed root\n let root: THREE.Object3D | null = hits[0].object;\n while (root && !this.placedObjects.includes(root)) root = root.parent;\n\n if (!root) return;\n\n this.selectedObject = root;\n this.transformControls?.attach(root);\n this.selectOutline.selectedObjects = this.collectMeshes(root);\n };\n\n private onHoverObject = (event: MouseEvent) => {\n if (this.pendingPlacementUrl) return;\n if (this.transformControls?.dragging) return; // don't hover-highlight while dragging\n\n const rect = this.renderer.domElement.getBoundingClientRect();\n this.mouse.set(\n ((event.clientX - rect.left) / rect.width) * 2 - 1,\n -((event.clientY - rect.top) / rect.height) * 2 + 1,\n );\n\n this.raycaster.setFromCamera(this.mouse, this.camera);\n const hits = this.raycaster.intersectObjects(this.placedObjects, true);\n\n if (!hits.length) {\n this.hoveredObject = undefined;\n this.hoverOutline.selectedObjects = [];\n this.renderer.domElement.style.cursor = \"default\";\n return;\n }\n\n let root: THREE.Object3D | null = hits[0].object;\n while (root && !this.placedObjects.includes(root)) root = root.parent;\n if (!root) return;\n\n if (root !== this.hoveredObject) {\n this.hoveredObject = root;\n this.hoverOutline.selectedObjects = this.collectMeshes(root);\n this.renderer.domElement.style.cursor = \"pointer\";\n }\n };\n\n private onDeleteObject = (event: KeyboardEvent) => {\n const tag = (event.target as HTMLElement | null)?.tagName?.toLowerCase();\n if (tag === \"input\" || tag === \"textarea\") return;\n\n if (event.key !== \"Delete\" && event.key !== \"Backspace\") return;\n if (!this.selectedObject) return;\n\n event.preventDefault();\n\n this.selectedObject.parent?.remove(this.selectedObject);\n\n this.placedObjects = this.placedObjects.filter(\n (o) => o !== this.selectedObject,\n );\n\n this.transformControls?.detach();\n this.selectOutline.selectedObjects = [];\n this.hoverOutline.selectedObjects = [];\n\n this.selectedObject = undefined;\n };\n}\n","import { SplatMesh } from \"@sparkjsdev/spark\";\nimport * as THREE from \"three\";\nimport type { ViewerSource } from \"../../core/types\";\nimport { computePLYBounds, parsePLYHeader } from \"../three/utils\";\n\nexport class SparkSplatRenderer {\n private mesh!: SplatMesh;\n\n async load(source: ViewerSource) {\n if (source.type !== \"ply\" && source.type !== \"pgsg\") {\n throw new Error(\"SparkJS supports splat-based sources only\");\n }\n\n // const res = await fetch(source.url);\n // const buffer = await res.arrayBuffer();\n\n // const { vertexCount, headerSize } = parsePLYHeader(buffer);\n // const bounds = computePLYBounds(buffer, headerSize, vertexCount);\n\n this.mesh = new SplatMesh({\n url: source.url,\n });\n\n await this.mesh.initialized;\n this.mesh.updateMatrixWorld(true);\n\n const box = this.mesh.getBoundingBox(true);\n\n const min = box.min.clone();\n const max = box.max.clone();\n\n // Match SparkJS doc defaults\n this.mesh.position.set(0, 0, 0);\n this.mesh.quaternion.identity();\n\n return {\n mesh: this.mesh,\n bounds: {\n min,\n max,\n },\n };\n }\n\n addToScene(scene: THREE.Scene) {\n scene.add(this.mesh);\n }\n\n update(dt: number) {\n // optional: rotation / animation\n }\n\n destroy(scene: THREE.Scene) {\n scene.remove(this.mesh);\n this.mesh.dispose?.();\n }\n}\n","import * as THREE from \"three\";\nimport * as RAPIER from \"@dimforge/rapier3d-compat\";\n\nexport type RapierWalkOptions = {\n dom: HTMLElement;\n camera: THREE.PerspectiveCamera;\n world: RAPIER.World;\n\n radius?: number;\n halfHeight?: number;\n eyeHeight?: number;\n\n moveSpeed?: number;\n jumpSpeed?: number;\n lookSensitivity?: number;\n\n usePointerLock?: boolean;\n\n // small tuning values\n groundProbeExtra?: number; // extra ray length\n groundSnapMax?: number; // max snap distance\n};\n\nexport class RapierWalkController {\n private dom: HTMLElement;\n private camera: THREE.PerspectiveCamera;\n private world: RAPIER.World;\n\n private body: RAPIER.RigidBody;\n private collider: RAPIER.Collider;\n\n private radius: number;\n private halfHeight: number;\n private eyeHeight: number;\n\n private moveSpeed: number;\n private jumpSpeed: number;\n private lookSensitivity: number;\n\n private usePointerLock: boolean;\n\n private yaw = 0;\n private pitch = 0;\n\n private keys = new Set<string>();\n private moveVec = new THREE.Vector2(0, 0); // joystick: x=forward, y=right\n\n private groundProbeExtra: number;\n private groundSnapMax: number;\n\n // ---- bound handlers (so dispose works) ----\n private onClickBound = () => this.onClick();\n private onMouseMoveBound = (e: MouseEvent) => this.onMouseMove(e);\n private onKeyDownBound = (e: KeyboardEvent) => this.onKeyDown(e);\n private onKeyUpBound = (e: KeyboardEvent) => this.onKeyUp(e);\n private onBlurBound = () => this.onBlur();\n\n constructor(opts: RapierWalkOptions) {\n this.dom = opts.dom;\n this.camera = opts.camera;\n this.world = opts.world;\n\n this.radius = opts.radius ?? 0.2;\n this.halfHeight = opts.halfHeight ?? 0.6;\n this.eyeHeight = opts.eyeHeight ?? 1.6;\n\n this.moveSpeed = opts.moveSpeed ?? 3.0;\n this.jumpSpeed = opts.jumpSpeed ?? 6.0;\n this.lookSensitivity = opts.lookSensitivity ?? 0.0022;\n\n this.usePointerLock = opts.usePointerLock ?? true;\n\n this.groundProbeExtra = opts.groundProbeExtra ?? 0.25;\n this.groundSnapMax = opts.groundSnapMax ?? 0.65;\n\n // init yaw/pitch from camera\n const euler = new THREE.Euler().setFromQuaternion(\n this.camera.quaternion,\n \"YXZ\",\n );\n this.pitch = euler.x;\n this.yaw = euler.y;\n\n // Create capsule rigidbody at camera position (best guess)\n const start = this.camera.position.clone();\n const centerY = start.y - this.eyeHeight + (this.halfHeight + this.radius);\n\n const bodyDesc = RAPIER.RigidBodyDesc.dynamic()\n .setTranslation(start.x, centerY, start.z)\n .lockRotations()\n .setLinearDamping(6.0) // higher damping to kill drift\n .setCcdEnabled(true);\n\n this.body = this.world.createRigidBody(bodyDesc);\n\n const colDesc = RAPIER.ColliderDesc.capsule(this.halfHeight, this.radius)\n .setFriction(0.8)\n .setRestitution(0.0);\n\n this.collider = this.world.createCollider(colDesc, this.body);\n\n // optional: helps prevent “sucked into edges”\n this.collider.setActiveEvents?.(RAPIER.ActiveEvents.COLLISION_EVENTS);\n\n this.bindInput();\n }\n\n dispose() {\n this.unbindInput();\n // optional: if you want to remove from world completely\n // this.world.removeRigidBody(this.body);\n if (this.body) {\n this.world.removeRigidBody(this.body);\n }\n }\n\n // ---------------------------\n // External movement (joystick)\n // x = forward/back (-1..1), y = right/left (-1..1)\n // ---------------------------\n setMovementVector(x: number, y: number) {\n this.moveVec.set(x, y);\n }\n\n setRotation(yaw: number, pitch: number) {\n this.yaw = yaw;\n this.pitch = THREE.MathUtils.clamp(\n pitch,\n -Math.PI / 2 + 0.01,\n Math.PI / 2 - 0.01,\n );\n this.camera.quaternion.setFromEuler(\n new THREE.Euler(this.pitch, this.yaw, 0, \"YXZ\"),\n );\n }\n\n resetVelocity() {\n this.body.setLinvel({ x: 0, y: 0, z: 0 }, true);\n this.body.setAngvel({ x: 0, y: 0, z: 0 }, true);\n }\n\n setPositionFromCamera() {\n const p = this.camera.position;\n const centerY = p.y - this.eyeHeight + (this.halfHeight + this.radius);\n this.body.setTranslation({ x: p.x, y: centerY, z: p.z }, true);\n this.resetVelocity();\n }\n\n // Snap the capsule so its feet rest on the nearest floor below\n snapToGround() {\n const p = this.body.translation();\n\n const origin = { x: p.x, y: p.y + 2.0, z: p.z };\n const dir = { x: 0, y: -1, z: 0 };\n const ray = new RAPIER.Ray(origin, dir);\n\n const maxDist = 50;\n\n const hit = this.castRayWithNormal(ray, maxDist);\n if (!hit) return;\n\n // place feet just above hit point\n const toi = hit.timeOfImpact;\n const hitY = origin.y - toi;\n\n const newCenterY = hitY + (this.halfHeight + this.radius) + 0.02;\n this.body.setTranslation({ x: p.x, y: newCenterY, z: p.z }, true);\n this.resetVelocity();\n }\n\n // ---------------------------\n // Input binding\n // ---------------------------\n private bindInput() {\n if (this.usePointerLock) {\n this.dom.addEventListener(\"click\", this.onClickBound);\n window.addEventListener(\"mousemove\", this.onMouseMoveBound);\n }\n window.addEventListener(\"keydown\", this.onKeyDownBound);\n window.addEventListener(\"keyup\", this.onKeyUpBound);\n window.addEventListener(\"blur\", this.onBlurBound);\n }\n\n private unbindInput() {\n this.dom.removeEventListener(\"click\", this.onClickBound);\n window.removeEventListener(\"mousemove\", this.onMouseMoveBound);\n window.removeEventListener(\"keydown\", this.onKeyDownBound);\n window.removeEventListener(\"keyup\", this.onKeyUpBound);\n window.removeEventListener(\"blur\", this.onBlurBound);\n }\n\n private onClick() {\n if (!this.usePointerLock) return;\n if (document.pointerLockElement !== this.dom) this.dom.requestPointerLock();\n }\n\n private onBlur() {\n this.keys.clear();\n this.moveVec.set(0, 0);\n }\n\n private onMouseMove(e: MouseEvent) {\n if (!this.usePointerLock) return;\n if (document.pointerLockElement !== this.dom) return;\n\n this.yaw -= e.movementX * this.lookSensitivity;\n this.pitch -= e.movementY * this.lookSensitivity;\n this.pitch = THREE.MathUtils.clamp(\n this.pitch,\n -Math.PI / 2 + 0.01,\n Math.PI / 2 - 0.01,\n );\n\n this.camera.quaternion.setFromEuler(\n new THREE.Euler(this.pitch, this.yaw, 0, \"YXZ\"),\n );\n }\n\n private onKeyDown(e: KeyboardEvent) {\n this.keys.add(e.key.toLowerCase());\n }\n\n private onKeyUp(e: KeyboardEvent) {\n this.keys.delete(e.key.toLowerCase());\n }\n\n // ---------------------------\n // Update\n // ---------------------------\n update(_dt: number) {\n // yaw-only basis from yaw (not full camera direction) -> avoids pitch causing weird forces\n const forward = new THREE.Vector3(0, 0, -1).applyAxisAngle(\n new THREE.Vector3(0, 1, 0),\n this.yaw,\n );\n const right = new THREE.Vector3(1, 0, 0).applyAxisAngle(\n new THREE.Vector3(0, 1, 0),\n this.yaw,\n );\n\n const wish = new THREE.Vector3();\n\n // keyboard\n if (this.keys.has(\"w\")) wish.add(forward);\n if (this.keys.has(\"s\")) wish.sub(forward);\n if (this.keys.has(\"d\")) wish.add(right);\n if (this.keys.has(\"a\")) wish.sub(right);\n\n // joystick\n if (this.moveVec.lengthSq() > 1e-6) {\n wish.addScaledVector(forward, this.moveVec.x);\n wish.addScaledVector(right, this.moveVec.y);\n }\n\n if (wish.lengthSq() > 1e-8) wish.normalize();\n\n const vel = this.body.linvel();\n\n // 🔥 kill drift when no input\n const targetVX = wish.x * this.moveSpeed;\n const targetVZ = wish.z * this.moveSpeed;\n\n this.body.setLinvel(\n {\n x: targetVX,\n y: vel.y,\n z: targetVZ,\n },\n true, // wake up\n );\n\n // jump\n if (this.keys.has(\" \")) {\n if (this.isGrounded()) {\n this.body.setLinvel(\n { x: targetVX, y: this.jumpSpeed, z: targetVZ },\n true,\n );\n }\n }\n\n // sync camera to body\n const p = this.body.translation();\n const feetY = p.y - (this.halfHeight + this.radius);\n this.camera.position.set(p.x, feetY + this.eyeHeight, p.z);\n }\n\n // ---------------------------\n // Grounding\n // ---------------------------\n private isGrounded(): boolean {\n const p = this.body.translation();\n\n const origin = { x: p.x, y: p.y, z: p.z };\n const dir = { x: 0, y: -1, z: 0 };\n const ray = new RAPIER.Ray(origin, dir);\n\n const maxDist = this.halfHeight + this.radius + this.groundProbeExtra;\n const hit = this.castRayWithNormal(ray, maxDist);\n if (!hit) return false;\n\n // accept “up-ish” surfaces\n const ny = hit.normal?.y ?? 0;\n return ny > 0.35;\n }\n\n // Ray cast helper with “exclude self” when possible\n private castRayWithNormal(ray: RAPIER.Ray, maxDist: number) {\n // If QueryFilter exists in your build, use it to exclude the player collider.\n const anyRapier: any = RAPIER as any;\n\n try {\n if (anyRapier.QueryFilter) {\n const filter = new anyRapier.QueryFilter();\n // exclude collider preferred\n if (filter.excludeCollider) filter.excludeCollider(this.collider);\n else if (filter.excludeRigidBody) filter.excludeRigidBody(this.body);\n\n return this.world.castRayAndGetNormal(ray, maxDist, true, filter);\n }\n } catch {\n // ignore, fall back below\n }\n\n // Fallback (no filter): may occasionally hit self if Rapier allows, but often still ok.\n return this.world.castRayAndGetNormal(ray, maxDist, true);\n }\n}\n","import * as THREE from \"three\";\n\nexport interface OrbitOptions {\n target: THREE.Vector3;\n distance: number;\n minDistance?: number;\n maxDistance?: number;\n rotateSpeed?: number;\n zoomSpeed?: number;\n usePointerLock?: boolean;\n}\n\nexport class OrbitCameraController {\n private camera: THREE.PerspectiveCamera;\n private dom: HTMLElement;\n\n private target: THREE.Vector3;\n private distance: number;\n private minDistance: number;\n private maxDistance: number;\n\n private yaw = 0;\n private pitch = 0;\n\n private rotateSpeed: number;\n private zoomSpeed: number;\n\n private dragging = false;\n private lastX = 0;\n private lastY = 0;\n\n private panning = false;\n private panSpeed = 0.002;\n\n private usePointerLock?: boolean = false;\n private lastTouchX = 0;\n private lastTouchY = 0;\n private externalMove = new THREE.Vector2(0, 0);\n private moveSpeed: number = 5;\n\n public enabled = true;\n\n constructor(\n camera: THREE.PerspectiveCamera,\n dom: HTMLElement,\n opts: OrbitOptions,\n ) {\n this.camera = camera;\n this.dom = dom;\n\n this.target = opts.target.clone();\n this.distance = opts.distance;\n this.minDistance = opts.minDistance ?? 0.2;\n this.maxDistance = opts.maxDistance ?? 500;\n\n this.rotateSpeed = opts.rotateSpeed ?? 0.005;\n this.zoomSpeed = opts.zoomSpeed ?? 1.1;\n this.usePointerLock = opts.usePointerLock ?? false;\n\n this.syncFromCamera();\n if (this.usePointerLock === false) {\n this.bindTouch();\n } else {\n this.bind();\n this.updateCamera();\n }\n }\n\n update(dt: number) {\n if (this.externalMove.lengthSq() === 0) return;\n\n const forward = new THREE.Vector3();\n this.camera.getWorldDirection(forward);\n forward.y = 0;\n forward.normalize();\n\n const right = new THREE.Vector3()\n .crossVectors(forward, new THREE.Vector3(0, 1, 0))\n .normalize();\n\n const move = new THREE.Vector3()\n .addScaledVector(forward, this.externalMove.x)\n .addScaledVector(right, this.externalMove.y);\n\n if (move.lengthSq() > 0) move.normalize();\n\n move.multiplyScalar(this.moveSpeed * dt);\n\n this.target.add(move);\n\n this.updateCamera();\n }\n\n dispose() {\n if (this.usePointerLock === false) {\n this.unbindTouch();\n } else {\n this.unbind();\n if (this.usePointerLock) document.exitPointerLock();\n }\n }\n\n setMovementVector(x: number, y: number) {\n this.externalMove.set(x, y);\n }\n\n // -----------------------------\n // Setup\n // -----------------------------\n\n private bind() {\n this.dom.addEventListener(\"contextmenu\", (e) => e.preventDefault());\n this.dom.addEventListener(\"mousedown\", this.onMouseDown);\n window.addEventListener(\"mouseup\", this.onMouseUp);\n window.addEventListener(\"mousemove\", this.onMouseMove);\n this.dom.addEventListener(\"wheel\", this.onWheel, { passive: false });\n }\n\n private bindTouch() {\n this.dom.addEventListener(\"touchstart\", this.onTouchStart);\n this.dom.addEventListener(\"touchmove\", this.onTouchMove);\n }\n\n private unbind() {\n this.dom.removeEventListener(\"mousedown\", this.onMouseDown);\n window.removeEventListener(\"mouseup\", this.onMouseUp);\n window.removeEventListener(\"mousemove\", this.onMouseMove);\n this.dom.removeEventListener(\"wheel\", this.onWheel);\n }\n\n private unbindTouch() {\n this.dom.removeEventListener(\"touchstart\", this.onTouchStart);\n this.dom.removeEventListener(\"touchmove\", this.onTouchMove);\n }\n\n private syncFromCamera() {\n const offset = this.camera.position.clone().sub(this.target);\n this.distance = offset.length();\n\n const spherical = new THREE.Spherical().setFromVector3(offset);\n this.yaw = spherical.theta;\n this.pitch = spherical.phi;\n }\n\n // -----------------------------\n // Input\n // -----------------------------\n\n private onMouseDown = (e: MouseEvent) => {\n if (!this.enabled) return;\n if (e.button === 0) {\n // LEFT = orbit\n this.dragging = true;\n } else if (e.button === 2 || e.button === 1) {\n // RIGHT or MIDDLE = pan\n this.panning = true;\n }\n\n this.lastX = e.clientX;\n this.lastY = e.clientY;\n };\n\n private onMouseUp = () => {\n this.dragging = false;\n this.panning = false;\n };\n\n private onMouseMove = (e: MouseEvent) => {\n if (!this.enabled) return;\n if (!this.dragging && !this.panning) return;\n\n const dx = e.clientX - this.lastX;\n const dy = e.clientY - this.lastY;\n\n this.lastX = e.clientX;\n this.lastY = e.clientY;\n\n // -----------------\n // ORBIT ROTATION\n // -----------------\n if (this.dragging) {\n this.yaw -= dx * this.rotateSpeed;\n this.pitch -= dy * this.rotateSpeed;\n\n this.pitch = THREE.MathUtils.clamp(this.pitch, 0.01, Math.PI - 0.01);\n\n this.updateCamera();\n return;\n }\n\n // -----------------\n // PANNING\n // -----------------\n if (this.panning) {\n const panScale = this.distance * this.panSpeed;\n\n const right = new THREE.Vector3();\n const up = new THREE.Vector3();\n\n this.camera.getWorldDirection(up);\n right.crossVectors(this.camera.up, up).normalize();\n up.crossVectors(\n right,\n this.camera.getWorldDirection(new THREE.Vector3()),\n ).normalize();\n\n const panOffset = new THREE.Vector3()\n .addScaledVector(right, dx * panScale)\n .addScaledVector(up, -dy * panScale);\n\n this.target.add(panOffset);\n this.camera.position.add(panOffset);\n\n // no updateCamera() — we already moved both\n }\n };\n\n private onWheel = (e: WheelEvent) => {\n if (!this.enabled) return;\n e.preventDefault();\n\n const zoomFactor = Math.pow(this.zoomSpeed, e.deltaY / 100);\n this.distance *= zoomFactor;\n\n this.distance = THREE.MathUtils.clamp(\n this.distance,\n this.minDistance,\n this.maxDistance,\n );\n\n this.updateCamera();\n };\n\n private onTouchStart = (e: TouchEvent) => {\n if (!this.enabled) return;\n const t = e.touches[0];\n this.lastTouchX = t.clientX;\n this.lastTouchY = t.clientY;\n };\n\n private onTouchMove = (e: TouchEvent) => {\n if (!this.enabled) return;\n const t = e.touches[0];\n\n const deltaX = t.clientX - this.lastTouchX;\n const deltaY = t.clientY - this.lastTouchY;\n\n this.lastTouchX = t.clientX;\n this.lastTouchY = t.clientY;\n\n this.yaw -= deltaX * 0.002;\n this.pitch -= deltaY * 0.002;\n\n this.pitch = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, this.pitch));\n this.camera.quaternion.setFromEuler(\n new THREE.Euler(this.pitch, this.yaw, 0, \"YXZ\"),\n );\n };\n\n // -----------------------------\n // Camera math\n // -----------------------------\n\n private updateCamera() {\n const spherical = new THREE.Spherical(this.distance, this.pitch, this.yaw);\n\n const pos = new THREE.Vector3()\n .setFromSpherical(spherical)\n .add(this.target);\n\n this.camera.position.copy(pos);\n this.camera.lookAt(this.target);\n }\n\n setTarget(v: THREE.Vector3) {\n this.target.copy(v);\n this.updateCamera();\n }\n}\n","import * as THREE from \"three\";\n\nexport type MeasurementOptions = {\n dom: HTMLElement;\n camera: THREE.PerspectiveCamera;\n scene: THREE.Scene;\n colliders: THREE.Object3D[];\n};\n\ninterface Measurement {\n points: THREE.Vector3[];\n markers: THREE.Mesh[];\n lines: THREE.Line[]; // Changed from line: THREE.Line\n labels: HTMLDivElement[]; // Changed from label: HTMLDivElement\n}\n\nexport class MeasurementController {\n private dom: HTMLElement;\n private camera: THREE.PerspectiveCamera;\n private scene: THREE.Scene;\n private colliders: THREE.Object3D[];\n\n private raycaster = new THREE.Raycaster();\n private mouse = new THREE.Vector2();\n\n private measurements: Measurement[] = [];\n private activePoints: THREE.Vector3[] = [];\n private activeMarkers: THREE.Mesh[] = [];\n private activeLines: THREE.Line[] = [];\n private activeLabels: HTMLDivElement[] = [];\n\n // Ghost elements for the *next* potential segment\n private ghostLine: THREE.Line | null = null;\n private ghostLabel: HTMLDivElement | null = null;\n private lastGhostPoint: THREE.Vector3 | null = null;\n\n private yaw = 0;\n private pitch = Math.PI / 4;\n private dragging = false;\n private panning = false;\n private lastX = 0;\n private lastY = 0;\n private rotateSpeed = 0.005;\n private panSpeed = 0.01;\n private keys: Record<string, boolean> = {};\n private moveSpeed: number = 10;\n private isVisible = true;\n\n constructor(opts: MeasurementOptions) {\n this.dom = opts.dom;\n this.camera = opts.camera;\n this.scene = opts.scene;\n this.colliders = opts.colliders;\n\n this.bind();\n this.bindKeyboard();\n }\n\n dispose() {\n this.unbind();\n this.unbindKeyboard();\n this.clearAll();\n }\n\n private bindKeyboard() {\n window.addEventListener(\"keydown\", this.onKeyDown);\n window.addEventListener(\"keyup\", this.onKeyUp);\n }\n\n private unbindKeyboard() {\n window.removeEventListener(\"keydown\", this.onKeyDown);\n window.removeEventListener(\"keyup\", this.onKeyUp);\n }\n\n private onKeyDown = (e: KeyboardEvent) => {\n this.keys[e.code] = true;\n };\n\n private onKeyUp = (e: KeyboardEvent) => {\n this.keys[e.code] = false;\n };\n\n public setVisible(visible: boolean) {\n this.isVisible = visible;\n this.measurements.forEach(m => {\n m.markers.forEach(mk => mk.visible = visible);\n m.lines.forEach(l => l.visible = visible);\n if (!visible) m.labels.forEach(lbl => lbl.style.display = \"none\");\n });\n\n this.activeMarkers.forEach(mk => mk.visible = visible);\n this.activeLines.forEach(l => l.visible = visible);\n if (!visible) this.activeLabels.forEach(lbl => lbl.style.display = \"none\");\n\n if (this.ghostLine) this.ghostLine.visible = visible;\n if (this.ghostLabel && !visible) this.ghostLabel.style.display = \"none\";\n }\n\n private bind() {\n this.dom.addEventListener(\"contextmenu\", (e) => e.preventDefault());\n this.dom.addEventListener(\"mousedown\", this.onMouseDown);\n window.addEventListener(\"mousemove\", this.onMouseMove);\n window.addEventListener(\"mouseup\", this.onMouseUp);\n }\n\n private unbind() {\n this.dom.removeEventListener(\"mousedown\", this.onMouseDown);\n window.removeEventListener(\"mousemove\", this.onMouseMove);\n window.removeEventListener(\"mouseup\", this.onMouseUp);\n }\n\n private onMouseDown = (e: MouseEvent) => {\n if (e.button === 0) {\n if (!this.isVisible) return;\n if (e.shiftKey) {\n this.dragging = true;\n } else {\n this.handleLeftClick(e);\n }\n } else if (e.button === 2) {\n this.panning = true;\n if (this.isVisible) this.handleRightClick(e);\n } else if (e.button === 1) {\n this.dragging = true;\n }\n\n this.lastX = e.clientX;\n this.lastY = e.clientY;\n };\n\n private onMouseUp = () => {\n this.dragging = false;\n this.panning = false;\n };\n\n private handleLeftClick(e: MouseEvent) {\n const rect = this.dom.getBoundingClientRect();\n this.mouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;\n this.mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;\n\n this.raycaster.setFromCamera(this.mouse, this.camera);\n const intersects = this.raycaster.intersectObjects(this.colliders, true);\n\n if (intersects.length > 0) {\n const hit = intersects[0].point;\n this.addPoint(hit);\n }\n }\n\n private handleRightClick(e: MouseEvent) {\n console.log(\"[Measure] handleRightClick, activePoints:\", this.activePoints.length);\n if (this.activePoints.length > 0) {\n this.finalizePolyline();\n }\n }\n\n private onMouseMove = (e: MouseEvent) => {\n const dx = e.clientX - this.lastX;\n const dy = e.clientY - this.lastY;\n this.lastX = e.clientX;\n this.lastY = e.clientY;\n\n if (!this.isVisible && !this.dragging && !this.panning) return;\n\n if (this.dragging) {\n this.yaw -= dx * this.rotateSpeed;\n this.pitch -= dy * this.rotateSpeed;\n this.pitch = Math.max(0.01, Math.min(Math.PI - 0.01, this.pitch));\n this.camera.quaternion.setFromEuler(new THREE.Euler(this.pitch, this.yaw, 0, 'YXZ'));\n return;\n }\n\n if (this.panning) {\n const right = new THREE.Vector3().set(1, 0, 0).applyQuaternion(this.camera.quaternion);\n const up = new THREE.Vector3().set(0, 1, 0).applyQuaternion(this.camera.quaternion);\n const pan = new THREE.Vector3().addScaledVector(right, -dx * this.panSpeed).addScaledVector(up, dy * this.panSpeed);\n this.camera.position.add(pan);\n return;\n }\n\n if (this.activePoints.length > 0 || true) { // Always update mouse pos for raycasting\n const rect = this.dom.getBoundingClientRect();\n this.mouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;\n this.mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;\n\n if (this.activePoints.length > 0) {\n this.raycaster.setFromCamera(this.mouse, this.camera);\n const intersects = this.raycaster.intersectObjects(this.colliders, true);\n if (intersects.length > 0) {\n this.lastGhostPoint = intersects[0].point.clone();\n this.updateGhost(this.activePoints[this.activePoints.length - 1], this.lastGhostPoint);\n }\n }\n }\n };\n\n private addPoint(pos: THREE.Vector3) {\n // Add Marker for new point\n const marker = this.createMarker(pos);\n this.scene.add(marker);\n this.activeMarkers.push(marker);\n\n // If this isn't the first point, create a permanent line + label from previous point\n if (this.activePoints.length > 0) {\n const prev = this.activePoints[this.activePoints.length - 1];\n const current = pos.clone();\n\n const line = this.createLine(prev, current, 0.8); // 0.8 opacity for permanent\n this.scene.add(line);\n this.activeLines.push(line);\n\n const label = this.createLabel();\n this.updateLabelPos(label, prev, current);\n this.activeLabels.push(label);\n }\n\n this.activePoints.push(pos.clone());\n }\n\n private updateGhost(p1: THREE.Vector3, p2: THREE.Vector3) {\n // Update Line\n if (this.ghostLine) this.scene.remove(this.ghostLine);\n this.ghostLine = this.createLine(p1, p2, 0.4); // lower opacity for ghost\n this.scene.add(this.ghostLine);\n\n // Update Label\n if (!this.ghostLabel) {\n this.ghostLabel = this.createLabel();\n }\n this.updateLabelPos(this.ghostLabel, p1, p2);\n }\n\n public finalizePolyline() {\n console.log(\"[Measure] finalizePolyline, points:\", this.activePoints.length);\n if (this.activePoints.length === 0) {\n this.clearActiveSession();\n return;\n }\n\n // Bundle everything into a measurement object\n // NOTE: In a real polyline impl, we might want to store all segments. \n // For 'getMeasurements', we'll flatten this or just store lines.\n // For now, let's treat the whole polyline as one \"Measurement\" entry \n // but it holds multiple lines/markers.\n\n // We'll trick the existing structure a bit or assume the consumer handles it,\n // but to keep it compatible with existing types, let's construct a \"Measurement\" \n // that holds arrays of these things.\n\n // Actually, we're better off refactoring `Measurement` interface if we want true polyline support.\n // But to stick to the requested \"add multiple point functionality\" quickly:\n // We will push ONE measurement object per polyline.\n // However, the `Measurement` interface defined previously had `line: THREE.Line` (singular).\n // Let's update `Measurement` interface to support multiple.\n\n // Wait, to avoid breaking too much code, let's just make `Measurement` hold arrays of lines too?\n // Or better: Each segment is a measurement? No, that spams the list.\n // Let's assume a \"Distance\" is total distance? \n\n // Let's assume the user just wants to click-click-click and leave trails.\n // We will group them.\n\n const newMeasurement: Measurement = {\n points: [...this.activePoints],\n markers: [...this.activeMarkers],\n // We need to change the interface to support multiple lines/labels or change how we store them.\n // For this specific 'hack' to work with minimal changes, let's cast or change the type below.\n // See 'createLine' helper.\n lines: [...this.activeLines],\n labels: [...this.activeLabels]\n } as any;\n\n this.measurements.push(newMeasurement);\n\n // Clear active session state WITHOUT removing from scene\n this.activePoints = [];\n this.activeMarkers = [];\n this.activeLines = [];\n this.activeLabels = [];\n\n if (this.ghostLine) {\n this.scene.remove(this.ghostLine);\n this.ghostLine = null;\n }\n if (this.ghostLabel) {\n this.ghostLabel.remove();\n this.ghostLabel = null;\n }\n this.lastGhostPoint = null;\n }\n\n private clearActiveSession() {\n this.activeMarkers.forEach(mk => this.scene.remove(mk));\n this.activeLines.forEach(l => this.scene.remove(l));\n this.activeLabels.forEach(l => l.remove());\n\n this.activePoints = [];\n this.activeMarkers = [];\n this.activeLines = [];\n this.activeLabels = [];\n\n if (this.ghostLine) {\n this.scene.remove(this.ghostLine);\n this.ghostLine = null;\n }\n if (this.ghostLabel) {\n this.ghostLabel.remove();\n this.ghostLabel = null;\n }\n this.lastGhostPoint = null;\n }\n\n private createLine(p1: THREE.Vector3, p2: THREE.Vector3, opacity: number) {\n const geometry = new THREE.BufferGeometry().setFromPoints([p1, p2]);\n const material = new THREE.LineBasicMaterial({\n color: 0xffffff,\n linewidth: 1,\n depthTest: false,\n transparent: true,\n opacity: opacity\n });\n const line = new THREE.Line(geometry, material);\n line.renderOrder = 1000;\n line.frustumCulled = false;\n return line;\n }\n\n private createMarker(pos: THREE.Vector3) {\n const marker = new THREE.Mesh(\n new THREE.SphereGeometry(0.02),\n new THREE.MeshBasicMaterial({\n color: 0xffffff,\n depthTest: false,\n transparent: true,\n opacity: 0.9\n })\n );\n marker.position.copy(pos);\n marker.renderOrder = 1001;\n marker.frustumCulled = false;\n return marker;\n }\n\n private createLabel() {\n const label = document.createElement(\"div\");\n label.style.position = \"absolute\";\n label.style.pointerEvents = \"none\";\n label.style.background = \"rgba(0,0,0,0.6)\";\n label.style.color = \"white\";\n label.style.padding = \"4px 8px\";\n label.style.borderRadius = \"12px\";\n label.style.fontSize = \"11px\";\n label.style.fontFamily = \"sans-serif\";\n label.style.fontWeight = \"500\";\n label.style.zIndex = \"100\";\n label.style.backdropFilter = \"blur(4px)\";\n // label.style.border = \"1px solid rgba(255,255,255,0.2)\";\n this.dom.parentElement?.appendChild(label);\n return label;\n }\n\n private updateLabelPos(label: HTMLDivElement, p1: THREE.Vector3, p2: THREE.Vector3) {\n const distance = p1.distanceTo(p2);\n const midPoint = new THREE.Vector3().lerpVectors(p1, p2, 0.5);\n const vector = midPoint.project(this.camera);\n\n if (vector.z > 1) {\n label.style.display = \"none\";\n return;\n }\n\n const x = (vector.x * 0.5 + 0.5) * this.dom.clientWidth;\n const y = (-(vector.y * 0.5) + 0.5) * this.dom.clientHeight;\n\n label.style.left = `${x}px`;\n label.style.top = `${y}px`;\n label.innerText = `${distance.toFixed(3)}m`;\n label.style.display = (this.isVisible && vector.z <= 1) ? \"block\" : \"none\";\n }\n\n public restoreMeasurements(measurements: Measurement[]) {\n this.measurements = measurements;\n this.measurements.forEach(m => {\n m.markers.forEach(mk => {\n mk.visible = this.isVisible;\n this.scene.add(mk);\n });\n m.lines.forEach(l => {\n l.visible = this.isVisible;\n this.scene.add(l);\n });\n m.labels.forEach((lbl, idx) => {\n this.dom.parentElement?.appendChild(lbl);\n if (idx < m.points.length - 1) {\n this.updateLabelPos(lbl, m.points[idx], m.points[idx + 1]);\n }\n });\n });\n }\n\n public getMeasurements() {\n return this.measurements.map((m, i) => {\n // Calculate total distance for the polyline\n let totalDist = 0;\n for (let j = 0; j < m.points.length - 1; j++) {\n totalDist += m.points[j].distanceTo(m.points[j + 1]);\n }\n\n return {\n id: i,\n distance: totalDist,\n points: m.points.map(p => p.clone()),\n segments: m.points.length - 1\n };\n });\n }\n\n public deleteMeasurement(index: number) {\n if (index < 0 || index >= this.measurements.length) return;\n const m = this.measurements[index];\n m.markers.forEach(mk => this.scene.remove(mk));\n m.lines.forEach(l => this.scene.remove(l));\n m.labels.forEach(lbl => lbl.remove());\n this.measurements.splice(index, 1);\n }\n\n public clearAll() {\n this.measurements.forEach(m => {\n m.markers.forEach(mk => this.scene.remove(mk));\n m.lines.forEach(l => this.scene.remove(l));\n m.labels.forEach(lbl => lbl.remove());\n });\n this.measurements = [];\n this.activePoints = [];\n if (this.ghostLine) this.scene.remove(this.ghostLine);\n\n // Clear any leftover active markers if the session was abandoned\n this.activeMarkers.forEach(mk => this.scene.remove(mk));\n this.activeLines.forEach(l => this.scene.remove(l));\n this.activeLabels.forEach(l => l.remove());\n\n if (this.ghostLabel) this.ghostLabel.remove();\n this.ghostLine = null;\n this.ghostLabel = null;\n this.lastGhostPoint = null;\n }\n\n update(dt: number = 1 / 60) {\n if (!this.isVisible) return;\n const move = new THREE.Vector3(0, 0, 0);\n\n // Keyboard Movement (WASDQE)\n const forward = new THREE.Vector3();\n this.camera.getWorldDirection(forward);\n const orbitForward = forward.clone();\n orbitForward.y = 0;\n orbitForward.normalize();\n\n const right = new THREE.Vector3()\n .crossVectors(orbitForward, new THREE.Vector3(0, 1, 0))\n .normalize();\n\n if (this.keys[\"KeyW\"]) move.add(orbitForward);\n if (this.keys[\"KeyS\"]) move.sub(orbitForward);\n if (this.keys[\"KeyA\"]) move.sub(right);\n if (this.keys[\"KeyD\"]) move.add(right);\n if (this.keys[\"KeyE\"]) move.y += 1;\n if (this.keys[\"KeyQ\"]) move.y -= 1;\n\n if (move.lengthSq() > 0) {\n move.normalize();\n move.multiplyScalar(this.moveSpeed * dt);\n this.camera.position.add(move);\n }\n\n // Update raycasting/ghost even if mouse isn't moving, because camera is moving\n if (this.activePoints.length > 0) {\n this.raycaster.setFromCamera(this.mouse, this.camera);\n const intersects = this.raycaster.intersectObjects(this.colliders, true);\n if (intersects.length > 0) {\n this.lastGhostPoint = intersects[0].point.clone();\n this.updateGhost(this.activePoints[this.activePoints.length - 1], this.lastGhostPoint);\n }\n }\n\n this.measurements.forEach(m => {\n // Update all labels in this measurement\n m.labels.forEach((lbl, idx) => {\n if (idx < m.points.length - 1) {\n this.updateLabelPos(lbl, m.points[idx], m.points[idx + 1]);\n }\n });\n });\n\n // Also update active session labels\n this.activeLabels.forEach((lbl, idx) => {\n if (idx < this.activePoints.length - 1) {\n this.updateLabelPos(lbl, this.activePoints[idx], this.activePoints[idx + 1]);\n }\n });\n\n if (this.ghostLabel && this.activePoints.length > 0 && this.lastGhostPoint) {\n this.updateLabelPos(this.ghostLabel, this.activePoints[this.activePoints.length - 1], this.lastGhostPoint);\n }\n }\n}\n","import * as THREE from \"three\";\n\nexport type FloorplanOptions = {\n dom: HTMLElement;\n camera: THREE.PerspectiveCamera;\n target: THREE.Vector3;\n height: number; // camera y above target\n panSpeed?: number; // world units per pixel\n zoomSpeed?: number; // wheel multiplier\n minHeight?: number;\n maxHeight?: number;\n};\n\nexport class FloorplanController {\n private dom: HTMLElement;\n private camera: THREE.PerspectiveCamera;\n\n private target: THREE.Vector3;\n private height: number;\n\n private panSpeed: number;\n private zoomSpeed: number;\n private minHeight: number;\n private maxHeight: number;\n\n private isDragging = false;\n private lastX = 0;\n private lastY = 0;\n\n // touch\n private touchMode: \"none\" | \"pan\" | \"pinch\" = \"none\";\n private lastDist = 0;\n\n constructor(opts: FloorplanOptions) {\n this.dom = opts.dom;\n this.camera = opts.camera;\n\n this.target = opts.target.clone();\n this.height = opts.height;\n\n this.panSpeed = opts.panSpeed ?? 0.01;\n this.zoomSpeed = opts.zoomSpeed ?? 1.1;\n this.minHeight = opts.minHeight ?? opts.height * 0.25;\n this.maxHeight = opts.maxHeight ?? opts.height * 3.0;\n\n this.applyCamera();\n this.bind();\n }\n\n dispose() {\n this.unbind();\n }\n\n update(_dt: number) {\n // keep camera locked top-down always\n this.applyCamera();\n }\n\n setTarget(t: THREE.Vector3) {\n this.target.copy(t);\n this.applyCamera();\n }\n\n private applyCamera() {\n this.height = THREE.MathUtils.clamp(\n this.height,\n this.minHeight,\n this.maxHeight,\n );\n this.camera.position.set(\n this.target.x,\n this.target.y + this.height,\n this.target.z,\n );\n this.camera.up.set(0, 0, -1); // keeps “north” stable (optional)\n this.camera.lookAt(this.target);\n }\n\n private bind() {\n this.dom.addEventListener(\"contextmenu\", (e) => e.preventDefault());\n this.dom.addEventListener(\"mousedown\", this.onMouseDown);\n window.addEventListener(\"mousemove\", this.onMouseMove);\n window.addEventListener(\"mouseup\", this.onMouseUp);\n this.dom.addEventListener(\"wheel\", this.onWheel, { passive: false });\n\n this.dom.addEventListener(\"touchstart\", this.onTouchStart, {\n passive: false,\n });\n this.dom.addEventListener(\"touchmove\", this.onTouchMove, {\n passive: false,\n });\n this.dom.addEventListener(\"touchend\", this.onTouchEnd);\n }\n\n private unbind() {\n this.dom.removeEventListener(\"mousedown\", this.onMouseDown);\n window.removeEventListener(\"mousemove\", this.onMouseMove);\n window.removeEventListener(\"mouseup\", this.onMouseUp);\n this.dom.removeEventListener(\"wheel\", this.onWheel);\n\n this.dom.removeEventListener(\"touchstart\", this.onTouchStart);\n this.dom.removeEventListener(\"touchmove\", this.onTouchMove);\n this.dom.removeEventListener(\"touchend\", this.onTouchEnd);\n }\n\n private onMouseDown = (e: MouseEvent) => {\n if (e.button !== 0) return;\n this.isDragging = true;\n this.lastX = e.clientX;\n this.lastY = e.clientY;\n };\n\n private onMouseUp = () => {\n this.isDragging = false;\n };\n\n private onMouseMove = (e: MouseEvent) => {\n if (!this.isDragging) return;\n\n const dx = e.clientX - this.lastX;\n const dy = e.clientY - this.lastY;\n this.lastX = e.clientX;\n this.lastY = e.clientY;\n\n // screen -> world: in top-down, x maps to world x, y maps to world z\n this.target.x -= dx * this.panSpeed * this.height;\n this.target.z += dy * this.panSpeed * this.height;\n\n this.applyCamera();\n };\n\n private onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const factor = Math.pow(this.zoomSpeed, e.deltaY / 100);\n this.height *= factor;\n this.applyCamera();\n };\n\n private onTouchStart = (e: TouchEvent) => {\n if (e.touches.length === 1) {\n this.touchMode = \"pan\";\n this.lastX = e.touches[0].clientX;\n this.lastY = e.touches[0].clientY;\n } else if (e.touches.length === 2) {\n this.touchMode = \"pinch\";\n this.lastDist = this.touchDistance(e.touches[0], e.touches[1]);\n }\n };\n\n private onTouchMove = (e: TouchEvent) => {\n e.preventDefault();\n\n if (this.touchMode === \"pan\" && e.touches.length === 1) {\n const x = e.touches[0].clientX;\n const y = e.touches[0].clientY;\n const dx = x - this.lastX;\n const dy = y - this.lastY;\n this.lastX = x;\n this.lastY = y;\n\n this.target.x -= dx * this.panSpeed * this.height;\n this.target.z += dy * this.panSpeed * this.height;\n\n this.applyCamera();\n }\n\n if (this.touchMode === \"pinch\" && e.touches.length === 2) {\n const dist = this.touchDistance(e.touches[0], e.touches[1]);\n const ratio = this.lastDist / Math.max(1e-6, dist);\n this.lastDist = dist;\n\n this.height *= ratio;\n this.applyCamera();\n }\n };\n\n private onTouchEnd = () => {\n this.touchMode = \"none\";\n };\n\n private touchDistance(a: Touch, b: Touch) {\n const dx = a.clientX - b.clientX;\n const dy = a.clientY - b.clientY;\n return Math.sqrt(dx * dx + dy * dy);\n }\n}\n"],"mappings":"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","names":["THREE","RAPIER","THREE","THREE","THREE"]}