@popaya/pgsg-viewer 0.1.5 → 0.1.6

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.
@@ -10,7 +10,7 @@ var PGSGViewer = class {
10
10
  const { PGSGPlayCanvasViewer } = await import("./pgsg-playcanvas-viewer-4WORM4WU.js");
11
11
  this.engine = new PGSGPlayCanvasViewer(this.options);
12
12
  } else {
13
- const { PGSGThreeViewer } = await import("./pgsg-three-viewer-IJNO2SYE.js");
13
+ const { PGSGThreeViewer } = await import("./pgsg-three-viewer-IJSA555G.js");
14
14
  this.engine = new PGSGThreeViewer(this.options);
15
15
  }
16
16
  await this.engine.load();
@@ -30,4 +30,4 @@ var PGSGViewer = class {
30
30
  export {
31
31
  PGSGViewer
32
32
  };
33
- //# sourceMappingURL=chunk-PRUUK6YZ.js.map
33
+ //# sourceMappingURL=chunk-WFONX3TR.js.map
@@ -1,7 +1,7 @@
1
1
  import "../chunk-PYYLHUV6.js";
2
2
  import {
3
3
  PGSGViewer
4
- } from "../chunk-PRUUK6YZ.js";
4
+ } from "../chunk-WFONX3TR.js";
5
5
  export {
6
6
  PGSGViewer
7
7
  };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import "./chunk-PYYLHUV6.js";
2
2
  import {
3
3
  PGSGViewer
4
- } from "./chunk-PRUUK6YZ.js";
4
+ } from "./chunk-WFONX3TR.js";
5
5
  export {
6
6
  PGSGViewer
7
7
  };
