@pascal-app/viewer 0.5.1 → 0.7.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/error-boundary.d.ts +7 -3
- package/dist/components/error-boundary.d.ts.map +1 -1
- package/dist/components/error-boundary.js +3 -1
- package/dist/components/renderers/ceiling/ceiling-renderer.d.ts.map +1 -1
- package/dist/components/renderers/ceiling/ceiling-renderer.js +21 -4
- package/dist/components/renderers/column/column-renderer.d.ts +5 -0
- package/dist/components/renderers/column/column-renderer.d.ts.map +1 -0
- package/dist/components/renderers/column/column-renderer.js +594 -0
- package/dist/components/renderers/door/door-renderer.d.ts.map +1 -1
- package/dist/components/renderers/door/door-renderer.js +8 -10
- package/dist/components/renderers/fence/fence-renderer.d.ts.map +1 -1
- package/dist/components/renderers/fence/fence-renderer.js +16 -2
- package/dist/components/renderers/guide/guide-renderer.js +1 -1
- package/dist/components/renderers/item/item-renderer.d.ts.map +1 -1
- package/dist/components/renderers/item/item-renderer.js +2 -1
- package/dist/components/renderers/node-renderer.d.ts.map +1 -1
- package/dist/components/renderers/node-renderer.js +3 -1
- package/dist/components/renderers/roof/roof-renderer.d.ts.map +1 -1
- package/dist/components/renderers/roof/roof-renderer.js +19 -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 +27 -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 +48 -7
- package/dist/components/renderers/spawn/spawn-renderer.d.ts +5 -0
- package/dist/components/renderers/spawn/spawn-renderer.d.ts.map +1 -0
- package/dist/components/renderers/spawn/spawn-renderer.js +32 -0
- package/dist/components/renderers/stair/stair-renderer.d.ts.map +1 -1
- package/dist/components/renderers/stair/stair-renderer.js +154 -39
- package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts.map +1 -1
- package/dist/components/renderers/stair-segment/stair-segment-renderer.js +22 -10
- 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 +2 -0
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +90 -20
- package/dist/components/viewer/post-processing.d.ts +13 -1
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +98 -44
- package/dist/components/viewer/selection-manager.d.ts.map +1 -1
- package/dist/components/viewer/selection-manager.js +31 -3
- package/dist/hooks/use-node-events.d.ts +9 -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 +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/lib/materials.d.ts +7 -1
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +192 -2
- package/dist/lib/merged-outline-node.d.ts +2 -0
- package/dist/lib/merged-outline-node.d.ts.map +1 -1
- package/dist/lib/merged-outline-node.js +36 -9
- package/dist/store/use-viewer.d.ts +6 -6
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +2 -2
- package/dist/systems/ceiling/ceiling-system.d.ts +8 -0
- package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -0
- package/dist/systems/ceiling/ceiling-system.js +91 -0
- package/dist/systems/column/column-geometry.d.ts +22 -0
- package/dist/systems/column/column-geometry.d.ts.map +1 -0
- package/dist/systems/column/column-geometry.js +108 -0
- package/dist/systems/door/door-animation-system.d.ts +2 -0
- package/dist/systems/door/door-animation-system.d.ts.map +1 -0
- package/dist/systems/door/door-animation-system.js +53 -0
- package/dist/systems/door/door-system.d.ts +2 -0
- package/dist/systems/door/door-system.d.ts.map +1 -0
- package/dist/systems/door/door-system.js +867 -0
- package/dist/systems/fence/fence-system.d.ts +2 -0
- package/dist/systems/fence/fence-system.d.ts.map +1 -0
- package/dist/systems/fence/fence-system.js +185 -0
- package/dist/systems/item/item-system.d.ts +2 -0
- package/dist/systems/item/item-system.d.ts.map +1 -0
- package/dist/systems/item/item-system.js +44 -0
- package/dist/systems/item-mesh-metadata/compute-item-mesh-metadata.d.ts +14 -0
- package/dist/systems/item-mesh-metadata/compute-item-mesh-metadata.d.ts.map +1 -0
- package/dist/systems/item-mesh-metadata/compute-item-mesh-metadata.js +155 -0
- package/dist/systems/item-mesh-metadata/item-mesh-metadata-system.d.ts +6 -0
- package/dist/systems/item-mesh-metadata/item-mesh-metadata-system.d.ts.map +1 -0
- package/dist/systems/item-mesh-metadata/item-mesh-metadata-system.js +75 -0
- package/dist/systems/item-mesh-metadata/sync-request.d.ts +7 -0
- package/dist/systems/item-mesh-metadata/sync-request.d.ts.map +1 -0
- package/dist/systems/item-mesh-metadata/sync-request.js +25 -0
- 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 +46 -0
- package/dist/systems/roof/roof-system.d.ts +16 -0
- package/dist/systems/roof/roof-system.d.ts.map +1 -0
- package/dist/systems/roof/roof-system.js +797 -0
- package/dist/systems/slab/slab-system.d.ts +8 -0
- package/dist/systems/slab/slab-system.d.ts.map +1 -0
- package/dist/systems/slab/slab-system.js +155 -0
- 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 +56 -0
- package/dist/systems/stair/stair-system.d.ts +2 -0
- package/dist/systems/stair/stair-system.d.ts.map +1 -0
- package/dist/systems/stair/stair-system.js +772 -0
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +4 -123
- 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/dist/systems/wall/wall-system.d.ts +11 -0
- package/dist/systems/wall/wall-system.d.ts.map +1 -0
- package/dist/systems/wall/wall-system.js +592 -0
- package/dist/systems/window/window-animation-system.d.ts +2 -0
- package/dist/systems/window/window-animation-system.d.ts.map +1 -0
- package/dist/systems/window/window-animation-system.js +135 -0
- package/dist/systems/window/window-system.d.ts +12 -0
- package/dist/systems/window/window-system.d.ts.map +1 -0
- package/dist/systems/window/window-system.js +1430 -0
- package/package.json +6 -4
|
@@ -1,21 +1,33 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { CeilingSystem, DoorSystem, FenceSystem, ItemSystem, RoofSystem, SlabSystem, StairSystem, WallSystem, WindowSystem, } from '@pascal-app/core';
|
|
4
3
|
import { Bvh } from '@react-three/drei';
|
|
5
4
|
import { Canvas, extend, useFrame, useThree } from '@react-three/fiber';
|
|
6
5
|
import { useEffect, useMemo, useRef } from 'react';
|
|
7
6
|
import * as THREE from 'three/webgpu';
|
|
8
7
|
import useViewer from '../../store/use-viewer';
|
|
8
|
+
import { CeilingSystem } from '../../systems/ceiling/ceiling-system';
|
|
9
|
+
import { DoorAnimationSystem } from '../../systems/door/door-animation-system';
|
|
10
|
+
import { DoorSystem } from '../../systems/door/door-system';
|
|
11
|
+
import { FenceSystem } from '../../systems/fence/fence-system';
|
|
9
12
|
import { GuideSystem } from '../../systems/guide/guide-system';
|
|
13
|
+
import { ItemSystem } from '../../systems/item/item-system';
|
|
10
14
|
import { ItemLightSystem } from '../../systems/item-light/item-light-system';
|
|
11
15
|
import { LevelSystem } from '../../systems/level/level-system';
|
|
16
|
+
import { RoofSystem } from '../../systems/roof/roof-system';
|
|
12
17
|
import { ScanSystem } from '../../systems/scan/scan-system';
|
|
18
|
+
import { SlabSystem } from '../../systems/slab/slab-system';
|
|
19
|
+
import { StairSystem } from '../../systems/stair/stair-system';
|
|
13
20
|
import { WallCutout } from '../../systems/wall/wall-cutout';
|
|
21
|
+
import { WallSystem } from '../../systems/wall/wall-system';
|
|
22
|
+
import { WindowAnimationSystem } from '../../systems/window/window-animation-system';
|
|
23
|
+
import { WindowSystem } from '../../systems/window/window-system';
|
|
14
24
|
import { ZoneSystem } from '../../systems/zone/zone-system';
|
|
25
|
+
import { ErrorBoundary } from '../error-boundary';
|
|
15
26
|
import { SceneRenderer } from '../renderers/scene-renderer';
|
|
27
|
+
import FrameLimiter from './frame-limiter';
|
|
16
28
|
import { Lights } from './lights';
|
|
17
29
|
import { PerfMonitor } from './perf-monitor';
|
|
18
|
-
import PostProcessing from './post-processing';
|
|
30
|
+
import PostProcessing, { DEFAULT_HOVER_STYLES } from './post-processing';
|
|
19
31
|
import { SelectionManager } from './selection-manager';
|
|
20
32
|
import { ViewerCamera } from './viewer-camera';
|
|
21
33
|
function AnimatedBackground({ isDark }) {
|
|
@@ -40,41 +52,99 @@ function AnimatedBackground({ isDark }) {
|
|
|
40
52
|
return null;
|
|
41
53
|
}
|
|
42
54
|
extend(THREE);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
// R3F's <Canvas> useLayoutEffect has no deps, so any re-render (theme switch,
|
|
56
|
+
// parent re-render, StrictMode double-mount) re-invokes `configure()`. With a
|
|
57
|
+
// sync `gl` factory that's harmless — the renderer is created once and reused.
|
|
58
|
+
// With an async factory (WebGPURenderer needs `await init()`), two configure
|
|
59
|
+
// calls can race: both see `state.gl == null` and both create a renderer. The
|
|
60
|
+
// first to resolve gets `setSize`/`setDpr` called on it; the second overwrites
|
|
61
|
+
// `state.gl` but R3F's store already holds the new size/dpr, so the new
|
|
62
|
+
// renderer is never resized and stays at the canvas's 300×150 default.
|
|
63
|
+
//
|
|
64
|
+
// Caching by canvas guarantees both branches return the same instance, so
|
|
65
|
+
// "duplicate" configure calls become no-ops on an already-sized renderer.
|
|
66
|
+
// We cache the in-flight Promise (not just the resolved renderer) so two
|
|
67
|
+
// concurrent configure() calls await the same init instead of creating two
|
|
68
|
+
// renderers in parallel and only caching the second.
|
|
69
|
+
const WEBGPU_RENDERER_CACHE = new WeakMap();
|
|
50
70
|
function GPUDeviceWatcher() {
|
|
51
71
|
const gl = useThree((s) => s.gl);
|
|
52
72
|
useEffect(() => {
|
|
53
73
|
const backend = gl.backend;
|
|
54
74
|
const device = backend?.device;
|
|
55
|
-
if (!device)
|
|
75
|
+
if (!device) {
|
|
76
|
+
console.warn('[viewer] No WebGPU device on backend — running on a fallback renderer.', {
|
|
77
|
+
backend: backend?.constructor?.name ?? 'unknown',
|
|
78
|
+
rendererType: gl.constructor?.name ?? 'unknown',
|
|
79
|
+
});
|
|
56
80
|
return;
|
|
81
|
+
}
|
|
82
|
+
console.log('[viewer] WebGPU device ready', {
|
|
83
|
+
label: device.label,
|
|
84
|
+
features: device.features ? Array.from(device.features) : [],
|
|
85
|
+
});
|
|
57
86
|
device.lost.then((info) => {
|
|
58
|
-
console.error(`[viewer] WebGPU device lost: reason="${info.reason}", message="${info.message}". ` +
|
|
87
|
+
console.error(`[viewer] WebGPU device lost: reason="${info.reason ?? 'unknown'}", message="${info.message ?? ''}". ` +
|
|
59
88
|
'The page must be reloaded to recover the GPU context.');
|
|
60
89
|
});
|
|
90
|
+
// Uncaptured errors are normally silent (only console-warned by Chrome at
|
|
91
|
+
// best). Pipe them to console.error so silent mobile crashes show up.
|
|
92
|
+
const onUncapturedError = (event) => {
|
|
93
|
+
console.error('[viewer] WebGPU uncaptured error:', event?.error?.message, event?.error);
|
|
94
|
+
};
|
|
95
|
+
device.addEventListener?.('uncapturederror', onUncapturedError);
|
|
96
|
+
return () => {
|
|
97
|
+
device.removeEventListener?.('uncapturederror', onUncapturedError);
|
|
98
|
+
};
|
|
61
99
|
}, [gl]);
|
|
62
100
|
return null;
|
|
63
101
|
}
|
|
64
|
-
const Viewer = ({ children, selectionManager = 'default', perf = false, }) => {
|
|
102
|
+
const Viewer = ({ children, hoverStyles = DEFAULT_HOVER_STYLES, selectionManager = 'default', perf = false, }) => {
|
|
65
103
|
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) => {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
104
|
+
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: ((props) => {
|
|
105
|
+
const canvas = props.canvas;
|
|
106
|
+
const cached = canvas ? WEBGPU_RENDERER_CACHE.get(canvas) : undefined;
|
|
107
|
+
if (cached)
|
|
108
|
+
return cached;
|
|
109
|
+
// Surface the env we're about to ask WebGPU for — catches "no
|
|
110
|
+
// navigator.gpu" / "adapter request failed" silently failing in
|
|
111
|
+
// mobile WebViews where WebGPU is gated behind flags.
|
|
112
|
+
const hasGpu = typeof navigator !== 'undefined' && 'gpu' in navigator;
|
|
113
|
+
console.log('[viewer] Creating WebGPURenderer', {
|
|
114
|
+
hasNavigatorGPU: hasGpu,
|
|
115
|
+
ua: typeof navigator !== 'undefined' ? navigator.userAgent : 'n/a',
|
|
116
|
+
});
|
|
117
|
+
const promise = (async () => {
|
|
118
|
+
try {
|
|
119
|
+
const renderer = new THREE.WebGPURenderer(props);
|
|
120
|
+
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
|
121
|
+
renderer.toneMappingExposure = 0.9;
|
|
122
|
+
await renderer.init();
|
|
123
|
+
console.log('[viewer] WebGPURenderer ready', {
|
|
124
|
+
backend: renderer.backend?.constructor?.name,
|
|
125
|
+
isWebGPU: renderer.isWebGPURenderer === true,
|
|
126
|
+
});
|
|
127
|
+
return renderer;
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
// Drop the failed promise from the cache so a future Canvas
|
|
131
|
+
// mount on the same DOM can retry instead of inheriting the
|
|
132
|
+
// rejection forever.
|
|
133
|
+
if (canvas)
|
|
134
|
+
WEBGPU_RENDERER_CACHE.delete(canvas);
|
|
135
|
+
console.error('[viewer] WebGPURenderer init failed', err);
|
|
136
|
+
throw err;
|
|
137
|
+
}
|
|
138
|
+
})();
|
|
139
|
+
if (canvas)
|
|
140
|
+
WEBGPU_RENDERER_CACHE.set(canvas, promise);
|
|
141
|
+
return promise;
|
|
142
|
+
}), resize: {
|
|
73
143
|
debounce: 100,
|
|
74
144
|
}, shadows: {
|
|
75
145
|
type: THREE.PCFShadowMap,
|
|
76
146
|
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(FenceSystem, {}), _jsx(ItemSystem, {}), _jsx(RoofSystem, {}), _jsx(SlabSystem, {}), _jsx(StairSystem, {}), _jsx(WallSystem, {}), _jsx(WindowSystem, {}), _jsx(ZoneSystem, {}), _jsx(PostProcessing, {
|
|
147
|
+
}, children: [_jsx(FrameLimiter, { fps: 50 }), _jsx(ViewerCamera, {}), _jsx(GPUDeviceWatcher, {}), _jsxs(ErrorBoundary, { fallback: null, scope: "viewer-scene", children: [_jsx(Lights, {}), _jsx(Bvh, { children: _jsx(SceneRenderer, {}) }), _jsx(LevelSystem, {}), _jsx(GuideSystem, {}), _jsx(ScanSystem, {}), _jsx(WallCutout, {}), _jsx(CeilingSystem, {}), _jsx(DoorAnimationSystem, {}), _jsx(WindowAnimationSystem, {}), _jsx(DoorSystem, {}), _jsx(FenceSystem, {}), _jsx(ItemSystem, {}), _jsx(RoofSystem, {}), _jsx(SlabSystem, {}), _jsx(StairSystem, {}), _jsx(WallSystem, {}), _jsx(WindowSystem, {}), _jsx(ZoneSystem, {}), _jsx(PostProcessing, { hoverStyles: hoverStyles }), _jsx(ItemLightSystem, {}), selectionManager === 'default' && _jsx(SelectionManager, {}), perf && _jsx(PerfMonitor, {}), children] })] }));
|
|
78
148
|
};
|
|
79
149
|
const DebugRenderer = () => {
|
|
80
150
|
useFrame(({ gl, scene, camera }) => {
|
|
@@ -12,6 +12,18 @@ export declare const SSGI_PARAMS: {
|
|
|
12
12
|
useScreenSpaceSampling: boolean;
|
|
13
13
|
useTemporalFiltering: boolean;
|
|
14
14
|
};
|
|
15
|
-
|
|
15
|
+
export type HoverStyle = {
|
|
16
|
+
visibleColor: number;
|
|
17
|
+
hiddenColor: number;
|
|
18
|
+
strength: number;
|
|
19
|
+
pulse: boolean;
|
|
20
|
+
};
|
|
21
|
+
export type HoverStyles = {
|
|
22
|
+
default: HoverStyle;
|
|
23
|
+
} & Record<string, HoverStyle>;
|
|
24
|
+
export declare const DEFAULT_HOVER_STYLES: HoverStyles;
|
|
25
|
+
declare const PostProcessingPasses: ({ hoverStyles, }: {
|
|
26
|
+
hoverStyles?: HoverStyles;
|
|
27
|
+
}) => null;
|
|
16
28
|
export default PostProcessingPasses;
|
|
17
29
|
//# sourceMappingURL=post-processing.d.ts.map
|
|
@@ -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;AAQD,QAAA,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"post-processing.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/post-processing.tsx"],"names":[],"mappings":"AA4BA,eAAO,MAAM,WAAW;;;;;;;;;;;;;CAavB,CAAA;AAQD,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,kBAE3B;IACD,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B,SAkVA,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
|
@@ -27,13 +27,32 @@ 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
|
-
const
|
|
31
|
-
|
|
30
|
+
const DEFAULT_HOVER_STYLE = {
|
|
31
|
+
visibleColor: 0x00_aa_ff,
|
|
32
|
+
hiddenColor: 0xf3_ff_47,
|
|
33
|
+
strength: 5,
|
|
34
|
+
pulse: true,
|
|
35
|
+
};
|
|
36
|
+
export const DEFAULT_HOVER_STYLES = {
|
|
37
|
+
default: DEFAULT_HOVER_STYLE,
|
|
38
|
+
};
|
|
39
|
+
function sanitizeOutlineObjects(objects) {
|
|
40
|
+
let nextIndex = 0;
|
|
41
|
+
for (const object of objects) {
|
|
42
|
+
if (!(object && typeof object.id === 'number' && object.parent)) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
objects[nextIndex] = object;
|
|
46
|
+
nextIndex++;
|
|
47
|
+
}
|
|
48
|
+
objects.length = nextIndex;
|
|
49
|
+
}
|
|
50
|
+
const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, }) => {
|
|
51
|
+
const { gl: renderer, invalidate, scene, camera } = useThree();
|
|
32
52
|
const renderPipelineRef = useRef(null);
|
|
33
53
|
const hasPipelineErrorRef = useRef(false);
|
|
34
54
|
const retryCountRef = useRef(0);
|
|
35
55
|
const rebuildTimeoutRef = useRef(null);
|
|
36
|
-
const [isInitialized, setIsInitialized] = useState(false);
|
|
37
56
|
// Background color uniform — updated every frame via lerp, read by the TSL pipeline.
|
|
38
57
|
// Initialised from the current theme so there's no flash on first render.
|
|
39
58
|
const initBg = useViewer.getState().theme === 'dark' ? DARK_BG : LIGHT_BG;
|
|
@@ -47,6 +66,10 @@ const PostProcessingPasses = () => {
|
|
|
47
66
|
return l;
|
|
48
67
|
}, []);
|
|
49
68
|
const hoverHighlightMode = useViewer((s) => s.hoverHighlightMode);
|
|
69
|
+
const hoverVisibleColor = useMemo(() => uniform(new Color(DEFAULT_HOVER_STYLE.visibleColor)), []);
|
|
70
|
+
const hoverHiddenColor = useMemo(() => uniform(new Color(DEFAULT_HOVER_STYLE.hiddenColor)), []);
|
|
71
|
+
const hoverStrength = useMemo(() => uniform(DEFAULT_HOVER_STYLE.strength), []);
|
|
72
|
+
const hoverPulseMix = useMemo(() => uniform(DEFAULT_HOVER_STYLE.pulse ? 0 : 1), []);
|
|
50
73
|
// Subscribe to projectId so the pipeline rebuilds on project switch
|
|
51
74
|
const projectId = useViewer((s) => s.projectId);
|
|
52
75
|
// Bump this to force a pipeline rebuild (used by retry logic)
|
|
@@ -58,30 +81,6 @@ const PostProcessingPasses = () => {
|
|
|
58
81
|
}
|
|
59
82
|
setPipelineVersion((v) => v + 1);
|
|
60
83
|
}, []);
|
|
61
|
-
// Renderer initialization
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
let mounted = true;
|
|
64
|
-
const initRenderer = async () => {
|
|
65
|
-
try {
|
|
66
|
-
if (renderer && renderer.init) {
|
|
67
|
-
await renderer.init();
|
|
68
|
-
}
|
|
69
|
-
if (mounted) {
|
|
70
|
-
setIsInitialized(true);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
console.error('[viewer] Failed to initialize renderer for post-processing.', error);
|
|
75
|
-
if (mounted) {
|
|
76
|
-
setIsInitialized(false);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
initRenderer();
|
|
81
|
-
return () => {
|
|
82
|
-
mounted = false;
|
|
83
|
-
};
|
|
84
|
-
}, [renderer]);
|
|
85
84
|
// Reset retry state when project changes
|
|
86
85
|
useEffect(() => {
|
|
87
86
|
// Intentionally touch projectId so the effect reruns on project switches.
|
|
@@ -100,19 +99,64 @@ const PostProcessingPasses = () => {
|
|
|
100
99
|
}
|
|
101
100
|
};
|
|
102
101
|
}, []);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const style = hoverStyles[hoverHighlightMode] ?? hoverStyles.default;
|
|
104
|
+
hoverVisibleColor.value.setHex(style.visibleColor);
|
|
105
|
+
hoverHiddenColor.value.setHex(style.hiddenColor);
|
|
106
|
+
hoverStrength.value = style.strength;
|
|
107
|
+
hoverPulseMix.value = style.pulse ? 0 : 1;
|
|
108
|
+
invalidate();
|
|
109
|
+
}, [
|
|
110
|
+
hoverHiddenColor,
|
|
111
|
+
hoverHighlightMode,
|
|
112
|
+
hoverPulseMix,
|
|
113
|
+
hoverStrength,
|
|
114
|
+
hoverStyles,
|
|
115
|
+
hoverVisibleColor,
|
|
116
|
+
invalidate,
|
|
117
|
+
]);
|
|
103
118
|
// Build / rebuild the post-processing pipeline
|
|
104
119
|
useEffect(() => {
|
|
105
120
|
// Intentionally touch these so React/biome treat project switches and retry bumps
|
|
106
121
|
// as explicit rebuild triggers instead of accidental extra dependencies.
|
|
107
122
|
void projectId;
|
|
108
123
|
void pipelineVersion;
|
|
109
|
-
if (!(renderer && scene && camera
|
|
124
|
+
if (!(renderer && scene && camera)) {
|
|
125
|
+
console.warn('[viewer/post-processing] Skipping pipeline build — missing dependency.', {
|
|
126
|
+
hasRenderer: !!renderer,
|
|
127
|
+
hasScene: !!scene,
|
|
128
|
+
hasCamera: !!camera,
|
|
129
|
+
});
|
|
110
130
|
return;
|
|
111
131
|
}
|
|
132
|
+
console.log('[viewer/post-processing] Building pipeline', {
|
|
133
|
+
version: pipelineVersion,
|
|
134
|
+
ssgi: SSGI_PARAMS.enabled,
|
|
135
|
+
hoverHighlightMode,
|
|
136
|
+
projectId,
|
|
137
|
+
rendererCtor: renderer.constructor?.name,
|
|
138
|
+
});
|
|
112
139
|
hasPipelineErrorRef.current = false;
|
|
140
|
+
// WebGPU availability check: SSGI, denoise, and RenderPipeline are all
|
|
141
|
+
// WebGPU-only APIs. When the browser falls back to WebGL2 (no
|
|
142
|
+
// `navigator.gpu`, or the device couldn't be created), building the
|
|
143
|
+
// pipeline either throws silently or produces a broken output where
|
|
144
|
+
// the scene renders for a few frames and then goes black as the retry
|
|
145
|
+
// loop fights the direct-render fallback path. Short-circuit here so
|
|
146
|
+
// `useFrame` uses the direct `renderer.render(scene, camera)` path
|
|
147
|
+
// exclusively and never attempts the TSL pipeline.
|
|
148
|
+
const hasWebGPU = typeof navigator !== 'undefined' && 'gpu' in navigator;
|
|
149
|
+
if (!hasWebGPU) {
|
|
150
|
+
console.warn('[viewer] WebGPU unavailable — rendering without post-processing (SSGI, outlines, denoise).');
|
|
151
|
+
hasPipelineErrorRef.current = true;
|
|
152
|
+
renderPipelineRef.current = null;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
113
155
|
// Clear outliner arrays synchronously to prevent stale Object3D refs
|
|
114
156
|
// from the previous project leaking into the new pipeline's outline passes.
|
|
115
157
|
const outliner = useViewer.getState().outliner;
|
|
158
|
+
sanitizeOutlineObjects(outliner.selectedObjects);
|
|
159
|
+
sanitizeOutlineObjects(outliner.hoveredObjects);
|
|
116
160
|
outliner.selectedObjects.length = 0;
|
|
117
161
|
outliner.hoveredObjects.length = 0;
|
|
118
162
|
try {
|
|
@@ -185,13 +229,9 @@ const PostProcessingPasses = () => {
|
|
|
185
229
|
.add(outlineNode.primaryHiddenEdge.mul(selectedHiddenColor))
|
|
186
230
|
.mul(selectedStrength);
|
|
187
231
|
// Hovered: blue visible, yellow hidden, pulsing
|
|
188
|
-
const hoverVisibleColor = uniform(new Color(hoverHighlightMode === 'delete' ? 0xef_44_44 : 0x00_aa_ff));
|
|
189
|
-
const hoverHiddenColor = uniform(new Color(hoverHighlightMode === 'delete' ? 0x99_1b_1b : 0xf3_ff_47));
|
|
190
|
-
const hoverStrength = uniform(hoverHighlightMode === 'delete' ? 6 : 5);
|
|
191
232
|
const pulsePeriod = uniform(3);
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
: oscSine(time.div(pulsePeriod).mul(2)).mul(0.5).add(0.5); // [ 0.5, 1.0 ]
|
|
233
|
+
const oscillating = oscSine(time.div(pulsePeriod).mul(2)).mul(0.5).add(0.5);
|
|
234
|
+
const osc = mix(oscillating, float(1), hoverPulseMix);
|
|
195
235
|
const hoverOutline = outlineNode.secondaryVisibleEdge
|
|
196
236
|
.mul(hoverVisibleColor)
|
|
197
237
|
.add(outlineNode.secondaryHiddenEdge.mul(hoverHiddenColor))
|
|
@@ -203,10 +243,15 @@ const PostProcessingPasses = () => {
|
|
|
203
243
|
renderPipeline.outputNode = finalOutput;
|
|
204
244
|
renderPipelineRef.current = renderPipeline;
|
|
205
245
|
retryCountRef.current = 0;
|
|
246
|
+
console.log('[viewer/post-processing] Pipeline built OK', { version: pipelineVersion });
|
|
206
247
|
}
|
|
207
248
|
catch (error) {
|
|
208
249
|
hasPipelineErrorRef.current = true;
|
|
209
|
-
console.error('[viewer] Failed to set up post-processing pipeline. Rendering without post FX.',
|
|
250
|
+
console.error('[viewer/post-processing] Failed to set up post-processing pipeline. Rendering without post FX.', {
|
|
251
|
+
version: pipelineVersion,
|
|
252
|
+
ssgi: SSGI_PARAMS.enabled,
|
|
253
|
+
rendererCtor: renderer.constructor?.name,
|
|
254
|
+
}, error);
|
|
210
255
|
if (renderPipelineRef.current) {
|
|
211
256
|
renderPipelineRef.current.dispose();
|
|
212
257
|
}
|
|
@@ -219,20 +264,25 @@ const PostProcessingPasses = () => {
|
|
|
219
264
|
renderPipelineRef.current = null;
|
|
220
265
|
};
|
|
221
266
|
}, [
|
|
267
|
+
camera,
|
|
268
|
+
hoverHiddenColor,
|
|
269
|
+
hoverPulseMix,
|
|
270
|
+
hoverStrength,
|
|
271
|
+
hoverVisibleColor,
|
|
272
|
+
pipelineVersion,
|
|
273
|
+
projectId,
|
|
222
274
|
renderer,
|
|
223
275
|
scene,
|
|
224
|
-
camera,
|
|
225
|
-
hoverHighlightMode,
|
|
226
|
-
isInitialized,
|
|
227
276
|
zoneLayers,
|
|
228
|
-
projectId,
|
|
229
|
-
pipelineVersion,
|
|
230
277
|
]);
|
|
231
278
|
useFrame((_, delta) => {
|
|
232
279
|
// Animate background colour toward the current theme target (same lerp as AnimatedBackground)
|
|
233
280
|
bgTarget.current.set(useViewer.getState().theme === 'dark' ? DARK_BG : LIGHT_BG);
|
|
234
281
|
bgCurrent.current.lerp(bgTarget.current, Math.min(delta, 0.1) * 4);
|
|
235
282
|
bgUniform.current.value.copy(bgCurrent.current);
|
|
283
|
+
const outliner = useViewer.getState().outliner;
|
|
284
|
+
sanitizeOutlineObjects(outliner.selectedObjects);
|
|
285
|
+
sanitizeOutlineObjects(outliner.hoveredObjects);
|
|
236
286
|
if (hasPipelineErrorRef.current || !renderPipelineRef.current) {
|
|
237
287
|
try {
|
|
238
288
|
if (renderer.setClearAlpha) {
|
|
@@ -243,7 +293,7 @@ const PostProcessingPasses = () => {
|
|
|
243
293
|
renderer.render(scene, camera);
|
|
244
294
|
}
|
|
245
295
|
catch (fallbackError) {
|
|
246
|
-
console.error('[viewer] Fallback render failed.', fallbackError);
|
|
296
|
+
console.error('[viewer/post-processing] Fallback render failed.', fallbackError);
|
|
247
297
|
}
|
|
248
298
|
return;
|
|
249
299
|
}
|
|
@@ -256,7 +306,11 @@ const PostProcessingPasses = () => {
|
|
|
256
306
|
}
|
|
257
307
|
catch (error) {
|
|
258
308
|
hasPipelineErrorRef.current = true;
|
|
259
|
-
console.error('[viewer
|
|
309
|
+
console.error('[viewer/post-processing] Render pass failed.', {
|
|
310
|
+
retryCount: retryCountRef.current,
|
|
311
|
+
rendererCtor: renderer.constructor?.name,
|
|
312
|
+
error,
|
|
313
|
+
});
|
|
260
314
|
if (renderPipelineRef.current) {
|
|
261
315
|
renderPipelineRef.current.dispose();
|
|
262
316
|
}
|
|
@@ -264,14 +318,14 @@ const PostProcessingPasses = () => {
|
|
|
264
318
|
if (retryCountRef.current < MAX_PIPELINE_RETRIES) {
|
|
265
319
|
// Auto-retry: schedule a pipeline rebuild if we haven't exceeded the retry limit
|
|
266
320
|
retryCountRef.current++;
|
|
267
|
-
console.warn(`[viewer] Scheduling
|
|
321
|
+
console.warn(`[viewer/post-processing] Scheduling pipeline rebuild (attempt ${retryCountRef.current}/${MAX_PIPELINE_RETRIES})`);
|
|
268
322
|
if (rebuildTimeoutRef.current !== null) {
|
|
269
323
|
clearTimeout(rebuildTimeoutRef.current);
|
|
270
324
|
}
|
|
271
325
|
rebuildTimeoutRef.current = setTimeout(requestPipelineRebuild, RETRY_DELAY_MS);
|
|
272
326
|
}
|
|
273
327
|
else {
|
|
274
|
-
console.error('[viewer
|
|
328
|
+
console.error('[viewer/post-processing] Retries exhausted. Rendering without post FX for this session.');
|
|
275
329
|
}
|
|
276
330
|
}
|
|
277
331
|
}, 1);
|
|
@@ -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":"AAoSA,eAAO,MAAM,gBAAgB,+CA4E5B,CAAA"}
|
|
@@ -82,6 +82,10 @@ const isNodeInZone = (node, levelId, zoneId) => {
|
|
|
82
82
|
const item = node;
|
|
83
83
|
return pointInPolygonWithTolerance(item.position[0], item.position[2], zone.polygon);
|
|
84
84
|
}
|
|
85
|
+
if (node.type === 'column') {
|
|
86
|
+
const column = node;
|
|
87
|
+
return pointInPolygonWithTolerance(column.position[0], column.position[2], zone.polygon);
|
|
88
|
+
}
|
|
85
89
|
if (node.type === 'wall') {
|
|
86
90
|
const wall = node;
|
|
87
91
|
const startIn = pointInPolygonWithTolerance(wall.start[0], wall.start[1], zone.polygon);
|
|
@@ -168,9 +172,20 @@ const getStrategy = () => {
|
|
|
168
172
|
isValid: (node) => node.type === 'zone' && node.parentId === levelId,
|
|
169
173
|
};
|
|
170
174
|
}
|
|
171
|
-
// Zone selected -> can select/hover contents (walls, items, slabs, ceilings, roofs, windows, doors)
|
|
175
|
+
// Zone selected -> can select/hover contents (walls, items, columns, slabs, ceilings, roofs, windows, doors)
|
|
172
176
|
return {
|
|
173
|
-
types: [
|
|
177
|
+
types: [
|
|
178
|
+
'wall',
|
|
179
|
+
'fence',
|
|
180
|
+
'item',
|
|
181
|
+
'column',
|
|
182
|
+
'slab',
|
|
183
|
+
'ceiling',
|
|
184
|
+
'roof',
|
|
185
|
+
'roof-segment',
|
|
186
|
+
'window',
|
|
187
|
+
'door',
|
|
188
|
+
],
|
|
174
189
|
handleClick: (node, nativeEvent) => {
|
|
175
190
|
let nodeToSelect = node;
|
|
176
191
|
if (node.type === 'roof-segment' && node.parentId) {
|
|
@@ -199,6 +214,7 @@ const getStrategy = () => {
|
|
|
199
214
|
'wall',
|
|
200
215
|
'fence',
|
|
201
216
|
'item',
|
|
217
|
+
'column',
|
|
202
218
|
'slab',
|
|
203
219
|
'ceiling',
|
|
204
220
|
'roof',
|
|
@@ -222,6 +238,10 @@ export const SelectionManager = () => {
|
|
|
222
238
|
return;
|
|
223
239
|
if (strategy.isValid(event.node)) {
|
|
224
240
|
event.stopPropagation();
|
|
241
|
+
if (event.node.type === 'slab') {
|
|
242
|
+
useViewer.setState({ hoveredId: null });
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
225
245
|
useViewer.setState({ hoveredId: event.node.id });
|
|
226
246
|
}
|
|
227
247
|
};
|
|
@@ -254,6 +274,7 @@ export const SelectionManager = () => {
|
|
|
254
274
|
'wall',
|
|
255
275
|
'fence',
|
|
256
276
|
'item',
|
|
277
|
+
'column',
|
|
257
278
|
'slab',
|
|
258
279
|
'ceiling',
|
|
259
280
|
'roof',
|
|
@@ -311,10 +332,14 @@ const OutlinerSync = () => {
|
|
|
311
332
|
const selection = useViewer((s) => s.selection);
|
|
312
333
|
const hoveredId = useViewer((s) => s.hoveredId);
|
|
313
334
|
const outliner = useViewer((s) => s.outliner);
|
|
335
|
+
const nodes = useScene((s) => s.nodes);
|
|
314
336
|
useEffect(() => {
|
|
315
337
|
// Sync selected objects
|
|
316
338
|
outliner.selectedObjects.length = 0;
|
|
317
339
|
for (const id of selection.selectedIds) {
|
|
340
|
+
const node = nodes[id];
|
|
341
|
+
if (node?.type === 'slab')
|
|
342
|
+
continue;
|
|
318
343
|
const obj = sceneRegistry.nodes.get(id);
|
|
319
344
|
if (obj)
|
|
320
345
|
outliner.selectedObjects.push(obj);
|
|
@@ -322,10 +347,13 @@ const OutlinerSync = () => {
|
|
|
322
347
|
// Sync hovered objects
|
|
323
348
|
outliner.hoveredObjects.length = 0;
|
|
324
349
|
if (hoveredId) {
|
|
350
|
+
const hoveredNode = nodes[hoveredId];
|
|
351
|
+
if (hoveredNode?.type === 'slab')
|
|
352
|
+
return;
|
|
325
353
|
const obj = sceneRegistry.nodes.get(hoveredId);
|
|
326
354
|
if (obj)
|
|
327
355
|
outliner.hoveredObjects.push(obj);
|
|
328
356
|
}
|
|
329
|
-
}, [selection, hoveredId, outliner]);
|
|
357
|
+
}, [selection, hoveredId, outliner, nodes]);
|
|
330
358
|
return null;
|
|
331
359
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
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';
|
|
1
|
+
import { type BuildingEvent, type BuildingNode, type CeilingEvent, type CeilingNode, type ColumnEvent, type ColumnNode, 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 SpawnEvent, type SpawnNode, 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: {
|
|
@@ -33,10 +33,18 @@ type NodeConfig = {
|
|
|
33
33
|
node: SlabNode;
|
|
34
34
|
event: SlabEvent;
|
|
35
35
|
};
|
|
36
|
+
spawn: {
|
|
37
|
+
node: SpawnNode;
|
|
38
|
+
event: SpawnEvent;
|
|
39
|
+
};
|
|
36
40
|
ceiling: {
|
|
37
41
|
node: CeilingNode;
|
|
38
42
|
event: CeilingEvent;
|
|
39
43
|
};
|
|
44
|
+
column: {
|
|
45
|
+
node: ColumnNode;
|
|
46
|
+
event: ColumnEvent;
|
|
47
|
+
};
|
|
40
48
|
roof: {
|
|
41
49
|
node: RoofNode;
|
|
42
50
|
event: RoofEvent;
|
|
@@ -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,UAAU,EACf,KAAK,SAAS,EACd,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,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAA;IAC7C,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,11 +1,15 @@
|
|
|
1
1
|
export { default as Viewer } from './components/viewer';
|
|
2
|
-
export {
|
|
2
|
+
export type { HoverStyle, HoverStyles } from './components/viewer/post-processing';
|
|
3
|
+
export { DEFAULT_HOVER_STYLES, SSGI_PARAMS, } from './components/viewer/post-processing';
|
|
3
4
|
export { WalkthroughControls } from './components/viewer/walkthrough-controls';
|
|
4
5
|
export { ASSETS_CDN_URL, resolveAssetUrl, resolveCdnUrl } from './lib/asset-url';
|
|
5
6
|
export { SCENE_LAYER, ZONE_LAYER } from './lib/layers';
|
|
6
|
-
export { clearMaterialCache, createDefaultMaterial, createMaterial, DEFAULT_CEILING_MATERIAL, DEFAULT_DOOR_MATERIAL, DEFAULT_ROOF_MATERIAL, DEFAULT_SLAB_MATERIAL, DEFAULT_WALL_MATERIAL, DEFAULT_WINDOW_MATERIAL, disposeMaterial, } from './lib/materials';
|
|
7
|
+
export { applyMaterialPresetToMaterials, clearMaterialCache, createDefaultMaterial, createMaterial, createMaterialFromPresetRef, DEFAULT_CEILING_MATERIAL, DEFAULT_DOOR_MATERIAL, DEFAULT_ROOF_MATERIAL, DEFAULT_SLAB_MATERIAL, DEFAULT_WALL_MATERIAL, DEFAULT_WINDOW_MATERIAL, disposeMaterial, } from './lib/materials';
|
|
7
8
|
export { mergedOutline } from './lib/merged-outline-node';
|
|
8
9
|
export { default as useViewer } from './store/use-viewer';
|
|
9
10
|
export { InteractiveSystem } from './systems/interactive/interactive-system';
|
|
10
11
|
export { snapLevelsToTruePositions } from './systems/level/level-utils';
|
|
12
|
+
export { getRoofMaterialArray } from './systems/roof/roof-materials';
|
|
13
|
+
export { getStairBodyMaterials, getStairRailingMaterial } from './systems/stair/stair-materials';
|
|
14
|
+
export { getVisibleWallMaterials } from './systems/wall/wall-materials';
|
|
11
15
|
//# sourceMappingURL=index.d.ts.map
|
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,
|
|
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,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AAClF,OAAO,EACL,oBAAoB,EACpB,WAAW,GACZ,MAAM,qCAAqC,CAAA;AAC5C,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,8BAA8B,EAC9B,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,2BAA2B,EAC3B,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;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AACpE,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AAChG,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
export { default as Viewer } from './components/viewer';
|
|
2
|
-
export { SSGI_PARAMS } from './components/viewer/post-processing';
|
|
2
|
+
export { DEFAULT_HOVER_STYLES, SSGI_PARAMS, } from './components/viewer/post-processing';
|
|
3
3
|
export { WalkthroughControls } from './components/viewer/walkthrough-controls';
|
|
4
4
|
export { ASSETS_CDN_URL, resolveAssetUrl, resolveCdnUrl } from './lib/asset-url';
|
|
5
5
|
export { SCENE_LAYER, ZONE_LAYER } from './lib/layers';
|
|
6
|
-
export { clearMaterialCache, createDefaultMaterial, createMaterial, DEFAULT_CEILING_MATERIAL, DEFAULT_DOOR_MATERIAL, DEFAULT_ROOF_MATERIAL, DEFAULT_SLAB_MATERIAL, DEFAULT_WALL_MATERIAL, DEFAULT_WINDOW_MATERIAL, disposeMaterial, } from './lib/materials';
|
|
6
|
+
export { applyMaterialPresetToMaterials, clearMaterialCache, createDefaultMaterial, createMaterial, createMaterialFromPresetRef, DEFAULT_CEILING_MATERIAL, DEFAULT_DOOR_MATERIAL, DEFAULT_ROOF_MATERIAL, DEFAULT_SLAB_MATERIAL, DEFAULT_WALL_MATERIAL, DEFAULT_WINDOW_MATERIAL, disposeMaterial, } from './lib/materials';
|
|
7
7
|
export { mergedOutline } from './lib/merged-outline-node';
|
|
8
8
|
export { default as useViewer } from './store/use-viewer';
|
|
9
9
|
export { InteractiveSystem } from './systems/interactive/interactive-system';
|
|
10
10
|
export { snapLevelsToTruePositions } from './systems/level/level-utils';
|
|
11
|
+
export { getRoofMaterialArray } from './systems/roof/roof-materials';
|
|
12
|
+
export { getStairBodyMaterials, getStairRailingMaterial } from './systems/stair/stair-materials';
|
|
13
|
+
export { getVisibleWallMaterials } from './systems/wall/wall-materials';
|
package/dist/lib/materials.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
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
|
+
import { MeshStandardNodeMaterial } from 'three/webgpu';
|
|
4
|
+
export declare const baseMaterial: MeshStandardNodeMaterial;
|
|
5
|
+
export declare const glassMaterial: MeshStandardNodeMaterial;
|
|
6
|
+
export declare function applyMaterialPresetToMaterials(materialInput: THREE.Material | THREE.Material[], preset: MaterialPresetPayload | null | undefined): void;
|
|
7
|
+
export declare function createMaterialFromPreset(preset: MaterialPresetPayload): THREE.MeshStandardMaterial;
|
|
8
|
+
export declare function createMaterialFromPresetRef(materialPreset?: string): THREE.MeshStandardMaterial | null;
|
|
3
9
|
export declare function createMaterial(material?: MaterialSchema): THREE.MeshStandardMaterial;
|
|
4
10
|
export declare function createDefaultMaterial(color?: string, roughness?: number): THREE.MeshStandardMaterial;
|
|
5
11
|
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;AAC9B,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAA;AAEvD,eAAO,MAAM,YAAY,0BAIvB,CAAA;AAEF,eAAO,MAAM,aAAa,0BAOxB,CAAA;AA2MF,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"}
|