@pascal-app/viewer 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/components/renderers/building/building-renderer.d.ts.map +1 -1
  2. package/dist/components/renderers/ceiling/ceiling-renderer.d.ts.map +1 -1
  3. package/dist/components/renderers/ceiling/ceiling-renderer.js +4 -3
  4. package/dist/components/renderers/door/door-renderer.d.ts.map +1 -1
  5. package/dist/components/renderers/door/door-renderer.js +5 -2
  6. package/dist/components/renderers/fence/fence-renderer.d.ts +5 -0
  7. package/dist/components/renderers/fence/fence-renderer.d.ts.map +1 -0
  8. package/dist/components/renderers/fence/fence-renderer.js +29 -0
  9. package/dist/components/renderers/node-renderer.d.ts.map +1 -1
  10. package/dist/components/renderers/node-renderer.js +2 -1
  11. package/dist/components/renderers/roof/roof-renderer.d.ts.map +1 -1
  12. package/dist/components/renderers/roof/roof-renderer.js +31 -9
  13. package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts.map +1 -1
  14. package/dist/components/renderers/roof-segment/roof-segment-renderer.js +42 -8
  15. package/dist/components/renderers/site/site-renderer.d.ts.map +1 -1
  16. package/dist/components/renderers/site/site-renderer.js +7 -1
  17. package/dist/components/renderers/slab/slab-renderer.d.ts.map +1 -1
  18. package/dist/components/renderers/slab/slab-renderer.js +37 -8
  19. package/dist/components/renderers/stair/stair-renderer.d.ts.map +1 -1
  20. package/dist/components/renderers/stair/stair-renderer.js +605 -5
  21. package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts.map +1 -1
  22. package/dist/components/renderers/stair-segment/stair-segment-renderer.js +37 -8
  23. package/dist/components/renderers/wall/wall-renderer.d.ts.map +1 -1
  24. package/dist/components/renderers/wall/wall-renderer.js +4 -9
  25. package/dist/components/renderers/window/window-renderer.d.ts.map +1 -1
  26. package/dist/components/renderers/window/window-renderer.js +5 -2
  27. package/dist/components/viewer/frame-limiter.d.ts +6 -0
  28. package/dist/components/viewer/frame-limiter.d.ts.map +1 -0
  29. package/dist/components/viewer/frame-limiter.js +31 -0
  30. package/dist/components/viewer/ground-occluder.d.ts.map +1 -1
  31. package/dist/components/viewer/ground-occluder.js +5 -1
  32. package/dist/components/viewer/index.d.ts.map +1 -1
  33. package/dist/components/viewer/index.js +12 -12
  34. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  35. package/dist/components/viewer/post-processing.js +72 -28
  36. package/dist/components/viewer/selection-manager.d.ts.map +1 -1
  37. package/dist/components/viewer/selection-manager.js +21 -2
  38. package/dist/hooks/use-node-events.d.ts +5 -1
  39. package/dist/hooks/use-node-events.d.ts.map +1 -1
  40. package/dist/hooks/use-node-events.js +2 -0
  41. package/dist/index.d.ts +1 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +1 -0
  44. package/dist/lib/materials.d.ts +4 -1
  45. package/dist/lib/materials.d.ts.map +1 -1
  46. package/dist/lib/materials.js +178 -2
  47. package/dist/lib/merged-outline-node.d.ts.map +1 -1
  48. package/dist/lib/merged-outline-node.js +11 -4
  49. package/dist/store/use-viewer.d.ts +2 -2
  50. package/dist/systems/guide/guide-system.d.ts.map +1 -1
  51. package/dist/systems/guide/guide-system.js +26 -1
  52. package/dist/systems/roof/roof-materials.d.ts +5 -0
  53. package/dist/systems/roof/roof-materials.d.ts.map +1 -0
  54. package/dist/systems/roof/roof-materials.js +29 -0
  55. package/dist/systems/scan/scan-system.d.ts.map +1 -1
  56. package/dist/systems/scan/scan-system.js +26 -1
  57. package/dist/systems/stair/stair-materials.d.ts +7 -0
  58. package/dist/systems/stair/stair-materials.d.ts.map +1 -0
  59. package/dist/systems/stair/stair-materials.js +33 -0
  60. package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
  61. package/dist/systems/wall/wall-cutout.js +39 -124
  62. package/dist/systems/wall/wall-materials.d.ts +16 -0
  63. package/dist/systems/wall/wall-materials.d.ts.map +1 -0
  64. package/dist/systems/wall/wall-materials.js +148 -0
  65. package/package.json +4 -4
