@pascal-app/viewer 1.0.0-beta.5 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/capture/asset-url.d.ts +2 -0
  4. package/dist/capture/asset-url.d.ts.map +1 -0
  5. package/dist/capture/asset-url.js +13 -0
  6. package/dist/capture/capture-runtime.d.ts +43 -0
  7. package/dist/capture/capture-runtime.d.ts.map +1 -0
  8. package/dist/capture/capture-runtime.js +198 -0
  9. package/dist/capture/frame.d.ts +4 -0
  10. package/dist/capture/frame.d.ts.map +1 -0
  11. package/dist/capture/frame.js +21 -0
  12. package/dist/capture/index.d.ts +12 -0
  13. package/dist/capture/index.d.ts.map +1 -0
  14. package/dist/capture/index.js +11 -0
  15. package/dist/capture/layer-visibility.d.ts +5 -0
  16. package/dist/capture/layer-visibility.d.ts.map +1 -0
  17. package/dist/capture/layer-visibility.js +11 -0
  18. package/dist/capture/layers/clay-matcap.d.ts +3 -0
  19. package/dist/capture/layers/clay-matcap.d.ts.map +1 -0
  20. package/dist/capture/layers/clay-matcap.js +26 -0
  21. package/dist/capture/layers/device-motion-layer.d.ts +7 -0
  22. package/dist/capture/layers/device-motion-layer.d.ts.map +1 -0
  23. package/dist/capture/layers/device-motion-layer.js +76 -0
  24. package/dist/capture/layers/point-cloud-layer.d.ts +15 -0
  25. package/dist/capture/layers/point-cloud-layer.d.ts.map +1 -0
  26. package/dist/capture/layers/point-cloud-layer.js +106 -0
  27. package/dist/capture/layers/room-model-layer.d.ts +9 -0
  28. package/dist/capture/layers/room-model-layer.d.ts.map +1 -0
  29. package/dist/capture/layers/room-model-layer.js +71 -0
  30. package/dist/capture/layers/surface-mesh-data.d.ts +9 -0
  31. package/dist/capture/layers/surface-mesh-data.d.ts.map +1 -0
  32. package/dist/capture/layers/surface-mesh-data.js +74 -0
  33. package/dist/capture/layers/surface-mesh-layer.d.ts +7 -0
  34. package/dist/capture/layers/surface-mesh-layer.d.ts.map +1 -0
  35. package/dist/capture/layers/surface-mesh-layer.js +16 -0
  36. package/dist/capture/preview.d.ts +3 -0
  37. package/dist/capture/preview.d.ts.map +1 -0
  38. package/dist/capture/preview.js +2 -0
  39. package/dist/capture/source-state.d.ts +22 -0
  40. package/dist/capture/source-state.d.ts.map +1 -0
  41. package/dist/capture/source-state.js +182 -0
  42. package/dist/capture/stream-rendering.d.ts +14 -0
  43. package/dist/capture/stream-rendering.d.ts.map +1 -0
  44. package/dist/capture/stream-rendering.js +70 -0
  45. package/dist/capture/trajectory.d.ts +20 -0
  46. package/dist/capture/trajectory.d.ts.map +1 -0
  47. package/dist/capture/trajectory.js +77 -0
  48. package/dist/capture/use-json-artifact.d.ts +2 -0
  49. package/dist/capture/use-json-artifact.d.ts.map +1 -0
  50. package/dist/capture/use-json-artifact.js +42 -0
  51. package/dist/components/viewer/batched-mesh-spike.d.ts +14 -0
  52. package/dist/components/viewer/batched-mesh-spike.d.ts.map +1 -0
  53. package/dist/components/viewer/batched-mesh-spike.js +64 -0
  54. package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
  55. package/dist/components/viewer/frame-limiter.js +4 -3
  56. package/dist/components/viewer/glb-scene.d.ts.map +1 -1
  57. package/dist/components/viewer/glb-scene.js +3 -1
  58. package/dist/components/viewer/index.d.ts.map +1 -1
  59. package/dist/components/viewer/index.js +70 -62
  60. package/dist/components/viewer/lights.d.ts.map +1 -1
  61. package/dist/components/viewer/lights.js +123 -89
  62. package/dist/components/viewer/perf-monitor.d.ts +6 -1
  63. package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
  64. package/dist/components/viewer/perf-monitor.js +307 -116
  65. package/dist/components/viewer/perf-panel.d.ts +3 -0
  66. package/dist/components/viewer/perf-panel.d.ts.map +1 -0
  67. package/dist/components/viewer/perf-panel.js +178 -0
  68. package/dist/components/viewer/pointer-raycast-layers.d.ts +15 -0
  69. package/dist/components/viewer/pointer-raycast-layers.d.ts.map +1 -0
  70. package/dist/components/viewer/pointer-raycast-layers.js +28 -0
  71. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  72. package/dist/components/viewer/post-processing.js +130 -83
  73. package/dist/components/viewer/registered-systems.d.ts +14 -5
  74. package/dist/components/viewer/registered-systems.d.ts.map +1 -1
  75. package/dist/components/viewer/registered-systems.js +22 -10
  76. package/dist/components/viewer/scene-atmosphere.d.ts +30 -0
  77. package/dist/components/viewer/scene-atmosphere.d.ts.map +1 -0
  78. package/dist/components/viewer/scene-atmosphere.js +89 -0
  79. package/dist/components/viewer/scene-environment.d.ts.map +1 -1
  80. package/dist/components/viewer/scene-environment.js +19 -5
  81. package/dist/components/viewer/scene-ground-replacement.d.ts +5 -0
  82. package/dist/components/viewer/scene-ground-replacement.d.ts.map +1 -0
  83. package/dist/components/viewer/scene-ground-replacement.js +35 -0
  84. package/dist/components/viewer/selection-manager.d.ts.map +1 -1
  85. package/dist/components/viewer/selection-manager.js +8 -16
  86. package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
  87. package/dist/components/viewer/viewer-camera.js +4 -1
  88. package/dist/components/viewer/viewer-presentations.d.ts +67 -0
  89. package/dist/components/viewer/viewer-presentations.d.ts.map +1 -0
  90. package/dist/components/viewer/viewer-presentations.js +120 -0
  91. package/dist/hooks/use-library-materials-version.d.ts +7 -0
  92. package/dist/hooks/use-library-materials-version.d.ts.map +1 -0
  93. package/dist/hooks/use-library-materials-version.js +10 -0
  94. package/dist/hooks/use-node-events.d.ts.map +1 -1
  95. package/dist/hooks/use-node-events.js +1 -0
  96. package/dist/index.d.ts +16 -7
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +16 -7
  99. package/dist/lib/csg-utils.d.ts +1 -0
  100. package/dist/lib/csg-utils.d.ts.map +1 -1
  101. package/dist/lib/csg-utils.js +6 -1
  102. package/dist/lib/gpu-perf.d.ts +0 -2
  103. package/dist/lib/gpu-perf.d.ts.map +1 -1
  104. package/dist/lib/gpu-perf.js +7 -21
  105. package/dist/lib/isolation.d.ts +14 -30
  106. package/dist/lib/isolation.d.ts.map +1 -1
  107. package/dist/lib/isolation.js +62 -66
  108. package/dist/lib/layer-pass.d.ts +28 -0
  109. package/dist/lib/layer-pass.d.ts.map +1 -0
  110. package/dist/lib/layer-pass.js +254 -0
  111. package/dist/lib/materials.d.ts +12 -0
  112. package/dist/lib/materials.d.ts.map +1 -1
  113. package/dist/lib/materials.js +52 -17
  114. package/dist/lib/merged-outline-node.d.ts +17 -8
  115. package/dist/lib/merged-outline-node.d.ts.map +1 -1
  116. package/dist/lib/merged-outline-node.js +194 -52
  117. package/dist/lib/perf-actions.d.ts +55 -0
  118. package/dist/lib/perf-actions.d.ts.map +1 -0
  119. package/dist/lib/perf-actions.js +211 -0
  120. package/dist/lib/perf-observers.d.ts +2 -0
  121. package/dist/lib/perf-observers.d.ts.map +1 -0
  122. package/dist/lib/perf-observers.js +17 -0
  123. package/dist/lib/perf-panel-store.d.ts +71 -0
  124. package/dist/lib/perf-panel-store.d.ts.map +1 -0
  125. package/dist/lib/perf-panel-store.js +29 -0
  126. package/dist/lib/perf-tracks.d.ts +43 -0
  127. package/dist/lib/perf-tracks.d.ts.map +1 -0
  128. package/dist/lib/perf-tracks.js +113 -0
  129. package/dist/lib/pointer-events.d.ts +7 -0
  130. package/dist/lib/pointer-events.d.ts.map +1 -0
  131. package/dist/lib/pointer-events.js +680 -0
  132. package/dist/lib/post-processing-resources.d.ts +12 -0
  133. package/dist/lib/post-processing-resources.d.ts.map +1 -0
  134. package/dist/lib/post-processing-resources.js +19 -0
  135. package/dist/lib/renderer-capability.d.ts.map +1 -1
  136. package/dist/lib/renderer-capability.js +4 -2
  137. package/dist/lib/scene-visibility.d.ts +2 -1
  138. package/dist/lib/scene-visibility.d.ts.map +1 -1
  139. package/dist/lib/scene-visibility.js +25 -2
  140. package/dist/lib/snapshot-pipeline.d.ts +3 -1
  141. package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
  142. package/dist/lib/snapshot-pipeline.js +32 -16
  143. package/dist/store/use-viewer.d.ts +5 -3
  144. package/dist/store/use-viewer.d.ts.map +1 -1
  145. package/dist/store/use-viewer.js +2 -0
  146. package/dist/systems/ceiling/ceiling-system.js +1 -1
  147. package/dist/systems/door/door-animation-system.d.ts.map +1 -1
  148. package/dist/systems/door/door-animation-system.js +6 -9
  149. package/dist/systems/door/door-system.d.ts.map +1 -1
  150. package/dist/systems/door/door-system.js +13 -2
  151. package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -1
  152. package/dist/systems/floor-elevation/floor-elevation-system.js +7 -3
  153. package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
  154. package/dist/systems/geometry/geometry-system.js +7 -2
  155. package/dist/systems/level/level-system.d.ts.map +1 -1
  156. package/dist/systems/level/level-system.js +1 -1
  157. package/dist/systems/level/level-utils.d.ts +9 -0
  158. package/dist/systems/level/level-utils.d.ts.map +1 -1
  159. package/dist/systems/level/level-utils.js +14 -0
  160. package/dist/systems/perf-action-settle/perf-action-settle-system.d.ts +8 -0
  161. package/dist/systems/perf-action-settle/perf-action-settle-system.d.ts.map +1 -0
  162. package/dist/systems/perf-action-settle/perf-action-settle-system.js +32 -0
  163. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  164. package/dist/systems/roof/roof-system.js +1196 -58
  165. package/dist/systems/scan/scan-system.js +6 -5
  166. package/dist/systems/slab/slab-system.d.ts.map +1 -1
  167. package/dist/systems/slab/slab-system.js +1 -2
  168. package/dist/systems/stair/stair-system.d.ts.map +1 -1
  169. package/dist/systems/stair/stair-system.js +9 -8
  170. package/dist/systems/surface-hole-geometry.d.ts +1 -1
  171. package/dist/systems/surface-hole-geometry.d.ts.map +1 -1
  172. package/dist/systems/surface-hole-geometry.js +1 -1
  173. package/dist/systems/wall/level-miter-cache.d.ts.map +1 -1
  174. package/dist/systems/wall/wall-build-lifecycle.d.ts +9 -0
  175. package/dist/systems/wall/wall-build-lifecycle.d.ts.map +1 -0
  176. package/dist/systems/wall/wall-build-lifecycle.js +74 -0
  177. package/dist/systems/wall/wall-cutout-cache.d.ts +57 -0
  178. package/dist/systems/wall/wall-cutout-cache.d.ts.map +1 -0
  179. package/dist/systems/wall/wall-cutout-cache.js +304 -0
  180. package/dist/systems/wall/wall-cutout.d.ts +12 -1
  181. package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
  182. package/dist/systems/wall/wall-cutout.js +24 -161
  183. package/dist/systems/wall/wall-material-variant.d.ts +31 -0
  184. package/dist/systems/wall/wall-material-variant.d.ts.map +1 -0
  185. package/dist/systems/wall/wall-material-variant.js +10 -0
  186. package/dist/systems/wall/wall-materials.d.ts +6 -0
  187. package/dist/systems/wall/wall-materials.d.ts.map +1 -1
  188. package/dist/systems/wall/wall-materials.js +29 -13
  189. package/dist/systems/wall/wall-placeholder-sweep.d.ts +50 -0
  190. package/dist/systems/wall/wall-placeholder-sweep.d.ts.map +1 -0
  191. package/dist/systems/wall/wall-placeholder-sweep.js +51 -0
  192. package/dist/systems/wall/wall-rebuild-notifications.d.ts +5 -0
  193. package/dist/systems/wall/wall-rebuild-notifications.d.ts.map +1 -0
  194. package/dist/systems/wall/wall-rebuild-notifications.js +23 -0
  195. package/dist/systems/wall/wall-system.d.ts +11 -4
  196. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  197. package/dist/systems/wall/wall-system.js +405 -153
  198. package/dist/systems/window/window-animation-system.d.ts.map +1 -1
  199. package/dist/systems/window/window-animation-system.js +9 -8
  200. package/dist/systems/window/window-system.d.ts +1 -0
  201. package/dist/systems/window/window-system.d.ts.map +1 -1
  202. package/dist/systems/window/window-system.js +16 -2
  203. package/dist/systems/zone/zone-system.d.ts.map +1 -1
  204. package/dist/systems/zone/zone-system.js +28 -2
  205. package/package.json +17 -4
  206. package/dist/lib/polygon-union.d.ts +0 -4
  207. package/dist/lib/polygon-union.d.ts.map +0 -1
  208. package/dist/lib/polygon-union.js +0 -289
