@pascal-app/viewer 0.8.0 → 0.9.1

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 (194) hide show
  1. package/dist/components/renderers/node-renderer.d.ts +1 -1
  2. package/dist/components/renderers/node-renderer.d.ts.map +1 -1
  3. package/dist/components/renderers/node-renderer.js +38 -22
  4. package/dist/components/renderers/parametric-node-renderer.d.ts +5 -0
  5. package/dist/components/renderers/parametric-node-renderer.d.ts.map +1 -0
  6. package/dist/components/renderers/parametric-node-renderer.js +34 -0
  7. package/dist/components/renderers/scene-renderer.d.ts +1 -1
  8. package/dist/components/renderers/scene-renderer.d.ts.map +1 -1
  9. package/dist/components/viewer/ground-occluder.d.ts +1 -1
  10. package/dist/components/viewer/ground-occluder.d.ts.map +1 -1
  11. package/dist/components/viewer/ground-occluder.js +12 -24
  12. package/dist/components/viewer/index.d.ts +37 -1
  13. package/dist/components/viewer/index.d.ts.map +1 -1
  14. package/dist/components/viewer/index.js +186 -63
  15. package/dist/components/viewer/lights.d.ts +1 -1
  16. package/dist/components/viewer/lights.d.ts.map +1 -1
  17. package/dist/components/viewer/lights.js +170 -43
  18. package/dist/components/viewer/perf-monitor.d.ts +1 -1
  19. package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
  20. package/dist/components/viewer/perf-monitor.js +99 -11
  21. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  22. package/dist/components/viewer/post-processing.js +231 -54
  23. package/dist/components/viewer/registered-systems.d.ts +12 -0
  24. package/dist/components/viewer/registered-systems.d.ts.map +1 -0
  25. package/dist/components/viewer/registered-systems.js +47 -0
  26. package/dist/components/viewer/scene-bvh.d.ts +17 -0
  27. package/dist/components/viewer/scene-bvh.d.ts.map +1 -0
  28. package/dist/components/viewer/scene-bvh.js +94 -0
  29. package/dist/components/viewer/selection-manager.d.ts +1 -1
  30. package/dist/components/viewer/selection-manager.d.ts.map +1 -1
  31. package/dist/components/viewer/selection-manager.js +20 -5
  32. package/dist/components/viewer/viewer-camera.d.ts +1 -1
  33. package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
  34. package/dist/components/viewer/walkthrough-controls.d.ts +1 -1
  35. package/dist/components/viewer/walkthrough-controls.d.ts.map +1 -1
  36. package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
  37. package/dist/hooks/use-node-events.d.ts +5 -73
  38. package/dist/hooks/use-node-events.d.ts.map +1 -1
  39. package/dist/hooks/use-node-events.js +19 -7
  40. package/dist/index.d.ts +36 -4
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +67 -3
  43. package/dist/lib/csg-utils.d.ts +16 -0
  44. package/dist/lib/csg-utils.d.ts.map +1 -0
  45. package/dist/lib/csg-utils.js +33 -0
  46. package/dist/lib/drawable-geometry.d.ts +21 -0
  47. package/dist/lib/drawable-geometry.d.ts.map +1 -0
  48. package/dist/lib/drawable-geometry.js +22 -0
  49. package/dist/lib/edge-style.d.ts +3 -0
  50. package/dist/lib/edge-style.d.ts.map +1 -0
  51. package/dist/lib/edge-style.js +11 -0
  52. package/dist/lib/gpu-perf.d.ts +4 -0
  53. package/dist/lib/gpu-perf.d.ts.map +1 -0
  54. package/dist/lib/gpu-perf.js +23 -0
  55. package/dist/lib/ink-edges.d.ts +9 -0
  56. package/dist/lib/ink-edges.d.ts.map +1 -0
  57. package/dist/lib/ink-edges.js +43 -0
  58. package/dist/lib/isolation.d.ts +39 -0
  59. package/dist/lib/isolation.d.ts.map +1 -0
  60. package/dist/lib/isolation.js +103 -0
  61. package/dist/lib/layers.d.ts +18 -0
  62. package/dist/lib/layers.d.ts.map +1 -1
  63. package/dist/lib/layers.js +18 -0
  64. package/dist/lib/materials.d.ts +25 -15
  65. package/dist/lib/materials.d.ts.map +1 -1
  66. package/dist/lib/materials.js +277 -62
  67. package/dist/lib/merged-outline-node.d.ts.map +1 -1
  68. package/dist/lib/merged-outline-node.js +7 -0
  69. package/dist/lib/polygon-union.d.ts +4 -0
  70. package/dist/lib/polygon-union.d.ts.map +1 -0
  71. package/dist/lib/polygon-union.js +289 -0
  72. package/dist/lib/polygon-union.test.d.ts +2 -0
  73. package/dist/lib/polygon-union.test.d.ts.map +1 -0
  74. package/dist/lib/polygon-union.test.js +105 -0
  75. package/dist/lib/scene-themes.d.ts +29 -0
  76. package/dist/lib/scene-themes.d.ts.map +1 -0
  77. package/dist/lib/scene-themes.js +193 -0
  78. package/dist/store/use-viewer.d.ts +42 -4
  79. package/dist/store/use-viewer.d.ts.map +1 -1
  80. package/dist/store/use-viewer.js +26 -3
  81. package/dist/systems/ceiling/ceiling-system.d.ts +6 -2
  82. package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
  83. package/dist/systems/ceiling/ceiling-system.js +62 -12
  84. package/dist/systems/door/door-system.d.ts.map +1 -1
  85. package/dist/systems/door/door-system.js +373 -22
  86. package/dist/systems/elevator/elevator-interaction-system.d.ts +2 -0
  87. package/dist/systems/elevator/elevator-interaction-system.d.ts.map +1 -0
  88. package/dist/systems/elevator/elevator-interaction-system.js +62 -0
  89. package/dist/systems/fence/fence-system.d.ts +3 -0
  90. package/dist/systems/fence/fence-system.d.ts.map +1 -1
  91. package/dist/systems/fence/fence-system.js +9 -5
  92. package/dist/systems/floor-elevation/floor-elevation-system.d.ts +20 -0
  93. package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -0
  94. package/dist/systems/floor-elevation/floor-elevation-system.js +78 -0
  95. package/dist/systems/geometry/geometry-system.d.ts +34 -0
  96. package/dist/systems/geometry/geometry-system.d.ts.map +1 -0
  97. package/dist/systems/geometry/geometry-system.js +279 -0
  98. package/dist/systems/interactive/interactive-system.d.ts +1 -1
  99. package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
  100. package/dist/systems/item/item-system.d.ts +7 -0
  101. package/dist/systems/item/item-system.d.ts.map +1 -1
  102. package/dist/systems/item/item-system.js +8 -11
  103. package/dist/systems/item-light/item-light-system.d.ts +1 -1
  104. package/dist/systems/item-light/item-light-system.d.ts.map +1 -1
  105. package/dist/systems/item-light/item-light-system.js +18 -5
  106. package/dist/systems/roof/roof-materials.d.ts +3 -2
  107. package/dist/systems/roof/roof-materials.d.ts.map +1 -1
  108. package/dist/systems/roof/roof-materials.js +38 -14
  109. package/dist/systems/roof/roof-system.d.ts +27 -0
  110. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  111. package/dist/systems/roof/roof-system.js +396 -59
  112. package/dist/systems/slab/slab-system.d.ts.map +1 -1
  113. package/dist/systems/slab/slab-system.js +167 -49
  114. package/dist/systems/slab/slab-system.test.d.ts +2 -0
  115. package/dist/systems/slab/slab-system.test.d.ts.map +1 -0
  116. package/dist/systems/slab/slab-system.test.js +62 -0
  117. package/dist/systems/stair/stair-materials.d.ts +4 -3
  118. package/dist/systems/stair/stair-materials.d.ts.map +1 -1
  119. package/dist/systems/stair/stair-materials.js +30 -15
  120. package/dist/systems/stair/stair-system.d.ts.map +1 -1
  121. package/dist/systems/stair/stair-system.js +50 -61
  122. package/dist/systems/surface-hole-geometry.d.ts +3 -0
  123. package/dist/systems/surface-hole-geometry.d.ts.map +1 -0
  124. package/dist/systems/surface-hole-geometry.js +4 -0
  125. package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
  126. package/dist/systems/wall/wall-cutout.js +18 -2
  127. package/dist/systems/wall/wall-materials.d.ts +4 -3
  128. package/dist/systems/wall/wall-materials.d.ts.map +1 -1
  129. package/dist/systems/wall/wall-materials.js +52 -28
  130. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  131. package/dist/systems/wall/wall-system.js +171 -26
  132. package/dist/systems/window/window-system.d.ts.map +1 -1
  133. package/dist/systems/window/window-system.js +71 -7
  134. package/package.json +3 -4
  135. package/dist/components/renderers/building/building-renderer.d.ts +0 -5
  136. package/dist/components/renderers/building/building-renderer.d.ts.map +0 -1
  137. package/dist/components/renderers/building/building-renderer.js +0 -11
  138. package/dist/components/renderers/ceiling/ceiling-renderer.d.ts +0 -5
  139. package/dist/components/renderers/ceiling/ceiling-renderer.d.ts.map +0 -1
  140. package/dist/components/renderers/ceiling/ceiling-renderer.js +0 -58
  141. package/dist/components/renderers/column/column-renderer.d.ts +0 -5
  142. package/dist/components/renderers/column/column-renderer.d.ts.map +0 -1
  143. package/dist/components/renderers/column/column-renderer.js +0 -597
  144. package/dist/components/renderers/door/door-renderer.d.ts +0 -5
  145. package/dist/components/renderers/door/door-renderer.d.ts.map +0 -1
  146. package/dist/components/renderers/door/door-renderer.js +0 -16
  147. package/dist/components/renderers/fence/fence-renderer.d.ts +0 -5
  148. package/dist/components/renderers/fence/fence-renderer.d.ts.map +0 -1
  149. package/dist/components/renderers/fence/fence-renderer.js +0 -15
  150. package/dist/components/renderers/guide/guide-renderer.d.ts +0 -5
  151. package/dist/components/renderers/guide/guide-renderer.d.ts.map +0 -1
  152. package/dist/components/renderers/guide/guide-renderer.js +0 -38
  153. package/dist/components/renderers/item/item-renderer.d.ts +0 -5
  154. package/dist/components/renderers/item/item-renderer.d.ts.map +0 -1
  155. package/dist/components/renderers/item/item-renderer.js +0 -172
  156. package/dist/components/renderers/level/level-renderer.d.ts +0 -5
  157. package/dist/components/renderers/level/level-renderer.d.ts.map +0 -1
  158. package/dist/components/renderers/level/level-renderer.js +0 -11
  159. package/dist/components/renderers/roof/roof-materials.d.ts +0 -4
  160. package/dist/components/renderers/roof/roof-materials.d.ts.map +0 -1
  161. package/dist/components/renderers/roof/roof-materials.js +0 -16
  162. package/dist/components/renderers/roof/roof-renderer.d.ts +0 -5
  163. package/dist/components/renderers/roof/roof-renderer.d.ts.map +0 -1
  164. package/dist/components/renderers/roof/roof-renderer.js +0 -32
  165. package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts +0 -5
  166. package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts.map +0 -1
  167. package/dist/components/renderers/roof-segment/roof-segment-renderer.js +0 -40
  168. package/dist/components/renderers/scan/scan-renderer.d.ts +0 -5
  169. package/dist/components/renderers/scan/scan-renderer.d.ts.map +0 -1
  170. package/dist/components/renderers/scan/scan-renderer.js +0 -54
  171. package/dist/components/renderers/site/site-renderer.d.ts +0 -5
  172. package/dist/components/renderers/site/site-renderer.d.ts.map +0 -1
  173. package/dist/components/renderers/site/site-renderer.js +0 -106
  174. package/dist/components/renderers/slab/slab-renderer.d.ts +0 -5
  175. package/dist/components/renderers/slab/slab-renderer.d.ts.map +0 -1
  176. package/dist/components/renderers/slab/slab-renderer.js +0 -58
  177. package/dist/components/renderers/spawn/spawn-renderer.d.ts +0 -5
  178. package/dist/components/renderers/spawn/spawn-renderer.d.ts.map +0 -1
  179. package/dist/components/renderers/spawn/spawn-renderer.js +0 -32
  180. package/dist/components/renderers/stair/stair-renderer.d.ts +0 -5
  181. package/dist/components/renderers/stair/stair-renderer.d.ts.map +0 -1
  182. package/dist/components/renderers/stair/stair-renderer.js +0 -603
  183. package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts +0 -5
  184. package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts.map +0 -1
  185. package/dist/components/renderers/stair-segment/stair-segment-renderer.js +0 -51
  186. package/dist/components/renderers/wall/wall-renderer.d.ts +0 -5
  187. package/dist/components/renderers/wall/wall-renderer.d.ts.map +0 -1
  188. package/dist/components/renderers/wall/wall-renderer.js +0 -16
  189. package/dist/components/renderers/window/window-renderer.d.ts +0 -5
  190. package/dist/components/renderers/window/window-renderer.d.ts.map +0 -1
  191. package/dist/components/renderers/window/window-renderer.js +0 -21
  192. package/dist/components/renderers/zone/zone-renderer.d.ts +0 -5
  193. package/dist/components/renderers/zone/zone-renderer.d.ts.map +0 -1
  194. package/dist/components/renderers/zone/zone-renderer.js +0 -181
