@pascal-app/viewer 1.0.3 → 1.0.5

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 (276) hide show
  1. package/dist/capture/capture-runtime.js +1 -1
  2. package/dist/components/error-boundary.d.ts.map +1 -1
  3. package/dist/components/renderers/node-renderer.d.ts +1 -1
  4. package/dist/components/renderers/node-renderer.d.ts.map +1 -1
  5. package/dist/components/renderers/node-renderer.js +12 -4
  6. package/dist/components/renderers/parametric-node-renderer.d.ts.map +1 -1
  7. package/dist/components/viewer/bvh-ecctrl.d.ts.map +1 -1
  8. package/dist/components/viewer/frame-limiter.d.ts +1 -0
  9. package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
  10. package/dist/components/viewer/frame-limiter.js +22 -3
  11. package/dist/components/viewer/glb-interactive.d.ts +25 -1
  12. package/dist/components/viewer/glb-interactive.d.ts.map +1 -1
  13. package/dist/components/viewer/glb-interactive.js +253 -86
  14. package/dist/components/viewer/glb-mechanisms.d.ts +10 -0
  15. package/dist/components/viewer/glb-mechanisms.d.ts.map +1 -0
  16. package/dist/components/viewer/glb-mechanisms.js +19 -0
  17. package/dist/components/viewer/glb-reference-nodes.js +1 -1
  18. package/dist/components/viewer/glb-replace-instances.js +1 -1
  19. package/dist/components/viewer/glb-scene.d.ts +45 -27
  20. package/dist/components/viewer/glb-scene.d.ts.map +1 -1
  21. package/dist/components/viewer/glb-scene.js +421 -508
  22. package/dist/components/viewer/glb-walkthrough-controller.d.ts +1 -1
  23. package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -1
  24. package/dist/components/viewer/glb-walkthrough-controller.js +13 -2
  25. package/dist/components/viewer/index.d.ts +24 -1
  26. package/dist/components/viewer/index.d.ts.map +1 -1
  27. package/dist/components/viewer/index.js +111 -37
  28. package/dist/components/viewer/lights.d.ts.map +1 -1
  29. package/dist/components/viewer/lights.js +113 -22
  30. package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
  31. package/dist/components/viewer/perf-monitor.js +6 -0
  32. package/dist/components/viewer/perf-panel.d.ts.map +1 -1
  33. package/dist/components/viewer/perf-panel.js +1 -1
  34. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  35. package/dist/components/viewer/post-processing.js +104 -36
  36. package/dist/components/viewer/registered-systems.d.ts.map +1 -1
  37. package/dist/components/viewer/registered-systems.js +17 -3
  38. package/dist/components/viewer/render-error.d.ts +18 -0
  39. package/dist/components/viewer/render-error.d.ts.map +1 -0
  40. package/dist/components/viewer/render-error.js +29 -0
  41. package/dist/components/viewer/scene-bvh.d.ts.map +1 -1
  42. package/dist/components/viewer/scene-bvh.js +1 -1
  43. package/dist/components/viewer/scene-environment.d.ts.map +1 -1
  44. package/dist/components/viewer/scene-environment.js +31 -11
  45. package/dist/components/viewer/scene-ground-replacement.d.ts +6 -0
  46. package/dist/components/viewer/scene-ground-replacement.d.ts.map +1 -1
  47. package/dist/components/viewer/scene-ground-replacement.js +15 -0
  48. package/dist/components/viewer/selection-manager.d.ts.map +1 -1
  49. package/dist/components/viewer/selection-manager.js +25 -7
  50. package/dist/components/viewer/underground-ambiance.d.ts +9 -0
  51. package/dist/components/viewer/underground-ambiance.d.ts.map +1 -0
  52. package/dist/components/viewer/underground-ambiance.js +105 -0
  53. package/dist/components/viewer/viewer-camera.d.ts +4 -0
  54. package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
  55. package/dist/components/viewer/viewer-camera.js +12 -2
  56. package/dist/components/viewer/viewer-presentations.d.ts.map +1 -1
  57. package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
  58. package/dist/hooks/use-gltf-ktx2.js +2 -0
  59. package/dist/hooks/use-node-events.d.ts.map +1 -1
  60. package/dist/index.d.ts +36 -16
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +34 -19
  63. package/dist/lib/asset-url.d.ts.map +1 -1
  64. package/dist/lib/asset-url.js +7 -1
  65. package/dist/lib/backdrop.d.ts +17 -0
  66. package/dist/lib/backdrop.d.ts.map +1 -1
  67. package/dist/lib/backdrop.js +18 -1
  68. package/dist/lib/construction-dust.d.ts +57 -0
  69. package/dist/lib/construction-dust.d.ts.map +1 -0
  70. package/dist/lib/construction-dust.js +187 -0
  71. package/dist/lib/csg-utils.js +1 -1
  72. package/dist/lib/display-state.d.ts +25 -0
  73. package/dist/lib/display-state.d.ts.map +1 -0
  74. package/dist/lib/display-state.js +1 -0
  75. package/dist/lib/foundation-materials.d.ts +26 -0
  76. package/dist/lib/foundation-materials.d.ts.map +1 -0
  77. package/dist/lib/foundation-materials.js +65 -0
  78. package/dist/lib/gltf-unlit.d.ts +10 -0
  79. package/dist/lib/gltf-unlit.d.ts.map +1 -0
  80. package/dist/lib/gltf-unlit.js +23 -0
  81. package/dist/lib/ground-window.d.ts +33 -0
  82. package/dist/lib/ground-window.d.ts.map +1 -0
  83. package/dist/lib/ground-window.js +114 -0
  84. package/dist/lib/hero-pose.d.ts +13 -3
  85. package/dist/lib/hero-pose.d.ts.map +1 -1
  86. package/dist/lib/hero-pose.js +72 -5
  87. package/dist/lib/ink-edges.d.ts +6 -3
  88. package/dist/lib/ink-edges.d.ts.map +1 -1
  89. package/dist/lib/ink-edges.js +17 -7
  90. package/dist/lib/key-light-override.d.ts +11 -0
  91. package/dist/lib/key-light-override.d.ts.map +1 -0
  92. package/dist/lib/key-light-override.js +14 -0
  93. package/dist/lib/ktx2-loader.d.ts +7 -0
  94. package/dist/lib/ktx2-loader.d.ts.map +1 -1
  95. package/dist/lib/ktx2-loader.js +35 -0
  96. package/dist/lib/layer-pass.d.ts.map +1 -1
  97. package/dist/lib/layers.d.ts +11 -7
  98. package/dist/lib/layers.d.ts.map +1 -1
  99. package/dist/lib/layers.js +16 -6
  100. package/dist/lib/live-frame-hold.d.ts +14 -0
  101. package/dist/lib/live-frame-hold.d.ts.map +1 -0
  102. package/dist/lib/live-frame-hold.js +28 -0
  103. package/dist/lib/materials.d.ts +19 -7
  104. package/dist/lib/materials.d.ts.map +1 -1
  105. package/dist/lib/materials.js +65 -9
  106. package/dist/lib/merged-outline-node.d.ts +5 -0
  107. package/dist/lib/merged-outline-node.d.ts.map +1 -1
  108. package/dist/lib/merged-outline-node.js +80 -2
  109. package/dist/lib/node-top-surface-height.d.ts +6 -0
  110. package/dist/lib/node-top-surface-height.d.ts.map +1 -0
  111. package/dist/lib/node-top-surface-height.js +74 -0
  112. package/dist/lib/perf-probe-state.d.ts +39 -0
  113. package/dist/lib/perf-probe-state.d.ts.map +1 -0
  114. package/dist/lib/perf-probe-state.js +17 -0
  115. package/dist/lib/pointer-events.d.ts +26 -2
  116. package/dist/lib/pointer-events.d.ts.map +1 -1
  117. package/dist/lib/pointer-events.js +99 -12
  118. package/dist/lib/post-processing-resources.d.ts.map +1 -1
  119. package/dist/lib/procedural-emission.d.ts +7 -0
  120. package/dist/lib/procedural-emission.d.ts.map +1 -0
  121. package/dist/lib/procedural-emission.js +54 -0
  122. package/dist/lib/reveal-candidates.d.ts +80 -0
  123. package/dist/lib/reveal-candidates.d.ts.map +1 -0
  124. package/dist/lib/reveal-candidates.js +524 -0
  125. package/dist/lib/reveal-ghost.d.ts +9 -0
  126. package/dist/lib/reveal-ghost.d.ts.map +1 -0
  127. package/dist/lib/reveal-ghost.js +62 -0
  128. package/dist/lib/reveal-pending.d.ts +12 -0
  129. package/dist/lib/reveal-pending.d.ts.map +1 -0
  130. package/dist/lib/reveal-pending.js +12 -0
  131. package/dist/lib/reveal-pose.d.ts +70 -0
  132. package/dist/lib/reveal-pose.d.ts.map +1 -0
  133. package/dist/lib/reveal-pose.js +248 -0
  134. package/dist/lib/reveal-schedule.d.ts +208 -0
  135. package/dist/lib/reveal-schedule.d.ts.map +1 -0
  136. package/dist/lib/reveal-schedule.js +410 -0
  137. package/dist/lib/reveal-texture-scale.d.ts +5 -0
  138. package/dist/lib/reveal-texture-scale.d.ts.map +1 -0
  139. package/dist/lib/reveal-texture-scale.js +113 -0
  140. package/dist/lib/reveal-windows.d.ts +23 -0
  141. package/dist/lib/reveal-windows.d.ts.map +1 -0
  142. package/dist/lib/reveal-windows.js +31 -0
  143. package/dist/lib/reveal-wipe.d.ts +71 -0
  144. package/dist/lib/reveal-wipe.d.ts.map +1 -0
  145. package/dist/lib/reveal-wipe.js +105 -0
  146. package/dist/lib/scene-pass-mrt.d.ts +12 -0
  147. package/dist/lib/scene-pass-mrt.d.ts.map +1 -0
  148. package/dist/lib/scene-pass-mrt.js +23 -0
  149. package/dist/lib/scene-support-height.d.ts +4 -0
  150. package/dist/lib/scene-support-height.d.ts.map +1 -0
  151. package/dist/lib/scene-support-height.js +34 -0
  152. package/dist/lib/scene-themes.d.ts +30 -8
  153. package/dist/lib/scene-themes.d.ts.map +1 -1
  154. package/dist/lib/scene-themes.js +36 -0
  155. package/dist/lib/scene-visibility.d.ts +17 -1
  156. package/dist/lib/scene-visibility.d.ts.map +1 -1
  157. package/dist/lib/scene-visibility.js +53 -3
  158. package/dist/lib/scripted-opening.d.ts +11 -0
  159. package/dist/lib/scripted-opening.d.ts.map +1 -0
  160. package/dist/lib/scripted-opening.js +20 -0
  161. package/dist/lib/site-surfaces.d.ts +32 -0
  162. package/dist/lib/site-surfaces.d.ts.map +1 -0
  163. package/dist/lib/site-surfaces.js +70 -0
  164. package/dist/lib/snapshot-pipeline.d.ts +34 -3
  165. package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
  166. package/dist/lib/snapshot-pipeline.js +247 -117
  167. package/dist/lib/terrain-perimeter-fill.d.ts.map +1 -1
  168. package/dist/lib/terrain-perimeter-fill.js +22 -14
  169. package/dist/lib/tsl-compat.d.ts +2 -2
  170. package/dist/lib/tsl-compat.d.ts.map +1 -1
  171. package/dist/lib/underground-ambiance.d.ts +168 -0
  172. package/dist/lib/underground-ambiance.d.ts.map +1 -0
  173. package/dist/lib/underground-ambiance.js +334 -0
  174. package/dist/lib/zone-geometry.d.ts +11 -0
  175. package/dist/lib/zone-geometry.d.ts.map +1 -0
  176. package/dist/lib/zone-geometry.js +46 -0
  177. package/dist/store/use-item-light-pool.d.ts +14 -10
  178. package/dist/store/use-item-light-pool.d.ts.map +1 -1
  179. package/dist/store/use-item-light-pool.js +52 -26
  180. package/dist/store/use-viewer.d.ts +194 -26
  181. package/dist/store/use-viewer.d.ts.map +1 -1
  182. package/dist/store/use-viewer.js +164 -21
  183. package/dist/systems/ceiling/ceiling-system.d.ts +15 -1
  184. package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
  185. package/dist/systems/ceiling/ceiling-system.js +88 -6
  186. package/dist/systems/construction-reveal/construction-dust.d.ts +16 -0
  187. package/dist/systems/construction-reveal/construction-dust.d.ts.map +1 -0
  188. package/dist/systems/construction-reveal/construction-dust.js +92 -0
  189. package/dist/systems/construction-reveal/construction-reveal.d.ts +276 -0
  190. package/dist/systems/construction-reveal/construction-reveal.d.ts.map +1 -0
  191. package/dist/systems/construction-reveal/construction-reveal.js +2383 -0
  192. package/dist/systems/construction-reveal/dust-material.d.ts +10 -0
  193. package/dist/systems/construction-reveal/dust-material.d.ts.map +1 -0
  194. package/dist/systems/construction-reveal/dust-material.js +17 -0
  195. package/dist/systems/construction-reveal/ghost-dress.d.ts +10 -0
  196. package/dist/systems/construction-reveal/ghost-dress.d.ts.map +1 -0
  197. package/dist/systems/construction-reveal/ghost-dress.js +24 -0
  198. package/dist/systems/door/door-system.d.ts.map +1 -1
  199. package/dist/systems/door/door-system.js +55 -17
  200. package/dist/systems/elevator/elevator-interaction-system.d.ts +7 -0
  201. package/dist/systems/elevator/elevator-interaction-system.d.ts.map +1 -1
  202. package/dist/systems/elevator/elevator-interaction-system.js +18 -1
  203. package/dist/systems/floor-elevation/floor-elevation-system.d.ts +3 -1
  204. package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -1
  205. package/dist/systems/floor-elevation/floor-elevation-system.js +33 -5
  206. package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
  207. package/dist/systems/geometry/geometry-system.js +71 -11
  208. package/dist/systems/interactive/control-widget.d.ts.map +1 -1
  209. package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
  210. package/dist/systems/interactive/interactive-system.js +52 -17
  211. package/dist/systems/interactive/procedural-controls.d.ts +13 -0
  212. package/dist/systems/interactive/procedural-controls.d.ts.map +1 -0
  213. package/dist/systems/interactive/procedural-controls.js +17 -0
  214. package/dist/systems/interactive/scripted-clips.d.ts +19 -0
  215. package/dist/systems/interactive/scripted-clips.d.ts.map +1 -0
  216. package/dist/systems/interactive/scripted-clips.js +134 -0
  217. package/dist/systems/item/item-system.d.ts.map +1 -1
  218. package/dist/systems/item/item-system.js +9 -3
  219. package/dist/systems/item/object-cut-invalidation.d.ts +3 -0
  220. package/dist/systems/item/object-cut-invalidation.d.ts.map +1 -0
  221. package/dist/systems/item/object-cut-invalidation.js +68 -0
  222. package/dist/systems/item-light/item-light-system.d.ts +1 -1
  223. package/dist/systems/item-light/item-light-system.d.ts.map +1 -1
  224. package/dist/systems/item-light/item-light-system.js +48 -53
  225. package/dist/systems/level/level-hold.d.ts +4 -0
  226. package/dist/systems/level/level-hold.d.ts.map +1 -0
  227. package/dist/systems/level/level-hold.js +14 -0
  228. package/dist/systems/level/level-system.d.ts.map +1 -1
  229. package/dist/systems/level/level-system.js +19 -6
  230. package/dist/systems/level/level-utils.d.ts +19 -6
  231. package/dist/systems/level/level-utils.d.ts.map +1 -1
  232. package/dist/systems/level/level-utils.js +68 -9
  233. package/dist/systems/level/shadow-only-levels.d.ts +9 -0
  234. package/dist/systems/level/shadow-only-levels.d.ts.map +1 -0
  235. package/dist/systems/level/shadow-only-levels.js +7 -0
  236. package/dist/systems/roof/__fixtures__/roof-plane-cases.d.ts +103 -0
  237. package/dist/systems/roof/__fixtures__/roof-plane-cases.d.ts.map +1 -0
  238. package/dist/systems/roof/__fixtures__/roof-plane-cases.js +317 -0
  239. package/dist/systems/roof/roof-materials.d.ts +16 -2
  240. package/dist/systems/roof/roof-materials.d.ts.map +1 -1
  241. package/dist/systems/roof/roof-materials.js +64 -31
  242. package/dist/systems/roof/roof-system.d.ts +21 -4
  243. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  244. package/dist/systems/roof/roof-system.js +374 -49
  245. package/dist/systems/slab/slab-system.d.ts +1 -1
  246. package/dist/systems/slab/slab-system.d.ts.map +1 -1
  247. package/dist/systems/slab/slab-system.js +49 -19
  248. package/dist/systems/stair/stair-system.d.ts.map +1 -1
  249. package/dist/systems/stair/stair-system.js +133 -354
  250. package/dist/systems/wall/wall-cutout-cache.d.ts +39 -3
  251. package/dist/systems/wall/wall-cutout-cache.d.ts.map +1 -1
  252. package/dist/systems/wall/wall-cutout-cache.js +141 -19
  253. package/dist/systems/wall/wall-cutout.d.ts +6 -0
  254. package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
  255. package/dist/systems/wall/wall-cutout.js +42 -28
  256. package/dist/systems/wall/wall-finish-data.d.ts +22 -0
  257. package/dist/systems/wall/wall-finish-data.d.ts.map +1 -0
  258. package/dist/systems/wall/wall-finish-data.js +17 -0
  259. package/dist/systems/wall/wall-material-variant.d.ts.map +1 -1
  260. package/dist/systems/wall/wall-materials.d.ts +9 -4
  261. package/dist/systems/wall/wall-materials.d.ts.map +1 -1
  262. package/dist/systems/wall/wall-materials.js +135 -153
  263. package/dist/systems/wall/wall-placeholder-sweep.d.ts.map +1 -1
  264. package/dist/systems/wall/wall-system.d.ts +33 -2
  265. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  266. package/dist/systems/wall/wall-system.js +621 -159
  267. package/dist/systems/window/corner-frame.d.ts +10 -0
  268. package/dist/systems/window/corner-frame.d.ts.map +1 -0
  269. package/dist/systems/window/corner-frame.js +17 -0
  270. package/dist/systems/window/window-system.d.ts +1 -1
  271. package/dist/systems/window/window-system.d.ts.map +1 -1
  272. package/dist/systems/window/window-system.js +71 -27
  273. package/package.json +10 -10
  274. package/dist/systems/fence/fence-system.d.ts +0 -22
  275. package/dist/systems/fence/fence-system.d.ts.map +0 -1
  276. package/dist/systems/fence/fence-system.js +0 -357
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useCallback, useEffect, useRef, useState } from 'react';
4
4
  import { createPortal } from 'react-dom';
