@pascal-app/viewer 0.5.0 → 0.6.0
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/dist/components/renderers/building/building-renderer.d.ts.map +1 -1
- package/dist/components/renderers/ceiling/ceiling-renderer.d.ts.map +1 -1
- package/dist/components/renderers/ceiling/ceiling-renderer.js +4 -3
- package/dist/components/renderers/door/door-renderer.d.ts.map +1 -1
- package/dist/components/renderers/door/door-renderer.js +5 -2
- package/dist/components/renderers/fence/fence-renderer.d.ts +5 -0
- package/dist/components/renderers/fence/fence-renderer.d.ts.map +1 -0
- package/dist/components/renderers/fence/fence-renderer.js +29 -0
- package/dist/components/renderers/node-renderer.d.ts.map +1 -1
- package/dist/components/renderers/node-renderer.js +2 -1
- package/dist/components/renderers/roof/roof-renderer.d.ts.map +1 -1
- package/dist/components/renderers/roof/roof-renderer.js +31 -9
- package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts.map +1 -1
- package/dist/components/renderers/roof-segment/roof-segment-renderer.js +42 -8
- package/dist/components/renderers/site/site-renderer.d.ts.map +1 -1
- package/dist/components/renderers/site/site-renderer.js +7 -1
- package/dist/components/renderers/slab/slab-renderer.d.ts.map +1 -1
- package/dist/components/renderers/slab/slab-renderer.js +37 -8
- package/dist/components/renderers/stair/stair-renderer.d.ts.map +1 -1
- package/dist/components/renderers/stair/stair-renderer.js +605 -5
- package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts.map +1 -1
- package/dist/components/renderers/stair-segment/stair-segment-renderer.js +37 -8
- package/dist/components/renderers/wall/wall-renderer.d.ts.map +1 -1
- package/dist/components/renderers/wall/wall-renderer.js +4 -9
- package/dist/components/renderers/window/window-renderer.d.ts.map +1 -1
- package/dist/components/renderers/window/window-renderer.js +5 -2
- package/dist/components/viewer/frame-limiter.d.ts +6 -0
- package/dist/components/viewer/frame-limiter.d.ts.map +1 -0
- package/dist/components/viewer/frame-limiter.js +31 -0
- package/dist/components/viewer/ground-occluder.d.ts.map +1 -1
- package/dist/components/viewer/ground-occluder.js +5 -1
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +12 -12
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +72 -28
- package/dist/components/viewer/selection-manager.d.ts.map +1 -1
- package/dist/components/viewer/selection-manager.js +21 -2
- package/dist/hooks/use-node-events.d.ts +5 -1
- package/dist/hooks/use-node-events.d.ts.map +1 -1
- package/dist/hooks/use-node-events.js +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lib/materials.d.ts +4 -1
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +178 -2
- package/dist/lib/merged-outline-node.d.ts.map +1 -1
- package/dist/lib/merged-outline-node.js +11 -4
- package/dist/store/use-viewer.d.ts +2 -2
- package/dist/systems/guide/guide-system.d.ts.map +1 -1
- package/dist/systems/guide/guide-system.js +26 -1
- package/dist/systems/roof/roof-materials.d.ts +5 -0
- package/dist/systems/roof/roof-materials.d.ts.map +1 -0
- package/dist/systems/roof/roof-materials.js +29 -0
- package/dist/systems/scan/scan-system.d.ts.map +1 -1
- package/dist/systems/scan/scan-system.js +26 -1
- package/dist/systems/stair/stair-materials.d.ts +7 -0
- package/dist/systems/stair/stair-materials.d.ts.map +1 -0
- package/dist/systems/stair/stair-materials.js +33 -0
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +39 -124
- package/dist/systems/wall/wall-materials.d.ts +16 -0
- package/dist/systems/wall/wall-materials.d.ts.map +1 -0
- package/dist/systems/wall/wall-materials.js +148 -0
- package/package.json +4 -4
|
@@ -1,20 +1,49 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useRegistry, useScene } from '@pascal-app/core';
|
|
3
|
-
import { useLayoutEffect, useMemo, useRef } from 'react';
|
|
3
|
+
import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
4
|
+
import * as THREE from 'three';
|
|
4
5
|
import { useNodeEvents } from '../../../hooks/use-node-events';
|
|
5
|
-
import {
|
|
6
|
+
import { getStraightStairSegmentBodyMaterials } from '../../../systems/stair/stair-materials';
|
|
6
7
|
export const StairSegmentRenderer = ({ node }) => {
|
|
7
8
|
const ref = useRef(null);
|
|
9
|
+
const nodes = useScene((state) => state.nodes);
|
|
8
10
|
useRegistry(node.id, 'stair-segment', ref);
|
|
9
11
|
useLayoutEffect(() => {
|
|
10
12
|
useScene.getState().markDirty(node.id);
|
|
11
13
|
}, [node.id]);
|
|
12
14
|
const handlers = useNodeEvents(node, 'stair-segment');
|
|
15
|
+
const parentNode = node.parentId ? nodes[node.parentId] : undefined;
|
|
13
16
|
const material = useMemo(() => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
return getStraightStairSegmentBodyMaterials(node, parentNode);
|
|
18
|
+
}, [
|
|
19
|
+
node.materialPreset,
|
|
20
|
+
node.material,
|
|
21
|
+
node.material?.preset,
|
|
22
|
+
node.material?.properties,
|
|
23
|
+
node.material?.texture,
|
|
24
|
+
parentNode?.materialPreset,
|
|
25
|
+
parentNode?.material,
|
|
26
|
+
parentNode?.material?.preset,
|
|
27
|
+
parentNode?.material?.properties,
|
|
28
|
+
parentNode?.material?.texture,
|
|
29
|
+
parentNode?.railingMaterialPreset,
|
|
30
|
+
parentNode?.railingMaterial,
|
|
31
|
+
parentNode?.sideMaterialPreset,
|
|
32
|
+
parentNode?.sideMaterial,
|
|
33
|
+
parentNode?.treadMaterialPreset,
|
|
34
|
+
parentNode?.treadMaterial,
|
|
35
|
+
]);
|
|
36
|
+
const placeholderGeometry = useMemo(() => {
|
|
37
|
+
const geometry = new THREE.BufferGeometry();
|
|
38
|
+
geometry.setAttribute('position', new THREE.Float32BufferAttribute([], 3));
|
|
39
|
+
geometry.addGroup(0, 0, 0);
|
|
40
|
+
geometry.addGroup(0, 0, 1);
|
|
41
|
+
return geometry;
|
|
42
|
+
}, []);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
return () => {
|
|
45
|
+
placeholderGeometry.dispose();
|
|
46
|
+
};
|
|
47
|
+
}, [placeholderGeometry]);
|
|
48
|
+
return (_jsx("mesh", { geometry: placeholderGeometry, material: material, position: node.position, ref: ref, "rotation-y": node.rotation, visible: node.visible, ...handlers }));
|
|
20
49
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wall-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/wall/wall-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAOvE,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"wall-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/wall/wall-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAOvE,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,4CAwBxD,CAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useRegistry, useScene } from '@pascal-app/core';
|
|
3
|
-
import { useLayoutEffect,
|
|
3
|
+
import { useLayoutEffect, useRef } from 'react';
|
|
4
4
|
import { useNodeEvents } from '../../../hooks/use-node-events';
|
|
5
|
-
import {
|
|
5
|
+
import { getVisibleWallMaterials } from '../../../systems/wall/wall-materials';
|
|
6
6
|
import { NodeRenderer } from '../node-renderer';
|
|
7
7
|
export const WallRenderer = ({ node }) => {
|
|
8
8
|
const ref = useRef(null);
|
|
@@ -11,11 +11,6 @@ export const WallRenderer = ({ node }) => {
|
|
|
11
11
|
useScene.getState().markDirty(node.id);
|
|
12
12
|
}, [node.id]);
|
|
13
13
|
const handlers = useNodeEvents(node, 'wall');
|
|
14
|
-
const material =
|
|
15
|
-
|
|
16
|
-
if (!mat)
|
|
17
|
-
return DEFAULT_WALL_MATERIAL;
|
|
18
|
-
return createMaterial(mat);
|
|
19
|
-
}, [node.material, node.material?.preset, node.material?.properties, node.material?.texture]);
|
|
20
|
-
return (_jsxs("mesh", { castShadow: true, material: material, receiveShadow: true, ref: ref, visible: node.visible, children: [_jsx("boxGeometry", { args: [0, 0, 0] }), _jsx("mesh", { name: "collision-mesh", visible: false, ...handlers, children: _jsx("boxGeometry", { args: [0, 0, 0] }) }), node.children.map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, childId)))] }));
|
|
14
|
+
const material = getVisibleWallMaterials(node);
|
|
15
|
+
return (_jsxs("mesh", { castShadow: true, material: material, receiveShadow: true, ref: ref, visible: node.visible, children: [_jsx("boxGeometry", { args: [0, 0, 0] }), _jsx("mesh", { name: "collision-mesh", visible: false, ...handlers, children: _jsx("boxGeometry", { args: [0, 0, 0] }) }), node.children.map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, `${node.id}:${childId}`)))] }));
|
|
21
16
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"window-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/window/window-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"window-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/window/window-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAMzE,eAAO,MAAM,cAAc,GAAI,UAAU;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,4CA8B5D,CAAA"}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useRegistry } from '@pascal-app/core';
|
|
3
|
-
import { useMemo, useRef } from 'react';
|
|
2
|
+
import { useRegistry, useScene } from '@pascal-app/core';
|
|
3
|
+
import { useLayoutEffect, useMemo, useRef } from 'react';
|
|
4
4
|
import { useNodeEvents } from '../../../hooks/use-node-events';
|
|
5
5
|
import { createMaterial, DEFAULT_WINDOW_MATERIAL } from '../../../lib/materials';
|
|
6
6
|
export const WindowRenderer = ({ node }) => {
|
|
7
7
|
const ref = useRef(null);
|
|
8
8
|
useRegistry(node.id, 'window', ref);
|
|
9
|
+
useLayoutEffect(() => {
|
|
10
|
+
useScene.getState().markDirty(node.id);
|
|
11
|
+
}, [node.id]);
|
|
9
12
|
const handlers = useNodeEvents(node, 'window');
|
|
10
13
|
const isTransient = !!node.metadata?.isTransient;
|
|
11
14
|
const material = useMemo(() => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-limiter.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/frame-limiter.tsx"],"names":[],"mappings":"AAGA,KAAK,iBAAiB,GAAG;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,CAAA;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAgC7C,CAAA;AAED,eAAe,YAAY,CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useThree } from '@react-three/fiber';
|
|
2
|
+
import { useLayoutEffect } from 'react';
|
|
3
|
+
const FrameLimiter = ({ fps = 50 }) => {
|
|
4
|
+
const { advance, set, frameloop: initFrameloop } = useThree();
|
|
5
|
+
useLayoutEffect(() => {
|
|
6
|
+
let elapsed = 0;
|
|
7
|
+
let then = 0;
|
|
8
|
+
let i = 0;
|
|
9
|
+
let raf = null;
|
|
10
|
+
const interval = 1000 / fps;
|
|
11
|
+
function tick(t) {
|
|
12
|
+
raf = requestAnimationFrame(tick);
|
|
13
|
+
elapsed = t - then;
|
|
14
|
+
if (elapsed > interval) {
|
|
15
|
+
advance(i);
|
|
16
|
+
i += elapsed / 1000 - (elapsed % interval) / 1000;
|
|
17
|
+
then = t - (elapsed % interval);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
set({ frameloop: 'never' });
|
|
21
|
+
raf = requestAnimationFrame(tick);
|
|
22
|
+
return () => {
|
|
23
|
+
if (raf) {
|
|
24
|
+
cancelAnimationFrame(raf);
|
|
25
|
+
}
|
|
26
|
+
set({ frameloop: initFrameloop });
|
|
27
|
+
};
|
|
28
|
+
}, [fps, advance, set, initFrameloop]);
|
|
29
|
+
return null;
|
|
30
|
+
};
|
|
31
|
+
export default FrameLimiter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ground-occluder.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/ground-occluder.tsx"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc,+
|
|
1
|
+
{"version":3,"file":"ground-occluder.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/ground-occluder.tsx"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc,+CAuG1B,CAAA"}
|
|
@@ -31,7 +31,11 @@ export const GroundOccluder = () => {
|
|
|
31
31
|
// reveal their footprint on the level-zero ground material.
|
|
32
32
|
const polygons = [];
|
|
33
33
|
Object.values(nodes).forEach((node) => {
|
|
34
|
-
if (!(node.type === 'slab' &&
|
|
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)) {
|
|
35
39
|
return;
|
|
36
40
|
}
|
|
37
41
|
if (Number.isFinite(lowestLevelIndex)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/index.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAkB,KAAK,kBAAkB,EAAsB,MAAM,oBAAoB,CAAA;AAEhG,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AA2CrC,OAAO,QAAQ,oBAAoB,CAAC;IAClC,UAAU,aAAc,SAAQ,kBAAkB,CAAC,OAAO,KAAK,CAAC;KAAG;CACpE;AAwCD,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,gBAAgB,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;IACvC,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,QAAA,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAsEjC,CAAA;AASD,eAAe,MAAM,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { CeilingSystem, DoorSystem, ItemSystem, RoofSystem, SlabSystem, StairSystem, WallSystem, WindowSystem, } from '@pascal-app/core';
|
|
3
|
+
import { CeilingSystem, DoorSystem, FenceSystem, ItemSystem, RoofSystem, SlabSystem, StairSystem, WallSystem, WindowSystem, } from '@pascal-app/core';
|
|
4
4
|
import { Bvh } from '@react-three/drei';
|
|
5
5
|
import { Canvas, extend, useFrame, useThree } from '@react-three/fiber';
|
|
6
6
|
import { useEffect, useMemo, useRef } from 'react';
|
|
@@ -13,6 +13,7 @@ import { ScanSystem } from '../../systems/scan/scan-system';
|
|
|
13
13
|
import { WallCutout } from '../../systems/wall/wall-cutout';
|
|
14
14
|
import { ZoneSystem } from '../../systems/zone/zone-system';
|
|
15
15
|
import { SceneRenderer } from '../renderers/scene-renderer';
|
|
16
|
+
import FrameLimiter from './frame-limiter';
|
|
16
17
|
import { Lights } from './lights';
|
|
17
18
|
import { PerfMonitor } from './perf-monitor';
|
|
18
19
|
import PostProcessing from './post-processing';
|
|
@@ -40,13 +41,6 @@ function AnimatedBackground({ isDark }) {
|
|
|
40
41
|
return null;
|
|
41
42
|
}
|
|
42
43
|
extend(THREE);
|
|
43
|
-
/**
|
|
44
|
-
* Monitors the WebGPU device for loss events and logs them.
|
|
45
|
-
* WebGPU device loss can happen when:
|
|
46
|
-
* - Tab is backgrounded and OS reclaims GPU
|
|
47
|
-
* - Driver crash or GPU reset
|
|
48
|
-
* - Browser security policy kills the context
|
|
49
|
-
*/
|
|
50
44
|
function GPUDeviceWatcher() {
|
|
51
45
|
const gl = useThree((s) => s.gl);
|
|
52
46
|
useEffect(() => {
|
|
@@ -55,7 +49,7 @@ function GPUDeviceWatcher() {
|
|
|
55
49
|
if (!device)
|
|
56
50
|
return;
|
|
57
51
|
device.lost.then((info) => {
|
|
58
|
-
console.error(`[viewer] WebGPU device lost: reason="${info.reason}", message="${info.message}". ` +
|
|
52
|
+
console.error(`[viewer] WebGPU device lost: reason="${info.reason ?? 'unknown'}", message="${info.message ?? ''}". ` +
|
|
59
53
|
'The page must be reloaded to recover the GPU context.');
|
|
60
54
|
});
|
|
61
55
|
}, [gl]);
|
|
@@ -63,18 +57,24 @@ function GPUDeviceWatcher() {
|
|
|
63
57
|
}
|
|
64
58
|
const Viewer = ({ children, selectionManager = 'default', perf = false, }) => {
|
|
65
59
|
const theme = useViewer((state) => state.theme);
|
|
66
|
-
return (_jsxs(Canvas, { camera: { position: [50, 50, 50], fov: 50 }, className: `transition-colors duration-700 ${theme === 'dark' ? 'bg-[#1f2433]' : 'bg-[#fafafa]'}`, dpr: [1, 1.5], gl: (props) => {
|
|
60
|
+
return (_jsxs(Canvas, { camera: { position: [50, 50, 50], fov: 50 }, className: `transition-colors duration-700 ${theme === 'dark' ? 'bg-[#1f2433]' : 'bg-[#fafafa]'}`, dpr: [1, 1.5], frameloop: "never", gl: async (props) => {
|
|
67
61
|
const renderer = new THREE.WebGPURenderer(props);
|
|
68
62
|
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
|
69
63
|
renderer.toneMappingExposure = 0.9;
|
|
70
|
-
//
|
|
64
|
+
// Awaiting init() is required when the browser falls back to the
|
|
65
|
+
// WebGL2 backend (Safari without the WebGPU flag, older Chrome on
|
|
66
|
+
// machines without a WebGPU device). In native WebGPU mode the
|
|
67
|
+
// init resolves almost instantly. Without this await, the first
|
|
68
|
+
// render throws "Renderer: .render() called before the backend is
|
|
69
|
+
// initialized" from the post-processing fallback path.
|
|
70
|
+
await renderer.init();
|
|
71
71
|
return renderer;
|
|
72
72
|
}, resize: {
|
|
73
73
|
debounce: 100,
|
|
74
74
|
}, shadows: {
|
|
75
75
|
type: THREE.PCFShadowMap,
|
|
76
76
|
enabled: true,
|
|
77
|
-
}, children: [_jsx(ViewerCamera, {}), _jsx(Lights, {}), _jsx(Bvh, { children: _jsx(SceneRenderer, {}) }), _jsx(LevelSystem, {}), _jsx(GuideSystem, {}), _jsx(ScanSystem, {}), _jsx(WallCutout, {}), _jsx(CeilingSystem, {}), _jsx(DoorSystem, {}), _jsx(ItemSystem, {}), _jsx(RoofSystem, {}), _jsx(SlabSystem, {}), _jsx(StairSystem, {}), _jsx(WallSystem, {}), _jsx(WindowSystem, {}), _jsx(ZoneSystem, {}), _jsx(PostProcessing, {}), _jsx(GPUDeviceWatcher, {}), _jsx(ItemLightSystem, {}), selectionManager === 'default' && _jsx(SelectionManager, {}), perf && _jsx(PerfMonitor, {}), children] }));
|
|
77
|
+
}, children: [_jsx(FrameLimiter, { fps: 50 }), _jsx(ViewerCamera, {}), _jsx(Lights, {}), _jsx(Bvh, { children: _jsx(SceneRenderer, {}) }), _jsx(LevelSystem, {}), _jsx(GuideSystem, {}), _jsx(ScanSystem, {}), _jsx(WallCutout, {}), _jsx(CeilingSystem, {}), _jsx(DoorSystem, {}), _jsx(FenceSystem, {}), _jsx(ItemSystem, {}), _jsx(RoofSystem, {}), _jsx(SlabSystem, {}), _jsx(StairSystem, {}), _jsx(WallSystem, {}), _jsx(WindowSystem, {}), _jsx(ZoneSystem, {}), _jsx(PostProcessing, {}), _jsx(GPUDeviceWatcher, {}), _jsx(ItemLightSystem, {}), selectionManager === 'default' && _jsx(SelectionManager, {}), perf && _jsx(PerfMonitor, {}), children] }));
|
|
78
78
|
};
|
|
79
79
|
const DebugRenderer = () => {
|
|
80
80
|
useFrame(({ gl, scene, camera }) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"post-processing.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/post-processing.tsx"],"names":[],"mappings":"AA4BA,eAAO,MAAM,WAAW;;;;;;;;;;;;;CAavB,CAAA;
|
|
1
|
+
{"version":3,"file":"post-processing.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/post-processing.tsx"],"names":[],"mappings":"AA4BA,eAAO,MAAM,WAAW;;;;;;;;;;;;;CAavB,CAAA;AAuBD,QAAA,MAAM,oBAAoB,YAoSzB,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
|
@@ -27,12 +27,23 @@ const MAX_PIPELINE_RETRIES = 3;
|
|
|
27
27
|
const RETRY_DELAY_MS = 500;
|
|
28
28
|
const DARK_BG = '#1f2433';
|
|
29
29
|
const LIGHT_BG = '#ffffff';
|
|
30
|
+
function sanitizeOutlineObjects(objects) {
|
|
31
|
+
let nextIndex = 0;
|
|
32
|
+
for (const object of objects) {
|
|
33
|
+
if (!(object && typeof object.id === 'number' && object.parent)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
objects[nextIndex] = object;
|
|
37
|
+
nextIndex++;
|
|
38
|
+
}
|
|
39
|
+
objects.length = nextIndex;
|
|
40
|
+
}
|
|
30
41
|
const PostProcessingPasses = () => {
|
|
31
42
|
const { gl: renderer, scene, camera } = useThree();
|
|
32
43
|
const renderPipelineRef = useRef(null);
|
|
33
44
|
const hasPipelineErrorRef = useRef(false);
|
|
34
45
|
const retryCountRef = useRef(0);
|
|
35
|
-
const
|
|
46
|
+
const rebuildTimeoutRef = useRef(null);
|
|
36
47
|
// Background color uniform — updated every frame via lerp, read by the TSL pipeline.
|
|
37
48
|
// Initialised from the current theme so there's no flash on first render.
|
|
38
49
|
const initBg = useViewer.getState().theme === 'dark' ? DARK_BG : LIGHT_BG;
|
|
@@ -51,45 +62,60 @@ const PostProcessingPasses = () => {
|
|
|
51
62
|
// Bump this to force a pipeline rebuild (used by retry logic)
|
|
52
63
|
const [pipelineVersion, setPipelineVersion] = useState(0);
|
|
53
64
|
const requestPipelineRebuild = useCallback(() => {
|
|
65
|
+
if (rebuildTimeoutRef.current !== null) {
|
|
66
|
+
clearTimeout(rebuildTimeoutRef.current);
|
|
67
|
+
rebuildTimeoutRef.current = null;
|
|
68
|
+
}
|
|
54
69
|
setPipelineVersion((v) => v + 1);
|
|
55
70
|
}, []);
|
|
56
|
-
//
|
|
71
|
+
// Reset retry state when project changes
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
// Intentionally touch projectId so the effect reruns on project switches.
|
|
74
|
+
void projectId;
|
|
75
|
+
retryCountRef.current = 0;
|
|
76
|
+
if (rebuildTimeoutRef.current !== null) {
|
|
77
|
+
clearTimeout(rebuildTimeoutRef.current);
|
|
78
|
+
rebuildTimeoutRef.current = null;
|
|
79
|
+
}
|
|
80
|
+
}, [projectId]);
|
|
57
81
|
useEffect(() => {
|
|
58
|
-
let mounted = true;
|
|
59
|
-
const initRenderer = async () => {
|
|
60
|
-
try {
|
|
61
|
-
if (renderer && renderer.init) {
|
|
62
|
-
await renderer.init();
|
|
63
|
-
}
|
|
64
|
-
if (mounted) {
|
|
65
|
-
setIsInitialized(true);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
console.error('[viewer] Failed to initialize renderer for post-processing.', error);
|
|
70
|
-
if (mounted) {
|
|
71
|
-
setIsInitialized(false);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
initRenderer();
|
|
76
82
|
return () => {
|
|
77
|
-
|
|
83
|
+
if (rebuildTimeoutRef.current !== null) {
|
|
84
|
+
clearTimeout(rebuildTimeoutRef.current);
|
|
85
|
+
rebuildTimeoutRef.current = null;
|
|
86
|
+
}
|
|
78
87
|
};
|
|
79
|
-
}, [renderer]);
|
|
80
|
-
// Reset retry count when project changes
|
|
81
|
-
useEffect(() => {
|
|
82
|
-
retryCountRef.current = 0;
|
|
83
88
|
}, []);
|
|
84
89
|
// Build / rebuild the post-processing pipeline
|
|
85
90
|
useEffect(() => {
|
|
86
|
-
|
|
91
|
+
// Intentionally touch these so React/biome treat project switches and retry bumps
|
|
92
|
+
// as explicit rebuild triggers instead of accidental extra dependencies.
|
|
93
|
+
void projectId;
|
|
94
|
+
void pipelineVersion;
|
|
95
|
+
if (!(renderer && scene && camera)) {
|
|
87
96
|
return;
|
|
88
97
|
}
|
|
89
98
|
hasPipelineErrorRef.current = false;
|
|
99
|
+
// WebGPU availability check: SSGI, denoise, and RenderPipeline are all
|
|
100
|
+
// WebGPU-only APIs. When the browser falls back to WebGL2 (no
|
|
101
|
+
// `navigator.gpu`, or the device couldn't be created), building the
|
|
102
|
+
// pipeline either throws silently or produces a broken output where
|
|
103
|
+
// the scene renders for a few frames and then goes black as the retry
|
|
104
|
+
// loop fights the direct-render fallback path. Short-circuit here so
|
|
105
|
+
// `useFrame` uses the direct `renderer.render(scene, camera)` path
|
|
106
|
+
// exclusively and never attempts the TSL pipeline.
|
|
107
|
+
const hasWebGPU = typeof navigator !== 'undefined' && 'gpu' in navigator;
|
|
108
|
+
if (!hasWebGPU) {
|
|
109
|
+
console.warn('[viewer] WebGPU unavailable — rendering without post-processing (SSGI, outlines, denoise).');
|
|
110
|
+
hasPipelineErrorRef.current = true;
|
|
111
|
+
renderPipelineRef.current = null;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
90
114
|
// Clear outliner arrays synchronously to prevent stale Object3D refs
|
|
91
115
|
// from the previous project leaking into the new pipeline's outline passes.
|
|
92
116
|
const outliner = useViewer.getState().outliner;
|
|
117
|
+
sanitizeOutlineObjects(outliner.selectedObjects);
|
|
118
|
+
sanitizeOutlineObjects(outliner.hoveredObjects);
|
|
93
119
|
outliner.selectedObjects.length = 0;
|
|
94
120
|
outliner.hoveredObjects.length = 0;
|
|
95
121
|
try {
|
|
@@ -179,6 +205,7 @@ const PostProcessingPasses = () => {
|
|
|
179
205
|
const renderPipeline = new RenderPipeline(renderer);
|
|
180
206
|
renderPipeline.outputNode = finalOutput;
|
|
181
207
|
renderPipelineRef.current = renderPipeline;
|
|
208
|
+
retryCountRef.current = 0;
|
|
182
209
|
}
|
|
183
210
|
catch (error) {
|
|
184
211
|
hasPipelineErrorRef.current = true;
|
|
@@ -194,13 +221,27 @@ const PostProcessingPasses = () => {
|
|
|
194
221
|
}
|
|
195
222
|
renderPipelineRef.current = null;
|
|
196
223
|
};
|
|
197
|
-
}, [renderer, scene, camera, hoverHighlightMode,
|
|
224
|
+
}, [renderer, scene, camera, hoverHighlightMode, zoneLayers, projectId, pipelineVersion]);
|
|
198
225
|
useFrame((_, delta) => {
|
|
199
226
|
// Animate background colour toward the current theme target (same lerp as AnimatedBackground)
|
|
200
227
|
bgTarget.current.set(useViewer.getState().theme === 'dark' ? DARK_BG : LIGHT_BG);
|
|
201
228
|
bgCurrent.current.lerp(bgTarget.current, Math.min(delta, 0.1) * 4);
|
|
202
229
|
bgUniform.current.value.copy(bgCurrent.current);
|
|
230
|
+
const outliner = useViewer.getState().outliner;
|
|
231
|
+
sanitizeOutlineObjects(outliner.selectedObjects);
|
|
232
|
+
sanitizeOutlineObjects(outliner.hoveredObjects);
|
|
203
233
|
if (hasPipelineErrorRef.current || !renderPipelineRef.current) {
|
|
234
|
+
try {
|
|
235
|
+
if (renderer.setClearAlpha) {
|
|
236
|
+
;
|
|
237
|
+
renderer.setClearAlpha(1);
|
|
238
|
+
}
|
|
239
|
+
;
|
|
240
|
+
renderer.render(scene, camera);
|
|
241
|
+
}
|
|
242
|
+
catch (fallbackError) {
|
|
243
|
+
console.error('[viewer] Fallback render failed.', fallbackError);
|
|
244
|
+
}
|
|
204
245
|
return;
|
|
205
246
|
}
|
|
206
247
|
try {
|
|
@@ -221,7 +262,10 @@ const PostProcessingPasses = () => {
|
|
|
221
262
|
// Auto-retry: schedule a pipeline rebuild if we haven't exceeded the retry limit
|
|
222
263
|
retryCountRef.current++;
|
|
223
264
|
console.warn(`[viewer] Scheduling post-processing rebuild (attempt ${retryCountRef.current}/${MAX_PIPELINE_RETRIES})`);
|
|
224
|
-
|
|
265
|
+
if (rebuildTimeoutRef.current !== null) {
|
|
266
|
+
clearTimeout(rebuildTimeoutRef.current);
|
|
267
|
+
}
|
|
268
|
+
rebuildTimeoutRef.current = setTimeout(requestPipelineRebuild, RETRY_DELAY_MS);
|
|
225
269
|
}
|
|
226
270
|
else {
|
|
227
271
|
console.error('[viewer] Post-processing retries exhausted. Rendering without post FX for this session.');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection-manager.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/selection-manager.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"selection-manager.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/selection-manager.tsx"],"names":[],"mappings":"AAiRA,eAAO,MAAM,gBAAgB,+CA2E5B,CAAA"}
|
|
@@ -88,6 +88,12 @@ const isNodeInZone = (node, levelId, zoneId) => {
|
|
|
88
88
|
const endIn = pointInPolygonWithTolerance(wall.end[0], wall.end[1], zone.polygon);
|
|
89
89
|
return startIn || endIn;
|
|
90
90
|
}
|
|
91
|
+
if (node.type === 'fence') {
|
|
92
|
+
const fence = node;
|
|
93
|
+
const startIn = pointInPolygonWithTolerance(fence.start[0], fence.start[1], zone.polygon);
|
|
94
|
+
const endIn = pointInPolygonWithTolerance(fence.end[0], fence.end[1], zone.polygon);
|
|
95
|
+
return startIn || endIn;
|
|
96
|
+
}
|
|
91
97
|
if (node.type === 'slab' || node.type === 'ceiling') {
|
|
92
98
|
const poly = node.polygon;
|
|
93
99
|
if (!poly?.length)
|
|
@@ -164,7 +170,7 @@ const getStrategy = () => {
|
|
|
164
170
|
}
|
|
165
171
|
// Zone selected -> can select/hover contents (walls, items, slabs, ceilings, roofs, windows, doors)
|
|
166
172
|
return {
|
|
167
|
-
types: ['wall', 'item', 'slab', 'ceiling', 'roof', 'roof-segment', 'window', 'door'],
|
|
173
|
+
types: ['wall', 'fence', 'item', 'slab', 'ceiling', 'roof', 'roof-segment', 'window', 'door'],
|
|
168
174
|
handleClick: (node, nativeEvent) => {
|
|
169
175
|
let nodeToSelect = node;
|
|
170
176
|
if (node.type === 'roof-segment' && node.parentId) {
|
|
@@ -191,6 +197,7 @@ const getStrategy = () => {
|
|
|
191
197
|
isValid: (node) => {
|
|
192
198
|
const validTypes = [
|
|
193
199
|
'wall',
|
|
200
|
+
'fence',
|
|
194
201
|
'item',
|
|
195
202
|
'slab',
|
|
196
203
|
'ceiling',
|
|
@@ -215,6 +222,10 @@ export const SelectionManager = () => {
|
|
|
215
222
|
return;
|
|
216
223
|
if (strategy.isValid(event.node)) {
|
|
217
224
|
event.stopPropagation();
|
|
225
|
+
if (event.node.type === 'slab') {
|
|
226
|
+
useViewer.setState({ hoveredId: null });
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
218
229
|
useViewer.setState({ hoveredId: event.node.id });
|
|
219
230
|
}
|
|
220
231
|
};
|
|
@@ -245,6 +256,7 @@ export const SelectionManager = () => {
|
|
|
245
256
|
'level',
|
|
246
257
|
'zone',
|
|
247
258
|
'wall',
|
|
259
|
+
'fence',
|
|
248
260
|
'item',
|
|
249
261
|
'slab',
|
|
250
262
|
'ceiling',
|
|
@@ -303,10 +315,14 @@ const OutlinerSync = () => {
|
|
|
303
315
|
const selection = useViewer((s) => s.selection);
|
|
304
316
|
const hoveredId = useViewer((s) => s.hoveredId);
|
|
305
317
|
const outliner = useViewer((s) => s.outliner);
|
|
318
|
+
const nodes = useScene((s) => s.nodes);
|
|
306
319
|
useEffect(() => {
|
|
307
320
|
// Sync selected objects
|
|
308
321
|
outliner.selectedObjects.length = 0;
|
|
309
322
|
for (const id of selection.selectedIds) {
|
|
323
|
+
const node = nodes[id];
|
|
324
|
+
if (node?.type === 'slab')
|
|
325
|
+
continue;
|
|
310
326
|
const obj = sceneRegistry.nodes.get(id);
|
|
311
327
|
if (obj)
|
|
312
328
|
outliner.selectedObjects.push(obj);
|
|
@@ -314,10 +330,13 @@ const OutlinerSync = () => {
|
|
|
314
330
|
// Sync hovered objects
|
|
315
331
|
outliner.hoveredObjects.length = 0;
|
|
316
332
|
if (hoveredId) {
|
|
333
|
+
const hoveredNode = nodes[hoveredId];
|
|
334
|
+
if (hoveredNode?.type === 'slab')
|
|
335
|
+
return;
|
|
317
336
|
const obj = sceneRegistry.nodes.get(hoveredId);
|
|
318
337
|
if (obj)
|
|
319
338
|
outliner.hoveredObjects.push(obj);
|
|
320
339
|
}
|
|
321
|
-
}, [selection, hoveredId, outliner]);
|
|
340
|
+
}, [selection, hoveredId, outliner, nodes]);
|
|
322
341
|
return null;
|
|
323
342
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type BuildingEvent, type BuildingNode, type CeilingEvent, type CeilingNode, type DoorEvent, type DoorNode, type ItemEvent, type ItemNode, type LevelEvent, type LevelNode, type RoofEvent, type RoofNode, type RoofSegmentEvent, type RoofSegmentNode, type SiteEvent, type SiteNode, type SlabEvent, type SlabNode, type StairEvent, type StairNode, type StairSegmentEvent, type StairSegmentNode, type WallEvent, type WallNode, type WindowEvent, type WindowNode, type ZoneEvent, type ZoneNode } from '@pascal-app/core';
|
|
1
|
+
import { type BuildingEvent, type BuildingNode, type CeilingEvent, type CeilingNode, type DoorEvent, type DoorNode, type FenceEvent, type FenceNode, type ItemEvent, type ItemNode, type LevelEvent, type LevelNode, type RoofEvent, type RoofNode, type RoofSegmentEvent, type RoofSegmentNode, type SiteEvent, type SiteNode, type SlabEvent, type SlabNode, type StairEvent, type StairNode, type StairSegmentEvent, type StairSegmentNode, type WallEvent, type WallNode, type WindowEvent, type WindowNode, type ZoneEvent, type ZoneNode } from '@pascal-app/core';
|
|
2
2
|
import type { ThreeEvent } from '@react-three/fiber';
|
|
3
3
|
type NodeConfig = {
|
|
4
4
|
site: {
|
|
@@ -13,6 +13,10 @@ type NodeConfig = {
|
|
|
13
13
|
node: WallNode;
|
|
14
14
|
event: WallEvent;
|
|
15
15
|
};
|
|
16
|
+
fence: {
|
|
17
|
+
node: FenceNode;
|
|
18
|
+
event: FenceEvent;
|
|
19
|
+
};
|
|
16
20
|
building: {
|
|
17
21
|
node: BuildingNode;
|
|
18
22
|
event: BuildingEvent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-node-events.d.ts","sourceRoot":"","sources":["../../src/hooks/use-node-events.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,QAAQ,EAGb,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAGpD,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,QAAQ,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAE,CAAA;IACtD,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAA;IAC7C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,OAAO,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE,CAAA;IACnD,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,cAAc,EAAE;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,KAAK,EAAE,gBAAgB,CAAA;KAAE,CAAA;IAClE,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAA;IAC7C,eAAe,EAAE;QAAE,IAAI,EAAE,gBAAgB,CAAC;QAAC,KAAK,EAAE,iBAAiB,CAAA;KAAE,CAAA;IACrE,MAAM,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,CAAA;IAChD,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;CAC3C,CAAA;AAED,KAAK,QAAQ,GAAG,MAAM,UAAU,CAAA;AAEhC,wBAAgB,aAAa,CAAC,CAAC,SAAS,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"use-node-events.d.ts","sourceRoot":"","sources":["../../src/hooks/use-node-events.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,8 @@ export function useNodeEvents(node, type) {
|
|
|
9
9
|
position: [e.point.x, e.point.y, e.point.z],
|
|
10
10
|
localPosition: [localPoint.x, localPoint.y, localPoint.z],
|
|
11
11
|
normal: e.face ? [e.face.normal.x, e.face.normal.y, e.face.normal.z] : undefined,
|
|
12
|
+
faceIndex: e.faceIndex ?? undefined,
|
|
13
|
+
object: e.object,
|
|
12
14
|
stopPropagation: () => e.stopPropagation(),
|
|
13
15
|
nativeEvent: e,
|
|
14
16
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { default as Viewer } from './components/viewer';
|
|
2
|
+
export { SSGI_PARAMS } from './components/viewer/post-processing';
|
|
2
3
|
export { WalkthroughControls } from './components/viewer/walkthrough-controls';
|
|
3
4
|
export { ASSETS_CDN_URL, resolveAssetUrl, resolveCdnUrl } from './lib/asset-url';
|
|
4
5
|
export { SCENE_LAYER, ZONE_LAYER } from './lib/layers';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAChF,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,GAChB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAA;AAC5E,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAChF,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,GAChB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAA;AAC5E,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { default as Viewer } from './components/viewer';
|
|
2
|
+
export { SSGI_PARAMS } from './components/viewer/post-processing';
|
|
2
3
|
export { WalkthroughControls } from './components/viewer/walkthrough-controls';
|
|
3
4
|
export { ASSETS_CDN_URL, resolveAssetUrl, resolveCdnUrl } from './lib/asset-url';
|
|
4
5
|
export { SCENE_LAYER, ZONE_LAYER } from './lib/layers';
|
package/dist/lib/materials.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { type MaterialSchema } from '@pascal-app/core';
|
|
1
|
+
import { type MaterialPresetPayload, type MaterialSchema } from '@pascal-app/core';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
|
+
export declare function applyMaterialPresetToMaterials(materialInput: THREE.Material | THREE.Material[], preset: MaterialPresetPayload | null | undefined): void;
|
|
4
|
+
export declare function createMaterialFromPreset(preset: MaterialPresetPayload): THREE.MeshStandardMaterial;
|
|
5
|
+
export declare function createMaterialFromPresetRef(materialPreset?: string): THREE.MeshStandardMaterial | null;
|
|
3
6
|
export declare function createMaterial(material?: MaterialSchema): THREE.MeshStandardMaterial;
|
|
4
7
|
export declare function createDefaultMaterial(color?: string, roughness?: number): THREE.MeshStandardMaterial;
|
|
5
8
|
export declare const DEFAULT_WALL_MATERIAL: THREE.MeshStandardMaterial;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../src/lib/materials.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../src/lib/materials.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,qBAAqB,EAE1B,KAAK,cAAc,EAGpB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA2M9B,wBAAgB,8BAA8B,CAC5C,aAAa,EAAE,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,EAAE,EAChD,MAAM,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,QAcjD;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,qBAAqB,GAAG,KAAK,CAAC,oBAAoB,CAWlG;AAED,wBAAgB,2BAA2B,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,oBAAoB,GAAG,IAAI,CAItG;AAED,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,cAAc,GAAG,KAAK,CAAC,oBAAoB,CAsBpF;AAED,wBAAgB,qBAAqB,CACnC,KAAK,SAAY,EACjB,SAAS,SAAM,GACd,KAAK,CAAC,oBAAoB,CAO5B;AAED,eAAO,MAAM,qBAAqB,4BAAwC,CAAA;AAC1E,eAAO,MAAM,qBAAqB,4BAAwC,CAAA;AAC1E,eAAO,MAAM,qBAAqB,4BAAwC,CAAA;AAC1E,eAAO,MAAM,uBAAuB,4BAOlC,CAAA;AACF,eAAO,MAAM,wBAAwB,4BAAyC,CAAA;AAC9E,eAAO,MAAM,qBAAqB,4BAAyC,CAAA;AAC3E,eAAO,MAAM,sBAAsB,4BAAwC,CAAA;AAE3E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAE9D;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAWzC"}
|