@@ -1,4 +1,4 @@
1
- import { resolveMaterial } from '@pascal-app/core';
1
+ import { getMaterialPresetByRef, resolveMaterial, } from '@pascal-app/core';
2
2
  import * as THREE from 'three';
3
3
  const sideMap = {
4
4
  front: THREE.FrontSide,
@@ -6,15 +6,185 @@ const sideMap = {
6
6
  double: THREE.DoubleSide,
7
7
  };
8
8
  const materialCache = new Map();
9
+ const textureCache = new Map();
10
+ const textureLoadPromises = new Map();
11
+ const textureLoader = new THREE.TextureLoader();
12
+ const wrapMap = {
13
+ Repeat: THREE.RepeatWrapping,
14
+ ClampToEdge: THREE.ClampToEdgeWrapping,
15
+ MirroredRepeat: THREE.MirroredRepeatWrapping,
16
+ };
17
+ const SRGB_TEXTURE_SLOTS = ['map', 'emissiveMap'];
9
18
  function getCacheKey(props) {
10
19
  return `${props.color}-${props.roughness}-${props.metalness}-${props.opacity}-${props.transparent}-${props.side}`;
11
20
  }
21
+ function getTextureKey(material) {
22
+ const texture = material?.texture;
23
+ if (!texture)
24
+ return 'none';
25
+ const repeat = texture.repeat?.join('x') ?? 'default';
26
+ const scale = texture.scale ?? 'default';
27
+ return `${texture.url}-${repeat}-${scale}`;
28
+ }
29
+ function getTexture(material) {
30
+ const textureConfig = material?.texture;
31
+ if (!textureConfig?.url)
32
+ return undefined;
33
+ const cacheKey = getTextureKey(material);
34
+ const cached = textureCache.get(cacheKey);
35
+ if (cached)
36
+ return cached;
37
+ const texture = textureLoader.load(textureConfig.url);
38
+ texture.wrapS = THREE.RepeatWrapping;
39
+ texture.wrapT = THREE.RepeatWrapping;
40
+ const repeatX = textureConfig.repeat?.[0] ?? textureConfig.scale ?? 1;
41
+ const repeatY = textureConfig.repeat?.[1] ?? textureConfig.scale ?? 1;
42
+ texture.repeat.set(repeatX, repeatY);
43
+ texture.colorSpace = THREE.SRGBColorSpace;
44
+ textureCache.set(cacheKey, texture);
45
+ return texture;
46
+ }
47
+ function isStandardMaterial(material) {
48
+ return (material instanceof THREE.MeshStandardMaterial ||
49
+ material instanceof THREE.MeshPhysicalMaterial);
50
+ }
51
+ function applyTextureProperties(texture, props, slot) {
52
+ texture.wrapS = wrapMap[props.wrapS];
53
+ texture.wrapT = wrapMap[props.wrapT];
54
+ texture.repeat.set(props.repeatX, props.repeatY);
55
+ texture.rotation = props.rotation;
56
+ texture.flipY = props.flipY;
57
+ texture.colorSpace = SRGB_TEXTURE_SLOTS.includes(slot ?? 'map')
58
+ ? THREE.SRGBColorSpace
59
+ : THREE.NoColorSpace;
60
+ texture.needsUpdate = true;
61
+ return texture;
62
+ }
63
+ function getPresetTextureCacheKey(path, props, slot) {
64
+ return `${path}-${props.repeatX}-${props.repeatY}-${props.rotation}-${props.wrapS}-${props.wrapT}-${props.flipY}-${slot ?? 'map'}`;
65
+ }
66
+ function getPresetTexture(path, props, slot) {
67
+ const cacheKey = getPresetTextureCacheKey(path, props, slot);
68
+ const cached = textureCache.get(cacheKey);
69
+ if (cached)
70
+ return cached;
71
+ const texture = textureLoader.load(path);
72
+ applyTextureProperties(texture, props, slot);
73
+ textureCache.set(cacheKey, texture);
74
+ return texture;
75
+ }
76
+ async function loadPresetTexture(path, props, slot) {
77
+ const cacheKey = getPresetTextureCacheKey(path, props, slot);
78
+ const cached = textureCache.get(cacheKey);
79
+ if (cached)
80
+ return cached;
81
+ const existingPromise = textureLoadPromises.get(cacheKey);
82
+ if (existingPromise)
83
+ return existingPromise;
84
+ const promise = textureLoader
85
+ .loadAsync(path)
86
+ .then((texture) => {
87
+ applyTextureProperties(texture, props, slot);
88
+ textureCache.set(cacheKey, texture);
89
+ textureLoadPromises.delete(cacheKey);
90
+ return texture;
91
+ })
92
+ .catch((error) => {
93
+ console.warn('[viewer] Failed to load material texture', path, error);
94
+ textureLoadPromises.delete(cacheKey);
95
+ return null;
96
+ });
97
+ textureLoadPromises.set(cacheKey, promise);
98
+ return promise;
99
+ }
100
+ function queueTextureAssignment(material, slot, path, props) {
101
+ if (!path) {
102
+ material[slot] = null;
103
+ return;
104
+ }
105
+ const cacheKey = getPresetTextureCacheKey(path, props, slot);
106
+ const cached = textureCache.get(cacheKey);
107
+ if (cached) {
108
+ material[slot] = cached;
109
+ return;
110
+ }
111
+ material[slot] = null;
112
+ void loadPresetTexture(path, props, slot).then((texture) => {
113
+ if (!texture)
114
+ return;
115
+ material[slot] = texture;
116
+ material.needsUpdate = true;
117
+ });
118
+ }
119
+ function applyMaterialMapProperties(material, mapProperties) {
120
+ material.color.set(mapProperties.color);
121
+ material.roughness = mapProperties.roughness;
122
+ material.metalness = mapProperties.metalness;
123
+ material.emissiveIntensity = mapProperties.emissiveIntensity;
124
+ material.emissive.set(mapProperties.emissiveColor);
125
+ material.displacementScale = mapProperties.displacementScale;
126
+ material.bumpScale = mapProperties.bumpScale;
127
+ material.aoMapIntensity = mapProperties.aoMapIntensity;
128
+ material.lightMapIntensity = mapProperties.lightMapIntensity;
129
+ material.transparent = mapProperties.transparent;
130
+ material.opacity = mapProperties.opacity;
131
+ material.side =
132
+ mapProperties.side === 0
133
+ ? THREE.FrontSide
134
+ : mapProperties.side === 1
135
+ ? THREE.BackSide
136
+ : THREE.DoubleSide;
137
+ material.normalScale.set(mapProperties.normalScaleX, mapProperties.normalScaleY);
138
+ material.needsUpdate = true;
139
+ }
140
+ function applyMaterialPresetTextures(material, preset) {
141
+ const { maps, mapProperties } = preset;
142
+ queueTextureAssignment(material, 'map', maps.albedoMap, mapProperties);
143
+ queueTextureAssignment(material, 'normalMap', maps.normalMap, mapProperties);
144
+ queueTextureAssignment(material, 'roughnessMap', maps.roughnessMap, mapProperties);
145
+ queueTextureAssignment(material, 'metalnessMap', maps.metalnessMap, mapProperties);
146
+ queueTextureAssignment(material, 'displacementMap', maps.displacementMap, mapProperties);
147
+ queueTextureAssignment(material, 'aoMap', maps.aoMap, mapProperties);
148
+ queueTextureAssignment(material, 'bumpMap', maps.bumpMap, mapProperties);
149
+ queueTextureAssignment(material, 'alphaMap', maps.alphaMap, mapProperties);
150
+ queueTextureAssignment(material, 'lightMap', maps.lightMap, mapProperties);
151
+ queueTextureAssignment(material, 'emissiveMap', maps.emissiveMap, mapProperties);
152
+ material.needsUpdate = true;
153
+ }
154
+ export function applyMaterialPresetToMaterials(materialInput, preset) {
155
+ if (!preset)
156
+ return;
157
+ const materials = (Array.isArray(materialInput) ? materialInput : [materialInput]).filter(isStandardMaterial);
158
+ if (materials.length === 0)
159
+ return;
160
+ for (const material of materials) {
161
+ applyMaterialMapProperties(material, preset.mapProperties);
162
+ applyMaterialPresetTextures(material, preset);
163
+ }
164
+ }
165
+ export function createMaterialFromPreset(preset) {
166
+ const cacheKey = JSON.stringify(preset);
167
+ if (materialCache.has(cacheKey)) {
168
+ return materialCache.get(cacheKey);
169
+ }
170
+ const material = new THREE.MeshStandardMaterial();
171
+ applyMaterialPresetToMaterials(material, preset);
172
+ materialCache.set(cacheKey, material);
173
+ return material;
174
+ }
175
+ export function createMaterialFromPresetRef(materialPreset) {
176
+ const preset = getMaterialPresetByRef(materialPreset);
177
+ if (!preset)
178
+ return null;
179
+ return createMaterialFromPreset(preset);
180
+ }
12
181
  export function createMaterial(material) {
13
182
  const props = resolveMaterial(material);
14
- const cacheKey = getCacheKey(props);
183
+ const cacheKey = `${getCacheKey(props)}-${getTextureKey(material)}`;
15
184
  if (materialCache.has(cacheKey)) {
16
185
  return materialCache.get(cacheKey);
17
186
  }
187
+ const map = getTexture(material);
18
188
  const threeMaterial = new THREE.MeshStandardMaterial({
19
189
  color: props.color,
20
190
  roughness: props.roughness,
@@ -22,6 +192,7 @@ export function createMaterial(material) {
22
192
  opacity: props.opacity,
23
193
  transparent: props.transparent,
24
194
  side: sideMap[props.side],
195
+ map,
25
196
  });
26
197
  materialCache.set(cacheKey, threeMaterial);
27
198
  return threeMaterial;
@@ -56,4 +227,9 @@ export function clearMaterialCache() {
56
227
  material.dispose();
57
228
  }
58
229
  materialCache.clear();
230
+ for (const texture of textureCache.values()) {
231
+ texture.dispose();
232
+ }
233
+ textureCache.clear();
234
+ textureLoadPromises.clear();
59
235
  }
@@ -1 +1 @@
1
- {"version":3,"file":"merged-outline-node.d.ts","sourceRoot":"","sources":["../../src/lib/merged-outline-node.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"merged-outline-node.d.ts","sourceRoot":"","sources":["../../src/lib/merged-outline-node.ts"],"names":[],"mappings":"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"}
@@ -440,10 +440,17 @@ export class MergedOutlineNode extends TempNode {
440
440
  }
441
441
  _buildCache(objects, cache) {
442
442
  for (const obj of objects) {
443
- obj.traverse((child) => {
444
- if (child.isMesh || child.isSprite)
445
- cache.add(child);
446
- });
443
+ if (!obj || !obj.traverse)
444
+ continue;
445
+ try {
446
+ obj.traverse((child) => {
447
+ if (child.isMesh || child.isSprite)
448
+ cache.add(child);
449
+ });
450
+ }
451
+ catch {
452
+ // Skip objects that were disposed or removed from the scene graph
453
+ }
447
454
  }
448
455
  }
449
456
  }
@@ -61,7 +61,7 @@ declare const useViewer: import("zustand").UseBoundStore<Omit<import("zustand").
61
61
  cameraMode: "perspective" | "orthographic";
62
62
  theme: "light" | "dark";
63
63
  unit: "metric" | "imperial";
64
- levelMode: "stacked" | "exploded" | "solo" | "manual";
64
+ levelMode: "manual" | "stacked" | "exploded" | "solo";
65
65
  wallMode: "up" | "cutaway" | "down";
66
66
  projectPreferences: Record<string, {
67
67
  showScans?: boolean;
@@ -78,7 +78,7 @@ declare const useViewer: import("zustand").UseBoundStore<Omit<import("zustand").
78
78
  cameraMode: "perspective" | "orthographic";
79
79
  theme: "light" | "dark";
80
80
  unit: "metric" | "imperial";
81
- levelMode: "stacked" | "exploded" | "solo" | "manual";
81
+ levelMode: "manual" | "stacked" | "exploded" | "solo";
82
82
  wallMode: "up" | "cutaway" | "down";
83
83
  projectPreferences: Record<string, {
84
84
  showScans?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"guide-system.d.ts","sourceRoot":"","sources":["../../../src/systems/guide/guide-system.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,YAavB,CAAA"}
1
+ {"version":3,"file":"guide-system.d.ts","sourceRoot":"","sources":["../../../src/systems/guide/guide-system.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,YAsCvB,CAAA"}
@@ -1,4 +1,4 @@
1
- import { sceneRegistry } from '@pascal-app/core';
1
+ import { emitter, sceneRegistry } from '@pascal-app/core';
2
2
  import { useEffect } from 'react';
3
3
  import useViewer from '../../store/use-viewer';
4
4
  export const GuideSystem = () => {
@@ -12,5 +12,30 @@ export const GuideSystem = () => {
12
12
  }
13
13
  });
14
14
  }, [showGuides]);
15
+ useEffect(() => {
16
+ const hideForCapture = () => {
17
+ const guides = sceneRegistry.byType.guide || new Set();
18
+ guides.forEach((guideId) => {
19
+ const node = sceneRegistry.nodes.get(guideId);
20
+ if (node)
21
+ node.visible = false;
22
+ });
23
+ };
24
+ const restoreAfterCapture = () => {
25
+ const showGuidesNow = useViewer.getState().showGuides;
26
+ const guides = sceneRegistry.byType.guide || new Set();
27
+ guides.forEach((guideId) => {
28
+ const node = sceneRegistry.nodes.get(guideId);
29
+ if (node)
30
+ node.visible = showGuidesNow;
31
+ });
32
+ };
33
+ emitter.on('thumbnail:before-capture', hideForCapture);
34
+ emitter.on('thumbnail:after-capture', restoreAfterCapture);
35
+ return () => {
36
+ emitter.off('thumbnail:before-capture', hideForCapture);
37
+ emitter.off('thumbnail:after-capture', restoreAfterCapture);
38
+ };
39
+ }, []);
15
40
  return null;
16
41
  };
@@ -0,0 +1,5 @@
1
+ import { type RoofNode } from '@pascal-app/core';
2
+ import * as THREE from 'three';
3
+ export type RoofMaterialArray = [THREE.Material, THREE.Material, THREE.Material, THREE.Material];
4
+ export declare function getRoofMaterialArray(node: RoofNode): RoofMaterialArray | null;
5
+ //# sourceMappingURL=roof-materials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roof-materials.d.ts","sourceRoot":"","sources":["../../../src/systems/roof/roof-materials.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;AAiBhG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,iBAAiB,GAAG,IAAI,CAmB7E"}
@@ -0,0 +1,29 @@
1
+ import { getEffectiveRoofSurfaceMaterial, } from '@pascal-app/core';
2
+ import * as THREE from 'three';
3
+ import { createMaterial, createMaterialFromPresetRef } from '../../lib/materials';
4
+ function createResolvedMaterial(material, materialPreset) {
5
+ if (materialPreset) {
6
+ return createMaterialFromPresetRef(materialPreset);
7
+ }
8
+ if (material) {
9
+ return createMaterial(material);
10
+ }
11
+ return null;
12
+ }
13
+ export function getRoofMaterialArray(node) {
14
+ const top = getEffectiveRoofSurfaceMaterial(node, 'top');
15
+ const edge = getEffectiveRoofSurfaceMaterial(node, 'edge');
16
+ const wall = getEffectiveRoofSurfaceMaterial(node, 'wall');
17
+ const topMaterial = createResolvedMaterial(top.material, top.materialPreset);
18
+ const edgeMaterial = createResolvedMaterial(edge.material, edge.materialPreset);
19
+ const wallMaterial = createResolvedMaterial(wall.material, wall.materialPreset);
20
+ if (!(topMaterial || edgeMaterial || wallMaterial)) {
21
+ return null;
22
+ }
23
+ return [
24
+ edgeMaterial ?? wallMaterial ?? topMaterial ?? new THREE.MeshStandardMaterial(),
25
+ wallMaterial ?? edgeMaterial ?? topMaterial ?? new THREE.MeshStandardMaterial(),
26
+ wallMaterial ?? edgeMaterial ?? topMaterial ?? new THREE.MeshStandardMaterial(),
27
+ topMaterial ?? wallMaterial ?? edgeMaterial ?? new THREE.MeshStandardMaterial(),
28
+ ];
29
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"scan-system.d.ts","sourceRoot":"","sources":["../../../src/systems/scan/scan-system.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,YAatB,CAAA"}
1
+ {"version":3,"file":"scan-system.d.ts","sourceRoot":"","sources":["../../../src/systems/scan/scan-system.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,YAsCtB,CAAA"}
@@ -1,4 +1,4 @@
1
- import { sceneRegistry } from '@pascal-app/core';
1
+ import { emitter, sceneRegistry } from '@pascal-app/core';
2
2
  import { useEffect } from 'react';
3
3
  import useViewer from '../../store/use-viewer';
4
4
  export const ScanSystem = () => {
@@ -12,5 +12,30 @@ export const ScanSystem = () => {
12
12
  }
13
13
  });
14
14
  }, [showScans]);
15
+ useEffect(() => {
16
+ const hideForCapture = () => {
17
+ const scans = sceneRegistry.byType.scan || new Set();
18
+ scans.forEach((scanId) => {
19
+ const node = sceneRegistry.nodes.get(scanId);
20
+ if (node)
21
+ node.visible = false;
22
+ });
23
+ };
24
+ const restoreAfterCapture = () => {
25
+ const showScansNow = useViewer.getState().showScans;
26
+ const scans = sceneRegistry.byType.scan || new Set();
27
+ scans.forEach((scanId) => {
28
+ const node = sceneRegistry.nodes.get(scanId);
29
+ if (node)
30
+ node.visible = showScansNow;
31
+ });
32
+ };
33
+ emitter.on('thumbnail:before-capture', hideForCapture);
34
+ emitter.on('thumbnail:after-capture', restoreAfterCapture);
35
+ return () => {
36
+ emitter.off('thumbnail:before-capture', hideForCapture);
37
+ emitter.off('thumbnail:after-capture', restoreAfterCapture);
38
+ };
39
+ }, []);
15
40
  return null;
16
41
  };