5
5
  import { usePerfActionReceipts } from '../../lib/perf-actions';
@@ -1 +1 @@
1
- {"version":3,"file":"post-processing.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/post-processing.tsx"],"names":[],"mappings":"AA8CA,eAAO,MAAM,YAAY;;;CAGxB,CAAA;AAGD,eAAO,MAAM,WAAW;;;;;;;;;;;;;CAavB,CAAA;AAgED,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,UAAU,CAAA;CACpB,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;AAS9B,eAAO,MAAM,oBAAoB,EAAE,WAElC,CAAA;AA+CD,QAAA,MAAM,oBAAoB,GAAI,iCAG3B;IACD,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,SAmnBA,CAAA;AAED,eAAe,oBAAoB,CAAA"}
1
+ {"version":3,"file":"post-processing.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/post-processing.tsx"],"names":[],"mappings":"AA0DA,eAAO,MAAM,YAAY;IACvB,QAAQ;IACR,UAAU;CACX,CAAA;AAGD,eAAO,MAAM,WAAW;IACtB,OAAO;IACP,UAAU;IACV,SAAS;IACT,MAAM;IACN,SAAS;IACT,SAAS;IACT,gBAAgB;IAChB,WAAW;IACX,WAAW;IACX,kBAAkB;IAClB,sBAAsB;IACtB,oBAAoB;CACrB,CAAA;AAgED,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,UAAU,CAAA;CACpB,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;AAS9B,eAAO,MAAM,oBAAoB,EAAE,WAElC,CAAA;AA+CD,QAAA,MAAM,oBAAoB,oCAGvB;IACD,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,SAwsBA,CAAA;eAEc,oBAAoB"}
@@ -3,25 +3,26 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { Color, Layers, Matrix4, Scene, UnsignedByteType } from 'three';
4
4
  import { ssgi } from 'three/addons/tsl/display/SSGINode.js';
