@pascal-app/viewer 1.0.6 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/README.md +54 -21
  2. package/dist/components/viewer/daylight-atmosphere.d.ts +9 -0
  3. package/dist/components/viewer/daylight-atmosphere.d.ts.map +1 -0
  4. package/dist/components/viewer/daylight-atmosphere.js +315 -0
  5. package/dist/components/viewer/drone-controller.d.ts +15 -0
  6. package/dist/components/viewer/drone-controller.d.ts.map +1 -0
  7. package/dist/components/viewer/drone-controller.js +194 -0
  8. package/dist/components/viewer/glb-interactive.d.ts +4 -18
  9. package/dist/components/viewer/glb-interactive.d.ts.map +1 -1
  10. package/dist/components/viewer/glb-interactive.js +32 -268
  11. package/dist/components/viewer/glb-replace-instances.d.ts +6 -3
  12. package/dist/components/viewer/glb-replace-instances.d.ts.map +1 -1
  13. package/dist/components/viewer/glb-replace-instances.js +5 -4
  14. package/dist/components/viewer/glb-scene-motion.d.ts +8 -0
  15. package/dist/components/viewer/glb-scene-motion.d.ts.map +1 -0
  16. package/dist/components/viewer/glb-scene-motion.js +57 -0
  17. package/dist/components/viewer/glb-scene.d.ts +5 -1
  18. package/dist/components/viewer/glb-scene.d.ts.map +1 -1
  19. package/dist/components/viewer/glb-scene.js +290 -49
  20. package/dist/components/viewer/glb-selection-callout.d.ts +17 -0
  21. package/dist/components/viewer/glb-selection-callout.d.ts.map +1 -0
  22. package/dist/components/viewer/glb-selection-callout.js +54 -0
  23. package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -1
  24. package/dist/components/viewer/glb-walkthrough-controller.js +6 -3
  25. package/dist/components/viewer/index.d.ts +5 -0
  26. package/dist/components/viewer/index.d.ts.map +1 -1
  27. package/dist/components/viewer/index.js +38 -10
  28. package/dist/components/viewer/lights.d.ts.map +1 -1
  29. package/dist/components/viewer/lights.js +192 -5
  30. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  31. package/dist/components/viewer/post-processing.js +150 -94
  32. package/dist/components/viewer/registered-systems.d.ts.map +1 -1
  33. package/dist/components/viewer/registered-systems.js +2 -2
  34. package/dist/components/viewer/scene-environment.js +4 -5
  35. package/dist/components/viewer/selection-callout.d.ts +51 -0
  36. package/dist/components/viewer/selection-callout.d.ts.map +1 -0
  37. package/dist/components/viewer/selection-callout.js +197 -0
  38. package/dist/components/viewer/unsupported-gpu-fallback.d.ts.map +1 -1
  39. package/dist/components/viewer/unsupported-gpu-fallback.js +21 -1
  40. package/dist/components/viewer/use-daylight-rooms.d.ts +13 -0
  41. package/dist/components/viewer/use-daylight-rooms.d.ts.map +1 -0
  42. package/dist/components/viewer/use-daylight-rooms.js +278 -0
  43. package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
  44. package/dist/components/viewer/viewer-camera.js +12 -1
  45. package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
  46. package/dist/hooks/use-gltf-ktx2.js +2 -1
  47. package/dist/index.d.ts +26 -8
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +28 -8
  50. package/dist/lib/asset-url.d.ts +0 -1
  51. package/dist/lib/asset-url.d.ts.map +1 -1
  52. package/dist/lib/asset-url.js +3 -3
  53. package/dist/lib/daylight/ground.d.ts +21 -0
  54. package/dist/lib/daylight/ground.d.ts.map +1 -0
  55. package/dist/lib/daylight/ground.js +53 -0
  56. package/dist/lib/daylight/location.d.ts +32 -0
  57. package/dist/lib/daylight/location.d.ts.map +1 -0
  58. package/dist/lib/daylight/location.js +74 -0
  59. package/dist/lib/daylight/look.d.ts +33 -0
  60. package/dist/lib/daylight/look.d.ts.map +1 -0
  61. package/dist/lib/daylight/look.js +13 -0
  62. package/dist/lib/daylight/material-hooks.d.ts +2 -0
  63. package/dist/lib/daylight/material-hooks.d.ts.map +1 -0
  64. package/dist/lib/daylight/material-hooks.js +150 -0
  65. package/dist/lib/daylight/room-context.d.ts +12 -0
  66. package/dist/lib/daylight/room-context.d.ts.map +1 -0
  67. package/dist/lib/daylight/room-context.js +54 -0
  68. package/dist/lib/daylight/room-map.d.ts +124 -0
  69. package/dist/lib/daylight/room-map.d.ts.map +1 -0
  70. package/dist/lib/daylight/room-map.js +630 -0
  71. package/dist/lib/daylight/room-scene.d.ts +56 -0
  72. package/dist/lib/daylight/room-scene.d.ts.map +1 -0
  73. package/dist/lib/daylight/room-scene.js +391 -0
  74. package/dist/lib/daylight/rooms.d.ts +292 -0
  75. package/dist/lib/daylight/rooms.d.ts.map +1 -0
  76. package/dist/lib/daylight/rooms.js +1268 -0
  77. package/dist/lib/daylight/runtime.d.ts +33 -0
  78. package/dist/lib/daylight/runtime.d.ts.map +1 -0
  79. package/dist/lib/daylight/runtime.js +42 -0
  80. package/dist/lib/daylight/sky.d.ts +26 -0
  81. package/dist/lib/daylight/sky.d.ts.map +1 -0
  82. package/dist/lib/daylight/sky.js +217 -0
  83. package/dist/lib/daylight/solar.d.ts +46 -0
  84. package/dist/lib/daylight/solar.d.ts.map +1 -0
  85. package/dist/lib/daylight/solar.js +156 -0
  86. package/dist/lib/device-tier.d.ts +29 -0
  87. package/dist/lib/device-tier.d.ts.map +1 -0
  88. package/dist/lib/device-tier.js +71 -0
  89. package/dist/lib/dispose-object3d.d.ts.map +1 -1
  90. package/dist/lib/dispose-object3d.js +4 -2
  91. package/dist/lib/drone-flight.d.ts +44 -0
  92. package/dist/lib/drone-flight.d.ts.map +1 -0
  93. package/dist/lib/drone-flight.js +121 -0
  94. package/dist/lib/editor-highlight.d.ts +16 -0
  95. package/dist/lib/editor-highlight.d.ts.map +1 -0
  96. package/dist/lib/editor-highlight.js +33 -0
  97. package/dist/lib/foundation-materials.d.ts.map +1 -1
  98. package/dist/lib/foundation-materials.js +2 -4
  99. package/dist/lib/glb-merge.d.ts +23 -0
  100. package/dist/lib/glb-merge.d.ts.map +1 -0
  101. package/dist/lib/glb-merge.js +184 -0
  102. package/dist/lib/hardware-geometry.d.ts +21 -0
  103. package/dist/lib/hardware-geometry.d.ts.map +1 -0
  104. package/dist/lib/hardware-geometry.js +283 -0
  105. package/dist/lib/ktx2-loader.d.ts.map +1 -1
  106. package/dist/lib/ktx2-loader.js +2 -1
  107. package/dist/lib/layer-pass.d.ts +2 -0
  108. package/dist/lib/layer-pass.d.ts.map +1 -1
  109. package/dist/lib/layer-pass.js +20 -0
  110. package/dist/lib/materials.d.ts.map +1 -1
  111. package/dist/lib/materials.js +50 -23
  112. package/dist/lib/measurement-label.d.ts +4 -0
  113. package/dist/lib/measurement-label.d.ts.map +1 -0
  114. package/dist/lib/measurement-label.js +54 -0
  115. package/dist/lib/measurement-presentation.d.ts +5 -0
  116. package/dist/lib/measurement-presentation.d.ts.map +1 -0
  117. package/dist/lib/measurement-presentation.js +8 -0
  118. package/dist/lib/merged-outline-node.d.ts.map +1 -1
  119. package/dist/lib/merged-outline-node.js +7 -1
  120. package/dist/lib/occlusion-culler.d.ts +34 -0
  121. package/dist/lib/occlusion-culler.d.ts.map +1 -0
  122. package/dist/lib/occlusion-culler.js +698 -0
  123. package/dist/lib/pointer-events.d.ts.map +1 -1
  124. package/dist/lib/pointer-events.js +3 -3
  125. package/dist/lib/post-processing-resources.d.ts +4 -0
  126. package/dist/lib/post-processing-resources.d.ts.map +1 -1
  127. package/dist/lib/post-processing-resources.js +5 -0
  128. package/dist/lib/readback-rows.d.ts +14 -0
  129. package/dist/lib/readback-rows.d.ts.map +1 -0
  130. package/dist/lib/readback-rows.js +31 -0
  131. package/dist/lib/reveal-pose.d.ts.map +1 -1
  132. package/dist/lib/reveal-pose.js +3 -0
  133. package/dist/lib/scene-matrices.d.ts +12 -0
  134. package/dist/lib/scene-matrices.d.ts.map +1 -0
  135. package/dist/lib/scene-matrices.js +287 -0
  136. package/dist/lib/scene-pass-mrt.d.ts +5 -2
  137. package/dist/lib/scene-pass-mrt.d.ts.map +1 -1
  138. package/dist/lib/scene-pass-mrt.js +7 -2
  139. package/dist/lib/scene-themes.d.ts +0 -2
  140. package/dist/lib/scene-themes.d.ts.map +1 -1
  141. package/dist/lib/scene-themes.js +0 -2
  142. package/dist/lib/scene-visibility.d.ts +2 -0
  143. package/dist/lib/scene-visibility.d.ts.map +1 -1
  144. package/dist/lib/scene-visibility.js +12 -3
  145. package/dist/lib/site-surfaces.d.ts +1 -8
  146. package/dist/lib/site-surfaces.d.ts.map +1 -1
  147. package/dist/lib/site-surfaces.js +0 -19
  148. package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
  149. package/dist/lib/snapshot-pipeline.js +24 -40
  150. package/dist/lib/texture-reference.d.ts.map +1 -1
  151. package/dist/lib/texture-reference.js +13 -10
  152. package/dist/lib/underground-ambiance.d.ts +0 -2
  153. package/dist/lib/underground-ambiance.d.ts.map +1 -1
  154. package/dist/lib/underground-ambiance.js +0 -2
  155. package/dist/lib/viewer-config.d.ts +21 -0
  156. package/dist/lib/viewer-config.d.ts.map +1 -0
  157. package/dist/lib/viewer-config.js +21 -0
  158. package/dist/lib/viewer-preference-storage.d.ts +7 -0
  159. package/dist/lib/viewer-preference-storage.d.ts.map +1 -0
  160. package/dist/lib/viewer-preference-storage.js +23 -0
  161. package/dist/store/use-item-light-pool.d.ts +3 -6
  162. package/dist/store/use-item-light-pool.d.ts.map +1 -1
  163. package/dist/store/use-item-light-pool.js +12 -0
  164. package/dist/store/use-viewer.d.ts +62 -59
  165. package/dist/store/use-viewer.d.ts.map +1 -1
  166. package/dist/store/use-viewer.js +106 -19
  167. package/dist/systems/ceiling/ceiling-system.d.ts +5 -0
  168. package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
  169. package/dist/systems/ceiling/ceiling-system.js +11 -1
  170. package/dist/systems/door/door-system.d.ts.map +1 -1
  171. package/dist/systems/door/door-system.js +501 -145
  172. package/dist/systems/door/leaf-profile.d.ts +11 -0
  173. package/dist/systems/door/leaf-profile.d.ts.map +1 -0
  174. package/dist/systems/door/leaf-profile.js +140 -0
  175. package/dist/systems/elevator/elevator-interaction-system.d.ts +16 -2
  176. package/dist/systems/elevator/elevator-interaction-system.d.ts.map +1 -1
  177. package/dist/systems/elevator/elevator-interaction-system.js +41 -8
  178. package/dist/systems/geometry/geometry-status.d.ts +8 -0
  179. package/dist/systems/geometry/geometry-status.d.ts.map +1 -0
  180. package/dist/systems/geometry/geometry-status.js +24 -0
  181. package/dist/systems/interactive/callout-actions.d.ts +72 -0
  182. package/dist/systems/interactive/callout-actions.d.ts.map +1 -0
  183. package/dist/systems/interactive/callout-actions.js +212 -0
  184. package/dist/systems/interactive/interactive-system.d.ts +5 -1
  185. package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
  186. package/dist/systems/interactive/interactive-system.js +44 -121
  187. package/dist/systems/interactive/opening-settled.d.ts +16 -0
  188. package/dist/systems/interactive/opening-settled.d.ts.map +1 -0
  189. package/dist/systems/interactive/opening-settled.js +53 -0
  190. package/dist/systems/item-light/item-light-system.d.ts.map +1 -1
  191. package/dist/systems/item-light/item-light-system.js +22 -214
  192. package/dist/systems/item-light/pooled-lights.d.ts +70 -0
  193. package/dist/systems/item-light/pooled-lights.d.ts.map +1 -0
  194. package/dist/systems/item-light/pooled-lights.js +449 -0
  195. package/dist/systems/level/level-system.d.ts.map +1 -1
  196. package/dist/systems/level/level-system.js +19 -1
  197. package/dist/systems/roof/roof-material-slots.d.ts +14 -0
  198. package/dist/systems/roof/roof-material-slots.d.ts.map +1 -0
  199. package/dist/systems/roof/roof-material-slots.js +13 -0
  200. package/dist/systems/roof/roof-materials.d.ts +25 -2
  201. package/dist/systems/roof/roof-materials.d.ts.map +1 -1
  202. package/dist/systems/roof/roof-materials.js +85 -26
  203. package/dist/systems/roof/roof-system.d.ts +34 -1
  204. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  205. package/dist/systems/roof/roof-system.js +582 -168
  206. package/dist/systems/wall/opening-casing-geometry.d.ts +14 -0
  207. package/dist/systems/wall/opening-casing-geometry.d.ts.map +1 -0
  208. package/dist/systems/wall/opening-casing-geometry.js +102 -0
  209. package/dist/systems/wall/opening-cutout-geometry.d.ts +9 -0
  210. package/dist/systems/wall/opening-cutout-geometry.d.ts.map +1 -1
  211. package/dist/systems/wall/opening-cutout-geometry.js +7 -3
  212. package/dist/systems/wall/wall-materials.d.ts.map +1 -1
  213. package/dist/systems/wall/wall-materials.js +28 -35
  214. package/dist/systems/wall/wall-system.d.ts +11 -0
  215. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  216. package/dist/systems/wall/wall-system.js +86 -25
  217. package/dist/systems/wall/wall-t-junctions.d.ts +15 -0
  218. package/dist/systems/wall/wall-t-junctions.d.ts.map +1 -0
  219. package/dist/systems/wall/wall-t-junctions.js +149 -0
  220. package/dist/systems/window/window-animation-system.d.ts +3 -12
  221. package/dist/systems/window/window-animation-system.d.ts.map +1 -1
  222. package/dist/systems/window/window-animation-system.js +37 -122
  223. package/dist/systems/window/window-pose.d.ts +31 -0
  224. package/dist/systems/window/window-pose.d.ts.map +1 -0
  225. package/dist/systems/window/window-pose.js +152 -0
  226. package/dist/systems/window/window-roller-shutter.d.ts +8 -0
  227. package/dist/systems/window/window-roller-shutter.d.ts.map +1 -0
  228. package/dist/systems/window/window-roller-shutter.js +64 -0
  229. package/dist/systems/window/window-system.d.ts +2 -11
  230. package/dist/systems/window/window-system.d.ts.map +1 -1
  231. package/dist/systems/window/window-system.js +470 -303
  232. package/package.json +6 -6
  233. package/dist/systems/interactive/control-widget.d.ts +0 -10
  234. package/dist/systems/interactive/control-widget.d.ts.map +0 -1
  235. package/dist/systems/interactive/control-widget.js +0 -35
  236. package/dist/systems/interactive/procedural-controls.d.ts +0 -13
  237. package/dist/systems/interactive/procedural-controls.d.ts.map +0 -1
  238. package/dist/systems/interactive/procedural-controls.js +0 -17