@@ -0,0 +1,7 @@
1
+ import { type StairNode, type StairSegmentNode } from '@pascal-app/core';
2
+ import type * as THREE from 'three';
3
+ export type StairBodyMaterials = [THREE.Material, THREE.Material];
4
+ export declare function getStairBodyMaterials(stair: StairNode): StairBodyMaterials;
5
+ export declare function getStairRailingMaterial(stair: StairNode): THREE.Material;
6
+ export declare function getStraightStairSegmentBodyMaterials(segment: StairSegmentNode, parentNode?: StairNode): StairBodyMaterials;
7
+ //# sourceMappingURL=stair-materials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stair-materials.d.ts","sourceRoot":"","sources":["../../../src/systems/stair/stair-materials.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAOnC,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;AAiBjE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,GAAG,kBAAkB,CAQ1E;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,CAAC,QAAQ,CAGxE;AAED,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,gBAAgB,EACzB,UAAU,CAAC,EAAE,SAAS,GACrB,kBAAkB,CAWpB"}
@@ -0,0 +1,33 @@
1
+ import { getEffectiveStairSurfaceMaterial, } from '@pascal-app/core';
2
+ import { createMaterial, createMaterialFromPresetRef, DEFAULT_STAIR_MATERIAL, } from '../../lib/materials';
3
+ function createResolvedMaterial(material, materialPreset) {
4
+ if (materialPreset) {
5
+ return createMaterialFromPresetRef(materialPreset) ?? DEFAULT_STAIR_MATERIAL;
6
+ }
7
+ if (material) {
8
+ return createMaterial(material);
9
+ }
10
+ return DEFAULT_STAIR_MATERIAL;
11
+ }
12
+ export function getStairBodyMaterials(stair) {
13
+ const tread = getEffectiveStairSurfaceMaterial(stair, 'tread');
14
+ const side = getEffectiveStairSurfaceMaterial(stair, 'side');
15
+ return [
16
+ createResolvedMaterial(tread.material, tread.materialPreset),
17
+ createResolvedMaterial(side.material, side.materialPreset),
18
+ ];
19
+ }
20
+ export function getStairRailingMaterial(stair) {
21
+ const railing = getEffectiveStairSurfaceMaterial(stair, 'railing');
22
+ return createResolvedMaterial(railing.material, railing.materialPreset);
23
+ }
24
+ export function getStraightStairSegmentBodyMaterials(segment, parentNode) {
25
+ if (segment.material !== undefined || typeof segment.materialPreset === 'string') {
26
+ const override = createResolvedMaterial(segment.material, segment.materialPreset);
27
+ return [override, override];
28
+ }
29
+ if (parentNode) {
30
+ return getStairBodyMaterials(parentNode);
31
+ }
32
+ return [DEFAULT_STAIR_MATERIAL, DEFAULT_STAIR_MATERIAL];
33
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"wall-cutout.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-cutout.tsx"],"names":[],"mappings":"AAoMA,eAAO,MAAM,UAAU,YAgFtB,CAAA"}
1
+ {"version":3,"file":"wall-cutout.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-cutout.tsx"],"names":[],"mappings":"AAsCA,eAAO,MAAM,UAAU,YAkHtB,CAAA"}
@@ -1,129 +1,12 @@
1
- import { baseMaterial, sceneRegistry, useScene, } from '@pascal-app/core';
1
+ import { emitter, sceneRegistry, useScene } from '@pascal-app/core';
2
2
  import { useFrame } from '@react-three/fiber';