5
5
  import { denoise } from 'three/examples/jsm/tsl/display/DenoiseNode.js';
6
- import { add, diffuseColor, mix, mrt, normalView, normalWorldGeometry, oscSine, output, pass, premultiplyAlpha, renderOutput, sample, saturation, screenUV, smoothstep, time, float as tslFloat, uniform, vec3, vec4, } from 'three/tsl';
6
+ import { add, diffuseColor, mix, normalView, normalWorldGeometry, oscSine, output, pass, premultiplyAlpha, renderOutput, sample, saturation, screenUV, smoothstep, time, color as tslColor, float as tslFloat, uniform, vec3, vec4, } from 'three/tsl';
7
7
  import { RenderPipeline, TimestampQuery } from 'three/webgpu';
8
- import { backdropGradient, deepSkyColor, horizonHazeColor } from '../../lib/backdrop';
8
+ import { backdropColors, backdropGradient, flatBackdropOutput } from '../../lib/backdrop';
9
9
  import { edgeColorFor, edgeOpacityScaleFor } from '../../lib/edge-style';
10
10
  import { PERF_OVERLAY_ENABLED } from '../../lib/gpu-perf';
11
- import { inkedEdges } from '../../lib/ink-edges';
11
+ import { createEdgeDepthSampler, inkedEdges } from '../../lib/ink-edges';
12
12
  import { refreshIsolation } from '../../lib/isolation';