@@ -1,9 +1,10 @@
1
1
  'use client';
2
2
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { nodeRegistry, RoofElevationSystem, StairOpeningSystem, sceneRegistry, useInteractive, useScene, } from '@pascal-app/core';
3
+ import { isDevelopmentBuild, nodeRegistry, RoofElevationSystem, StairOpeningSystem, sceneRegistry, useInteractive, useScene, } from '@pascal-app/core';
4
4
  import { Canvas, extend, useFrame, useThree } from '@react-three/fiber';
5
5
  import { forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState, } from 'react';
6
6
  import * as THREE from 'three/webgpu';
7
+ import { classifyDevice, isSoftwareRenderer, readDeviceSignals } from '../../lib/device-tier';
7
8
  import { hasDrawableGeometry } from '../../lib/drawable-geometry';
8
9
  import { PERF_OVERLAY_ENABLED } from '../../lib/gpu-perf';
9
10
  import { applyIsolation, clearIsolation } from '../../lib/isolation';
@@ -12,6 +13,7 @@ import { choosePointerEvents } from '../../lib/pointer-events';
12
13
  import { initializeGpuRenderer } from '../../lib/renderer-capability';
13
14
  import { getSceneTheme } from '../../lib/scene-themes';
14
15
  import { installTextureNodeNullGuard } from '../../lib/texture-node-guard';