@@ -664,14 +664,14 @@ var PGSGThreeViewer = class {
664
664
  zone.style.position = "absolute";
665
665
  zone.style.left = "20px";
666
666
  zone.style.bottom = "20px";
667
- zone.style.width = "150px";
668
- zone.style.height = "150px";
667
+ zone.style.width = "1000px";
668
+ zone.style.height = "1000px";
669
669
  zone.style.zIndex = "1000";
670
670
  this.container.appendChild(zone);
671
671
  const joystick = nipplejs.create({
672
672
  zone,
673
673
  mode: "static",
674
- position: { left: "75px", bottom: "75px" },
674
+ position: { left: "50px", bottom: "50px" },
675
675
  color: "white"
676
676
  });
677
677
  joystick.on("move", (_, data) => {
@@ -698,7 +698,7 @@ var PGSGThreeViewer = class {
698
698
  const btn = document.createElement("div");
699
699
  btn.style.position = "absolute";
700
700
  btn.style.right = "20px";
701
- btn.style.bottom = "40px";
701
+ btn.style.bottom = "20px";
702
702
  btn.style.width = "70px";
703
703
  btn.style.height = "70px";
704
704
  btn.style.borderRadius = "50%";
@@ -789,4 +789,4 @@ var PGSGThreeViewer = class {
789
789
  export {
790
790
  PGSGThreeViewer
791
791
  };
792
- //# sourceMappingURL=pgsg-three-viewer-IJNO2SYE.js.map
792
+ //# sourceMappingURL=pgsg-three-viewer-IJSA555G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/viewers/three/pgsg-three-viewer.ts","../src/viewers/spark/SparkSplatRenderer.ts","../src/viewers/three/controls/WalkCapsuleController.ts","../src/viewers/three/controls/OrbitCameraController.ts"],"sourcesContent":["import type { PGSGViewerOptions } from \"../../core/types\";\nimport * as THREE from \"three\";\nimport { GLTFLoader } from \"three/examples/jsm/Addons.js\";\nimport nipplejs from \"nipplejs\";\n\nimport { SparkSplatRenderer } from \"../spark/SparkSplatRenderer\";\nimport { WalkCapsuleController } from \"./controls/WalkCapsuleController\";\nimport { OrbitCameraController } from \"./controls/OrbitCameraController\";\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 container: HTMLElement;\n private resizeObserver: ResizeObserver | null = null;\n\n private controls!: WalkCapsuleController | OrbitCameraController;\n private running = false;\n\n private orbitTarget = new THREE.Vector3();\n private lastTime = performance.now();\n\n private colliders: THREE.Object3D[] = [];\n\n private worldRoot = new THREE.Object3D();\n private splatPivot = new THREE.Object3D();\n private colliderMesh?: THREE.Object3D;\n\n private modeButton?: HTMLDivElement;\n\n constructor(private options: PGSGViewerOptions) {\n this.container = options.container;\n this.options = options;\n if (!this.container) {\n throw new Error(\"[PGSGThreeViewer] Container is required\");\n }\n }\n\n async load() {\n this.initRenderer();\n this.initCamera();\n this.initScene();\n\n // Resize\n this.bindResize();\n this.resize();\n\n this.scene.add(this.worldRoot);\n\n this.splats = new SparkSplatRenderer();\n const { mesh, bounds } = await this.splats.load(this.options.source);\n\n this.splatPivot.clear();\n this.splatPivot.add(mesh);\n this.worldRoot.add(this.splatPivot);\n\n this.worldRoot.rotation.x = Math.PI;\n this.worldRoot.position.y -= bounds.min.y;\n this.worldRoot.updateMatrixWorld(true);\n\n if (this.options.colliderSource) {\n await this.loadCollider(this.options.colliderSource);\n }\n\n this.scene.updateMatrixWorld(true);\n\n if (this.isMobile()) {\n this.initJoystick();\n this.initModeToggle();\n this.switchToWalk();\n this.updateModeLabel(\"WALK\");\n\n const walk = this.controls as WalkCapsuleController;\n walk.enableGyro();\n } else {\n this.switchToOrbit();\n }\n window.addEventListener(\"keydown\", this.onKeyToggle);\n }\n\n start() {\n if (this.running) return;\n this.running = true;\n this.renderer.setAnimationLoop((time) => {\n const now = performance.now();\n const delta = (now - this.lastTime) / 1000;\n this.lastTime = now;\n\n (this.controls as any)?.update?.(delta);\n\n this.renderer.render(this.scene, this.camera);\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 this.camera.aspect = w / h;\n this.camera.updateProjectionMatrix();\n }\n\n destroy() {\n this.running = false;\n this.renderer.setAnimationLoop(null);\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.controls?.dispose();\n this.renderer.dispose();\n }\n\n setCameraMode(mode: \"orbit\" | \"walk\") {\n if (mode === \"orbit\") {\n document.exitPointerLock();\n }\n\n if (mode === \"walk\") {\n // FORCE pointer lock NOW (gesture already happened)\n setTimeout(() => {\n if (document.pointerLockElement !== this.renderer.domElement) {\n this.renderer.domElement.focus();\n this.renderer.domElement.requestPointerLock();\n }\n }, 0);\n }\n }\n\n toggleCameraMode() {\n if (this.controls instanceof WalkCapsuleController) {\n this.switchToOrbit();\n this.updateModeLabel(\"ORBIT\");\n } else {\n this.switchToWalk();\n this.updateModeLabel(\"WALK\");\n }\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\n this.renderer.setPixelRatio(\n this.options.renderer?.pixelRatio ?? window.devicePixelRatio,\n );\n\n this.container.appendChild(this.renderer.domElement);\n\n this.renderer.domElement.addEventListener(\"webglcontextlost\", (e) => {\n e.preventDefault();\n console.log(\"[PGSG Viewer] WebGL context lost\");\n });\n }\n\n private initScene() {\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(0x111111);\n\n const gridHelper = new THREE.GridHelper(10, 10);\n // this.scene.add(gridHelper);\n\n const light = new THREE.HemisphereLight(0xffffff, 0x222222, 1.0);\n this.scene.add(light);\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\n this.camera.position.set(0, 1.6, 3);\n this.camera.lookAt(0, 1.6, 0);\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 = \"1000px\";\n zone.style.height = \"1000px\";\n zone.style.zIndex = \"1000\";\n\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 (this.controls instanceof WalkCapsuleController) {\n this.controls.setMovementVector(\n Math.sin(angle) * force,\n Math.cos(angle) * force,\n );\n }\n\n if (this.controls instanceof OrbitCameraController) {\n this.controls.setMovementVector(\n Math.sin(angle) * force,\n Math.cos(angle) * force,\n );\n }\n });\n\n joystick.on(\"end\", () => {\n this.controls.setMovementVector(0, 0);\n });\n }\n\n private initModeToggle() {\n const btn = document.createElement(\"div\");\n\n btn.style.position = \"absolute\";\n btn.style.right = \"20px\";\n btn.style.bottom = \"20px\";\n btn.style.width = \"70px\";\n btn.style.height = \"70px\";\n btn.style.borderRadius = \"50%\";\n btn.style.background = \"rgba(255,255,255,0.15)\";\n btn.style.backdropFilter = \"blur(6px)\";\n btn.style.border = \"2px solid rgba(255,255,255,0.4)\";\n btn.style.display = \"flex\";\n btn.style.alignItems = \"center\";\n btn.style.justifyContent = \"center\";\n btn.style.color = \"white\";\n btn.style.fontWeight = \"bold\";\n btn.style.fontSize = \"14px\";\n btn.style.zIndex = \"1000\";\n btn.style.userSelect = \"none\";\n btn.style.cursor = \"pointer\";\n btn.innerText = \"ORBIT\";\n\n btn.addEventListener(\"click\", () => {\n this.toggleCameraMode();\n });\n\n this.container.appendChild(btn);\n this.modeButton = btn;\n }\n\n private updateModeLabel(mode: \"WALK\" | \"ORBIT\") {\n if (!this.modeButton) return;\n this.modeButton.innerText = mode;\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 async loadCollider(url: string) {\n const loader = new GLTFLoader();\n const gltf = await loader.loadAsync(url);\n\n this.colliderMesh = gltf.scene;\n this.worldRoot.add(this.colliderMesh);\n\n this.colliders.length = 0;\n\n this.colliderMesh.traverse((child: any) => {\n if ((child as THREE.Mesh).isMesh) {\n child.material = new THREE.MeshBasicMaterial({ visible: false });\n child.updateMatrixWorld(true);\n this.colliders.push(child);\n }\n });\n\n this.worldRoot.updateMatrixWorld(true);\n }\n\n private isMobile(): boolean {\n return (\n \"ontouchstart\" in window ||\n navigator.maxTouchPoints > 0 ||\n window.innerWidth < 768\n );\n }\n\n private onKeyToggle = (e: KeyboardEvent) => {\n if (e.key !== \"v\") return;\n\n if (this.controls instanceof WalkCapsuleController) {\n this.switchToOrbit();\n } else {\n this.switchToWalk();\n }\n };\n\n private switchToWalk() {\n this.controls?.dispose();\n const walk = new WalkCapsuleController({\n camera: this.camera,\n dom: this.renderer.domElement,\n colliders: this.colliders,\n eyeHeight: 1.6,\n radius: 0.35,\n walkSpeed: 2.5,\n runMultiplier: 2.0,\n gravity: 9.8,\n usePointerLock: !this.isMobile(),\n }) as any;\n\n this.controls = walk;\n walk.snapToGround();\n }\n\n private switchToOrbit() {\n this.controls?.dispose();\n\n const distance = this.camera.position.distanceTo(this.orbitTarget);\n\n this.controls = new OrbitCameraController(\n this.camera,\n this.renderer.domElement,\n {\n target: this.orbitTarget.clone(),\n distance: Math.max(distance, 0.5),\n usePointerLock: !this.isMobile(),\n },\n );\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\";\n\nexport type WalkCapsuleOptions = {\n dom: HTMLElement;\n camera: THREE.PerspectiveCamera;\n colliders: THREE.Object3D[];\n\n eyeHeight?: number;\n radius?: number;\n gravity?: number;\n walkSpeed?: number;\n runMultiplier?: number;\n lookSensitivity?: number;\n usePointerLock?: boolean;\n};\n\nexport class WalkCapsuleController {\n private dom: HTMLElement;\n private camera: THREE.PerspectiveCamera;\n private colliders: THREE.Object3D[];\n\n private eyeHeight: number;\n private radius: number;\n\n private gravity: number;\n private walkSpeed: number;\n private runMultiplier: number;\n private lookSensitivity: number;\n\n private yaw = 0;\n private pitch = 0;\n\n private velocity = new THREE.Vector3();\n private onGround = false;\n private lastGroundY: number | null = null;\n\n private keys = new Set<string>();\n private raycaster = new THREE.Raycaster();\n\n private usePointerLock: boolean = false;\n\n private lastTouchX = 0;\n private lastTouchY = 0;\n private externalMove = new THREE.Vector2(0, 0);\n\n private useGyro = false;\n private gyroAlpha = 0;\n private gyroBeta = 0;\n private gyroGamma = 0;\n\n constructor(opts: WalkCapsuleOptions) {\n this.dom = opts.dom;\n this.camera = opts.camera;\n this.colliders = opts.colliders;\n console.log(\"colliders\", this.colliders.length);\n\n this.eyeHeight = opts.eyeHeight ?? 1.6;\n this.radius = opts.radius ?? 0.35;\n this.gravity = opts.gravity ?? 9.8;\n this.walkSpeed = opts.walkSpeed ?? 2.5;\n this.runMultiplier = opts.runMultiplier ?? 2.0;\n this.lookSensitivity = opts.lookSensitivity ?? 0.0022;\n this.usePointerLock = opts.usePointerLock ?? false;\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 if (this.usePointerLock === false) {\n this.bindTouch();\n } else {\n this.bind();\n }\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 enableGyro() {\n if (typeof DeviceOrientationEvent === \"undefined\") return;\n\n // iOS permission\n if ((DeviceOrientationEvent as any).requestPermission) {\n (DeviceOrientationEvent as any)\n .requestPermission()\n .then((response: string) => {\n if (response === \"granted\") {\n this.startGyro();\n }\n })\n .catch(console.error);\n } else {\n this.startGyro();\n }\n }\n\n // --------------------------------------------------\n // Input binding (SAFE for pointer lock)\n // --------------------------------------------------\n\n private bind() {\n // 🔴 IMPORTANT: pointer lock ONLY on click\n this.dom.addEventListener(\"click\", this.onClick);\n\n window.addEventListener(\"mousemove\", this.onMouseMove);\n window.addEventListener(\"keydown\", this.onKeyDown);\n window.addEventListener(\"keyup\", this.onKeyUp);\n window.addEventListener(\"blur\", this.onBlur);\n\n this.dom.addEventListener(\"contextmenu\", (e) => e.preventDefault());\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(\"click\", this.onClick);\n window.removeEventListener(\"mousemove\", this.onMouseMove);\n window.removeEventListener(\"keydown\", this.onKeyDown);\n window.removeEventListener(\"keyup\", this.onKeyUp);\n window.removeEventListener(\"blur\", this.onBlur);\n }\n\n private unbindTouch() {\n this.dom.removeEventListener(\"touchstart\", this.onTouchStart);\n this.dom.removeEventListener(\"touchmove\", this.onTouchMove);\n }\n\n private onClick = () => {\n if (this.usePointerLock && document.pointerLockElement !== this.dom) {\n this.dom.requestPointerLock();\n }\n };\n\n private onBlur = () => {\n if (this.usePointerLock) {\n document.exitPointerLock();\n }\n this.keys.clear();\n };\n\n private onMouseMove = (e: MouseEvent) => {\n if (this.usePointerLock && document.pointerLockElement !== this.dom) return;\n\n this.yaw -= e.movementX * this.lookSensitivity;\n this.pitch -= e.movementY * this.lookSensitivity;\n\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 private onTouchStart = (e: TouchEvent) => {\n const t = e.touches[0];\n this.lastTouchX = t.clientX;\n this.lastTouchY = t.clientY;\n };\n\n private onTouchMove = (e: TouchEvent) => {\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 private startGyro() {\n this.useGyro = true;\n\n window.addEventListener(\"deviceorientation\", (e) => {\n if (!e.alpha || !e.beta) return;\n\n this.gyroAlpha = THREE.MathUtils.degToRad(e.alpha);\n this.gyroBeta = THREE.MathUtils.degToRad(e.beta);\n this.gyroGamma = THREE.MathUtils.degToRad(e.gamma ?? 0);\n });\n }\n\n // --------------------------------------------------\n // Update loop\n // --------------------------------------------------\n\n update(dt: number) {\n if (this.useGyro) {\n this.yaw = THREE.MathUtils.lerp(this.yaw, -this.gyroAlpha, 0.1);\n this.pitch = THREE.MathUtils.lerp(\n this.pitch,\n this.gyroBeta - Math.PI / 2,\n 0.1,\n );\n\n this.camera.quaternion.setFromEuler(\n new THREE.Euler(this.pitch, this.yaw, 0, \"YXZ\"),\n );\n }\n if (!Number.isFinite(this.camera.position.y)) return;\n\n dt = Math.min(dt, 0.05);\n\n // Direction vectors (yaw-only)\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 wish = new THREE.Vector3();\n\n // Desktop\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 // Mobile\n if (this.externalMove.lengthSq() > 0) {\n wish.addScaledVector(forward, this.externalMove.x);\n wish.addScaledVector(right, this.externalMove.y);\n }\n\n if (wish.lengthSq() > 0) wish.normalize();\n\n // if (this.keys.size > 0) {\n // console.log(\"walking\", [...this.keys]);\n // }\n\n const speed =\n this.walkSpeed * (this.keys.has(\"shift\") ? this.runMultiplier : 1);\n\n this.velocity.x = wish.x * speed;\n this.velocity.z = wish.z * speed;\n\n // gravity (once)\n this.velocity.y -= this.gravity * dt;\n\n // integrate position once\n const nextPos = this.camera.position.clone();\n nextPos.x += this.velocity.x * dt;\n nextPos.z += this.velocity.z * dt;\n nextPos.y += this.velocity.y * dt;\n\n const resolved = this.resolveGroundAndCollisions(nextPos);\n this.camera.position.copy(resolved);\n }\n\n snapToGround() {\n const origin = this.camera.position.clone();\n origin.y += 5;\n\n this.raycaster.set(origin, new THREE.Vector3(0, -1, 0));\n this.raycaster.far = 50;\n\n const hits = this.raycaster.intersectObjects(this.colliders, true);\n\n for (const hit of hits) {\n if (!hit.face) continue;\n\n const normalMatrix = new THREE.Matrix3().getNormalMatrix(\n hit.object.matrixWorld,\n );\n\n const worldNormal = hit.face.normal\n .clone()\n .applyMatrix3(normalMatrix)\n .normalize();\n\n if (worldNormal.y > 0.5) {\n this.lastGroundY = hit.point.y;\n this.camera.position.y = this.lastGroundY + this.eyeHeight;\n this.velocity.y = 0;\n this.onGround = true;\n return;\n }\n }\n\n // fallback if no hit\n this.lastGroundY = this.camera.position.y - this.eyeHeight;\n }\n\n // --------------------------------------------------\n // Collision & Ground\n // --------------------------------------------------\n\n private resolveGroundAndCollisions(desiredCamPos: THREE.Vector3) {\n const camPos = desiredCamPos.clone();\n\n // ----- Ground check (robust) -----\n const maxRayDown = 10.0;\n\n const origin = camPos.clone();\n origin.y += 2.0;\n\n this.raycaster.set(origin, new THREE.Vector3(0, -1, 0));\n this.raycaster.near = 0;\n this.raycaster.far = maxRayDown;\n\n const hits = this.raycaster.intersectObjects(this.colliders, true);\n\n let groundHit: THREE.Intersection | null = null;\n\n for (const hit of hits) {\n if (!hit.face) continue;\n\n // Convert face normal to world space\n const normalMatrix = new THREE.Matrix3().getNormalMatrix(\n hit.object.matrixWorld,\n );\n\n const worldNormal = hit.face.normal\n .clone()\n .applyMatrix3(normalMatrix)\n .normalize();\n\n // Accept only surfaces that face upward\n if (worldNormal.y > 0.5) {\n groundHit = hit;\n break;\n }\n }\n\n if (groundHit) {\n const groundY = groundHit.point.y;\n const targetY = groundY + this.eyeHeight;\n\n this.lastGroundY = groundY;\n\n const falling = this.velocity.y <= 0;\n const maxSnap = 1.0;\n\n if (falling && camPos.y <= targetY + maxSnap) {\n camPos.y = targetY;\n this.velocity.y = 0;\n this.onGround = true;\n } else {\n this.onGround = false;\n }\n } else {\n if (this.lastGroundY !== null) {\n camPos.y = this.lastGroundY + this.eyeHeight;\n this.velocity.y = 0;\n this.onGround = true;\n } else {\n this.onGround = false;\n }\n }\n\n // ----- Wall push -----\n const center = camPos.clone();\n center.y -= this.eyeHeight * 0.9;\n\n const dirs = [\n new THREE.Vector3(1, 0, 0),\n new THREE.Vector3(-1, 0, 0),\n new THREE.Vector3(0, 0, 1),\n new THREE.Vector3(0, 0, -1),\n ];\n\n for (const d of dirs) {\n this.raycaster.set(center, d);\n this.raycaster.far = this.radius + 0.25;\n\n const wallHits = this.raycaster.intersectObjects(this.colliders, true);\n if (!wallHits.length) continue;\n\n const overlap = this.radius + 0.25 - wallHits[0].distance;\n if (overlap > 0) camPos.addScaledVector(d, -overlap);\n }\n\n // console.log({\n // camY: camPos.y.toFixed(2),\n // footY: footY.toFixed(2),\n // groundHit: hits[0]?.point.y.toFixed(2),\n // onGround: this.onGround,\n // });\n\n return camPos;\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 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 (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.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 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 const t = e.touches[0];\n this.lastTouchX = t.clientX;\n this.lastTouchY = t.clientY;\n };\n\n private onTouchMove = (e: TouchEvent) => {\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"],"mappings":"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","names":["THREE","THREE"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  PGSGViewer
3
- } from "../chunk-PRUUK6YZ.js";
3
+ } from "../chunk-WFONX3TR.js";
4
4
 
5
5
  // src/react/PGSGCanvas.tsx
6
6
  import * as React from "react";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@popaya/pgsg-viewer",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/viewers/three/pgsg-three-viewer.ts","../src/viewers/spark/SparkSplatRenderer.ts","../src/viewers/three/controls/WalkCapsuleController.ts","../src/viewers/three/controls/OrbitCameraController.ts"],"sourcesContent":["import type { PGSGViewerOptions } from \"../../core/types\";\nimport * as THREE from \"three\";\nimport { GLTFLoader } from \"three/examples/jsm/Addons.js\";\nimport nipplejs from \"nipplejs\";\n\nimport { SparkSplatRenderer } from \"../spark/SparkSplatRenderer\";\nimport { WalkCapsuleController } from \"./controls/WalkCapsuleController\";\nimport { OrbitCameraController } from \"./controls/OrbitCameraController\";\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 container: HTMLElement;\n private resizeObserver: ResizeObserver | null = null;\n\n private controls!: WalkCapsuleController | OrbitCameraController;\n private running = false;\n\n private orbitTarget = new THREE.Vector3();\n private lastTime = performance.now();\n\n private colliders: THREE.Object3D[] = [];\n\n private worldRoot = new THREE.Object3D();\n private splatPivot = new THREE.Object3D();\n private colliderMesh?: THREE.Object3D;\n\n private modeButton?: HTMLDivElement;\n\n constructor(private options: PGSGViewerOptions) {\n this.container = options.container;\n this.options = options;\n if (!this.container) {\n throw new Error(\"[PGSGThreeViewer] Container is required\");\n }\n }\n\n async load() {\n this.initRenderer();\n this.initCamera();\n this.initScene();\n\n // Resize\n this.bindResize();\n this.resize();\n\n this.scene.add(this.worldRoot);\n\n this.splats = new SparkSplatRenderer();\n const { mesh, bounds } = await this.splats.load(this.options.source);\n\n this.splatPivot.clear();\n this.splatPivot.add(mesh);\n this.worldRoot.add(this.splatPivot);\n\n this.worldRoot.rotation.x = Math.PI;\n this.worldRoot.position.y -= bounds.min.y;\n this.worldRoot.updateMatrixWorld(true);\n\n if (this.options.colliderSource) {\n await this.loadCollider(this.options.colliderSource);\n }\n\n this.scene.updateMatrixWorld(true);\n\n if (this.isMobile()) {\n this.initJoystick();\n this.initModeToggle();\n this.switchToWalk();\n this.updateModeLabel(\"WALK\");\n\n const walk = this.controls as WalkCapsuleController;\n walk.enableGyro();\n } else {\n this.switchToOrbit();\n }\n window.addEventListener(\"keydown\", this.onKeyToggle);\n }\n\n start() {\n if (this.running) return;\n this.running = true;\n this.renderer.setAnimationLoop((time) => {\n const now = performance.now();\n const delta = (now - this.lastTime) / 1000;\n this.lastTime = now;\n\n (this.controls as any)?.update?.(delta);\n\n this.renderer.render(this.scene, this.camera);\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 this.camera.aspect = w / h;\n this.camera.updateProjectionMatrix();\n }\n\n destroy() {\n this.running = false;\n this.renderer.setAnimationLoop(null);\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.controls?.dispose();\n this.renderer.dispose();\n }\n\n setCameraMode(mode: \"orbit\" | \"walk\") {\n if (mode === \"orbit\") {\n document.exitPointerLock();\n }\n\n if (mode === \"walk\") {\n // FORCE pointer lock NOW (gesture already happened)\n setTimeout(() => {\n if (document.pointerLockElement !== this.renderer.domElement) {\n this.renderer.domElement.focus();\n this.renderer.domElement.requestPointerLock();\n }\n }, 0);\n }\n }\n\n toggleCameraMode() {\n if (this.controls instanceof WalkCapsuleController) {\n this.switchToOrbit();\n this.updateModeLabel(\"ORBIT\");\n } else {\n this.switchToWalk();\n this.updateModeLabel(\"WALK\");\n }\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\n this.renderer.setPixelRatio(\n this.options.renderer?.pixelRatio ?? window.devicePixelRatio,\n );\n\n this.container.appendChild(this.renderer.domElement);\n\n this.renderer.domElement.addEventListener(\"webglcontextlost\", (e) => {\n e.preventDefault();\n console.log(\"[PGSG Viewer] WebGL context lost\");\n });\n }\n\n private initScene() {\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(0x111111);\n\n const gridHelper = new THREE.GridHelper(10, 10);\n // this.scene.add(gridHelper);\n\n const light = new THREE.HemisphereLight(0xffffff, 0x222222, 1.0);\n this.scene.add(light);\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\n this.camera.position.set(0, 1.6, 3);\n this.camera.lookAt(0, 1.6, 0);\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\n this.container.appendChild(zone);\n\n const joystick = nipplejs.create({\n zone,\n mode: \"static\",\n position: { left: \"75px\", bottom: \"75px\" },\n color: \"white\",\n });\n\n joystick.on(\"move\", (_, data) => {\n const angle = data.angle.radian;\n const force = data.force;\n\n if (this.controls instanceof WalkCapsuleController) {\n this.controls.setMovementVector(\n Math.sin(angle) * force,\n Math.cos(angle) * force,\n );\n }\n\n if (this.controls instanceof OrbitCameraController) {\n this.controls.setMovementVector(\n Math.sin(angle) * force,\n Math.cos(angle) * force,\n );\n }\n });\n\n joystick.on(\"end\", () => {\n this.controls.setMovementVector(0, 0);\n });\n }\n\n private initModeToggle() {\n const btn = document.createElement(\"div\");\n\n btn.style.position = \"absolute\";\n btn.style.right = \"20px\";\n btn.style.bottom = \"40px\";\n btn.style.width = \"70px\";\n btn.style.height = \"70px\";\n btn.style.borderRadius = \"50%\";\n btn.style.background = \"rgba(255,255,255,0.15)\";\n btn.style.backdropFilter = \"blur(6px)\";\n btn.style.border = \"2px solid rgba(255,255,255,0.4)\";\n btn.style.display = \"flex\";\n btn.style.alignItems = \"center\";\n btn.style.justifyContent = \"center\";\n btn.style.color = \"white\";\n btn.style.fontWeight = \"bold\";\n btn.style.fontSize = \"14px\";\n btn.style.zIndex = \"1000\";\n btn.style.userSelect = \"none\";\n btn.style.cursor = \"pointer\";\n btn.innerText = \"ORBIT\";\n\n btn.addEventListener(\"click\", () => {\n this.toggleCameraMode();\n });\n\n this.container.appendChild(btn);\n this.modeButton = btn;\n }\n\n private updateModeLabel(mode: \"WALK\" | \"ORBIT\") {\n if (!this.modeButton) return;\n this.modeButton.innerText = mode;\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 async loadCollider(url: string) {\n const loader = new GLTFLoader();\n const gltf = await loader.loadAsync(url);\n\n this.colliderMesh = gltf.scene;\n this.worldRoot.add(this.colliderMesh);\n\n this.colliders.length = 0;\n\n this.colliderMesh.traverse((child: any) => {\n if ((child as THREE.Mesh).isMesh) {\n child.material = new THREE.MeshBasicMaterial({ visible: false });\n child.updateMatrixWorld(true);\n this.colliders.push(child);\n }\n });\n\n this.worldRoot.updateMatrixWorld(true);\n }\n\n private isMobile(): boolean {\n return (\n \"ontouchstart\" in window ||\n navigator.maxTouchPoints > 0 ||\n window.innerWidth < 768\n );\n }\n\n private onKeyToggle = (e: KeyboardEvent) => {\n if (e.key !== \"v\") return;\n\n if (this.controls instanceof WalkCapsuleController) {\n this.switchToOrbit();\n } else {\n this.switchToWalk();\n }\n };\n\n private switchToWalk() {\n this.controls?.dispose();\n const walk = new WalkCapsuleController({\n camera: this.camera,\n dom: this.renderer.domElement,\n colliders: this.colliders,\n eyeHeight: 1.6,\n radius: 0.35,\n walkSpeed: 2.5,\n runMultiplier: 2.0,\n gravity: 9.8,\n usePointerLock: !this.isMobile(),\n }) as any;\n\n this.controls = walk;\n walk.snapToGround();\n }\n\n private switchToOrbit() {\n this.controls?.dispose();\n\n const distance = this.camera.position.distanceTo(this.orbitTarget);\n\n this.controls = new OrbitCameraController(\n this.camera,\n this.renderer.domElement,\n {\n target: this.orbitTarget.clone(),\n distance: Math.max(distance, 0.5),\n usePointerLock: !this.isMobile(),\n },\n );\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\";\n\nexport type WalkCapsuleOptions = {\n dom: HTMLElement;\n camera: THREE.PerspectiveCamera;\n colliders: THREE.Object3D[];\n\n eyeHeight?: number;\n radius?: number;\n gravity?: number;\n walkSpeed?: number;\n runMultiplier?: number;\n lookSensitivity?: number;\n usePointerLock?: boolean;\n};\n\nexport class WalkCapsuleController {\n private dom: HTMLElement;\n private camera: THREE.PerspectiveCamera;\n private colliders: THREE.Object3D[];\n\n private eyeHeight: number;\n private radius: number;\n\n private gravity: number;\n private walkSpeed: number;\n private runMultiplier: number;\n private lookSensitivity: number;\n\n private yaw = 0;\n private pitch = 0;\n\n private velocity = new THREE.Vector3();\n private onGround = false;\n private lastGroundY: number | null = null;\n\n private keys = new Set<string>();\n private raycaster = new THREE.Raycaster();\n\n private usePointerLock: boolean = false;\n\n private lastTouchX = 0;\n private lastTouchY = 0;\n private externalMove = new THREE.Vector2(0, 0);\n\n private useGyro = false;\n private gyroAlpha = 0;\n private gyroBeta = 0;\n private gyroGamma = 0;\n\n constructor(opts: WalkCapsuleOptions) {\n this.dom = opts.dom;\n this.camera = opts.camera;\n this.colliders = opts.colliders;\n console.log(\"colliders\", this.colliders.length);\n\n this.eyeHeight = opts.eyeHeight ?? 1.6;\n this.radius = opts.radius ?? 0.35;\n this.gravity = opts.gravity ?? 9.8;\n this.walkSpeed = opts.walkSpeed ?? 2.5;\n this.runMultiplier = opts.runMultiplier ?? 2.0;\n this.lookSensitivity = opts.lookSensitivity ?? 0.0022;\n this.usePointerLock = opts.usePointerLock ?? false;\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 if (this.usePointerLock === false) {\n this.bindTouch();\n } else {\n this.bind();\n }\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 enableGyro() {\n if (typeof DeviceOrientationEvent === \"undefined\") return;\n\n // iOS permission\n if ((DeviceOrientationEvent as any).requestPermission) {\n (DeviceOrientationEvent as any)\n .requestPermission()\n .then((response: string) => {\n if (response === \"granted\") {\n this.startGyro();\n }\n })\n .catch(console.error);\n } else {\n this.startGyro();\n }\n }\n\n // --------------------------------------------------\n // Input binding (SAFE for pointer lock)\n // --------------------------------------------------\n\n private bind() {\n // 🔴 IMPORTANT: pointer lock ONLY on click\n this.dom.addEventListener(\"click\", this.onClick);\n\n window.addEventListener(\"mousemove\", this.onMouseMove);\n window.addEventListener(\"keydown\", this.onKeyDown);\n window.addEventListener(\"keyup\", this.onKeyUp);\n window.addEventListener(\"blur\", this.onBlur);\n\n this.dom.addEventListener(\"contextmenu\", (e) => e.preventDefault());\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(\"click\", this.onClick);\n window.removeEventListener(\"mousemove\", this.onMouseMove);\n window.removeEventListener(\"keydown\", this.onKeyDown);\n window.removeEventListener(\"keyup\", this.onKeyUp);\n window.removeEventListener(\"blur\", this.onBlur);\n }\n\n private unbindTouch() {\n this.dom.removeEventListener(\"touchstart\", this.onTouchStart);\n this.dom.removeEventListener(\"touchmove\", this.onTouchMove);\n }\n\n private onClick = () => {\n if (this.usePointerLock && document.pointerLockElement !== this.dom) {\n this.dom.requestPointerLock();\n }\n };\n\n private onBlur = () => {\n if (this.usePointerLock) {\n document.exitPointerLock();\n }\n this.keys.clear();\n };\n\n private onMouseMove = (e: MouseEvent) => {\n if (this.usePointerLock && document.pointerLockElement !== this.dom) return;\n\n this.yaw -= e.movementX * this.lookSensitivity;\n this.pitch -= e.movementY * this.lookSensitivity;\n\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 private onTouchStart = (e: TouchEvent) => {\n const t = e.touches[0];\n this.lastTouchX = t.clientX;\n this.lastTouchY = t.clientY;\n };\n\n private onTouchMove = (e: TouchEvent) => {\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 private startGyro() {\n this.useGyro = true;\n\n window.addEventListener(\"deviceorientation\", (e) => {\n if (!e.alpha || !e.beta) return;\n\n this.gyroAlpha = THREE.MathUtils.degToRad(e.alpha);\n this.gyroBeta = THREE.MathUtils.degToRad(e.beta);\n this.gyroGamma = THREE.MathUtils.degToRad(e.gamma ?? 0);\n });\n }\n\n // --------------------------------------------------\n // Update loop\n // --------------------------------------------------\n\n update(dt: number) {\n if (this.useGyro) {\n this.yaw = THREE.MathUtils.lerp(this.yaw, -this.gyroAlpha, 0.1);\n this.pitch = THREE.MathUtils.lerp(\n this.pitch,\n this.gyroBeta - Math.PI / 2,\n 0.1,\n );\n\n this.camera.quaternion.setFromEuler(\n new THREE.Euler(this.pitch, this.yaw, 0, \"YXZ\"),\n );\n }\n if (!Number.isFinite(this.camera.position.y)) return;\n\n dt = Math.min(dt, 0.05);\n\n // Direction vectors (yaw-only)\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 wish = new THREE.Vector3();\n\n // Desktop\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 // Mobile\n if (this.externalMove.lengthSq() > 0) {\n wish.addScaledVector(forward, this.externalMove.x);\n wish.addScaledVector(right, this.externalMove.y);\n }\n\n if (wish.lengthSq() > 0) wish.normalize();\n\n // if (this.keys.size > 0) {\n // console.log(\"walking\", [...this.keys]);\n // }\n\n const speed =\n this.walkSpeed * (this.keys.has(\"shift\") ? this.runMultiplier : 1);\n\n this.velocity.x = wish.x * speed;\n this.velocity.z = wish.z * speed;\n\n // gravity (once)\n this.velocity.y -= this.gravity * dt;\n\n // integrate position once\n const nextPos = this.camera.position.clone();\n nextPos.x += this.velocity.x * dt;\n nextPos.z += this.velocity.z * dt;\n nextPos.y += this.velocity.y * dt;\n\n const resolved = this.resolveGroundAndCollisions(nextPos);\n this.camera.position.copy(resolved);\n }\n\n snapToGround() {\n const origin = this.camera.position.clone();\n origin.y += 5;\n\n this.raycaster.set(origin, new THREE.Vector3(0, -1, 0));\n this.raycaster.far = 50;\n\n const hits = this.raycaster.intersectObjects(this.colliders, true);\n\n for (const hit of hits) {\n if (!hit.face) continue;\n\n const normalMatrix = new THREE.Matrix3().getNormalMatrix(\n hit.object.matrixWorld,\n );\n\n const worldNormal = hit.face.normal\n .clone()\n .applyMatrix3(normalMatrix)\n .normalize();\n\n if (worldNormal.y > 0.5) {\n this.lastGroundY = hit.point.y;\n this.camera.position.y = this.lastGroundY + this.eyeHeight;\n this.velocity.y = 0;\n this.onGround = true;\n return;\n }\n }\n\n // fallback if no hit\n this.lastGroundY = this.camera.position.y - this.eyeHeight;\n }\n\n // --------------------------------------------------\n // Collision & Ground\n // --------------------------------------------------\n\n private resolveGroundAndCollisions(desiredCamPos: THREE.Vector3) {\n const camPos = desiredCamPos.clone();\n\n // ----- Ground check (robust) -----\n const maxRayDown = 10.0;\n\n const origin = camPos.clone();\n origin.y += 2.0;\n\n this.raycaster.set(origin, new THREE.Vector3(0, -1, 0));\n this.raycaster.near = 0;\n this.raycaster.far = maxRayDown;\n\n const hits = this.raycaster.intersectObjects(this.colliders, true);\n\n let groundHit: THREE.Intersection | null = null;\n\n for (const hit of hits) {\n if (!hit.face) continue;\n\n // Convert face normal to world space\n const normalMatrix = new THREE.Matrix3().getNormalMatrix(\n hit.object.matrixWorld,\n );\n\n const worldNormal = hit.face.normal\n .clone()\n .applyMatrix3(normalMatrix)\n .normalize();\n\n // Accept only surfaces that face upward\n if (worldNormal.y > 0.5) {\n groundHit = hit;\n break;\n }\n }\n\n if (groundHit) {\n const groundY = groundHit.point.y;\n const targetY = groundY + this.eyeHeight;\n\n this.lastGroundY = groundY;\n\n const falling = this.velocity.y <= 0;\n const maxSnap = 1.0;\n\n if (falling && camPos.y <= targetY + maxSnap) {\n camPos.y = targetY;\n this.velocity.y = 0;\n this.onGround = true;\n } else {\n this.onGround = false;\n }\n } else {\n if (this.lastGroundY !== null) {\n camPos.y = this.lastGroundY + this.eyeHeight;\n this.velocity.y = 0;\n this.onGround = true;\n } else {\n this.onGround = false;\n }\n }\n\n // ----- Wall push -----\n const center = camPos.clone();\n center.y -= this.eyeHeight * 0.9;\n\n const dirs = [\n new THREE.Vector3(1, 0, 0),\n new THREE.Vector3(-1, 0, 0),\n new THREE.Vector3(0, 0, 1),\n new THREE.Vector3(0, 0, -1),\n ];\n\n for (const d of dirs) {\n this.raycaster.set(center, d);\n this.raycaster.far = this.radius + 0.25;\n\n const wallHits = this.raycaster.intersectObjects(this.colliders, true);\n if (!wallHits.length) continue;\n\n const overlap = this.radius + 0.25 - wallHits[0].distance;\n if (overlap > 0) camPos.addScaledVector(d, -overlap);\n }\n\n // console.log({\n // camY: camPos.y.toFixed(2),\n // footY: footY.toFixed(2),\n // groundHit: hits[0]?.point.y.toFixed(2),\n // onGround: this.onGround,\n // });\n\n return camPos;\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 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 (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.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 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 const t = e.touches[0];\n this.lastTouchX = t.clientX;\n this.lastTouchY = t.clientY;\n };\n\n private onTouchMove = (e: TouchEvent) => {\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"],"mappings":"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","names":["THREE","THREE"]}