13
13
  import { LayerPassIndex, LayerPassNode } from '../../lib/layer-pass';
14
- import { GRID_LAYER, OVERLAY_LAYER, SCENE_LAYER, ZONE_LAYER } from '../../lib/layers';
14
+ import { OVERLAY_LAYER, SCENE_LAYER, scenePassLayers, ZONE_LAYER } from '../../lib/layers';
15
+ import { isLiveFrameHeld } from '../../lib/live-frame-hold';
15
16
  import { mergedOutline } from '../../lib/merged-outline-node';
16
17
  import { recordPerfSample, timeSpan } from '../../lib/perf-tracks';
17
18
  import { PostProcessingResources } from '../../lib/post-processing-resources';
18
- import { getSceneTheme } from '../../lib/scene-themes';
19
+ import { sceneLightingMask, scenePassMrt } from '../../lib/scene-pass-mrt';
19
20
  import { packNormalToRGB, unpackRGBToNormal } from '../../lib/tsl-compat';
21
+ import { earthNow, UNDERGROUND_VIGNETTE, undergroundAmbianceNode, undergroundBackdrop, undergroundDissolve, undergroundDissolveGrain, undergroundEarthNode, undergroundFogAmount, undergroundVignette, worldPositionFromDepth, } from '../../lib/underground-ambiance';
20
22
  import useViewer from '../../store/use-viewer';
21
23
  import { useSceneAtmosphere } from './scene-atmosphere';
22
- // Scene-referred grade applied before the output tone mapping (AgX). AgX rolls
23
- // highlights off gently but reads flat on its own; a mild mid-gray-pivot
24
- // contrast + saturation lift restores the punch. Rendered shading only.
24
+ // A mild mid-gray contrast and saturation lift separates surfaces before the
25
+ // output transform. Saved project looks can turn it off. Rendered shading only.
25
26
  export const GRADE_PARAMS = {
26
27
  contrast: 1.05,
27
28
  saturation: 1.1,
@@ -142,29 +143,33 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
142
143
  const { gl: renderer, invalidate, scene, camera, size } = useThree();
143
144
  const resourcesRef = useRef(null);
144
145
  const atmosphere = useSceneAtmosphere();
145
- const directSkyNode = useMemo(() => (atmosphere ? atmosphere.skyRadiance(normalWorldGeometry) : null), [atmosphere]);
146
+ // Under the ground the sky is the dark mode's: the same mix the pipeline's backdrop makes.
147
+ const directSkyNode = useMemo(() => atmosphere
148
+ ? mix(atmosphere.skyRadiance(normalWorldGeometry), undergroundBackdrop(normalWorldGeometry.y), undergroundEarthNode())
149
+ : null, [atmosphere]);
146
150
  const hasPipelineErrorRef = useRef(false);
147
151
  const retryCountRef = useRef(0);
148
152
  const rebuildTimeoutRef = useRef(null);
149
153
  const skippedZeroSizeRef = useRef(false);
150
154
  // Background color uniform — updated every frame via lerp, read by the TSL pipeline.
151
155
  // Initialised from the current scene theme so there's no flash on first render.
152
- const initTheme = getSceneTheme(useViewer.getState().sceneTheme);
156
+ const initTheme = useViewer.getState().sceneAppearance;
157
+ const initBackdrop = backdropColors(initTheme);
153
158
  const initBg = initTheme.background;
154
159
  const bgUniform = useRef(uniform(new Color(initBg)));
155
160
  const bgCurrent = useRef(new Color(initBg));
156
161
  const bgTarget = useRef(new Color());
157
162
  // Zenith colour of the backdrop gradient (falls back to the flat background).
158
- const initSky = initTheme.backgroundSky ?? initBg;
163
+ const initSky = initBackdrop.sky;
159
164
  const bgSkyUniform = useRef(uniform(new Color(initSky)));
160
165
  const bgSkyCurrent = useRef(new Color(initSky));
161
166
  const bgSkyTarget = useRef(new Color());
162
167
  // Horizon haze band + deep zenith (derived — see lib/backdrop.ts).
163
- const initHaze = horizonHazeColor(initSky, initTheme.appearance);
168
+ const initHaze = initBackdrop.haze;
164
169
  const bgHazeUniform = useRef(uniform(new Color(initHaze)));
165
170
  const bgHazeCurrent = useRef(new Color(initHaze));
166
171
  const bgHazeTarget = useRef(new Color());
167
- const initSkyDeep = deepSkyColor(initSky);
172
+ const initSkyDeep = initBackdrop.skyDeep;
168
173
  const bgSkyDeepUniform = useRef(uniform(new Color(initSkyDeep)));
169
174
  const bgSkyDeepCurrent = useRef(new Color(initSkyDeep));
170
175
  const bgSkyDeepTarget = useRef(new Color());
@@ -173,6 +178,9 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
173
178
  // view ray from these to find the true horizon (dir.y = 0).
174
179
  const camProjInvUniform = useRef(uniform(new Matrix4()));
175
180
  const camWorldUniform = useRef(uniform(new Matrix4()));
181
+ // The clear colour of the no-pipeline fallback under the ground (scratch, and the dark mode's tone).
182
+ const fallbackClear = useRef(new Color());
183
+ const fallbackEarth = useRef(new Color(UNDERGROUND_VIGNETTE));
176
184
  // Ink-line colour follows the scene-theme background luminance (dark lines on
177
185
  // light scenes, light on dark), refreshed each frame like the background.
178
186
  // Dark scenes also scale the ink opacity down (see edge-style.ts).
@@ -189,13 +197,10 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
189
197
  // picking), so without this the gizmos/handles/tool previews land in the
190
198
  // depth+normal MRT and get inked / AO'd as if they were geometry. The grid is
191
199
  // kept in here (not the overlay pass) so scene geometry depth-occludes it; it's
192
- // a flat, depth-non-writing plane so the ink never picks it up.
193
- const sceneOnlyLayers = useMemo(() => {
194
- const l = new Layers();
195
- l.set(SCENE_LAYER);
196
- l.enable(GRID_LAYER);
197
- return l;
198
- }, []);
200
+ // a flat, depth-non-writing plane. The dust shares the layer and writes alpha 0 to
201
+ // the normal and diffuse attachments, which `scenePassMrt` blends, so the ink
202
+ // never sees its quads.
203
+ const sceneOnlyLayers = useMemo(scenePassLayers, []);
199
204
  // Editor overlays render in their own pass, composited on top after the ink
200
205
  // and outlines so they read as crisp UI rather than scene geometry.
201
206
  const overlayLayers = useMemo(() => {
@@ -203,7 +208,10 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
203
208
  l.set(OVERLAY_LAYER);
204
209
  return l;
205
210
  }, []);
206
- const hoverHighlightMode = useViewer((s) => s.hoverHighlightMode);
211
+ const hoverMode = useViewer((s) => s.hoverHighlightMode);
212
+ // Elements a chat chip points at draw in the `point` style whatever the editor's hover mode is.
213
+ const hasPointedIds = useViewer((s) => s.pointedIds.length > 0);
214
+ const hoverHighlightMode = hasPointedIds ? 'point' : hoverMode;
207
215
  const hoverVisibleColor = useMemo(() => uniform(new Color(DEFAULT_HOVER_STYLE.visibleColor)), []);
208
216
  const hoverHiddenColor = useMemo(() => uniform(new Color(DEFAULT_HOVER_STYLE.hiddenColor)), []);
209
217
  const hoverStrength = useMemo(() => uniform(DEFAULT_HOVER_STYLE.strength), []);
@@ -211,6 +219,9 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
211
219
  // Subscribe to projectId so the pipeline rebuilds on project switch
212
220
  const projectId = useViewer((s) => s.projectId);
213
221
  const shading = useViewer((s) => s.shading);
222
+ const ambientOcclusion = useViewer((s) => s.sceneAppearance.postprocessing?.ambientOcclusion !== false);
223
+ const colorGrading = useViewer((s) => s.sceneAppearance.postprocessing?.colorGrading !== false);
224
+ const flatBackground = useViewer((s) => s.sceneAppearance.backgroundSky === null);
214
225
  const edges = useViewer((s) => s.edges);
215
226
  const inkOpacityOverride = useViewer((s) => s.inkOpacity);
216
227
  const transparentBackground = useViewer((s) => s.transparentBackground);
@@ -294,7 +305,7 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
294
305
  disposePipeline();
295
306
  return;
296
307
  }
