@pascal-app/viewer 0.9.1 → 0.9.2

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 (176) hide show
  1. package/dist/components/error-boundary.d.ts +6 -0
  2. package/dist/components/error-boundary.d.ts.map +1 -1
  3. package/dist/components/error-boundary.js +6 -0
  4. package/dist/components/renderers/node-renderer.d.ts +5 -1
  5. package/dist/components/renderers/node-renderer.d.ts.map +1 -1
  6. package/dist/components/renderers/node-renderer.js +5 -2
  7. package/dist/components/renderers/parametric-node-renderer.d.ts.map +1 -1
  8. package/dist/components/renderers/parametric-node-renderer.js +7 -4
  9. package/dist/components/viewer/bvh-ecctrl.d.ts +77 -0
  10. package/dist/components/viewer/bvh-ecctrl.d.ts.map +1 -0
  11. package/dist/components/viewer/bvh-ecctrl.js +552 -0
  12. package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
  13. package/dist/components/viewer/frame-limiter.js +39 -4
  14. package/dist/components/viewer/glb-interactive.d.ts +41 -0
  15. package/dist/components/viewer/glb-interactive.d.ts.map +1 -0
  16. package/dist/components/viewer/glb-interactive.js +394 -0
  17. package/dist/components/viewer/glb-reference-nodes.d.ts +29 -0
  18. package/dist/components/viewer/glb-reference-nodes.d.ts.map +1 -0
  19. package/dist/components/viewer/glb-reference-nodes.js +80 -0
  20. package/dist/components/viewer/glb-replace-instances.d.ts +18 -0
  21. package/dist/components/viewer/glb-replace-instances.d.ts.map +1 -0
  22. package/dist/components/viewer/glb-replace-instances.js +61 -0
  23. package/dist/components/viewer/glb-scene.d.ts +54 -0
  24. package/dist/components/viewer/glb-scene.d.ts.map +1 -0
  25. package/dist/components/viewer/glb-scene.js +920 -0
  26. package/dist/components/viewer/glb-walkthrough-controller.d.ts +12 -0
  27. package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -0
  28. package/dist/components/viewer/glb-walkthrough-controller.js +357 -0
  29. package/dist/components/viewer/index.d.ts +19 -2
  30. package/dist/components/viewer/index.d.ts.map +1 -1
  31. package/dist/components/viewer/index.js +104 -12
  32. package/dist/components/viewer/lights.d.ts.map +1 -1
  33. package/dist/components/viewer/lights.js +36 -5
  34. package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
  35. package/dist/components/viewer/perf-monitor.js +17 -2
  36. package/dist/components/viewer/post-processing.d.ts +7 -1
  37. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  38. package/dist/components/viewer/post-processing.js +179 -24
  39. package/dist/components/viewer/registered-systems.d.ts.map +1 -1
  40. package/dist/components/viewer/registered-systems.js +6 -4
  41. package/dist/components/viewer/scene-bvh.d.ts +2 -1
  42. package/dist/components/viewer/scene-bvh.d.ts.map +1 -1
  43. package/dist/components/viewer/scene-bvh.js +3 -0
  44. package/dist/components/viewer/scene-bvh.test.d.ts +2 -0
  45. package/dist/components/viewer/scene-bvh.test.d.ts.map +1 -0
  46. package/dist/components/viewer/scene-bvh.test.js +13 -0
  47. package/dist/components/viewer/scene-environment.d.ts +2 -0
  48. package/dist/components/viewer/scene-environment.d.ts.map +1 -0
  49. package/dist/components/viewer/scene-environment.js +79 -0
  50. package/dist/components/viewer/selection-manager.d.ts.map +1 -1
  51. package/dist/components/viewer/selection-manager.js +18 -10
  52. package/dist/components/viewer/walkthrough-controls.d.ts +1 -0
  53. package/dist/components/viewer/walkthrough-controls.d.ts.map +1 -1
  54. package/dist/components/viewer/walkthrough-controls.js +20 -0
  55. package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
  56. package/dist/hooks/use-gltf-ktx2.js +3 -22
  57. package/dist/hooks/use-node-events.d.ts +1 -1
  58. package/dist/hooks/use-node-events.d.ts.map +1 -1
  59. package/dist/hooks/use-node-events.js +22 -14
  60. package/dist/index.d.ts +19 -8
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +22 -8
  63. package/dist/lib/backdrop.d.ts +33 -0
  64. package/dist/lib/backdrop.d.ts.map +1 -0
  65. package/dist/lib/backdrop.js +92 -0
  66. package/dist/lib/box-uv.d.ts +13 -0
  67. package/dist/lib/box-uv.d.ts.map +1 -0
  68. package/dist/lib/box-uv.js +32 -0
  69. package/dist/lib/csg-utils.d.ts +3 -9
  70. package/dist/lib/csg-utils.d.ts.map +1 -1
  71. package/dist/lib/csg-utils.js +65 -5
  72. package/dist/lib/csg-utils.test.d.ts +2 -0
  73. package/dist/lib/csg-utils.test.d.ts.map +1 -0
  74. package/dist/lib/csg-utils.test.js +45 -0
  75. package/dist/lib/edge-style.d.ts +1 -0
  76. package/dist/lib/edge-style.d.ts.map +1 -1
  77. package/dist/lib/edge-style.js +26 -6
  78. package/dist/lib/ink-edges.d.ts +1 -1
  79. package/dist/lib/ink-edges.d.ts.map +1 -1
  80. package/dist/lib/ink-edges.js +13 -7
  81. package/dist/lib/ktx2-loader.d.ts +43 -0
  82. package/dist/lib/ktx2-loader.d.ts.map +1 -0
  83. package/dist/lib/ktx2-loader.js +136 -0
  84. package/dist/lib/layers.d.ts +10 -0
  85. package/dist/lib/layers.d.ts.map +1 -1
  86. package/dist/lib/layers.js +10 -0
  87. package/dist/lib/materials.d.ts +14 -1
  88. package/dist/lib/materials.d.ts.map +1 -1
  89. package/dist/lib/materials.js +103 -26
  90. package/dist/lib/scene-themes.d.ts +1 -0
  91. package/dist/lib/scene-themes.d.ts.map +1 -1
  92. package/dist/lib/scene-themes.js +25 -16
  93. package/dist/lib/shadow-only.d.ts +4 -0
  94. package/dist/lib/shadow-only.d.ts.map +1 -0
  95. package/dist/lib/shadow-only.js +36 -0
  96. package/dist/lib/tsl-compat.d.ts +12 -0
  97. package/dist/lib/tsl-compat.d.ts.map +1 -0
  98. package/dist/lib/tsl-compat.js +13 -0
  99. package/dist/store/use-viewer.d.ts +60 -18
  100. package/dist/store/use-viewer.d.ts.map +1 -1
  101. package/dist/store/use-viewer.js +175 -3
  102. package/dist/store/use-viewer.test.d.ts +2 -0
  103. package/dist/store/use-viewer.test.d.ts.map +1 -0
  104. package/dist/store/use-viewer.test.js +42 -0
  105. package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
  106. package/dist/systems/ceiling/ceiling-system.js +4 -1
  107. package/dist/systems/door/door-animation.test.d.ts +2 -0
  108. package/dist/systems/door/door-animation.test.d.ts.map +1 -0
  109. package/dist/systems/door/door-animation.test.js +51 -0
  110. package/dist/systems/door/door-floor-alignment.test.d.ts +2 -0
  111. package/dist/systems/door/door-floor-alignment.test.d.ts.map +1 -0
  112. package/dist/systems/door/door-floor-alignment.test.js +50 -0
  113. package/dist/systems/door/door-system.d.ts +24 -0
  114. package/dist/systems/door/door-system.d.ts.map +1 -1
  115. package/dist/systems/door/door-system.js +494 -161
  116. package/dist/systems/fence/fence-system.d.ts +17 -0
  117. package/dist/systems/fence/fence-system.d.ts.map +1 -1
  118. package/dist/systems/fence/fence-system.js +221 -53
  119. package/dist/systems/geometry/geometry-system.d.ts +7 -0
  120. package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
  121. package/dist/systems/geometry/geometry-system.js +95 -26
  122. package/dist/systems/geometry/geometry-system.test.d.ts +2 -0
  123. package/dist/systems/geometry/geometry-system.test.d.ts.map +1 -0
  124. package/dist/systems/geometry/geometry-system.test.js +30 -0
  125. package/dist/systems/interactive/control-widget.d.ts +10 -0
  126. package/dist/systems/interactive/control-widget.d.ts.map +1 -0
  127. package/dist/systems/interactive/control-widget.js +35 -0
  128. package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
  129. package/dist/systems/interactive/interactive-system.js +55 -56
  130. package/dist/systems/item/item-system.d.ts.map +1 -1
  131. package/dist/systems/item/item-system.js +20 -6
  132. package/dist/systems/level/level-system.d.ts.map +1 -1
  133. package/dist/systems/level/level-system.js +28 -4
  134. package/dist/systems/level/level-utils.d.ts +0 -3
  135. package/dist/systems/level/level-utils.d.ts.map +1 -1
  136. package/dist/systems/level/level-utils.js +2 -41
  137. package/dist/systems/roof/roof-materials.d.ts.map +1 -1
  138. package/dist/systems/roof/roof-materials.js +29 -8
  139. package/dist/systems/roof/roof-system.d.ts +21 -8
  140. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  141. package/dist/systems/roof/roof-system.js +1079 -221
  142. package/dist/systems/slab/slab-system.d.ts +5 -3
  143. package/dist/systems/slab/slab-system.d.ts.map +1 -1
  144. package/dist/systems/slab/slab-system.js +41 -23
  145. package/dist/systems/slab/slab-system.test.js +3 -2
  146. package/dist/systems/stair/stair-system.js +6 -3
  147. package/dist/systems/wall/opening-cutout-geometry.d.ts +31 -0
  148. package/dist/systems/wall/opening-cutout-geometry.d.ts.map +1 -0
  149. package/dist/systems/wall/opening-cutout-geometry.js +167 -0
  150. package/dist/systems/wall/opening-cutout-geometry.test.d.ts +2 -0
  151. package/dist/systems/wall/opening-cutout-geometry.test.d.ts.map +1 -0
  152. package/dist/systems/wall/opening-cutout-geometry.test.js +172 -0
  153. package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
  154. package/dist/systems/wall/wall-cutout.js +46 -17
  155. package/dist/systems/wall/wall-materials.d.ts +11 -7
  156. package/dist/systems/wall/wall-materials.d.ts.map +1 -1
  157. package/dist/systems/wall/wall-materials.js +244 -35
  158. package/dist/systems/wall/wall-opening-cutout.test.d.ts +2 -0
  159. package/dist/systems/wall/wall-opening-cutout.test.d.ts.map +1 -0
  160. package/dist/systems/wall/wall-opening-cutout.test.js +59 -0
  161. package/dist/systems/wall/wall-support-extension.test.d.ts +2 -0
  162. package/dist/systems/wall/wall-support-extension.test.d.ts.map +1 -0
  163. package/dist/systems/wall/wall-support-extension.test.js +48 -0
  164. package/dist/systems/wall/wall-system.d.ts +2 -2
  165. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  166. package/dist/systems/wall/wall-system.js +329 -174
  167. package/dist/systems/window/window-animation-system.d.ts +12 -0
  168. package/dist/systems/window/window-animation-system.d.ts.map +1 -1
  169. package/dist/systems/window/window-animation-system.js +16 -5
  170. package/dist/systems/window/window-system.d.ts +7 -0
  171. package/dist/systems/window/window-system.d.ts.map +1 -1
  172. package/dist/systems/window/window-system.js +240 -14
  173. package/package.json +4 -4
  174. package/dist/components/viewer/ground-occluder.d.ts +0 -2
  175. package/dist/components/viewer/ground-occluder.d.ts.map +0 -1
  176. package/dist/components/viewer/ground-occluder.js +0 -67