16
+ import { viewerPreferenceStorage } from '../../lib/viewer-preference-storage';
15
17
  import useViewer, {} from '../../store/use-viewer';
16
18
  import { FloorElevationSystem } from '../../systems/floor-elevation/floor-elevation-system';
17
19
  import { GeometrySystem } from '../../systems/geometry/geometry-system';
@@ -21,6 +23,7 @@ import { subscribeWallBuildInteractions } from '../../systems/wall/wall-build-li
21
23
  import { ImmersiveXRPresentationProvider } from '../../xr/presentation-context';
22
24
  import { SceneRenderer } from '../renderers/scene-renderer';
23
25
  import { BATCH_SPIKE_ENABLED, BatchedMeshSpike } from './batched-mesh-spike';
26
+ import { DaylightAtmosphere } from './daylight-atmosphere';
24
27
  import FrameLimiter from './frame-limiter';
25
28
  import { Lights } from './lights';
26
29
  import { PerfMonitor } from './perf-monitor';
@@ -66,7 +69,7 @@ const DIRTY_BUILD_KINDS = new Set([
66
69
  'wall',
67
70
  'window',
68
71
  ]);
69
- const warnedEmptyDraw = process.env.NODE_ENV === 'production' ? null : new WeakSet();
72
+ const warnedEmptyDraw = isDevelopmentBuild() ? new WeakSet() : null;
70
73
  /**
71
74
  * Renderer-level safety net against the empty-vertex-buffer crash.
72
75
  *
@@ -283,7 +286,13 @@ function SceneReadyTracker({ onSceneReadyChange, sceneReadyKey, sceneReadyMaxWai
283
286
  }, 10);
284
287
  return null;
285
288
  }
286
- const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVER_STYLES, selectionManager = 'default', perf = false, useBvh = true, renderContext = 'editor', transparent, defaultRender, presentation: suppliedPresentation, isolate, sceneReadyKey, onSceneReadyChange, onRenderError, onBreadcrumb, sceneReadyMaxWaitMs, maxFps = 50, disablePostFx = false, renderPaused = false, immersive, }, ref) {
289
+ const MAX_DPR = { high: 1.5, medium: 1.25, low: 1 };
290
+ /**
291
+ * A software renderer can't reach the usual cadence, and chasing it starves the app of the CPU it
292
+ * rasterizes on: frames are capped lower there.
293
+ */
294
+ const SOFTWARE_MAX_FPS = 20;
295
+ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVER_STYLES, selectionManager = 'default', perf = false, useBvh = true, renderContext = 'editor', transparent, defaultRender, presentation: suppliedPresentation, daylight = true, isolate, sceneReadyKey, onSceneReadyChange, onRenderError, onBreadcrumb, sceneReadyMaxWaitMs, maxFps = 50, disablePostFx = false, renderPaused = false, immersive, }, ref) {
287
296
  useEffect(() => {
288
297
  if (nodeRegistry.size === 0) {
289
298
  console.warn('[viewer] Node registry is empty. Install @pascal-app/nodes and call await loadPlugin(builtinPlugin) before mounting <Viewer>.');
@@ -313,12 +322,18 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
313
322
  const isDark = useViewer((state) => state.sceneAppearance.appearance === 'dark');
314
323
  const sceneTheme = useViewer((state) => state.sceneTheme);
315
324
  const previousLampTheme = useRef(sceneTheme);
325
+ // Scene themes drive the lamps only in monochrome; the colored appearance's daylight follows
326
+ // its time of day instead.
327
+ const colored = useViewer((state) => state.textures);
328
+ const themeDrivesLamps = !(daylight && colored);
316
329
  useEffect(() => {
330
+ if (!themeDrivesLamps)
331
+ return;
317
332
  useInteractive
318
333
  .getState()
319
334
  .setLampDefault(getSceneTheme(sceneTheme).appearance === 'dark', previousLampTheme.current !== sceneTheme);
320
335
  previousLampTheme.current = sceneTheme;
321
- }, [sceneTheme]);
336
+ }, [sceneTheme, themeDrivesLamps]);
322
337
  const transparentBackground = useViewer((state) => state.transparentBackground);
323
338
  // The shadows toggle drives `renderer.shadowMap.enabled` (via the Canvas
324
339
  // `shadows` prop) rather than the lights' `castShadow`: toggling castShadow
@@ -361,7 +376,7 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
361
376
  if (!hasDefaultRender || typeof window === 'undefined')
362
377
  return;
363
378
  let persistedState = {};
364
- const rawPreferences = window.localStorage.getItem('viewer-preferences');
379
+ const rawPreferences = viewerPreferenceStorage.getItem('viewer-preferences');
365
380
  if (rawPreferences) {
366
381
  try {
367
382
  const parsed = JSON.parse(rawPreferences);
@@ -384,7 +399,10 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
384
399
  // Coarse-pointer devices (phones/tablets) get a tighter DPR ceiling to keep
385
400
  // fragment-shader cost down — saves another ~30% over 1.5x on high-DPI mobile.
386
401
  // Desktops (fine pointer) keep the original 1.5 cap.
387
- const maxDpr = typeof window !== 'undefined' && window.matchMedia('(pointer: coarse)').matches ? 1.25 : 1.5;
402
+ // Pixel-ratio cap per quality tier (touch devices default to Medium).
403
+ const renderQuality = useViewer((state) => state.renderQuality);
404
+ const softwareRenderer = useViewer((state) => state.softwareRenderer);
405
+ const maxDpr = MAX_DPR[renderQuality];
388
406
  const showGpuFallback = rendererInitFailed;
389
407
  // When we can't mount the GPU canvas, the SceneReadyTracker never mounts and
390
408
  // the host editor would otherwise wait on its scene-readiness timeout. Signal
@@ -404,7 +422,10 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
404
422
  if (showGpuFallback) {
405
423
  return _jsx(UnsupportedGpuViewerFallback, {});
406
424
  }
407
- return (_jsxs(_Fragment, { children: [(perf || PERF_OVERLAY_ENABLED) && _jsx(PerfPanel, {}), _jsx(Canvas, { ref: subscribeWallBuildInteractions, camera: { position: [50, 50, 50], fov: 50 }, className: `transition-colors duration-700 ${transparentBackground ? 'bg-transparent' : isDark ? 'bg-[#1f2433]' : 'bg-[#fafafa]'}`, dpr: [1, maxDpr], events: pointerEvents, frameloop: "never", gl: ((props) => {
425
+ return (_jsxs(_Fragment, { children: [(perf || PERF_OVERLAY_ENABLED) && _jsx(PerfPanel, {}), _jsx(Canvas, { ref: subscribeWallBuildInteractions, camera: { position: [50, 50, 50], fov: 50 }, style: {
426
+ backgroundColor: transparentBackground ? 'transparent' : isDark ? '#1f2433' : '#fafafa',
427
+ transition: 'background-color 700ms cubic-bezier(0.4, 0, 0.2, 1), color 700ms cubic-bezier(0.4, 0, 0.2, 1)',
428
+ }, dpr: [1, maxDpr], events: pointerEvents, frameloop: "never", gl: ((props) => {
408
429
  const canvas = props.canvas;
409
430
  const cached = canvas ? WEBGPU_RENDERER_CACHE.get(canvas) : undefined;
410
431
  if (cached)
@@ -434,6 +455,11 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
434
455
  });
435
456
  if (result.status === 'ready') {
436
457
  installEmptyDrawGuard(result.renderer);
458
+ // Before the first frame, so the post-processing builds once at the device's tier.
459
+ const signals = readDeviceSignals(result.backend, result.renderer.backend?.device);
460
+ useViewer
461
+ .getState()
462
+ .setDetectedRenderQuality(classifyDevice(signals), isSoftwareRenderer(signals));
437
463
  return result.renderer;
438
464
  }
439
465
  if (canvas)
@@ -456,11 +482,13 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
456
482
  }, shadows: {
457
483
  type: THREE.PCFShadowMap,
458
484
  enabled: shadowsEnabled,
459
- }, children: _jsx(ImmersiveXRPresentationProvider, { enabled: immersiveActive, children: ImmersiveSession ? (_jsx(ImmersiveSession, { children: _jsx(ViewerScene, { disablePostFx: true, hoverStyles: hoverStyles, immersiveXR: true, renderErrorHandlers: [immersive.onError, onRenderError], onSceneReadyChange: onSceneReadyChange, perf: perf, sceneReadyKey: sceneReadyKey, sceneReadyMaxWaitMs: sceneReadyMaxWaitMs, selectionManager: selectionManager, useBvh: useBvh, SceneWrapper: immersive.Scene, children: children }) })) : (_jsxs(_Fragment, { children: [_jsx(FrameLimiter, { fps: maxFps, onFrameError: composeRenderErrorHandlers(onRenderError), paused: renderPaused }), _jsx(ViewerScene, { disablePostFx: disablePostFx, hoverStyles: hoverStyles, renderErrorHandlers: [onRenderError], onSceneReadyChange: onSceneReadyChange, perf: perf, sceneReadyKey: sceneReadyKey, sceneReadyMaxWaitMs: sceneReadyMaxWaitMs, selectionManager: selectionManager, useBvh: useBvh, children: children })] })) }) }, immersiveActive ? 'webgl-xr' : 'webgpu')] }));
485
+ }, children: _jsx(ImmersiveXRPresentationProvider, { enabled: immersiveActive, children: ImmersiveSession ? (_jsx(ImmersiveSession, { children: _jsx(ViewerScene, { daylight: daylight, disablePostFx: true, hoverStyles: hoverStyles, immersiveXR: true, renderErrorHandlers: [immersive.onError, onRenderError], onSceneReadyChange: onSceneReadyChange, perf: perf, sceneReadyKey: sceneReadyKey, sceneReadyMaxWaitMs: sceneReadyMaxWaitMs, selectionManager: selectionManager, useBvh: useBvh, SceneWrapper: immersive.Scene, children: children }) })) : (_jsxs(_Fragment, { children: [_jsx(FrameLimiter, { fps: softwareRenderer ? Math.min(maxFps, SOFTWARE_MAX_FPS) : maxFps, onFrameError: composeRenderErrorHandlers(onRenderError), paused: renderPaused }), _jsx(ViewerScene, { daylight: daylight, disablePostFx: disablePostFx, hoverStyles: hoverStyles, renderErrorHandlers: [onRenderError], onSceneReadyChange: onSceneReadyChange, perf: perf, sceneReadyKey: sceneReadyKey, sceneReadyMaxWaitMs: sceneReadyMaxWaitMs, selectionManager: selectionManager, useBvh: useBvh, children: children })] })) }) }, immersiveActive ? 'webgl-xr' : 'webgpu')] }));
460
486
  });
461
- function ViewerScene({ children, disablePostFx, hoverStyles, immersiveXR = false, renderErrorHandlers, onSceneReadyChange, perf, sceneReadyKey, sceneReadyMaxWaitMs, selectionManager, useBvh, SceneWrapper, }) {
487
+ function ViewerScene({ children, daylight, disablePostFx, hoverStyles, immersiveXR = false, renderErrorHandlers, onSceneReadyChange, perf, sceneReadyKey, sceneReadyMaxWaitMs, selectionManager, useBvh, SceneWrapper, }) {
488
+ // Colored appearance = the built-in daylight look; monochrome keeps the scene themes.
489
+ const colored = useViewer((state) => state.textures);
462
490
  const renderedScene = useBvh ? (_jsx(SceneBvh, { children: _jsx(SceneRenderer, {}) })) : (_jsx(SceneRenderer, {}));
463
491
  const spatialScene = (_jsxs(_Fragment, { children: [renderedScene, _jsx(FloorElevationSystem, {}), _jsx(GeometrySystem, {}), _jsx(StairOpeningSystem, {}), _jsx(RoofElevationSystem, {}), _jsx(RegisteredSystems, {}), BATCH_SPIKE_ENABLED && _jsx(BatchedMeshSpike, {}), children] }));
464
- return (_jsxs(_Fragment, { children: [_jsx(ViewerCamera, { immersiveXR: immersiveXR }), immersiveXR && _jsx(ImmersiveXRBackground, {}), _jsx(PointerRaycastLayers, {}), _jsx(GPUDeviceWatcher, { intentionalWebGL: immersiveXR }), _jsx(ToneMappingExposure, {}), _jsx(SceneReadyTracker, { onSceneReadyChange: onSceneReadyChange, sceneReadyKey: sceneReadyKey, sceneReadyMaxWaitMs: sceneReadyMaxWaitMs }), _jsxs(SceneErrorBoundary, { handlers: renderErrorHandlers, children: [_jsx(Lights, {}), SceneWrapper ? _jsx(SceneWrapper, { children: spatialScene }) : spatialScene, !immersiveXR && _jsx(PostProcessing, { disablePostFx: disablePostFx, hoverStyles: hoverStyles }), selectionManager === 'default' && _jsx(SelectionManager, {}), (perf || PERF_OVERLAY_ENABLED) && _jsx(PerfMonitor, {}), (perf || PERF_OVERLAY_ENABLED) && _jsx(PerfActionSettleSystem, {})] })] }));
492
+ return (_jsxs(_Fragment, { children: [_jsx(ViewerCamera, { immersiveXR: immersiveXR }), immersiveXR && _jsx(ImmersiveXRBackground, {}), _jsx(PointerRaycastLayers, {}), _jsx(GPUDeviceWatcher, { intentionalWebGL: immersiveXR }), _jsx(ToneMappingExposure, {}), _jsx(SceneReadyTracker, { onSceneReadyChange: onSceneReadyChange, sceneReadyKey: sceneReadyKey, sceneReadyMaxWaitMs: sceneReadyMaxWaitMs }), _jsxs(SceneErrorBoundary, { handlers: renderErrorHandlers, children: [daylight && colored && _jsx(DaylightAtmosphere, {}), _jsx(Lights, {}), SceneWrapper ? _jsx(SceneWrapper, { children: spatialScene }) : spatialScene, !immersiveXR && _jsx(PostProcessing, { disablePostFx: disablePostFx, hoverStyles: hoverStyles }), selectionManager === 'default' && _jsx(SelectionManager, {}), (perf || PERF_OVERLAY_ENABLED) && _jsx(PerfMonitor, {}), (perf || PERF_OVERLAY_ENABLED) && _jsx(PerfActionSettleSystem, {})] })] }));
465
493
  }
466
494
  export default Viewer;
@@ -1 +1 @@
1
- {"version":3,"file":"lights.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/lights.tsx"],"names":[],"mappings":"AAmGA,wBAAgB,MAAM,gCAiVrB"}
1
+ {"version":3,"file":"lights.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/lights.tsx"],"names":[],"mappings":"AAoGA,wBAAgB,MAAM,gCA+XrB"}
@@ -3,6 +3,7 @@ import { sceneRegistry } from '@pascal-app/core';
3
3
  import { useFrame } from '@react-three/fiber';
4
4
  import { useEffect, useMemo, useRef } from 'react';
5
5
  import * as THREE from 'three/webgpu';
6
+ import { isDaylightAtmosphere } from '../../lib/daylight/look';
6
7
  import { getKeyLightDirectionOverride } from '../../lib/key-light-override';
7
8
  import { SHADOW_ONLY_LAYER } from '../../lib/layers';
8
9
  import { registerSkyLights } from '../../lib/underground-ambiance';
@@ -97,7 +98,10 @@ export function Lights() {
97
98
  fillMounted.current = true;
98
99
  const filled = fillMounted.current;
99
100
  const atmosphere = useSceneAtmosphere();
100
- const lightSlots = useMemo(() => Array.from({ length: atmosphere ? 2 : theme.lights.length }, (_, index) => index), [atmosphere, theme.lights.length]);
101
+ // The daylight look lights with one key (sun, or moon at night) and the sky environment only:
102
+ // no moon slot, hemisphere or ambient light (each light costs every material's shader).
103
+ const daylight = isDaylightAtmosphere(atmosphere);
104
+ const lightSlots = useMemo(() => Array.from({ length: daylight ? 1 : atmosphere ? 2 : theme.lights.length }, (_, index) => index), [atmosphere, daylight, theme.lights.length]);
101
105
  const lightRefs = useRef([]);
102
106
  const shadowCamera = useRef(null);
103
107
  // Initial ortho half-size; overridden each refresh to fit the building.
@@ -109,6 +113,10 @@ export function Lights() {
109
113
  const boundsBox = useRef(new THREE.Box3()); // scratch: union AABB
110
114
  const boundsSphere = useRef(new THREE.Sphere()); // scratch: fitted sphere
111
115
  const lastBoundsTime = useRef(-1); // last refresh timestamp (-1 = never)
116
+ // Daylight sun shadows render on change only (see `shadowSignature`).
117
+ const shadowCasters = useRef([]);
118
+ const shadowCasterTime = useRef(-1);
119
+ const lastShadowSignature = useRef(Number.NaN);
112
120
  const shadowHelpers = useRef([]);
113
121
  const hemiRef = useRef(null);
114
122
  const ambientRef = useRef(null);
@@ -135,6 +143,9 @@ export function Lights() {
135
143
  const dt = Math.min(delta, 0.1) * 4;
136
144
  const sourceShadow = atmosphere ? undefined : theme.lights[0]?.shadow;
137
145
  const sourceCamera = sourceShadow?.camera;
146
+ // The daylight look: one key (sun or moon) with its own shadow settings, frustum fitted
147
+ // tightly around the building in light space.
148
+ const daylightShadow = isDaylightAtmosphere(atmosphere) ? atmosphere.shadow : undefined;
138
149
  // Atmosphere directions are stable mutable vectors. Keep both light
139
150
  // resources mounted and move them imperatively so time/angle changes never
140
151
  // rebuild materials or shadow resources.
@@ -168,11 +179,24 @@ export function Lights() {
168
179
  if (!sourceCamera && now - lastBoundsTime.current >= BOUNDS_REFRESH_INTERVAL) {
169
180
  lastBoundsTime.current = now;
170
181
  const box = boundsBox.current.makeEmpty();
182
+ const counted = new Set();
171
183
  for (const [id, obj] of sceneRegistry.nodes) {
172
184
  if (SHADOW_EXCLUDED_TYPES.some((type) => sceneRegistry.byType[type].has(id)))
173
185
  continue;
174
- box.expandByObject(obj);
186
+ counted.add(obj);
175
187
  }
188
+ // A counted node's subtree already holds the nodes below it: walk each mesh once, not
189
+ // once per counted ancestor (building, level, wall, item…).
190
+ for (const obj of counted) {
191
+ let nested = false;
192
+ for (let p = obj.parent; p && !nested; p = p.parent)
193
+ nested = counted.has(p);
194
+ if (!nested)
195
+ expandByWorldBounds(box, obj);
196
+ }
197
+ // Baked artifacts stay out of the registry: frame their shadow casters instead.
198
+ if (box.isEmpty() && daylightShadow)
199
+ expandByShadowCasters(state.scene, box);
176
200
  box.getBoundingSphere(boundsSphere.current);
177
201
  const center = boundsSphere.current.center;
178
202
  const radius = boundsSphere.current.radius;
@@ -235,7 +259,29 @@ export function Lights() {
235
259
  light.position.set(tx, ty, tz).add(shadowDir.current);
236
260
  }
237
261
  const cam = light.shadow?.camera;
238
- if (cam) {
262
+ if (cam && daylightShadow && !sourceCamera) {
263
+ light.shadow.mapSize.setScalar(daylightShadow.mapSize);
264
+ light.shadow.bias = daylightShadow.bias;
265
+ light.shadow.normalBias = daylightShadow.normalBias;
266
+ light.shadow.radius = daylightShadow.radius;
267
+ cam.layers.enable(SHADOW_ONLY_LAYER);
268
+ fitShadowToBounds(light, boundsBox.current, shadowDir.current);
269
+ // The sun's map re-renders only when something it depends on changes: its placement,
270
+ // frustum or settings, or a caster that moved, appeared, vanished or changed shape.
271
+ // A walkthrough or an orbit moves only the eye, so the map is reused frame to frame.
272
+ light.shadow.autoUpdate = false;
273
+ if (now - shadowCasterTime.current >= BOUNDS_REFRESH_INTERVAL) {
274
+ shadowCasterTime.current = now;
275
+ collectShadowCasters(state.scene, shadowCasters.current);
276
+ }
277
+ const signature = shadowSignature(light, cam, shadowCasters.current);
278
+ if (signature !== lastShadowSignature.current) {
279
+ lastShadowSignature.current = signature;
280
+ light.shadow.needsUpdate = true;
281
+ }
282
+ }
283
+ else if (cam) {
284
+ light.shadow.autoUpdate = true;
239
285
  // The calibrated building bias detaches furniture-scale contact shadows.
240
286
  // Small scenes need finer shadow edges too; retain the building map budget.
241
287
  const smallScene = !sourceCamera && shadowRadius.current < 1.5;
@@ -300,7 +346,9 @@ export function Lights() {
300
346
  light.color.lerp(target, dt);
301
347
  }
302
348
  if (index === 0 && light.shadow?.intensity !== undefined) {
303
- const shadowIntensity = sourceShadow?.intensity ?? (intensity <= 1 ? intensity : MAX_SHADOW_INTENSITY);
349
+ const shadowIntensity = daylightShadow
350
+ ? 1
351
+ : (sourceShadow?.intensity ?? (intensity <= 1 ? intensity : MAX_SHADOW_INTENSITY));
304
352
  light.shadow.intensity =
305
353
  atmosphere || !initialized.current
306
354
  ? shadowIntensity
@@ -353,5 +401,144 @@ export function Lights() {
353
401
  : (themeLight?.position ?? [0, 1, 0]), ref: (light) => {
354
402
  lightRefs.current[index] = light;
355
403
  }, "shadow-bias": SHADOW_DEPTH_BIAS, "shadow-mapSize": [1024, 1024], "shadow-normalBias": SHADOW_NORMAL_BIAS, "shadow-radius": 2, children: index === 0 && keyCastsShadow ? (_jsx("orthographicCamera", { attach: "shadow-camera", bottom: -shadowCameraSize, far: 400, left: -shadowCameraSize, near: 1, ref: shadowCamera, right: shadowCameraSize, top: shadowCameraSize })) : null }, index));
356
- }), atmosphere || theme.hemi ? _jsx("hemisphereLight", { ref: hemiRef }) : null, _jsx("ambientLight", { ref: ambientRef }), filled && _jsx(UndergroundFill, { lightRef: fillRef }), _jsx(UndergroundAmbiance, {})] }));
404
+ }), !daylight && (atmosphere || theme.hemi) ? _jsx("hemisphereLight", { ref: hemiRef }) : null, daylight ? null : _jsx("ambientLight", { ref: ambientRef }), filled && _jsx(UndergroundFill, { lightRef: fillRef }), _jsx(UndergroundAmbiance, {})] }));
405
+ }
406
+ const _fitCenter = new THREE.Vector3();
407
+ const _fitSize = new THREE.Vector3();
408
+ const _fitCorner = new THREE.Vector3();
409
+ const _fitBox = new THREE.Box3();
410
+ const _fitBounds = new THREE.Box3();
411
+ const _fitView = new THREE.Matrix4();
412
+ const _fitUp = new THREE.Vector3(0, 1, 0);
413
+ const _fitMargin = new THREE.Vector3(2, 0, 2);
414
+ /**
415
+ * Daylight key: place the light on its direction around the building and fit the ortho shadow
416
+ * camera to the building box (+2 m of ground) projected into light space — the tightest frustum,
417
+ * so the map's texels all land on the building. Its depth reaches on to where the casters' shadows
418
+ * meet the ground: a receiver beyond the far plane reads as fully lit, which cut long shadows off
419
+ * square. A shadow keeps its caster's light-space x/y, so only the depth grows, not the texels.
420
+ */
421
+ function fitShadowToBounds(light, bounds, direction) {
422
+ if (bounds.isEmpty())
423
+ return;
424
+ const center = bounds.getCenter(_fitCenter);
425
+ const radius = bounds.getSize(_fitSize).length() / 2 + 2;
426
+ const toLight = _fitSize.copy(direction).normalize();
427
+ light.position.copy(center).addScaledVector(toLight, radius * 2);
428
+ light.target.position.copy(center);
429
+ light.target.updateMatrixWorld();
430
+ light.updateMatrixWorld();
431
+ _fitView.lookAt(light.position, center, _fitUp).invert();
432
+ _fitView.setPosition(0, 0, 0);
433
+ const b = _fitBounds.copy(bounds).expandByVector(_fitMargin);
434
+ const box = _fitBox.makeEmpty();
435
+ // The ground under the casters (the site ground sits just below 0).
436
+ const groundY = Math.min(bounds.min.y, -0.07);
437
+ for (let i = 0; i < 8; i++) {
438
+ const y = i & 2 ? b.max.y : b.min.y;
439
+ _fitCorner
440
+ .set(i & 1 ? b.max.x : b.min.x, y, i & 4 ? b.max.z : b.min.z)
441
+ .sub(light.position)
442
+ .applyMatrix4(_fitView);
443
+ box.expandByPoint(_fitCorner);
444
+ // Down the light ray to the ground: same x/y in light space, only deeper.
445
+ if (toLight.y > 0)
446
+ box.min.z = Math.min(box.min.z, _fitCorner.z - (y - groundY) / toLight.y);
447
+ }
448
+ const cam = light.shadow.camera;
449
+ cam.left = box.min.x - 0.5;
450
+ cam.right = box.max.x + 0.5;
451
+ cam.bottom = box.min.y - 0.5;
452
+ cam.top = box.max.y + 0.5;
453
+ cam.near = Math.max(0.1, -box.max.z - 1);
454
+ cam.far = -box.min.z + 1;
455
+ cam.updateProjectionMatrix();
456
+ }
457
+ /** Every shadow-casting mesh under `root` (visible or not: a level shown again must count). */
458
+ function collectShadowCasters(root, out) {
459
+ out.length = 0;
460
+ root.traverse((object) => {
461
+ const mesh = object;
462
+ if (mesh.isMesh && mesh.castShadow)
463
+ out.push(mesh);
464
+ });
465
+ }
466
+ /**
467
+ * A number that changes whenever the sun's shadow map would: the light's world placement and
468
+ * projection, its map settings, and each caster's world transform, shown state (through its
469
+ * ancestors) and geometry. Cheap enough per frame: a few reads per caster, no allocation.
470
+ */
471
+ function shadowSignature(light, cam, casters) {
472
+ // A weighted sum, not a multiply-and-wrap hash: it stays exact to ~1e-7 at these magnitudes,
473
+ // so a door turning by a fraction of a degree still changes it.
474
+ let h = light.shadow.mapSize.x + light.shadow.bias * 1e4 + light.shadow.normalBias * 1e3;
475
+ h += light.shadow.radius * 7;
476
+ const lm = light.matrixWorld.elements;
477
+ const pm = cam.projectionMatrix.elements;
478
+ for (let i = 0; i < 16; i++)
479
+ h += (i + 1) * (lm[i] * 1.013 + pm[i] * 0.917);
480
+ for (let i = 0; i < casters.length; i++) {
481
+ const mesh = casters[i];
482
+ let shown = mesh.castShadow;
483
+ for (let x = mesh; x && shown; x = x.parent)
484
+ shown = x.visible;
485
+ if (!shown)
486
+ continue;
487
+ const m = mesh.matrixWorld.elements;
488
+ const w = (i % 89) + 1;
489
+ h +=
490
+ w *
491
+ (m[0] +
492
+ m[1] * 2 +
493
+ m[2] * 3 +
494
+ m[5] * 5 +
495
+ m[10] * 7 +
496
+ m[12] * 11 +
497
+ m[13] * 13 +
498
+ m[14] * 17 +
499
+ mesh.geometry.id * 0.019 +
500
+ 0.5);
501
+ }
502
+ return h;
503
+ }
504
+ const _objectBox = new THREE.Box3();
505
+ /**
506
+ * `Box3.expandByObject` without its `updateWorldMatrix` on every object visited, which recomposed
507
+ * ~10k matrices per refresh: the frame's render already brought world matrices up to date
508
+ * (scene-matrices.ts), and bounds a frame old are fine for fitting the shadow frustum.
509
+ */
510
+ function expandByWorldBounds(box, root) {
511
+ root.traverse((object) => {
512
+ const geometry = object.geometry;
513
+ if (geometry === undefined)
514
+ return;
515
+ const owned = object;
516
+ if (owned.boundingBox !== undefined) {
517
+ if (owned.boundingBox === null)
518
+ owned.computeBoundingBox?.();
519
+ if (!owned.boundingBox)
520
+ return;
521
+ _objectBox.copy(owned.boundingBox);
522
+ }
523
+ else {
524
+ if (geometry.boundingBox === null)
525
+ geometry.computeBoundingBox();
526
+ _objectBox.copy(geometry.boundingBox);
527
+ }
528
+ _objectBox.applyMatrix4(object.matrixWorld);
529
+ box.union(_objectBox);
530
+ });
531
+ }
532
+ /** Shadow-casting meshes of a scene (skipping the effectively infinite grounds). */
533
+ function expandByShadowCasters(scene, box) {
534
+ const mesh = new THREE.Box3();
535
+ scene.traverseVisible((object) => {
536
+ const candidate = object;
537
+ if (!candidate.isMesh || !candidate.castShadow)
538
+ return;
539
+ mesh.setFromObject(candidate);
540
+ if (mesh.isEmpty() || mesh.max.x - mesh.min.x > 500 || mesh.max.z - mesh.min.z > 500)
541
+ return;
542
+ box.union(mesh);
543
+ });
357
544
  }
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"post-processing.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/post-processing.tsx"],"names":[],"mappings":"AA+FA,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,SAkvBA,CAAA;eAEc,oBAAoB"}