297
- const ssgiEnabled = shading === 'rendered' && SSGI_PARAMS.enabled && !perfDisable.ao;
308
+ const ssgiEnabled = shading === 'rendered' && ambientOcclusion && SSGI_PARAMS.enabled && !perfDisable.ao;
298
309
  const denoiseEnabled = ssgiEnabled && !perfDisable.denoise;
299
310
  const outlineEnabled = !perfDisable.outline;
300
311
  const inkEnabled = edges !== 'off';
@@ -312,6 +323,8 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
312
323
  perfDisable,
313
324
  projectId,
314
325
  shading,
326
+ ambientOcclusion,
327
+ colorGrading,
315
328
  transparentBackground,
316
329
  rendererCtor: renderer.constructor?.name,
317
330
  width,
@@ -371,18 +384,21 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
371
384
  // Scene depth is shared by SSGI, ink, and outlines.
372
385
  // The normal MRT is only built when SSGI or ink needs it.
373
386
  const scenePassDepth = scenePass.getTextureNode('depth');
387
+ const sampleEdgeDepth = createEdgeDepthSampler(scenePassDepth, camera);
374
388
  let scenePassNormal = null;
375
389
  if (needsNormalMRT) {
376
- scenePass.setMRT(mrt({
390
+ scenePass.setMRT(scenePassMrt({
377
391
  output,
378
392
  diffuseColor,
379
393
  normal: packNormalToRGB(normalView),
394
+ lighting: sceneLightingMask(),
380
395
  }));
381
396
  scenePassNormal = scenePass.getTextureNode('normal');
382
397
  }
383
398
  if (scenePassNormal) {
384
399
  const normalTexture = scenePass.getTexture('normal');
385
400
  normalTexture.type = UnsignedByteType;
401
+ scenePass.getTexture('lighting').type = UnsignedByteType;
386
402
  }
387
403
  // Extract normal from color-encoded texture (SSGI consumes the node form).
388
404
  const normalNode = scenePassNormal;
@@ -428,10 +444,12 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
428
444
  // (same ≈150→350 m window as ink-edges' distanceFade) so the horizon
429
445
  // disc and the geometry↔sky depth cliff never grow an AO band — that
430
446
  // band read as a visible line along the horizon.
431
- const aoFarFade = smoothstep(tslFloat(0.9994), tslFloat(0.9998), scenePassDepth.sample(screenUV).r);
447
+ const aoFarFade = smoothstep(tslFloat(0.9994), tslFloat(0.9998), sampleEdgeDepth(screenUV));
432
448
  ao = mix(ao, tslFloat(1), aoFarFade);
449
+ const lightingWeight = scenePass.getTextureNode('lighting').r;
450
+ ao = mix(tslFloat(1), ao, lightingWeight);
433
451
  // Composite: scene * AO + diffuse * GI
434
- sceneColor = vec4(add(scenePassColor.rgb.mul(ao), add(zonePass.rgb, scenePassDiffuse.rgb.mul(gi))), contentAlpha);
452
+ sceneColor = vec4(add(scenePassColor.rgb.mul(ao), add(zonePass.rgb, scenePassDiffuse.rgb.mul(gi).mul(lightingWeight))), contentAlpha);
435
453
  }
436
454
  // Screen-space ink outline (SketchUp look) — depth/normal edge detection
437
455
  // over the composited scene. Topology-agnostic, so it handles CSG-cut
@@ -439,7 +457,7 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
439
457
  if (inkEnabled && scenePassDepth && scenePassNormal) {
440
458
  sceneColor = vec4(inkedEdges({
441
459
  sceneRgb: sceneColor.rgb,
442
- depthTex: scenePassDepth,
460
+ sampleDepth: sampleEdgeDepth,
443
461
  normalTex: scenePassNormal,
444
462
  inkColor: inkColorUniform.current,
445
463
  radius: inkRadius,
@@ -452,7 +470,7 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
452
470
  // backdrop below so geometry that fades to the background colour (the
453
471
  // horizon disc) matches it exactly.
454
472
  const gradeRgb = (rgb) => saturation(rgb.div(0.18).pow(vec3(GRADE_PARAMS.contrast)).mul(0.18), GRADE_PARAMS.saturation);
455
- if (shading === 'rendered') {
473
+ if (shading === 'rendered' && colorGrading) {
456
474
  sceneColor = vec4(gradeRgb(sceneColor.rgb), sceneColor.a);
457
475
  }
458
476
  // Reused scene depth lets outlined groups occlude each other; materials
@@ -509,11 +527,37 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
509
527
  sky: bgSkyUniform.current,
510
528
  skyDeep: bgSkyDeepUniform.current,
511
529
  });
512
- if (shading === 'rendered') {
530
+ if (shading === 'rendered' && colorGrading) {
513
531
  bgGradient = gradeRgb(bgGradient);
514
532
  }
515
- const sceneComposite = compositeWithOutlines.rgb;
516
- const composited = mix(bgGradient, sceneComposite, contentAlpha);
533
+ let sceneComposite = compositeWithOutlines.rgb;
534
+ // Under the ground (the eye below the ground surface) the scene goes to its dark mode: the
535
+ // sky is the dark theme's backdrop, and what stands far from the shown level dissolves into
536
+ // it (distance outside the level's box, from the scene pass's own depth; backdrop and fog
537
+ // meet in one colour per pixel). A noise mask closes over the screen as the eye crosses,
538
+ // 0 everywhere above the ground, 1 everywhere below.
539
+ let dive = null;
540
+ if (!transparentBackground) {
541
+ const grain = undergroundDissolveGrain();
542
+ dive = undergroundDissolve(screenUV, undergroundAmbianceNode(), grain);
543
+ // The backdrop follows the earth factor, which is the dark mode's own in the overview and
544
+ // alone in the walkthrough (looking out of a basement window shows earth, the rooms keep
545
+ // their light: no fog, no vignette).
546
+ const earthDive = undergroundDissolve(screenUV, undergroundEarthNode(), grain);
547
+ const dark = undergroundBackdrop(worldDir.y);
548
+ // The day's backdrop leaves ahead of the blobs: it greys and dims over the first half of
549
+ // the crossing, so the anthracite spreads over a neutral grey picture, not a blue sky.
550
+ const leaving = smoothstep(tslFloat(0), tslFloat(0.5), undergroundEarthNode());
551
+ const day = saturation(bgGradient, tslFloat(1).sub(leaving)).mul(tslFloat(1).sub(leaving.mul(0.35)));
552
+ bgGradient = mix(day, dark, earthDive);
553
+ const worldPosition = worldPositionFromDepth(scenePassDepth.sample(screenUV).r, camProjInvUniform.current, camWorldUniform.current);
554
+ sceneComposite = mix(sceneComposite, dark, undergroundFogAmount(worldPosition).mul(dive));
555
+ }
556
+ let composited = mix(bgGradient, sceneComposite, contentAlpha);
557
+ // The screen's edges close in with it.
558
+ if (dive) {
559
+ composited = mix(composited, tslColor(UNDERGROUND_VIGNETTE), undergroundVignette().mul(dive));
560
+ }
517
561
  // Editor overlays painted on top by their own alpha — they never get inked,
518
562
  // AO'd, or outlined, and always read crisp regardless of scene depth.
519
563
  const withOverlay = mix(composited, overlayColor.rgb, overlayColor.a);
@@ -527,9 +571,21 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
527
571
  .div(alpha.max(tslFloat(0.00001)));
528
572
  finalOutput = premultiplyAlpha(renderOutput(vec4(straightRgb, alpha)));
529
573
  }
574
+ else if (flatBackground && !atmosphere) {
575
+ const backdrop = flatBackdropOutput({
576
+ background: bgUniform.current,
577
+ foreground: sceneComposite,
578
+ alpha: contentAlpha,
579
+ toneMapping: renderer.toneMapping,
580
+ outputColorSpace: renderer.outputColorSpace,
581
+ });
582
+ const overlay = renderOutput(vec4(overlayColor.rgb, 1), renderer.toneMapping, renderer.outputColorSpace);
583
+ finalOutput = vec4(mix(backdrop.rgb, overlay.rgb, overlayColor.a), 1);
584
+ }
530
585
  const renderPipeline = new RenderPipeline(renderer);
531
586
  resources.pipeline = renderPipeline;
532
- renderPipeline.outputColorTransform = !transparentBackground;
587
+ renderPipeline.outputColorTransform =
588
+ !transparentBackground && !(flatBackground && !atmosphere);
533
589
  renderPipeline.outputNode = finalOutput;
534
590
  retryCountRef.current = 0;
535
591
  }
@@ -563,6 +619,9 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
563
619
  renderer,
564
620
  scene,
565
621
  shading,
622
+ ambientOcclusion,
623
+ colorGrading,
624
+ flatBackground,
566
625
  transparentBackground,
567
626
  size.height,
568
627
  size.width,
@@ -574,6 +633,9 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
574
633
  if (size.width < 1 || size.height < 1) {
575
634
  return;
576
635
  }
636
+ // A capture is working on the shared scene: the canvas keeps its last frame.
637
+ if (isLiveFrameHeld())
638
+ return;
577
639
  // `?disable=draw`: nothing downstream wants pixels — render an EMPTY scene
578
640
  // instead of the real one. This is the only render call (positive-priority
579
641
  // useFrame subscribers already disable R3F's automatic render), so the real
@@ -593,17 +655,18 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
593
655
  return;
594
656
  }
595
657
  // Animate background colour toward the current scene theme target (same lerp as AnimatedBackground)
596
- const bgTheme = getSceneTheme(useViewer.getState().sceneTheme);
658
+ const bgTheme = useViewer.getState().sceneAppearance;
659
+ const backdrop = backdropColors(bgTheme);
597
660
  bgTarget.current.set(bgTheme.background);
598
661
  bgCurrent.current.lerp(bgTarget.current, Math.min(delta, 0.1) * 4);
599
662
  bgUniform.current.value.copy(bgCurrent.current);
600
- bgSkyTarget.current.set(bgTheme.backgroundSky ?? bgTheme.background);
663
+ bgSkyTarget.current.set(backdrop.sky);
601
664
  bgSkyCurrent.current.lerp(bgSkyTarget.current, Math.min(delta, 0.1) * 4);
602
665
  bgSkyUniform.current.value.copy(bgSkyCurrent.current);
603
- bgHazeTarget.current.set(horizonHazeColor(bgTheme.backgroundSky ?? bgTheme.background, bgTheme.appearance));
666
+ bgHazeTarget.current.set(backdrop.haze);
604
667
  bgHazeCurrent.current.lerp(bgHazeTarget.current, Math.min(delta, 0.1) * 4);
605
668
  bgHazeUniform.current.value.copy(bgHazeCurrent.current);
606
- bgSkyDeepTarget.current.set(deepSkyColor(bgTheme.backgroundSky ?? bgTheme.background));
669
+ bgSkyDeepTarget.current.set(backdrop.skyDeep);
607
670
  bgSkyDeepCurrent.current.lerp(bgSkyDeepTarget.current, Math.min(delta, 0.1) * 4);
608
671
  bgSkyDeepUniform.current.value.copy(bgSkyDeepCurrent.current);
609
672
  camProjInvUniform.current.value.copy(camera.projectionMatrixInverse);
@@ -625,9 +688,14 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
625
688
  scene.backgroundNode = directSkyNode;
626
689
  try {
627
690
  const clearAlpha = transparentBackground ? 0 : 1;
691
+ // Without the pipeline there is no fog and no vignette: the clear colour is the dark mode's.
692
+ const underground = transparentBackground ? 0 : earthNow();
693
+ const clearColor = underground > 0 ? fallbackClear.current.copy(bgCurrent.current) : bgCurrent.current;
694
+ if (underground > 0)
695
+ clearColor.lerp(fallbackEarth.current, underground);
628
696
  if (renderer.setClearColor) {
629
697
  ;
630
- renderer.setClearColor(bgCurrent.current, clearAlpha);
698
+ renderer.setClearColor(clearColor, clearAlpha);
631
699
  }
632
700
  else if (renderer.setClearAlpha) {
633
701
  ;
@@ -1 +1 @@
1
- {"version":3,"file":"registered-systems.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/registered-systems.tsx"],"names":[],"mappings":"AA+BA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,uCAgChC"}
1
+ {"version":3,"file":"registered-systems.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/registered-systems.tsx"],"names":[],"mappings":"AAoDA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,uCAkChC"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
3
  import { createSceneApi, isNodeKindEnabled, nodeRegistry, useRegistryVersion, useScene, } from '@pascal-app/core';
4
- import { lazy, Suspense, useMemo } from 'react';
4
+ import { Component, lazy, Suspense, useMemo } from 'react';
5
5
  const DEFAULT_PRIORITY = 5;
6
6
  const lazyCache = new WeakMap();
7
7
  function loadSystem(def) {
@@ -14,6 +14,20 @@ function loadSystem(def) {
14
14
  lazyCache.set(def.system.module, Comp);
15
15
  return Comp;
16
16
  }
17
+ class SystemErrorBoundary extends Component {
18
+ state = { failed: false };
19
+ static getDerivedStateFromError() {
20
+ return { failed: true };
21
+ }
22
+ componentDidCatch(error) {
23
+ if (process.env.NODE_ENV !== 'production') {
24
+ console.error(`[viewer] Disabled system ${this.props.systemId}`, error);
25
+ }
26
+ }
27
+ render() {
28
+ return this.state.failed ? null : this.props.children;
29
+ }
30
+ }
17
31
  /**
18
32
  * Mounts every registered node kind's system component, ordered by
19
33
  * `system.priority` (default {@link DEFAULT_PRIORITY}).
@@ -56,6 +70,6 @@ export function RegisteredSystems() {
56
70
  const Comp = loadSystem(def);
57
71
  if (!Comp)
58
72
  return null;
59
- return (_jsx(Suspense, { fallback: null, children: _jsx(Comp, { sceneApi: sceneApi }) }, `registered-system:${kind}`));
73
+ return (_jsx(SystemErrorBoundary, { systemId: kind, children: _jsx(Suspense, { fallback: null, children: _jsx(Comp, { sceneApi: sceneApi }) }) }, `registered-system:${kind}`));
60
74
  }) }));
61
75
  }
@@ -0,0 +1,18 @@
1
+ import type { ReactNode } from 'react';
2
+ type RenderErrorHandler = ((cause: unknown) => void) | undefined;
3
+ /**
4
+ * One handler that notifies every given handler (the immersive session's and
5
+ * the host's), or undefined when there is none. A handler that throws is
6
+ * logged and does not stop the others.
7
+ */
8
+ export declare function composeRenderErrorHandlers(...handlers: RenderErrorHandler[]): RenderErrorHandler;
9
+ /**
10
+ * The viewer-scene error boundary: a node renderer or system that throws while
11
+ * rendering renders nothing in its place, and every handler hears about it.
12
+ */
13
+ export declare function SceneErrorBoundary({ handlers, children, }: {
14
+ handlers: RenderErrorHandler[];
15
+ children: ReactNode;
16
+ }): import("react").JSX.Element;
17
+ export {};
18
+ //# sourceMappingURL=render-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-error.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/render-error.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,KAAK,kBAAkB,GAAG,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;AAEhE;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,QAAQ,EAAE,kBAAkB,EAAE,GAAG,kBAAkB,CAYhG;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,kBAAkB,EAAE,CAAA;IAC9B,QAAQ,EAAE,SAAS,CAAA;CACpB,+BAUA"}
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ErrorBoundary } from '../error-boundary';
3
+ /**
4
+ * One handler that notifies every given handler (the immersive session's and
5
+ * the host's), or undefined when there is none. A handler that throws is
6
+ * logged and does not stop the others.
7
+ */
8
+ export function composeRenderErrorHandlers(...handlers) {
9
+ const present = handlers.filter((handler) => handler !== undefined);
10
+ if (present.length === 0)
11
+ return;
12
+ return (cause) => {
13
+ for (const handler of present) {
14
+ try {
15
+ handler(cause);
16
+ }
17
+ catch (error) {
18
+ console.error('[viewer] a render-error handler threw', error);
19
+ }
20
+ }
21
+ };
22
+ }
23
+ /**
24
+ * The viewer-scene error boundary: a node renderer or system that throws while
25
+ * rendering renders nothing in its place, and every handler hears about it.
26
+ */
27
+ export function SceneErrorBoundary({ handlers, children, }) {
28
+ return (_jsx(ErrorBoundary, { fallback: null, onError: composeRenderErrorHandlers(...handlers), scope: "viewer-scene", children: children }));
29
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"scene-bvh.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/scene-bvh.tsx"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,SAAS,EAA0C,MAAM,OAAO,CAAA;AAC1F,OAAO,EAAuB,KAAK,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAC7D,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAA;AAEvB,KAAK,aAAa,GAAG;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,aAAa,CAAA;IACxB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAKD,eAAO,MAAM,kBAAkB,GAAI,QAAQ,IAAI,YAA4C,CAAA;AAY3F,eAAO,MAAM,QAAQ,mIAoGpB,CAAA"}
1
+ {"version":3,"file":"scene-bvh.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/scene-bvh.tsx"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,SAAS,EAA0C,MAAM,OAAO,CAAA;AAC1F,OAAO,EAAuB,KAAK,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAC7D,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAA;AAEvB,KAAK,aAAa,GAAG;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,aAAa,CAAA;IACxB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAKD,eAAO,MAAM,kBAAkB,WAAY,IAAI,YAA4C,CAAA;AAY3F,eAAO,MAAM,QAAQ,mIAoGpB,CAAA"}
@@ -26,7 +26,7 @@ export const SceneBvh = forwardRef(({ children, enabled = true, firstHitOnly = f
26
26
  verbose,
27
27
  setBoundingBox,
28
28
  maxDepth,
29
- maxLeafSize,
29
+ targetLeafSize: maxLeafSize,
30
30
  indirect,
31
31
  };
32
32
  const group = ref.current;
@@ -1 +1 @@
1
- {"version":3,"file":"scene-environment.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/scene-environment.tsx"],"names":[],"mappings":"AAoEA,wBAAgB,gBAAgB,SA8B/B"}
1
+ {"version":3,"file":"scene-environment.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/scene-environment.tsx"],"names":[],"mappings":"AAoEA,wBAAgB,gBAAgB,SA8C/B"}
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
  import { useThree } from '@react-three/fiber';
3
- import { useEffect, useMemo, useRef } from 'react';
3
+ import { useEffect, useRef } from 'react';
4
+ import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';
4
5
  import * as THREE from 'three/webgpu';
5
- import { getSceneTheme } from '../../lib/scene-themes';
6
6
  import useViewer from '../../store/use-viewer';
7
7
  import { useSceneAtmosphere } from './scene-atmosphere';
8
8
  /**
@@ -63,31 +63,51 @@ function buildGradientSky() {
63
63
  }
64
64
  export function SceneEnvironment() {
65
65
  const scene = useThree((state) => state.scene);
66
- const texture = useMemo(buildGradientSky, []);
67
- const appearance = useViewer((state) => getSceneTheme(state.sceneTheme).appearance);
66
+ const renderer = useThree((state) => state.gl);
67
+ const appearance = useViewer((state) => state.sceneAppearance.appearance);
68
+ const environment = useViewer((state) => state.sceneAppearance.environment);
69
+ const source = environment?.source ?? 'gradient';
68
70
  const atmosphere = useSceneAtmosphere();
69
71
  const atmosphereRef = useRef(atmosphere);
70
72
  atmosphereRef.current = atmosphere;
71
73
  useEffect(() => {
72
74
  const prevEnvironment = scene.environment;
73
- const prevIntensity = scene.environmentIntensity;
75
+ let target;
76
+ let texture = null;
77
+ if (source === 'room') {
78
+ const room = new RoomEnvironment();
79
+ const generator = new THREE.PMREMGenerator(renderer);
80
+ target = generator.fromScene(room, 0.04);
81
+ texture = target.texture;
82
+ room.dispose();
83
+ generator.dispose();
84
+ }
85
+ else if (source === 'gradient')
86
+ texture = buildGradientSky();
74
87
  scene.environment = texture;
75
88
  return () => {
76
89
  if (scene.environment === texture) {
77
90
  scene.environment = prevEnvironment;
78
- if (!atmosphereRef.current)
79
- scene.environmentIntensity = prevIntensity;
80
91
  }
81
- texture.dispose();
92
+ if (target)
93
+ target.dispose();
94
+ else
95
+ texture?.dispose();
82
96
  };
83
- }, [scene, texture]);
97
+ }, [renderer, scene, source]);
84
98
  useEffect(() => {
85
99
  // An atmosphere owns environmentIntensity while its environmentNode is
86
100
  // active. The gradient remains installed as the fallback texture and takes
87
101
  // over immediately when the atmosphere restores scene ownership.
88
102
  if (atmosphere)
89
103
  return;
90
- scene.environmentIntensity = appearance === 'dark' ? ENV_INTENSITY_DARK : ENV_INTENSITY;
91
- }, [appearance, atmosphere, scene]);
104
+ const previous = scene.environmentIntensity;
105
+ scene.environmentIntensity =
106
+ environment?.intensity ?? (appearance === 'dark' ? ENV_INTENSITY_DARK : ENV_INTENSITY);
107
+ return () => {
108
+ if (!atmosphereRef.current)
109
+ scene.environmentIntensity = previous;
110
+ };
111
+ }, [appearance, atmosphere, scene, environment?.intensity]);
92
112
  return null;
93
113
  }
@@ -1,5 +1,11 @@
1
+ import type { Scene } from 'three';
1
2
  /** Whether modeled exterior ground replaces this scene's fallback horizon disc. */
2
3
  export declare function useSceneGroundReplacement(): boolean;
4
+ /**
5
+ * The same claim from outside React (a map layer that hangs its own meshes on
6
+ * the scene): returns the release. The last release restores the fallback.
7
+ */
8
+ export declare function claimSceneGround(scene: Scene): () => void;
3
9
  /** Mount alongside replacement ground. The last release restores the fallback. */
4
10
  export declare function SceneGroundReplacement(): null;
5
11
  //# sourceMappingURL=scene-ground-replacement.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scene-ground-replacement.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/scene-ground-replacement.tsx"],"names":[],"mappings":"AAoBA,mFAAmF;AACnF,wBAAgB,yBAAyB,IAAI,OAAO,CAInD;AAED,kFAAkF;AAClF,wBAAgB,sBAAsB,SAarC"}
1
+ {"version":3,"file":"scene-ground-replacement.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/scene-ground-replacement.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAgBlC,mFAAmF;AACnF,wBAAgB,yBAAyB,IAAI,OAAO,CAInD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,IAAI,CASzD;AAED,kFAAkF;AAClF,wBAAgB,sBAAsB,SAarC"}
@@ -18,6 +18,21 @@ export function useSceneGroundReplacement() {
18
18
  const store = useMemo(() => groundStore(scene), [scene]);
19
19
  return useStore(store, (state) => state.owners > 0);
20
20
  }
21
+ /**
22
+ * The same claim from outside React (a map layer that hangs its own meshes on
23
+ * the scene): returns the release. The last release restores the fallback.
24
+ */
25
+ export function claimSceneGround(scene) {
26
+ const store = groundStore(scene);
27
+ store.setState((state) => ({ owners: state.owners + 1 }));
28
+ let released = false;
29
+ return () => {
30
+ if (released)
31
+ return;
32
+ released = true;
33
+ store.setState((state) => ({ owners: Math.max(0, state.owners - 1) }));
34
+ };
35
+ }
21
36
  /** Mount alongside replacement ground. The last release restores the fallback. */
22
37
  export function SceneGroundReplacement() {
23
38
  const scene = useThree((state) => state.scene);
@@ -1 +1 @@
1
- {"version":3,"file":"selection-manager.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/selection-manager.tsx"],"names":[],"mappings":"AAqSA,eAAO,MAAM,gBAAgB,mCA0G5B,CAAA"}
1
+ {"version":3,"file":"selection-manager.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/selection-manager.tsx"],"names":[],"mappings":"AAqSA,eAAO,MAAM,gBAAgB,mCA+G5B,CAAA"}