@pascal-app/viewer 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. package/dist/capture/capture-runtime.js +1 -1
  2. package/dist/components/error-boundary.d.ts.map +1 -1
  3. package/dist/components/renderers/node-renderer.d.ts +1 -1
  4. package/dist/components/renderers/node-renderer.d.ts.map +1 -1
  5. package/dist/components/renderers/node-renderer.js +12 -4
  6. package/dist/components/renderers/parametric-node-renderer.d.ts.map +1 -1
  7. package/dist/components/viewer/bvh-ecctrl.d.ts.map +1 -1
  8. package/dist/components/viewer/frame-limiter.d.ts +1 -0
  9. package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
  10. package/dist/components/viewer/frame-limiter.js +22 -3
  11. package/dist/components/viewer/glb-interactive.d.ts +25 -1
  12. package/dist/components/viewer/glb-interactive.d.ts.map +1 -1
  13. package/dist/components/viewer/glb-interactive.js +253 -86
  14. package/dist/components/viewer/glb-mechanisms.d.ts +10 -0
  15. package/dist/components/viewer/glb-mechanisms.d.ts.map +1 -0
  16. package/dist/components/viewer/glb-mechanisms.js +19 -0
  17. package/dist/components/viewer/glb-reference-nodes.js +1 -1
  18. package/dist/components/viewer/glb-replace-instances.js +1 -1
  19. package/dist/components/viewer/glb-scene.d.ts +45 -27
  20. package/dist/components/viewer/glb-scene.d.ts.map +1 -1
  21. package/dist/components/viewer/glb-scene.js +421 -508
  22. package/dist/components/viewer/glb-walkthrough-controller.d.ts +1 -1
  23. package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -1
  24. package/dist/components/viewer/glb-walkthrough-controller.js +13 -2
  25. package/dist/components/viewer/index.d.ts +24 -1
  26. package/dist/components/viewer/index.d.ts.map +1 -1
  27. package/dist/components/viewer/index.js +111 -37
  28. package/dist/components/viewer/lights.d.ts.map +1 -1
  29. package/dist/components/viewer/lights.js +113 -22
  30. package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
  31. package/dist/components/viewer/perf-monitor.js +6 -0
  32. package/dist/components/viewer/perf-panel.d.ts.map +1 -1
  33. package/dist/components/viewer/perf-panel.js +1 -1
  34. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  35. package/dist/components/viewer/post-processing.js +104 -36
  36. package/dist/components/viewer/registered-systems.d.ts.map +1 -1
  37. package/dist/components/viewer/registered-systems.js +17 -3
  38. package/dist/components/viewer/render-error.d.ts +18 -0
  39. package/dist/components/viewer/render-error.d.ts.map +1 -0
  40. package/dist/components/viewer/render-error.js +29 -0
  41. package/dist/components/viewer/scene-bvh.d.ts.map +1 -1
  42. package/dist/components/viewer/scene-bvh.js +1 -1
  43. package/dist/components/viewer/scene-environment.d.ts.map +1 -1
  44. package/dist/components/viewer/scene-environment.js +31 -11
  45. package/dist/components/viewer/scene-ground-replacement.d.ts +6 -0
  46. package/dist/components/viewer/scene-ground-replacement.d.ts.map +1 -1
  47. package/dist/components/viewer/scene-ground-replacement.js +15 -0
  48. package/dist/components/viewer/selection-manager.d.ts.map +1 -1
  49. package/dist/components/viewer/selection-manager.js +25 -7
  50. package/dist/components/viewer/underground-ambiance.d.ts +9 -0
  51. package/dist/components/viewer/underground-ambiance.d.ts.map +1 -0
  52. package/dist/components/viewer/underground-ambiance.js +105 -0
  53. package/dist/components/viewer/viewer-camera.d.ts +4 -0
  54. package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
  55. package/dist/components/viewer/viewer-camera.js +12 -2
  56. package/dist/components/viewer/viewer-presentations.d.ts.map +1 -1
  57. package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
  58. package/dist/hooks/use-gltf-ktx2.js +2 -0
  59. package/dist/hooks/use-node-events.d.ts.map +1 -1
  60. package/dist/index.d.ts +36 -16
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +34 -19
  63. package/dist/lib/asset-url.d.ts.map +1 -1
  64. package/dist/lib/asset-url.js +7 -1
  65. package/dist/lib/backdrop.d.ts +17 -0
  66. package/dist/lib/backdrop.d.ts.map +1 -1
  67. package/dist/lib/backdrop.js +18 -1
  68. package/dist/lib/construction-dust.d.ts +57 -0
  69. package/dist/lib/construction-dust.d.ts.map +1 -0
  70. package/dist/lib/construction-dust.js +187 -0
  71. package/dist/lib/csg-utils.js +1 -1
  72. package/dist/lib/display-state.d.ts +25 -0
  73. package/dist/lib/display-state.d.ts.map +1 -0
  74. package/dist/lib/display-state.js +1 -0
  75. package/dist/lib/foundation-materials.d.ts +26 -0
  76. package/dist/lib/foundation-materials.d.ts.map +1 -0
  77. package/dist/lib/foundation-materials.js +65 -0
  78. package/dist/lib/gltf-unlit.d.ts +10 -0
  79. package/dist/lib/gltf-unlit.d.ts.map +1 -0
  80. package/dist/lib/gltf-unlit.js +23 -0
  81. package/dist/lib/ground-window.d.ts +33 -0
  82. package/dist/lib/ground-window.d.ts.map +1 -0
  83. package/dist/lib/ground-window.js +114 -0
  84. package/dist/lib/hero-pose.d.ts +13 -3
  85. package/dist/lib/hero-pose.d.ts.map +1 -1
  86. package/dist/lib/hero-pose.js +72 -5
  87. package/dist/lib/ink-edges.d.ts +6 -3
  88. package/dist/lib/ink-edges.d.ts.map +1 -1
  89. package/dist/lib/ink-edges.js +17 -7
  90. package/dist/lib/key-light-override.d.ts +11 -0
  91. package/dist/lib/key-light-override.d.ts.map +1 -0
  92. package/dist/lib/key-light-override.js +14 -0
  93. package/dist/lib/ktx2-loader.d.ts +7 -0
  94. package/dist/lib/ktx2-loader.d.ts.map +1 -1
  95. package/dist/lib/ktx2-loader.js +35 -0
  96. package/dist/lib/layer-pass.d.ts.map +1 -1
  97. package/dist/lib/layers.d.ts +11 -7
  98. package/dist/lib/layers.d.ts.map +1 -1
  99. package/dist/lib/layers.js +16 -6
  100. package/dist/lib/live-frame-hold.d.ts +14 -0
  101. package/dist/lib/live-frame-hold.d.ts.map +1 -0
  102. package/dist/lib/live-frame-hold.js +28 -0
  103. package/dist/lib/materials.d.ts +19 -7
  104. package/dist/lib/materials.d.ts.map +1 -1
  105. package/dist/lib/materials.js +65 -9
  106. package/dist/lib/merged-outline-node.d.ts +5 -0
  107. package/dist/lib/merged-outline-node.d.ts.map +1 -1
  108. package/dist/lib/merged-outline-node.js +80 -2
  109. package/dist/lib/node-top-surface-height.d.ts +6 -0
  110. package/dist/lib/node-top-surface-height.d.ts.map +1 -0
  111. package/dist/lib/node-top-surface-height.js +74 -0
  112. package/dist/lib/perf-probe-state.d.ts +39 -0
  113. package/dist/lib/perf-probe-state.d.ts.map +1 -0
  114. package/dist/lib/perf-probe-state.js +17 -0
  115. package/dist/lib/pointer-events.d.ts +26 -2
  116. package/dist/lib/pointer-events.d.ts.map +1 -1
  117. package/dist/lib/pointer-events.js +99 -12
  118. package/dist/lib/post-processing-resources.d.ts.map +1 -1
  119. package/dist/lib/procedural-emission.d.ts +7 -0
  120. package/dist/lib/procedural-emission.d.ts.map +1 -0
  121. package/dist/lib/procedural-emission.js +54 -0
  122. package/dist/lib/reveal-candidates.d.ts +80 -0
  123. package/dist/lib/reveal-candidates.d.ts.map +1 -0
  124. package/dist/lib/reveal-candidates.js +524 -0
  125. package/dist/lib/reveal-ghost.d.ts +9 -0
  126. package/dist/lib/reveal-ghost.d.ts.map +1 -0
  127. package/dist/lib/reveal-ghost.js +62 -0
  128. package/dist/lib/reveal-pending.d.ts +12 -0
  129. package/dist/lib/reveal-pending.d.ts.map +1 -0
  130. package/dist/lib/reveal-pending.js +12 -0
  131. package/dist/lib/reveal-pose.d.ts +70 -0
  132. package/dist/lib/reveal-pose.d.ts.map +1 -0
  133. package/dist/lib/reveal-pose.js +248 -0
  134. package/dist/lib/reveal-schedule.d.ts +208 -0
  135. package/dist/lib/reveal-schedule.d.ts.map +1 -0
  136. package/dist/lib/reveal-schedule.js +410 -0
  137. package/dist/lib/reveal-texture-scale.d.ts +5 -0
  138. package/dist/lib/reveal-texture-scale.d.ts.map +1 -0
  139. package/dist/lib/reveal-texture-scale.js +113 -0
  140. package/dist/lib/reveal-windows.d.ts +23 -0
  141. package/dist/lib/reveal-windows.d.ts.map +1 -0
  142. package/dist/lib/reveal-windows.js +31 -0
  143. package/dist/lib/reveal-wipe.d.ts +71 -0
  144. package/dist/lib/reveal-wipe.d.ts.map +1 -0
  145. package/dist/lib/reveal-wipe.js +105 -0
  146. package/dist/lib/scene-pass-mrt.d.ts +12 -0
  147. package/dist/lib/scene-pass-mrt.d.ts.map +1 -0
  148. package/dist/lib/scene-pass-mrt.js +23 -0
  149. package/dist/lib/scene-support-height.d.ts +4 -0
  150. package/dist/lib/scene-support-height.d.ts.map +1 -0
  151. package/dist/lib/scene-support-height.js +34 -0
  152. package/dist/lib/scene-themes.d.ts +30 -8
  153. package/dist/lib/scene-themes.d.ts.map +1 -1
  154. package/dist/lib/scene-themes.js +36 -0
  155. package/dist/lib/scene-visibility.d.ts +17 -1
  156. package/dist/lib/scene-visibility.d.ts.map +1 -1
  157. package/dist/lib/scene-visibility.js +53 -3
  158. package/dist/lib/scripted-opening.d.ts +11 -0
  159. package/dist/lib/scripted-opening.d.ts.map +1 -0
  160. package/dist/lib/scripted-opening.js +20 -0
  161. package/dist/lib/site-surfaces.d.ts +32 -0
  162. package/dist/lib/site-surfaces.d.ts.map +1 -0
  163. package/dist/lib/site-surfaces.js +70 -0
  164. package/dist/lib/snapshot-pipeline.d.ts +34 -3
  165. package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
  166. package/dist/lib/snapshot-pipeline.js +247 -117
  167. package/dist/lib/terrain-perimeter-fill.d.ts.map +1 -1
  168. package/dist/lib/terrain-perimeter-fill.js +22 -14
  169. package/dist/lib/tsl-compat.d.ts +2 -2
  170. package/dist/lib/tsl-compat.d.ts.map +1 -1
  171. package/dist/lib/underground-ambiance.d.ts +168 -0
  172. package/dist/lib/underground-ambiance.d.ts.map +1 -0
  173. package/dist/lib/underground-ambiance.js +334 -0
  174. package/dist/lib/zone-geometry.d.ts +11 -0
  175. package/dist/lib/zone-geometry.d.ts.map +1 -0
  176. package/dist/lib/zone-geometry.js +46 -0
  177. package/dist/store/use-item-light-pool.d.ts +14 -10
  178. package/dist/store/use-item-light-pool.d.ts.map +1 -1
  179. package/dist/store/use-item-light-pool.js +52 -26
  180. package/dist/store/use-viewer.d.ts +194 -26
  181. package/dist/store/use-viewer.d.ts.map +1 -1
  182. package/dist/store/use-viewer.js +164 -21
  183. package/dist/systems/ceiling/ceiling-system.d.ts +15 -1
  184. package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
  185. package/dist/systems/ceiling/ceiling-system.js +88 -6
  186. package/dist/systems/construction-reveal/construction-dust.d.ts +16 -0
  187. package/dist/systems/construction-reveal/construction-dust.d.ts.map +1 -0
  188. package/dist/systems/construction-reveal/construction-dust.js +92 -0
  189. package/dist/systems/construction-reveal/construction-reveal.d.ts +276 -0
  190. package/dist/systems/construction-reveal/construction-reveal.d.ts.map +1 -0
  191. package/dist/systems/construction-reveal/construction-reveal.js +2383 -0
  192. package/dist/systems/construction-reveal/dust-material.d.ts +10 -0
  193. package/dist/systems/construction-reveal/dust-material.d.ts.map +1 -0
  194. package/dist/systems/construction-reveal/dust-material.js +17 -0
  195. package/dist/systems/construction-reveal/ghost-dress.d.ts +10 -0
  196. package/dist/systems/construction-reveal/ghost-dress.d.ts.map +1 -0
  197. package/dist/systems/construction-reveal/ghost-dress.js +24 -0
  198. package/dist/systems/door/door-system.d.ts.map +1 -1
  199. package/dist/systems/door/door-system.js +55 -17
  200. package/dist/systems/elevator/elevator-interaction-system.d.ts +7 -0
  201. package/dist/systems/elevator/elevator-interaction-system.d.ts.map +1 -1
  202. package/dist/systems/elevator/elevator-interaction-system.js +18 -1
  203. package/dist/systems/floor-elevation/floor-elevation-system.d.ts +3 -1
  204. package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -1
  205. package/dist/systems/floor-elevation/floor-elevation-system.js +33 -5
  206. package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
  207. package/dist/systems/geometry/geometry-system.js +71 -11
  208. package/dist/systems/interactive/control-widget.d.ts.map +1 -1
  209. package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
  210. package/dist/systems/interactive/interactive-system.js +52 -17
  211. package/dist/systems/interactive/procedural-controls.d.ts +13 -0
  212. package/dist/systems/interactive/procedural-controls.d.ts.map +1 -0
  213. package/dist/systems/interactive/procedural-controls.js +17 -0
  214. package/dist/systems/interactive/scripted-clips.d.ts +19 -0
  215. package/dist/systems/interactive/scripted-clips.d.ts.map +1 -0
  216. package/dist/systems/interactive/scripted-clips.js +134 -0
  217. package/dist/systems/item/item-system.d.ts.map +1 -1
  218. package/dist/systems/item/item-system.js +9 -3
  219. package/dist/systems/item/object-cut-invalidation.d.ts +3 -0
  220. package/dist/systems/item/object-cut-invalidation.d.ts.map +1 -0
  221. package/dist/systems/item/object-cut-invalidation.js +68 -0
  222. package/dist/systems/item-light/item-light-system.d.ts +1 -1
  223. package/dist/systems/item-light/item-light-system.d.ts.map +1 -1
  224. package/dist/systems/item-light/item-light-system.js +48 -53
  225. package/dist/systems/level/level-hold.d.ts +4 -0
  226. package/dist/systems/level/level-hold.d.ts.map +1 -0
  227. package/dist/systems/level/level-hold.js +14 -0
  228. package/dist/systems/level/level-system.d.ts.map +1 -1
  229. package/dist/systems/level/level-system.js +19 -6
  230. package/dist/systems/level/level-utils.d.ts +19 -6
  231. package/dist/systems/level/level-utils.d.ts.map +1 -1
  232. package/dist/systems/level/level-utils.js +68 -9
  233. package/dist/systems/level/shadow-only-levels.d.ts +9 -0
  234. package/dist/systems/level/shadow-only-levels.d.ts.map +1 -0
  235. package/dist/systems/level/shadow-only-levels.js +7 -0
  236. package/dist/systems/roof/__fixtures__/roof-plane-cases.d.ts +103 -0
  237. package/dist/systems/roof/__fixtures__/roof-plane-cases.d.ts.map +1 -0
  238. package/dist/systems/roof/__fixtures__/roof-plane-cases.js +317 -0
  239. package/dist/systems/roof/roof-materials.d.ts +16 -2
  240. package/dist/systems/roof/roof-materials.d.ts.map +1 -1
  241. package/dist/systems/roof/roof-materials.js +64 -31
  242. package/dist/systems/roof/roof-system.d.ts +21 -4
  243. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  244. package/dist/systems/roof/roof-system.js +374 -49
  245. package/dist/systems/slab/slab-system.d.ts +1 -1
  246. package/dist/systems/slab/slab-system.d.ts.map +1 -1
  247. package/dist/systems/slab/slab-system.js +49 -19
  248. package/dist/systems/stair/stair-system.d.ts.map +1 -1
  249. package/dist/systems/stair/stair-system.js +133 -354
  250. package/dist/systems/wall/wall-cutout-cache.d.ts +39 -3
  251. package/dist/systems/wall/wall-cutout-cache.d.ts.map +1 -1
  252. package/dist/systems/wall/wall-cutout-cache.js +141 -19
  253. package/dist/systems/wall/wall-cutout.d.ts +6 -0
  254. package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
  255. package/dist/systems/wall/wall-cutout.js +42 -28
  256. package/dist/systems/wall/wall-finish-data.d.ts +22 -0
  257. package/dist/systems/wall/wall-finish-data.d.ts.map +1 -0
  258. package/dist/systems/wall/wall-finish-data.js +17 -0
  259. package/dist/systems/wall/wall-material-variant.d.ts.map +1 -1
  260. package/dist/systems/wall/wall-materials.d.ts +9 -4
  261. package/dist/systems/wall/wall-materials.d.ts.map +1 -1
  262. package/dist/systems/wall/wall-materials.js +135 -153
  263. package/dist/systems/wall/wall-placeholder-sweep.d.ts.map +1 -1
  264. package/dist/systems/wall/wall-system.d.ts +33 -2
  265. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  266. package/dist/systems/wall/wall-system.js +621 -159
  267. package/dist/systems/window/corner-frame.d.ts +10 -0
  268. package/dist/systems/window/corner-frame.d.ts.map +1 -0
  269. package/dist/systems/window/corner-frame.js +17 -0
  270. package/dist/systems/window/window-system.d.ts +1 -1
  271. package/dist/systems/window/window-system.d.ts.map +1 -1
  272. package/dist/systems/window/window-system.js +71 -27
  273. package/package.json +10 -10
  274. package/dist/systems/fence/fence-system.d.ts +0 -22
  275. package/dist/systems/fence/fence-system.d.ts.map +0 -1
  276. package/dist/systems/fence/fence-system.js +0 -357