3
- import { useRef } from 'react';
4
- import { Color } from 'three';
5
- import { Fn, float, fract, length, mix, positionLocal, smoothstep, step, vec2 } from 'three/tsl';
6
- import { MeshStandardNodeMaterial, Vector3 } from 'three/webgpu';
3
+ import { useEffect, useRef } from 'react';
4
+ import { Vector3 } from 'three/webgpu';
7
5
  import useViewer from '../../store/use-viewer';
6
+ import { getMaterialsForWall } from './wall-materials';
8
7
  const tmpVec = new Vector3();
9
8
  const u = new Vector3();
10
9
  const v = new Vector3();
11
- const DEFAULT_WALL_COLOR = '#f2f0ed';
12
- const WALL_HIGHLIGHT_PROFILES = {
13
- delete: {
14
- color: new Color('#dc2626'),
15
- blend: 0.78,
16
- emissiveIntensity: 0.46,
17
- },
18
- selection: {
19
- color: new Color('#818cf8'),
20
- blend: 0.32,
21
- emissiveIntensity: 0.42,
22
- },
23
- };
24
- const dotPattern = Fn(() => {
25
- const scale = float(0.1);
26
- const dotSize = float(0.3);
27
- const uv = vec2(positionLocal.x, positionLocal.y).div(scale);
28
- const gridUV = fract(uv);
29
- const dist = length(gridUV.sub(0.5));
30
- const dots = step(dist, dotSize.mul(0.5));
31
- const fadeHeight = float(2.5);
32
- const yFade = float(1).sub(smoothstep(float(0), fadeHeight, positionLocal.y));
33
- return dots.mul(yFade);
34
- });
35
- const wallMaterialCache = new Map();
36
- const presetColors = {
37
- white: '#ffffff',
38
- brick: '#8b4513',
39
- concrete: '#808080',
40
- wood: '#deb887',
41
- glass: '#87ceeb',
42
- metal: '#c0c0c0',
43
- plaster: '#f5f5dc',
44
- tile: '#dcdcdc',
45
- marble: '#f5f5f5',
46
- };
47
- function getMaterialHash(wallNode) {
48
- if (!wallNode.material)
49
- return 'none';
50
- const mat = wallNode.material;
51
- if (mat.preset && mat.preset !== 'custom') {
52
- return `preset-${mat.preset}`;
53
- }
54
- if (mat.properties) {
55
- return `props-${mat.properties.color}-${mat.properties.roughness}-${mat.properties.metalness}`;
56
- }
57
- return 'default';
58
- }
59
- function getPresetColor(preset) {
60
- return presetColors[preset] ?? '#ffffff';
61
- }
62
- function getHighlightedColor(color, kind) {
63
- const profile = WALL_HIGHLIGHT_PROFILES[kind];
64
- return new Color(color).lerp(profile.color, profile.blend);
65
- }
66
- function createHighlightedWallMaterial(material, baseColor, kind) {
67
- const highlightedMaterial = material.clone();
68
- const highlightedColor = getHighlightedColor(baseColor, kind);
69
- const profile = WALL_HIGHLIGHT_PROFILES[kind];
70
- highlightedMaterial.color = highlightedColor;
71
- highlightedMaterial.emissive = highlightedColor.clone();
72
- highlightedMaterial.emissiveIntensity = profile.emissiveIntensity;
73
- return highlightedMaterial;
74
- }
75
- function getMaterialsForWall(wallNode) {
76
- const cacheKey = wallNode.id;
77
- const materialHash = getMaterialHash(wallNode);
78
- const existing = wallMaterialCache.get(cacheKey);
79
- if (existing && existing.materialHash === materialHash) {
80
- return existing;
81
- }
82
- if (existing) {
83
- existing.visible.dispose();
84
- existing.invisible.dispose();
85
- existing.deleteVisible.dispose();
86
- existing.deleteInvisible.dispose();
87
- existing.highlightedVisible.dispose();
88
- existing.highlightedInvisible.dispose();
89
- }
90
- let userColor = DEFAULT_WALL_COLOR;
91
- if (wallNode.material?.properties?.color) {
92
- userColor = wallNode.material.properties.color;
93
- }
94
- else if (wallNode.material?.preset && wallNode.material.preset !== 'custom') {
95
- userColor = getPresetColor(wallNode.material.preset);
96
- }
97
- const visibleMat = wallNode.material
98
- ? new MeshStandardNodeMaterial({
99
- color: userColor,
100
- roughness: 1,
101
- metalness: 0,
102
- })
103
- : baseMaterial.clone();
104
- const invisibleMat = new MeshStandardNodeMaterial({
105
- transparent: true,
106
- opacityNode: mix(float(0.0), float(0.24), dotPattern()),
107
- color: userColor,
108
- depthWrite: false,
109
- emissive: userColor,
110
- });
111
- const highlightedVisible = createHighlightedWallMaterial(visibleMat, userColor, 'selection');
112
- const highlightedInvisible = createHighlightedWallMaterial(invisibleMat, userColor, 'selection');
113
- const deleteVisible = createHighlightedWallMaterial(visibleMat, userColor, 'delete');
114
- const deleteInvisible = createHighlightedWallMaterial(invisibleMat, userColor, 'delete');
115
- const result = {
116
- visible: visibleMat,
117
- invisible: invisibleMat,
118
- deleteVisible,
119
- deleteInvisible,
120
- highlightedVisible,
121
- highlightedInvisible,
122
- materialHash,
123
- };
124
- wallMaterialCache.set(cacheKey, result);
125
- return result;
126
- }
127
10
  function getWallHideState(wallNode, wallMesh, wallMode, cameraDir) {
128
11
  let hideWall = wallNode.frontSide === 'interior' && wallNode.backSide === 'interior';
129
12
  if (wallMode === 'up') {
@@ -206,9 +89,7 @@ export const WallCutout = () => {
206
89
  ? materials.deleteVisible
207
90
  : isSelectionHighlighted
208
91
  ? materials.highlightedVisible
209
- : wallNode.material
210
- ? materials.visible
211
- : baseMaterial;
92
+ : materials.visible;
212
93
  }
213
94
  });
