@pascal-app/viewer 1.0.4 → 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 (183) 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 +4 -1
  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.map +1 -1
  9. package/dist/components/viewer/glb-interactive.js +1 -1
  10. package/dist/components/viewer/glb-reference-nodes.js +1 -1
  11. package/dist/components/viewer/glb-replace-instances.js +1 -1
  12. package/dist/components/viewer/glb-scene.d.ts.map +1 -1
  13. package/dist/components/viewer/glb-scene.js +2 -3
  14. package/dist/components/viewer/glb-walkthrough-controller.js +1 -1
  15. package/dist/components/viewer/index.d.ts +10 -1
  16. package/dist/components/viewer/index.d.ts.map +1 -1
  17. package/dist/components/viewer/index.js +28 -12
  18. package/dist/components/viewer/lights.d.ts.map +1 -1
  19. package/dist/components/viewer/lights.js +107 -21
  20. package/dist/components/viewer/perf-panel.d.ts.map +1 -1
  21. package/dist/components/viewer/perf-panel.js +1 -1
  22. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  23. package/dist/components/viewer/post-processing.js +96 -33
  24. package/dist/components/viewer/registered-systems.js +1 -1
  25. package/dist/components/viewer/scene-bvh.d.ts.map +1 -1
  26. package/dist/components/viewer/scene-bvh.js +1 -1
  27. package/dist/components/viewer/scene-environment.d.ts.map +1 -1
  28. package/dist/components/viewer/scene-environment.js +31 -11
  29. package/dist/components/viewer/selection-manager.js +15 -7
  30. package/dist/components/viewer/underground-ambiance.d.ts +9 -0
  31. package/dist/components/viewer/underground-ambiance.d.ts.map +1 -0
  32. package/dist/components/viewer/underground-ambiance.js +105 -0
  33. package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
  34. package/dist/components/viewer/viewer-camera.js +1 -1
  35. package/dist/components/viewer/viewer-presentations.d.ts.map +1 -1
  36. package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
  37. package/dist/hooks/use-gltf-ktx2.js +2 -0
  38. package/dist/hooks/use-node-events.d.ts.map +1 -1
  39. package/dist/index.d.ts +16 -7
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +16 -7
  42. package/dist/lib/backdrop.d.ts +17 -0
  43. package/dist/lib/backdrop.d.ts.map +1 -1
  44. package/dist/lib/backdrop.js +18 -1
  45. package/dist/lib/construction-dust.d.ts +57 -0
  46. package/dist/lib/construction-dust.d.ts.map +1 -0
  47. package/dist/lib/construction-dust.js +187 -0
  48. package/dist/lib/csg-utils.js +1 -1
  49. package/dist/lib/foundation-materials.d.ts +26 -0
  50. package/dist/lib/foundation-materials.d.ts.map +1 -0
  51. package/dist/lib/foundation-materials.js +65 -0
  52. package/dist/lib/gltf-unlit.d.ts +10 -0
  53. package/dist/lib/gltf-unlit.d.ts.map +1 -0
  54. package/dist/lib/gltf-unlit.js +23 -0
  55. package/dist/lib/ground-window.d.ts +33 -0
  56. package/dist/lib/ground-window.d.ts.map +1 -0
  57. package/dist/lib/ground-window.js +114 -0
  58. package/dist/lib/hero-pose.d.ts +1 -1
  59. package/dist/lib/hero-pose.d.ts.map +1 -1
  60. package/dist/lib/ink-edges.d.ts +2 -1
  61. package/dist/lib/ink-edges.d.ts.map +1 -1
  62. package/dist/lib/ktx2-loader.d.ts +7 -0
  63. package/dist/lib/ktx2-loader.d.ts.map +1 -1
  64. package/dist/lib/ktx2-loader.js +35 -0
  65. package/dist/lib/layer-pass.d.ts.map +1 -1
  66. package/dist/lib/layers.d.ts +11 -7
  67. package/dist/lib/layers.d.ts.map +1 -1
  68. package/dist/lib/layers.js +16 -6
  69. package/dist/lib/materials.d.ts +5 -0
  70. package/dist/lib/materials.d.ts.map +1 -1
  71. package/dist/lib/materials.js +34 -4
  72. package/dist/lib/merged-outline-node.d.ts +5 -0
  73. package/dist/lib/merged-outline-node.d.ts.map +1 -1
  74. package/dist/lib/merged-outline-node.js +80 -2
  75. package/dist/lib/pointer-events.d.ts +20 -4
  76. package/dist/lib/pointer-events.d.ts.map +1 -1
  77. package/dist/lib/pointer-events.js +78 -14
  78. package/dist/lib/post-processing-resources.d.ts.map +1 -1
  79. package/dist/lib/reveal-candidates.d.ts +80 -0
  80. package/dist/lib/reveal-candidates.d.ts.map +1 -0
  81. package/dist/lib/reveal-candidates.js +524 -0
  82. package/dist/lib/reveal-ghost.d.ts +9 -0
  83. package/dist/lib/reveal-ghost.d.ts.map +1 -0
  84. package/dist/lib/reveal-ghost.js +62 -0
  85. package/dist/lib/reveal-pending.d.ts +12 -0
  86. package/dist/lib/reveal-pending.d.ts.map +1 -0
  87. package/dist/lib/reveal-pending.js +12 -0
  88. package/dist/lib/reveal-pose.d.ts +70 -0
  89. package/dist/lib/reveal-pose.d.ts.map +1 -0
  90. package/dist/lib/reveal-pose.js +248 -0
  91. package/dist/lib/reveal-schedule.d.ts +208 -0
  92. package/dist/lib/reveal-schedule.d.ts.map +1 -0
  93. package/dist/lib/reveal-schedule.js +410 -0
  94. package/dist/lib/reveal-texture-scale.d.ts +5 -0
  95. package/dist/lib/reveal-texture-scale.d.ts.map +1 -0
  96. package/dist/lib/reveal-texture-scale.js +113 -0
  97. package/dist/lib/reveal-windows.d.ts +23 -0
  98. package/dist/lib/reveal-windows.d.ts.map +1 -0
  99. package/dist/lib/reveal-windows.js +31 -0
  100. package/dist/lib/reveal-wipe.d.ts +71 -0
  101. package/dist/lib/reveal-wipe.d.ts.map +1 -0
  102. package/dist/lib/reveal-wipe.js +105 -0
  103. package/dist/lib/scene-pass-mrt.d.ts +12 -0
  104. package/dist/lib/scene-pass-mrt.d.ts.map +1 -0
  105. package/dist/lib/scene-pass-mrt.js +23 -0
  106. package/dist/lib/scene-themes.d.ts +30 -8
  107. package/dist/lib/scene-themes.d.ts.map +1 -1
  108. package/dist/lib/scene-themes.js +36 -0
  109. package/dist/lib/scene-visibility.d.ts +11 -1
  110. package/dist/lib/scene-visibility.d.ts.map +1 -1
  111. package/dist/lib/scene-visibility.js +38 -0
  112. package/dist/lib/site-surfaces.d.ts +32 -0
  113. package/dist/lib/site-surfaces.d.ts.map +1 -0
  114. package/dist/lib/site-surfaces.js +70 -0
  115. package/dist/lib/snapshot-pipeline.d.ts +2 -1
  116. package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
  117. package/dist/lib/snapshot-pipeline.js +35 -15
  118. package/dist/lib/tsl-compat.d.ts +2 -2
  119. package/dist/lib/tsl-compat.d.ts.map +1 -1
  120. package/dist/lib/underground-ambiance.d.ts +168 -0
  121. package/dist/lib/underground-ambiance.d.ts.map +1 -0
  122. package/dist/lib/underground-ambiance.js +334 -0
  123. package/dist/store/use-viewer.d.ts +184 -27
  124. package/dist/store/use-viewer.d.ts.map +1 -1
  125. package/dist/store/use-viewer.js +155 -19
  126. package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
  127. package/dist/systems/ceiling/ceiling-system.js +2 -0
  128. package/dist/systems/construction-reveal/construction-dust.d.ts +16 -0
  129. package/dist/systems/construction-reveal/construction-dust.d.ts.map +1 -0
  130. package/dist/systems/construction-reveal/construction-dust.js +92 -0
  131. package/dist/systems/construction-reveal/construction-reveal.d.ts +276 -0
  132. package/dist/systems/construction-reveal/construction-reveal.d.ts.map +1 -0
  133. package/dist/systems/construction-reveal/construction-reveal.js +2383 -0
  134. package/dist/systems/construction-reveal/dust-material.d.ts +10 -0
  135. package/dist/systems/construction-reveal/dust-material.d.ts.map +1 -0
  136. package/dist/systems/construction-reveal/dust-material.js +17 -0
  137. package/dist/systems/construction-reveal/ghost-dress.d.ts +10 -0
  138. package/dist/systems/construction-reveal/ghost-dress.d.ts.map +1 -0
  139. package/dist/systems/construction-reveal/ghost-dress.js +24 -0
  140. package/dist/systems/elevator/elevator-interaction-system.d.ts +7 -0
  141. package/dist/systems/elevator/elevator-interaction-system.d.ts.map +1 -1
  142. package/dist/systems/elevator/elevator-interaction-system.js +18 -1
  143. package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
  144. package/dist/systems/interactive/control-widget.d.ts.map +1 -1
  145. package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
  146. package/dist/systems/interactive/interactive-system.js +16 -6
  147. package/dist/systems/interactive/scripted-clips.js +1 -1
  148. package/dist/systems/item-light/item-light-system.js +1 -1
  149. package/dist/systems/level/level-hold.d.ts +4 -0
  150. package/dist/systems/level/level-hold.d.ts.map +1 -0
  151. package/dist/systems/level/level-hold.js +14 -0
  152. package/dist/systems/level/level-system.d.ts.map +1 -1
  153. package/dist/systems/level/level-system.js +16 -1
  154. package/dist/systems/level/level-utils.d.ts +13 -3
  155. package/dist/systems/level/level-utils.d.ts.map +1 -1
  156. package/dist/systems/level/level-utils.js +56 -8
  157. package/dist/systems/roof/__fixtures__/roof-plane-cases.d.ts +103 -0
  158. package/dist/systems/roof/__fixtures__/roof-plane-cases.d.ts.map +1 -0
  159. package/dist/systems/roof/__fixtures__/roof-plane-cases.js +317 -0
  160. package/dist/systems/roof/roof-materials.d.ts +4 -2
  161. package/dist/systems/roof/roof-materials.d.ts.map +1 -1
  162. package/dist/systems/roof/roof-materials.js +18 -24
  163. package/dist/systems/roof/roof-system.d.ts +8 -1
  164. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  165. package/dist/systems/roof/roof-system.js +195 -45
  166. package/dist/systems/wall/wall-cutout-cache.d.ts +32 -3
  167. package/dist/systems/wall/wall-cutout-cache.d.ts.map +1 -1
  168. package/dist/systems/wall/wall-cutout-cache.js +95 -2
  169. package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
  170. package/dist/systems/wall/wall-material-variant.d.ts.map +1 -1
  171. package/dist/systems/wall/wall-materials.d.ts.map +1 -1
  172. package/dist/systems/wall/wall-materials.js +39 -4
  173. package/dist/systems/wall/wall-placeholder-sweep.d.ts.map +1 -1
  174. package/dist/systems/wall/wall-system.d.ts +5 -0
  175. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  176. package/dist/systems/wall/wall-system.js +42 -19
  177. package/dist/systems/window/corner-frame.d.ts +10 -0
  178. package/dist/systems/window/corner-frame.d.ts.map +1 -0
  179. package/dist/systems/window/corner-frame.js +17 -0
  180. package/dist/systems/window/window-system.d.ts +1 -1
  181. package/dist/systems/window/window-system.d.ts.map +1 -1
  182. package/dist/systems/window/window-system.js +31 -6
  183. package/package.json +8 -8
