@pascal-app/viewer 0.9.1 → 1.0.0-beta.1
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.
- package/README.md +20 -5
- package/dist/components/error-boundary.d.ts +6 -0
- package/dist/components/error-boundary.d.ts.map +1 -1
- package/dist/components/error-boundary.js +6 -0
- package/dist/components/renderers/node-renderer.d.ts +5 -1
- package/dist/components/renderers/node-renderer.d.ts.map +1 -1
- package/dist/components/renderers/node-renderer.js +5 -2
- package/dist/components/renderers/parametric-node-renderer.d.ts.map +1 -1
- package/dist/components/renderers/parametric-node-renderer.js +7 -4
- package/dist/components/viewer/bvh-ecctrl.d.ts +77 -0
- package/dist/components/viewer/bvh-ecctrl.d.ts.map +1 -0
- package/dist/components/viewer/bvh-ecctrl.js +552 -0
- package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
- package/dist/components/viewer/frame-limiter.js +59 -4
- package/dist/components/viewer/glb-interactive.d.ts +41 -0
- package/dist/components/viewer/glb-interactive.d.ts.map +1 -0
- package/dist/components/viewer/glb-interactive.js +394 -0
- package/dist/components/viewer/glb-reference-nodes.d.ts +29 -0
- package/dist/components/viewer/glb-reference-nodes.d.ts.map +1 -0
- package/dist/components/viewer/glb-reference-nodes.js +80 -0
- package/dist/components/viewer/glb-replace-instances.d.ts +18 -0
- package/dist/components/viewer/glb-replace-instances.d.ts.map +1 -0
- package/dist/components/viewer/glb-replace-instances.js +61 -0
- package/dist/components/viewer/glb-scene.d.ts +54 -0
- package/dist/components/viewer/glb-scene.d.ts.map +1 -0
- package/dist/components/viewer/glb-scene.js +920 -0
- package/dist/components/viewer/glb-walkthrough-controller.d.ts +22 -0
- package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -0
- package/dist/components/viewer/glb-walkthrough-controller.js +445 -0
- package/dist/components/viewer/index.d.ts +19 -2
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +113 -12
- package/dist/components/viewer/lights.d.ts.map +1 -1
- package/dist/components/viewer/lights.js +36 -5
- package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
- package/dist/components/viewer/perf-monitor.js +17 -2
- package/dist/components/viewer/post-processing.d.ts +7 -1
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +180 -24
- package/dist/components/viewer/registered-systems.d.ts.map +1 -1
- package/dist/components/viewer/registered-systems.js +6 -4
- package/dist/components/viewer/scene-bvh.d.ts +2 -1
- package/dist/components/viewer/scene-bvh.d.ts.map +1 -1
- package/dist/components/viewer/scene-bvh.js +3 -0
- package/dist/components/viewer/scene-bvh.test.d.ts +2 -0
- package/dist/components/viewer/scene-bvh.test.d.ts.map +1 -0
- package/dist/components/viewer/scene-bvh.test.js +13 -0
- package/dist/components/viewer/scene-environment.d.ts +2 -0
- package/dist/components/viewer/scene-environment.d.ts.map +1 -0
- package/dist/components/viewer/scene-environment.js +79 -0
- package/dist/components/viewer/selection-manager.d.ts.map +1 -1
- package/dist/components/viewer/selection-manager.js +23 -12
- package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
- package/dist/hooks/use-gltf-ktx2.js +2 -24
- package/dist/hooks/use-node-events.d.ts +1 -1
- package/dist/hooks/use-node-events.d.ts.map +1 -1
- package/dist/hooks/use-node-events.js +22 -14
- package/dist/index.d.ts +24 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -13
- package/dist/lib/backdrop.d.ts +33 -0
- package/dist/lib/backdrop.d.ts.map +1 -0
- package/dist/lib/backdrop.js +92 -0
- package/dist/lib/box-uv.d.ts +13 -0
- package/dist/lib/box-uv.d.ts.map +1 -0
- package/dist/lib/box-uv.js +32 -0
- package/dist/lib/csg-utils.d.ts +3 -9
- package/dist/lib/csg-utils.d.ts.map +1 -1
- package/dist/lib/csg-utils.js +65 -5
- package/dist/lib/csg-utils.test.d.ts +2 -0
- package/dist/lib/csg-utils.test.d.ts.map +1 -0
- package/dist/lib/csg-utils.test.js +45 -0
- package/dist/lib/edge-style.d.ts +1 -0
- package/dist/lib/edge-style.d.ts.map +1 -1
- package/dist/lib/edge-style.js +26 -6
- package/dist/lib/hero-pose.d.ts +47 -0
- package/dist/lib/hero-pose.d.ts.map +1 -0
- package/dist/lib/hero-pose.js +227 -0
- package/dist/lib/ink-edges.d.ts +1 -1
- package/dist/lib/ink-edges.d.ts.map +1 -1
- package/dist/lib/ink-edges.js +13 -7
- package/dist/lib/ktx2-loader.d.ts +46 -0
- package/dist/lib/ktx2-loader.d.ts.map +1 -0
- package/dist/lib/ktx2-loader.js +142 -0
- package/dist/lib/layers.d.ts +10 -0
- package/dist/lib/layers.d.ts.map +1 -1
- package/dist/lib/layers.js +10 -0
- package/dist/lib/materials.d.ts +16 -1
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +158 -34
- package/dist/lib/materials.test.d.ts +2 -0
- package/dist/lib/materials.test.d.ts.map +1 -0
- package/dist/lib/materials.test.js +25 -0
- package/dist/lib/merged-outline-node.test.d.ts +2 -0
- package/dist/lib/merged-outline-node.test.d.ts.map +1 -0
- package/dist/lib/merged-outline-node.test.js +22 -0
- package/dist/lib/scene-themes.d.ts +1 -0
- package/dist/lib/scene-themes.d.ts.map +1 -1
- package/dist/lib/scene-themes.js +25 -16
- package/dist/lib/shadow-only.d.ts +4 -0
- package/dist/lib/shadow-only.d.ts.map +1 -0
- package/dist/lib/shadow-only.js +36 -0
- package/dist/lib/snapshot-pipeline.d.ts +42 -0
- package/dist/lib/snapshot-pipeline.d.ts.map +1 -0
- package/dist/lib/snapshot-pipeline.js +254 -0
- package/dist/lib/terrain-perimeter-fill.d.ts +7 -0
- package/dist/lib/terrain-perimeter-fill.d.ts.map +1 -0
- package/dist/lib/terrain-perimeter-fill.js +75 -0
- package/dist/lib/texture-node-guard.d.ts +13 -0
- package/dist/lib/texture-node-guard.d.ts.map +1 -0
- package/dist/lib/texture-node-guard.js +39 -0
- package/dist/lib/texture-reference.d.ts +31 -0
- package/dist/lib/texture-reference.d.ts.map +1 -0
- package/dist/lib/texture-reference.js +139 -0
- package/dist/lib/texture-reference.test.d.ts +2 -0
- package/dist/lib/texture-reference.test.d.ts.map +1 -0
- package/dist/lib/texture-reference.test.js +86 -0
- package/dist/lib/tsl-compat.d.ts +12 -0
- package/dist/lib/tsl-compat.d.ts.map +1 -0
- package/dist/lib/tsl-compat.js +13 -0
- package/dist/store/use-viewer.d.ts +73 -18
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +191 -4
- package/dist/store/use-viewer.test.d.ts +2 -0
- package/dist/store/use-viewer.test.d.ts.map +1 -0
- package/dist/store/use-viewer.test.js +61 -0
- package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
- package/dist/systems/ceiling/ceiling-system.js +12 -5
- package/dist/systems/door/door-animation.test.d.ts +2 -0
- package/dist/systems/door/door-animation.test.d.ts.map +1 -0
- package/dist/systems/door/door-animation.test.js +51 -0
- package/dist/systems/door/door-floor-alignment.test.d.ts +2 -0
- package/dist/systems/door/door-floor-alignment.test.d.ts.map +1 -0
- package/dist/systems/door/door-floor-alignment.test.js +50 -0
- package/dist/systems/door/door-system.d.ts +24 -0
- package/dist/systems/door/door-system.d.ts.map +1 -1
- package/dist/systems/door/door-system.js +494 -161
- package/dist/systems/fence/fence-system.d.ts +17 -0
- package/dist/systems/fence/fence-system.d.ts.map +1 -1
- package/dist/systems/fence/fence-system.js +221 -53
- package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -1
- package/dist/systems/floor-elevation/floor-elevation-system.js +30 -7
- package/dist/systems/geometry/geometry-system.d.ts +7 -0
- package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
- package/dist/systems/geometry/geometry-system.js +95 -26
- package/dist/systems/geometry/geometry-system.test.d.ts +2 -0
- package/dist/systems/geometry/geometry-system.test.d.ts.map +1 -0
- package/dist/systems/geometry/geometry-system.test.js +30 -0
- package/dist/systems/interactive/control-widget.d.ts +10 -0
- package/dist/systems/interactive/control-widget.d.ts.map +1 -0
- package/dist/systems/interactive/control-widget.js +35 -0
- package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
- package/dist/systems/interactive/interactive-system.js +55 -56
- package/dist/systems/item/item-system.d.ts.map +1 -1
- package/dist/systems/item/item-system.js +20 -6
- package/dist/systems/level/level-system.d.ts.map +1 -1
- package/dist/systems/level/level-system.js +34 -9
- package/dist/systems/level/level-utils.d.ts +0 -3
- package/dist/systems/level/level-utils.d.ts.map +1 -1
- package/dist/systems/level/level-utils.js +7 -45
- package/dist/systems/roof/roof-materials.d.ts.map +1 -1
- package/dist/systems/roof/roof-materials.js +29 -8
- package/dist/systems/roof/roof-system.d.ts +21 -8
- package/dist/systems/roof/roof-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-system.js +1079 -221
- package/dist/systems/slab/slab-system.d.ts +7 -4
- package/dist/systems/slab/slab-system.d.ts.map +1 -1
- package/dist/systems/slab/slab-system.js +31 -83
- package/dist/systems/slab/slab-system.test.js +54 -14
- package/dist/systems/stair/stair-system.js +7 -4
- package/dist/systems/wall/opening-cutout-geometry.d.ts +31 -0
- package/dist/systems/wall/opening-cutout-geometry.d.ts.map +1 -0
- package/dist/systems/wall/opening-cutout-geometry.js +167 -0
- package/dist/systems/wall/opening-cutout-geometry.test.d.ts +2 -0
- package/dist/systems/wall/opening-cutout-geometry.test.d.ts.map +1 -0
- package/dist/systems/wall/opening-cutout-geometry.test.js +172 -0
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +49 -17
- package/dist/systems/wall/wall-materials.d.ts +11 -7
- package/dist/systems/wall/wall-materials.d.ts.map +1 -1
- package/dist/systems/wall/wall-materials.js +244 -35
- package/dist/systems/wall/wall-opening-cutout.test.d.ts +2 -0
- package/dist/systems/wall/wall-opening-cutout.test.d.ts.map +1 -0
- package/dist/systems/wall/wall-opening-cutout.test.js +59 -0
- package/dist/systems/wall/wall-support-extension.test.d.ts +2 -0
- package/dist/systems/wall/wall-support-extension.test.d.ts.map +1 -0
- package/dist/systems/wall/wall-support-extension.test.js +116 -0
- package/dist/systems/wall/wall-system.d.ts +4 -8
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +397 -177
- package/dist/systems/wall/wall-terrain-bottom.test.d.ts +2 -0
- package/dist/systems/wall/wall-terrain-bottom.test.d.ts.map +1 -0
- package/dist/systems/wall/wall-terrain-bottom.test.js +34 -0
- package/dist/systems/window/window-animation-system.d.ts +12 -0
- package/dist/systems/window/window-animation-system.d.ts.map +1 -1
- package/dist/systems/window/window-animation-system.js +16 -5
- package/dist/systems/window/window-system.d.ts +7 -0
- package/dist/systems/window/window-system.d.ts.map +1 -1
- package/dist/systems/window/window-system.js +240 -14
- package/package.json +4 -4
- package/dist/components/viewer/ground-occluder.d.ts +0 -2
- package/dist/components/viewer/ground-occluder.d.ts.map +0 -1
- package/dist/components/viewer/ground-occluder.js +0 -67
- package/dist/components/viewer/walkthrough-controls.d.ts +0 -2
- package/dist/components/viewer/walkthrough-controls.d.ts.map +0 -1
- package/dist/components/viewer/walkthrough-controls.js +0 -131
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pascal-app/viewer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
4
|
"description": "3D viewer component for Pascal building editor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,15 +18,15 @@
|
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
20
|
"build": "tsc --build",
|
|
21
|
-
"dev": "
|
|
21
|
+
"dev": "tsgo --build --watch",
|
|
22
22
|
"prepublishOnly": "npm run build"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
|
-
"@pascal-app/core": "^0.
|
|
25
|
+
"@pascal-app/core": "^1.0.0-beta.1",
|
|
26
26
|
"@react-three/drei": "^10",
|
|
27
27
|
"@react-three/fiber": "^9",
|
|
28
28
|
"react": "^18 || ^19",
|
|
29
|
-
"three": "^0.
|
|
29
|
+
"three": "^0.185"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"three-bvh-csg": "^0.0.18",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ground-occluder.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/ground-occluder.tsx"],"names":[],"mappings":"AAOA,eAAO,MAAM,cAAc,mCAuF1B,CAAA"}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useScene } from '@pascal-app/core';
|
|
3
|
-
import { useMemo } from 'react';
|
|
4
|
-
import * as THREE from 'three';
|
|
5
|
-
import { unionPolygons } from '../../lib/polygon-union';
|
|
6
|
-
import { getSceneTheme } from '../../lib/scene-themes';
|
|
7
|
-
import useViewer from '../../store/use-viewer';
|
|
8
|
-
export const GroundOccluder = () => {
|
|
9
|
-
const bgColor = useViewer((state) => getSceneTheme(state.sceneTheme).ground);
|
|
10
|
-
const nodes = useScene((state) => state.nodes);
|
|
11
|
-
const shape = useMemo(() => {
|
|
12
|
-
const s = new THREE.Shape();
|
|
13
|
-
const size = 1000;
|
|
14
|
-
// Create outer infinite plane
|
|
15
|
-
s.moveTo(-size, -size);
|
|
16
|
-
s.lineTo(size, -size);
|
|
17
|
-
s.lineTo(size, size);
|
|
18
|
-
s.lineTo(-size, size);
|
|
19
|
-
s.closePath();
|
|
20
|
-
const levelIndexById = new Map();
|
|
21
|
-
let lowestLevelIndex = Number.POSITIVE_INFINITY;
|
|
22
|
-
Object.values(nodes).forEach((node) => {
|
|
23
|
-
if (node.type !== 'level') {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
levelIndexById.set(node.id, node.level);
|
|
27
|
-
lowestLevelIndex = Math.min(lowestLevelIndex, node.level);
|
|
28
|
-
});
|
|
29
|
-
// Only the lowest level should punch through the ground plane.
|
|
30
|
-
// Upper-level slabs should still cast shadows, but they should not
|
|
31
|
-
// reveal their footprint on the level-zero ground material.
|
|
32
|
-
const polygons = [];
|
|
33
|
-
Object.values(nodes).forEach((node) => {
|
|
34
|
-
if (!(node.type === 'slab' &&
|
|
35
|
-
node.visible &&
|
|
36
|
-
node.polygon.length >= 3 &&
|
|
37
|
-
// Only recessed slabs should punch through the ground plane.
|
|
38
|
-
(node.elevation ?? 0.05) < 0)) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
if (Number.isFinite(lowestLevelIndex)) {
|
|
42
|
-
const parentLevelIndex = node.parentId
|
|
43
|
-
? levelIndexById.get(node.parentId)
|
|
44
|
-
: undefined;
|
|
45
|
-
if (parentLevelIndex !== lowestLevelIndex) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
polygons.push(node.polygon);
|
|
50
|
-
});
|
|
51
|
-
if (polygons.length > 0) {
|
|
52
|
-
for (const ring of unionPolygons(polygons.map((pts) => pts.map((p) => [p[0], -p[1]])))) {
|
|
53
|
-
if (ring.length < 3)
|
|
54
|
-
continue;
|
|
55
|
-
const hole = new THREE.Path();
|
|
56
|
-
hole.moveTo(ring[0][0], ring[0][1]);
|
|
57
|
-
for (let i = 1; i < ring.length; i++) {
|
|
58
|
-
hole.lineTo(ring[i][0], ring[i][1]);
|
|
59
|
-
}
|
|
60
|
-
hole.closePath();
|
|
61
|
-
s.holes.push(hole);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return s;
|
|
65
|
-
}, [nodes]);
|
|
66
|
-
return (_jsxs("mesh", { "position-y": -0.05, "rotation-x": -Math.PI / 2, children: [_jsx("shapeGeometry", { args: [shape] }), _jsx("meshBasicMaterial", { color: bgColor, depthWrite: true, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 1 })] }));
|
|
67
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"walkthrough-controls.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/walkthrough-controls.tsx"],"names":[],"mappings":"AAeA,eAAO,MAAM,mBAAmB,0CAwH/B,CAAA"}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { PointerLockControls } from '@react-three/drei';
|
|
4
|
-
import { useFrame, useThree } from '@react-three/fiber';
|
|
5
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
6
|
-
import { Vector3 } from 'three';
|
|
7
|
-
import useViewer from '../../store/use-viewer';
|
|
8
|
-
const MOVE_SPEED = 5;
|
|
9
|
-
const EYE_HEIGHT = 1.6;
|
|
10
|
-
const _direction = new Vector3();
|
|
11
|
-
const _forward = new Vector3();
|
|
12
|
-
const _right = new Vector3();
|
|
13
|
-
export const WalkthroughControls = () => {
|
|
14
|
-
const controlsRef = useRef(null);
|
|
15
|
-
const walkthroughMode = useViewer((s) => s.walkthroughMode);
|
|
16
|
-
const keys = useRef({ w: false, a: false, s: false, d: false });
|
|
17
|
-
const camera = useThree((s) => s.camera);
|
|
18
|
-
// Set initial eye height
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
if (walkthroughMode) {
|
|
21
|
-
camera.position.y = EYE_HEIGHT;
|
|
22
|
-
}
|
|
23
|
-
}, [walkthroughMode, camera]);
|
|
24
|
-
// Keyboard handlers
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
if (!walkthroughMode)
|
|
27
|
-
return;
|
|
28
|
-
const onKeyDown = (e) => {
|
|
29
|
-
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement)
|
|
30
|
-
return;
|
|
31
|
-
const key = e.key.toLowerCase();
|
|
32
|
-
// ESC exits walkthrough mode completely
|
|
33
|
-
if (e.key === 'Escape') {
|
|
34
|
-
e.preventDefault();
|
|
35
|
-
e.stopPropagation();
|
|
36
|
-
useViewer.getState().setWalkthroughMode(false);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
if (key === 'w' || key === 'arrowup')
|
|
40
|
-
keys.current.w = true;
|
|
41
|
-
if (key === 'a' || key === 'arrowleft')
|
|
42
|
-
keys.current.a = true;
|
|
43
|
-
if (key === 's' || key === 'arrowdown')
|
|
44
|
-
keys.current.s = true;
|
|
45
|
-
if (key === 'd' || key === 'arrowright')
|
|
46
|
-
keys.current.d = true;
|
|
47
|
-
};
|
|
48
|
-
const onKeyUp = (e) => {
|
|
49
|
-
const key = e.key.toLowerCase();
|
|
50
|
-
if (key === 'w' || key === 'arrowup')
|
|
51
|
-
keys.current.w = false;
|
|
52
|
-
if (key === 'a' || key === 'arrowleft')
|
|
53
|
-
keys.current.a = false;
|
|
54
|
-
if (key === 's' || key === 'arrowdown')
|
|
55
|
-
keys.current.s = false;
|
|
56
|
-
if (key === 'd' || key === 'arrowright')
|
|
57
|
-
keys.current.d = false;
|
|
58
|
-
};
|
|
59
|
-
window.addEventListener('keydown', onKeyDown);
|
|
60
|
-
window.addEventListener('keyup', onKeyUp);
|
|
61
|
-
return () => {
|
|
62
|
-
window.removeEventListener('keydown', onKeyDown);
|
|
63
|
-
window.removeEventListener('keyup', onKeyUp);
|
|
64
|
-
// Reset keys on cleanup
|
|
65
|
-
keys.current = { w: false, a: false, s: false, d: false };
|
|
66
|
-
};
|
|
67
|
-
}, [walkthroughMode]);
|
|
68
|
-
// Release pointer lock when walkthrough mode is turned off
|
|
69
|
-
useEffect(() => {
|
|
70
|
-
if (!walkthroughMode && document.pointerLockElement) {
|
|
71
|
-
document.exitPointerLock();
|
|
72
|
-
}
|
|
73
|
-
}, [walkthroughMode]);
|
|
74
|
-
// Movement loop
|
|
75
|
-
useFrame((_, delta) => {
|
|
76
|
-
if (!(walkthroughMode && controlsRef.current))
|
|
77
|
-
return;
|
|
78
|
-
_direction.set(0, 0, 0);
|
|
79
|
-
// Get camera forward and right vectors (XZ plane only)
|
|
80
|
-
camera.getWorldDirection(_forward);
|
|
81
|
-
_forward.y = 0;
|
|
82
|
-
_forward.normalize();
|
|
83
|
-
_right.crossVectors(_forward, camera.up).normalize();
|
|
84
|
-
if (keys.current.w)
|
|
85
|
-
_direction.add(_forward);
|
|
86
|
-
if (keys.current.s)
|
|
87
|
-
_direction.sub(_forward);
|
|
88
|
-
if (keys.current.d)
|
|
89
|
-
_direction.add(_right);
|
|
90
|
-
if (keys.current.a)
|
|
91
|
-
_direction.sub(_right);
|
|
92
|
-
if (_direction.lengthSq() > 0) {
|
|
93
|
-
_direction.normalize().multiplyScalar(MOVE_SPEED * delta);
|
|
94
|
-
camera.position.add(_direction);
|
|
95
|
-
// Keep eye height constant
|
|
96
|
-
camera.position.y = EYE_HEIGHT;
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
const handleClick = useCallback(() => {
|
|
100
|
-
if (walkthroughMode && controlsRef.current) {
|
|
101
|
-
// Feature detection: some browsers (Facebook/Instagram in-app, older Safari)
|
|
102
|
-
// don't support pointer lock on the canvas element
|
|
103
|
-
if (typeof controlsRef.current.lock === 'function') {
|
|
104
|
-
try {
|
|
105
|
-
controlsRef.current.lock();
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
// Silently ignore — pointer lock unavailable in this browser context
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}, [walkthroughMode]);
|
|
113
|
-
// Click to lock
|
|
114
|
-
useEffect(() => {
|
|
115
|
-
if (!walkthroughMode)
|
|
116
|
-
return;
|
|
117
|
-
const canvas = document.querySelector('canvas');
|
|
118
|
-
if (!canvas)
|
|
119
|
-
return;
|
|
120
|
-
canvas.addEventListener('click', handleClick);
|
|
121
|
-
return () => canvas.removeEventListener('click', handleClick);
|
|
122
|
-
}, [walkthroughMode, handleClick]);
|
|
123
|
-
if (!walkthroughMode)
|
|
124
|
-
return null;
|
|
125
|
-
// Skip PointerLockControls on browsers that don't support pointer lock
|
|
126
|
-
// (Facebook/Instagram in-app browsers, some iOS WebViews)
|
|
127
|
-
if (typeof document !== 'undefined' && !('requestPointerLock' in HTMLElement.prototype)) {
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
return _jsx(PointerLockControls, { ref: controlsRef });
|
|
131
|
-
};
|