214
95
  lastWallMode.current = wallMode;
@@ -216,5 +97,39 @@ export const WallCutout = () => {
216
97
  lastHighlightKey.current = highlightKey;
217
98
  }
218
99
  });
100
+ useEffect(() => {
101
+ const snapshot = new Map();
102
+ const restoreForCapture = () => {
103
+ sceneRegistry.byType.wall.forEach((wallId) => {
104
+ const wallMesh = sceneRegistry.nodes.get(wallId);
105
+ if (!wallMesh)
106
+ return;
107
+ const wallNode = useScene.getState().nodes[wallId];
108
+ if (!wallNode || wallNode.type !== 'wall')
109
+ return;
110
+ const mats = getMaterialsForWall(wallNode);
111
+ const current = wallMesh.material;
112
+ snapshot.set(wallMesh, current);
113
+ if (current === mats.highlightedVisible || current === mats.deleteVisible) {
114
+ wallMesh.material = mats.visible;
115
+ }
116
+ else if (current === mats.highlightedInvisible || current === mats.deleteInvisible) {
117
+ wallMesh.material = mats.invisible;
118
+ }
119
+ });
120
+ };
121
+ const reapplyAfterCapture = () => {
122
+ snapshot.forEach((mat, mesh) => {
123
+ mesh.material = mat;
124
+ });
125
+ snapshot.clear();
126
+ };
127
+ emitter.on('thumbnail:before-capture', restoreForCapture);
128
+ emitter.on('thumbnail:after-capture', reapplyAfterCapture);
129
+ return () => {
130
+ emitter.off('thumbnail:before-capture', restoreForCapture);
131
+ emitter.off('thumbnail:after-capture', reapplyAfterCapture);
132
+ };
133
+ }, []);
219
134
  return null;