@@ -1,5 +1,5 @@
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 { sceneRegistry, useScene } from '@pascal-app/core';
4
4
  import { CaptureArtifactReferenceSchema, captureLayerKey, DeviceMotionTrajectorySchema, } from '@pascal-app/core/capture';
5
5
  import { createPortal, useFrame } from '@react-three/fiber';
@@ -1 +1 @@
1
- {"version":3,"file":"error-boundary.d.ts","sourceRoot":"","sources":["../../src/components/error-boundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjC,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,SAAS,CAAA;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uEAAuE;IACvE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC;2EACuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,qBAAa,aAAc,SAAQ,SAAS,CAAC,kBAAkB,EAAE;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;IACrF,KAAK;;MAAsB;IAC3B,MAAM,CAAC,wBAAwB;;;IAG/B,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS;IAQ/C,kBAAkB,CAAC,SAAS,EAAE,kBAAkB;IAKhD,MAAM;CAGP"}
1
+ {"version":3,"file":"error-boundary.d.ts","sourceRoot":"","sources":["../../src/components/error-boundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjC,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,SAAS,CAAA;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uEAAuE;IACvE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC;2EACuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,qBAAa,aAAc,SAAQ,SAAS,CAAC,kBAAkB,EAAE;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;IACrF,KAAK;QAAK,QAAQ;MAAS;IAC3B,MAAM,CAAC,wBAAwB;QACpB,QAAQ;MAClB;IACD,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,QAO9C;IACD,kBAAkB,CAAC,SAAS,EAAE,kBAAkB,QAI/C;IACD,MAAM,cAEL;CACF"}
@@ -4,6 +4,6 @@ export declare function getRegistryRenderer(source: RendererSource<AnyNode>): Co
4
4
  node: AnyNode;
5
5
  }> | null;
6
6
  export declare const NodeRenderer: ({ nodeId }: {
7
- nodeId: AnyNode["id"];
7
+ nodeId: AnyNode['id'];
8
8
  }) => import("react").JSX.Element | null;
9
9
  //# sourceMappingURL=node-renderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node-renderer.d.ts","sourceRoot":"","sources":["../../../src/components/renderers/node-renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,OAAO,EAIZ,KAAK,cAAc,EAEpB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,KAAK,aAAa,EAAqD,MAAM,OAAO,CAAA;AAO7F,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,GAC9B,aAAa,CAAC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,GAAG,IAAI,CASzC;AAED,eAAO,MAAM,YAAY,GAAI,YAAY;IAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,uCA+BjE,CAAA"}
1
+ {"version":3,"file":"node-renderer.d.ts","sourceRoot":"","sources":["../../../src/components/renderers/node-renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,OAAO,EAIZ,KAAK,cAAc,EAEpB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,KAAK,aAAa,EAAqD,MAAM,OAAO,CAAA;AAQ7F,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,GAC9B,aAAa,CAAC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,GAAG,IAAI,CASzC;AAED,eAAO,MAAM,YAAY,eAAgB;IAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,uCAiCjE,CAAA"}
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { isNodeKindEnabled, nodeRegistry, onRegistryChange, useScene, } from '@pascal-app/core';
4
4
  import { lazy, Suspense, useCallback, useSyncExternalStore } from 'react';
5
+ import { useRevealPending } from '../../systems/construction-reveal/construction-reveal';
5
6
  import { ParametricNodeRenderer } from './parametric-node-renderer';
6
7
  // Cache lazy components by their RendererSource so React.lazy isn't re-invoked
7
8
  // on every render — that would create a new Suspense boundary each time.
@@ -27,7 +28,9 @@ export const NodeRenderer = ({ nodeId }) => {
27
28
  const kind = node?.type;
28
29
  const readDefinition = useCallback(() => (kind ? nodeRegistry.get(kind) : undefined), [kind]);
29
30
  const def = useSyncExternalStore(onRegistryChange, readDefinition, readDefinition);
30
- if (!node)
31
+ // A node an agent just built mounts on its construction-reveal turn.
32
+ const revealPending = useRevealPending(nodeId);
33
+ if (!node || revealPending)
31
34
  return null;
32
35
  if (!isNodeKindEnabled(node.type, installedPlugins))
33
36
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"parametric-node-renderer.d.ts","sourceRoot":"","sources":["../../../src/components/renderers/parametric-node-renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,OAAO,EAMb,MAAM,kBAAkB,CAAA;AAwCzB,eAAO,MAAM,sBAAsB,GAAI,UAAU;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,gCAgDjE,CAAA"}
1
+ {"version":3,"file":"parametric-node-renderer.d.ts","sourceRoot":"","sources":["../../../src/components/renderers/parametric-node-renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,OAAO,EAMb,MAAM,kBAAkB,CAAA;AAwCzB,eAAO,MAAM,sBAAsB,aAAc;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,gCAgDjE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"bvh-ecctrl.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/bvh-ecctrl.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bvh-ecctrl.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/bvh-ecctrl.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"frame-limiter.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/frame-limiter.tsx"],"names":[],"mappings":"AAKA,KAAK,iBAAiB,GAAG;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CACxC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IACjE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;CAClC,CAAA;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,SAAI,GAAG,UAAU,CAwB5D;AAgBD,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAmG7C,CAAA;AAED,eAAe,YAAY,CAAA"}
1
+ {"version":3,"file":"frame-limiter.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/frame-limiter.tsx"],"names":[],"mappings":"AAKA,KAAK,iBAAiB,GAAG;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CACxC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IACjE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;CAClC,CAAA;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,SAAI,GAAG,UAAU,CAwB5D;AAgBD,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAmG7C,CAAA;eAEc,YAAY"}
@@ -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 { containsPoint, isScriptedNode, scriptedOrigin, scriptedSize, scriptInteractive, useInteractive, } from '@pascal-app/core';
4
4
  import { evaluateRecipe, } from '@pascal-app/core/procedural-items';
5
5
  import { Html } from '@react-three/drei';
@@ -1,5 +1,5 @@
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 { bakePolicyOf, isNodeKindEnabled, nodeRegistry, } from '@pascal-app/core';
4
4
  import { createPortal } from '@react-three/fiber';
5
5
  import { memo, Suspense } from 'react';
@@ -1,5 +1,5 @@
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 { nodeRegistry } from '@pascal-app/core';
4
4
  import { createPortal } from '@react-three/fiber';
5
5
  import { Fragment, lazy, memo, Suspense, useMemo } from 'react';
@@ -1 +1 @@
1
- {"version":3,"file":"glb-scene.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/glb-scene.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,OAAO,EAWb,MAAM,kBAAkB,CAAA;AAQzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAS9B,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAsB3E;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;IACvB,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;IAC/D,SAAS,EAAE;QAAE,GAAG,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAA;CAC1E,CAAA;AAKD;0EAC0E;AAC1E,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CAC/D,GAAG,IAAI,CAAA;AAoDR,KAAK,YAAY,GAAG;IAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAA;CAAE,CAAA;AA0CpE;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,SAAS,YAAY,EAAE,EAC7B,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,GAC5C,CAAC,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG;IAAE,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAA;CAAE,CAAC,GAAG,IAAI,CAkB5E;AASD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,MAAM,EACN,mBAAmB,GACpB,EAAE;IACD,GAAG,EAAE,MAAM,CAAA;IACX;oFACgF;IAChF,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,CAAA;IACvC;mFAC+E;IAC/E,cAAc,CAAC,EAAE,OAAO,EAAE,CAAA;IAC1B;kFAC8E;IAC9E,YAAY,CAAC,EAAE,OAAO,EAAE,CAAA;IACxB,iFAAiF;IACjF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAA;IACxE,4EAA4E;IAC5E,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAA;IACtC,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAA;CACtD,+BA6xBA"}
1
+ {"version":3,"file":"glb-scene.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/glb-scene.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,OAAO,EAYb,MAAM,kBAAkB,CAAA;AAQzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAS9B,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAmB3E;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;IACvB,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;IAC/D,SAAS,EAAE;QAAE,GAAG,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAA;CAC1E,CAAA;AAKD;0EAC0E;AAC1E,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CAC/D,GAAG,IAAI,CAAA;AAoDR,KAAK,YAAY,GAAG;IAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAA;CAAE,CAAA;AA0CpE;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,SAAS,YAAY,EAAE,EAC7B,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,GAC5C,CAAC,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG;IAAE,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAA;CAAE,CAAC,GAAG,IAAI,CAkB5E;AASD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,MAAM,EACN,mBAAmB,GACpB,EAAE;IACD,GAAG,EAAE,MAAM,CAAA;IACX;oFACgF;IAChF,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,CAAA;IACvC;mFAC+E;IAC/E,cAAc,CAAC,EAAE,OAAO,EAAE,CAAA;IAC1B;kFAC8E;IAC9E,YAAY,CAAC,EAAE,OAAO,EAAE,CAAA;IACxB,iFAAiF;IACjF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAA;IACxE,4EAA4E;IAC5E,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAA;IACtC,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAA;CACtD,+BA8xBA"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { bakePolicyOf, containsPoint, distanceToBoundary, itemInteraction, itemPrompt, operateItem, polygonInteriorPoint, useInteractive, } from '@pascal-app/core';
3
+ import { bakePolicyOf, containsPoint, distanceToBoundary, EXPLODED_GAP, itemInteraction, itemPrompt, operateItem, polygonInteriorPoint, useInteractive, } from '@pascal-app/core';
4
4
  import { operableParts, ProceduralMotionController, } from '@pascal-app/core/procedural-items';
5
5
  import { useFrame, useThree } from '@react-three/fiber';
6
6
  import { useCallback, useEffect, useMemo, useRef } from 'react';
@@ -17,8 +17,6 @@ import { GlbInteractive } from './glb-interactive';
17
17
  import { bakedLoopMechanisms } from './glb-mechanisms';
18
18
  import { GlbReferenceNodes } from './glb-reference-nodes';
19
19
  import { GlbReplaceInstances } from './glb-replace-instances';
20
- /** Vertical gap added per floor in `exploded` level mode (matches LevelSystem). */
21
- const EXPLODED_GAP = 5;
22
20
  /** Baked `kind` → surface role, so monochrome can recolor by role like the
23
21
  * parametric viewer (textures-off collapses each face to its themed clay). */
24
22
  const ROLE_BY_KIND = {
@@ -427,6 +425,7 @@ export function GlbScene({ url, interactiveItems, referenceNodes, replaceNodes,
427
425
  index,
428
426
  selectedIndex: selectedIdx >= 0 ? selectedIdx : undefined,
429
427
  nodeVisible: true,
428
+ revealing: false,
430
429
  });
431
430
  if (shadowOnly)
432
431
  applyShadowOnly(node);
@@ -178,7 +178,7 @@ function buildGlbColliderWorld(scene) {
178
178
  ;
179
179
  merged.computeBoundsTree = computeBoundsTree;
180
180
  merged.disposeBoundsTree = disposeBoundsTree;
181
- merged.computeBoundsTree({ maxLeafSize: 12, strategy: 0 });
181
+ merged.computeBoundsTree({ targetLeafSize: 12, strategy: 0 });
182
182
  merged.computeBoundingBox();
183
183
  const mesh = new Mesh(merged, colliderMaterial);
184
184
  mesh.raycast = acceleratedRaycast;
@@ -1,8 +1,9 @@
1
- import { type AnyNodeId } from '@pascal-app/core';
1
+ import { type AnyNodeId, type SitePresentation } from '@pascal-app/core';
2
2
  import { type ThreeElement } from '@react-three/fiber';
3
3
  import { type ComponentType } from 'react';
4
4
  import * as THREE from 'three/webgpu';
5
5
  import type { ColorPreset, RenderShading } from '../../lib/materials';
6
+ import { type ViewerBreadcrumbHandler } from '../../lib/pointer-events';
6
7
  import { type RenderContext } from '../../store/use-viewer';
7
8
  import { type HoverStyles } from './post-processing';
8
9
  declare module '@react-three/fiber' {
@@ -39,6 +40,8 @@ interface ViewerProps {
39
40
  textures?: boolean;
40
41
  colorPreset?: ColorPreset;
41
42
  };
43
+ /** Saved site appearance when rendering a baked asset without its graph. Null ignores it. */
44
+ presentation?: SitePresentation | null;
42
45
  /**
43
46
  * Visibility filter on the live canvas. When non-null, every registered
44
47
  * node group whose id is not in `isolate` (or in the isolated set's
@@ -63,6 +66,12 @@ interface ViewerProps {
63
66
  * that must not carry on silently (a bake) fail with its own error.
64
67
  */
65
68
  onRenderError?: (cause: unknown) => void;
69
+ /**
70
+ * Called with diagnostics worth keeping on a host's error-reporter trail,
71
+ * such as `raycast_invalid_material` when a pointer raycast skips a mesh
72
+ * whose geometry groups point past its material array.
73
+ */
74
+ onBreadcrumb?: ViewerBreadcrumbHandler;
66
75
  /**
67
76
  * Wall-clock give-up cap for scene readiness, replacing the default
68
77
  * frame-count cap. Set it on hosts whose frame cadence is decoupled from
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,SAAS,EAOf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAkB,KAAK,YAAY,EAAsB,MAAM,oBAAoB,CAAA;AAC1F,OAAO,EACL,KAAK,aAAa,EAOnB,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAKrC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAKrE,OAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAA;AActE,OAAuB,EAAwB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAa1F,OAAO,QAAQ,oBAAoB,CAAC;IAOlC,UAAU,aAAa;QACrB,qBAAqB,EAAE,YAAY,CAAC,OAAO,KAAK,CAAC,qBAAqB,CAAC,CAAA;KACxE;CACF;AAsPD;;;;;GAKG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAS/C;AAsED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;KAAE,CAAC,CAAA;IACrD,KAAK,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;KAAE,CAAC,CAAA;IACnD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CACnC;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,gBAAgB,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;IACvC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,aAAa,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,aAAa,CAAA;QACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,WAAW,CAAC,EAAE,WAAW,CAAA;KAC1B,CAAA;IACD;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;IAC5B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACtC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAC7C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACxC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,sEAAsE;IACtE,SAAS,CAAC,EAAE,sBAAsB,CAAA;CACnC;AAED,yDAAyD;AACzD,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;OAKG;IACH,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;CAC3C,CAAA;AAED,QAAA,MAAM,MAAM,sGAwQV,CAAA;AAyEF,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,SAAS,EAGd,KAAK,gBAAgB,EAKtB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAkB,KAAK,YAAY,EAAsB,MAAM,oBAAoB,CAAA;AAC1F,OAAO,EACL,KAAK,aAAa,EAOnB,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAKrC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACrE,OAAO,EAAuB,KAAK,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAI5F,OAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAA;AActE,OAAuB,EAAwB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAa1F,OAAO,QAAQ,oBAAoB,CAAC;IAOlC,UAAU,aAAa;QACrB,qBAAqB,EAAE,YAAY,CAAC,OAAO,KAAK,CAAC,qBAAqB,CAAC,CAAA;KACxE;CACF;AAsPD;;;;;GAKG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAS/C;AAsED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;KAAE,CAAC,CAAA;IACrD,KAAK,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;KAAE,CAAC,CAAA;IACnD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CACnC;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,gBAAgB,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;IACvC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,aAAa,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,aAAa,CAAA;QACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,WAAW,CAAC,EAAE,WAAW,CAAA;KAC1B,CAAA;IACD,6FAA6F;IAC7F,YAAY,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACtC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;IAC5B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACtC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAC7C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACxC;;;;OAIG;IACH,YAAY,CAAC,EAAE,uBAAuB,CAAA;IACtC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,sEAAsE;IACtE,SAAS,CAAC,EAAE,sBAAsB,CAAA;CACnC;AAED,yDAAyD;AACzD,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;OAKG;IACH,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;CAC3C,CAAA;AAED,QAAA,MAAM,MAAM,sGA2RV,CAAA;eAyEa,MAAM"}
@@ -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 { 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';
@@ -164,16 +164,16 @@ function GPUDeviceWatcher({ intentionalWebGL = false }) {
164
164
  return null;
165
165
  }
166
166
  function ToneMappingExposure() {
167
- const sceneTheme = useViewer((state) => state.sceneTheme);
167
+ const appearance = useViewer((state) => state.sceneAppearance);
168
168
  const atmosphere = useSceneAtmosphere();
169
169
  const gl = useThree((state) => state.gl);
170
170
  const invalidate = useThree((state) => state.invalidate);
171
171
  useEffect(() => {
172
172
  if (atmosphere)
173
173
  return;
174
- gl.toneMappingExposure = getSceneTheme(sceneTheme).toneMappingExposure;
174
+ gl.toneMappingExposure = appearance.toneMappingExposure;
175
175
  invalidate();
176
- }, [atmosphere, gl, invalidate, sceneTheme]);
176
+ }, [atmosphere, gl, invalidate, appearance]);
177
177
  useFrame(() => {
178
178
  if (!atmosphere)
179
179
  return;
@@ -182,7 +182,7 @@ function ToneMappingExposure() {
182
182
  return null;
183
183
  }
184
184
  function ImmersiveXRBackground() {
185
- const background = useViewer((state) => getSceneTheme(state.sceneTheme).background);
185
+ const background = useViewer((state) => state.sceneAppearance.background);
186
186
  return _jsx("color", { args: [background], attach: "background" });
187
187
  }
188
188
  function isPendingSceneBuild(id, { nodes, rootNodeIds }) {
@@ -283,7 +283,7 @@ function SceneReadyTracker({ onSceneReadyChange, sceneReadyKey, sceneReadyMaxWai
283
283
  }, 10);
284
284
  return null;
285
285
  }
286
- const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVER_STYLES, selectionManager = 'default', perf = false, useBvh = true, renderContext = 'editor', transparent, defaultRender, isolate, sceneReadyKey, onSceneReadyChange, onRenderError, sceneReadyMaxWaitMs, maxFps = 50, disablePostFx = false, renderPaused = false, immersive, }, ref) {
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) {
287
287
  useEffect(() => {
288
288
  if (nodeRegistry.size === 0) {
289
289
  console.warn('[viewer] Node registry is empty. Install @pascal-app/nodes and call await loadPlugin(builtinPlugin) before mounting <Viewer>.');
@@ -306,9 +306,11 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
306
306
  clearIsolation();
307
307
  };
308
308
  }, [isolate]);
309
- const [pointerEvents] = useState(() => choosePointerEvents());
309
+ const onBreadcrumbRef = useRef(onBreadcrumb);
310
+ onBreadcrumbRef.current = onBreadcrumb;
311
+ const [pointerEvents] = useState(() => choosePointerEvents(undefined, (breadcrumb) => onBreadcrumbRef.current?.(breadcrumb)));
310
312
  const [rendererInitFailed, setRendererInitFailed] = useState(false);
311
- const isDark = useViewer((state) => getSceneTheme(state.sceneTheme).appearance === 'dark');
313
+ const isDark = useViewer((state) => state.sceneAppearance.appearance === 'dark');
312
314
  const sceneTheme = useViewer((state) => state.sceneTheme);
313
315
  const previousLampTheme = useRef(sceneTheme);
314
316
  useEffect(() => {
@@ -334,15 +336,28 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
334
336
  useViewer.getState().setTransparentBackground(false);
335
337
  };
336
338
  }, [transparent]);
339
+ const scenePresentation = useScene((state) => {
340
+ for (const id of state.rootNodeIds) {
341
+ const node = state.nodes[id];
342
+ if (node?.type === 'site')
343
+ return node.presentation;
344
+ }
345
+ return undefined;
346
+ });
347
+ const presentation = suppliedPresentation === undefined ? scenePresentation : (suppliedPresentation ?? undefined);
348
+ const projectId = useViewer((state) => state.projectId);
349
+ useLayoutEffect(() => {
350
+ // Project selection clears the previous look even when both graphs share a preset.
351
+ if (useViewer.getState().projectId === projectId)
352
+ useViewer.getState().setProjectPresentation(presentation);
353
+ }, [presentation, projectId]);
337
354
  const defaultShading = defaultRender?.shading;
338
355
  const defaultTextures = defaultRender?.textures;
339
356
  const defaultColorPreset = defaultRender?.colorPreset;
340
357
  const hasDefaultRender = defaultRender != null;
341
358
  useEffect(() => {
342
359
  const ctx = renderContext;
343
- useViewer.getState().setRenderContext(ctx);
344
- const { shading, shadingByContext, setShading } = useViewer.getState();
345
- setShading(shadingByContext[ctx] ?? defaultShading ?? shading);
360
+ useViewer.getState().setRenderContext(ctx, defaultShading);
346
361
  if (!hasDefaultRender || typeof window === 'undefined')
347
362
  return;
348
363
  let persistedState = {};
@@ -412,7 +427,8 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
412
427
  trackTimestamp: PERF_OVERLAY_ENABLED,
413
428
  });
414
429
  renderer.toneMapping = THREE.ACESFilmicToneMapping;
415
- renderer.toneMappingExposure = getSceneTheme(useViewer.getState().sceneTheme).toneMappingExposure;
430
+ renderer.toneMappingExposure =
431
+ useViewer.getState().sceneAppearance.toneMappingExposure;
416
432
  return renderer;
417
433
  },
418
434
  });
@@ -1 +1 @@
1
- {"version":3,"file":"lights.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/lights.tsx"],"names":[],"mappings":"AA8EA,wBAAgB,MAAM,gCAwQrB"}
1
+ {"version":3,"file":"lights.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/lights.tsx"],"names":[],"mappings":"AAmGA,wBAAgB,MAAM,gCAiVrB"}
@@ -1,13 +1,14 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { sceneRegistry } from '@pascal-app/core';
3
3
  import { useFrame } from '@react-three/fiber';
4
- import { useMemo, useRef } from 'react';
4
+ import { useEffect, useMemo, useRef } from 'react';
5
5
  import * as THREE from 'three/webgpu';
6
6
  import { getKeyLightDirectionOverride } from '../../lib/key-light-override';
7
7
  import { SHADOW_ONLY_LAYER } from '../../lib/layers';
8
- import { getSceneTheme } from '../../lib/scene-themes';
9
- import useViewer from '../../store/use-viewer';
8
+ import { registerSkyLights } from '../../lib/underground-ambiance';
9
+ import useViewer, { groundVeiled } from '../../store/use-viewer';
10
10
  import { useSceneAtmosphere } from './scene-atmosphere';
11
+ import { UndergroundAmbiance } from './underground-ambiance';
11
12
  // Diagnostic toggle: `?disable=shadows` skips the shadow-map render pass
12
13
  // (which doubles draw calls for every shadow-casting mesh) so you can
13
14
  // isolate how much of the baseline GPU cost is shadows vs. raw geometry.
@@ -59,10 +60,42 @@ const SHADOW_MARGIN = 3;
59
60
  const SHADOW_BACKOFF = 10;
60
61
  // Fallback radius when the scene has no building geometry yet (empty scene).
61
62
  const SHADOW_FALLBACK_RADIUS = 30;
63
+ /**
64
+ * The live counterpart of the interior capture's lighting: a light that shines from the eye along
65
+ * the view, casting no shadow. Over a veiled ground the floor below grade still lies in the
66
+ * shadow of the storeys above and has no sky: this keeps it from reading as a cave. The
67
+ * underground ambiance owns its intensity (the veil's 1 at rest, brought up as the sky's light
68
+ * comes down when the eye dives, back to rest in a capture); the hemisphere's ground side is
69
+ * lifted in `Lights`.
70
+ */
71
+ function UndergroundFill({ lightRef }) {
72
+ const look = useMemo(() => new THREE.Vector3(), []);
73
+ useFrame(({ camera }) => {
74
+ const fill = lightRef.current;
75
+ if (!fill)
76
+ return;
77
+ camera.getWorldPosition(fill.position);
78
+ fill.target.position.copy(fill.position).add(camera.getWorldDirection(look));
79
+ fill.target.updateMatrixWorld();
80
+ });
81
+ return _jsx("directionalLight", { intensity: 0, ref: lightRef });
82
+ }
62
83
  export function Lights() {
63
- const sceneTheme = useViewer((state) => state.sceneTheme);
64
- const theme = getSceneTheme(sceneTheme);
84
+ const theme = useViewer((state) => state.sceneAppearance);
65
85
  const shadows = useViewer((state) => state.shadows);
86
+ const veiled = useViewer(groundVeiled);
87
+ // The eye's fill is mounted once, and stays: adding or taking away a light changes every lit
88
+ // material's shader (a runtime compile that lagged the switch to a basement), so it is there
89
+ // from the moment the scene has a level below grade or the eye may dive (or a view first needs
90
+ // it) and only its intensity, the ambiance's, moves.
91
+ const wantsFill = useViewer((state) => state.hasLevelBelowGrade ||
92
+ state.diveAvailable ||
93
+ groundVeiled(state) ||
94
+ state.ambianceActive);
95
+ const fillMounted = useRef(false);
96
+ if (wantsFill)
97
+ fillMounted.current = true;
98
+ const filled = fillMounted.current;
66
99
  const atmosphere = useSceneAtmosphere();
67
100
  const lightSlots = useMemo(() => Array.from({ length: atmosphere ? 2 : theme.lights.length }, (_, index) => index), [atmosphere, theme.lights.length]);
68
101
  const lightRefs = useRef([]);
@@ -79,6 +112,17 @@ export function Lights() {
79
112
  const shadowHelpers = useRef([]);
80
113
  const hemiRef = useRef(null);
81
114
  const ambientRef = useRef(null);
115
+ const fillRef = useRef(null);
116
+ // What the eye's fill shines at with no ambiance: the veil's own 1 over a veiled ground.
117
+ const fillRest = useRef(0);
118
+ fillRest.current = veiled ? 1 : 0;
119
+ // The underground ambiance moves the sky's own light and the eye's fill for the frame it draws.
120
+ useEffect(() => registerSkyLights(() => ({
121
+ ambient: ambientRef.current,
122
+ hemisphere: hemiRef.current,
123
+ fill: fillRef.current,
124
+ fillRest: fillRest.current,
125
+ })), []);
82
126
  const initialized = useRef(false);
83
127
  const lightTargets = useRef([]);
84
128
  const targets = useMemo(() => ({
@@ -89,6 +133,8 @@ export function Lights() {
89
133
  useFrame((state, delta) => {
90
134
  // Clamp delta to avoid huge jumps on tab switch.
91
135
  const dt = Math.min(delta, 0.1) * 4;
136
+ const sourceShadow = atmosphere ? undefined : theme.lights[0]?.shadow;
137
+ const sourceCamera = sourceShadow?.camera;
92
138
  // Atmosphere directions are stable mutable vectors. Keep both light
93
139
  // resources mounted and move them imperatively so time/angle changes never
94
140
  // rebuild materials or shadow resources.
@@ -103,12 +149,23 @@ export function Lights() {
103
149
  light.target.updateMatrixWorld();
104
150
  }
105
151
  }
152
+ else {
153
+ for (const index of lightSlots) {
154
+ const light = lightRefs.current[index];
155
+ const config = theme.lights[index];
156
+ if (!light || !config || (index === 0 && shadows && !sourceCamera))
157
+ continue;
158
+ light.position.set(...config.position);
159
+ light.target.position.set(...(config.target ?? [0, 0, 0]));
160
+ light.target.updateMatrixWorld();
161
+ }
162
+ }
106
163
  // Fit the single key-light shadow frustum to the BUILDING geometry rather
107
164
  // than the camera. The source controls its direction; only its distance and
108
165
  // frustum extents are derived here.
109
166
  if (shadows) {
110
167
  const now = state.clock.elapsedTime;
111
- if (now - lastBoundsTime.current >= BOUNDS_REFRESH_INTERVAL) {
168
+ if (!sourceCamera && now - lastBoundsTime.current >= BOUNDS_REFRESH_INTERVAL) {
112
169
  lastBoundsTime.current = now;
113
170
  const box = boundsBox.current.makeEmpty();
114
171
  for (const [id, obj] of sceneRegistry.nodes) {
@@ -138,10 +195,12 @@ export function Lights() {
138
195
  const castsShadow = atmosphere ? true : Boolean(themeKey?.castShadow);
139
196
  if (light && castsShadow) {
140
197
  const focus = shadowFocus.current;
141
- const size = shadowRadius.current * SHADOW_MARGIN_SCALE + SHADOW_MARGIN;
198
+ const size = shadowRadius.current * SHADOW_MARGIN_SCALE +
199
+ Math.min(SHADOW_MARGIN, shadowRadius.current * 0.25);
142
200
  const distance = size + SHADOW_BACKOFF;
143
201
  const near = SHADOW_BACKOFF;
144
- const far = distance + size;
202
+ // Receivers can lie beyond the caster's bounds, especially under a low sun.
203
+ const far = distance + shadowRadius.current * SHADOW_MARGIN_SCALE + SHADOW_MARGIN;
145
204
  const directionOverride = getKeyLightDirectionOverride();
146
205
  if (directionOverride) {
147
206
  shadowDir.current.set(...directionOverride);
@@ -151,6 +210,12 @@ export function Lights() {
151
210
  }
152
211
  else if (themeKey) {
153
212
  shadowDir.current.set(...themeKey.position);
213
+ if (themeKey.target) {
214
+ const [x, y, z] = themeKey.target;
215
+ shadowDir.current.x -= x;
216
+ shadowDir.current.y -= y;
217
+ shadowDir.current.z -= z;
218
+ }
154
219
  }
155
220
  else {
156
221
  shadowDir.current.set(0, 1, 0);
@@ -158,18 +223,38 @@ export function Lights() {
158
223
  if (shadowDir.current.lengthSq() === 0)
159
224
  shadowDir.current.set(0, 1, 0);
160
225
  shadowDir.current.normalize().multiplyScalar(distance);
161
- light.position.copy(focus).add(shadowDir.current);
162
- light.target.position.copy(focus);
163
- light.target.updateMatrixWorld();
226
+ if (!sourceCamera) {
227
+ light.position.copy(focus).add(shadowDir.current);
228
+ light.target.position.copy(focus);
229
+ light.target.updateMatrixWorld();
230
+ }
231
+ else if (directionOverride && themeKey) {
232
+ const [x, y, z] = themeKey.position;
233
+ const [tx, ty, tz] = themeKey.target ?? [0, 0, 0];
234
+ shadowDir.current.normalize().multiplyScalar(Math.hypot(x - tx, y - ty, z - tz) || 1);
235
+ light.position.set(tx, ty, tz).add(shadowDir.current);
236
+ }
164
237
  const cam = light.shadow?.camera;
165
238
  if (cam) {
239
+ // The calibrated building bias detaches furniture-scale contact shadows.
240
+ // Small scenes need finer shadow edges too; retain the building map budget.
241
+ const smallScene = !sourceCamera && shadowRadius.current < 1.5;
242
+ light.shadow.mapSize.setScalar(sourceShadow?.mapSize ?? (smallScene ? 2048 : 1024));
243
+ light.shadow.bias = sourceShadow?.bias ?? SHADOW_DEPTH_BIAS;
244
+ light.shadow.radius = sourceShadow?.radius ?? 2;
245
+ light.shadow.normalBias =
246
+ sourceShadow?.normalBias ??
247
+ (smallScene
248
+ ? Math.min(SHADOW_NORMAL_BIAS, (4 * size) / light.shadow.mapSize.x)
249
+ : SHADOW_NORMAL_BIAS);
166
250
  cam.layers.enable(SHADOW_ONLY_LAYER);
167
- cam.left = -size;
168
- cam.right = size;
169
- cam.top = size;
170
- cam.bottom = -size;
171
- cam.near = near;
172
- cam.far = far;
251
+ // A retained source frustum keeps distant context from diluting the building's shadows.
252
+ cam.left = sourceCamera?.left ?? -size;
253
+ cam.right = sourceCamera?.right ?? size;
254
+ cam.top = sourceCamera?.top ?? size;
255
+ cam.bottom = sourceCamera?.bottom ?? -size;
256
+ cam.near = sourceCamera?.near ?? near;
257
+ cam.far = sourceCamera?.far ?? far;
173
258
  cam.updateProjectionMatrix();
174
259
  if (SHADOW_CAMERA_DEBUG) {
175
260
  let helper = shadowHelpers.current[0];
@@ -215,7 +300,7 @@ export function Lights() {
215
300
  light.color.lerp(target, dt);
216
301
  }
217
302
  if (index === 0 && light.shadow?.intensity !== undefined) {
218
- const shadowIntensity = intensity <= 1 ? intensity : MAX_SHADOW_INTENSITY;
303
+ const shadowIntensity = sourceShadow?.intensity ?? (intensity <= 1 ? intensity : MAX_SHADOW_INTENSITY);
219
304
  light.shadow.intensity =
220
305
  atmosphere || !initialized.current
221
306
  ? shadowIntensity
@@ -224,7 +309,8 @@ export function Lights() {
224
309
  }
225
310
  const hemiIntensity = atmosphere ? atmosphere.hemisphereIntensity : theme.hemi?.intensity;
226
311
  const hemiSky = atmosphere ? atmosphere.skyColor : theme.hemi?.sky;
227
- const hemiGround = atmosphere ? atmosphere.groundColor : theme.hemi?.ground;
312
+ // Over a veiled ground the floor is lit from below as from above, as in an interior capture.
313
+ const hemiGround = veiled ? hemiSky : atmosphere ? atmosphere.groundColor : theme.hemi?.ground;
228
314
  if (hemiRef.current && hemiIntensity !== undefined && hemiSky && hemiGround) {
229
315
  if (atmosphere || !initialized.current) {
230
316
  hemiRef.current.intensity = hemiIntensity;
@@ -267,5 +353,5 @@ export function Lights() {
267
353
  : (themeLight?.position ?? [0, 1, 0]), ref: (light) => {
268
354
  lightRefs.current[index] = light;
269
355
  }, "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));
270
- }), atmosphere || theme.hemi ? _jsx("hemisphereLight", { ref: hemiRef }) : null, _jsx("ambientLight", { ref: ambientRef })] }));
356
+ }), atmosphere || theme.hemi ? _jsx("hemisphereLight", { ref: hemiRef }) : null, _jsx("ambientLight", { ref: ambientRef }), filled && _jsx(UndergroundFill, { lightRef: fillRef }), _jsx(UndergroundAmbiance, {})] }));
271
357
  }
@@ -1 +1 @@
1
- {"version":3,"file":"perf-panel.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/perf-panel.tsx"],"names":[],"mappings":"AA2GA,eAAO,MAAM,SAAS,0CA2MrB,CAAA;AAED,eAAe,SAAS,CAAA"}
1
+ {"version":3,"file":"perf-panel.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/perf-panel.tsx"],"names":[],"mappings":"AA2GA,eAAO,MAAM,SAAS,0CA2MrB,CAAA;eAEc,SAAS"}
@@ -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":"AA+CA,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"}