@@ -0,0 +1,12 @@
1
+ import type { PassNode, RenderPipeline } from 'three/webgpu';
2
+ import type { LayerPassIndex } from './layer-pass';
3
+ export declare class PostProcessingResources {
4
+ layerIndex: LayerPassIndex | null;
5
+ readonly passes: PassNode[];
6
+ outline: {
7
+ dispose(): void;
8
+ } | null;
9
+ pipeline: RenderPipeline | null;
10
+ dispose(): void;
11
+ }
12
+ //# sourceMappingURL=post-processing-resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-processing-resources.d.ts","sourceRoot":"","sources":["../../src/lib/post-processing-resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAIlD,qBAAa,uBAAuB;IAClC,UAAU,EAAE,cAAc,GAAG,IAAI,CAAO;IACxC,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAK;IAChC,OAAO,EAAE;QAAE,OAAO,IAAI,IAAI,CAAA;KAAE,GAAG,IAAI,CAAO;IAC1C,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAO;IAEtC,OAAO;CAUR"}
@@ -0,0 +1,19 @@
1
+ // RenderPipeline.dispose() only releases its fullscreen material, so the owner
2
+ // must also release the passes and scene observers on failure and teardown.
3
+ export class PostProcessingResources {
4
+ layerIndex = null;
5
+ passes = [];
6
+ outline = null;
7
+ pipeline = null;
8
+ dispose() {
9
+ this.layerIndex?.dispose();
10
+ this.layerIndex = null;
11
+ for (const pass of this.passes)
12
+ pass.dispose();
13
+ this.passes.length = 0;
14
+ this.outline?.dispose();
15
+ this.outline = null;
16
+ this.pipeline?.dispose();
17
+ this.pipeline = null;
18
+ }
19
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"renderer-capability.d.ts","sourceRoot":"","sources":["../../src/lib/renderer-capability.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,UAAU,CAAC,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAA;CACzC,CAAA;AAED,oGAAoG;AACpG,MAAM,MAAM,uBAAuB,GAAG,kBAAkB,GAAG,WAAW,CAAA;AAEtE,KAAK,kBAAkB,GAAG;IACxB,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IAC3B,aAAa,CAAC,UAAU,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAC9E,CAAA;AAED,KAAK,WAAW,GAAG;IACjB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAA;CACtF,CAAA;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,OAAO,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAC3D;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACzC;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAA;AAE9C,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAED,KAAK,qBAAqB,GAAG;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CAC7B,CAAA;AAED,MAAM,MAAM,4BAA4B,CAAC,QAAQ,IAC7C;IAAE,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GACpE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAA;AAiD9C,wBAAsB,wBAAwB,CAAC,EAC7C,MAAwB,EACxB,GAAkB,EAClB,eAAe,EACf,eAAkD,GACnD,GAAE;IACD,MAAM,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAA;IACxC,GAAG,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IACxB,eAAe,CAAC,EAAE,uBAAuB,CAAA;IACzC,eAAe,CAAC,EAAE,MAAM,CAAA;CACpB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA2BnC;AAED,wBAAsB,qBAAqB,CAAC,QAAQ,SAAS,qBAAqB,EAAE,EAClF,cAAc,EACd,GAAG,EACH,eAAe,EACf,WAA6B,EAC7B,eAAkD,GACnD,EAAE;IACD,cAAc,EAAE,CAAC,UAAU,EAAE,yBAAyB,KAAK,QAAQ,CAAA;IACnE,GAAG,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IACxB,eAAe,CAAC,EAAE,uBAAuB,CAAA;IACzC,WAAW,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAA;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,GAAG,OAAO,CAAC,4BAA4B,CAAC,QAAQ,CAAC,CAAC,CAuClD"}
1
+ {"version":3,"file":"renderer-capability.d.ts","sourceRoot":"","sources":["../../src/lib/renderer-capability.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,UAAU,CAAC,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAA;CACzC,CAAA;AAED,oGAAoG;AACpG,MAAM,MAAM,uBAAuB,GAAG,kBAAkB,GAAG,WAAW,CAAA;AAEtE,KAAK,kBAAkB,GAAG;IACxB,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IAC3B,aAAa,CAAC,UAAU,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAC9E,CAAA;AAED,KAAK,WAAW,GAAG;IACjB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAA;CACtF,CAAA;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,OAAO,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAC3D;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACzC;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAA;AAE9C,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAED,KAAK,qBAAqB,GAAG;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CAC7B,CAAA;AAED,MAAM,MAAM,4BAA4B,CAAC,QAAQ,IAC7C;IAAE,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GACpE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAA;AAiD9C,wBAAsB,wBAAwB,CAAC,EAC7C,MAAwB,EACxB,GAAkB,EAClB,eAAe,EACf,eAAkD,GACnD,GAAE;IACD,MAAM,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAA;IACxC,GAAG,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IACxB,eAAe,CAAC,EAAE,uBAAuB,CAAA;IACzC,eAAe,CAAC,EAAE,MAAM,CAAA;CACpB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA2BnC;AAED,wBAAsB,qBAAqB,CAAC,QAAQ,SAAS,qBAAqB,EAAE,EAClF,cAAc,EACd,GAAG,EACH,eAAe,EACf,WAA6B,EAC7B,eAAkD,GACnD,EAAE;IACD,cAAc,EAAE,CAAC,UAAU,EAAE,yBAAyB,KAAK,QAAQ,CAAA;IACnE,GAAG,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IACxB,eAAe,CAAC,EAAE,uBAAuB,CAAA;IACzC,WAAW,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAA;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,GAAG,OAAO,CAAC,4BAA4B,CAAC,QAAQ,CAAC,CAAC,CAyClD"}
@@ -91,7 +91,9 @@ export async function initializeGpuRenderer({ createRenderer, gpu, powerPreferen
91
91
  }
92
92
  catch (error) {
93
93
  try {
94
- renderer?.dispose?.();
94
+ // r186 made dispose() async: let it finish before the device is released
95
+ // and the WebGL fallback starts on the same canvas.
96
+ await renderer?.dispose?.();
95
97
  }
96
98
  catch { }
97
99
  if (capability.backend !== 'webgpu')
@@ -105,7 +107,7 @@ export async function initializeGpuRenderer({ createRenderer, gpu, powerPreferen
105
107
  }
106
108
  catch (fallbackError) {
107
109
  try {
108
- renderer?.dispose?.();
110
+ await renderer?.dispose?.();
109
111
  }
110
112
  catch { }
111
113
  return { error: fallbackError, status: 'unsupported' };
@@ -6,9 +6,10 @@ import type { Object3D } from 'three';
6
6
  * - `shadow-only` — solo mode: out of the color passes, still casting shadows.
7
7
  * - `batched` — a level's merged wall mesh draws this wall now.
8
8
  */
9
- export type HiddenReason = 'isolated' | 'shadow-only' | 'batched';
9
+ export type HiddenReason = 'isolated' | 'shadow-only' | 'batched' | 'wall-batched';
10
10
  /** Holds `obj` off the scene layer for `reason`. Idempotent per reason. */
11
11
  export declare function hideFromScene(obj: Object3D, reason: HiddenReason): void;
12
12
  /** Drops `reason`, restoring the mask `obj` had before the first one arrived. */
13
13
  export declare function showInScene(obj: Object3D, reason: HiddenReason): void;
14
+ export declare function temporarilyShowShadowOnly(root: Object3D): () => void;
14
15
  //# sourceMappingURL=scene-visibility.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scene-visibility.d.ts","sourceRoot":"","sources":["../../src/lib/scene-visibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAGrC;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,aAAa,GAAG,SAAS,CAAA;AAmBjE,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAMvE;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAarE"}
1
+ {"version":3,"file":"scene-visibility.d.ts","sourceRoot":"","sources":["../../src/lib/scene-visibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAGrC;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,aAAa,GAAG,SAAS,GAAG,cAAc,CAAA;AAmBlF,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAMvE;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAarE;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,IAAI,CAgBpE"}
@@ -33,16 +33,39 @@ export function showInScene(obj, reason) {
33
33
  obj.layers.mask = hold.original;
34
34
  delete holder[HOLD];
35
35
  }
36
+ export function temporarilyShowShadowOnly(root) {
37
+ const masks = new Map();
38
+ root.traverse((obj) => {
39
+ const hold = obj[HOLD];
40
+ if (!hold?.reasons.has('shadow-only'))
41
+ return;
42
+ masks.set(obj, obj.layers.mask);
43
+ const reasons = new Set(hold.reasons);
44
+ reasons.delete('shadow-only');
45
+ // A capture needs the original scene geometry, while editor overlays and
46
+ // objects hidden by isolation or batching must retain their own masks.
47
+ if (reasons.size === 0)
48
+ obj.layers.mask = hold.original;
49
+ else
50
+ applyHold(obj, { original: hold.original, reasons });
51
+ });
52
+ return () => {
53
+ for (const [obj, mask] of masks)
54
+ obj.layers.mask = mask;
55
+ };
56
+ }
36
57
  function applyHold(obj, hold) {
37
58
  obj.layers.mask = hold.original;
38
59
  obj.layers.disable(SCENE_LAYER);
39
60
  // A batched wall is both drawn and shadowed by the merged mesh, so it stays
40
61
  // out of the shadow pass too — enabling the shadow-only bit would submit its
41
62
  // triangles a second time, on top of the copy the batch already casts.
42
- if (hold.reasons.has('batched')) {
63
+ if (hold.reasons.has('isolated'))
64
+ obj.layers.disable(SHADOW_ONLY_LAYER);
65
+ if (hold.reasons.has('batched') || hold.reasons.has('wall-batched')) {
43
66
  obj.layers.enable(BATCHED_LAYER);
44
67
  return;
45
68
  }
46
- if (hold.reasons.has('shadow-only'))
69
+ if (!hold.reasons.has('isolated') && hold.reasons.has('shadow-only'))
47
70
  obj.layers.enable(SHADOW_ONLY_LAYER);
48
71
  }
@@ -1,5 +1,6 @@
1
1
  import { type Camera, type Scene } from 'three';
2
2
  import { type WebGPURenderer } from 'three/webgpu';
3
+ import type { SceneAtmosphereSource } from '../components/viewer/scene-atmosphere';
3
4
  import { type EdgeMode } from './edge-style';
4
5
  export declare const THUMBNAIL_WIDTH = 1920;
5
6
  export declare const THUMBNAIL_HEIGHT = 1080;
@@ -43,9 +44,10 @@ export type SnapshotPipeline = {
43
44
  }) => Promise<SnapshotCaptureResult>;
44
45
  dispose: () => void;
45
46
  };
46
- export declare function createSnapshotPipeline({ renderer, scene, camera, }: {
47
+ export declare function createSnapshotPipeline({ renderer, scene, camera, atmosphere, }: {
47
48
  renderer: WebGPURenderer;
48
49
  scene: Scene;
49
50
  camera: Camera;
51
+ atmosphere?: SceneAtmosphereSource | null;
50
52
  }): Promise<SnapshotPipeline | null>;
51
53
  //# sourceMappingURL=snapshot-pipeline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"snapshot-pipeline.d.ts","sourceRoot":"","sources":["../../src/lib/snapshot-pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAkB,KAAK,KAAK,EAAoB,MAAM,OAAO,CAAA;AAqBjF,OAAO,EAAgC,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAGhF,OAAO,EAAE,KAAK,QAAQ,EAAqC,MAAM,cAAc,CAAA;AAK/E,eAAO,MAAM,eAAe,OAAO,CAAA;AACnC,eAAO,MAAM,gBAAgB,OAAO,CAAA;AAEpC;;;;;GAKG;AACH,eAAO,MAAM,aAAa,eAAe,CAAA;AACzC,eAAO,MAAM,gBAAgB,MAAM,CAAA;AAEnC,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAUrC,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAA;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,IAAI,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,gBAAgB,EAAE,CAAC,EACjB,KAAK,EACL,WAAW,EACX,KAAK,EACL,KAAK,EACL,MAAM,GACP,EAAE;QACD,KAAK,EAAE,MAAM,CAAA;QACb,WAAW,EAAE,OAAO,CAAA;QACpB,KAAK,EAAE,OAAO,CAAA;QACd,KAAK,EAAE,QAAQ,CAAA;QACf,MAAM,EAAE,MAAM,CAAA;KACf,KAAK,IAAI,CAAA;IACV,OAAO,EAAE,CAAC,EACR,WAAW,EACX,UAAU,EACV,YAAY,GACb,EAAE;QACD,WAAW,CAAC,EAAE,mBAAmB,CAAA;QACjC,UAAU,CAAC,EAAE,kBAAkB,CAAA;QAC/B,YAAY,CAAC,EAAE,YAAY,CAAA;KAC5B,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACpC,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED,wBAAsB,sBAAsB,CAAC,EAC3C,QAAQ,EACR,KAAK,EACL,MAAM,GACP,EAAE;IACD,QAAQ,EAAE,cAAc,CAAA;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAwSnC"}
1
+ {"version":3,"file":"snapshot-pipeline.d.ts","sourceRoot":"","sources":["../../src/lib/snapshot-pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAkB,KAAK,KAAK,EAAoB,MAAM,OAAO,CAAA;AAoBjF,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAA;AAErB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AAElF,OAAO,EAAE,KAAK,QAAQ,EAAqC,MAAM,cAAc,CAAA;AAK/E,eAAO,MAAM,eAAe,OAAO,CAAA;AACnC,eAAO,MAAM,gBAAgB,OAAO,CAAA;AAEpC;;;;;GAKG;AACH,eAAO,MAAM,aAAa,eAAe,CAAA;AACzC,eAAO,MAAM,gBAAgB,MAAM,CAAA;AAEnC,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAUrC,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAA;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,IAAI,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,gBAAgB,EAAE,CAAC,EACjB,KAAK,EACL,WAAW,EACX,KAAK,EACL,KAAK,EACL,MAAM,GACP,EAAE;QACD,KAAK,EAAE,MAAM,CAAA;QACb,WAAW,EAAE,OAAO,CAAA;QACpB,KAAK,EAAE,OAAO,CAAA;QACd,KAAK,EAAE,QAAQ,CAAA;QACf,MAAM,EAAE,MAAM,CAAA;KACf,KAAK,IAAI,CAAA;IACV,OAAO,EAAE,CAAC,EACR,WAAW,EACX,UAAU,EACV,YAAY,GACb,EAAE;QACD,WAAW,CAAC,EAAE,mBAAmB,CAAA;QACjC,UAAU,CAAC,EAAE,kBAAkB,CAAA;QAC/B,YAAY,CAAC,EAAE,YAAY,CAAA;KAC5B,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACpC,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAgBD,wBAAsB,sBAAsB,CAAC,EAC3C,QAAQ,EACR,KAAK,EACL,MAAM,EACN,UAAiB,GAClB,EAAE;IACD,QAAQ,EAAE,cAAc,CAAA;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAA;CAC1C,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA0SnC"}
@@ -2,8 +2,8 @@ import { Color, Matrix4, UnsignedByteType } from 'three';
2
2
  import { ssgi } from 'three/addons/tsl/display/SSGINode.js';
3
3
  import { denoise } from 'three/examples/jsm/tsl/display/DenoiseNode.js';
4
4
  import { fxaa } from 'three/examples/jsm/tsl/display/FXAANode.js';
5
- import { convertToTexture, diffuseColor, float, mix, mrt, normalView, output, pass, sample, saturation, screenUV, smoothstep, uniform, vec3, vec4, } from 'three/tsl';
6
- import { RenderPipeline, RenderTarget } from 'three/webgpu';
5
+ import { convertToTexture, diffuseColor, float, mix, mrt, normalView, output, sample, saturation, screenUV, smoothstep, uniform, vec3, vec4, } from 'three/tsl';
6
+ import { PassNode, RenderPipeline, RenderTarget, } from 'three/webgpu';
7
7
  import { GRADE_PARAMS, SSGI_PARAMS } from '../components/viewer/post-processing';
8
8
  import { backdropGradient, deepSkyColor, horizonHazeColor } from './backdrop';
9
9
  import { edgeColorFor, edgeOpacityScaleFor } from './edge-style';
@@ -29,7 +29,22 @@ function clampSnapshotSize(width, height) {
29
29
  const scale = SNAPSHOT_MAX_EDGE / maxEdge;
30
30
  return { w: Math.round(width * scale), h: Math.round(height * scale) };
31
31
  }
32
- export async function createSnapshotPipeline({ renderer, scene, camera, }) {
32
+ class SnapshotScenePass extends PassNode {
33
+ updateBefore(frame) {
34
+ const renderer = frame.renderer;
35
+ const clearAlpha = renderer.getClearAlpha();
36
+ // RTTNode resets clear alpha in r186. The geometry mask must be cleared
37
+ // inside this pass, not inherited from the outer snapshot render.
38
+ renderer.setClearAlpha(0);
39
+ try {
40
+ return super.updateBefore(frame);
41
+ }
42
+ finally {
43
+ renderer.setClearAlpha(clearAlpha);
44
+ }
45
+ }
46
+ }
47
+ export async function createSnapshotPipeline({ renderer, scene, camera, atmosphere = null, }) {
33
48
  try {
34
49
  if (renderer.init)
35
50
  await renderer.init();
@@ -49,10 +64,9 @@ export async function createSnapshotPipeline({ renderer, scene, camera, }) {
49
64
  const inkColorUniform = uniform(new Color('#1a1d24'));
50
65
  const inkOpacityUniform = uniform(0.5);
51
66
  const inkOpacityScaleUniform = uniform(1);
52
- // pass() handles MRT internally for all material types, including custom
53
- // shaders — unlike renderer.setMRT() which crashes on non-NodeMaterials.
54
- // pass() also respects camera.layers, so caller-disabled objects are filtered.
55
- const scenePass = pass(scene, camera);
67
+ // The scene pass owns MRT and its transparent clear, including when nested
68
+ // inside FXAA's intermediate render target.
69
+ const scenePass = new SnapshotScenePass('color', scene, camera);
56
70
  scenePass.setMRT(mrt({
57
71
  output,
58
72
  diffuseColor,
@@ -111,13 +125,15 @@ export async function createSnapshotPipeline({ renderer, scene, camera, }) {
111
125
  const ndc = vec4(screenUV.x.mul(2).sub(1), float(1).sub(screenUV.y).mul(2).sub(1), 1, 1);
112
126
  const viewRay = bgProjInvUniform.mul(ndc);
113
127
  const worldDir = bgCamWorldUniform.mul(vec4(viewRay.xyz, 0)).xyz.normalize();
114
- const ungradedBgGradient = backdropGradient({
115
- dirY: worldDir.y,
116
- background: bgColorUniform,
117
- haze: bgHazeUniform,
118
- sky: bgSkyUniform,
119
- skyDeep: bgSkyDeepUniform,
120
- });
128
+ const ungradedBgGradient = atmosphere
129
+ ? atmosphere.skyRadiance(worldDir)
130
+ : backdropGradient({
131
+ dirY: worldDir.y,
132
+ background: bgColorUniform,
133
+ haze: bgHazeUniform,
134
+ sky: bgSkyUniform,
135
+ skyDeep: bgSkyDeepUniform,
136
+ });
121
137
  const bgGradient = mix(ungradedBgGradient, gradeRgb(ungradedBgGradient), gradeMixUniform);
122
138
  const alpha = scenePassColor.a;
123
139
  const finalOutput = vec4(mix(sceneRgb, mix(bgGradient, sceneRgb, alpha), bgMixUniform), mix(alpha, float(1), bgMixUniform));
@@ -159,8 +175,6 @@ export async function createSnapshotPipeline({ renderer, scene, camera, }) {
159
175
  renderTarget.setSize(captureWidth, captureHeight);
160
176
  }
161
177
  try {
162
- ;
163
- renderer.setClearAlpha(0);
164
178
  renderer.setRenderTarget(renderTarget);
165
179
  pipeline.render();
166
180
  }
@@ -268,6 +282,8 @@ export async function createSnapshotPipeline({ renderer, scene, camera, }) {
268
282
  dispose: () => {
269
283
  pipeline.dispose();
270
284
  renderTarget.dispose();
285
+ scenePass.dispose();
286
+ giPass.dispose();
271
287
  },
272
288
  };
273
289
  }
@@ -1,4 +1,4 @@
1
- import type { AnyNode, BaseNode, BuildingNode, LevelNode, ZoneNode } from '@pascal-app/core';
1
+ import type { AnyNode, BaseNode, BuildingNode, LevelNode, UnitNode, ZoneNode } from '@pascal-app/core';
2
2
  import type { Object3D } from 'three';
3
3
  import type { EdgeMode } from '../lib/edge-style';
4
4
  import type { ColorPreset, RenderShading } from '../lib/materials';
@@ -17,6 +17,8 @@ type Outliner = {
17
17
  };
18
18
  type ViewerState = {
19
19
  selection: SelectionPath;
20
+ focusedUnitId: UnitNode['id'] | null;
21
+ setFocusedUnit: (id: UnitNode['id'] | null) => void;
20
22
  previewSelectedIds: BaseNode['id'][];
21
23
  setPreviewSelectedIds: (ids: BaseNode['id'][]) => void;
22
24
  /** Host-owned selection highlights rendered through the viewer's native
@@ -102,8 +104,8 @@ type ViewerState = {
102
104
  * effects can re-apply to the freshly swapped meshes. */
103
105
  geometryRevision: number;
104
106
  bumpGeometryRevision: () => void;
105
- exportScene: ((format?: 'glb' | 'stl' | 'obj') => Promise<void>) | null;
106
- setExportScene: (fn: ((format?: 'glb' | 'stl' | 'obj') => Promise<void>) | null) => void;
107
+ exportScene: ((format?: 'glb' | 'usdz' | 'stl' | 'obj') => Promise<void>) | null;
108
+ setExportScene: (fn: ((format?: 'glb' | 'usdz' | 'stl' | 'obj') => Promise<void>) | null) => void;
107
109
  debugColors: boolean;
108
110
  setDebugColors: (enabled: boolean) => void;
109
111
  walkthroughMode: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"use-viewer.d.ts","sourceRoot":"","sources":["../../src/store/use-viewer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-viewer.d.ts","sourceRoot":"","sources":["../../src/store/use-viewer.ts"],"names":[],"mappings":"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"}
@@ -122,6 +122,8 @@ function normalizePersistedViewerState(value) {
122
122
  }
123
123
  const useViewer = create()(persist((set) => ({
124
124
  selection: { buildingId: null, levelId: null, zoneId: null, selectedIds: [] },
125
+ focusedUnitId: null,
126
+ setFocusedUnit: (focusedUnitId) => set({ focusedUnitId }),
125
127
  previewSelectedIds: [],
126
128
  setPreviewSelectedIds: (ids) => set({ previewSelectedIds: ids }),
127
129
  externalSelectedIds: [],
@@ -35,7 +35,7 @@ export const CeilingSystem = () => {
35
35
  }
36
36
  // If mesh not found, keep it dirty for next frame
37
37
  });
38
- });
38
+ }, 2);
39
39
  return null;
40
40
  };
41
41
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"door-animation-system.d.ts","sourceRoot":"","sources":["../../../src/systems/door/door-animation-system.tsx"],"names":[],"mappings":"AAYA,eAAO,MAAM,mBAAmB,YA8C/B,CAAA"}
1
+ {"version":3,"file":"door-animation-system.d.ts","sourceRoot":"","sources":["../../../src/systems/door/door-animation-system.tsx"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,YAkD/B,CAAA"}
@@ -1,13 +1,6 @@
1
1
  import { emitter, useInteractive, useScene } from '@pascal-app/core';
2
2
  import { useFrame } from '@react-three/fiber';
3
3
  const easeDoorAnimation = (value) => value * value * (3 - 2 * value);
4
- function markDoorDirty(doorId) {
5
- const scene = useScene.getState();
6
- const node = scene.nodes[doorId];
7
- scene.dirtyNodes.add(doorId);
8
- if (node?.parentId)
9
- scene.dirtyNodes.add(node.parentId);
10
- }
11
4
  export const DoorAnimationSystem = () => {
12
5
  useFrame(({ clock }) => {
13
6
  const interactive = useInteractive.getState();
@@ -30,19 +23,23 @@ export const DoorAnimationSystem = () => {
30
23
  }
31
24
  const progress = Math.min(1, (now - startedAt) / animation.durationMs);
32
25
  const value = animation.from + (animation.to - animation.from) * easeDoorAnimation(progress);
26
+ // No dirty mark per tick: DoorSystem rebuilds any door with an entry in
27
+ // `doorAnimations`, and a dirty mark is a one-shot work item, not a
28
+ // needs-frame signal — per-tick marks kept the scene from ever settling.
33
29
  interactive.setDoorOpenState(typedDoorId, { [animation.field]: value });
34
- markDoorDirty(typedDoorId);
35
30
  if (progress < 1)
36
31
  continue;
37
32
  interactive.cancelDoorAnimation(typedDoorId);
38
33
  if (animation.persist) {
39
34
  scene.updateNode(typedDoorId, { [animation.field]: animation.to });
40
35
  interactive.removeDoorOpenState(typedDoorId);
41
- markDoorDirty(typedDoorId);
42
36
  }
43
37
  else {
44
38
  interactive.setDoorOpenState(typedDoorId, { [animation.field]: animation.to });
45
39
  }
40
+ // One final mark so the settled pose gets a rebuild after the animation
41
+ // entry is gone (the persist branch's updateNode also marks, harmlessly).
42
+ scene.markDirty(typedDoorId);
46
43
  emitter.emit('door:animation-completed', {
47
44
  doorId: typedDoorId,
48
45
  field: animation.field,
@@ -1 +1 @@
1
- {"version":3,"file":"door-system.d.ts","sourceRoot":"","sources":["../../../src/systems/door/door-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAYd,MAAM,kBAAkB,CAAA;AAGzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA0D9B,eAAO,MAAM,UAAU,YA6GtB,CAAA;AAupCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,KAAK,CAAC,QAAQ,GAAG,SAAS,EAChC,KAAK,EAAE,MAAM,GACZ,OAAO,CA6GT;AAyuCD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC,IAAI,CAI/D"}
1
+ {"version":3,"file":"door-system.d.ts","sourceRoot":"","sources":["../../../src/systems/door/door-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAYd,MAAM,kBAAkB,CAAA;AAGzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA2D9B,eAAO,MAAM,UAAU,YAsHtB,CAAA;AAupCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,KAAK,CAAC,QAAQ,GAAG,SAAS,EAChC,KAAK,EAAE,MAAM,GACZ,OAAO,CA6GT;AAyuCD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC,IAAI,CAI/D"}
@@ -4,6 +4,7 @@ import { useEffect, useRef } from 'react';
4
4
  import * as THREE from 'three';
5
5
  import { applyWorldScaleBoxUVs } from '../../lib/box-uv';
6
6
  import { createDefaultMaterial, createSurfaceRoleMaterial, glassMaterial as defaultGlassMaterial, baseMaterial as getBaseMaterial, resolveMaterialRef, } from '../../lib/materials';
7
+ import { timeSpan } from '../../lib/perf-tracks';
7
8
  import useViewer from '../../store/use-viewer';
8
9
  import { getOpeningCutoutProxyDepth } from '../wall/opening-cutout-geometry';
9
10
  // Invisible material for root mesh — used as selection hitbox only
@@ -94,7 +95,11 @@ export const DoorSystem = () => {
94
95
  }
95
96
  }, [sceneMaterials]);
96
97
  useFrame(() => {
97
- if (dirtyNodes.size === 0)
98
+ // Doors mid-swing rebuild every tick via their `doorAnimations` entry —
99
+ // the tween is a needs-frame signal, not dirty-set work (the set must be
100
+ // able to reach zero while an animation runs).
101
+ const animatingDoorIds = Object.keys(useInteractive.getState().doorAnimations);
102
+ if (dirtyNodes.size === 0 && animatingDoorIds.length === 0)
98
103
  return;
99
104
  const frameJoineryMaterial = createSurfaceRoleMaterial('joinery', colorPreset);
100
105
  baseMaterial = textures ? getBaseMaterial(shading) : frameJoineryMaterial;
@@ -114,6 +119,10 @@ export const DoorSystem = () => {
114
119
  return;
115
120
  dirtyDoorIds.push(id);
116
121
  });
122
+ for (const id of animatingDoorIds) {
123
+ if (nodes[id]?.type === 'door' && !dirtyDoorIds.includes(id))
124
+ dirtyDoorIds.push(id);
125
+ }
117
126
  const useProgressiveDoorRebuilds = dirtyDoorIds.length > DOOR_PROGRESSIVE_DIRTY_THRESHOLD;
118
127
  const frameStartedAt = performance.now();
119
128
  let rebuiltDoorsThisFrame = 0;
@@ -137,7 +146,9 @@ export const DoorSystem = () => {
137
146
  // rebuild reflects the in-flight drag without zustand churn. When
138
147
  // no override is set this returns the scene node unchanged.
139
148
  const effectiveNode = getEffectiveNode(node);
140
- updateDoorMesh(effectiveNode, mesh);
149
+ timeSpan('door', () => updateDoorMesh(effectiveNode, mesh), {
150
+ properties: [['node', id]],
151
+ });
141
152
  clearDirty(id);
142
153
  rebuiltDoorsThisFrame += 1;
143
154
  // Rebuild the parent wall so its cutout reflects the updated door geometry
@@ -1 +1 @@
1
- {"version":3,"file":"floor-elevation-system.d.ts","sourceRoot":"","sources":["../../../src/systems/floor-elevation/floor-elevation-system.tsx"],"names":[],"mappings":"AAyCA;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,oBAAoB,YA6EhC,CAAA"}
1
+ {"version":3,"file":"floor-elevation-system.d.ts","sourceRoot":"","sources":["../../../src/systems/floor-elevation/floor-elevation-system.tsx"],"names":[],"mappings":"AAyCA;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,oBAAoB,YAiFhC,CAAA"}
@@ -64,6 +64,9 @@ export const FloorElevationSystem = () => {
64
64
  const position = effectiveNode.position;
65
65
  if (!position)
66
66
  return;
67
+ if (!(def.geometry || def.system) && dirtyNodes.has(id)) {
68
+ clearDirty(id);
69
+ }
67
70
  // `applies === false` means the kind opts OUT of floor stacking for this
68
71
  // node: its Y belongs to a host frame (a wall/ceiling-mounted item, a
69
72
  // cabinet module inside a run, a wall duct terminal). `getFloorPlacedElevation`
@@ -73,6 +76,10 @@ export const FloorElevationSystem = () => {
73
76
  // the host frame's own elevation.
74
77
  if (floorPlaced.applies && !floorPlaced.applies(effectiveNode))
75
78
  return;
79
+ // Hosted meshes inherit elevation from their parent (and possibly a surface group).
80
+ // Their live transform can be world-space, so it cannot replace the mesh's local Y.
81
+ if (!effectiveNode.parentId || nodes[effectiveNode.parentId]?.type !== 'level')
82
+ return;
76
83
  // This system is the single drag-time authority for floor-stack mesh Y:
77
84
  // tools publish base positions to live stores, renderers may
78
85
  // reconcile that base Y onto the group, then this presentation system
@@ -90,9 +97,6 @@ export const FloorElevationSystem = () => {
90
97
  maxElevation: liveTransform?.supportElevationCap,
91
98
  });
92
99
  mesh.position.y = visualPosition[1];
93
- if (!(def.geometry || def.system) && dirtyNodes.has(id)) {
94
- clearDirty(id);
95
- }
96
100
  };
97
101
  dirtyNodes.forEach((id) => {
98
102
  applyLift(id);
@@ -1 +1 @@
1
- {"version":3,"file":"geometry-system.d.ts","sourceRoot":"","sources":["../../../src/systems/geometry/geometry-system.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAa,KAAK,KAAK,EAA4B,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAA;AAStF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,cAAc,YA8L1B,CAAA;AA8ID,eAAe,cAAc,CAAA;AAE7B,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,KAAK,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAU7D;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAC3C,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,GACV,OAAO,CAKT"}
1
+ {"version":3,"file":"geometry-system.d.ts","sourceRoot":"","sources":["../../../src/systems/geometry/geometry-system.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAa,KAAK,KAAK,EAA4B,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAA;AAUtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,cAAc,YAuM1B,CAAA;AAiJD,eAAe,cAAc,CAAA;AAE7B,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,KAAK,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAU7D;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAC3C,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,GACV,OAAO,CAKT"}
@@ -5,6 +5,7 @@ import { useEffect, useRef } from 'react';
5
5
  import { FrontSide } from 'three';
6
6
  import { disposeObject3DResources } from '../../lib/dispose-object3d';
7
7
  import { createSurfaceRoleMaterial, } from '../../lib/materials';
8
+ import { timeSpan } from '../../lib/perf-tracks';
8
9
  import useViewer from '../../store/use-viewer';
9
10
  /**
10
11
  * Generic geometry system.
@@ -138,7 +139,7 @@ export const GeometrySystem = () => {
138
139
  siblings.push(node);
139
140
  }
140
141
  }
141
- levelDataByBatch.set(key, def.computeLevelData(siblings));
142
+ levelDataByBatch.set(key, timeSpan('geometry', () => def.computeLevelData(siblings), { name: 'geometry:levelData' }));
142
143
  }
143
144
  // Phase 3 — per-node rebuild. Each node receives its batch's
144
145
  // precomputed `levelData` in ctx.
@@ -180,7 +181,7 @@ export const GeometrySystem = () => {
180
181
  // The builder is typed against the kind's specific node — at the
181
182
  // generic system level we lose that refinement, so the cast lands
182
183
  // here. Builders are responsible for trusting their schema.
183
- const built = builder(effectiveNode, ctx, shading, textures, colorPreset, sceneTheme);
184
+ const built = timeSpan('geometry', () => builder(effectiveNode, ctx, shading, textures, colorPreset, sceneTheme), { name: `geometry:${node.type}`, properties: [['node', id]] });
184
185
  if (!textures && def.surfaceRole) {
185
186
  applyDefaultSurfaceRole(built, def.surfaceRole, colorPreset, sceneTheme);
186
187
  }
@@ -211,7 +212,11 @@ function liveChildOverrideKey(node) {
211
212
  return '';
212
213
  const overrides = useLiveNodeOverrides.getState().overrides;
213
214
  const entries = [];
215
+ const childTypes = nodeRegistry.get(node.type)?.geometryChildTypes;
216
+ const nodes = useScene.getState().nodes;
214
217
  for (const childId of childIds) {
218
+ if (childTypes && !childTypes.includes(nodes[childId]?.type ?? ''))
219
+ continue;
215
220
  const override = overrides.get(childId);
216
221
  if (override)
217
222
  entries.push([childId, override]);
@@ -1 +1 @@
1
- {"version":3,"file":"level-system.d.ts","sourceRoot":"","sources":["../../../src/systems/level/level-system.tsx"],"names":[],"mappings":"AAeA,eAAO,MAAM,WAAW,YA6DvB,CAAA"}
1
+ {"version":3,"file":"level-system.d.ts","sourceRoot":"","sources":["../../../src/systems/level/level-system.tsx"],"names":[],"mappings":"AAcA,eAAO,MAAM,WAAW,YA6DvB,CAAA"}
@@ -3,7 +3,7 @@ import { useFrame } from '@react-three/fiber';
3
3
  import { lerp } from 'three/src/math/MathUtils.js';
4
4
  import { applyShadowOnly, clearShadowOnly } from '../../lib/shadow-only';
5
5
  import useViewer from '../../store/use-viewer';
6
- const EXPLODED_GAP = 5;
6
+ import { EXPLODED_GAP } from './level-utils';
7
7
  // Levels currently in shadow-caster-only mode (solo hides them from the color
8
8
  // passes but keeps their sun shadows). Tracked so we can restore layer masks
9
9
  // exactly once on transition; apply re-runs every frame so meshes rebuilt
@@ -1,3 +1,12 @@
1
+ export declare const EXPLODED_GAP = 5;
2
+ /**
3
+ * The Y a level settles at under the given presentation mode — its stacked
4
+ * elevation plus the exploded gap. Analytic (scene store + mode), never a
5
+ * mesh read: a level created this frame has its Object3D at y=0 until
6
+ * LevelSystem lerps it, and a mode switch leaves meshes mid-lerp — camera
7
+ * code framing a level must aim at the destination, not the moving target.
8
+ */
9
+ export declare function getLevelPresentationY(levelId: string, nodes: Record<string, unknown>, levelMode: 'stacked' | 'exploded' | 'solo' | 'manual'): number;
1
10
  /**
2
11
  * Instantly snaps all level Objects3D to their true stacked Y positions
3
12
  * (ignores levelMode — always uses stacked, no exploded gap).
@@ -1 +1 @@
1
- {"version":3,"file":"level-utils.d.ts","sourceRoot":"","sources":["../../../src/systems/level/level-utils.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,IAAI,CAyCtD"}
1
+ {"version":3,"file":"level-utils.d.ts","sourceRoot":"","sources":["../../../src/systems/level/level-utils.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY,IAAI,CAAA;AAE7B;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GACpD,MAAM,CAKR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,IAAI,CAyCtD"}
@@ -1,4 +1,18 @@
1
1
  import { getLevelElevations, sceneRegistry, useScene } from '@pascal-app/core';
2
+ export const EXPLODED_GAP = 5;
3
+ /**
4
+ * The Y a level settles at under the given presentation mode — its stacked
5
+ * elevation plus the exploded gap. Analytic (scene store + mode), never a
6
+ * mesh read: a level created this frame has its Object3D at y=0 until
7
+ * LevelSystem lerps it, and a mode switch leaves meshes mid-lerp — camera
8
+ * code framing a level must aim at the destination, not the moving target.
9
+ */
10
+ export function getLevelPresentationY(levelId, nodes, levelMode) {
11
+ const level = nodes[levelId];
12
+ const baseY = getLevelElevations(nodes).get(levelId)?.baseY ?? 0;
13
+ const explodedExtra = levelMode === 'exploded' && level ? level.level * EXPLODED_GAP : 0;
14
+ return baseY + explodedExtra;
15
+ }
2
16
  /**
3
17
  * Instantly snaps all level Objects3D to their true stacked Y positions
4
18
  * (ignores levelMode — always uses stacked, no exploded gap).
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Feeds the action-cost ledger (lib/perf-actions.ts) the per-frame settle
3
+ * state: how much of the scene is still dirty and how many wall neighbour
4
+ * rebuilds the wall system still owes. Without `?perf` the inner component
5
+ * never mounts, so no useFrame subscriber is registered at all.
6
+ */
7
+ export declare const PerfActionSettleSystem: () => import("react").JSX.Element | null;
8
+ //# sourceMappingURL=perf-action-settle-system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perf-action-settle-system.d.ts","sourceRoot":"","sources":["../../../src/systems/perf-action-settle/perf-action-settle-system.tsx"],"names":[],"mappings":"AAuBA;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,0CAGlC,CAAA"}
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useScene } from '@pascal-app/core';
3
+ import { useFrame } from '@react-three/fiber';
4
+ import { PERF_OVERLAY_ENABLED } from '../../lib/gpu-perf';
5
+ import { notifyPerfActionFrame } from '../../lib/perf-actions';
6
+ import { getPendingWallRebuildCount } from '../wall/wall-system';
7
+ // Later than every other viewer system (the highest in the tree is 10) and
8
+ // later than the render call in post-processing (priority 1), so the counts
9
+ // reported are what the frame actually left behind.
10
+ const SETTLE_PRIORITY = 100;
11
+ const PerfActionSettleFrame = () => {
12
+ useFrame(() => {
13
+ // The raw set size, deliberately: the dirty lifecycle now guarantees marks
14
+ // are cleared when their node goes away (undo sweep) and never added for
15
+ // consumerless kinds (GuardedDirtySet), so any lingering mark is a leak
16
+ // that SHOULD fail settle instead of being filtered out here.
17
+ const { dirtyNodes } = useScene.getState();
18
+ notifyPerfActionFrame(dirtyNodes.size, getPendingWallRebuildCount());
19
+ }, SETTLE_PRIORITY);
20
+ return null;
21
+ };
22
+ /**
23
+ * Feeds the action-cost ledger (lib/perf-actions.ts) the per-frame settle
24
+ * state: how much of the scene is still dirty and how many wall neighbour
25
+ * rebuilds the wall system still owes. Without `?perf` the inner component
26
+ * never mounts, so no useFrame subscriber is registered at all.
27
+ */
28
+ export const PerfActionSettleSystem = () => {
29
+ if (!PERF_OVERLAY_ENABLED)
30
+ return null;
31
+ return _jsx(PerfActionSettleFrame, {});
32
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"roof-system.d.ts","sourceRoot":"","sources":["../../../src/systems/roof/roof-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAcZ,KAAK,eAAe,EAKrB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAY,KAAK,EAA0B,MAAM,eAAe,CAAA;AAwIvE,eAAO,MAAM,UAAU,YAuItB,CAAA;AAmXD;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE;IAC7B,KAAK,CAAC,iBAAiB;IACvB,KAAK,CAAC,iBAAiB;IACvB,KAAK,CAAC,iBAAiB;IACvB,KAAK,CAAC,iBAAiB;CAMxB,CAAA;AAID,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAEzC,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,KAAK,CAAA;IACf,QAAQ,EAAE,KAAK,CAAA;IACf,SAAS,EAAE,KAAK,CAAA;IAChB,UAAU,EAAE,KAAK,CAAA;IACjB,UAAU,EAAE,KAAK,CAAC,cAAc,GAAG,IAAI,CAAA;CACxC,CAAA;AA0FD,wBAAgB,yBAAyB,CACvC,kBAAkB,EAAE,MAAM,GAAG,SAAS,EACtC,YAAY,EAAE,KAAK,CAAC,QAAQ,EAAE,EAC9B,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,GACtC,MAAM,CAuBR;AAgUD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,KAAK,CAAC,cAAc,GAAG,IAAI,EACrC,OAAO,EAAE,eAAe,GACvB,KAAK,CAAC,cAAc,GAAG,IAAI,CAyB7B;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,eAAe,GAAG,mBAAmB,GAAG,IAAI,CA+SvF;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,eAAe,EACrB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,KAAK,CAAC,cAAc,CAsFtB;AAsLD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,eAAe,QA2ExF;AAijBD,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAA;IACpB,MAAM,EAAE,KAAK,CAAC,OAAO,CAAA;CACtB,CAAA;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,eAAe,EACxB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GACT,YAAY,CAqLd"}
1
+ {"version":3,"file":"roof-system.d.ts","sourceRoot":"","sources":["../../../src/systems/roof/roof-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAoBZ,KAAK,eAAe,EAQrB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAY,KAAK,EAA0B,MAAM,eAAe,CAAA;AAkMvE,eAAO,MAAM,UAAU,YAwItB,CAAA;AAgbD;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE;IAC7B,KAAK,CAAC,iBAAiB;IACvB,KAAK,CAAC,iBAAiB;IACvB,KAAK,CAAC,iBAAiB;IACvB,KAAK,CAAC,iBAAiB;CAMxB,CAAA;AAID,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAEzC,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,KAAK,CAAA;IACf,QAAQ,EAAE,KAAK,CAAA;IACf,SAAS,EAAE,KAAK,CAAA;IAChB,UAAU,EAAE,KAAK,CAAA;IACjB,UAAU,EAAE,KAAK,CAAC,cAAc,GAAG,IAAI,CAAA;CACxC,CAAA;AA0FD,wBAAgB,yBAAyB,CACvC,kBAAkB,EAAE,MAAM,GAAG,SAAS,EACtC,YAAY,EAAE,KAAK,CAAC,QAAQ,EAAE,EAC9B,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,GACtC,MAAM,CAuBR;AAoWD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,KAAK,CAAC,cAAc,GAAG,IAAI,EACrC,OAAO,EAAE,eAAe,GACvB,KAAK,CAAC,cAAc,GAAG,IAAI,CAyB7B;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,eAAe,GAAG,mBAAmB,GAAG,IAAI,CA8TvF;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,eAAe,EACrB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,KAAK,CAAC,cAAc,CA2GtB;AAuyCD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,eAAe,QA0ExF;AA+qBD,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAA;IACpB,MAAM,EAAE,KAAK,CAAC,OAAO,CAAA;CACtB,CAAA;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,eAAe,EACxB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GACT,YAAY,CAqLd"}