@@ -1,4 +1,4 @@
1
- import { type MaterialPresetPayload, type MaterialSchema, type SurfaceRole } from '@pascal-app/core';
1
+ import { type MaterialPresetPayload, type MaterialSchema, type SceneMaterial, type SceneMaterialId, type SurfaceRole } from '@pascal-app/core';
2
2
  import * as THREE from 'three';
3
3
  import { MeshLambertNodeMaterial } from 'three/webgpu';
4
4
  export type RenderShading = 'solid' | 'rendered';
@@ -14,6 +14,19 @@ export declare function applyMaterialPresetToMaterials(materialInput: THREE.Mate
14
14
  export declare function createMaterialFromPreset(preset: MaterialPresetPayload, shading?: RenderShading): THREE.Material;
15
15
  export declare function createMaterialFromPresetRef(materialPreset?: string, shading?: RenderShading): THREE.Material | null;
16
16
  export declare function createMaterial(material?: MaterialSchema, shading?: RenderShading): THREE.Material;
17
+ /**
18
+ * Resolve a MaterialRef ('library:<id>' | 'scene:<id>') to a three.js material.
19
+ * Returns null for an unknown / dangling ref so callers fall back to the
20
+ * slot's default (authored material, then themed default). Never throws.
21
+ */
22
+ export declare function resolveMaterialRef(ref: string | undefined, sceneMaterials: Record<SceneMaterialId, SceneMaterial> | undefined, shading?: RenderShading): THREE.Material | null;
23
+ /**
24
+ * Resolve a node kind's declared slot default — either a catalog `library:<id>`
25
+ * finish or a flat `#rrggbb` colour — to a renderable material. Shared by the
26
+ * procedural kinds whose colored-mode unpainted appearance comes from a
27
+ * declarative default (slab, wall).
28
+ */
29
+ export declare function resolveSlotDefaultMaterial(slotDefault: string, shading?: RenderShading, roughness?: number): THREE.Material;
17
30
  export declare function createDefaultMaterial(color?: string, roughness?: number, shading?: RenderShading, side?: THREE.Side): THREE.Material;
18
31
  export declare function createSurfaceRoleMaterial(role: SurfaceRole, preset: ColorPreset, side?: THREE.Side, sceneThemeId?: string): THREE.Material;
19
32
  export declare function baseMaterial(shading?: RenderShading): THREE.Material;
@@ -1 +1 @@
1
- {"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../src/lib/materials.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../src/lib/materials.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,9 @@
1
- import { getMaterialPresetByRef, resolveMaterial, } from '@pascal-app/core';
1
+ import { getMaterialPresetByRef, parseMaterialRef, resolveMaterial, } from '@pascal-app/core';
2
2
  import * as THREE from 'three';
3
+ import { float, mix, positionViewDirection, transformedNormalView } from 'three/tsl';
3
4
  import { MeshLambertNodeMaterial, MeshStandardNodeMaterial } from 'three/webgpu';
4
5
  import { resolveCdnUrl } from './asset-url';
6
+ import { isKtx2Url, ktx2Loader, whenKtx2Ready } from './ktx2-loader';
5
7
  import { getSceneTheme } from './scene-themes';
6
8
  export const CLAY_PALETTE = {
7
9
  wall: '#dcd6c7',
@@ -12,14 +14,16 @@ export const CLAY_PALETTE = {
12
14
  glazing: '#c8d4dc',
13
15
  furnishing: '#d2ccbe',
14
16
  };
17
+ // Albedos are clamped to ≈0.83 linear (max channel #eb): real white paint
18
+ // reflects ~80%, and pure-white albedo kills GI/shadow contrast.
15
19
  export const WHITE_PALETTE = {
16
- wall: '#f4f3ef',
17
- floor: '#ece9e2',
18
- ceiling: '#fbfaf6',
20
+ wall: '#ebeae6',
21
+ floor: '#e7e4dd',
22
+ ceiling: '#ebeae6',
19
23
  roof: '#dedbd2',
20
- joinery: '#e8e5dc',
24
+ joinery: '#e5e2d9',
21
25
  glazing: '#dbe8ee',
22
- furnishing: '#efede7',
26
+ furnishing: '#e9e7e1',
23
27
  };
24
28
  export const MONO_PALETTE = {
25
29
  wall: '#c8c8c8',
@@ -49,7 +53,7 @@ export function resolveSurfaceColor(role, preset, sceneThemeId) {
49
53
  // The active scene theme may tint individual roles (e.g. Mediterranean's blue
50
54
  // roof); fall back to the chosen colour preset's palette when it doesn't.
51
55
  const tints = sceneThemeId ? getSceneTheme(sceneThemeId).clayTints : undefined;
52
- return tints?.[role] ?? PRESET_PALETTES[preset][role];
56
+ return tints?.[role] ?? (PRESET_PALETTES[preset] ?? CLAY_PALETTE)[role];
53
57
  }
54
58
  // DoubleSide on any NodeMaterial inside the MRT scenePass (SSGI's output /
55
59
  // diffuseColor / normal targets) causes WebGPU to create a render pipeline
@@ -62,10 +66,14 @@ export const glassMaterial = new MeshLambertNodeMaterial({
62
66
  opacity: 0.35,
63
67
  side: THREE.FrontSide,
64
68
  });
69
+ glassMaterial.userData.__pascalCachedMaterial = true;
70
+ function resolveNodeMaterialSide(side) {
71
+ return side === THREE.DoubleSide ? THREE.FrontSide : side;
72
+ }
65
73
  const sideMap = {
66
74
  front: THREE.FrontSide,
67
75
  back: THREE.BackSide,
68
- double: THREE.DoubleSide,
76
+ double: THREE.FrontSide,
69
77
  };
70
78
  const materialCache = new Map();
71
79
  const defaultMaterialCache = new Map();
@@ -73,6 +81,13 @@ const surfaceRoleMaterialCache = new Map();
73
81
  const textureCache = new Map();
74
82
  const textureLoadPromises = new Map();
75
83
  const textureLoader = new THREE.TextureLoader();
84
+ // `.ktx2` finish maps transcode through the shared KTX2 loader (support is
85
+ // detected once at viewer init); everything else loads as a normal image.
86
+ function pickTextureLoader(url) {
87
+ // KTX2Loader's load/loadAsync are call-compatible with TextureLoader (url →
88
+ // Texture / Promise<Texture>); cast for typing.
89
+ return isKtx2Url(url) ? ktx2Loader : textureLoader;
90
+ }
76
91
  const wrapMap = {
77
92
  Repeat: THREE.RepeatWrapping,
78
93
  ClampToEdge: THREE.ClampToEdgeWrapping,
@@ -116,7 +131,7 @@ function getTexture(material) {
116
131
  const cached = textureCache.get(cacheKey);
117
132
  if (cached)
118
133
  return cached;
119
- const texture = textureLoader.load(textureConfig.url);
134
+ const texture = pickTextureLoader(textureConfig.url).load(textureConfig.url);
120
135
  texture.wrapS = THREE.RepeatWrapping;
121
136
  texture.wrapT = THREE.RepeatWrapping;
122
137
  const repeatX = textureConfig.repeat?.[0] ?? textureConfig.scale ?? 1;
@@ -162,7 +177,7 @@ function getPresetTexture(path, props, slot) {
162
177
  const cached = textureCache.get(cacheKey);
163
178
  if (cached)
164
179
  return cached;
165
- const texture = textureLoader.load(resolvedPath);
180
+ const texture = pickTextureLoader(resolvedPath).load(resolvedPath);
166
181
  applyTextureProperties(texture, props, slot);
167
182
  setTextureCacheKey(texture, cacheKey);
168
183
  textureCache.set(cacheKey, texture);
@@ -195,8 +210,14 @@ async function loadPresetTexture(path, props, slot) {
195
210
  const existingPromise = textureLoadPromises.get(cacheKey);
196
211
  if (existingPromise)
197
212
  return existingPromise;
198
- const promise = textureLoader
199
- .loadAsync(resolvedPath)
213
+ // `.ktx2` loads wait for `detectSupport` (KTX2Loader.load throws before it) —
214
+ // materials can be created while a capture canvas's renderer is still
215
+ // initializing, and failing here would cache the material permanently
216
+ // texture-less (white).
217
+ const load = isKtx2Url(resolvedPath)
218
+ ? whenKtx2Ready().then(() => ktx2Loader.loadAsync(resolvedPath))
219
+ : textureLoader.loadAsync(resolvedPath);
220
+ const promise = load
200
221
  .then((texture) => {
201
222
  applyTextureProperties(texture, props, slot);
202
223
  setTextureCacheKey(texture, cacheKey);
@@ -257,15 +278,35 @@ function applyMaterialMapProperties(material, mapProperties) {
257
278
  }
258
279
  material.transparent = mapProperties.transparent;
259
280
  material.opacity = mapProperties.opacity;
260
- material.side =
261
- mapProperties.side === 0
262
- ? THREE.FrontSide
263
- : mapProperties.side === 1
264
- ? THREE.BackSide
265
- : THREE.DoubleSide;
281
+ material.side = resolveNodeMaterialSide(mapProperties.side === 0
282
+ ? THREE.FrontSide
283
+ : mapProperties.side === 1
284
+ ? THREE.BackSide
285
+ : THREE.DoubleSide);
266
286
  applyTexturePropertiesToMaterial(material, mapProperties);
267
287
  material.needsUpdate = true;
268
288
  }
289
+ // Glass-like transparency threshold: any standard material authored as
290
+ // `transparent` with opacity below this gets the fresnel treatment.
291
+ const GLASS_OPACITY_THRESHOLD = 0.6;
292
+ /**
293
+ * Fresnel-driven opacity for glass: nearly the authored opacity head-on,
294
+ * increasingly opaque (showing the environment reflection) at grazing angles.
295
+ * This is what makes glass read as a surface instead of a flat blue tint.
296
+ */
297
+ function applyGlassFresnel(material) {
298
+ const facing = transformedNormalView.dot(positionViewDirection).clamp(0, 1);
299
+ const fresnel = facing.oneMinus().pow(3);
300
+ material.opacityNode = mix(float(material.opacity), float(0.92), fresnel);
301
+ material.envMapIntensity = 1.4;
302
+ }
303
+ function maybeApplyGlassFresnel(material) {
304
+ if (material instanceof MeshStandardNodeMaterial &&
305
+ material.transparent &&
306
+ material.opacity < GLASS_OPACITY_THRESHOLD) {
307
+ applyGlassFresnel(material);
308
+ }
309
+ }
269
310
  function applyMaterialPresetTextures(material, preset) {
270
311
  const { maps, mapProperties } = preset;
271
312
  queueTextureAssignment(material, 'map', maps.albedoMap, mapProperties);
@@ -302,6 +343,8 @@ export function createMaterialFromPreset(preset, shading = 'rendered') {
302
343
  }
303
344
  const material = shading === 'solid' ? new MeshLambertNodeMaterial() : new MeshStandardNodeMaterial();
304
345
  applyMaterialPresetToMaterials(material, preset);
346
+ maybeApplyGlassFresnel(material);
347
+ material.userData.__pascalCachedMaterial = true;
305
348
  materialCache.set(cacheKey, material);
306
349
  return material;
307
350
  }
@@ -333,21 +376,53 @@ export function createMaterial(material, shading = 'rendered') {
333
376
  roughness: props.roughness,
334
377
  metalness: props.metalness,
335
378
  });
379
+ maybeApplyGlassFresnel(threeMaterial);
380
+ threeMaterial.userData.__pascalCachedMaterial = true;
336
381
  materialCache.set(cacheKey, threeMaterial);
337
382
  return threeMaterial;
338
383
  }
384
+ /**
385
+ * Resolve a MaterialRef ('library:<id>' | 'scene:<id>') to a three.js material.
386
+ * Returns null for an unknown / dangling ref so callers fall back to the
387
+ * slot's default (authored material, then themed default). Never throws.
388
+ */
389
+ export function resolveMaterialRef(ref, sceneMaterials, shading = 'rendered') {
390
+ const parsed = parseMaterialRef(ref);
391
+ if (!parsed)
392
+ return null;
393
+ if (parsed.kind === 'library')
394
+ return createMaterialFromPresetRef(ref, shading);
395
+ const sceneMaterial = sceneMaterials?.[parsed.id];
396
+ if (!sceneMaterial)
397
+ return null;
398
+ return createMaterial(sceneMaterial.material, shading);
399
+ }
400
+ /**
401
+ * Resolve a node kind's declared slot default — either a catalog `library:<id>`
402
+ * finish or a flat `#rrggbb` colour — to a renderable material. Shared by the
403
+ * procedural kinds whose colored-mode unpainted appearance comes from a
404
+ * declarative default (slab, wall).
405
+ */
406
+ export function resolveSlotDefaultMaterial(slotDefault, shading = 'rendered', roughness = 0.9) {
407
+ if (parseMaterialRef(slotDefault)?.kind === 'library') {
408
+ return (createMaterialFromPresetRef(slotDefault, shading) ??
409
+ createDefaultMaterial('#ffffff', roughness, shading));
410
+ }
411
+ return createDefaultMaterial(slotDefault, roughness, shading);
412
+ }
339
413
  export function createDefaultMaterial(color = '#ffffff', roughness = 0.9, shading = 'rendered', side = THREE.FrontSide) {
414
+ const resolvedSide = resolveNodeMaterialSide(side);
340
415
  if (shading === 'solid') {
341
416
  return new MeshLambertNodeMaterial({
342
417
  color,
343
- side,
418
+ side: resolvedSide,
344
419
  });
345
420
  }
346
421
  return new MeshStandardNodeMaterial({
347
422
  color,
348
423
  roughness,
349
424
  metalness: 0,
350
- side,
425
+ side: resolvedSide,
351
426
  });
352
427
  }
353
428
  function cachedDefaultMaterial(key, color, roughness, shading, side = THREE.FrontSide) {
@@ -356,6 +431,7 @@ function cachedDefaultMaterial(key, color, roughness, shading, side = THREE.Fron
356
431
  if (cached)
357
432
  return cached;
358
433
  const material = createDefaultMaterial(color, roughness, shading, side);
434
+ material.userData.__pascalCachedMaterial = true;
359
435
  defaultMaterialCache.set(cacheKey, material);
360
436
  return material;
361
437
  }
@@ -368,7 +444,7 @@ export function createSurfaceRoleMaterial(role, preset, side = THREE.FrontSide,
368
444
  // on both gable faces on the first frame). Callers that need both sides
369
445
  // visible (e.g. dormer back gable) must rotate the host mesh 180° so the
370
446
  // FrontSide faces the viewer.
371
- const resolvedSide = role === 'glazing' ? THREE.FrontSide : side;
447
+ const resolvedSide = role === 'glazing' ? THREE.FrontSide : resolveNodeMaterialSide(side ?? THREE.FrontSide);
372
448
  const cacheKey = `${role}-${preset}-${resolvedSide}-${sceneThemeId ?? 'base'}`;
373
449
  const cached = surfaceRoleMaterialCache.get(cacheKey);
374
450
  if (cached)
@@ -390,10 +466,10 @@ export function createSurfaceRoleMaterial(role, preset, side = THREE.FrontSide,
390
466
  return material;
391
467
  }
392
468
  export function baseMaterial(shading = 'rendered') {
393
- return cachedDefaultMaterial('base', '#f2f0ed', 0.5, shading);
469
+ return cachedDefaultMaterial('base', '#e9e7e3', 0.5, shading);
394
470
  }
395
471
  export function DEFAULT_WALL_MATERIAL(shading = 'rendered') {
396
- return cachedDefaultMaterial('wall', '#ffffff', 0.9, shading);
472
+ return cachedDefaultMaterial('wall', '#e9e6e0', 0.9, shading);
397
473
  }
398
474
  export function DEFAULT_SLAB_MATERIAL(shading = 'rendered') {
399
475
  return cachedDefaultMaterial('slab', '#e5e5e5', 0.8, shading);
@@ -424,20 +500,21 @@ export function DEFAULT_WINDOW_MATERIAL(shading = 'rendered') {
424
500
  roughness: 0.1,
425
501
  metalness: 0.1,
426
502
  });
503
+ maybeApplyGlassFresnel(material);
427
504
  defaultMaterialCache.set(cacheKey, material);
428
505
  return material;
429
506
  }
430
507
  export function DEFAULT_CEILING_MATERIAL(shading = 'rendered') {
431
- return cachedDefaultMaterial('ceiling', '#f5f5dc', 0.95, shading);
508
+ return cachedDefaultMaterial('ceiling', '#ebebd3', 0.95, shading);
432
509
  }
433
510
  export function DEFAULT_ROOF_MATERIAL(shading = 'rendered') {
434
511
  return cachedDefaultMaterial('roof', '#808080', 0.85, shading);
435
512
  }
436
513
  export function DEFAULT_SHELF_MATERIAL(shading = 'rendered') {
437
- return cachedDefaultMaterial('shelf', '#ffffff', 0.9, shading);
514
+ return cachedDefaultMaterial('shelf', '#e9e6e0', 0.9, shading);
438
515
  }
439
516
  export function DEFAULT_STAIR_MATERIAL(shading = 'rendered') {
440
- return cachedDefaultMaterial('stair', '#ffffff', 0.9, shading);
517
+ return cachedDefaultMaterial('stair', '#e9e6e0', 0.9, shading);
441
518
  }
442
519
  export function disposeMaterial(material) {
443
520
  material.dispose();
@@ -4,6 +4,7 @@ export type SceneTheme = {
4
4
  name: string;
5
5
  appearance: 'light' | 'dark';
6
6
  background: string;
7
+ backgroundSky?: string;
7
8
  ground: string;
8
9
  ambient: {
9
10
  color: string;
@@ -1 +1 @@
1
- {"version":3,"file":"scene-themes.d.ts","sourceRoot":"","sources":["../../src/lib/scene-themes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAEnD,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IAIZ,UAAU,EAAE,OAAO,GAAG,MAAM,CAAA;IAC5B,UAAU,EAAE,MAAM,CAAA;IAIlB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7C,IAAI,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,MAAM,EAAE,KAAK,CAAC;QACZ,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;QAClC,KAAK,EAAE,MAAM,CAAA;QACb,SAAS,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,OAAO,CAAA;KACrB,CAAC,CAAA;IACF,mBAAmB,EAAE,MAAM,CAAA;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAA;CACjD,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,UAAU,EA2LpC,CAAA;AAED,eAAO,MAAM,eAAe,UAAwC,CAAA;AAIpE,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,CAEpD"}
1
+ {"version":3,"file":"scene-themes.d.ts","sourceRoot":"","sources":["../../src/lib/scene-themes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAEnD,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IAIZ,UAAU,EAAE,OAAO,GAAG,MAAM,CAAA;IAC5B,UAAU,EAAE,MAAM,CAAA;IAIlB,aAAa,CAAC,EAAE,MAAM,CAAA;IAItB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7C,IAAI,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,MAAM,EAAE,KAAK,CAAC;QACZ,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;QAClC,KAAK,EAAE,MAAM,CAAA;QACb,SAAS,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,OAAO,CAAA;KACrB,CAAC,CAAA;IACF,mBAAmB,EAAE,MAAM,CAAA;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAA;CACjD,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,UAAU,EAoMpC,CAAA;AAED,eAAO,MAAM,eAAe,UAAwC,CAAA;AAIpE,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,CAEpD"}
@@ -3,13 +3,14 @@ export const SCENE_THEMES = [
3
3
  id: 'studio',
4
4
  name: 'Studio',
5
5
  appearance: 'light',
6
- background: '#ffffff',
7
- ground: '#f4f4f2',
6
+ background: '#fbfbfa',
7
+ backgroundSky: '#b6cfe7',
8
+ ground: '#e9e7e2',
8
9
  ambient: { color: '#ffffff', intensity: 0.15 },
9
- hemi: { sky: '#ffffff', ground: '#aaa49a', intensity: 0.6 },
10
+ hemi: { sky: '#ffffff', ground: '#aaa49a', intensity: 0.45 },
10
11
  lights: [
11
12
  { position: [10, 10, 10], color: '#ffffff', intensity: 4, castShadow: true },
12
- { position: [-10, 10, -10], color: '#ffffff', intensity: 0.75 },
13
+ { position: [-10, 10, -10], color: '#ffffff', intensity: 0.6 },
13
14
  ],
14
15
  toneMappingExposure: 0.9,
15
16
  clayTints: {
@@ -25,6 +26,7 @@ export const SCENE_THEMES = [
25
26
  name: 'Paper',
26
27
  appearance: 'light',
27
28
  background: '#ede9df',
29
+ backgroundSky: '#c0d2e4',
28
30
  ground: '#e7e1d3',
29
31
  ambient: { color: '#fff9eb', intensity: 0.55 },
30
32
  hemi: { sky: '#fff5d9', ground: '#c2b89c', intensity: 0.35 },
@@ -46,6 +48,7 @@ export const SCENE_THEMES = [
46
48
  name: 'Sunset',
47
49
  appearance: 'light',
48
50
  background: '#f6e8d4',
51
+ backgroundSky: '#b5bede',
49
52
  ground: '#ecd9bf',
50
53
  ambient: { color: '#ffd9a8', intensity: 0.45 },
51
54
  hemi: { sky: '#ffd9a8', ground: '#5b4634', intensity: 0.4 },
@@ -67,11 +70,12 @@ export const SCENE_THEMES = [
67
70
  name: 'Overcast',
68
71
  appearance: 'light',
69
72
  background: '#e6e7e6',
73
+ backgroundSky: '#c3ccd6',
70
74
  ground: '#dadcd9',
71
75
  ambient: { color: '#eef0ef', intensity: 1.1 },
72
76
  hemi: { sky: '#f4f5f3', ground: '#bcbfbb', intensity: 0.9 },
73
77
  lights: [{ position: [12, 28, 10], color: '#f4f5f3', intensity: 0.8, castShadow: true }],
74
- toneMappingExposure: 0.95,
78
+ toneMappingExposure: 0.9,
75
79
  clayTints: {
76
80
  wall: '#dedfdc',
77
81
  floor: '#cdcec9',
@@ -85,6 +89,7 @@ export const SCENE_THEMES = [
85
89
  name: 'Blueprint',
86
90
  appearance: 'light',
87
91
  background: '#dde6ef',
92
+ backgroundSky: '#a5c4e2',
88
93
  ground: '#c9d6e6',
89
94
  ambient: { color: '#cfdcec', intensity: 0.7 },
90
95
  hemi: { sky: '#dfeaf6', ground: '#5b6b80', intensity: 0.55 },
@@ -92,7 +97,7 @@ export const SCENE_THEMES = [
92
97
  { position: [16, 24, 12], color: '#e6efff', intensity: 1.8, castShadow: true },
93
98
  { position: [-12, 10, -8], color: '#9fb6d8', intensity: 0.4 },
94
99
  ],
95
- toneMappingExposure: 0.95,
100
+ toneMappingExposure: 0.9,
96
101
  clayTints: {
97
102
  wall: '#9fb6d2',
98
103
  floor: '#8ba2c2',
@@ -106,6 +111,7 @@ export const SCENE_THEMES = [
106
111
  name: 'Mediterranean',
107
112
  appearance: 'light',
108
113
  background: '#bdd6e8',
114
+ backgroundSky: '#8ab4d6',
109
115
  ground: '#ddd2bb',
110
116
  ambient: { color: '#d6e6f3', intensity: 0.5 },
111
117
  hemi: { sky: '#a8c8e2', ground: '#d8c9a4', intensity: 0.6 },
@@ -127,14 +133,15 @@ export const SCENE_THEMES = [
127
133
  name: 'Twilight',
128
134
  appearance: 'dark',
129
135
  background: '#3a3550',
130
- ground: '#4a4566',
131
- ambient: { color: '#a89cc8', intensity: 0.35 },
132
- hemi: { sky: '#d8a8c0', ground: '#1c1830', intensity: 0.5 },
136
+ backgroundSky: '#272338',
137
+ ground: '#67618a',
138
+ ambient: { color: '#a89cc8', intensity: 0.55 },
139
+ hemi: { sky: '#d8a8c0', ground: '#3a3450', intensity: 0.7 },
133
140
  lights: [
134
141
  { position: [-14, 22, -10], color: '#a4b6e8', intensity: 1.4, castShadow: true },
135
142
  { position: [14, 6, 8], color: '#ffb070', intensity: 0.9 },
136
143
  ],
137
- toneMappingExposure: 1.1,
144
+ toneMappingExposure: 0.9,
138
145
  clayTints: {
139
146
  wall: '#c5b9cf',
140
147
  floor: '#ad9fbb',
@@ -148,12 +155,13 @@ export const SCENE_THEMES = [
148
155
  name: 'Night',
149
156
  appearance: 'dark',
150
157
  background: '#1f2433',
151
- ground: '#2b3247',
152
- ambient: { color: '#a0b0ff', intensity: 0.07 },
153
- hemi: { sky: '#3a4666', ground: '#0e111c', intensity: 0.4 },
158
+ backgroundSky: '#12161f',
159
+ ground: '#4a5470',
160
+ ambient: { color: '#a0b0ff', intensity: 0.25 },
161
+ hemi: { sky: '#3a4666', ground: '#232a3d', intensity: 0.55 },
154
162
  lights: [
155
- { position: [10, 10, 10], color: '#e0e5ff', intensity: 0.8, castShadow: true },
156
- { position: [-10, 10, -10], color: '#8090ff', intensity: 0.2 },
163
+ { position: [10, 10, 10], color: '#e0e5ff', intensity: 1.2, castShadow: true },
164
+ { position: [-10, 10, -10], color: '#8090ff', intensity: 0.3 },
157
165
  ],
158
166
  toneMappingExposure: 0.9,
159
167
  clayTints: {
@@ -169,6 +177,7 @@ export const SCENE_THEMES = [
169
177
  name: 'Verdant',
170
178
  appearance: 'light',
171
179
  background: '#d6e4d2',
180
+ backgroundSky: '#aecde0',
172
181
  ground: '#c7d6b4',
173
182
  ambient: { color: '#e3efdd', intensity: 0.5 },
174
183
  hemi: { sky: '#cfe6cf', ground: '#8ea06f', intensity: 0.65 },
@@ -176,7 +185,7 @@ export const SCENE_THEMES = [
176
185
  { position: [16, 22, 12], color: '#fff6d8', intensity: 3, castShadow: true },
177
186
  { position: [-12, 10, -8], color: '#bfe0c2', intensity: 0.5 },
178
187
  ],
179
- toneMappingExposure: 0.95,
188
+ toneMappingExposure: 0.9,
180
189
  clayTints: {
181
190
  wall: '#eef0e6',
182
191
  floor: '#d8ddc6',
@@ -0,0 +1,4 @@
1
+ import type { Object3D } from 'three';
2
+ export declare function applyShadowOnly(root: Object3D): void;
3
+ export declare function clearShadowOnly(root: Object3D): void;
4
+ //# sourceMappingURL=shadow-only.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow-only.d.ts","sourceRoot":"","sources":["../../src/lib/shadow-only.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAuBrC,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CASpD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAOpD"}
@@ -0,0 +1,36 @@
1
+ import { SCENE_LAYER, SHADOW_ONLY_LAYER } from './layers';
2
+ /**
3
+ * Shadow-caster-only hiding: removes an object (and its descendants) from the
4
+ * color passes while keeping it in the shadow map, so a hidden roof or level
5
+ * still shadows the interior and sun enters through windows correctly.
6
+ *
7
+ * Uses layer masks instead of `visible = false` for two reasons: `visible`
8
+ * cascades (and, critically, prunes the object from the shadow pass too),
9
+ * while layers are tested per-object against the rendering camera — the main
10
+ * camera never enables {@link SHADOW_ONLY_LAYER}, but every shadow-casting
11
+ * light's shadow camera does (see `lights.tsx`).
12
+ *
13
+ * The original `layers.mask` is stashed under a private Symbol so
14
+ * {@link clearShadowOnly} restores the exact prior state. Both calls are
15
+ * idempotent and cheap to reapply.
16
+ */
17
+ const ORIGINAL_LAYERS = Symbol('pascal:shadow-only:original-layers');
18
+ export function applyShadowOnly(root) {
19
+ root.traverse((obj) => {
20
+ const carrier = obj;
21
+ if (carrier[ORIGINAL_LAYERS] === undefined) {
22
+ carrier[ORIGINAL_LAYERS] = obj.layers.mask;
23
+ }
24
+ obj.layers.disable(SCENE_LAYER);
25
+ obj.layers.enable(SHADOW_ONLY_LAYER);
26
+ });
27
+ }
28
+ export function clearShadowOnly(root) {
29
+ root.traverse((obj) => {
30
+ const carrier = obj;
31
+ if (carrier[ORIGINAL_LAYERS] === undefined)
32
+ return;
33
+ obj.layers.mask = carrier[ORIGINAL_LAYERS];
34
+ delete carrier[ORIGINAL_LAYERS];
35
+ });
36
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * three runs at 0.185 but @types/three is pinned at 0.184: the 0.185 typings
3
+ * make tsgo's type inference allocate unboundedly (microsoft/typescript-go
4
+ * #2125 class) and OOM the machine. r185 renamed directionToColor /
5
+ * colorToDirection to packNormalToRGB / unpackRGBToNormal — re-export the new
6
+ * runtime names under the old names' signatures. Delete this file (and the
7
+ * @types/three pin) once tsgo handles the 0.185 types; the `typeof` references
8
+ * to the removed old names will fail the build as a reminder.
9
+ */
10
+ export declare const packNormalToRGB: (node: import("three/webgpu").Node) => import("three/webgpu").Node<"vec3">;
11
+ export declare const unpackRGBToNormal: (node: import("three/webgpu").Node) => import("three/webgpu").Node<"vec3">;
12
+ //# sourceMappingURL=tsl-compat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tsl-compat.d.ts","sourceRoot":"","sources":["../../src/lib/tsl-compat.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,4EACV,CAAA;AAClB,eAAO,MAAM,iBAAiB,4EAEX,CAAA"}
@@ -0,0 +1,13 @@
1
+ import * as TSL from 'three/tsl';
2
+ /**
3
+ * three runs at 0.185 but @types/three is pinned at 0.184: the 0.185 typings
4
+ * make tsgo's type inference allocate unboundedly (microsoft/typescript-go
5
+ * #2125 class) and OOM the machine. r185 renamed directionToColor /
6
+ * colorToDirection to packNormalToRGB / unpackRGBToNormal — re-export the new
7
+ * runtime names under the old names' signatures. Delete this file (and the
8
+ * @types/three pin) once tsgo handles the 0.185 types; the `typeof` references
9
+ * to the removed old names will fail the build as a reminder.
10
+ */
11
+ export const packNormalToRGB = TSL
12
+ .packNormalToRGB;
13
+ export const unpackRGBToNormal = TSL.unpackRGBToNormal;