@pascal-app/viewer 1.0.0 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/capture/capture-runtime.js +2 -32
- package/dist/capture/layers/device-motion-layer.d.ts.map +1 -1
- package/dist/capture/layers/device-motion-layer.js +5 -7
- package/dist/capture/stream-rendering.d.ts.map +1 -1
- package/dist/capture/stream-rendering.js +2 -1
- package/dist/capture/use-json-artifact.d.ts +2 -0
- package/dist/capture/use-json-artifact.d.ts.map +1 -0
- package/dist/capture/use-json-artifact.js +42 -0
- package/dist/components/viewer/glb-scene.d.ts.map +1 -1
- package/dist/components/viewer/glb-scene.js +3 -1
- package/dist/components/viewer/index.d.ts +12 -0
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +28 -7
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +6 -0
- package/dist/components/viewer/selection-manager.d.ts.map +1 -1
- package/dist/components/viewer/selection-manager.js +8 -16
- package/dist/components/viewer/viewer-camera.d.ts +15 -1
- package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
- package/dist/components/viewer/viewer-camera.js +43 -5
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/lib/csg-utils.d.ts +1 -1
- package/dist/lib/csg-utils.d.ts.map +1 -1
- package/dist/lib/csg-utils.js +1 -1
- package/dist/lib/isolation.d.ts +14 -30
- package/dist/lib/isolation.d.ts.map +1 -1
- package/dist/lib/isolation.js +62 -66
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +2 -1
- package/dist/lib/renderer-capability.d.ts +2 -1
- package/dist/lib/renderer-capability.d.ts.map +1 -1
- package/dist/lib/renderer-capability.js +2 -2
- package/dist/lib/scene-visibility.js +3 -1
- package/dist/lib/snapshot-pipeline.d.ts +3 -1
- package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
- package/dist/lib/snapshot-pipeline.js +32 -16
- package/dist/store/use-viewer.d.ts +3 -1
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +2 -0
- package/dist/systems/door/door-system.d.ts.map +1 -1
- package/dist/systems/door/door-system.js +18 -5
- package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -1
- package/dist/systems/floor-elevation/floor-elevation-system.js +122 -3
- package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
- package/dist/systems/geometry/geometry-system.js +4 -0
- package/dist/systems/level/level-system.js +14 -14
- package/dist/systems/level/level-utils.d.ts +25 -1
- package/dist/systems/level/level-utils.d.ts.map +1 -1
- package/dist/systems/level/level-utils.js +25 -4
- package/dist/systems/wall/wall-cutout-cache.d.ts +4 -1
- package/dist/systems/wall/wall-cutout-cache.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout-cache.js +16 -7
- package/dist/systems/wall/wall-cutout.d.ts +3 -1
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +5 -5
- package/dist/systems/wall/wall-materials.d.ts +11 -2
- package/dist/systems/wall/wall-materials.d.ts.map +1 -1
- package/dist/systems/wall/wall-materials.js +24 -18
- package/dist/systems/wall/wall-system.d.ts +15 -2
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +20 -21
- package/dist/systems/window/window-system.d.ts +1 -1
- package/dist/systems/window/window-system.d.ts.map +1 -1
- package/dist/systems/window/window-system.js +3 -2
- package/dist/systems/zone/zone-system.d.ts.map +1 -1
- package/dist/systems/zone/zone-system.js +28 -2
- package/dist/xr/presentation-context.d.ts +7 -0
- package/dist/xr/presentation-context.d.ts.map +1 -0
- package/dist/xr/presentation-context.js +10 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -175,6 +175,18 @@ colors; dollhouse enables front-face rendering for surface previews and room mod
|
|
|
175
175
|
inward-facing room surfaces from outside. It changes per-instance materials, not geometry or
|
|
176
176
|
loader-cached materials. Omitting these options preserves the existing presentation.
|
|
177
177
|
|
|
178
|
+
## Scene Snapshots
|
|
179
|
+
|
|
180
|
+
`createSnapshotPipeline` renders offscreen snapshots with the scene theme's backdrop by default.
|
|
181
|
+
Inside a `Viewer`, pass the source returned by `useSceneAtmosphere()` as `atmosphere` to capture
|
|
182
|
+
the active presentation's sky instead. Recreate the pipeline when that source changes; updates
|
|
183
|
+
to its existing uniforms do not require rebuilding it.
|
|
184
|
+
|
|
185
|
+
Use `applyEnvironment({ ..., transparent: true })` to retain scene alpha without compositing a
|
|
186
|
+
backdrop. The snapshot scene pass owns its transparent clear so intermediate post-processing
|
|
187
|
+
passes cannot turn empty sky into opaque pixels. Dispose the pipeline when it is replaced or
|
|
188
|
+
no longer needed.
|
|
189
|
+
|
|
178
190
|
## Viewer State
|
|
179
191
|
|
|
180
192
|
```typescript
|
|
@@ -7,7 +7,6 @@ import { Suspense, useCallback, useEffect, useMemo, useRef, useState, } from 're
|
|
|
7
7
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
8
8
|
import { useNodeEvents } from '../hooks/use-node-events';
|
|
9
9
|
import useViewer from '../store/use-viewer';
|
|
10
|
-
import { rewriteLoopbackAssetUrl } from './asset-url';
|
|
11
10
|
import { resolveCaptureFrameMatrix } from './frame';
|
|
12
11
|
import { isCaptureSessionVisible, isCaptureStreamVisible } from './layer-visibility';
|
|
13
12
|
import { CaptureDeviceMotionLayer } from './layers/device-motion-layer';
|
|
@@ -17,6 +16,7 @@ import { CaptureSurfaceMeshLayer } from './layers/surface-mesh-layer';
|
|
|
17
16
|
import { useCaptureSource } from './source-state';
|
|
18
17
|
import { captureModelFormat, isCaptureModelArtifact, isCapturePointCloudArtifact, isCaptureStreamRenderable, streamHydratesJsonPayload, } from './stream-rendering';
|
|
19
18
|
import { parseDeviceTrajectoryPackets, parseDeviceTrajectoryPayload } from './trajectory';
|
|
19
|
+
import { useJsonArtifactPayload } from './use-json-artifact';
|
|
20
20
|
const EMPTY_RENDERERS = {};
|
|
21
21
|
const EMPTY_LAYER_VISIBILITY = {};
|
|
22
22
|
export function CaptureRuntime({ defaultLayerVisibility = EMPTY_LAYER_VISIBILITY, maxPacketsPerStream = 32, onError, renderers = EMPTY_RENDERERS, resolveSource, retryKey = 0, }) {
|
|
@@ -135,7 +135,7 @@ export function CaptureStreamLayer({ descriptor, meshPresentation, packets, rend
|
|
|
135
135
|
if (Renderer) {
|
|
136
136
|
content = (_jsx(Renderer, { artifactUrl: artifactUrl, descriptor: descriptor, meshPresentation: meshPresentation, packets: packets, scan: scan, source: source, stream: stream, streamEpoch: streamEpoch }));
|
|
137
137
|
}
|
|
138
|
-
else if (layerKey === 'model' &&
|
|
138
|
+
else if ((layerKey === 'model' || layerKey === 'spaceformScene') &&
|
|
139
139
|
isCaptureModelArtifact(stream.artifact) &&
|
|
140
140
|
stream.artifact &&
|
|
141
141
|
artifactUrl) {
|
|
@@ -154,36 +154,6 @@ export function CaptureStreamLayer({ descriptor, meshPresentation, packets, rend
|
|
|
154
154
|
return content;
|
|
155
155
|
return (_jsx("group", { matrix: frameMatrix, matrixAutoUpdate: false, children: content }));
|
|
156
156
|
}
|
|
157
|
-
function useJsonArtifactPayload(url) {
|
|
158
|
-
const [error, setError] = useState(null);
|
|
159
|
-
const [payload, setPayload] = useState(null);
|
|
160
|
-
useEffect(() => {
|
|
161
|
-
setError(null);
|
|
162
|
-
setPayload(null);
|
|
163
|
-
if (!url)
|
|
164
|
-
return;
|
|
165
|
-
const abort = new AbortController();
|
|
166
|
-
void fetch(rewriteLoopbackAssetUrl(url), { signal: abort.signal })
|
|
167
|
-
.then(async (response) => {
|
|
168
|
-
if (!response.ok)
|
|
169
|
-
throw new Error(`Could not load ${url}: ${response.status}`);
|
|
170
|
-
return (await response.json());
|
|
171
|
-
})
|
|
172
|
-
.then((data) => {
|
|
173
|
-
if (!abort.signal.aborted)
|
|
174
|
-
setPayload(data);
|
|
175
|
-
})
|
|
176
|
-
.catch((cause) => {
|
|
177
|
-
if (abort.signal.aborted)
|
|
178
|
-
return;
|
|
179
|
-
setError(cause instanceof Error ? cause : new Error(`Could not load ${url}.`));
|
|
180
|
-
});
|
|
181
|
-
return () => abort.abort();
|
|
182
|
-
}, [url]);
|
|
183
|
-
if (error)
|
|
184
|
-
throw error;
|
|
185
|
-
return payload;
|
|
186
|
-
}
|
|
187
157
|
function useResolvedArtifact(source, artifact) {
|
|
188
158
|
const [error, setError] = useState(null);
|
|
189
159
|
const [url, setUrl] = useState(null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device-motion-layer.d.ts","sourceRoot":"","sources":["../../../src/capture/layers/device-motion-layer.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,KAAK,gBAAgB,EAA0B,MAAM,eAAe,CAAA;AAE7E,eAAO,MAAM,4BAA4B,IAAI,CAAA;AAE7C,wBAAgB,wBAAwB,CAAC,EACvC,SAAe,EACf,UAAU,GACX,EAAE;IACD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,gBAAgB,CAAA;CAC7B,+
|
|
1
|
+
{"version":3,"file":"device-motion-layer.d.ts","sourceRoot":"","sources":["../../../src/capture/layers/device-motion-layer.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,KAAK,gBAAgB,EAA0B,MAAM,eAAe,CAAA;AAE7E,eAAO,MAAM,4BAA4B,IAAI,CAAA;AAE7C,wBAAgB,wBAAwB,CAAC,EACvC,SAAe,EACf,UAAU,GACX,EAAE;IACD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,gBAAgB,CAAA;CAC7B,+BA2CA"}
|
|
@@ -36,7 +36,7 @@ export function CaptureDeviceMotionLayer({ lineWidth = 2.5, trajectory, }) {
|
|
|
36
36
|
deviceRef.current.position.copy(position);
|
|
37
37
|
deviceRef.current.quaternion.slerpQuaternions(fromQuaternion, toQuaternion, frame.alpha);
|
|
38
38
|
});
|
|
39
|
-
return (_jsxs("group", { children: [trajectorySegments.map(({ points, segment }) => (_jsx(CaptureLine, { color: "#
|
|
39
|
+
return (_jsxs("group", { children: [trajectorySegments.map(({ points, segment }) => (_jsx(CaptureLine, { color: "#39ff14", lineWidth: lineWidth, points: points }, segment))), _jsx("group", { ref: deviceRef, children: _jsx(CameraFrustum, { lineWidth: lineWidth }) })] }));
|
|
40
40
|
}
|
|
41
41
|
function CameraFrustum({ lineWidth }) {
|
|
42
42
|
const apex = [0, 0, 0];
|
|
@@ -52,24 +52,22 @@ function CameraFrustum({ lineWidth }) {
|
|
|
52
52
|
[bottomLeft, bottomRight],
|
|
53
53
|
[bottomRight, topRight],
|
|
54
54
|
].flat();
|
|
55
|
-
return (_jsxs("group", { children: [_jsx(CaptureLine, { color: "#
|
|
55
|
+
return (_jsxs("group", { scale: 1.35, children: [_jsx(CaptureLine, { color: "#ffee00", lineWidth: lineWidth, points: points, segments: true }), _jsxs("mesh", { children: [_jsx("sphereGeometry", { args: [0.035, 12, 12] }), _jsx("meshBasicMaterial", { color: "#ffee00", toneMapped: false })] })] }));
|
|
56
56
|
}
|
|
57
|
-
function CaptureLine({ color, lineWidth,
|
|
57
|
+
function CaptureLine({ color, lineWidth, points, segments = false, }) {
|
|
58
58
|
const line = useMemo(() => {
|
|
59
59
|
const geometry = new BufferGeometry().setFromPoints(points.map(([x, y, z]) => new Vector3(x, y, z)));
|
|
60
60
|
const material = new LineBasicMaterial({
|
|
61
61
|
color,
|
|
62
|
-
depthWrite: opacity >= 1,
|
|
63
62
|
linewidth: lineWidth,
|
|
64
|
-
|
|
65
|
-
transparent: opacity < 1,
|
|
63
|
+
toneMapped: false,
|
|
66
64
|
});
|
|
67
65
|
const object = segments
|
|
68
66
|
? new LineSegments(geometry, material)
|
|
69
67
|
: new ThreeLine(geometry, material);
|
|
70
68
|
object.frustumCulled = false;
|
|
71
69
|
return object;
|
|
72
|
-
}, [color, lineWidth,
|
|
70
|
+
}, [color, lineWidth, points, segments]);
|
|
73
71
|
useEffect(() => () => {
|
|
74
72
|
line.geometry.dispose();
|
|
75
73
|
line.material.dispose();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-rendering.d.ts","sourceRoot":"","sources":["../../src/capture/stream-rendering.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAK7B,MAAM,0BAA0B,CAAA;AAOjC,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,CAAA;AAEhD,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,uBAAuB,EAC/B,kBAAkB,GAAE,WAAW,CAAC,MAAM,CAAa,GAClD,OAAO,
|
|
1
|
+
{"version":3,"file":"stream-rendering.d.ts","sourceRoot":"","sources":["../../src/capture/stream-rendering.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAK7B,MAAM,0BAA0B,CAAA;AAOjC,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,CAAA;AAEhD,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,uBAAuB,EAC/B,kBAAkB,GAAE,WAAW,CAAC,MAAM,CAAa,GAClD,OAAO,CA4BT;AAID;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAKlF;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,SAAS,GAAG,OAAO,CAE9F;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,wBAAwB,GAAG,SAAS,GAC7C,kBAAkB,GAAG,IAAI,CAS3B;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,wBAAwB,GAAG,SAAS,GAC7C,OAAO,CAGT"}
|
|
@@ -9,8 +9,9 @@ export function isCaptureStreamRenderable(stream, customRendererKeys = new Set()
|
|
|
9
9
|
const layerKey = captureLayerKey(stream);
|
|
10
10
|
if (customRendererKeys.has(layerKey) || customRendererKeys.has(stream.kind))
|
|
11
11
|
return true;
|
|
12
|
-
if (layerKey === 'model')
|
|
12
|
+
if (layerKey === 'model' || layerKey === 'spaceformScene') {
|
|
13
13
|
return isCaptureModelArtifact(stream.artifact);
|
|
14
|
+
}
|
|
14
15
|
if (layerKey === 'deviceMotion') {
|
|
15
16
|
return (stream.availability === 'live' ||
|
|
16
17
|
streamHydratesJsonPayload(stream) ||
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-json-artifact.d.ts","sourceRoot":"","sources":["../../src/capture/use-json-artifact.ts"],"names":[],"mappings":"AAgBA,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAgClE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { FileLoader } from 'three';
|
|
3
|
+
import { rewriteLoopbackAssetUrl } from './asset-url';
|
|
4
|
+
const requests = new Map();
|
|
5
|
+
function loadJsonArtifact(url) {
|
|
6
|
+
const cached = requests.get(url);
|
|
7
|
+
if (cached)
|
|
8
|
+
return cached;
|
|
9
|
+
const request = new FileLoader().setResponseType('json').loadAsync(url);
|
|
10
|
+
requests.set(url, request);
|
|
11
|
+
// Keep successful downloads across view switches, but let a remount retry failures.
|
|
12
|
+
void request.catch(() => requests.delete(url));
|
|
13
|
+
return request;
|
|
14
|
+
}
|
|
15
|
+
export function useJsonArtifactPayload(url) {
|
|
16
|
+
const resolvedUrl = url ? rewriteLoopbackAssetUrl(url) : null;
|
|
17
|
+
const [result, setResult] = useState(null);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!resolvedUrl)
|
|
20
|
+
return;
|
|
21
|
+
let active = true;
|
|
22
|
+
void loadJsonArtifact(resolvedUrl).then((payload) => {
|
|
23
|
+
if (active)
|
|
24
|
+
setResult({ url: resolvedUrl, payload });
|
|
25
|
+
}, (cause) => {
|
|
26
|
+
if (active) {
|
|
27
|
+
setResult({
|
|
28
|
+
url: resolvedUrl,
|
|
29
|
+
error: cause instanceof Error ? cause : new Error('Could not load capture data.'),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return () => {
|
|
34
|
+
active = false;
|
|
35
|
+
};
|
|
36
|
+
}, [resolvedUrl]);
|
|
37
|
+
if (!result || result.url !== resolvedUrl)
|
|
38
|
+
return null;
|
|
39
|
+
if (result.error)
|
|
40
|
+
throw result.error;
|
|
41
|
+
return result.payload ?? null;
|
|
42
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glb-scene.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/glb-scene.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAkC,MAAM,kBAAkB,CAAA;AAc/E,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAqB3E,2EAA2E;AAC3E,MAAM,MAAM,QAAQ,GAAG;IAAE,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/D,4EAA4E;AAC5E,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAEzE,mFAAmF;AACnF,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAA;AAE7D;8EAC8E;AAC9E,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;CAChD,GAAG,IAAI,CAAA;AA8NR;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,mBAAmB,GACpB,EAAE;IACD,GAAG,EAAE,MAAM,CAAA;IACX;oFACgF;IAChF,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,CAAA;IACvC;mFAC+E;IAC/E,cAAc,CAAC,EAAE,OAAO,EAAE,CAAA;IAC1B;kFAC8E;IAC9E,YAAY,CAAC,EAAE,OAAO,EAAE,CAAA;IACxB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAA;IAC7C,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,CAAA;IAClD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAA;IACzC,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAA;CACtD,+
|
|
1
|
+
{"version":3,"file":"glb-scene.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/glb-scene.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAkC,MAAM,kBAAkB,CAAA;AAc/E,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAqB3E,2EAA2E;AAC3E,MAAM,MAAM,QAAQ,GAAG;IAAE,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/D,4EAA4E;AAC5E,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAEzE,mFAAmF;AACnF,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAA;AAE7D;8EAC8E;AAC9E,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;CAChD,GAAG,IAAI,CAAA;AA8NR;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,mBAAmB,GACpB,EAAE;IACD,GAAG,EAAE,MAAM,CAAA;IACX;oFACgF;IAChF,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,CAAA;IACvC;mFAC+E;IAC/E,cAAc,CAAC,EAAE,OAAO,EAAE,CAAA;IAC1B;kFAC8E;IAC9E,YAAY,CAAC,EAAE,OAAO,EAAE,CAAA;IACxB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAA;IAC7C,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,CAAA;IAClD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAA;IACzC,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAA;CACtD,+BAkzBA"}
|
|
@@ -483,7 +483,9 @@ export function GlbScene({ url, interactiveItems, referenceNodes, replaceNodes,
|
|
|
483
483
|
const targetY = baseY + (exploded ? index * EXPLODED_GAP : 0);
|
|
484
484
|
// Snap (not lerp) in walkthrough so the first-person collider, built from
|
|
485
485
|
// these world positions, matches the stacked building immediately.
|
|
486
|
-
node.position.y = walkthroughMode
|
|
486
|
+
node.position.y = walkthroughMode
|
|
487
|
+
? targetY
|
|
488
|
+
: lerp(node.position.y, targetY, Math.min(1, delta * 12));
|
|
487
489
|
// Solo: hidden levels above the soloed one keep casting shadows
|
|
488
490
|
// (shadow-caster-only); below-levels can't block the sun, so plain-hide.
|
|
489
491
|
const hidden = !walkthroughMode && levelMode === 'solo' && Boolean(selectedLevel) && id !== selectedLevel;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type AnyNodeId } from '@pascal-app/core';
|
|
2
2
|
import { type ThreeElement } from '@react-three/fiber';
|
|
3
|
+
import { type ComponentType } from 'react';
|
|
3
4
|
import * as THREE from 'three/webgpu';
|
|
4
5
|
import type { ColorPreset, RenderShading } from '../../lib/materials';
|
|
5
6
|
import { type RenderContext } from '../../store/use-viewer';
|
|
@@ -9,6 +10,15 @@ declare module '@react-three/fiber' {
|
|
|
9
10
|
lineBasicNodeMaterial: ThreeElement<typeof THREE.LineBasicNodeMaterial>;
|
|
10
11
|
}
|
|
11
12
|
}
|
|
13
|
+
export interface ViewerImmersiveSession {
|
|
14
|
+
Session: ComponentType<{
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
}>;
|
|
17
|
+
Scene: ComponentType<{
|
|
18
|
+
children: React.ReactNode;
|
|
19
|
+
}>;
|
|
20
|
+
onError?: (cause: unknown) => void;
|
|
21
|
+
}
|
|
12
22
|
interface ViewerProps {
|
|
13
23
|
children?: React.ReactNode;
|
|
14
24
|
hoverStyles?: HoverStyles;
|
|
@@ -69,6 +79,8 @@ interface ViewerProps {
|
|
|
69
79
|
disablePostFx?: boolean;
|
|
70
80
|
/** Keep the mounted renderer/context warm without advancing scene frames. */
|
|
71
81
|
renderPaused?: boolean;
|
|
82
|
+
/** Host-provided immersive XR session wrappers for the main scene. */
|
|
83
|
+
immersive?: ViewerImmersiveSession;
|
|
72
84
|
}
|
|
73
85
|
/** Imperative handle exposed via `ref` on `<Viewer>`. */
|
|
74
86
|
export type ViewerHandle = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,SAAS,EAMf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAkB,KAAK,YAAY,EAAsB,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,SAAS,EAMf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAkB,KAAK,YAAY,EAAsB,MAAM,oBAAoB,CAAA;AAC1F,OAAO,EACL,KAAK,aAAa,EAOnB,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAKrC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAKrE,OAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAA;AActE,OAAuB,EAAwB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAY1F,OAAO,QAAQ,oBAAoB,CAAC;IAOlC,UAAU,aAAa;QACrB,qBAAqB,EAAE,YAAY,CAAC,OAAO,KAAK,CAAC,qBAAqB,CAAC,CAAA;KACxE;CACF;AAoRD,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;KAAE,CAAC,CAAA;IACrD,KAAK,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;KAAE,CAAC,CAAA;IACnD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CACnC;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,gBAAgB,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;IACvC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,aAAa,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,aAAa,CAAA;QACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,WAAW,CAAC,EAAE,WAAW,CAAA;KAC1B,CAAA;IACD;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;IAC5B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACtC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAC7C;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,sEAAsE;IACtE,SAAS,CAAC,EAAE,sBAAsB,CAAA;CACnC;AAED,yDAAyD;AACzD,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;OAKG;IACH,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;CAC3C,CAAA;AAED,QAAA,MAAM,MAAM,sGAuPV,CAAA;AAyEF,eAAe,MAAM,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx,
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { nodeRegistry, RoofElevationSystem, StairOpeningSystem, sceneRegistry, useScene, } from '@pascal-app/core';
|
|
4
4
|
import { Canvas, extend, useFrame, useThree } from '@react-three/fiber';
|
|
5
5
|
import { forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState, } from 'react';
|
|
@@ -17,6 +17,7 @@ import { FloorElevationSystem } from '../../systems/floor-elevation/floor-elevat
|
|
|
17
17
|
import { GeometrySystem } from '../../systems/geometry/geometry-system';
|
|
18
18
|
import { PerfActionSettleSystem } from '../../systems/perf-action-settle/perf-action-settle-system';
|
|
19
19
|
import { subscribeWallBuildInteractions } from '../../systems/wall/wall-build-lifecycle';
|
|
20
|
+
import { ImmersiveXRPresentationProvider } from '../../xr/presentation-context';
|
|
20
21
|
import { ErrorBoundary } from '../error-boundary';
|
|
21
22
|
import { SceneRenderer } from '../renderers/scene-renderer';
|
|
22
23
|
import { BATCH_SPIKE_ENABLED, BatchedMeshSpike } from './batched-mesh-spike';
|
|
@@ -94,7 +95,7 @@ function installEmptyDrawGuard(renderer) {
|
|
|
94
95
|
renderer.renderObject(object, scene, camera, geometry, material, group, lightsNode, clippingContext, passId);
|
|
95
96
|
});
|
|
96
97
|
}
|
|
97
|
-
function GPUDeviceWatcher() {
|
|
98
|
+
function GPUDeviceWatcher({ intentionalWebGL = false }) {
|
|
98
99
|
const gl = useThree((s) => s.gl);
|
|
99
100
|
useEffect(() => {
|
|
100
101
|
// Detect KTX2 transcode support as soon as the renderer exists, so catalog
|
|
@@ -103,13 +104,15 @@ function GPUDeviceWatcher() {
|
|
|
103
104
|
ensureKtx2Support(gl);
|
|
104
105
|
const backend = gl.backend;
|
|
105
106
|
const device = backend?.device;
|
|
106
|
-
if (!device) {
|
|
107
|
+
if (!device && !intentionalWebGL) {
|
|
107
108
|
console.warn('[viewer] No WebGPU device on backend — running on a fallback renderer.', {
|
|
108
109
|
backend: backend?.constructor?.name ?? 'unknown',
|
|
109
110
|
rendererType: gl.constructor?.name ?? 'unknown',
|
|
110
111
|
});
|
|
111
112
|
return;
|
|
112
113
|
}
|
|
114
|
+
if (!device)
|
|
115
|
+
return;
|
|
113
116
|
console.log('[viewer] WebGPU device ready', {
|
|
114
117
|
label: device.label,
|
|
115
118
|
features: Array.from(device.features ?? []),
|
|
@@ -127,7 +130,7 @@ function GPUDeviceWatcher() {
|
|
|
127
130
|
return () => {
|
|
128
131
|
device.removeEventListener?.('uncapturederror', onUncapturedError);
|
|
129
132
|
};
|
|
130
|
-
}, [gl]);
|
|
133
|
+
}, [gl, intentionalWebGL]);
|
|
131
134
|
return null;
|
|
132
135
|
}
|
|
133
136
|
function ToneMappingExposure() {
|
|
@@ -148,6 +151,10 @@ function ToneMappingExposure() {
|
|
|
148
151
|
}, -1);
|
|
149
152
|
return null;
|
|
150
153
|
}
|
|
154
|
+
function ImmersiveXRBackground() {
|
|
155
|
+
const background = useViewer((state) => getSceneTheme(state.sceneTheme).background);
|
|
156
|
+
return _jsx("color", { args: [background], attach: "background" });
|
|
157
|
+
}
|
|
151
158
|
function hasPendingSceneBuildWork() {
|
|
152
159
|
const { dirtyNodes, nodes, rootNodeIds } = useScene.getState();
|
|
153
160
|
for (const id of dirtyNodes) {
|
|
@@ -226,7 +233,7 @@ function SceneReadyTracker({ onSceneReadyChange, sceneReadyKey, sceneReadyMaxWai
|
|
|
226
233
|
}, 10);
|
|
227
234
|
return null;
|
|
228
235
|
}
|
|
229
|
-
const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVER_STYLES, selectionManager = 'default', perf = false, useBvh = true, renderContext = 'editor', transparent, defaultRender, isolate, sceneReadyKey, onSceneReadyChange, sceneReadyMaxWaitMs, maxFps = 50, disablePostFx = false, renderPaused = false, }, ref) {
|
|
236
|
+
const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVER_STYLES, selectionManager = 'default', perf = false, useBvh = true, renderContext = 'editor', transparent, defaultRender, isolate, sceneReadyKey, onSceneReadyChange, sceneReadyMaxWaitMs, maxFps = 50, disablePostFx = false, renderPaused = false, immersive, }, ref) {
|
|
230
237
|
useEffect(() => {
|
|
231
238
|
if (nodeRegistry.size === 0) {
|
|
232
239
|
console.warn('[viewer] Node registry is empty. Install @pascal-app/nodes and call await loadPlugin(builtinPlugin) before mounting <Viewer>.');
|
|
@@ -313,16 +320,25 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
|
|
|
313
320
|
if (showGpuFallback)
|
|
314
321
|
onSceneReadyChange?.(true);
|
|
315
322
|
}, [showGpuFallback, onSceneReadyChange]);
|
|
323
|
+
useEffect(() => {
|
|
324
|
+
if (!immersive)
|
|
325
|
+
return;
|
|
326
|
+
const timeout = window.setTimeout(() => window.dispatchEvent(new Event('resize')), 0);
|
|
327
|
+
return () => window.clearTimeout(timeout);
|
|
328
|
+
}, [immersive]);
|
|
329
|
+
const ImmersiveSession = immersive?.Session;
|
|
330
|
+
const immersiveActive = immersive != null;
|
|
316
331
|
if (showGpuFallback) {
|
|
317
332
|
return _jsx(UnsupportedGpuViewerFallback, {});
|
|
318
333
|
}
|
|
319
|
-
return (_jsxs(_Fragment, { children: [(perf || PERF_OVERLAY_ENABLED) && _jsx(PerfPanel, {}),
|
|
334
|
+
return (_jsxs(_Fragment, { children: [(perf || PERF_OVERLAY_ENABLED) && _jsx(PerfPanel, {}), _jsx(Canvas, { ref: subscribeWallBuildInteractions, camera: { position: [50, 50, 50], fov: 50 }, className: `transition-colors duration-700 ${transparentBackground ? 'bg-transparent' : isDark ? 'bg-[#1f2433]' : 'bg-[#fafafa]'}`, dpr: [1, maxDpr], events: pointerEvents, frameloop: "never", gl: ((props) => {
|
|
320
335
|
const canvas = props.canvas;
|
|
321
336
|
const cached = canvas ? WEBGPU_RENDERER_CACHE.get(canvas) : undefined;
|
|
322
337
|
if (cached)
|
|
323
338
|
return cached;
|
|
324
339
|
const promise = (async () => {
|
|
325
340
|
const result = await initializeGpuRenderer({
|
|
341
|
+
forceWebGL: immersiveActive,
|
|
326
342
|
// Supplying `device` makes three skip its own `requestAdapter`,
|
|
327
343
|
// so R3F's `powerPreference` only reaches the GPU if we forward it.
|
|
328
344
|
powerPreference: props.powerPreference,
|
|
@@ -366,6 +382,11 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
|
|
|
366
382
|
}, shadows: {
|
|
367
383
|
type: THREE.PCFShadowMap,
|
|
368
384
|
enabled: shadowsEnabled,
|
|
369
|
-
}, children:
|
|
385
|
+
}, children: _jsx(ImmersiveXRPresentationProvider, { enabled: immersiveActive, children: ImmersiveSession ? (_jsx(ImmersiveSession, { children: _jsx(ViewerScene, { disablePostFx: true, hoverStyles: hoverStyles, immersiveXR: true, onRenderError: immersive.onError, onSceneReadyChange: onSceneReadyChange, perf: perf, sceneReadyKey: sceneReadyKey, sceneReadyMaxWaitMs: sceneReadyMaxWaitMs, selectionManager: selectionManager, useBvh: useBvh, SceneWrapper: immersive.Scene, children: children }) })) : (_jsxs(_Fragment, { children: [_jsx(FrameLimiter, { fps: maxFps, paused: renderPaused }), _jsx(ViewerScene, { disablePostFx: disablePostFx, hoverStyles: hoverStyles, onSceneReadyChange: onSceneReadyChange, perf: perf, sceneReadyKey: sceneReadyKey, sceneReadyMaxWaitMs: sceneReadyMaxWaitMs, selectionManager: selectionManager, useBvh: useBvh, children: children })] })) }) }, immersiveActive ? 'webgl-xr' : 'webgpu')] }));
|
|
370
386
|
});
|
|
387
|
+
function ViewerScene({ children, disablePostFx, hoverStyles, immersiveXR = false, onRenderError, onSceneReadyChange, perf, sceneReadyKey, sceneReadyMaxWaitMs, selectionManager, useBvh, SceneWrapper, }) {
|
|
388
|
+
const renderedScene = useBvh ? (_jsx(SceneBvh, { children: _jsx(SceneRenderer, {}) })) : (_jsx(SceneRenderer, {}));
|
|
389
|
+
const spatialScene = (_jsxs(_Fragment, { children: [renderedScene, _jsx(FloorElevationSystem, {}), _jsx(GeometrySystem, {}), _jsx(StairOpeningSystem, {}), _jsx(RoofElevationSystem, {}), _jsx(RegisteredSystems, {}), BATCH_SPIKE_ENABLED && _jsx(BatchedMeshSpike, {}), children] }));
|
|
390
|
+
return (_jsxs(_Fragment, { children: [_jsx(ViewerCamera, { immersiveXR: immersiveXR }), immersiveXR && _jsx(ImmersiveXRBackground, {}), _jsx(PointerRaycastLayers, {}), _jsx(GPUDeviceWatcher, { intentionalWebGL: immersiveXR }), _jsx(ToneMappingExposure, {}), _jsx(SceneReadyTracker, { onSceneReadyChange: onSceneReadyChange, sceneReadyKey: sceneReadyKey, sceneReadyMaxWaitMs: sceneReadyMaxWaitMs }), _jsxs(ErrorBoundary, { fallback: null, onError: onRenderError, scope: "viewer-scene", children: [_jsx(Lights, {}), SceneWrapper ? _jsx(SceneWrapper, { children: spatialScene }) : spatialScene, !immersiveXR && _jsx(PostProcessing, { disablePostFx: disablePostFx, hoverStyles: hoverStyles }), selectionManager === 'default' && _jsx(SelectionManager, {}), (perf || PERF_OVERLAY_ENABLED) && _jsx(PerfMonitor, {}), (perf || PERF_OVERLAY_ENABLED) && _jsx(PerfActionSettleSystem, {})] })] }));
|
|
391
|
+
}
|
|
371
392
|
export default Viewer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"post-processing.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/post-processing.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"post-processing.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/post-processing.tsx"],"names":[],"mappings":"AA8CA,eAAO,MAAM,YAAY;;;CAGxB,CAAA;AAGD,eAAO,MAAM,WAAW;;;;;;;;;;;;;CAavB,CAAA;AAgED,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;AA+CD,QAAA,MAAM,oBAAoB,GAAI,iCAG3B;IACD,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,SAmnBA,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
|
@@ -9,6 +9,7 @@ import { backdropGradient, deepSkyColor, horizonHazeColor } from '../../lib/back
|
|
|
9
9
|
import { edgeColorFor, edgeOpacityScaleFor } from '../../lib/edge-style';
|
|
10
10
|
import { PERF_OVERLAY_ENABLED } from '../../lib/gpu-perf';
|
|
11
11
|
import { inkedEdges } from '../../lib/ink-edges';
|
|
12
|
+
import { refreshIsolation } from '../../lib/isolation';
|
|
12
13
|
import { LayerPassIndex, LayerPassNode } from '../../lib/layer-pass';
|
|
13
14
|
import { GRID_LAYER, OVERLAY_LAYER, SCENE_LAYER, ZONE_LAYER } from '../../lib/layers';
|
|
14
15
|
import { mergedOutline } from '../../lib/merged-outline-node';
|
|
@@ -612,6 +613,7 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
612
613
|
inkColorUniform.current.value.set(edgeColorFor(bgHex));
|
|
613
614
|
inkOpacityScaleUniform.current.value = edgeOpacityScaleFor(bgHex);
|
|
614
615
|
const outliner = useViewer.getState().outliner;
|
|
616
|
+
const restoreAtmosphere = refreshIsolation(scene);
|
|
615
617
|
sanitizeOutlineObjects(outliner.selectedObjects);
|
|
616
618
|
sanitizeOutlineObjects(outliner.hoveredObjects);
|
|
617
619
|
if (disablePostFx ||
|
|
@@ -644,6 +646,7 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
644
646
|
}
|
|
645
647
|
finally {
|
|
646
648
|
scene.backgroundNode = previousBackgroundNode;
|
|
649
|
+
restoreAtmosphere();
|
|
647
650
|
}
|
|
648
651
|
return;
|
|
649
652
|
}
|
|
@@ -681,6 +684,9 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
681
684
|
console.error('[viewer/post-processing] Retries exhausted. Rendering without post FX for this session.');
|
|
682
685
|
}
|
|
683
686
|
}
|
|
687
|
+
finally {
|
|
688
|
+
restoreAtmosphere();
|
|
689
|
+
}
|
|
684
690
|
}, 1);
|
|
685
691
|
return null;
|
|
686
692
|
};
|
|
@@ -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":"AAqSA,eAAO,MAAM,gBAAgB,mCA0G5B,CAAA"}
|
|
@@ -40,25 +40,15 @@ const pointInPolygonWithTolerance = (x, z, polygon) => {
|
|
|
40
40
|
const expanded = expandPolygon(polygon, EDGE_TOLERANCE);
|
|
41
41
|
return pointInPolygon(x, z, expanded);
|
|
42
42
|
};
|
|
43
|
-
// Check if a node belongs to the selected level (directly or via wall parent)
|
|
44
43
|
const isNodeOnLevel = (node, levelId) => {
|
|
45
44
|
const nodes = useScene.getState().nodes;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if ((node.type === 'item' || node.type === 'window' || node.type === 'door') && node.parentId) {
|
|
51
|
-
const parentNode = nodes[node.parentId];
|
|
52
|
-
if (parentNode?.type === 'wall' && parentNode.parentId === levelId) {
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
// Ceiling/slab/roof-attached items: check if parent structure is on the level
|
|
56
|
-
if ((parentNode?.type === 'ceiling' ||
|
|
57
|
-
parentNode?.type === 'slab' ||
|
|
58
|
-
parentNode?.type === 'roof') &&
|
|
59
|
-
parentNode.parentId === levelId) {
|
|
45
|
+
const seen = new Set();
|
|
46
|
+
let parentId = node.parentId;
|
|
47
|
+
while (parentId && !seen.has(parentId)) {
|
|
48
|
+
if (parentId === levelId)
|
|
60
49
|
return true;
|
|
61
|
-
|
|
50
|
+
seen.add(parentId);
|
|
51
|
+
parentId = nodes[parentId]?.parentId ?? null;
|
|
62
52
|
}
|
|
63
53
|
return false;
|
|
64
54
|
};
|
|
@@ -187,6 +177,7 @@ const getStrategy = () => {
|
|
|
187
177
|
'roof-segment',
|
|
188
178
|
'window',
|
|
189
179
|
'door',
|
|
180
|
+
...getSelectableKinds(),
|
|
190
181
|
],
|
|
191
182
|
handleClick: (node, nativeEvent) => {
|
|
192
183
|
let nodeToSelect = node;
|
|
@@ -224,6 +215,7 @@ const getStrategy = () => {
|
|
|
224
215
|
'roof-segment',
|
|
225
216
|
'window',
|
|
226
217
|
'door',
|
|
218
|
+
...getSelectableKinds(),
|
|
227
219
|
];
|
|
228
220
|
if (!validTypes.includes(node.type))
|
|
229
221
|
return false;
|
|
@@ -1,2 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Layers } from 'three';
|
|
2
|
+
export declare function enableImmersiveXRViewLayers(cameraLayers: Layers, raycasterLayers: Layers): () => void;
|
|
3
|
+
export declare function viewerCameraClipping(immersiveXR: boolean): {
|
|
4
|
+
far: number;
|
|
5
|
+
near: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function applyViewerCameraClipping(camera: {
|
|
8
|
+
far: number;
|
|
9
|
+
near: number;
|
|
10
|
+
updateProjectionMatrix(): void;
|
|
11
|
+
}, immersiveXR: boolean): void;
|
|
12
|
+
export declare function viewerUsesPerspectiveCamera(cameraMode: string, immersiveXR: boolean): boolean;
|
|
13
|
+
export declare const ViewerCamera: ({ immersiveXR }: {
|
|
14
|
+
immersiveXR?: boolean;
|
|
15
|
+
}) => import("react").JSX.Element;
|
|
2
16
|
//# sourceMappingURL=viewer-camera.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewer-camera.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/viewer-camera.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"viewer-camera.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/viewer-camera.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAOnC,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,cAWxF;AAcD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,OAAO;;;EAExD;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,sBAAsB,IAAI,IAAI,CAAA;CAAE,EACrE,WAAW,EAAE,OAAO,QAMrB;AAED,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,WAEnF;AAED,eAAO,MAAM,YAAY,GAAI,iBAAyB;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,gCAqB9E,CAAA"}
|
|
@@ -1,10 +1,48 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { OrthographicCamera, PerspectiveCamera } from '@react-three/drei';
|
|
3
|
+
import { useThree } from '@react-three/fiber';
|
|
4
|
+
import { useEffect } from 'react';
|
|
5
|
+
import { GRID_LAYER, OVERLAY_LAYER, ZONE_LAYER } from '../../lib/layers';
|
|
3
6
|
import useViewer from '../../store/use-viewer';
|
|
4
7
|
import { useSceneGroundReplacement } from './scene-ground-replacement';
|
|
5
|
-
|
|
8
|
+
const IMMERSIVE_XR_VISIBLE_LAYERS = [OVERLAY_LAYER, ZONE_LAYER, GRID_LAYER];
|
|
9
|
+
export function enableImmersiveXRViewLayers(cameraLayers, raycasterLayers) {
|
|
10
|
+
const cameraMask = cameraLayers.mask;
|
|
11
|
+
const raycasterMask = raycasterLayers.mask;
|
|
12
|
+
for (const layer of IMMERSIVE_XR_VISIBLE_LAYERS) {
|
|
13
|
+
cameraLayers.enable(layer);
|
|
14
|
+
raycasterLayers.enable(layer);
|
|
15
|
+
}
|
|
16
|
+
return () => {
|
|
17
|
+
cameraLayers.mask = cameraMask;
|
|
18
|
+
raycasterLayers.mask = raycasterMask;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function ImmersiveXRViewLayers({ enabled }) {
|
|
22
|
+
const camera = useThree((state) => state.camera);
|
|
23
|
+
const raycaster = useThree((state) => state.raycaster);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!enabled)
|
|
26
|
+
return;
|
|
27
|
+
return enableImmersiveXRViewLayers(camera.layers, raycaster.layers);
|
|
28
|
+
}, [camera, enabled, raycaster]);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
export function viewerCameraClipping(immersiveXR) {
|
|
32
|
+
return immersiveXR ? { far: 10_000, near: 0.001 } : { far: 1000, near: 0.1 };
|
|
33
|
+
}
|
|
34
|
+
export function applyViewerCameraClipping(camera, immersiveXR) {
|
|
35
|
+
const clipping = viewerCameraClipping(immersiveXR);
|
|
36
|
+
camera.far = clipping.far;
|
|
37
|
+
camera.near = clipping.near;
|
|
38
|
+
camera.updateProjectionMatrix();
|
|
39
|
+
}
|
|
40
|
+
export function viewerUsesPerspectiveCamera(cameraMode, immersiveXR) {
|
|
41
|
+
return immersiveXR || cameraMode === 'perspective';
|
|
42
|
+
}
|
|
43
|
+
export const ViewerCamera = ({ immersiveXR = false }) => {
|
|
6
44
|
const cameraMode = useViewer((state) => state.cameraMode);
|
|
7
|
-
|
|
8
|
-
const far = useSceneGroundReplacement() ? 20_000 :
|
|
9
|
-
return cameraMode
|
|
45
|
+
const clipping = viewerCameraClipping(immersiveXR);
|
|
46
|
+
const far = useSceneGroundReplacement() ? 20_000 : clipping.far;
|
|
47
|
+
return (_jsxs(_Fragment, { children: [viewerUsesPerspectiveCamera(cameraMode, immersiveXR) ? (_jsx(PerspectiveCamera, { far: far, fov: 50, makeDefault: true, near: clipping.near, position: [10, 10, 10] })) : (_jsx(OrthographicCamera, { far: 1000, makeDefault: true, near: -1000, position: [10, 10, 10], zoom: 20 })), _jsx(ImmersiveXRViewLayers, { enabled: immersiveXR })] }));
|
|
10
48
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type { SurfaceRole } from '@pascal-app/core';
|
|
2
2
|
export { ErrorBoundary } from './components/error-boundary';
|
|
3
3
|
export { NodeRenderer } from './components/renderers/node-renderer';
|
|
4
|
-
export { default as Viewer, type ViewerHandle } from './components/viewer';
|
|
4
|
+
export { default as Viewer, type ViewerHandle, type ViewerImmersiveSession, } from './components/viewer';
|
|
5
5
|
export { type BVHEcctrlApi, default as BVHEcctrl, type MovementInput, } from './components/viewer/bvh-ecctrl';
|
|
6
6
|
export { buildGlbInteractiveItems, GlbInteractive, type GlbInteractiveItem, } from './components/viewer/glb-interactive';
|
|
7
7
|
export { buildGlbReferenceNodes, buildGlbReplaceNodes, } from './components/viewer/glb-reference-nodes';
|
|
@@ -20,12 +20,12 @@ export { useNodeEvents } from './hooks/use-node-events';
|
|
|
20
20
|
export { ASSETS_CDN_URL, resolveAssetUrl, resolveCdnUrl } from './lib/asset-url';
|
|
21
21
|
export { backdropGradient, deepSkyColor, horizonHazeColor } from './lib/backdrop';
|
|
22
22
|
export { applyWorldScaleBoxUVs } from './lib/box-uv';
|
|
23
|
-
export { ADDITION, Brush, computeGeometryBoundsTree, csgEvaluator, csgGeometry, csgMaterials, INTERSECTION, prepareBrushForCSG, SUBTRACTION, } from './lib/csg-utils';
|
|
23
|
+
export { ADDITION, Brush, computeGeometryBoundsTree, csgEvaluator, csgGeometry, csgMaterials, Evaluator, ensureRenderableGeometryAttributes, INTERSECTION, prepareBrushForCSG, SUBTRACTION, } from './lib/csg-utils';
|
|
24
24
|
export { disposeObject3DResources } from './lib/dispose-object3d';
|
|
25
25
|
export type { EdgeMode } from './lib/edge-style';
|
|
26
26
|
export { PERF_OVERLAY_ENABLED } from './lib/gpu-perf';
|
|
27
27
|
export { computeHeroFraming, DEFAULT_FRAMING_EXCLUDED_TYPES, type HeroFraming, heroCameraPose, temporarilyHideNodeTypes, unionRegisteredNodeBounds, } from './lib/hero-pose';
|
|
28
|
-
export { applyIsolation, clearIsolation, collectIsolationSubtree, isIsolationActive, } from './lib/isolation';
|
|
28
|
+
export { applyIsolation, clearIsolation, collectIsolationSubtree, isIsolationActive, refreshIsolation, } from './lib/isolation';
|
|
29
29
|
export { configureKtx2Support, ensureKtx2Support } from './lib/ktx2-loader';
|
|
30
30
|
export { LayerPassIndex } from './lib/layer-pass';
|
|
31
31
|
export { BATCHED_LAYER, GRID_LAYER, OVERLAY_LAYER, SCENE_LAYER, SHADOW_ONLY_LAYER, setSurfaceRaycastLayers, ZONE_LAYER, } from './lib/layers';
|
|
@@ -63,11 +63,13 @@ export { ScanSystem } from './systems/scan/scan-system';
|
|
|
63
63
|
export { generateSlabGeometry } from './systems/slab/slab-system';
|
|
64
64
|
export { getStairBodyMaterials, getStairRailingMaterial, getStraightStairSegmentBodyMaterials, type StairBodyMaterials, } from './systems/stair/stair-materials';
|
|
65
65
|
export { StairSystem } from './systems/stair/stair-system';
|
|
66
|
-
export { buildOpeningCutoutGeometry, getOpeningCutoutBottomPadding, hasFlatOpeningCutoutBottom, } from './systems/wall/opening-cutout-geometry';
|
|
66
|
+
export { buildOpeningCutoutGeometry, buildOpeningCutoutShape, getOpeningCutoutBottomPadding, hasFlatOpeningCutoutBottom, } from './systems/wall/opening-cutout-geometry';
|
|
67
67
|
export { getWallHideState, WallCutout } from './systems/wall/wall-cutout';
|
|
68
|
-
export {
|
|
69
|
-
export {
|
|
68
|
+
export { WallCutoutCache, type WallCutoutViewerState, type WallCutoutViewerStore, } from './systems/wall/wall-cutout-cache';
|
|
69
|
+
export { getMaterialsForWall, getVisibleWallMaterials, type WallMaterialOverride, type WallMaterials, type WallMaterialsResolver, } from './systems/wall/wall-materials';
|
|
70
|
+
export { drainRebuiltWalls, generateExtrudedWall, getPendingWallRebuildCount, isWallInitialBuildActive, runWallBuildFrame, type WallGeometryAdapter, type WallGeometryAdapterContext, WallSystem, } from './systems/wall/wall-system';
|
|
70
71
|
export { poseWindowMovingParts, WindowAnimationSystem, } from './systems/window/window-animation-system';
|
|
71
72
|
export { buildWindowPreviewMesh, WindowSystem } from './systems/window/window-system';
|
|
72
73
|
export { ZoneSystem } from './systems/zone/zone-system';
|
|
74
|
+
export { useImmersiveXRPresentation } from './xr/presentation-context';
|
|
73
75
|
//# 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":"AAKA,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAO3D,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAA;AACnE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|