220
135
  };
@@ -0,0 +1,16 @@
1
+ import { type WallNode } from '@pascal-app/core';
2
+ import { type Material } from 'three';
3
+ export type WallMaterialArray = [Material, Material, Material];
4
+ export interface WallMaterials {
5
+ visible: WallMaterialArray;
6
+ invisible: WallMaterialArray;
7
+ deleteVisible: WallMaterialArray;
8
+ deleteInvisible: WallMaterialArray;
9
+ highlightedVisible: WallMaterialArray;
10
+ highlightedInvisible: WallMaterialArray;
11
+ materialHash: string;
12
+ }
13
+ export declare function getWallMaterialHash(wallNode: WallNode): string;
14
+ export declare function getMaterialsForWall(wallNode: WallNode): WallMaterials;
15
+ export declare function getVisibleWallMaterials(wallNode: WallNode): WallMaterialArray;
16
+ //# sourceMappingURL=wall-materials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wall-materials.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-materials.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,QAAQ,EAEd,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAS,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAA;AAwB5C,MAAM,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;AAE9D,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,iBAAiB,CAAA;IAC1B,SAAS,EAAE,iBAAiB,CAAA;IAC5B,aAAa,EAAE,iBAAiB,CAAA;IAChC,eAAe,EAAE,iBAAiB,CAAA;IAClC,kBAAkB,EAAE,iBAAiB,CAAA;IACrC,oBAAoB,EAAE,iBAAiB,CAAA;IACvC,YAAY,EAAE,MAAM,CAAA;CACrB;AA4GD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAS9D;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,GAAG,aAAa,CA2DrE;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,GAAG,iBAAiB,CAE7E"}