@pascal-app/viewer 0.3.3 → 0.5.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/building/building-renderer.js +1 -1
- package/dist/components/renderers/item/item-renderer.d.ts.map +1 -1
- package/dist/components/renderers/item/item-renderer.js +14 -19
- package/dist/components/renderers/node-renderer.d.ts.map +1 -1
- package/dist/components/renderers/node-renderer.js +3 -1
- package/dist/components/renderers/site/site-renderer.d.ts.map +1 -1
- package/dist/components/renderers/site/site-renderer.js +59 -15
- package/dist/components/renderers/slab/slab-renderer.js +1 -1
- package/dist/components/renderers/stair/stair-renderer.d.ts +5 -0
- package/dist/components/renderers/stair/stair-renderer.d.ts.map +1 -0
- package/dist/components/renderers/stair/stair-renderer.js +21 -0
- package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts +5 -0
- package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts.map +1 -0
- package/dist/components/renderers/stair-segment/stair-segment-renderer.js +20 -0
- package/dist/components/renderers/wall/wall-renderer.js +1 -1
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +2 -3
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +33 -45
- package/dist/components/viewer/walkthrough-controls.d.ts +2 -0
- package/dist/components/viewer/walkthrough-controls.d.ts.map +1 -0
- package/dist/components/viewer/walkthrough-controls.js +131 -0
- package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
- package/dist/hooks/use-node-events.d.ts +9 -1
- package/dist/hooks/use-node-events.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/lib/materials.d.ts +1 -0
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +1 -0
- package/dist/lib/merged-outline-node.d.ts +88 -0
- package/dist/lib/merged-outline-node.d.ts.map +1 -0
- package/dist/lib/merged-outline-node.js +450 -0
- package/dist/lib/suppress-three-clock-warning.d.ts +25 -0
- package/dist/lib/suppress-three-clock-warning.d.ts.map +1 -0
- package/dist/lib/suppress-three-clock-warning.js +51 -0
- package/dist/store/use-viewer.d.ts +6 -0
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +8 -1
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +110 -61
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"building-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/building/building-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAe,MAAM,kBAAkB,CAAA;AAMjE,eAAO,MAAM,gBAAgB,GAAI,UAAU;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"building-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/building/building-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAe,MAAM,kBAAkB,CAAA;AAMjE,eAAO,MAAM,gBAAgB,GAAI,UAAU;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,4CAiBhE,CAAA"}
|
|
@@ -7,5 +7,5 @@ export const BuildingRenderer = ({ node }) => {
|
|
|
7
7
|
const ref = useRef(null);
|
|
8
8
|
useRegistry(node.id, node.type, ref);
|
|
9
9
|
const handlers = useNodeEvents(node, 'building');
|
|
10
|
-
return (_jsx("group", { ref: ref, ...handlers, children: node.children.map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, childId))) }));
|
|
10
|
+
return (_jsx("group", { position: node.position, ref: ref, rotation: [node.rotation[0], node.rotation[1], node.rotation[2]], ...handlers, children: node.children.map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, childId))) }));
|
|
11
11
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"item-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/item/item-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"item-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/item/item-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,QAAQ,EAKd,MAAM,kBAAkB,CAAA;AAkCzB,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,4CAiBxD,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useInteractive, useRegistry, useScene, } from '@pascal-app/core';
|
|
2
|
+
import { baseMaterial, glassMaterial, useInteractive, useRegistry, useScene, } from '@pascal-app/core';
|
|
3
3
|
import { useAnimations } from '@react-three/drei';
|
|
4
4
|
import { Clone } from '@react-three/drei/core/Clone';
|
|
5
5
|
import { useGLTF } from '@react-three/drei/core/Gltf';
|
|
@@ -7,33 +7,17 @@ import { useFrame } from '@react-three/fiber';
|
|
|
7
7
|
import { Suspense, useEffect, useMemo, useRef } from 'react';
|
|
8
8
|
import { MathUtils } from 'three';
|
|
9
9
|
import { positionLocal, smoothstep, time } from 'three/tsl';
|
|
10
|
-
import {
|
|
10
|
+
import { MeshStandardNodeMaterial } from 'three/webgpu';
|
|
11
11
|
import { useNodeEvents } from '../../../hooks/use-node-events';
|
|
12
12
|
import { resolveCdnUrl } from '../../../lib/asset-url';
|
|
13
13
|
import { useItemLightPool } from '../../../store/use-item-light-pool';
|
|
14
14
|
import { ErrorBoundary } from '../../error-boundary';
|
|
15
15
|
import { NodeRenderer } from '../node-renderer';
|
|
16
|
-
// Shared materials to avoid creating new instances for every mesh
|
|
17
|
-
const defaultMaterial = new MeshStandardNodeMaterial({
|
|
18
|
-
color: 0xff_ff_ff,
|
|
19
|
-
roughness: 1,
|
|
20
|
-
metalness: 0,
|
|
21
|
-
});
|
|
22
|
-
const glassMaterial = new MeshStandardNodeMaterial({
|
|
23
|
-
name: 'glass',
|
|
24
|
-
color: 'lightgray',
|
|
25
|
-
roughness: 0.8,
|
|
26
|
-
metalness: 0,
|
|
27
|
-
transparent: true,
|
|
28
|
-
opacity: 0.35,
|
|
29
|
-
side: DoubleSide,
|
|
30
|
-
depthWrite: false,
|
|
31
|
-
});
|
|
32
16
|
const getMaterialForOriginal = (original) => {
|
|
33
17
|
if (original.name.toLowerCase() === 'glass') {
|
|
34
18
|
return glassMaterial;
|
|
35
19
|
}
|
|
36
|
-
return
|
|
20
|
+
return baseMaterial;
|
|
37
21
|
};
|
|
38
22
|
const BrokenItemFallback = ({ node }) => {
|
|
39
23
|
const handlers = useNodeEvents(node, 'item');
|
|
@@ -93,6 +77,17 @@ const ModelRenderer = ({ node }) => {
|
|
|
93
77
|
if (Array.isArray(mesh.material)) {
|
|
94
78
|
mesh.material = mesh.material.map((mat) => getMaterialForOriginal(mat));
|
|
95
79
|
hasGlass = mesh.material.some((mat) => mat.name === 'glass');
|
|
80
|
+
// Fix geometry groups that reference materialIndex beyond the material
|
|
81
|
+
// array length — this causes three-mesh-bvh to crash with
|
|
82
|
+
// "Cannot read properties of undefined (reading 'side')"
|
|
83
|
+
const matCount = mesh.material.length;
|
|
84
|
+
if (mesh.geometry.groups.length > 0) {
|
|
85
|
+
for (const group of mesh.geometry.groups) {
|
|
86
|
+
if (group.materialIndex !== undefined && group.materialIndex >= matCount) {
|
|
87
|
+
group.materialIndex = 0;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
96
91
|
}
|
|
97
92
|
else {
|
|
98
93
|
mesh.material = getMaterialForOriginal(mesh.material);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-renderer.d.ts","sourceRoot":"","sources":["../../../src/components/renderers/node-renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAY,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"node-renderer.d.ts","sourceRoot":"","sources":["../../../src/components/renderers/node-renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAY,MAAM,kBAAkB,CAAA;AAkBzD,eAAO,MAAM,YAAY,GAAI,YAAY;IAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,mDAyBjE,CAAA"}
|
|
@@ -12,6 +12,8 @@ import { RoofSegmentRenderer } from './roof-segment/roof-segment-renderer';
|
|
|
12
12
|
import { ScanRenderer } from './scan/scan-renderer';
|
|
13
13
|
import { SiteRenderer } from './site/site-renderer';
|
|
14
14
|
import { SlabRenderer } from './slab/slab-renderer';
|
|
15
|
+
import { StairRenderer } from './stair/stair-renderer';
|
|
16
|
+
import { StairSegmentRenderer } from './stair-segment/stair-segment-renderer';
|
|
15
17
|
import { WallRenderer } from './wall/wall-renderer';
|
|
16
18
|
import { WindowRenderer } from './window/window-renderer';
|
|
17
19
|
import { ZoneRenderer } from './zone/zone-renderer';
|
|
@@ -19,5 +21,5 @@ export const NodeRenderer = ({ nodeId }) => {
|
|
|
19
21
|
const node = useScene((state) => state.nodes[nodeId]);
|
|
20
22
|
if (!node)
|
|
21
23
|
return null;
|
|
22
|
-
return (_jsxs(_Fragment, { children: [node.type === 'site' && _jsx(SiteRenderer, { node: node }), node.type === 'building' && _jsx(BuildingRenderer, { node: node }), node.type === 'ceiling' && _jsx(CeilingRenderer, { node: node }), node.type === 'level' && _jsx(LevelRenderer, { node: node }), node.type === 'item' && _jsx(ItemRenderer, { node: node }), node.type === 'slab' && _jsx(SlabRenderer, { node: node }), node.type === 'wall' && _jsx(WallRenderer, { node: node }), node.type === 'door' && _jsx(DoorRenderer, { node: node }), node.type === 'window' && _jsx(WindowRenderer, { node: node }), node.type === 'zone' && _jsx(ZoneRenderer, { node: node }), node.type === 'roof' && _jsx(RoofRenderer, { node: node }), node.type === 'roof-segment' && _jsx(RoofSegmentRenderer, { node: node }), node.type === 'scan' && _jsx(ScanRenderer, { node: node }), node.type === 'guide' && _jsx(GuideRenderer, { node: node })] }));
|
|
24
|
+
return (_jsxs(_Fragment, { children: [node.type === 'site' && _jsx(SiteRenderer, { node: node }), node.type === 'building' && _jsx(BuildingRenderer, { node: node }), node.type === 'ceiling' && _jsx(CeilingRenderer, { node: node }), node.type === 'level' && _jsx(LevelRenderer, { node: node }), node.type === 'item' && _jsx(ItemRenderer, { node: node }), node.type === 'slab' && _jsx(SlabRenderer, { node: node }), node.type === 'wall' && _jsx(WallRenderer, { node: node }), node.type === 'door' && _jsx(DoorRenderer, { node: node }), node.type === 'window' && _jsx(WindowRenderer, { node: node }), node.type === 'zone' && _jsx(ZoneRenderer, { node: node }), node.type === 'roof' && _jsx(RoofRenderer, { node: node }), node.type === 'roof-segment' && _jsx(RoofSegmentRenderer, { node: node }), node.type === 'stair' && _jsx(StairRenderer, { node: node }), node.type === 'stair-segment' && _jsx(StairSegmentRenderer, { node: node }), node.type === 'scan' && _jsx(ScanRenderer, { node: node }), node.type === 'guide' && _jsx(GuideRenderer, { node: node })] }));
|
|
23
25
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"site-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/site/site-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,
|
|
1
|
+
{"version":3,"file":"site-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/site/site-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAwC,MAAM,kBAAkB,CAAA;AAmCtF,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,mDAgHxD,CAAA"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useRegistry } from '@pascal-app/core';
|
|
2
|
+
import { useRegistry, useScene } from '@pascal-app/core';
|
|
3
|
+
import polygonClipping from 'polygon-clipping';
|
|
3
4
|
import { useMemo, useRef } from 'react';
|
|
4
|
-
import { BufferGeometry, Float32BufferAttribute, Shape } from 'three';
|
|
5
|
+
import { BufferGeometry, Float32BufferAttribute, Path, Shape } from 'three';
|
|
5
6
|
import { useNodeEvents } from '../../../hooks/use-node-events';
|
|
7
|
+
import useViewer from '../../../store/use-viewer';
|
|
6
8
|
import { NodeRenderer } from '../node-renderer';
|
|
7
9
|
const Y_OFFSET = 0.01;
|
|
8
10
|
/**
|
|
@@ -26,22 +28,64 @@ const createBoundaryLineGeometry = (points) => {
|
|
|
26
28
|
export const SiteRenderer = ({ node }) => {
|
|
27
29
|
const ref = useRef(null);
|
|
28
30
|
useRegistry(node.id, 'site', ref);
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
+
const theme = useViewer((state) => state.theme);
|
|
32
|
+
const bgColor = theme === 'dark' ? '#1f2433' : '#fafafa';
|
|
33
|
+
// Cache slab polygon references to keep the selector stable across unrelated store updates
|
|
34
|
+
const slabPolygonsCache = useRef([]);
|
|
35
|
+
const slabPolygons = useScene((state) => {
|
|
36
|
+
const nodeList = Object.values(state.nodes);
|
|
37
|
+
const levelIndexById = new Map();
|
|
38
|
+
let lowestLevelIndex = Number.POSITIVE_INFINITY;
|
|
39
|
+
nodeList.forEach((n) => {
|
|
40
|
+
if (n.type !== 'level')
|
|
41
|
+
return;
|
|
42
|
+
levelIndexById.set(n.id, n.level);
|
|
43
|
+
lowestLevelIndex = Math.min(lowestLevelIndex, n.level);
|
|
44
|
+
});
|
|
45
|
+
const next = nodeList
|
|
46
|
+
.filter((n) => n.type === 'slab' && n.visible && n.polygon.length >= 3)
|
|
47
|
+
.filter((n) => {
|
|
48
|
+
if (!Number.isFinite(lowestLevelIndex))
|
|
49
|
+
return true;
|
|
50
|
+
const parentLevel = n.parentId ? levelIndexById.get(n.parentId) : undefined;
|
|
51
|
+
return parentLevel === lowestLevelIndex;
|
|
52
|
+
})
|
|
53
|
+
.map((n) => n.polygon);
|
|
54
|
+
const prev = slabPolygonsCache.current;
|
|
55
|
+
if (next.length === prev.length && next.every((p, i) => p === prev[i]))
|
|
56
|
+
return prev;
|
|
57
|
+
slabPolygonsCache.current = next;
|
|
58
|
+
return next;
|
|
59
|
+
});
|
|
60
|
+
// Ground shape: site polygon with slab footprints punched as holes
|
|
61
|
+
const groundShape = useMemo(() => {
|
|
31
62
|
if (!node?.polygon?.points || node.polygon.points.length < 3)
|
|
32
63
|
return null;
|
|
64
|
+
const pts = node.polygon.points;
|
|
33
65
|
const shape = new Shape();
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
shape.moveTo(firstPt[0], -firstPt[1]);
|
|
38
|
-
for (let i = 1; i < node.polygon.points.length; i++) {
|
|
39
|
-
const pt = node.polygon.points[i];
|
|
40
|
-
shape.lineTo(pt[0], -pt[1]);
|
|
41
|
-
}
|
|
66
|
+
shape.moveTo(pts[0][0], -pts[0][1]);
|
|
67
|
+
for (let i = 1; i < pts.length; i++)
|
|
68
|
+
shape.lineTo(pts[i][0], -pts[i][1]);
|
|
42
69
|
shape.closePath();
|
|
70
|
+
if (slabPolygons.length > 0) {
|
|
71
|
+
const multiPolygons = slabPolygons.map((p) => [
|
|
72
|
+
p.map((pt) => [pt[0], -pt[1]]),
|
|
73
|
+
]);
|
|
74
|
+
const unioned = polygonClipping.union(multiPolygons[0], ...multiPolygons.slice(1));
|
|
75
|
+
for (const geom of unioned) {
|
|
76
|
+
const ring = geom[0];
|
|
77
|
+
if (ring && ring.length > 0) {
|
|
78
|
+
const hole = new Path();
|
|
79
|
+
hole.moveTo(ring[0][0], ring[0][1]);
|
|
80
|
+
for (let i = 1; i < ring.length; i++)
|
|
81
|
+
hole.lineTo(ring[i][0], ring[i][1]);
|
|
82
|
+
hole.closePath();
|
|
83
|
+
shape.holes.push(hole);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
43
87
|
return shape;
|
|
44
|
-
}, [node?.polygon?.points]);
|
|
88
|
+
}, [node?.polygon?.points, slabPolygons]);
|
|
45
89
|
// Create boundary line geometry
|
|
46
90
|
const lineGeometry = useMemo(() => {
|
|
47
91
|
if (!node?.polygon?.points || node.polygon.points.length < 2)
|
|
@@ -49,8 +93,8 @@ export const SiteRenderer = ({ node }) => {
|
|
|
49
93
|
return createBoundaryLineGeometry(node.polygon.points);
|
|
50
94
|
}, [node?.polygon?.points]);
|
|
51
95
|
const handlers = useNodeEvents(node, 'site');
|
|
52
|
-
if (!(node &&
|
|
96
|
+
if (!(node && lineGeometry)) {
|
|
53
97
|
return null;
|
|
54
98
|
}
|
|
55
|
-
return (_jsxs("group", { ref: ref, ...handlers, children: [node.children.map((child) => (_jsx(NodeRenderer, { nodeId: typeof child === 'string' ? child : child.id }, typeof child === 'string' ? child : child.id))), _jsxs("mesh", { position: [0,
|
|
99
|
+
return (_jsxs("group", { ref: ref, ...handlers, children: [node.children.map((child) => (_jsx(NodeRenderer, { nodeId: typeof child === 'string' ? child : child.id }, typeof child === 'string' ? child : child.id))), groundShape && (_jsxs("mesh", { position: [0, -0.05, 0], receiveShadow: true, rotation: [-Math.PI / 2, 0, 0], children: [_jsx("shapeGeometry", { args: [groundShape] }), _jsx("meshStandardMaterial", { color: bgColor, depthWrite: true, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 1 })] })), _jsx("line", { frustumCulled: false, geometry: lineGeometry, renderOrder: 9, children: _jsx("lineBasicMaterial", { color: "#f59e0b", linewidth: 2, opacity: 0.6, transparent: true }) })] }));
|
|
56
100
|
};
|
|
@@ -13,5 +13,5 @@ export const SlabRenderer = ({ node }) => {
|
|
|
13
13
|
return DEFAULT_SLAB_MATERIAL;
|
|
14
14
|
return createMaterial(mat);
|
|
15
15
|
}, [node.material, node.material?.preset, node.material?.properties, node.material?.texture]);
|
|
16
|
-
return (_jsx("mesh", { castShadow: true, receiveShadow: true, ref: ref, ...handlers, visible: node.visible,
|
|
16
|
+
return (_jsx("mesh", { castShadow: true, receiveShadow: true, ref: ref, ...handlers, material: material, visible: node.visible, children: _jsx("boxGeometry", { args: [0, 0, 0] }) }));
|
|
17
17
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stair-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/stair/stair-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAyB,MAAM,kBAAkB,CAAA;AAOxE,eAAO,MAAM,aAAa,GAAI,UAAU;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,4CAoC1D,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRegistry, useScene } from '@pascal-app/core';
|
|
3
|
+
import { useLayoutEffect, useMemo, useRef } from 'react';
|
|
4
|
+
import { useNodeEvents } from '../../../hooks/use-node-events';
|
|
5
|
+
import { createMaterial, DEFAULT_STAIR_MATERIAL } from '../../../lib/materials';
|
|
6
|
+
import { NodeRenderer } from '../node-renderer';
|
|
7
|
+
export const StairRenderer = ({ node }) => {
|
|
8
|
+
const ref = useRef(null);
|
|
9
|
+
useRegistry(node.id, 'stair', ref);
|
|
10
|
+
useLayoutEffect(() => {
|
|
11
|
+
useScene.getState().markDirty(node.id);
|
|
12
|
+
}, [node.id]);
|
|
13
|
+
const handlers = useNodeEvents(node, 'stair');
|
|
14
|
+
const material = useMemo(() => {
|
|
15
|
+
const mat = node.material;
|
|
16
|
+
if (!mat)
|
|
17
|
+
return DEFAULT_STAIR_MATERIAL;
|
|
18
|
+
return createMaterial(mat);
|
|
19
|
+
}, [node.material, node.material?.preset, node.material?.properties, node.material?.texture]);
|
|
20
|
+
return (_jsxs("group", { "position-x": node.position[0], "position-z": node.position[2], ref: ref, "rotation-y": node.rotation, visible: node.visible, ...handlers, children: [_jsx("mesh", { castShadow: true, material: material, name: "merged-stair", receiveShadow: true, children: _jsx("boxGeometry", { args: [0, 0, 0] }) }), _jsx("group", { name: "segments-wrapper", visible: false, children: (node.children ?? []).map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, childId))) })] }));
|
|
21
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stair-segment-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/stair-segment/stair-segment-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAyB,MAAM,kBAAkB,CAAA;AAM/E,eAAO,MAAM,oBAAoB,GAAI,UAAU;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,4CA8BxE,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useRegistry, useScene } from '@pascal-app/core';
|
|
3
|
+
import { useLayoutEffect, useMemo, useRef } from 'react';
|
|
4
|
+
import { useNodeEvents } from '../../../hooks/use-node-events';
|
|
5
|
+
import { createMaterial, DEFAULT_STAIR_MATERIAL } from '../../../lib/materials';
|
|
6
|
+
export const StairSegmentRenderer = ({ node }) => {
|
|
7
|
+
const ref = useRef(null);
|
|
8
|
+
useRegistry(node.id, 'stair-segment', ref);
|
|
9
|
+
useLayoutEffect(() => {
|
|
10
|
+
useScene.getState().markDirty(node.id);
|
|
11
|
+
}, [node.id]);
|
|
12
|
+
const handlers = useNodeEvents(node, 'stair-segment');
|
|
13
|
+
const material = useMemo(() => {
|
|
14
|
+
const mat = node.material;
|
|
15
|
+
if (!mat)
|
|
16
|
+
return DEFAULT_STAIR_MATERIAL;
|
|
17
|
+
return createMaterial(mat);
|
|
18
|
+
}, [node.material, node.material?.preset, node.material?.properties, node.material?.texture]);
|
|
19
|
+
return (_jsx("mesh", { material: material, position: node.position, ref: ref, "rotation-y": node.rotation, visible: node.visible, ...handlers, children: _jsx("boxGeometry", { args: [0, 0, 0] }) }));
|
|
20
|
+
};
|
|
@@ -17,5 +17,5 @@ export const WallRenderer = ({ node }) => {
|
|
|
17
17
|
return DEFAULT_WALL_MATERIAL;
|
|
18
18
|
return createMaterial(mat);
|
|
19
19
|
}, [node.material, node.material?.preset, node.material?.properties, node.material?.texture]);
|
|
20
|
-
return (_jsxs("mesh", { castShadow: true, receiveShadow: true, ref: ref, visible: node.visible,
|
|
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)))] }));
|
|
21
21
|
};
|
|
@@ -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":"AAaA,OAAO,EAAkB,KAAK,kBAAkB,EAAsB,MAAM,oBAAoB,CAAA;AAEhG,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AA0CrC,OAAO,QAAQ,oBAAoB,CAAC;IAClC,UAAU,aAAc,SAAQ,kBAAkB,CAAC,OAAO,KAAK,CAAC;KAAG;CACpE;AA+BD,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,CA8DjC,CAAA;AASD,eAAe,MAAM,CAAA"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { CeilingSystem, DoorSystem, ItemSystem, RoofSystem, SlabSystem, WallSystem, WindowSystem, } from '@pascal-app/core';
|
|
3
|
+
import { CeilingSystem, DoorSystem, 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';
|
|
7
7
|
import * as THREE from 'three/webgpu';
|
|
8
8
|
import useViewer from '../../store/use-viewer';
|
|
9
|
-
import { ExportSystem } from '../../systems/export/export-system';
|
|
10
9
|
import { GuideSystem } from '../../systems/guide/guide-system';
|
|
11
10
|
import { ItemLightSystem } from '../../systems/item-light/item-light-system';
|
|
12
11
|
import { LevelSystem } from '../../systems/level/level-system';
|
|
@@ -75,7 +74,7 @@ const Viewer = ({ children, selectionManager = 'default', perf = false, }) => {
|
|
|
75
74
|
}, shadows: {
|
|
76
75
|
type: THREE.PCFShadowMap,
|
|
77
76
|
enabled: true,
|
|
78
|
-
}, 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(
|
|
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] }));
|
|
79
78
|
};
|
|
80
79
|
const DebugRenderer = () => {
|
|
81
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;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,QAAA,MAAM,oBAAoB,YAoQzB,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useFrame, useThree } from '@react-three/fiber';
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { Color, Layers, UnsignedByteType } from 'three';
|
|
4
|
-
import { outline } from 'three/addons/tsl/display/OutlineNode.js';
|
|
5
4
|
import { ssgi } from 'three/addons/tsl/display/SSGINode.js';
|
|
6
5
|
import { denoise } from 'three/examples/jsm/tsl/display/DenoiseNode.js';
|
|
7
6
|
import { add, colorToDirection, diffuseColor, directionToColor, float, mix, mrt, normalView, oscSine, output, pass, sample, time, uniform, vec4, } from 'three/tsl';
|
|
8
7
|
import { RenderPipeline } from 'three/webgpu';
|
|
9
8
|
import { SCENE_LAYER, ZONE_LAYER } from '../../lib/layers';
|
|
9
|
+
import { mergedOutline } from '../../lib/merged-outline-node';
|
|
10
10
|
import useViewer from '../../store/use-viewer';
|
|
11
11
|
// SSGI Parameters - adjust these to fine-tune global illumination and ambient occlusion
|
|
12
12
|
export const SSGI_PARAMS = {
|
|
@@ -45,6 +45,7 @@ const PostProcessingPasses = () => {
|
|
|
45
45
|
l.disable(SCENE_LAYER);
|
|
46
46
|
return l;
|
|
47
47
|
}, []);
|
|
48
|
+
const hoverHighlightMode = useViewer((s) => s.hoverHighlightMode);
|
|
48
49
|
// Subscribe to projectId so the pipeline rebuilds on project switch
|
|
49
50
|
const projectId = useViewer((s) => s.projectId);
|
|
50
51
|
// Bump this to force a pipeline rebuild (used by retry logic)
|
|
@@ -144,49 +145,36 @@ const PostProcessingPasses = () => {
|
|
|
144
145
|
// Composite: scene * AO + diffuse * GI
|
|
145
146
|
sceneColor = vec4(add(scenePassColor.rgb.mul(ao), add(zonePass.rgb, scenePassDiffuse.rgb.mul(gi))), contentAlpha);
|
|
146
147
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const { visibleEdge, hiddenEdge } = outlinePass;
|
|
178
|
-
const period = time.div(pulsePeriod).mul(2);
|
|
179
|
-
const osc = oscSine(period).mul(0.5).add(0.5); // osc [ 0.5, 1.0 ]
|
|
180
|
-
const outlineColor = visibleEdge
|
|
181
|
-
.mul(visibleEdgeColor)
|
|
182
|
-
.add(hiddenEdge.mul(hiddenEdgeColor))
|
|
183
|
-
.mul(edgeStrength);
|
|
184
|
-
const outlinePulse = pulsePeriod.greaterThan(0).select(outlineColor.mul(osc), outlineColor);
|
|
185
|
-
return outlinePulse;
|
|
186
|
-
}
|
|
187
|
-
const selectedOutlinePass = generateSelectedOutlinePass();
|
|
188
|
-
const hoverOutlinePass = generateHoverOutlinePass();
|
|
189
|
-
const compositeWithOutlines = vec4(add(sceneColor.rgb, selectedOutlinePass.add(hoverOutlinePass)), sceneColor.a);
|
|
148
|
+
// Single merged outline node: one shared depth pass for both selected + hovered groups.
|
|
149
|
+
const outliner = useViewer.getState().outliner;
|
|
150
|
+
const outlineNode = mergedOutline(scene, camera, {
|
|
151
|
+
primaryObjects: outliner.selectedObjects,
|
|
152
|
+
secondaryObjects: outliner.hoveredObjects,
|
|
153
|
+
primaryEdgeThickness: uniform(1),
|
|
154
|
+
secondaryEdgeThickness: uniform(1.5),
|
|
155
|
+
});
|
|
156
|
+
// Selected: white visible, yellow hidden
|
|
157
|
+
const selectedVisibleColor = uniform(new Color(0xff_ff_ff));
|
|
158
|
+
const selectedHiddenColor = uniform(new Color(0xf3_ff_47));
|
|
159
|
+
const selectedStrength = uniform(3);
|
|
160
|
+
const selectedOutline = outlineNode.primaryVisibleEdge
|
|
161
|
+
.mul(selectedVisibleColor)
|
|
162
|
+
.add(outlineNode.primaryHiddenEdge.mul(selectedHiddenColor))
|
|
163
|
+
.mul(selectedStrength);
|
|
164
|
+
// Hovered: blue visible, yellow hidden, pulsing
|
|
165
|
+
const hoverVisibleColor = uniform(new Color(hoverHighlightMode === 'delete' ? 0xef_44_44 : 0x00_aa_ff));
|
|
166
|
+
const hoverHiddenColor = uniform(new Color(hoverHighlightMode === 'delete' ? 0x99_1b_1b : 0xf3_ff_47));
|
|
167
|
+
const hoverStrength = uniform(hoverHighlightMode === 'delete' ? 6 : 5);
|
|
168
|
+
const pulsePeriod = uniform(3);
|
|
169
|
+
const osc = hoverHighlightMode === 'delete'
|
|
170
|
+
? float(1)
|
|
171
|
+
: oscSine(time.div(pulsePeriod).mul(2)).mul(0.5).add(0.5); // [ 0.5, 1.0 ]
|
|
172
|
+
const hoverOutline = outlineNode.secondaryVisibleEdge
|
|
173
|
+
.mul(hoverVisibleColor)
|
|
174
|
+
.add(outlineNode.secondaryHiddenEdge.mul(hoverHiddenColor))
|
|
175
|
+
.mul(hoverStrength)
|
|
176
|
+
.mul(osc);
|
|
177
|
+
const compositeWithOutlines = vec4(add(sceneColor.rgb, selectedOutline.add(hoverOutline)), sceneColor.a);
|
|
190
178
|
const finalOutput = vec4(mix(bgUniform.current, compositeWithOutlines.rgb, contentAlpha), float(1));
|
|
191
179
|
const renderPipeline = new RenderPipeline(renderer);
|
|
192
180
|
renderPipeline.outputNode = finalOutput;
|
|
@@ -206,7 +194,7 @@ const PostProcessingPasses = () => {
|
|
|
206
194
|
}
|
|
207
195
|
renderPipelineRef.current = null;
|
|
208
196
|
};
|
|
209
|
-
}, [renderer, scene, camera, isInitialized, zoneLayers]);
|
|
197
|
+
}, [renderer, scene, camera, hoverHighlightMode, isInitialized, zoneLayers]);
|
|
210
198
|
useFrame((_, delta) => {
|
|
211
199
|
// Animate background colour toward the current theme target (same lerp as AnimatedBackground)
|
|
212
200
|
bgTarget.current.set(useViewer.getState().theme === 'dark' ? DARK_BG : LIGHT_BG);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walkthrough-controls.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/walkthrough-controls.tsx"],"names":[],"mappings":"AAeA,eAAO,MAAM,mBAAmB,sDAwH/B,CAAA"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { PointerLockControls } from '@react-three/drei';
|
|
4
|
+
import { useFrame, useThree } from '@react-three/fiber';
|
|
5
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
6
|
+
import { Vector3 } from 'three';
|
|
7
|
+
import useViewer from '../../store/use-viewer';
|
|
8
|
+
const MOVE_SPEED = 5;
|
|
9
|
+
const EYE_HEIGHT = 1.6;
|
|
10
|
+
const _direction = new Vector3();
|
|
11
|
+
const _forward = new Vector3();
|
|
12
|
+
const _right = new Vector3();
|
|
13
|
+
export const WalkthroughControls = () => {
|
|
14
|
+
const controlsRef = useRef(null);
|
|
15
|
+
const walkthroughMode = useViewer((s) => s.walkthroughMode);
|
|
16
|
+
const keys = useRef({ w: false, a: false, s: false, d: false });
|
|
17
|
+
const camera = useThree((s) => s.camera);
|
|
18
|
+
// Set initial eye height
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (walkthroughMode) {
|
|
21
|
+
camera.position.y = EYE_HEIGHT;
|
|
22
|
+
}
|
|
23
|
+
}, [walkthroughMode, camera]);
|
|
24
|
+
// Keyboard handlers
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!walkthroughMode)
|
|
27
|
+
return;
|
|
28
|
+
const onKeyDown = (e) => {
|
|
29
|
+
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement)
|
|
30
|
+
return;
|
|
31
|
+
const key = e.key.toLowerCase();
|
|
32
|
+
// ESC exits walkthrough mode completely
|
|
33
|
+
if (e.key === 'Escape') {
|
|
34
|
+
e.preventDefault();
|
|
35
|
+
e.stopPropagation();
|
|
36
|
+
useViewer.getState().setWalkthroughMode(false);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (key === 'w' || key === 'arrowup')
|
|
40
|
+
keys.current.w = true;
|
|
41
|
+
if (key === 'a' || key === 'arrowleft')
|
|
42
|
+
keys.current.a = true;
|
|
43
|
+
if (key === 's' || key === 'arrowdown')
|
|
44
|
+
keys.current.s = true;
|
|
45
|
+
if (key === 'd' || key === 'arrowright')
|
|
46
|
+
keys.current.d = true;
|
|
47
|
+
};
|
|
48
|
+
const onKeyUp = (e) => {
|
|
49
|
+
const key = e.key.toLowerCase();
|
|
50
|
+
if (key === 'w' || key === 'arrowup')
|
|
51
|
+
keys.current.w = false;
|
|
52
|
+
if (key === 'a' || key === 'arrowleft')
|
|
53
|
+
keys.current.a = false;
|
|
54
|
+
if (key === 's' || key === 'arrowdown')
|
|
55
|
+
keys.current.s = false;
|
|
56
|
+
if (key === 'd' || key === 'arrowright')
|
|
57
|
+
keys.current.d = false;
|
|
58
|
+
};
|
|
59
|
+
window.addEventListener('keydown', onKeyDown);
|
|
60
|
+
window.addEventListener('keyup', onKeyUp);
|
|
61
|
+
return () => {
|
|
62
|
+
window.removeEventListener('keydown', onKeyDown);
|
|
63
|
+
window.removeEventListener('keyup', onKeyUp);
|
|
64
|
+
// Reset keys on cleanup
|
|
65
|
+
keys.current = { w: false, a: false, s: false, d: false };
|
|
66
|
+
};
|
|
67
|
+
}, [walkthroughMode]);
|
|
68
|
+
// Release pointer lock when walkthrough mode is turned off
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (!walkthroughMode && document.pointerLockElement) {
|
|
71
|
+
document.exitPointerLock();
|
|
72
|
+
}
|
|
73
|
+
}, [walkthroughMode]);
|
|
74
|
+
// Movement loop
|
|
75
|
+
useFrame((_, delta) => {
|
|
76
|
+
if (!(walkthroughMode && controlsRef.current))
|
|
77
|
+
return;
|
|
78
|
+
_direction.set(0, 0, 0);
|
|
79
|
+
// Get camera forward and right vectors (XZ plane only)
|
|
80
|
+
camera.getWorldDirection(_forward);
|
|
81
|
+
_forward.y = 0;
|
|
82
|
+
_forward.normalize();
|
|
83
|
+
_right.crossVectors(_forward, camera.up).normalize();
|
|
84
|
+
if (keys.current.w)
|
|
85
|
+
_direction.add(_forward);
|
|
86
|
+
if (keys.current.s)
|
|
87
|
+
_direction.sub(_forward);
|
|
88
|
+
if (keys.current.d)
|
|
89
|
+
_direction.add(_right);
|
|
90
|
+
if (keys.current.a)
|
|
91
|
+
_direction.sub(_right);
|
|
92
|
+
if (_direction.lengthSq() > 0) {
|
|
93
|
+
_direction.normalize().multiplyScalar(MOVE_SPEED * delta);
|
|
94
|
+
camera.position.add(_direction);
|
|
95
|
+
// Keep eye height constant
|
|
96
|
+
camera.position.y = EYE_HEIGHT;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
const handleClick = useCallback(() => {
|
|
100
|
+
if (walkthroughMode && controlsRef.current) {
|
|
101
|
+
// Feature detection: some browsers (Facebook/Instagram in-app, older Safari)
|
|
102
|
+
// don't support pointer lock on the canvas element
|
|
103
|
+
if (typeof controlsRef.current.lock === 'function') {
|
|
104
|
+
try {
|
|
105
|
+
controlsRef.current.lock();
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Silently ignore — pointer lock unavailable in this browser context
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}, [walkthroughMode]);
|
|
113
|
+
// Click to lock
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
if (!walkthroughMode)
|
|
116
|
+
return;
|
|
117
|
+
const canvas = document.querySelector('canvas');
|
|
118
|
+
if (!canvas)
|
|
119
|
+
return;
|
|
120
|
+
canvas.addEventListener('click', handleClick);
|
|
121
|
+
return () => canvas.removeEventListener('click', handleClick);
|
|
122
|
+
}, [walkthroughMode, handleClick]);
|
|
123
|
+
if (!walkthroughMode)
|
|
124
|
+
return null;
|
|
125
|
+
// Skip PointerLockControls on browsers that don't support pointer lock
|
|
126
|
+
// (Facebook/Instagram in-app browsers, some iOS WebViews)
|
|
127
|
+
if (typeof document !== 'undefined' && !('requestPointerLock' in HTMLElement.prototype)) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
return _jsx(PointerLockControls, { ref: controlsRef });
|
|
131
|
+
};
|
|
@@ -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;AAU3C,QAAA,MAAM,WAAW,GAAI,MAAM,MAAM,KAAG,UAAU,CAAC,OAAO,OAAO,CA2B5D,CAAA;
|
|
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;AAU3C,QAAA,MAAM,WAAW,GAAI,MAAM,MAAM,KAAG,UAAU,CAAC,OAAO,OAAO,CA2B5D,CAAA;AACD,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -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 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 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: {
|
|
@@ -41,6 +41,14 @@ type NodeConfig = {
|
|
|
41
41
|
node: RoofSegmentNode;
|
|
42
42
|
event: RoofSegmentEvent;
|
|
43
43
|
};
|
|
44
|
+
stair: {
|
|
45
|
+
node: StairNode;
|
|
46
|
+
event: StairEvent;
|
|
47
|
+
};
|
|
48
|
+
'stair-segment': {
|
|
49
|
+
node: StairSegmentNode;
|
|
50
|
+
event: StairSegmentEvent;
|
|
51
|
+
};
|
|
44
52
|
window: {
|
|
45
53
|
node: WindowNode;
|
|
46
54
|
event: WindowEvent;
|
|
@@ -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,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,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;uBAiB/D,UAAU,CAAC,YAAY,CAAC;qBAK1B,UAAU,CAAC,YAAY,CAAC;iBAQ5B,UAAU,CAAC,YAAY,CAAC;wBAIjB,UAAU,CAAC,YAAY,CAAC;wBAIxB,UAAU,CAAC,YAAY,CAAC;uBAIzB,UAAU,CAAC,YAAY,CAAC;uBAIxB,UAAU,CAAC,YAAY,CAAC;uBAIxB,UAAU,CAAC,YAAY,CAAC;EAK9C"}
|
|
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;uBAiB/D,UAAU,CAAC,YAAY,CAAC;qBAK1B,UAAU,CAAC,YAAY,CAAC;iBAQ5B,UAAU,CAAC,YAAY,CAAC;wBAIjB,UAAU,CAAC,YAAY,CAAC;wBAIxB,UAAU,CAAC,YAAY,CAAC;uBAIzB,UAAU,CAAC,YAAY,CAAC;uBAIxB,UAAU,CAAC,YAAY,CAAC;uBAIxB,UAAU,CAAC,YAAY,CAAC;EAK9C"}
|