@pascal-app/viewer 0.9.2 → 1.0.0-beta.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.
- package/README.md +20 -5
- package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
- package/dist/components/viewer/frame-limiter.js +25 -5
- package/dist/components/viewer/glb-scene.js +2 -2
- package/dist/components/viewer/glb-walkthrough-controller.d.ts +10 -0
- package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -1
- package/dist/components/viewer/glb-walkthrough-controller.js +96 -8
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +9 -0
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +1 -0
- package/dist/components/viewer/selection-manager.js +5 -2
- package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
- package/dist/hooks/use-gltf-ktx2.js +2 -5
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -8
- 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/ktx2-loader.d.ts +3 -0
- package/dist/lib/ktx2-loader.d.ts.map +1 -1
- package/dist/lib/ktx2-loader.js +6 -0
- package/dist/lib/materials.d.ts +2 -0
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +56 -9
- 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/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/store/use-viewer.d.ts +13 -0
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +16 -1
- package/dist/store/use-viewer.test.js +19 -0
- package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
- package/dist/systems/ceiling/ceiling-system.js +8 -4
- 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.map +1 -1
- package/dist/systems/geometry/geometry-system.js +18 -2
- package/dist/systems/level/level-system.d.ts.map +1 -1
- package/dist/systems/level/level-system.js +8 -7
- package/dist/systems/level/level-utils.d.ts.map +1 -1
- package/dist/systems/level/level-utils.js +7 -6
- package/dist/systems/slab/slab-system.d.ts +5 -4
- package/dist/systems/slab/slab-system.d.ts.map +1 -1
- package/dist/systems/slab/slab-system.js +24 -94
- package/dist/systems/slab/slab-system.test.js +51 -12
- package/dist/systems/stair/stair-system.js +1 -1
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +5 -2
- package/dist/systems/wall/wall-support-extension.test.js +69 -1
- package/dist/systems/wall/wall-system.d.ts +3 -7
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +87 -22
- 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/package.json +2 -2
- package/dist/components/viewer/walkthrough-controls.d.ts +0 -3
- package/dist/components/viewer/walkthrough-controls.d.ts.map +0 -1
- package/dist/components/viewer/walkthrough-controls.js +0 -151
package/README.md
CHANGED
|
@@ -5,19 +5,19 @@
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @pascal-app/viewer @pascal-app/
|
|
8
|
+
npm install @pascal-app/core @pascal-app/viewer @pascal-app/editor @pascal-app/nodes
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Peer Dependencies
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npm install react three @react-three/fiber @react-three/drei
|
|
14
|
+
npm install next react react-dom three @react-three/fiber @react-three/drei lucide-react zustand
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## What's Included
|
|
18
18
|
|
|
19
19
|
- **Viewer Component** - WebGPU-powered 3D viewer with camera controls
|
|
20
|
-
- **Node
|
|
20
|
+
- **Node Rendering Runtime** - Registry-driven dispatch for node renderers supplied by `@pascal-app/nodes`
|
|
21
21
|
- **Post-Processing** - SSGI (ambient occlusion + global illumination), TRAA (anti-aliasing), outline effects
|
|
22
22
|
- **Level System** - Level visibility and positioning (stacked/exploded/solo modes)
|
|
23
23
|
- **Wall Cutout System** - Dynamic wall hiding based on camera position
|
|
@@ -26,10 +26,22 @@ npm install react three @react-three/fiber @react-three/drei
|
|
|
26
26
|
## Usage
|
|
27
27
|
|
|
28
28
|
```typescript
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
29
|
+
import { loadPlugin } from '@pascal-app/core'
|
|
30
|
+
import { builtinPlugin } from '@pascal-app/nodes'
|
|
31
|
+
import { Viewer } from '@pascal-app/viewer'
|
|
32
|
+
import { useEffect, useState } from 'react'
|
|
33
|
+
|
|
34
|
+
const registryReady = loadPlugin(builtinPlugin)
|
|
31
35
|
|
|
32
36
|
function App() {
|
|
37
|
+
const [ready, setReady] = useState(false)
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
void registryReady.then(() => setReady(true))
|
|
41
|
+
}, [])
|
|
42
|
+
|
|
43
|
+
if (!ready) return null
|
|
44
|
+
|
|
33
45
|
return (
|
|
34
46
|
<div style={{ width: '100vw', height: '100vh' }}>
|
|
35
47
|
<Viewer />
|
|
@@ -38,6 +50,9 @@ function App() {
|
|
|
38
50
|
}
|
|
39
51
|
```
|
|
40
52
|
|
|
53
|
+
Load the built-in plugin once, before mounting any viewer. Without it, the registry has no node
|
|
54
|
+
definitions and scene nodes cannot render. Host-provided plugins use the same `loadPlugin` API.
|
|
55
|
+
|
|
41
56
|
## Custom Camera Controls
|
|
42
57
|
|
|
43
58
|
```typescript
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame-limiter.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/frame-limiter.tsx"],"names":[],"mappings":"AAIA,KAAK,iBAAiB,GAAG;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,CAAA;AAgBD,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,
|
|
1
|
+
{"version":3,"file":"frame-limiter.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/frame-limiter.tsx"],"names":[],"mappings":"AAIA,KAAK,iBAAiB,GAAG;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,CAAA;AAgBD,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAyE7C,CAAA;AAED,eAAe,YAAY,CAAA"}
|
|
@@ -28,13 +28,16 @@ const FrameLimiter = ({ fps = 50 }) => {
|
|
|
28
28
|
let timer = null;
|
|
29
29
|
let sizeSynced = false;
|
|
30
30
|
const interval = 1000 / fps;
|
|
31
|
+
function syncSize() {
|
|
32
|
+
if (sizeSynced)
|
|
33
|
+
return;
|
|
34
|
+
renderer.setPixelRatio(dpr);
|
|
35
|
+
renderer.setSize(size.width, size.height, false);
|
|
36
|
+
sizeSynced = true;
|
|
37
|
+
}
|
|
31
38
|
function tick(t) {
|
|
32
39
|
raf = requestAnimationFrame(tick);
|
|
33
|
-
|
|
34
|
-
renderer.setPixelRatio(dpr);
|
|
35
|
-
renderer.setSize(size.width, size.height, false);
|
|
36
|
-
sizeSynced = true;
|
|
37
|
-
}
|
|
40
|
+
syncSize();
|
|
38
41
|
elapsed = t - then;
|
|
39
42
|
if (elapsed > interval) {
|
|
40
43
|
advance(i);
|
|
@@ -42,6 +45,15 @@ const FrameLimiter = ({ fps = 50 }) => {
|
|
|
42
45
|
then = t - (elapsed % interval);
|
|
43
46
|
}
|
|
44
47
|
}
|
|
48
|
+
function kick() {
|
|
49
|
+
syncSize();
|
|
50
|
+
i += 1 / 1000;
|
|
51
|
+
advance(i);
|
|
52
|
+
}
|
|
53
|
+
function onVisibilityChange() {
|
|
54
|
+
if (document.visibilityState === 'visible')
|
|
55
|
+
kick();
|
|
56
|
+
}
|
|
45
57
|
// Set frameloop to never, it will shut down the default render loop
|
|
46
58
|
set({ frameloop: 'never' });
|
|
47
59
|
if (DRAW_DISABLED) {
|
|
@@ -53,6 +65,11 @@ const FrameLimiter = ({ fps = 50 }) => {
|
|
|
53
65
|
else {
|
|
54
66
|
// Kick off custom render loop
|
|
55
67
|
raf = requestAnimationFrame(tick);
|
|
68
|
+
// rAF can stall while a tab is hidden, unfocused, or occluded. With the
|
|
69
|
+
// default loop disabled, force one current frame as soon as it resumes.
|
|
70
|
+
document.addEventListener('visibilitychange', onVisibilityChange);
|
|
71
|
+
window.addEventListener('focus', kick);
|
|
72
|
+
window.addEventListener('pageshow', kick);
|
|
56
73
|
}
|
|
57
74
|
// Restore initial setting
|
|
58
75
|
return () => {
|
|
@@ -62,6 +79,9 @@ const FrameLimiter = ({ fps = 50 }) => {
|
|
|
62
79
|
if (timer) {
|
|
63
80
|
clearInterval(timer);
|
|
64
81
|
}
|
|
82
|
+
document.removeEventListener('visibilitychange', onVisibilityChange);
|
|
83
|
+
window.removeEventListener('focus', kick);
|
|
84
|
+
window.removeEventListener('pageshow', kick);
|
|
65
85
|
set({ frameloop: initFrameloop });
|
|
66
86
|
};
|
|
67
87
|
}, [advance, dpr, fps, initFrameloop, renderPaused, renderer, set, size.height, size.width]);
|
|
@@ -421,7 +421,7 @@ export function GlbScene({ url, interactiveItems, referenceNodes, replaceNodes,
|
|
|
421
421
|
}
|
|
422
422
|
else {
|
|
423
423
|
bookmarkNode = rootNode;
|
|
424
|
-
_camBox.setFromObject(gltf.scene);
|
|
424
|
+
_camBox.setFromObject(rootNode ?? gltf.scene);
|
|
425
425
|
}
|
|
426
426
|
const bookmark = bookmarkNode?.userData?.camera;
|
|
427
427
|
if (bookmark) {
|
|
@@ -781,7 +781,7 @@ export function GlbScene({ url, interactiveItems, referenceNodes, replaceNodes,
|
|
|
781
781
|
}
|
|
782
782
|
});
|
|
783
783
|
// E or click activates the openable in view. The click also re-locks the
|
|
784
|
-
// pointer
|
|
784
|
+
// pointer through the walkthrough controller; no selection happens.
|
|
785
785
|
const activateWalkDoor = useCallback(() => {
|
|
786
786
|
if (walkDoorRef.current)
|
|
787
787
|
toggleOpenable(walkDoorRef.current);
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
export declare const WALKTHROUGH_FOV = 60;
|
|
2
|
+
export declare const STAND_CAPSULE: [number, number, number, number];
|
|
3
|
+
export declare const CROUCH_CAPSULE: [number, number, number, number];
|
|
4
|
+
export declare const STAND_FLOAT_HEIGHT = 0.5;
|
|
5
|
+
export declare const CROUCH_FLOAT_HEIGHT = 0.25;
|
|
6
|
+
export declare const CROUCH_EYE_OFFSET = 0.1;
|
|
7
|
+
export declare const CROUCH_WALK_SPEED = 1;
|
|
8
|
+
export declare const CROUCH_RUN_SPEED = 1.4;
|
|
9
|
+
export declare const STAND_CLEARANCE = 1.25;
|
|
10
|
+
export declare const EYE_LERP_SPEED = 12;
|
|
1
11
|
/**
|
|
2
12
|
* First-person walkthrough controller for the baked GLB. Reuses the editor's
|
|
3
13
|
* `BVHEcctrl` capsule character controller (gravity, jump, sprint, ground-float,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glb-walkthrough-controller.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/glb-walkthrough-controller.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"glb-walkthrough-controller.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/glb-walkthrough-controller.tsx"],"names":[],"mappings":"AAiCA,eAAO,MAAM,eAAe,KAAK,CAAA;AAkBjC,eAAO,MAAM,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAqB,CAAA;AAChF,eAAO,MAAM,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAqB,CAAA;AACjF,eAAO,MAAM,kBAAkB,MAAM,CAAA;AACrC,eAAO,MAAM,mBAAmB,OAAO,CAAA;AACvC,eAAO,MAAM,iBAAiB,MAAM,CAAA;AACpC,eAAO,MAAM,iBAAiB,IAAI,CAAA;AAClC,eAAO,MAAM,gBAAgB,MAAM,CAAA;AAInC,eAAO,MAAM,eAAe,OAAO,CAAA;AACnC,eAAO,MAAM,cAAc,KAAK,CAAA;AA8LhC;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,GAAG,EAAE,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,sCAqPhE"}
|
|
@@ -3,14 +3,18 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { KeyboardControls } from '@react-three/drei';
|
|
4
4
|
import { useFrame, useThree } from '@react-three/fiber';
|
|
5
5
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
6
|
-
import { Box3, BoxGeometry, BufferGeometry, Euler, Float32BufferAttribute, Matrix4, Mesh, MeshBasicMaterial, Quaternion, Vector3, } from 'three';
|
|
6
|
+
import { Box3, BoxGeometry, BufferGeometry, Euler, Float32BufferAttribute, Matrix4, Mesh, MeshBasicMaterial, Quaternion, Raycaster, Vector3, } from 'three';
|
|
7
7
|
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
8
8
|
import { acceleratedRaycast, computeBoundsTree, disposeBoundsTree } from 'three-mesh-bvh';
|
|
9
9
|
import { useGLTFKTX2 } from '../../hooks/use-gltf-ktx2';
|
|
10
10
|
import { SCENE_LAYER } from '../../lib/layers';
|
|
11
11
|
import useViewer from '../../store/use-viewer';
|
|
12
12
|
import BVHEcctrl, {} from './bvh-ecctrl';
|
|
13
|
-
|
|
13
|
+
// First-person FOV. The orbit camera is 50° (set on the Canvas), which feels
|
|
14
|
+
// cramped on foot; ~60° vertical (~90° horizontal at 16:9) restores peripheral
|
|
15
|
+
// awareness without wide-angle distortion. Applied only while walking — both
|
|
16
|
+
// walkthrough controllers read this and restore the orbit FOV on exit.
|
|
17
|
+
export const WALKTHROUGH_FOV = 60;
|
|
14
18
|
// Eye/capsule geometry mirrors the editor's first-person controller so the
|
|
15
19
|
// baked walkthrough feels identical. The capsule centre sits below the eye; the
|
|
16
20
|
// camera rides the capsule with a small offset and the controller floats it to
|
|
@@ -20,6 +24,26 @@ const CONTROLLER_CENTER_FROM_EYE = 0.85;
|
|
|
20
24
|
const SPAWN_EYE_HEIGHT = 1.65;
|
|
21
25
|
const LOOK_SENSITIVITY = 0.002;
|
|
22
26
|
const VOID_FALL_RESPAWN_DEPTH = 12;
|
|
27
|
+
// Crouch (hold Ctrl): swap to a short capsule — it shrinks around the centre,
|
|
28
|
+
// so a crouch mid-jump also lowers the head AND raises the feet, letting the
|
|
29
|
+
// player thread window openings. Standing back up is gated on headroom.
|
|
30
|
+
// The float gap counts toward the effective obstacle height (the capsule rides
|
|
31
|
+
// floatHeight above the ground), so crouching also lowers it: crouched span is
|
|
32
|
+
// CROUCH_FLOAT_HEIGHT + capsule = 0.25 + 0.7 = 0.95 m — fits a 1 m opening.
|
|
33
|
+
export const STAND_CAPSULE = [0.25, 0.8, 4, 8];
|
|
34
|
+
export const CROUCH_CAPSULE = [0.25, 0.2, 4, 8];
|
|
35
|
+
export const STAND_FLOAT_HEIGHT = 0.5;
|
|
36
|
+
export const CROUCH_FLOAT_HEIGHT = 0.25;
|
|
37
|
+
export const CROUCH_EYE_OFFSET = 0.1;
|
|
38
|
+
export const CROUCH_WALK_SPEED = 1;
|
|
39
|
+
export const CROUCH_RUN_SPEED = 1.4;
|
|
40
|
+
// Headroom (from the capsule centre, upward) required before uncrouching:
|
|
41
|
+
// standing raises the centre by half the length delta plus the float delta,
|
|
42
|
+
// and the standing capsule top sits standLength/2 + radius above the centre.
|
|
43
|
+
export const STAND_CLEARANCE = 1.25;
|
|
44
|
+
export const EYE_LERP_SPEED = 12;
|
|
45
|
+
const standClearanceRaycaster = new Raycaster();
|
|
46
|
+
const UP = new Vector3(0, 1, 0);
|
|
23
47
|
// Kinds that must not block the player: room helpers, the spawn marker, the
|
|
24
48
|
// ceiling/roof shell (you walk under them), and door/window leaves — excluding
|
|
25
49
|
// the latter lets you pass any doorway whether the leaf is open or shut (the
|
|
@@ -34,7 +58,7 @@ const keyboardMap = [
|
|
|
34
58
|
{ name: 'jump', keys: ['Space'] },
|
|
35
59
|
{ name: 'run', keys: ['ShiftLeft', 'ShiftRight'] },
|
|
36
60
|
];
|
|
37
|
-
const cameraOffset = new Vector3(
|
|
61
|
+
const cameraOffset = new Vector3();
|
|
38
62
|
const cameraEuler = new Euler(0, 0, 0, 'YXZ');
|
|
39
63
|
const spawnQuat = new Quaternion();
|
|
40
64
|
const spawnEuler = new Euler(0, 0, 0, 'YXZ');
|
|
@@ -205,6 +229,10 @@ export function GlbWalkthroughController({ url }) {
|
|
|
205
229
|
const controllerRef = useRef(null);
|
|
206
230
|
const yawRef = useRef(0);
|
|
207
231
|
const pitchRef = useRef(0);
|
|
232
|
+
const crouchKeyRef = useRef(false);
|
|
233
|
+
const suspendRef = useRef(false);
|
|
234
|
+
const eyeOffsetRef = useRef(CAMERA_EYE_OFFSET);
|
|
235
|
+
const [crouched, setCrouched] = useState(false);
|
|
208
236
|
const [start, setStart] = useState(null);
|
|
209
237
|
const [world, setWorld] = useState(null);
|
|
210
238
|
// Build the collider on the first frame (priority after GlbScene's level loop,
|
|
@@ -299,22 +327,63 @@ export function GlbWalkthroughController({ url }) {
|
|
|
299
327
|
if (event.code === 'Escape' && document.pointerLockElement !== canvas) {
|
|
300
328
|
useViewer.getState().setWalkthroughMode(false);
|
|
301
329
|
}
|
|
330
|
+
// P toggles a cursor pause (advertised in the HUD): frees the pointer
|
|
331
|
+
// without leaving the walkthrough — e.g. for an OS screenshot, which
|
|
332
|
+
// needs a movable cursor — and click or P resumes.
|
|
333
|
+
if (event.code === 'KeyP') {
|
|
334
|
+
if (document.pointerLockElement === canvas) {
|
|
335
|
+
suspendRef.current = true;
|
|
336
|
+
useViewer.getState().setWalkthroughSuspended(true);
|
|
337
|
+
document.exitPointerLock();
|
|
338
|
+
}
|
|
339
|
+
else if (suspendRef.current) {
|
|
340
|
+
const result = canvas.requestPointerLock?.();
|
|
341
|
+
if (result && typeof result.catch === 'function')
|
|
342
|
+
result.catch(() => { });
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// While paused (P), crouch is frozen as-is — ⌃⇧⌘4 (clipboard screenshot)
|
|
346
|
+
// must not toggle it under the user.
|
|
347
|
+
if ((event.code === 'ControlLeft' || event.code === 'ControlRight') && !suspendRef.current) {
|
|
348
|
+
crouchKeyRef.current = true;
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
const onKeyUp = (event) => {
|
|
352
|
+
if ((event.code === 'ControlLeft' || event.code === 'ControlRight') && !suspendRef.current) {
|
|
353
|
+
crouchKeyRef.current = false;
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
const onBlur = () => {
|
|
357
|
+
if (!suspendRef.current)
|
|
358
|
+
crouchKeyRef.current = false;
|
|
302
359
|
};
|
|
303
360
|
const onPointerLockChange = () => {
|
|
304
|
-
if (document.pointerLockElement === canvas)
|
|
361
|
+
if (document.pointerLockElement === canvas) {
|
|
305
362
|
wasLocked = true;
|
|
306
|
-
|
|
363
|
+
suspendRef.current = false;
|
|
364
|
+
useViewer.getState().setWalkthroughSuspended(false);
|
|
365
|
+
}
|
|
366
|
+
else if (suspendRef.current) {
|
|
367
|
+
// Deliberately released (screenshot pause) — stay in walkthrough.
|
|
368
|
+
}
|
|
369
|
+
else if (wasLocked) {
|
|
307
370
|
useViewer.getState().setWalkthroughMode(false);
|
|
371
|
+
}
|
|
308
372
|
};
|
|
309
373
|
document.addEventListener('mousemove', onMouseMove);
|
|
310
374
|
canvas.addEventListener('click', onClick);
|
|
311
375
|
document.addEventListener('keydown', onKeyDown);
|
|
376
|
+
document.addEventListener('keyup', onKeyUp);
|
|
377
|
+
window.addEventListener('blur', onBlur);
|
|
312
378
|
document.addEventListener('pointerlockchange', onPointerLockChange);
|
|
313
379
|
return () => {
|
|
314
380
|
document.removeEventListener('mousemove', onMouseMove);
|
|
315
381
|
canvas.removeEventListener('click', onClick);
|
|
316
382
|
document.removeEventListener('keydown', onKeyDown);
|
|
383
|
+
document.removeEventListener('keyup', onKeyUp);
|
|
384
|
+
window.removeEventListener('blur', onBlur);
|
|
317
385
|
document.removeEventListener('pointerlockchange', onPointerLockChange);
|
|
386
|
+
useViewer.getState().setWalkthroughSuspended(false);
|
|
318
387
|
if (document.pointerLockElement === canvas)
|
|
319
388
|
document.exitPointerLock();
|
|
320
389
|
};
|
|
@@ -336,8 +405,16 @@ export function GlbWalkthroughController({ url }) {
|
|
|
336
405
|
const setControllerApi = useCallback((api) => {
|
|
337
406
|
controllerRef.current = api;
|
|
338
407
|
}, []);
|
|
408
|
+
const hasStandingClearance = useCallback((position) => {
|
|
409
|
+
const mesh = worldRef.current?.mesh;
|
|
410
|
+
if (!mesh)
|
|
411
|
+
return true;
|
|
412
|
+
standClearanceRaycaster.set(position, UP);
|
|
413
|
+
standClearanceRaycaster.far = STAND_CLEARANCE;
|
|
414
|
+
return standClearanceRaycaster.intersectObject(mesh, false).length === 0;
|
|
415
|
+
}, []);
|
|
339
416
|
// Drive the camera from the capsule each frame + respawn if it falls into void.
|
|
340
|
-
useFrame(() => {
|
|
417
|
+
useFrame((_, delta) => {
|
|
341
418
|
const group = controllerRef.current?.group;
|
|
342
419
|
if (!group)
|
|
343
420
|
return;
|
|
@@ -345,13 +422,24 @@ export function GlbWalkthroughController({ url }) {
|
|
|
345
422
|
group.position.set(start.position[0], start.position[1], start.position[2]);
|
|
346
423
|
controllerRef.current?.resetLinVel();
|
|
347
424
|
}
|
|
425
|
+
// Crouch follows the held key; standing back up waits for headroom.
|
|
426
|
+
// Frozen while the cursor pause is active.
|
|
427
|
+
if (!suspendRef.current && crouchKeyRef.current !== crouched) {
|
|
428
|
+
if (crouchKeyRef.current)
|
|
429
|
+
setCrouched(true);
|
|
430
|
+
else if (hasStandingClearance(group.position))
|
|
431
|
+
setCrouched(false);
|
|
432
|
+
}
|
|
433
|
+
const targetEyeOffset = crouched ? CROUCH_EYE_OFFSET : CAMERA_EYE_OFFSET;
|
|
434
|
+
eyeOffsetRef.current +=
|
|
435
|
+
(targetEyeOffset - eyeOffsetRef.current) * Math.min(1, delta * EYE_LERP_SPEED);
|
|
348
436
|
group.rotation.y = 0;
|
|
349
|
-
camera.position.copy(group.position).add(cameraOffset);
|
|
437
|
+
camera.position.copy(group.position).add(cameraOffset.set(0, eyeOffsetRef.current, 0));
|
|
350
438
|
cameraEuler.set(pitchRef.current, yawRef.current, 0, 'YXZ');
|
|
351
439
|
camera.quaternion.setFromEuler(cameraEuler);
|
|
352
440
|
camera.updateMatrixWorld(true);
|
|
353
441
|
}, 2.5);
|
|
354
442
|
if (!(world && start))
|
|
355
443
|
return null;
|
|
356
|
-
return (_jsx(KeyboardControls, { map: keyboardMap, children: _jsx(BVHEcctrl, { acceleration: 26, airDragFactor: 0.3, colliderCapsuleArgs:
|
|
444
|
+
return (_jsx(KeyboardControls, { map: keyboardMap, children: _jsx(BVHEcctrl, { acceleration: 26, airDragFactor: 0.3, colliderCapsuleArgs: crouched ? CROUCH_CAPSULE : STAND_CAPSULE, colliderMeshes: [world.mesh], collisionCheckIteration: 3, collisionPushBackDamping: 0.1, collisionPushBackThreshold: 0.001, deceleration: 30, delay: 0, fallGravityFactor: 4, floatCheckType: "BOTH", floatDampingC: 36, floatHeight: crouched ? CROUCH_FLOAT_HEIGHT : STAND_FLOAT_HEIGHT, floatPullBackHeight: 0.35, floatSensorRadius: 0.15, floatSpringK: 1200, gravity: 9.81, jumpVel: 5, maxRunSpeed: crouched ? CROUCH_RUN_SPEED : 5, maxSlope: 1.2, maxWalkSpeed: crouched ? CROUCH_WALK_SPEED : 2, position: start.position, ref: setControllerApi }) }));
|
|
357
445
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,SAAS,EAKf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAkB,KAAK,YAAY,EAAsB,MAAM,oBAAoB,CAAA;AAS1F,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAKrC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,SAAS,EAKf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAkB,KAAK,YAAY,EAAsB,MAAM,oBAAoB,CAAA;AAS1F,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAKrC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGrE,OAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAQtE,OAAuB,EAAwB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAU1F,OAAO,QAAQ,oBAAoB,CAAC;IAOlC,UAAU,aAAa;QACrB,qBAAqB,EAAE,YAAY,CAAC,OAAO,KAAK,CAAC,qBAAqB,CAAC,CAAA;KACxE;CACF;AAuSD,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,gBAAgB,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;IACvC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,aAAa,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,aAAa,CAAA;QACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,WAAW,CAAC,EAAE,WAAW,CAAA;KAC1B,CAAA;IACD;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;IAC5B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACtC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAC7C;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,yDAAyD;AACzD,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;OAKG;IACH,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;CAC3C,CAAA;AAED,QAAA,MAAM,MAAM,sGA4NV,CAAA;AAkBF,eAAe,MAAM,CAAA"}
|
|
@@ -9,6 +9,7 @@ import { PERF_OVERLAY_ENABLED, pushGpuSample } from '../../lib/gpu-perf';
|
|
|
9
9
|
import { applyIsolation, clearIsolation } from '../../lib/isolation';
|
|
10
10
|
import { ensureKtx2Support } from '../../lib/ktx2-loader';
|
|
11
11
|
import { getSceneTheme } from '../../lib/scene-themes';
|
|
12
|
+
import { installTextureNodeNullGuard } from '../../lib/texture-node-guard';
|
|
12
13
|
import useViewer, {} from '../../store/use-viewer';
|
|
13
14
|
import { FloorElevationSystem } from '../../systems/floor-elevation/floor-elevation-system';
|
|
14
15
|
import { GeometrySystem } from '../../systems/geometry/geometry-system';
|
|
@@ -22,6 +23,9 @@ import { RegisteredSystems } from './registered-systems';
|
|
|
22
23
|
import { SceneBvh } from './scene-bvh';
|
|
23
24
|
import { SelectionManager } from './selection-manager';
|
|
24
25
|
import { ViewerCamera } from './viewer-camera';
|
|
26
|
+
// Must be in place before any node material builds — a null texture pulled by
|
|
27
|
+
// a shared override-material pass otherwise kills the render pass outright.
|
|
28
|
+
installTextureNodeNullGuard();
|
|
25
29
|
extend(THREE);
|
|
26
30
|
// R3F's <Canvas> useLayoutEffect has no deps, so any re-render (theme switch,
|
|
27
31
|
// parent re-render, StrictMode double-mount) re-invokes `configure()`. With a
|
|
@@ -227,6 +231,11 @@ function SceneReadyTracker({ onSceneReadyChange, sceneReadyKey, sceneReadyMaxWai
|
|
|
227
231
|
return null;
|
|
228
232
|
}
|
|
229
233
|
const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVER_STYLES, selectionManager = 'default', perf = false, useBvh = true, renderContext = 'editor', transparent, defaultRender, isolate, sceneReadyKey, onSceneReadyChange, sceneReadyMaxWaitMs, disablePostFx = false, }, ref) {
|
|
234
|
+
useEffect(() => {
|
|
235
|
+
if (nodeRegistry.size === 0) {
|
|
236
|
+
console.warn('[viewer] Node registry is empty. Install @pascal-app/nodes and call await loadPlugin(builtinPlugin) before mounting <Viewer>.');
|
|
237
|
+
}
|
|
238
|
+
}, []);
|
|
230
239
|
useImperativeHandle(ref, () => ({
|
|
231
240
|
setIsolated: (ids) => applyIsolation(ids),
|
|
232
241
|
}), []);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"post-processing.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/post-processing.tsx"],"names":[],"mappings":"AAwCA,eAAO,MAAM,YAAY;;;CAGxB,CAAA;AAGD,eAAO,MAAM,WAAW;;;;;;;;;;;;;CAavB,CAAA;AA0DD,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,UAAU,CAAA;CACpB,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;AAS9B,eAAO,MAAM,oBAAoB,EAAE,WAElC,CAAA;AAiBD,QAAA,MAAM,oBAAoB,GAAI,iCAG3B;IACD,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,
|
|
1
|
+
{"version":3,"file":"post-processing.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/post-processing.tsx"],"names":[],"mappings":"AAwCA,eAAO,MAAM,YAAY;;;CAGxB,CAAA;AAGD,eAAO,MAAM,WAAW;;;;;;;;;;;;;CAavB,CAAA;AA0DD,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,UAAU,CAAA;CACpB,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;AAS9B,eAAO,MAAM,oBAAoB,EAAE,WAElC,CAAA;AAiBD,QAAA,MAAM,oBAAoB,GAAI,iCAG3B;IACD,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,SAgnBA,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
|
@@ -618,6 +618,7 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
618
618
|
}
|
|
619
619
|
catch (error) {
|
|
620
620
|
hasPipelineErrorRef.current = true;
|
|
621
|
+
renderer.setRenderTarget?.(null);
|
|
621
622
|
console.error('[viewer/post-processing] Render pass failed.', {
|
|
622
623
|
retryCount: retryCountRef.current,
|
|
623
624
|
rendererCtor: renderer.constructor?.name,
|
|
@@ -353,13 +353,16 @@ const PointerMissedHandler = ({ clickHandledRef, }) => {
|
|
|
353
353
|
};
|
|
354
354
|
const OutlinerSync = () => {
|
|
355
355
|
const selection = useViewer((s) => s.selection);
|
|
356
|
+
const externalSelectedIds = useViewer((s) => s.externalSelectedIds);
|
|
356
357
|
const hoveredId = useViewer((s) => s.hoveredId);
|
|
357
358
|
const outliner = useViewer((s) => s.outliner);
|
|
359
|
+
const geometryRevision = useViewer((s) => s.geometryRevision);
|
|
358
360
|
const nodes = useScene((s) => s.nodes);
|
|
359
361
|
useEffect(() => {
|
|
362
|
+
void geometryRevision;
|
|
360
363
|
// Sync selected objects
|
|
361
364
|
outliner.selectedObjects.length = 0;
|
|
362
|
-
for (const id of selection.selectedIds) {
|
|
365
|
+
for (const id of new Set([...selection.selectedIds, ...externalSelectedIds])) {
|
|
363
366
|
const node = nodes[id];
|
|
364
367
|
if (node?.type === 'slab')
|
|
365
368
|
continue;
|
|
@@ -377,6 +380,6 @@ const OutlinerSync = () => {
|
|
|
377
380
|
if (obj)
|
|
378
381
|
outliner.hoveredObjects.push(obj);
|
|
379
382
|
}
|
|
380
|
-
}, [selection, hoveredId, outliner, nodes]);
|
|
383
|
+
}, [selection, externalSelectedIds, hoveredId, outliner, nodes, geometryRevision]);
|
|
381
384
|
return null;
|
|
382
385
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-gltf-ktx2.d.ts","sourceRoot":"","sources":["../../src/hooks/use-gltf-ktx2.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAK3C,QAAA,MAAM,WAAW,GAAI,MAAM,MAAM,KAAG,UAAU,CAAC,OAAO,OAAO,
|
|
1
|
+
{"version":3,"file":"use-gltf-ktx2.d.ts","sourceRoot":"","sources":["../../src/hooks/use-gltf-ktx2.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAK3C,QAAA,MAAM,WAAW,GAAI,MAAM,MAAM,KAAG,UAAU,CAAC,OAAO,OAAO,CAO5D,CAAA;AAED,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { useGLTF } from '@react-three/drei';
|
|
2
2
|
import { useThree } from '@react-three/fiber';
|
|
3
3
|
import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js';
|
|
4
|
-
import {
|
|
4
|
+
import { configureKtx2Support } from '../lib/ktx2-loader';
|
|
5
5
|
const useGLTFKTX2 = (path) => {
|
|
6
6
|
const gl = useThree((state) => state.gl);
|
|
7
7
|
return useGLTF(path, true, true, (loader) => {
|
|
8
|
-
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
-
loader.setKTX2Loader(ktx2Loader);
|
|
11
|
-
}
|
|
8
|
+
configureKtx2Support(loader, gl);
|
|
12
9
|
loader.setMeshoptDecoder(MeshoptDecoder);
|
|
13
10
|
});
|
|
14
11
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -6,11 +6,10 @@ export { type BVHEcctrlApi, default as BVHEcctrl, type MovementInput, } from './
|
|
|
6
6
|
export { buildGlbInteractiveItems, GlbInteractive, type GlbInteractiveItem, } from './components/viewer/glb-interactive';
|
|
7
7
|
export { buildGlbReferenceNodes, buildGlbReplaceNodes, } from './components/viewer/glb-reference-nodes';
|
|
8
8
|
export { type GlbHover, type GlbIdentity, type GlbLevel, GlbScene, type GlbWalkthrough, } from './components/viewer/glb-scene';
|
|
9
|
-
export { GlbWalkthroughController } from './components/viewer/glb-walkthrough-controller';
|
|
9
|
+
export { CROUCH_CAPSULE, CROUCH_EYE_OFFSET, CROUCH_FLOAT_HEIGHT, CROUCH_RUN_SPEED, CROUCH_WALK_SPEED, EYE_LERP_SPEED, GlbWalkthroughController, STAND_CAPSULE, STAND_CLEARANCE, STAND_FLOAT_HEIGHT, WALKTHROUGH_FOV, } from './components/viewer/glb-walkthrough-controller';
|
|
10
10
|
export type { HoverStyle, HoverStyles } from './components/viewer/post-processing';
|
|
11
11
|
export { DEFAULT_HOVER_STYLES, SSGI_PARAMS, } from './components/viewer/post-processing';
|
|
12
12
|
export { SceneEnvironment } from './components/viewer/scene-environment';
|
|
13
|
-
export { WalkthroughControls } from './components/viewer/walkthrough-controls';
|
|
14
13
|
export { useAssetUrl } from './hooks/use-asset-url';
|
|
15
14
|
export { useGLTFKTX2 } from './hooks/use-gltf-ktx2';
|
|
16
15
|
export { useNodeEvents } from './hooks/use-node-events';
|
|
@@ -19,16 +18,20 @@ export { backdropGradient, deepSkyColor, horizonHazeColor } from './lib/backdrop
|
|
|
19
18
|
export { applyWorldScaleBoxUVs } from './lib/box-uv';
|
|
20
19
|
export { ADDITION, Brush, computeGeometryBoundsTree, csgEvaluator, csgGeometry, csgMaterials, INTERSECTION, prepareBrushForCSG, SUBTRACTION, } from './lib/csg-utils';
|
|
21
20
|
export type { EdgeMode } from './lib/edge-style';
|
|
21
|
+
export { computeHeroFraming, DEFAULT_FRAMING_EXCLUDED_TYPES, type HeroFraming, heroCameraPose, temporarilyHideNodeTypes, unionRegisteredNodeBounds, } from './lib/hero-pose';
|
|
22
22
|
export { applyIsolation, clearIsolation, collectIsolationSubtree, isIsolationActive, } from './lib/isolation';
|
|
23
|
-
export { ensureKtx2Support } from './lib/ktx2-loader';
|
|
23
|
+
export { configureKtx2Support, ensureKtx2Support } from './lib/ktx2-loader';
|
|
24
24
|
export { GRID_LAYER, OVERLAY_LAYER, SCENE_LAYER, ZONE_LAYER } from './lib/layers';
|
|
25
25
|
export { applyMaterialPresetToMaterials, BLUEPRINT_PALETTE, baseMaterial, CLAY_PALETTE, type ColorPreset, clearMaterialCache, createDefaultMaterial, createMaterial, createMaterialFromPresetRef, createSurfaceRoleMaterial, DEFAULT_CEILING_MATERIAL, DEFAULT_DOOR_MATERIAL, DEFAULT_ROOF_MATERIAL, DEFAULT_SHELF_MATERIAL, DEFAULT_SLAB_MATERIAL, DEFAULT_STAIR_MATERIAL, DEFAULT_WALL_MATERIAL, DEFAULT_WINDOW_MATERIAL, disposeMaterial, glassMaterial, MONO_PALETTE, PRESET_PALETTES, type RenderShading, resolveMaterialRef, resolveSlotDefaultMaterial, resolveSurfaceColor, WHITE_PALETTE, } from './lib/materials';
|
|
26
26
|
export { mergedOutline } from './lib/merged-outline-node';
|
|
27
27
|
export { unionPolygons } from './lib/polygon-union';
|
|
28
28
|
export { getSceneTheme, SCENE_THEME_IDS, SCENE_THEMES, type SceneTheme, } from './lib/scene-themes';
|
|
29
|
+
export { createSnapshotPipeline, type SnapshotCaptureMode, type SnapshotCaptureResult, type SnapshotCropRegion, type SnapshotPipeline, type SnapshotSize, THUMBNAIL_HEIGHT, THUMBNAIL_WIDTH, } from './lib/snapshot-pipeline';
|
|
30
|
+
export { buildTerrainPerimeterFillGeometry, type TerrainPerimeterPoint, } from './lib/terrain-perimeter-fill';
|
|
31
|
+
export { getPascalTextureRef, type PascalTextureColorSpace, type PascalTextureMap, type PascalTextureRef, stampPascalTextureRef, textureMapForSlot, } from './lib/texture-reference';
|
|
29
32
|
export { packNormalToRGB, unpackRGBToNormal } from './lib/tsl-compat';
|
|
30
33
|
export { useItemLightPool } from './store/use-item-light-pool';
|
|
31
|
-
export { applyCountryUnitDefault, default as useViewer } from './store/use-viewer';
|
|
34
|
+
export { applyCountryUnitDefault, default as useViewer, type MetricNotation, } from './store/use-viewer';
|
|
32
35
|
export { CeilingSystem } from './systems/ceiling/ceiling-system';
|
|
33
36
|
export { createColumnBoxGeometry, createColumnCylinderGeometry, createColumnSphereGeometry, createColumnTorusGeometry, } from './systems/column/column-geometry';
|
|
34
37
|
export { DoorAnimationSystem } from './systems/door/door-animation-system';
|
|
@@ -45,7 +48,7 @@ export { snapLevelsToTruePositions } from './systems/level/level-utils';
|
|
|
45
48
|
export { getRoofMaterialArray } from './systems/roof/roof-materials';
|
|
46
49
|
export { clipGeometryBySegmentTrim, generateRoofSegmentGeometry, getRoofOuterSurfaceFrameAtPoint, getRoofSegmentBrushes, mapRoofGroupMaterialIndex, ROOF_MATERIAL_SLOT_COUNT, RoofSystem, remapRoofShellFaces, roofCsgDummyMats, type SurfaceFrame, } from './systems/roof/roof-system';
|
|
47
50
|
export { ScanSystem } from './systems/scan/scan-system';
|
|
48
|
-
export { generateSlabGeometry
|
|
51
|
+
export { generateSlabGeometry } from './systems/slab/slab-system';
|
|
49
52
|
export { getStairBodyMaterials, getStairRailingMaterial, getStraightStairSegmentBodyMaterials, type StairBodyMaterials, } from './systems/stair/stair-materials';
|
|
50
53
|
export { StairSystem } from './systems/stair/stair-system';
|
|
51
54
|
export { buildOpeningCutoutGeometry, getOpeningCutoutBottomPadding, hasFlatOpeningCutoutBottom, } from './systems/wall/opening-cutout-geometry';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAO3D,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAA;AACnE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAC1E,OAAO,EACL,KAAK,YAAY,EACjB,OAAO,IAAI,SAAS,EACpB,KAAK,aAAa,GACnB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EACL,wBAAwB,EACxB,cAAc,EACd,KAAK,kBAAkB,GACxB,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EACL,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,yCAAyC,CAAA;AAChD,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,QAAQ,EACR,KAAK,cAAc,GACpB,MAAM,+BAA+B,CAAA;AACtC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -15,10 +15,9 @@ export { default as BVHEcctrl, } from './components/viewer/bvh-ecctrl';
|
|
|
15
15
|
export { buildGlbInteractiveItems, GlbInteractive, } from './components/viewer/glb-interactive';
|
|
16
16
|
export { buildGlbReferenceNodes, buildGlbReplaceNodes, } from './components/viewer/glb-reference-nodes';
|
|
17
17
|
export { GlbScene, } from './components/viewer/glb-scene';
|
|
18
|
-
export { GlbWalkthroughController } from './components/viewer/glb-walkthrough-controller';
|
|
18
|
+
export { CROUCH_CAPSULE, CROUCH_EYE_OFFSET, CROUCH_FLOAT_HEIGHT, CROUCH_RUN_SPEED, CROUCH_WALK_SPEED, EYE_LERP_SPEED, GlbWalkthroughController, STAND_CAPSULE, STAND_CLEARANCE, STAND_FLOAT_HEIGHT, WALKTHROUGH_FOV, } from './components/viewer/glb-walkthrough-controller';
|
|
19
19
|
export { DEFAULT_HOVER_STYLES, SSGI_PARAMS, } from './components/viewer/post-processing';
|
|
20
20
|
export { SceneEnvironment } from './components/viewer/scene-environment';
|
|
21
|
-
export { WalkthroughControls } from './components/viewer/walkthrough-controls';
|
|
22
21
|
export { useAssetUrl } from './hooks/use-asset-url';
|
|
23
22
|
export { useGLTFKTX2 } from './hooks/use-gltf-ktx2';
|
|
24
23
|
export { useNodeEvents } from './hooks/use-node-events';
|
|
@@ -29,16 +28,20 @@ export { applyWorldScaleBoxUVs } from './lib/box-uv';
|
|
|
29
28
|
// geometry subtracts pieces against their host. Lives in viewer
|
|
30
29
|
// because three-bvh-csg / three-mesh-bvh are viewer-only deps.
|
|
31
30
|
export { ADDITION, Brush, computeGeometryBoundsTree, csgEvaluator, csgGeometry, csgMaterials, INTERSECTION, prepareBrushForCSG, SUBTRACTION, } from './lib/csg-utils';
|
|
31
|
+
export { computeHeroFraming, DEFAULT_FRAMING_EXCLUDED_TYPES, heroCameraPose, temporarilyHideNodeTypes, unionRegisteredNodeBounds, } from './lib/hero-pose';
|
|
32
32
|
export { applyIsolation, clearIsolation, collectIsolationSubtree, isIsolationActive, } from './lib/isolation';
|
|
33
|
-
export { ensureKtx2Support } from './lib/ktx2-loader';
|
|
33
|
+
export { configureKtx2Support, ensureKtx2Support } from './lib/ktx2-loader';
|
|
34
34
|
export { GRID_LAYER, OVERLAY_LAYER, SCENE_LAYER, ZONE_LAYER } from './lib/layers';
|
|
35
35
|
export { applyMaterialPresetToMaterials, BLUEPRINT_PALETTE, baseMaterial, CLAY_PALETTE, clearMaterialCache, createDefaultMaterial, createMaterial, createMaterialFromPresetRef, createSurfaceRoleMaterial, DEFAULT_CEILING_MATERIAL, DEFAULT_DOOR_MATERIAL, DEFAULT_ROOF_MATERIAL, DEFAULT_SHELF_MATERIAL, DEFAULT_SLAB_MATERIAL, DEFAULT_STAIR_MATERIAL, DEFAULT_WALL_MATERIAL, DEFAULT_WINDOW_MATERIAL, disposeMaterial, glassMaterial, MONO_PALETTE, PRESET_PALETTES, resolveMaterialRef, resolveSlotDefaultMaterial, resolveSurfaceColor, WHITE_PALETTE, } from './lib/materials';
|
|
36
36
|
export { mergedOutline } from './lib/merged-outline-node';
|
|
37
37
|
export { unionPolygons } from './lib/polygon-union';
|
|
38
38
|
export { getSceneTheme, SCENE_THEME_IDS, SCENE_THEMES, } from './lib/scene-themes';
|
|
39
|
+
export { createSnapshotPipeline, THUMBNAIL_HEIGHT, THUMBNAIL_WIDTH, } from './lib/snapshot-pipeline';
|
|
40
|
+
export { buildTerrainPerimeterFillGeometry, } from './lib/terrain-perimeter-fill';
|
|
41
|
+
export { getPascalTextureRef, stampPascalTextureRef, textureMapForSlot, } from './lib/texture-reference';
|
|
39
42
|
export { packNormalToRGB, unpackRGBToNormal } from './lib/tsl-compat';
|
|
40
43
|
export { useItemLightPool } from './store/use-item-light-pool';
|
|
41
|
-
export { applyCountryUnitDefault, default as useViewer } from './store/use-viewer';
|
|
44
|
+
export { applyCountryUnitDefault, default as useViewer, } from './store/use-viewer';
|
|
42
45
|
export { CeilingSystem } from './systems/ceiling/ceiling-system';
|
|
43
46
|
export { createColumnBoxGeometry, createColumnCylinderGeometry, createColumnSphereGeometry, createColumnTorusGeometry, } from './systems/column/column-geometry';
|
|
44
47
|
export { DoorAnimationSystem } from './systems/door/door-animation-system';
|
|
@@ -69,10 +72,9 @@ export { getRoofMaterialArray } from './systems/roof/roof-materials';
|
|
|
69
72
|
// belong here — those live in `@pascal-app/nodes/<kind>/`.
|
|
70
73
|
export { clipGeometryBySegmentTrim, generateRoofSegmentGeometry, getRoofOuterSurfaceFrameAtPoint, getRoofSegmentBrushes, mapRoofGroupMaterialIndex, ROOF_MATERIAL_SLOT_COUNT, RoofSystem, remapRoofShellFaces, roofCsgDummyMats, } from './systems/roof/roof-system';
|
|
71
74
|
export { ScanSystem } from './systems/scan/scan-system';
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
export { generateSlabGeometry, SlabSystem } from './systems/slab/slab-system';
|
|
75
|
+
// Pure slab geometry generator — composed into the registry-driven slab
|
|
76
|
+
// definition's `def.geometry` in `@pascal-app/nodes`.
|
|
77
|
+
export { generateSlabGeometry } from './systems/slab/slab-system';
|
|
76
78
|
export { getStairBodyMaterials, getStairRailingMaterial, getStraightStairSegmentBodyMaterials, } from './systems/stair/stair-materials';
|
|
77
79
|
export { StairSystem } from './systems/stair/stair-system';
|
|
78
80
|
// Pure opening-cutout profile math shared by the wall CSG pipeline and
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Box3 } from 'three';
|
|
2
|
+
export declare const DEFAULT_FRAMING_EXCLUDED_TYPES: readonly ["site", "scan", "guide", "spawn"];
|
|
3
|
+
export declare function heroCameraPose({ boxes, aspect, aim, fovDeg, azimuthRad, elevationRad, padding, minDistance, frameShift, }: {
|
|
4
|
+
boxes: Box3 | readonly Box3[];
|
|
5
|
+
aspect: number;
|
|
6
|
+
/** Where the camera looks (frame center). Defaults to the union-box center;
|
|
7
|
+
* pass the building's center to keep it dead-center while outlying boxes
|
|
8
|
+
* (lot plate, far palms) simply take asymmetric margin — the corner fit
|
|
9
|
+
* still guarantees every box stays in frame. */
|
|
10
|
+
aim?: [number, number, number];
|
|
11
|
+
fovDeg?: number;
|
|
12
|
+
azimuthRad?: number;
|
|
13
|
+
elevationRad?: number;
|
|
14
|
+
padding?: number;
|
|
15
|
+
minDistance?: number;
|
|
16
|
+
/** Fraction of the frustum half-height to drop the aim by. 0 keeps the aim
|
|
17
|
+
* (the building center) exactly at frame center. */
|
|
18
|
+
frameShift?: number;
|
|
19
|
+
}): {
|
|
20
|
+
position: [number, number, number];
|
|
21
|
+
target: [number, number, number];
|
|
22
|
+
};
|
|
23
|
+
export declare function unionRegisteredNodeBounds({ excludeTypes, }: {
|
|
24
|
+
excludeTypes: readonly string[];
|
|
25
|
+
}): Box3 | null;
|
|
26
|
+
export type HeroFraming = {
|
|
27
|
+
/** Fit constraints — everything that must stay in frame. */
|
|
28
|
+
boxes: Box3[];
|
|
29
|
+
/** Frame center: plate/structure center on XZ, building center on Y. */
|
|
30
|
+
aim: [number, number, number];
|
|
31
|
+
/** 45° to the dominant facade (falls back to world 45°). */
|
|
32
|
+
azimuthRad: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Framing for a scene hero shot. The base set is the built structure (walls,
|
|
36
|
+
* roofs, slabs, …) plus any intentionally-shaped site plate; an item joins
|
|
37
|
+
* only when it sits near that base — one palm at the far lot corner must not
|
|
38
|
+
* shrink the building. `building`/`level` container groups are skipped (their
|
|
39
|
+
* Object3D holds the whole subtree). The aim keeps the building dead-center:
|
|
40
|
+
* XZ from the plate+structure union, Y from the structure alone so the
|
|
41
|
+
* building — not the ground — is vertically centered. Scenes with no
|
|
42
|
+
* structure (pure furniture arrangements) fall back to framing every
|
|
43
|
+
* non-helper node.
|
|
44
|
+
*/
|
|
45
|
+
export declare function computeHeroFraming(): HeroFraming | null;
|
|
46
|
+
export declare function temporarilyHideNodeTypes(types: readonly string[]): () => void;
|
|
47
|
+
//# sourceMappingURL=hero-pose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hero-pose.d.ts","sourceRoot":"","sources":["../../src/lib/hero-pose.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAA0B,MAAM,OAAO,CAAA;AAEpD,eAAO,MAAM,8BAA8B,6CAA8C,CAAA;AAEzF,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,MAAM,EACN,GAAG,EACH,MAAW,EACX,UAAwB,EACxB,YAAmC,EACnC,OAAc,EACd,WAAe,EACf,UAAc,GACf,EAAE;IACD,KAAK,EAAE,IAAI,GAAG,SAAS,IAAI,EAAE,CAAA;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd;;;qDAGiD;IACjD,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;yDACqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,GAAG;IACF,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC,CA2DA;AAED,wBAAgB,yBAAyB,CAAC,EACxC,YAAY,GACb,EAAE;IACD,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;CAChC,GAAG,IAAI,GAAG,IAAI,CAgBd;AAiFD,MAAM,MAAM,WAAW,GAAG;IACxB,4DAA4D;IAC5D,KAAK,EAAE,IAAI,EAAE,CAAA;IACb,wEAAwE;IACxE,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,IAAI,WAAW,GAAG,IAAI,CAuCvD;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,IAAI,CAiB7E"}
|