@@ -1,18 +1,66 @@
1
1
  import { getMaterialPresetByRef, resolveMaterial, } from '@pascal-app/core';
2
2
  import * as THREE from 'three';
3
- import { MeshStandardNodeMaterial } from 'three/webgpu';
4
- export const baseMaterial = new MeshStandardNodeMaterial({
5
- color: '#f2f0ed',
6
- roughness: 0.5,
7
- metalness: 0.0,
8
- });
9
- export const glassMaterial = new MeshStandardNodeMaterial({
3
+ import { MeshLambertNodeMaterial, MeshStandardNodeMaterial } from 'three/webgpu';
4
+ import { resolveCdnUrl } from './asset-url';
5
+ import { getSceneTheme } from './scene-themes';
6
+ export const CLAY_PALETTE = {
7
+ wall: '#dcd6c7',
8
+ floor: '#cfc8b6',
9
+ ceiling: '#e4ded0',
10
+ roof: '#b8ad96',
11
+ joinery: '#c4bba6',
12
+ glazing: '#c8d4dc',
13
+ furnishing: '#d2ccbe',
14
+ };
15
+ export const WHITE_PALETTE = {
16
+ wall: '#f4f3ef',
17
+ floor: '#ece9e2',
18
+ ceiling: '#fbfaf6',
19
+ roof: '#dedbd2',
20
+ joinery: '#e8e5dc',
21
+ glazing: '#dbe8ee',
22
+ furnishing: '#efede7',
23
+ };
24
+ export const MONO_PALETTE = {
25
+ wall: '#c8c8c8',
26
+ floor: '#b8b8b8',
27
+ ceiling: '#d8d8d8',
28
+ roof: '#9a9a9a',
29
+ joinery: '#adadad',
30
+ glazing: '#c2cbd0',
31
+ furnishing: '#c0c0c0',
32
+ };
33
+ export const BLUEPRINT_PALETTE = {
34
+ wall: '#90a9c7',
35
+ floor: '#7f98ba',
36
+ ceiling: '#aec0d8',
37
+ roof: '#5f789b',
38
+ joinery: '#6f86a8',
39
+ glazing: '#b6d7ea',
40
+ furnishing: '#8ba2bf',
41
+ };
42
+ export const PRESET_PALETTES = {
43
+ clay: CLAY_PALETTE,
44
+ white: WHITE_PALETTE,
45
+ mono: MONO_PALETTE,
46
+ blueprint: BLUEPRINT_PALETTE,
47
+ };
48
+ export function resolveSurfaceColor(role, preset, sceneThemeId) {
49
+ // The active scene theme may tint individual roles (e.g. Mediterranean's blue
50
+ // roof); fall back to the chosen colour preset's palette when it doesn't.
51
+ const tints = sceneThemeId ? getSceneTheme(sceneThemeId).clayTints : undefined;
52
+ return tints?.[role] ?? PRESET_PALETTES[preset][role];
53
+ }
54
+ // DoubleSide on any NodeMaterial inside the MRT scenePass (SSGI's output /
55
+ // diffuseColor / normal targets) causes WebGPU to create a render pipeline
56
+ // whose back-face shader variant doesn't declare outputs for every MRT target
57
+ // — the validator rejects it and poisons the entire render context. FrontSide
58
+ // avoids that code path. Same pattern as MeshStandardMaterial in renderer.tsx.
59
+ export const glassMaterial = new MeshLambertNodeMaterial({
10
60
  color: '#e0f2fe',
11
- roughness: 0.05,
12
- metalness: 0.0,
13
61
  transparent: true,
14
62
  opacity: 0.35,
15
- side: THREE.DoubleSide,
63
+ side: THREE.FrontSide,
16
64
  });
17
65
  const sideMap = {
18
66
  front: THREE.FrontSide,
@@ -20,6 +68,8 @@ const sideMap = {
20
68
  double: THREE.DoubleSide,
21
69
  };
22
70
  const materialCache = new Map();
71
+ const defaultMaterialCache = new Map();
72
+ const surfaceRoleMaterialCache = new Map();
23
73
  const textureCache = new Map();
24
74
  const textureLoadPromises = new Map();
25
75
  const textureLoader = new THREE.TextureLoader();
@@ -29,8 +79,26 @@ const wrapMap = {
29
79
  MirroredRepeat: THREE.MirroredRepeatWrapping,
30
80
  };
31
81
  const SRGB_TEXTURE_SLOTS = ['map', 'emissiveMap'];
32
- function getCacheKey(props) {
33
- return `${props.color}-${props.roughness}-${props.metalness}-${props.opacity}-${props.transparent}-${props.side}`;
82
+ const TEXTURE_SLOTS = [
83
+ 'map',
84
+ 'normalMap',
85
+ 'roughnessMap',
86
+ 'metalnessMap',
87
+ 'displacementMap',
88
+ 'aoMap',
89
+ 'bumpMap',
90
+ 'alphaMap',
91
+ 'lightMap',
92
+ 'emissiveMap',
93
+ ];
94
+ function getTextureChannel(slot) {
95
+ if (slot === 'aoMap' || slot === 'lightMap') {
96
+ return 2;
97
+ }
98
+ return 0;
99
+ }
100
+ function getCacheKey(props, shading) {
101
+ return `${shading}-${props.color}-${props.roughness}-${props.metalness}-${props.opacity}-${props.transparent}-${props.side}`;
34
102
  }
35
103
  function getTextureKey(material) {
36
104
  const texture = material?.texture;
@@ -54,12 +122,18 @@ function getTexture(material) {
54
122
  const repeatX = textureConfig.repeat?.[0] ?? textureConfig.scale ?? 1;
55
123
  const repeatY = textureConfig.repeat?.[1] ?? textureConfig.scale ?? 1;
56
124
  texture.repeat.set(repeatX, repeatY);
125
+ texture.updateMatrix();
57
126
  texture.colorSpace = THREE.SRGBColorSpace;
58
127
  textureCache.set(cacheKey, texture);
59
128
  return texture;
60
129
  }
61
130
  function isStandardMaterial(material) {
62
- return (material instanceof THREE.MeshStandardMaterial || material instanceof THREE.MeshPhysicalMaterial);
131
+ return (material instanceof THREE.MeshStandardMaterial ||
132
+ material instanceof THREE.MeshPhysicalMaterial ||
133
+ material instanceof MeshStandardNodeMaterial);
134
+ }
135
+ function isCommonMaterial(material) {
136
+ return 'color' in material && material.color instanceof THREE.Color;
63
137
  }
64
138
  function applyTextureProperties(texture, props, slot) {
65
139
  texture.wrapS = wrapMap[props.wrapS];
@@ -67,27 +141,54 @@ function applyTextureProperties(texture, props, slot) {
67
141
  texture.repeat.set(props.repeatX, props.repeatY);
68
142
  texture.rotation = props.rotation;
69
143
  texture.flipY = props.flipY;
144
+ texture.updateMatrix();
145
+ texture.channel = getTextureChannel(slot);
70
146
  texture.colorSpace = SRGB_TEXTURE_SLOTS.includes(slot ?? 'map')
71
147
  ? THREE.SRGBColorSpace
72
148
  : THREE.NoColorSpace;
73
149
  texture.needsUpdate = true;
74
150
  return texture;
75
151
  }
152
+ function setTextureCacheKey(texture, cacheKey) {
153
+ texture.userData.pascalTextureCacheKey = cacheKey;
154
+ return texture;
155
+ }
76
156
  function getPresetTextureCacheKey(path, props, slot) {
77
157
  return `${path}-${props.repeatX}-${props.repeatY}-${props.rotation}-${props.wrapS}-${props.wrapT}-${props.flipY}-${slot ?? 'map'}`;
78
158
  }
79
159
  function getPresetTexture(path, props, slot) {
80
- const cacheKey = getPresetTextureCacheKey(path, props, slot);
160
+ const resolvedPath = resolveCdnUrl(path) ?? path;
161
+ const cacheKey = getPresetTextureCacheKey(resolvedPath, props, slot);
81
162
  const cached = textureCache.get(cacheKey);
82
163
  if (cached)
83
164
  return cached;
84
- const texture = textureLoader.load(path);
165
+ const texture = textureLoader.load(resolvedPath);
85
166
  applyTextureProperties(texture, props, slot);
167
+ setTextureCacheKey(texture, cacheKey);
86
168
  textureCache.set(cacheKey, texture);
87
169
  return texture;
88
170
  }
171
+ function createAssignedTexture(source, props, slot) {
172
+ const texture = source.clone();
173
+ const cacheKey = source.userData.pascalTextureCacheKey;
174
+ if (typeof cacheKey === 'string') {
175
+ setTextureCacheKey(texture, cacheKey);
176
+ }
177
+ return applyTextureProperties(texture, props, slot);
178
+ }
179
+ function applyTexturePropertiesToMaterial(material, props) {
180
+ const slots = isStandardMaterial(material) ? TEXTURE_SLOTS : ['map'];
181
+ const textureMaterial = material;
182
+ for (const slot of slots) {
183
+ const texture = textureMaterial[slot];
184
+ if (!texture)
185
+ continue;
186
+ applyTextureProperties(texture, props, slot);
187
+ }
188
+ }
89
189
  async function loadPresetTexture(path, props, slot) {
90
- const cacheKey = getPresetTextureCacheKey(path, props, slot);
190
+ const resolvedPath = resolveCdnUrl(path) ?? path;
191
+ const cacheKey = getPresetTextureCacheKey(resolvedPath, props, slot);
91
192
  const cached = textureCache.get(cacheKey);
92
193
  if (cached)
93
194
  return cached;
@@ -95,15 +196,16 @@ async function loadPresetTexture(path, props, slot) {
95
196
  if (existingPromise)
96
197
  return existingPromise;
97
198
  const promise = textureLoader
98
- .loadAsync(path)
199
+ .loadAsync(resolvedPath)
99
200
  .then((texture) => {
100
201
  applyTextureProperties(texture, props, slot);
202
+ setTextureCacheKey(texture, cacheKey);
101
203
  textureCache.set(cacheKey, texture);
102
204
  textureLoadPromises.delete(cacheKey);
103
205
  return texture;
104
206
  })
105
207
  .catch((error) => {
106
- console.warn('[viewer] Failed to load material texture', path, error);
208
+ console.warn('[viewer] Failed to load material texture', resolvedPath, error);
107
209
  textureLoadPromises.delete(cacheKey);
108
210
  return null;
109
211
  });
@@ -111,34 +213,48 @@ async function loadPresetTexture(path, props, slot) {
111
213
  return promise;
112
214
  }
113
215
  function queueTextureAssignment(material, slot, path, props) {
216
+ const textureMaterial = material;
114
217
  if (!path) {
115
- material[slot] = null;
218
+ textureMaterial[slot] = null;
219
+ return;
220
+ }
221
+ const resolvedPath = resolveCdnUrl(path) ?? path;
222
+ const cacheKey = getPresetTextureCacheKey(resolvedPath, props, slot);
223
+ if (textureMaterial[slot]?.userData.pascalTextureCacheKey === cacheKey) {
224
+ applyTextureProperties(textureMaterial[slot], props, slot);
116
225
  return;
117
226
  }
118
- const cacheKey = getPresetTextureCacheKey(path, props, slot);
119
227
  const cached = textureCache.get(cacheKey);
120
228
  if (cached) {
121
- material[slot] = cached;
229
+ textureMaterial[slot] = createAssignedTexture(cached, props, slot);
230
+ material.needsUpdate = true;
122
231
  return;
123
232
  }
124
- material[slot] = null;
233
+ textureMaterial[slot] = null;
125
234
  loadPresetTexture(path, props, slot).then((texture) => {
126
235
  if (!texture)
127
236
  return;
128
- material[slot] = texture;
237
+ textureMaterial[slot] = createAssignedTexture(texture, props, slot);
129
238
  material.needsUpdate = true;
130
239
  });
131
240
  }
132
241
  function applyMaterialMapProperties(material, mapProperties) {
133
242
  material.color.set(mapProperties.color);
134
- material.roughness = mapProperties.roughness;
135
- material.metalness = mapProperties.metalness;
136
- material.emissiveIntensity = mapProperties.emissiveIntensity;
137
- material.emissive.set(mapProperties.emissiveColor);
138
- material.displacementScale = mapProperties.displacementScale;
139
- material.bumpScale = mapProperties.bumpScale;
140
- material.aoMapIntensity = mapProperties.aoMapIntensity;
141
- material.lightMapIntensity = mapProperties.lightMapIntensity;
243
+ if (isStandardMaterial(material)) {
244
+ material.roughness = mapProperties.roughness;
245
+ material.metalness = mapProperties.metalness;
246
+ material.displacementScale = mapProperties.displacementScale;
247
+ material.bumpScale = mapProperties.bumpScale;
248
+ material.aoMapIntensity = mapProperties.aoMapIntensity;
249
+ material.lightMapIntensity = mapProperties.lightMapIntensity;
250
+ material.normalScale.set(mapProperties.normalScaleX, mapProperties.normalScaleY);
251
+ }
252
+ if (material.emissive) {
253
+ material.emissive.set(mapProperties.emissiveColor);
254
+ }
255
+ if ('emissiveIntensity' in material) {
256
+ material.emissiveIntensity = mapProperties.emissiveIntensity;
257
+ }
142
258
  material.transparent = mapProperties.transparent;
143
259
  material.opacity = mapProperties.opacity;
144
260
  material.side =
@@ -147,12 +263,16 @@ function applyMaterialMapProperties(material, mapProperties) {
147
263
  : mapProperties.side === 1
148
264
  ? THREE.BackSide
149
265
  : THREE.DoubleSide;
150
- material.normalScale.set(mapProperties.normalScaleX, mapProperties.normalScaleY);
266
+ applyTexturePropertiesToMaterial(material, mapProperties);
151
267
  material.needsUpdate = true;
152
268
  }
153
269
  function applyMaterialPresetTextures(material, preset) {
154
270
  const { maps, mapProperties } = preset;
155
271
  queueTextureAssignment(material, 'map', maps.albedoMap, mapProperties);
272
+ if (!isStandardMaterial(material)) {
273
+ material.needsUpdate = true;
274
+ return;
275
+ }
156
276
  queueTextureAssignment(material, 'normalMap', maps.normalMap, mapProperties);
157
277
  queueTextureAssignment(material, 'roughnessMap', maps.roughnessMap, mapProperties);
158
278
  queueTextureAssignment(material, 'metalnessMap', maps.metalnessMap, mapProperties);
@@ -167,7 +287,7 @@ function applyMaterialPresetTextures(material, preset) {
167
287
  export function applyMaterialPresetToMaterials(materialInput, preset) {
168
288
  if (!preset)
169
289
  return;
170
- const materials = (Array.isArray(materialInput) ? materialInput : [materialInput]).filter(isStandardMaterial);
290
+ const materials = (Array.isArray(materialInput) ? materialInput : [materialInput]).filter(isCommonMaterial);
171
291
  if (materials.length === 0)
172
292
  return;
173
293
  for (const material of materials) {
@@ -175,63 +295,150 @@ export function applyMaterialPresetToMaterials(materialInput, preset) {
175
295
  applyMaterialPresetTextures(material, preset);
176
296
  }
177
297
  }
178
- export function createMaterialFromPreset(preset) {
179
- const cacheKey = JSON.stringify(preset);
298
+ export function createMaterialFromPreset(preset, shading = 'rendered') {
299
+ const cacheKey = `${shading}-${JSON.stringify(preset)}`;
180
300
  if (materialCache.has(cacheKey)) {
181
301
  return materialCache.get(cacheKey);
182
302
  }
183
- const material = new THREE.MeshStandardMaterial();
303
+ const material = shading === 'solid' ? new MeshLambertNodeMaterial() : new MeshStandardNodeMaterial();
184
304
  applyMaterialPresetToMaterials(material, preset);
185
305
  materialCache.set(cacheKey, material);
186
306
  return material;
187
307
  }
188
- export function createMaterialFromPresetRef(materialPreset) {
308
+ export function createMaterialFromPresetRef(materialPreset, shading = 'rendered') {
189
309
  const preset = getMaterialPresetByRef(materialPreset);
190
310
  if (!preset)
191
311
  return null;
192
- return createMaterialFromPreset(preset);
312
+ return createMaterialFromPreset(preset, shading);
193
313
  }
194
- export function createMaterial(material) {
314
+ export function createMaterial(material, shading = 'rendered') {
195
315
  const props = resolveMaterial(material);
196
- const cacheKey = `${getCacheKey(props)}-${getTextureKey(material)}`;
316
+ const cacheKey = `${getCacheKey(props, shading)}-${getTextureKey(material)}`;
197
317
  if (materialCache.has(cacheKey)) {
198
318
  return materialCache.get(cacheKey);
199
319
  }
200
320
  const map = getTexture(material);
201
- const threeMaterial = new THREE.MeshStandardMaterial({
321
+ const materialParams = {
202
322
  color: props.color,
203
- roughness: props.roughness,
204
- metalness: props.metalness,
205
323
  opacity: props.opacity,
206
324
  transparent: props.transparent,
207
325
  side: sideMap[props.side],
208
- map,
209
- });
326
+ };
327
+ if (map)
328
+ materialParams.map = map;
329
+ const threeMaterial = shading === 'solid'
330
+ ? new MeshLambertNodeMaterial(materialParams)
331
+ : new MeshStandardNodeMaterial({
332
+ ...materialParams,
333
+ roughness: props.roughness,
334
+ metalness: props.metalness,
335
+ });
210
336
  materialCache.set(cacheKey, threeMaterial);
211
337
  return threeMaterial;
212
338
  }
213
- export function createDefaultMaterial(color = '#ffffff', roughness = 0.9) {
214
- return new THREE.MeshStandardMaterial({
339
+ export function createDefaultMaterial(color = '#ffffff', roughness = 0.9, shading = 'rendered', side = THREE.FrontSide) {
340
+ if (shading === 'solid') {
341
+ return new MeshLambertNodeMaterial({
342
+ color,
343
+ side,
344
+ });
345
+ }
346
+ return new MeshStandardNodeMaterial({
215
347
  color,
216
348
  roughness,
217
349
  metalness: 0,
218
- side: THREE.FrontSide,
350
+ side,
219
351
  });
220
352
  }
221
- export const DEFAULT_WALL_MATERIAL = createDefaultMaterial('#ffffff', 0.9);
222
- export const DEFAULT_SLAB_MATERIAL = createDefaultMaterial('#e5e5e5', 0.8);
223
- export const DEFAULT_DOOR_MATERIAL = createDefaultMaterial('#8b4513', 0.7);
224
- export const DEFAULT_WINDOW_MATERIAL = new THREE.MeshStandardMaterial({
225
- color: '#87ceeb',
226
- roughness: 0.1,
227
- metalness: 0.1,
228
- opacity: 0.3,
229
- transparent: true,
230
- side: THREE.DoubleSide,
231
- });
232
- export const DEFAULT_CEILING_MATERIAL = createDefaultMaterial('#f5f5dc', 0.95);
233
- export const DEFAULT_ROOF_MATERIAL = createDefaultMaterial('#808080', 0.85);
234
- export const DEFAULT_STAIR_MATERIAL = createDefaultMaterial('#ffffff', 0.9);
353
+ function cachedDefaultMaterial(key, color, roughness, shading, side = THREE.FrontSide) {
354
+ const cacheKey = `${key}-${shading}`;
355
+ const cached = defaultMaterialCache.get(cacheKey);
356
+ if (cached)
357
+ return cached;
358
+ const material = createDefaultMaterial(color, roughness, shading, side);
359
+ defaultMaterialCache.set(cacheKey, material);
360
+ return material;
361
+ }
362
+ export function createSurfaceRoleMaterial(role, preset, side = THREE.FrontSide, sceneThemeId) {
363
+ // DoubleSide on glazing trips the MRT back-face pipeline issue documented
364
+ // on `glassMaterial` above — the validator rejects the back-face variant
365
+ // for missing MRT outputs and poisons the render context (manifests as
366
+ // "Color target has no corresponding fragment stage output" on scene
367
+ // open, since the dormer's window-assembly mounts the glazing material
368
+ // on both gable faces on the first frame). Callers that need both sides
369
+ // visible (e.g. dormer back gable) must rotate the host mesh 180° so the
370
+ // FrontSide faces the viewer.
371
+ const resolvedSide = role === 'glazing' ? THREE.FrontSide : side;
372
+ const cacheKey = `${role}-${preset}-${resolvedSide}-${sceneThemeId ?? 'base'}`;
373
+ const cached = surfaceRoleMaterialCache.get(cacheKey);
374
+ if (cached)
375
+ return cached;
376
+ const material = role === 'glazing'
377
+ ? new MeshLambertNodeMaterial({
378
+ color: resolveSurfaceColor(role, preset, sceneThemeId),
379
+ depthWrite: false,
380
+ opacity: 0.25,
381
+ side: resolvedSide,
382
+ transparent: true,
383
+ })
384
+ : new MeshLambertNodeMaterial({
385
+ color: resolveSurfaceColor(role, preset, sceneThemeId),
386
+ side: resolvedSide,
387
+ });
388
+ material.userData.__pascalCachedMaterial = true;
389
+ surfaceRoleMaterialCache.set(cacheKey, material);
390
+ return material;
391
+ }
392
+ export function baseMaterial(shading = 'rendered') {
393
+ return cachedDefaultMaterial('base', '#f2f0ed', 0.5, shading);
394
+ }
395
+ export function DEFAULT_WALL_MATERIAL(shading = 'rendered') {
396
+ return cachedDefaultMaterial('wall', '#ffffff', 0.9, shading);
397
+ }
398
+ export function DEFAULT_SLAB_MATERIAL(shading = 'rendered') {
399
+ return cachedDefaultMaterial('slab', '#e5e5e5', 0.8, shading);
400
+ }
401
+ export function DEFAULT_DOOR_MATERIAL(shading = 'rendered') {
402
+ return cachedDefaultMaterial('door', '#8b4513', 0.7, shading);
403
+ }
404
+ export function DEFAULT_WINDOW_MATERIAL(shading = 'rendered') {
405
+ const cacheKey = `window-${shading}`;
406
+ const cached = defaultMaterialCache.get(cacheKey);
407
+ if (cached)
408
+ return cached;
409
+ // DoubleSide on a NodeMaterial inside the MRT scene pass compiles a back-face
410
+ // pipeline variant whose fragment outputs don't cover every MRT target — the
411
+ // validator rejects it and poisons the render context (see the note above
412
+ // `glassMaterial`). FrontSide; flip the consumer's back-face group 180° if a
413
+ // back face is actually visible.
414
+ const params = {
415
+ color: '#87ceeb',
416
+ opacity: 0.3,
417
+ transparent: true,
418
+ side: THREE.FrontSide,
419
+ };
420
+ const material = shading === 'solid'
421
+ ? new MeshLambertNodeMaterial(params)
422
+ : new MeshStandardNodeMaterial({
423
+ ...params,
424
+ roughness: 0.1,
425
+ metalness: 0.1,
426
+ });
427
+ defaultMaterialCache.set(cacheKey, material);
428
+ return material;
429
+ }
430
+ export function DEFAULT_CEILING_MATERIAL(shading = 'rendered') {
431
+ return cachedDefaultMaterial('ceiling', '#f5f5dc', 0.95, shading);
432
+ }
433
+ export function DEFAULT_ROOF_MATERIAL(shading = 'rendered') {
434
+ return cachedDefaultMaterial('roof', '#808080', 0.85, shading);
435
+ }
436
+ export function DEFAULT_SHELF_MATERIAL(shading = 'rendered') {
437
+ return cachedDefaultMaterial('shelf', '#ffffff', 0.9, shading);
438
+ }
439
+ export function DEFAULT_STAIR_MATERIAL(shading = 'rendered') {
440
+ return cachedDefaultMaterial('stair', '#ffffff', 0.9, shading);
441
+ }
235
442
  export function disposeMaterial(material) {
236
443
  material.dispose();
237
444
  }
@@ -240,6 +447,14 @@ export function clearMaterialCache() {
240
447
  material.dispose();
241
448
  }
242
449
  materialCache.clear();
450
+ for (const material of defaultMaterialCache.values()) {
451
+ material.dispose();
452
+ }
453
+ defaultMaterialCache.clear();
454
+ for (const material of surfaceRoleMaterialCache.values()) {
455
+ material.dispose();
456
+ }
457
+ surfaceRoleMaterialCache.clear();
243
458
  for (const texture of textureCache.values()) {
244
459
  texture.dispose();
245
460
  }
@@ -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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"}
@@ -17,6 +17,7 @@
17
17
  import { DepthTexture, FloatType, RenderTarget, Vector2 } from 'three';
18
18
  import { color, exp, Fn, float, int, Loop, min, mul, nodeObject, orthographicDepthToViewZ, passTexture, perspectiveDepthToViewZ, positionView, reference, screenUV, texture, textureSize, uniform, uv, vec2, vec3, vec4, } from 'three/tsl';
19
19
  import { NodeMaterial, NodeUpdateType, QuadMesh, RendererUtils, SpriteNodeMaterial, TempNode, } from 'three/webgpu';
20
+ import { hasDrawableGeometry } from './drawable-geometry';
20
21
  const _quadMesh = new QuadMesh();
21
22
  const _size = new Vector2();
22
23
  const _BLUR_X = new Vector2(1.0, 0.0);
@@ -262,6 +263,8 @@ export class MergedOutlineNode extends TempNode {
262
263
  // ── 1. Shared depth pass: all objects NOT in either group ─────────────────
263
264
  renderer.setRenderTarget(this._depthRT);
264
265
  renderer.setRenderObjectFunction((obj, sc, cam, geo, _mat, grp, lights, clip) => {
266
+ if (!hasDrawableGeometry(geo))
267
+ return;
265
268
  const inCache = this._cacheA.has(obj) || this._cacheB.has(obj);
266
269
  if (!inCache) {
267
270
  const m = obj.isSprite ? this._depthSpriteMaterial : this._depthMaterial;
@@ -274,6 +277,8 @@ export class MergedOutlineNode extends TempNode {
274
277
  if (hasPrimary) {
275
278
  renderer.setRenderTarget(this._groupA.maskBuffer);
276
279
  renderer.setRenderObjectFunction((obj, sc, cam, geo, _mat, grp, lights, clip) => {
280
+ if (!hasDrawableGeometry(geo))
281
+ return;
277
282
  if (this._cacheA.has(obj)) {
278
283
  const m = obj.isSprite ? this._prepareMaskSpriteMatA : this._prepareMaskMatA;
279
284
  renderer.renderObject(obj, sc, cam, geo, m, grp, lights, clip);
@@ -286,6 +291,8 @@ export class MergedOutlineNode extends TempNode {
286
291
  if (hasSecondary) {
287
292
  renderer.setRenderTarget(this._groupB.maskBuffer);
288
293
  renderer.setRenderObjectFunction((obj, sc, cam, geo, _mat, grp, lights, clip) => {
294
+ if (!hasDrawableGeometry(geo))
295
+ return;
289
296
  if (this._cacheB.has(obj)) {
290
297
  const m = obj.isSprite ? this._prepareMaskSpriteMatB : this._prepareMaskMatB;
291
298
  renderer.renderObject(obj, sc, cam, geo, m, grp, lights, clip);
@@ -0,0 +1,4 @@
1
+ export type Point2D = [number, number];
2
+ export declare function unionPolygons(polygons: Point2D[][]): Point2D[][];
3
+ export declare function subtractPolygonsFromPolygon(subject: Point2D[], cutters: Point2D[][]): Point2D[][];
4
+ //# sourceMappingURL=polygon-union.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polygon-union.d.ts","sourceRoot":"","sources":["../../src/lib/polygon-union.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAwStC,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,CAShE;AA4CD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,CAkBjG"}