@@ -0,0 +1 @@
1
+ {"version":3,"file":"level-hold.d.ts","sourceRoot":"","sources":["../../../src/systems/level/level-hold.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,aAAa,YAAa,MAAM,KAAK,MAAM,SAEvD,CAAA;AAED,eAAO,MAAM,UAAU,YAAa,MAAM,KAAG,MAAM,GAAG,SAA+B,CAAA;AAErF,eAAO,MAAM,YAAY,YAAa,MAAM,SAE3C,CAAA"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Levels a construction reveal presents at a height of its own: the levels above a floor being taken
3
+ * apart stay where they stood until it has gone, then the reveal brings them down onto what is below,
4
+ * writing the height every frame. `LevelSystem` reads `heldLevelY` ahead of the stacked elevation, so a
5
+ * held level is neither lerped nor snapped. Presentation only: no scene write.
6
+ */
7
+ const heldY = new Map();
8
+ export const setHeldLevelY = (levelId, y) => {
9
+ heldY.set(levelId, y);
10
+ };
11
+ export const heldLevelY = (levelId) => heldY.get(levelId);
12
+ export const releaseLevel = (levelId) => {
13
+ heldY.delete(levelId);
14
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"level-system.d.ts","sourceRoot":"","sources":["../../../src/systems/level/level-system.tsx"],"names":[],"mappings":"AAcA,eAAO,MAAM,WAAW,YA6DvB,CAAA"}
1
+ {"version":3,"file":"level-system.d.ts","sourceRoot":"","sources":["../../../src/systems/level/level-system.tsx"],"names":[],"mappings":"AAWA,eAAO,MAAM,WAAW,YAyEvB,CAAA"}
@@ -3,17 +3,17 @@ 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
+ import { heldLevelY } from './level-hold';
6
7
  import { EXPLODED_GAP, resolveLevelVisibility } from './level-utils';
7
- // Levels currently in shadow-caster-only mode (solo hides them from the color
8
- // passes but keeps their sun shadows). Tracked so we can restore layer masks
9
- // exactly once on transition; apply re-runs every frame so meshes rebuilt
10
- // while hidden (theme/texture changes) get re-hidden.
11
- const shadowOnlyLevels = new WeakSet();
8
+ import { shadowOnlyLevels } from './shadow-only-levels';
9
+ const placed = new WeakSet();
12
10
  export const LevelSystem = () => {
13
11
  useFrame((_, delta) => {
14
12
  const nodes = useScene.getState().nodes;
15
13
  const levelMode = useViewer.getState().levelMode;
14
+ const hideAbove = useViewer.getState().hideLevelsAboveSelection;
16
15
  const selectedLevel = useViewer.getState().selection.levelId;
16
+ const levelsRevealing = useViewer.getState().levelsRevealing;
17
17
  const levelElevations = getLevelElevations(nodes);
18
18
  const entries = [];
19
19
  sceneRegistry.byType.level.forEach((levelId) => {
@@ -27,6 +27,10 @@ export const LevelSystem = () => {
27
27
  });
28
28
  }
29
29
  });
30
+ // A level that has just mounted (a restored floor, a new storey) cuts every level to its height
31
+ // together: sliding them from where they were would run the floor and the levels above through
32
+ // each other.
33
+ const appeared = entries.some(({ obj }) => !placed.has(obj));
30
34
  const selectedIndex = selectedLevel
31
35
  ? entries.find((e) => e.levelId === selectedLevel)?.index
32
36
  : undefined;
@@ -41,14 +45,23 @@ export const LevelSystem = () => {
41
45
  // oscillated kilometers off-screen and the level-fit camera followed
42
46
  // (blank viewport). Clamping keeps every step a contraction: identical
43
47
  // feel at 60 fps, exact snap instead of overshoot on slow frames.
44
- obj.position.y = lerp(obj.position.y, targetY, Math.min(1, delta * 12));
48
+ const held = heldLevelY(levelId);
49
+ if (held !== undefined)
50
+ obj.position.y = held;
51
+ else if (appeared)
52
+ obj.position.y = targetY;
53
+ else
54
+ obj.position.y = lerp(obj.position.y, targetY, Math.min(1, delta * 12));
55
+ placed.add(obj);
45
56
  const { visible, shadowOnly } = resolveLevelVisibility({
46
57
  levelMode,
58
+ hideAbove,
47
59
  hasSelectedLevel: Boolean(selectedLevel),
48
60
  isSelected: level?.id === selectedLevel,
49
61
  index,
50
62
  selectedIndex,
51
63
  nodeVisible: level?.visible !== false,
64
+ revealing: levelsRevealing.includes(levelId),
52
65
  });
53
66
  if (shadowOnly) {
54
67
  applyShadowOnly(obj);
@@ -1,4 +1,5 @@
1
- export declare const EXPLODED_GAP = 5;
1
+ import { type SceneViewPresentation } from '@pascal-app/core/agent-operations';
2
+ export { EXPLODED_GAP } from '@pascal-app/core';
2
3
  /**
3
4
  * The Y a level settles at under the given presentation mode — its stacked
4
5
  * elevation plus the exploded gap. Analytic (scene store + mode), never a
@@ -12,19 +13,27 @@ export declare function getLevelPresentationY(levelId: string, nodes: Record<str
12
13
  * shadow-caster only.
13
14
  *
14
15
  * Two unrelated things hide a level and they do not compose: the author's own
15
- * `visible` flag (the sidebar eye), which hides the floor outright, and solo
16
- * mode, which hides every level but the soloed one — keeping the levels ABOVE
17
- * it in the shadow map so the sun still shadows the soloed floor through them.
16
+ * `visible` flag (the sidebar eye), which hides the floor outright, and
17
+ * presentation hiding — solo mode hides every level but the soloed one, and
18
+ * the editor's level display (`hideAbove`) hides the levels above the
19
+ * selected one. Presentation-hidden levels ABOVE the selected one stay in the
20
+ * shadow map so the sun still shadows the selected floor through them.
18
21
  * A level the author hid never enters that shadow-caster branch: its shadows
19
22
  * on the floor below would be exactly what hiding it was meant to remove.
23
+ *
24
+ * A level a construction reveal is playing on (`revealing`) shows whatever the
25
+ * presentation hides, so the animation is seen; only the author's own hiding
26
+ * keeps it out.
20
27
  */
21
- export declare function resolveLevelVisibility({ levelMode, hasSelectedLevel, isSelected, index, selectedIndex, nodeVisible, }: {
28
+ export declare function resolveLevelVisibility({ levelMode, hideAbove, hasSelectedLevel, isSelected, index, selectedIndex, nodeVisible, revealing, }: {
22
29
  levelMode: 'stacked' | 'exploded' | 'solo' | 'manual';
30
+ hideAbove: boolean;
23
31
  hasSelectedLevel: boolean;
24
32
  isSelected: boolean;
25
33
  index: number;
26
34
  selectedIndex: number | undefined;
27
35
  nodeVisible: boolean;
36
+ revealing: boolean;
28
37
  }): {
29
38
  visible: boolean;
30
39
  shadowOnly: boolean;
@@ -43,5 +52,9 @@ export declare function resolveLevelVisibility({ levelMode, hasSelectedLevel, is
43
52
  * renderer.render(scene, camera)
44
53
  * restore()
45
54
  */
46
- export declare function snapLevelsToTruePositions(): () => void;
55
+ export declare function snapLevelsToTruePositions({ readOnly, }?: {
56
+ readOnly?: boolean;
57
+ }): () => void;
58
+ /** The viewer's settled level presentation for one render, without changing saved preferences. */
59
+ export declare function presentLevelsForCapture(presentation: SceneViewPresentation): () => void;
47
60
  //# sourceMappingURL=level-utils.d.ts.map
@@ -1 +1 @@
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;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,KAAK,EACL,aAAa,EACb,WAAW,GACZ,EAAE;IACD,SAAS,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAA;IACrD,gBAAgB,EAAE,OAAO,CAAA;IACzB,UAAU,EAAE,OAAO,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,WAAW,EAAE,OAAO,CAAA;CACrB,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAM5C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,IAAI,CA2CtD"}
1
+ {"version":3,"file":"level-utils.d.ts","sourceRoot":"","sources":["../../../src/systems/level/level-utils.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,mCAAmC,CAAA;AAS1C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE/C;;;;;;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;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,KAAK,EACL,aAAa,EACb,WAAW,EACX,SAAS,GACV,EAAE;IACD,SAAS,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAA;IACrD,SAAS,EAAE,OAAO,CAAA;IAClB,gBAAgB,EAAE,OAAO,CAAA;IACzB,UAAU,EAAE,OAAO,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,WAAW,EAAE,OAAO,CAAA;IACpB,SAAS,EAAE,OAAO,CAAA;CACnB,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAS5C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,EACxC,QAAgB,GACjB,GAAE;IACD,QAAQ,CAAC,EAAE,OAAO,CAAA;CACd,GAAG,MAAM,IAAI,CAiDlB;AAED,kGAAkG;AAClG,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,qBAAqB,GAAG,MAAM,IAAI,CAiCvF"}
@@ -1,5 +1,9 @@
1
- import { getLevelElevations, sceneRegistry, useScene } from '@pascal-app/core';
2
- export const EXPLODED_GAP = 5;
1
+ import { EXPLODED_GAP, getLevelElevations, sceneRegistry, useScene, } from '@pascal-app/core';
2
+ import { sceneViewPresentationLevel, } from '@pascal-app/core/agent-operations';
3
+ import { temporarilyHideFromScene, temporarilyShowPresentation, temporarilyShowShadowOnly, } from '../../lib/scene-visibility';
4
+ import { applyShadowOnly, clearShadowOnly } from '../../lib/shadow-only';
5
+ import { shadowOnlyLevels } from './shadow-only-levels';
6
+ export { EXPLODED_GAP } from '@pascal-app/core';
3
7
  /**
4
8
  * The Y a level settles at under the given presentation mode — its stacked
5
9
  * elevation plus the exploded gap. Analytic (scene store + mode), never a
@@ -18,16 +22,25 @@ export function getLevelPresentationY(levelId, nodes, levelMode) {
18
22
  * shadow-caster only.
19
23
  *
20
24
  * Two unrelated things hide a level and they do not compose: the author's own
21
- * `visible` flag (the sidebar eye), which hides the floor outright, and solo
22
- * mode, which hides every level but the soloed one — keeping the levels ABOVE
23
- * it in the shadow map so the sun still shadows the soloed floor through them.
25
+ * `visible` flag (the sidebar eye), which hides the floor outright, and
26
+ * presentation hiding — solo mode hides every level but the soloed one, and
27
+ * the editor's level display (`hideAbove`) hides the levels above the
28
+ * selected one. Presentation-hidden levels ABOVE the selected one stay in the
29
+ * shadow map so the sun still shadows the selected floor through them.
24
30
  * A level the author hid never enters that shadow-caster branch: its shadows
25
31
  * on the floor below would be exactly what hiding it was meant to remove.
32
+ *
33
+ * A level a construction reveal is playing on (`revealing`) shows whatever the
34
+ * presentation hides, so the animation is seen; only the author's own hiding
35
+ * keeps it out.
26
36
  */
27
- export function resolveLevelVisibility({ levelMode, hasSelectedLevel, isSelected, index, selectedIndex, nodeVisible, }) {
37
+ export function resolveLevelVisibility({ levelMode, hideAbove, hasSelectedLevel, isSelected, index, selectedIndex, nodeVisible, revealing, }) {
28
38
  if (!nodeVisible)
29
39
  return { visible: false, shadowOnly: false };
30
- const hidden = levelMode === 'solo' && hasSelectedLevel && !isSelected;
40
+ if (revealing)
41
+ return { visible: true, shadowOnly: false };
42
+ const hidden = (levelMode === 'solo' && hasSelectedLevel && !isSelected) ||
43
+ (hideAbove && selectedIndex !== undefined && index > selectedIndex);
31
44
  const shadowOnly = hidden && selectedIndex !== undefined && index > selectedIndex;
32
45
  return { visible: shadowOnly || !hidden, shadowOnly };
33
46
  }
@@ -45,7 +58,7 @@ export function resolveLevelVisibility({ levelMode, hasSelectedLevel, isSelected
45
58
  * renderer.render(scene, camera)
46
59
  * restore()
47
60
  */
48
- export function snapLevelsToTruePositions() {
61
+ export function snapLevelsToTruePositions({ readOnly = false, } = {}) {
49
62
  const nodes = useScene.getState().nodes;
50
63
  const entries = [];
51
64
  sceneRegistry.byType.level.forEach((levelId) => {
@@ -62,11 +75,17 @@ export function snapLevelsToTruePositions() {
62
75
  const levelElevations = getLevelElevations(nodes);
63
76
  // Snapshot current Y and visibility so we can restore them after the render
64
77
  const snapshot = new Map(entries.map(({ levelId, obj }) => [levelId, { y: obj.position.y, visible: obj.visible }]));
65
- // Snap to true stacked positions and undo presentation hiding
78
+ // Snap to true stacked positions and undo presentation hiding — including
79
+ // the levels kept shadow-caster-only above the selected level.
80
+ const shadowOnly = entries.filter(({ obj }) => shadowOnlyLevels.has(obj));
66
81
  for (const { levelId, obj, nodeVisible } of entries) {
67
82
  obj.position.y = levelElevations.get(levelId)?.baseY ?? 0;
68
83
  obj.visible = nodeVisible;
69
84
  }
85
+ const restoreMasks = readOnly ? shadowOnly.map(({ obj }) => temporarilyShowShadowOnly(obj)) : [];
86
+ if (!readOnly)
87
+ for (const { obj } of shadowOnly)
88
+ clearShadowOnly(obj);
70
89
  return () => {
71
90
  for (const { levelId, obj } of entries) {
72
91
  const saved = snapshot.get(levelId);
@@ -75,5 +94,45 @@ export function snapLevelsToTruePositions() {
75
94
  obj.visible = saved.visible;
76
95
  }
77
96
  }
97
+ if (readOnly)
98
+ for (const restore of restoreMasks.reverse())
99
+ restore();
100
+ else
101
+ for (const { obj } of shadowOnly)
102
+ applyShadowOnly(obj);
103
+ };
104
+ }
105
+ /** The viewer's settled level presentation for one render, without changing saved preferences. */
106
+ export function presentLevelsForCapture(presentation) {
107
+ const nodes = useScene.getState().nodes;
108
+ const selected = sceneViewPresentationLevel(nodes, presentation);
109
+ if (selected &&
110
+ (!sceneRegistry.nodes.has(selected.id) || !sceneRegistry.byType.level?.has(selected.id)))
111
+ throw new Error('The level to capture is not ready in this renderer. Try again.');
112
+ const restores = [snapLevelsToTruePositions({ readOnly: true })];
113
+ for (const levelId of sceneRegistry.byType.level ?? []) {
114
+ const obj = sceneRegistry.nodes.get(levelId);
115
+ const level = nodes[levelId];
116
+ if (!obj || level?.type !== 'level')
117
+ continue;
118
+ obj.position.y = getLevelPresentationY(levelId, nodes, presentation.mode);
119
+ const { visible, shadowOnly } = resolveLevelVisibility({
120
+ levelMode: presentation.mode,
121
+ hideAbove: false,
122
+ hasSelectedLevel: Boolean(selected),
123
+ isSelected: level.id === selected?.id,
124
+ index: level.level,
125
+ selectedIndex: selected?.type === 'level' ? selected.level : undefined,
126
+ nodeVisible: level.visible !== false,
127
+ revealing: false,
128
+ });
129
+ obj.visible = visible;
130
+ restores.push(level.id === selected?.id ? temporarilyShowPresentation(obj) : temporarilyShowShadowOnly(obj));
131
+ if (shadowOnly)
132
+ restores.push(temporarilyHideFromScene(obj, 'shadow-only'));
133
+ }
134
+ return () => {
135
+ for (const restore of restores.reverse())
136
+ restore();
78
137
  };
79
138
  }
@@ -0,0 +1,9 @@
1
+ import type { Object3D } from 'three';
2
+ /**
3
+ * Levels currently in shadow-caster-only mode (hidden above the selected level
4
+ * by solo or by the editor's level display). Tracked so layer masks are
5
+ * restored exactly once on transition, and so a full-building capture can
6
+ * show them for its one render.
7
+ */
8
+ export declare const shadowOnlyLevels: WeakSet<Object3D<import("three").Object3DEventMap>>;
9
+ //# sourceMappingURL=shadow-only-levels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow-only-levels.d.ts","sourceRoot":"","sources":["../../../src/systems/level/shadow-only-levels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAErC;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,qDAA0B,CAAA"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Levels currently in shadow-caster-only mode (hidden above the selected level
3
+ * by solo or by the editor's level display). Tracked so layer masks are
4
+ * restored exactly once on transition, and so a full-building capture can
5
+ * show them for its one render.
6
+ */
7
+ export const shadowOnlyLevels = new WeakSet();
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Every roof the hosted Architect plugin's `hip_roof_planes` and `gable_roof_planes` built, each
3
+ * beside the `roof_segment_add` call that covers it and the roof segment that call writes, so the
4
+ * two plane tools can retire into it (catalogue slice R). No stored thread called either tool, so
5
+ * the cases are what their contracts take (both ridge axes, a hip either way and square, the
6
+ * default, wide, flush and wider-than-the-eaves gable overhangs, a thickness, an eave on the plate,
7
+ * over it and on posts) and the plugin's own call (a hip at the walls' 2.6 m tops).
8
+ *
9
+ * The plane tools took the rectangle of the walls' outside faces, a rise per 12, the overhang past
10
+ * those faces in metres (a gable's ends their own), a thickness square to the slope (0.29 m by
11
+ * default) and an eave height that was the roof's SURFACE at the outside wall face. The segment
12
+ * takes the same rectangle (`rectAt: 'outside'`), the pitch, the overhangs and the thickness in
13
+ * any unit, and an eave that is the plate it bears on, its default the walls' tops; the walls'
14
+ * thickness, which it reads from the walls along those faces (6.5 in where none stand, a porch on
15
+ * posts), puts their centre lines inside the faces.
16
+ *
17
+ * A plane call whose roof stood on its walls, or over them, is the same roof as a segment: same
18
+ * outline, surface, ridge and thickness (`lift` 0).
19
+ *
20
+ * Not reproduced, on purpose (no stored call made either, so each is a call a model could make):
21
+ * - A plane call with its eave at the walls' tops, the plugin's own and the likeliest, sank its roof
22
+ * into them: its slab's underside stood `thickness / cos(pitch)` under the plate at the wall face.
23
+ * A segment is never sunk under the walls it sits on (`eave_under_walls`); the replacement leaves
24
+ * the eave out and the roof sits on them, the same outline, pitch and thickness, its surface
25
+ * `lift` higher. Those rows say so.
26
+ * - Planes over a storey with another over it stood inside that storey; a segment refuses that
27
+ * (`into_storey_above`). The hosted table checks the refusal.
28
+ * - The plane tools answered each plane's id, so one slope could be edited or painted on its own
29
+ * (`update_roof_plane`). A segment is one mass whose slopes change together; one slope on its own
30
+ * is `create_roof_plane`'s, which stays, and the retired tools' answer says so.
31
+ *
32
+ * The viewer runs the segments through the roof geometry against the planes' own geometry
33
+ * (`roof-plane-cases.test.ts`); the hosted plugin runs each replacement call through
34
+ * `roof_segment_add` and reads back the segment it wrote.
35
+ */
36
+ type Rect = [number, number, number, number];
37
+ /** The walls' thickness, a 2x6 wall finished: what `roof_segment_add` reads from them. */
38
+ export declare const ROOF_PLANE_WALL_THICKNESS: number;
39
+ /** The covering a segment lays over its deck, in the thickness the plane tools took whole. */
40
+ export declare const ROOF_PLANE_COVERING = 0.02;
41
+ export type RoofPlaneCall = {
42
+ tool: 'hip_roof_planes' | 'gable_roof_planes';
43
+ rect: Rect;
44
+ ridgeAxis?: 'x' | 'z';
45
+ /** Rise per 12. */
46
+ pitch: number;
47
+ /** The roof's surface at the outside wall face, metres above the storey's floor. */
48
+ eaveHeight: number;
49
+ overhang?: number;
50
+ gableOverhang?: number;
51
+ thickness?: number;
52
+ name?: string;
53
+ };
54
+ export type RoofSegmentAddCall = {
55
+ roofType: 'hip' | 'gable';
56
+ name: string;
57
+ rect: Rect;
58
+ rectAt: 'outside';
59
+ ridgeAxis: 'x' | 'z';
60
+ pitchTwelfths: number;
61
+ overhangIn: string;
62
+ gableOverhangIn?: string;
63
+ thicknessIn: string;
64
+ eaveHeight?: number;
65
+ };
66
+ /** The segment a replacement call writes, in its storey's plan and metres. */
67
+ export type ExpectedRoofSegment = {
68
+ roofType: 'hip' | 'gable';
69
+ name: string;
70
+ /** The centre of its wall centre-line rectangle. */
71
+ centre: [number, number];
72
+ /** Along its ridge axis and across it, at the wall centre lines. */
73
+ width: number;
74
+ depth: number;
75
+ rotation: number;
76
+ /** Degrees. */
77
+ pitch: number;
78
+ /** Along the slope, as the node stores it. */
79
+ overhang: number;
80
+ /** In plan past the gable-end walls' outside faces; none on a hip. */
81
+ gableOverhang?: number;
82
+ wallThickness: number;
83
+ deckThickness: number;
84
+ shingleThickness: number;
85
+ /** The plate it bears on, metres above the storey's floor. */
86
+ eave: number;
87
+ };
88
+ export type RoofPlaneCase = {
89
+ name: string;
90
+ /** The walls under the roof: their outside faces and how tall they stand (none: posts). */
91
+ walls: {
92
+ rect: Rect;
93
+ height: number;
94
+ } | null;
95
+ call: RoofPlaneCall;
96
+ replacement: RoofSegmentAddCall;
97
+ segment: ExpectedRoofSegment;
98
+ /** How far the segment's surface stands over the planes' (0: the same roof). */
99
+ lift: number;
100
+ };
101
+ export declare const ROOF_PLANE_CASES: readonly RoofPlaneCase[];
102
+ export {};
103
+ //# sourceMappingURL=roof-plane-cases.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roof-plane-cases.d.ts","sourceRoot":"","sources":["../../../../src/systems/roof/__fixtures__/roof-plane-cases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAG5C,0FAA0F;AAC1F,eAAO,MAAM,yBAAyB,QAAW,CAAA;AACjD,8FAA8F;AAC9F,eAAO,MAAM,mBAAmB,OAAO,CAAA;AAMvC,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,iBAAiB,GAAG,mBAAmB,CAAA;IAC7C,IAAI,EAAE,IAAI,CAAA;IACV,SAAS,CAAC,EAAE,GAAG,GAAG,GAAG,CAAA;IACrB,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,KAAK,GAAG,OAAO,CAAA;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,EAAE,SAAS,CAAA;IACjB,SAAS,EAAE,GAAG,GAAG,GAAG,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,8EAA8E;AAC9E,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,KAAK,GAAG,OAAO,CAAA;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,oDAAoD;IACpD,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxB,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe;IACf,KAAK,EAAE,MAAM,CAAA;IACb,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,gBAAgB,EAAE,MAAM,CAAA;IACxB,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,2FAA2F;IAC3F,KAAK,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC5C,IAAI,EAAE,aAAa,CAAA;IACnB,WAAW,EAAE,kBAAkB,CAAA;IAC/B,OAAO,EAAE,mBAAmB,CAAA;IAC5B,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AA0ED,eAAO,MAAM,gBAAgB,EAAE,SAAS,aAAa,EAsRpD,CAAA"}