@ifc-lite/viewer 1.17.3 → 1.17.6

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 (530) hide show
  1. package/.turbo/turbo-build.log +39 -30
  2. package/.turbo/turbo-typecheck.log +1 -1
  3. package/CHANGELOG.md +132 -0
  4. package/DESKTOP_CONTRACT_VERSION +1 -0
  5. package/dist/assets/arrow-CZ5kQ26f.js +20 -0
  6. package/dist/assets/basketViewActivator-86rgogji.js +1 -0
  7. package/dist/assets/{bcf-D5-QWGO9.js → bcf-DOG9_WPX.js} +1 -1
  8. package/dist/assets/{browser-CKs-FY1P.js → browser-C5TFR7sH.js} +1 -1
  9. package/dist/assets/cesium-ADbP7waU.css +1 -0
  10. package/dist/assets/cesium-DUOzBlqv.js +17817 -0
  11. package/dist/assets/drawing-2d-DoxKMqbO.js +257 -0
  12. package/dist/assets/{exporters-C_6J153K.js → exporters-CcPS9MK5.js} +2898 -2380
  13. package/dist/assets/geometry.worker-BFUYA08u.js +1 -0
  14. package/dist/assets/ids-DQ5jY0E8.js +1 -0
  15. package/dist/assets/ifc-lite_bg-BINvzoCP.wasm +0 -0
  16. package/dist/assets/{index-jhBr1wbn.js → index-Bfms9I4A.js} +41036 -34613
  17. package/dist/assets/index-_bfZsDCC.css +1 -0
  18. package/dist/assets/{maplibre-gl-BpvwNKKy.js → maplibre-gl-CGLcoNXc.js} +1 -1
  19. package/dist/assets/native-bridge-DUyLCMZS.js +429 -0
  20. package/dist/assets/{sandbox-B79eavQ3.js → sandbox-C8575tul.js} +4342 -4324
  21. package/dist/assets/{server-client-D3bUPJJc.js → server-client-BuZK7OST.js} +4 -4
  22. package/dist/assets/tauri-core-stub-D8Fa-u43.js +1 -0
  23. package/dist/assets/tauri-dialog-stub-r7Wksg7o.js +1 -0
  24. package/dist/assets/tauri-fs-stub-BdeRC7aK.js +1 -0
  25. package/dist/assets/wasm-bridge-JsqEGDV8.js +1 -0
  26. package/dist/assets/{zip-B-jFFAGa.js → zip-DBEtpeu6.js} +3 -3
  27. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_0.json +1 -0
  28. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_1.json +1 -0
  29. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_10.json +1 -0
  30. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_11.json +1 -0
  31. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_12.json +1 -0
  32. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_13.json +1 -0
  33. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_14.json +1 -0
  34. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_15.json +1 -0
  35. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_16.json +1 -0
  36. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_17.json +1 -0
  37. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_18.json +1 -0
  38. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_19.json +1 -0
  39. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_2.json +1 -0
  40. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_20.json +1 -0
  41. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_21.json +1 -0
  42. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_22.json +1 -0
  43. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_23.json +1 -0
  44. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_24.json +1 -0
  45. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_25.json +1 -0
  46. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_26.json +1 -0
  47. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_27.json +1 -0
  48. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_3.json +1 -0
  49. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_4.json +1 -0
  50. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_5.json +1 -0
  51. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_6.json +1 -0
  52. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_7.json +1 -0
  53. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_8.json +1 -0
  54. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_9.json +1 -0
  55. package/dist/cesium/Assets/Images/bing_maps_credit.png +0 -0
  56. package/dist/cesium/Assets/Images/cesium_credit.png +0 -0
  57. package/dist/cesium/Assets/Images/google_earth_credit.png +0 -0
  58. package/dist/cesium/Assets/Images/ion-credit.png +0 -0
  59. package/dist/cesium/Assets/Textures/LensFlare/DirtMask.jpg +0 -0
  60. package/dist/cesium/Assets/Textures/LensFlare/StarBurst.jpg +0 -0
  61. package/dist/cesium/Assets/Textures/NaturalEarthII/0/0/0.jpg +0 -0
  62. package/dist/cesium/Assets/Textures/NaturalEarthII/0/1/0.jpg +0 -0
  63. package/dist/cesium/Assets/Textures/NaturalEarthII/1/0/0.jpg +0 -0
  64. package/dist/cesium/Assets/Textures/NaturalEarthII/1/0/1.jpg +0 -0
  65. package/dist/cesium/Assets/Textures/NaturalEarthII/1/1/0.jpg +0 -0
  66. package/dist/cesium/Assets/Textures/NaturalEarthII/1/1/1.jpg +0 -0
  67. package/dist/cesium/Assets/Textures/NaturalEarthII/1/2/0.jpg +0 -0
  68. package/dist/cesium/Assets/Textures/NaturalEarthII/1/2/1.jpg +0 -0
  69. package/dist/cesium/Assets/Textures/NaturalEarthII/1/3/0.jpg +0 -0
  70. package/dist/cesium/Assets/Textures/NaturalEarthII/1/3/1.jpg +0 -0
  71. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/0.jpg +0 -0
  72. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/1.jpg +0 -0
  73. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/2.jpg +0 -0
  74. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/3.jpg +0 -0
  75. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/0.jpg +0 -0
  76. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/1.jpg +0 -0
  77. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/2.jpg +0 -0
  78. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/3.jpg +0 -0
  79. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/0.jpg +0 -0
  80. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/1.jpg +0 -0
  81. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/2.jpg +0 -0
  82. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/3.jpg +0 -0
  83. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/0.jpg +0 -0
  84. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/1.jpg +0 -0
  85. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/2.jpg +0 -0
  86. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/3.jpg +0 -0
  87. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/0.jpg +0 -0
  88. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/1.jpg +0 -0
  89. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/2.jpg +0 -0
  90. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/3.jpg +0 -0
  91. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/0.jpg +0 -0
  92. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/1.jpg +0 -0
  93. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/2.jpg +0 -0
  94. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/3.jpg +0 -0
  95. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/0.jpg +0 -0
  96. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/1.jpg +0 -0
  97. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/2.jpg +0 -0
  98. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/3.jpg +0 -0
  99. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/0.jpg +0 -0
  100. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/1.jpg +0 -0
  101. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/2.jpg +0 -0
  102. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/3.jpg +0 -0
  103. package/dist/cesium/Assets/Textures/NaturalEarthII/tilemapresource.xml +14 -0
  104. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_mx.jpg +0 -0
  105. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_my.jpg +0 -0
  106. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_mz.jpg +0 -0
  107. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_px.jpg +0 -0
  108. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_py.jpg +0 -0
  109. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_pz.jpg +0 -0
  110. package/dist/cesium/Assets/Textures/maki/airfield.png +0 -0
  111. package/dist/cesium/Assets/Textures/maki/airport.png +0 -0
  112. package/dist/cesium/Assets/Textures/maki/alcohol-shop.png +0 -0
  113. package/dist/cesium/Assets/Textures/maki/america-football.png +0 -0
  114. package/dist/cesium/Assets/Textures/maki/art-gallery.png +0 -0
  115. package/dist/cesium/Assets/Textures/maki/bakery.png +0 -0
  116. package/dist/cesium/Assets/Textures/maki/bank.png +0 -0
  117. package/dist/cesium/Assets/Textures/maki/bar.png +0 -0
  118. package/dist/cesium/Assets/Textures/maki/baseball.png +0 -0
  119. package/dist/cesium/Assets/Textures/maki/basketball.png +0 -0
  120. package/dist/cesium/Assets/Textures/maki/beer.png +0 -0
  121. package/dist/cesium/Assets/Textures/maki/bicycle.png +0 -0
  122. package/dist/cesium/Assets/Textures/maki/building.png +0 -0
  123. package/dist/cesium/Assets/Textures/maki/bus.png +0 -0
  124. package/dist/cesium/Assets/Textures/maki/cafe.png +0 -0
  125. package/dist/cesium/Assets/Textures/maki/camera.png +0 -0
  126. package/dist/cesium/Assets/Textures/maki/campsite.png +0 -0
  127. package/dist/cesium/Assets/Textures/maki/car.png +0 -0
  128. package/dist/cesium/Assets/Textures/maki/cemetery.png +0 -0
  129. package/dist/cesium/Assets/Textures/maki/cesium.png +0 -0
  130. package/dist/cesium/Assets/Textures/maki/chemist.png +0 -0
  131. package/dist/cesium/Assets/Textures/maki/cinema.png +0 -0
  132. package/dist/cesium/Assets/Textures/maki/circle-stroked.png +0 -0
  133. package/dist/cesium/Assets/Textures/maki/circle.png +0 -0
  134. package/dist/cesium/Assets/Textures/maki/city.png +0 -0
  135. package/dist/cesium/Assets/Textures/maki/clothing-store.png +0 -0
  136. package/dist/cesium/Assets/Textures/maki/college.png +0 -0
  137. package/dist/cesium/Assets/Textures/maki/commercial.png +0 -0
  138. package/dist/cesium/Assets/Textures/maki/cricket.png +0 -0
  139. package/dist/cesium/Assets/Textures/maki/cross.png +0 -0
  140. package/dist/cesium/Assets/Textures/maki/dam.png +0 -0
  141. package/dist/cesium/Assets/Textures/maki/danger.png +0 -0
  142. package/dist/cesium/Assets/Textures/maki/disability.png +0 -0
  143. package/dist/cesium/Assets/Textures/maki/dog-park.png +0 -0
  144. package/dist/cesium/Assets/Textures/maki/embassy.png +0 -0
  145. package/dist/cesium/Assets/Textures/maki/emergency-telephone.png +0 -0
  146. package/dist/cesium/Assets/Textures/maki/entrance.png +0 -0
  147. package/dist/cesium/Assets/Textures/maki/farm.png +0 -0
  148. package/dist/cesium/Assets/Textures/maki/fast-food.png +0 -0
  149. package/dist/cesium/Assets/Textures/maki/ferry.png +0 -0
  150. package/dist/cesium/Assets/Textures/maki/fire-station.png +0 -0
  151. package/dist/cesium/Assets/Textures/maki/fuel.png +0 -0
  152. package/dist/cesium/Assets/Textures/maki/garden.png +0 -0
  153. package/dist/cesium/Assets/Textures/maki/gift.png +0 -0
  154. package/dist/cesium/Assets/Textures/maki/golf.png +0 -0
  155. package/dist/cesium/Assets/Textures/maki/grocery.png +0 -0
  156. package/dist/cesium/Assets/Textures/maki/hairdresser.png +0 -0
  157. package/dist/cesium/Assets/Textures/maki/harbor.png +0 -0
  158. package/dist/cesium/Assets/Textures/maki/heart.png +0 -0
  159. package/dist/cesium/Assets/Textures/maki/heliport.png +0 -0
  160. package/dist/cesium/Assets/Textures/maki/hospital.png +0 -0
  161. package/dist/cesium/Assets/Textures/maki/ice-cream.png +0 -0
  162. package/dist/cesium/Assets/Textures/maki/industrial.png +0 -0
  163. package/dist/cesium/Assets/Textures/maki/land-use.png +0 -0
  164. package/dist/cesium/Assets/Textures/maki/laundry.png +0 -0
  165. package/dist/cesium/Assets/Textures/maki/library.png +0 -0
  166. package/dist/cesium/Assets/Textures/maki/lighthouse.png +0 -0
  167. package/dist/cesium/Assets/Textures/maki/lodging.png +0 -0
  168. package/dist/cesium/Assets/Textures/maki/logging.png +0 -0
  169. package/dist/cesium/Assets/Textures/maki/london-underground.png +0 -0
  170. package/dist/cesium/Assets/Textures/maki/marker-stroked.png +0 -0
  171. package/dist/cesium/Assets/Textures/maki/marker.png +0 -0
  172. package/dist/cesium/Assets/Textures/maki/minefield.png +0 -0
  173. package/dist/cesium/Assets/Textures/maki/mobilephone.png +0 -0
  174. package/dist/cesium/Assets/Textures/maki/monument.png +0 -0
  175. package/dist/cesium/Assets/Textures/maki/museum.png +0 -0
  176. package/dist/cesium/Assets/Textures/maki/music.png +0 -0
  177. package/dist/cesium/Assets/Textures/maki/oil-well.png +0 -0
  178. package/dist/cesium/Assets/Textures/maki/park.png +0 -0
  179. package/dist/cesium/Assets/Textures/maki/park2.png +0 -0
  180. package/dist/cesium/Assets/Textures/maki/parking-garage.png +0 -0
  181. package/dist/cesium/Assets/Textures/maki/parking.png +0 -0
  182. package/dist/cesium/Assets/Textures/maki/pharmacy.png +0 -0
  183. package/dist/cesium/Assets/Textures/maki/pitch.png +0 -0
  184. package/dist/cesium/Assets/Textures/maki/place-of-worship.png +0 -0
  185. package/dist/cesium/Assets/Textures/maki/playground.png +0 -0
  186. package/dist/cesium/Assets/Textures/maki/police.png +0 -0
  187. package/dist/cesium/Assets/Textures/maki/polling-place.png +0 -0
  188. package/dist/cesium/Assets/Textures/maki/post.png +0 -0
  189. package/dist/cesium/Assets/Textures/maki/prison.png +0 -0
  190. package/dist/cesium/Assets/Textures/maki/rail-above.png +0 -0
  191. package/dist/cesium/Assets/Textures/maki/rail-light.png +0 -0
  192. package/dist/cesium/Assets/Textures/maki/rail-metro.png +0 -0
  193. package/dist/cesium/Assets/Textures/maki/rail-underground.png +0 -0
  194. package/dist/cesium/Assets/Textures/maki/rail.png +0 -0
  195. package/dist/cesium/Assets/Textures/maki/religious-christian.png +0 -0
  196. package/dist/cesium/Assets/Textures/maki/religious-jewish.png +0 -0
  197. package/dist/cesium/Assets/Textures/maki/religious-muslim.png +0 -0
  198. package/dist/cesium/Assets/Textures/maki/restaurant.png +0 -0
  199. package/dist/cesium/Assets/Textures/maki/roadblock.png +0 -0
  200. package/dist/cesium/Assets/Textures/maki/rocket.png +0 -0
  201. package/dist/cesium/Assets/Textures/maki/school.png +0 -0
  202. package/dist/cesium/Assets/Textures/maki/scooter.png +0 -0
  203. package/dist/cesium/Assets/Textures/maki/shop.png +0 -0
  204. package/dist/cesium/Assets/Textures/maki/skiing.png +0 -0
  205. package/dist/cesium/Assets/Textures/maki/slaughterhouse.png +0 -0
  206. package/dist/cesium/Assets/Textures/maki/soccer.png +0 -0
  207. package/dist/cesium/Assets/Textures/maki/square-stroked.png +0 -0
  208. package/dist/cesium/Assets/Textures/maki/square.png +0 -0
  209. package/dist/cesium/Assets/Textures/maki/star-stroked.png +0 -0
  210. package/dist/cesium/Assets/Textures/maki/star.png +0 -0
  211. package/dist/cesium/Assets/Textures/maki/suitcase.png +0 -0
  212. package/dist/cesium/Assets/Textures/maki/swimming.png +0 -0
  213. package/dist/cesium/Assets/Textures/maki/telephone.png +0 -0
  214. package/dist/cesium/Assets/Textures/maki/tennis.png +0 -0
  215. package/dist/cesium/Assets/Textures/maki/theatre.png +0 -0
  216. package/dist/cesium/Assets/Textures/maki/toilets.png +0 -0
  217. package/dist/cesium/Assets/Textures/maki/town-hall.png +0 -0
  218. package/dist/cesium/Assets/Textures/maki/town.png +0 -0
  219. package/dist/cesium/Assets/Textures/maki/triangle-stroked.png +0 -0
  220. package/dist/cesium/Assets/Textures/maki/triangle.png +0 -0
  221. package/dist/cesium/Assets/Textures/maki/village.png +0 -0
  222. package/dist/cesium/Assets/Textures/maki/warehouse.png +0 -0
  223. package/dist/cesium/Assets/Textures/maki/waste-basket.png +0 -0
  224. package/dist/cesium/Assets/Textures/maki/water.png +0 -0
  225. package/dist/cesium/Assets/Textures/maki/wetland.png +0 -0
  226. package/dist/cesium/Assets/Textures/maki/zoo.png +0 -0
  227. package/dist/cesium/Assets/Textures/moonSmall.jpg +0 -0
  228. package/dist/cesium/Assets/Textures/pin.svg +1 -0
  229. package/dist/cesium/Assets/Textures/waterNormals.jpg +0 -0
  230. package/dist/cesium/Assets/Textures/waterNormalsSmall.jpg +0 -0
  231. package/dist/cesium/Assets/approximateTerrainHeights.json +1 -0
  232. package/dist/cesium/ThirdParty/Workers/package.json +1 -0
  233. package/dist/cesium/ThirdParty/Workers/zip-web-worker.js +1 -0
  234. package/dist/cesium/ThirdParty/basis_transcoder.wasm +0 -0
  235. package/dist/cesium/ThirdParty/draco_decoder.wasm +0 -0
  236. package/dist/cesium/ThirdParty/google-earth-dbroot-parser.js +1 -0
  237. package/dist/cesium/ThirdParty/wasm_splats_bg.wasm +0 -0
  238. package/dist/cesium/ThirdParty/zip-module.wasm +0 -0
  239. package/dist/cesium/Widgets/Animation/Animation.css +127 -0
  240. package/dist/cesium/Widgets/Animation/lighter.css +70 -0
  241. package/dist/cesium/Widgets/BaseLayerPicker/BaseLayerPicker.css +108 -0
  242. package/dist/cesium/Widgets/BaseLayerPicker/lighter.css +22 -0
  243. package/dist/cesium/Widgets/Cesium3DTilesInspector/Cesium3DTilesInspector.css +102 -0
  244. package/dist/cesium/Widgets/CesiumInspector/CesiumInspector.css +113 -0
  245. package/dist/cesium/Widgets/CesiumWidget/CesiumWidget.css +119 -0
  246. package/dist/cesium/Widgets/CesiumWidget/lighter.css +14 -0
  247. package/dist/cesium/Widgets/FullscreenButton/FullscreenButton.css +8 -0
  248. package/dist/cesium/Widgets/Geocoder/Geocoder.css +70 -0
  249. package/dist/cesium/Widgets/Geocoder/lighter.css +17 -0
  250. package/dist/cesium/Widgets/I3SBuildingSceneLayerExplorer/I3SBuildingSceneLayerExplorer.css +27 -0
  251. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldHillshade.png +0 -0
  252. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldImagery.png +0 -0
  253. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldOcean.png +0 -0
  254. package/dist/cesium/Widgets/Images/ImageryProviders/azureAerial.png +0 -0
  255. package/dist/cesium/Widgets/Images/ImageryProviders/azureRoads.png +0 -0
  256. package/dist/cesium/Widgets/Images/ImageryProviders/bingAerial.png +0 -0
  257. package/dist/cesium/Widgets/Images/ImageryProviders/bingAerialLabels.png +0 -0
  258. package/dist/cesium/Widgets/Images/ImageryProviders/bingRoads.png +0 -0
  259. package/dist/cesium/Widgets/Images/ImageryProviders/blueMarble.png +0 -0
  260. package/dist/cesium/Widgets/Images/ImageryProviders/earthAtNight.png +0 -0
  261. package/dist/cesium/Widgets/Images/ImageryProviders/googleContour.png +0 -0
  262. package/dist/cesium/Widgets/Images/ImageryProviders/googleRoadmap.png +0 -0
  263. package/dist/cesium/Widgets/Images/ImageryProviders/googleSatellite.png +0 -0
  264. package/dist/cesium/Widgets/Images/ImageryProviders/googleSatelliteLabels.png +0 -0
  265. package/dist/cesium/Widgets/Images/ImageryProviders/mapQuestOpenStreetMap.png +0 -0
  266. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxSatellite.png +0 -0
  267. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxStreets.png +0 -0
  268. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxTerrain.png +0 -0
  269. package/dist/cesium/Widgets/Images/ImageryProviders/naturalEarthII.png +0 -0
  270. package/dist/cesium/Widgets/Images/ImageryProviders/openStreetMap.png +0 -0
  271. package/dist/cesium/Widgets/Images/ImageryProviders/sentinel-2.png +0 -0
  272. package/dist/cesium/Widgets/Images/ImageryProviders/stadiaAlidadeSmooth.png +0 -0
  273. package/dist/cesium/Widgets/Images/ImageryProviders/stadiaAlidadeSmoothDark.png +0 -0
  274. package/dist/cesium/Widgets/Images/ImageryProviders/stamenToner.png +0 -0
  275. package/dist/cesium/Widgets/Images/ImageryProviders/stamenWatercolor.png +0 -0
  276. package/dist/cesium/Widgets/Images/NavigationHelp/Mouse.svg +84 -0
  277. package/dist/cesium/Widgets/Images/NavigationHelp/MouseLeft.svg +76 -0
  278. package/dist/cesium/Widgets/Images/NavigationHelp/MouseMiddle.svg +76 -0
  279. package/dist/cesium/Widgets/Images/NavigationHelp/MouseRight.svg +76 -0
  280. package/dist/cesium/Widgets/Images/NavigationHelp/Touch.svg +120 -0
  281. package/dist/cesium/Widgets/Images/NavigationHelp/TouchDrag.svg +129 -0
  282. package/dist/cesium/Widgets/Images/NavigationHelp/TouchRotate.svg +76 -0
  283. package/dist/cesium/Widgets/Images/NavigationHelp/TouchTilt.svg +135 -0
  284. package/dist/cesium/Widgets/Images/NavigationHelp/TouchZoom.svg +74 -0
  285. package/dist/cesium/Widgets/Images/TerrainProviders/CesiumWorldTerrain.png +0 -0
  286. package/dist/cesium/Widgets/Images/TerrainProviders/Ellipsoid.png +0 -0
  287. package/dist/cesium/Widgets/Images/TimelineIcons.png +0 -0
  288. package/dist/cesium/Widgets/Images/info-loading.gif +0 -0
  289. package/dist/cesium/Widgets/InfoBox/InfoBox.css +92 -0
  290. package/dist/cesium/Widgets/InfoBox/InfoBoxDescription.css +178 -0
  291. package/dist/cesium/Widgets/NavigationHelpButton/NavigationHelpButton.css +93 -0
  292. package/dist/cesium/Widgets/NavigationHelpButton/lighter.css +38 -0
  293. package/dist/cesium/Widgets/PerformanceWatchdog/PerformanceWatchdog.css +15 -0
  294. package/dist/cesium/Widgets/ProjectionPicker/ProjectionPicker.css +38 -0
  295. package/dist/cesium/Widgets/SceneModePicker/SceneModePicker.css +56 -0
  296. package/dist/cesium/Widgets/SelectionIndicator/SelectionIndicator.css +20 -0
  297. package/dist/cesium/Widgets/Timeline/Timeline.css +103 -0
  298. package/dist/cesium/Widgets/Timeline/lighter.css +23 -0
  299. package/dist/cesium/Widgets/VRButton/VRButton.css +8 -0
  300. package/dist/cesium/Widgets/Viewer/Viewer.css +107 -0
  301. package/dist/cesium/Widgets/VoxelInspector/VoxelInspector.css +16 -0
  302. package/dist/cesium/Widgets/lighter.css +237 -0
  303. package/dist/cesium/Widgets/lighterShared.css +46 -0
  304. package/dist/cesium/Widgets/shared.css +103 -0
  305. package/dist/cesium/Widgets/widgets.css +1342 -0
  306. package/dist/cesium/Workers/chunk-23ZQ2IVV.js +29 -0
  307. package/dist/cesium/Workers/chunk-2EQO3Q56.js +26 -0
  308. package/dist/cesium/Workers/chunk-2MJIIVP4.js +26 -0
  309. package/dist/cesium/Workers/chunk-2TE5NTVD.js +26 -0
  310. package/dist/cesium/Workers/chunk-2ZBHLJST.js +26 -0
  311. package/dist/cesium/Workers/chunk-5TJMAQVL.js +26 -0
  312. package/dist/cesium/Workers/chunk-6BD4U3VO.js +26 -0
  313. package/dist/cesium/Workers/chunk-7TVGLKQF.js +26 -0
  314. package/dist/cesium/Workers/chunk-BTSYJ5XU.js +26 -0
  315. package/dist/cesium/Workers/chunk-BXMEEOCS.js +63 -0
  316. package/dist/cesium/Workers/chunk-BYLCY7GP.js +29 -0
  317. package/dist/cesium/Workers/chunk-CTHM3W6I.js +26 -0
  318. package/dist/cesium/Workers/chunk-CUUSNIVQ.js +26 -0
  319. package/dist/cesium/Workers/chunk-E3JOOS3S.js +26 -0
  320. package/dist/cesium/Workers/chunk-E7KYDCM5.js +26 -0
  321. package/dist/cesium/Workers/chunk-EDVBB7SS.js +27 -0
  322. package/dist/cesium/Workers/chunk-EFBN7QNX.js +26 -0
  323. package/dist/cesium/Workers/chunk-EQ4YRVWL.js +26 -0
  324. package/dist/cesium/Workers/chunk-F6PRE7D6.js +26 -0
  325. package/dist/cesium/Workers/chunk-FC4ZZ65J.js +26 -0
  326. package/dist/cesium/Workers/chunk-FFBVWF2L.js +26 -0
  327. package/dist/cesium/Workers/chunk-GBAA6GVX.js +26 -0
  328. package/dist/cesium/Workers/chunk-ICALLYLG.js +26 -0
  329. package/dist/cesium/Workers/chunk-ILRYTWTP.js +26 -0
  330. package/dist/cesium/Workers/chunk-IRNLBSEJ.js +26 -0
  331. package/dist/cesium/Workers/chunk-IX4VMHEV.js +26 -0
  332. package/dist/cesium/Workers/chunk-L6QHHACZ.js +26 -0
  333. package/dist/cesium/Workers/chunk-LI2ZSORM.js +26 -0
  334. package/dist/cesium/Workers/chunk-LSLE2RL4.js +26 -0
  335. package/dist/cesium/Workers/chunk-M4HLDBCG.js +26 -0
  336. package/dist/cesium/Workers/chunk-MJHHSGEH.js +26 -0
  337. package/dist/cesium/Workers/chunk-NMVKML6W.js +26 -0
  338. package/dist/cesium/Workers/chunk-OCWJRAXS.js +26 -0
  339. package/dist/cesium/Workers/chunk-OIRKANTH.js +26 -0
  340. package/dist/cesium/Workers/chunk-OIT7J4IC.js +26 -0
  341. package/dist/cesium/Workers/chunk-OLZ3FYUM.js +26 -0
  342. package/dist/cesium/Workers/chunk-Q5BPHJQF.js +26 -0
  343. package/dist/cesium/Workers/chunk-QFM5DCMQ.js +26 -0
  344. package/dist/cesium/Workers/chunk-QKUIYMGC.js +28 -0
  345. package/dist/cesium/Workers/chunk-S44JILQT.js +26 -0
  346. package/dist/cesium/Workers/chunk-SLT4J352.js +26 -0
  347. package/dist/cesium/Workers/chunk-SQMIIXB7.js +26 -0
  348. package/dist/cesium/Workers/chunk-TJ4XLGBQ.js +26 -0
  349. package/dist/cesium/Workers/chunk-TNSUQXWK.js +27 -0
  350. package/dist/cesium/Workers/chunk-UBOGZS7F.js +26 -0
  351. package/dist/cesium/Workers/chunk-V3OSTMM6.js +26 -0
  352. package/dist/cesium/Workers/chunk-V7QEYVP3.js +26 -0
  353. package/dist/cesium/Workers/chunk-VUKYSU4H.js +26 -0
  354. package/dist/cesium/Workers/chunk-W37FE5GR.js +26 -0
  355. package/dist/cesium/Workers/chunk-WBOV35NL.js +26 -0
  356. package/dist/cesium/Workers/chunk-WPMZLB3Y.js +26 -0
  357. package/dist/cesium/Workers/chunk-WWWZVEEH.js +26 -0
  358. package/dist/cesium/Workers/chunk-XFIQ5DEQ.js +28 -0
  359. package/dist/cesium/Workers/chunk-XQHLGIO7.js +26 -0
  360. package/dist/cesium/Workers/chunk-XUSCFAVF.js +26 -0
  361. package/dist/cesium/Workers/chunk-YP7I5QBZ.js +26 -0
  362. package/dist/cesium/Workers/chunk-Z3QF2EHT.js +26 -0
  363. package/dist/cesium/Workers/combineGeometry.js +26 -0
  364. package/dist/cesium/Workers/createBoxGeometry.js +26 -0
  365. package/dist/cesium/Workers/createBoxOutlineGeometry.js +26 -0
  366. package/dist/cesium/Workers/createCircleGeometry.js +26 -0
  367. package/dist/cesium/Workers/createCircleOutlineGeometry.js +26 -0
  368. package/dist/cesium/Workers/createCoplanarPolygonGeometry.js +26 -0
  369. package/dist/cesium/Workers/createCoplanarPolygonOutlineGeometry.js +26 -0
  370. package/dist/cesium/Workers/createCorridorGeometry.js +26 -0
  371. package/dist/cesium/Workers/createCorridorOutlineGeometry.js +26 -0
  372. package/dist/cesium/Workers/createCylinderGeometry.js +26 -0
  373. package/dist/cesium/Workers/createCylinderOutlineGeometry.js +26 -0
  374. package/dist/cesium/Workers/createEllipseGeometry.js +26 -0
  375. package/dist/cesium/Workers/createEllipseOutlineGeometry.js +26 -0
  376. package/dist/cesium/Workers/createEllipsoidGeometry.js +26 -0
  377. package/dist/cesium/Workers/createEllipsoidOutlineGeometry.js +26 -0
  378. package/dist/cesium/Workers/createFrustumGeometry.js +26 -0
  379. package/dist/cesium/Workers/createFrustumOutlineGeometry.js +26 -0
  380. package/dist/cesium/Workers/createGeometry.js +26 -0
  381. package/dist/cesium/Workers/createGroundPolylineGeometry.js +26 -0
  382. package/dist/cesium/Workers/createPlaneGeometry.js +26 -0
  383. package/dist/cesium/Workers/createPlaneOutlineGeometry.js +26 -0
  384. package/dist/cesium/Workers/createPolygonGeometry.js +26 -0
  385. package/dist/cesium/Workers/createPolygonOutlineGeometry.js +26 -0
  386. package/dist/cesium/Workers/createPolylineGeometry.js +26 -0
  387. package/dist/cesium/Workers/createPolylineVolumeGeometry.js +26 -0
  388. package/dist/cesium/Workers/createPolylineVolumeOutlineGeometry.js +26 -0
  389. package/dist/cesium/Workers/createRectangleGeometry.js +26 -0
  390. package/dist/cesium/Workers/createRectangleOutlineGeometry.js +26 -0
  391. package/dist/cesium/Workers/createSimplePolylineGeometry.js +26 -0
  392. package/dist/cesium/Workers/createSphereGeometry.js +26 -0
  393. package/dist/cesium/Workers/createSphereOutlineGeometry.js +26 -0
  394. package/dist/cesium/Workers/createTaskProcessorWorker.js +26 -0
  395. package/dist/cesium/Workers/createVectorTileClampedPolylines.js +26 -0
  396. package/dist/cesium/Workers/createVectorTileGeometries.js +26 -0
  397. package/dist/cesium/Workers/createVectorTilePoints.js +26 -0
  398. package/dist/cesium/Workers/createVectorTilePolygons.js +26 -0
  399. package/dist/cesium/Workers/createVectorTilePolylines.js +26 -0
  400. package/dist/cesium/Workers/createVerticesFromCesium3DTilesTerrain.js +26 -0
  401. package/dist/cesium/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +26 -0
  402. package/dist/cesium/Workers/createVerticesFromHeightmap.js +26 -0
  403. package/dist/cesium/Workers/createVerticesFromQuantizedTerrainMesh.js +26 -0
  404. package/dist/cesium/Workers/createWallGeometry.js +26 -0
  405. package/dist/cesium/Workers/createWallOutlineGeometry.js +26 -0
  406. package/dist/cesium/Workers/decodeDraco.js +26 -0
  407. package/dist/cesium/Workers/decodeGoogleEarthEnterprisePacket.js +26 -0
  408. package/dist/cesium/Workers/decodeI3S.js +26 -0
  409. package/dist/cesium/Workers/gaussianSplatSorter.js +26 -0
  410. package/dist/cesium/Workers/gaussianSplatTextureGenerator.js +26 -0
  411. package/dist/cesium/Workers/incrementallyBuildTerrainPicker.js +26 -0
  412. package/dist/cesium/Workers/transcodeKTX2.js +56 -0
  413. package/dist/cesium/Workers/transferTypedArrayTest.js +26 -0
  414. package/dist/cesium/Workers/upsampleQuantizedTerrainMesh.js +26 -0
  415. package/dist/cesium/Workers/upsampleVerticesFromCesium3DTilesTerrain.js +26 -0
  416. package/dist/index.html +13 -10
  417. package/index.html +1 -0
  418. package/package.json +18 -15
  419. package/src/App.tsx +7 -9
  420. package/src/components/viewer/BCFPanel.tsx +46 -4
  421. package/src/components/viewer/CesiumOverlay.tsx +715 -0
  422. package/src/components/viewer/CesiumSettingsDialog.tsx +100 -0
  423. package/src/components/viewer/ChatPanel.tsx +232 -90
  424. package/src/components/viewer/CommandPalette.tsx +6 -1
  425. package/src/components/viewer/DesktopEntitlementBanner.tsx +74 -0
  426. package/src/components/viewer/ExportChangesButton.tsx +6 -1
  427. package/src/components/viewer/ExportDialog.tsx +22 -6
  428. package/src/components/viewer/HierarchyPanel.tsx +196 -0
  429. package/src/components/viewer/IDSPanel.tsx +52 -3
  430. package/src/components/viewer/KeyboardShortcutsDialog.tsx +1 -1
  431. package/src/components/viewer/MainToolbar.tsx +355 -28
  432. package/src/components/viewer/PropertiesPanel.tsx +234 -81
  433. package/src/components/viewer/ScriptPanel.tsx +34 -8
  434. package/src/components/viewer/SettingsPage.tsx +581 -0
  435. package/src/components/viewer/StatusBar.tsx +17 -1
  436. package/src/components/viewer/ThemeSwitch.tsx +63 -7
  437. package/src/components/viewer/ViewerLayout.tsx +48 -6
  438. package/src/components/viewer/Viewport.tsx +61 -8
  439. package/src/components/viewer/ViewportContainer.tsx +265 -28
  440. package/src/components/viewer/ViewportOverlays.tsx +132 -27
  441. package/src/components/viewer/bcf/BCFTopicDetail.tsx +4 -4
  442. package/src/components/viewer/chat/ModelSelector.tsx +90 -54
  443. package/src/components/viewer/properties/GeoreferencingPanel.tsx +229 -55
  444. package/src/components/viewer/properties/LocationMap.tsx +462 -19
  445. package/src/components/viewer/properties/ModelMetadataPanel.tsx +1 -1
  446. package/src/components/viewer/selectionHandlers.ts +4 -3
  447. package/src/components/viewer/tools/SectionCapControls.tsx +237 -0
  448. package/src/components/viewer/tools/SectionPanel.tsx +39 -18
  449. package/src/components/viewer/useAnimationLoop.ts +13 -1
  450. package/src/components/viewer/useGeometryStreaming.ts +127 -40
  451. package/src/components/viewer/useMouseControls.ts +4 -1
  452. package/src/components/viewer/useRenderUpdates.ts +1 -1
  453. package/src/hooks/ids/idsDataAccessor.ts +60 -24
  454. package/src/hooks/ingest/viewerModelIngest.ts +280 -0
  455. package/src/hooks/useIDS.ts +1 -1
  456. package/src/hooks/useIfc.ts +7 -1
  457. package/src/hooks/useIfcCache.ts +28 -15
  458. package/src/hooks/useIfcFederation.ts +378 -291
  459. package/src/hooks/useIfcLoader.ts +1657 -130
  460. package/src/hooks/useIfcServer.ts +0 -69
  461. package/src/hooks/useViewControls.ts +13 -5
  462. package/src/index.css +484 -10
  463. package/src/lib/desktop/desktopEntitlementEvents.ts +39 -0
  464. package/src/lib/desktop-entitlement.ts +43 -0
  465. package/src/lib/desktop-product.ts +124 -0
  466. package/src/lib/geo/cesium-bridge.ts +318 -0
  467. package/src/lib/geo/effective-georef.test.ts +73 -0
  468. package/src/lib/geo/effective-georef.ts +111 -0
  469. package/src/lib/geo/reproject.ts +249 -37
  470. package/src/lib/llm/byok-guard.test.ts +77 -0
  471. package/src/lib/llm/byok-guard.ts +39 -0
  472. package/src/lib/llm/free-models.test.ts +0 -6
  473. package/src/lib/llm/models.ts +104 -42
  474. package/src/lib/llm/stream-client.ts +74 -110
  475. package/src/lib/llm/stream-direct.test.ts +130 -0
  476. package/src/lib/llm/stream-direct.ts +316 -0
  477. package/src/lib/llm/types.ts +14 -2
  478. package/src/lib/recent-files.ts +2 -1
  479. package/src/main.tsx +1 -10
  480. package/src/services/analysis-extensions.ts +125 -0
  481. package/src/services/api-keys.ts +73 -0
  482. package/src/services/app-navigation.ts +13 -0
  483. package/src/services/bsdd.ts +53 -4
  484. package/src/services/cacheService.ts +1 -1
  485. package/src/services/desktop-cache.ts +43 -0
  486. package/src/services/desktop-export.ts +77 -0
  487. package/src/services/desktop-harness.ts +196 -0
  488. package/src/services/desktop-logger.ts +20 -0
  489. package/src/services/desktop-native-metadata.ts +207 -0
  490. package/src/services/desktop-panel-actions.ts +43 -0
  491. package/src/services/desktop-preferences.ts +44 -0
  492. package/src/services/file-dialog.ts +147 -0
  493. package/src/services/tauri-core-stub.ts +7 -0
  494. package/src/services/tauri-dialog-stub.ts +7 -0
  495. package/src/services/tauri-fs-stub.ts +7 -0
  496. package/src/store/constants.ts +20 -2
  497. package/src/store/index.ts +52 -7
  498. package/src/store/slices/cesiumSlice.ts +127 -0
  499. package/src/store/slices/chatSlice.test.ts +6 -76
  500. package/src/store/slices/chatSlice.ts +21 -58
  501. package/src/store/slices/dataSlice.ts +139 -28
  502. package/src/store/slices/desktopEntitlementSlice.ts +86 -0
  503. package/src/store/slices/loadingSlice.ts +14 -2
  504. package/src/store/slices/modelSlice.ts +58 -3
  505. package/src/store/slices/sectionSlice.test.ts +87 -7
  506. package/src/store/slices/sectionSlice.ts +151 -5
  507. package/src/store/slices/uiSlice.ts +28 -5
  508. package/src/store/types.ts +122 -2
  509. package/src/store.ts +1 -1
  510. package/src/utils/desktopModelSnapshot.ts +358 -0
  511. package/src/utils/ifcConfig.ts +6 -1
  512. package/src/utils/nativeSpatialDataStore.ts +253 -0
  513. package/src/utils/serverDataModel.ts +4 -0
  514. package/src/utils/spatialHierarchy.ts +10 -11
  515. package/src/utils/viewportUtils.ts +7 -2
  516. package/src/vite-env.d.ts +0 -4
  517. package/vite.config.ts +24 -0
  518. package/dist/assets/arrow-DJf2ErbF.js +0 -20
  519. package/dist/assets/basketViewActivator-aojwdomq.js +0 -1
  520. package/dist/assets/desktop-cache-oPzaWXYE.js +0 -1
  521. package/dist/assets/drawing-2d-gWfpdfYe.js +0 -257
  522. package/dist/assets/geometry.worker-Nz9_YIqh.js +0 -1
  523. package/dist/assets/ids-B4jTqB1O.js +0 -1
  524. package/dist/assets/ifc-lite_bg-eSkBTizQ.wasm +0 -0
  525. package/dist/assets/index-pbE7itQS.css +0 -1
  526. package/dist/assets/native-bridge-DSIyEYXG.js +0 -113
  527. package/dist/assets/wasm-bridge-B0J07fZZ.js +0 -1
  528. package/src/components/viewer/UpgradePage.tsx +0 -69
  529. package/src/lib/llm/ClerkChatSync.tsx +0 -74
  530. package/src/lib/llm/clerk-auth.ts +0 -62
@@ -13,6 +13,7 @@ import { coerceModelForEntitlement, DEFAULT_FREE_MODEL } from '../../lib/llm/mod
13
13
  import { extractCodeBlocks } from '../../lib/llm/code-extractor.js';
14
14
  import type { ScriptDiagnostic } from '../../lib/llm/script-diagnostics.js';
15
15
  import { formatDiagnosticsForPrompt, getPrimaryRootCause, groupDiagnosticsByRootCause } from '../../lib/llm/script-diagnostics.js';
16
+ import { hasAnyApiKey as hasAnyApiKeyAtInit } from '../../services/api-keys.js';
16
17
 
17
18
  const MODEL_STORAGE_KEY = 'ifc-lite-chat-model';
18
19
  const MESSAGES_STORAGE_KEY = 'ifc-lite-chat-messages';
@@ -43,11 +44,9 @@ export interface ChatSlice {
43
44
  chatPendingRepairRequest: ChatRepairRequest | null;
44
45
  /** Auto-captured viewport screenshot (base64 data URL) to include with next LLM message */
45
46
  chatViewportScreenshot: string | null;
46
- /** Clerk JWT for authenticated API calls (null for anonymous/free tier) */
47
- chatAuthToken: string | null;
48
- /** Whether the current user has a pro subscription */
49
- chatHasPro: boolean;
50
- /** Usage info from the server: credits (pro) or request count (free) */
47
+ /** Whether the user has at least one BYOK API key configured */
48
+ chatHasByokKey: boolean;
49
+ /** Usage info from the proxy: request count for free tier */
51
50
  chatUsage: ChatUsage | null;
52
51
  /** User ID used to scope persisted model preference (null for anonymous). */
53
52
  chatStorageUserId: string | null;
@@ -78,18 +77,10 @@ export interface ChatSlice {
78
77
  sendErrorFeedback: (code: string, error: string) => void;
79
78
  /** Store a viewport screenshot to include with the next LLM message */
80
79
  setChatViewportScreenshot: (dataUrl: string | null) => void;
81
- /** Set the Clerk auth token (called by ClerkProvider wrapper when user signs in) */
82
- setChatAuthToken: (token: string | null) => void;
83
- /** Set whether user has pro subscription (called by ClerkProvider wrapper) */
84
- setChatHasPro: (hasPro: boolean) => void;
80
+ /** Set whether user has at least one BYOK API key configured */
81
+ setChatHasByokKey: (hasByokKey: boolean) => void;
85
82
  /** Update usage info from server response headers */
86
83
  setChatUsage: (usage: ChatUsage | null) => void;
87
- /** Switch the active chat user/session context. */
88
- switchChatUserContext: (
89
- userId: string | null,
90
- hasPro: boolean,
91
- options?: { clearPersistedCurrent?: boolean; restoreMessages?: boolean },
92
- ) => void;
93
84
  }
94
85
 
95
86
  export interface ChatUsage {
@@ -177,6 +168,10 @@ function loadStoredModel(userId: string | null, fallback?: string): string {
177
168
  }
178
169
  }
179
170
 
171
+ function loadValidStoredModel(userId: string | null, hasPro: boolean, fallback?: string): string {
172
+ return coerceModelForEntitlement(loadStoredModel(userId, fallback), hasPro);
173
+ }
174
+
180
175
  function loadStoredAutoExecute(): boolean {
181
176
  try {
182
177
  const val = localStorage.getItem(AUTO_EXEC_STORAGE_KEY);
@@ -275,7 +270,7 @@ export const createChatSlice: StateCreator<ChatSlice, [], [], ChatSlice> = (set,
275
270
  chatMessages: loadStoredMessages(null),
276
271
  chatStatus: 'idle',
277
272
  chatStreamingContent: '',
278
- chatActiveModel: loadStoredModel(null),
273
+ chatActiveModel: loadValidStoredModel(null, hasAnyApiKeyAtInit()),
279
274
  chatAutoExecute: loadStoredAutoExecute(),
280
275
  chatError: null,
281
276
  chatAbortController: null,
@@ -283,8 +278,7 @@ export const createChatSlice: StateCreator<ChatSlice, [], [], ChatSlice> = (set,
283
278
  chatPendingPrompt: null,
284
279
  chatPendingRepairRequest: null,
285
280
  chatViewportScreenshot: null,
286
- chatAuthToken: null,
287
- chatHasPro: false,
281
+ chatHasByokKey: false,
288
282
  chatUsage: null,
289
283
  chatStorageUserId: null,
290
284
 
@@ -336,12 +330,15 @@ export const createChatSlice: StateCreator<ChatSlice, [], [], ChatSlice> = (set,
336
330
  setChatStreamingContent: (chatStreamingContent) => set({ chatStreamingContent }),
337
331
 
338
332
  setChatActiveModel: (chatActiveModel) => {
339
- const nextModel = coerceModelForEntitlement(chatActiveModel, get().chatHasPro);
333
+ // Accept any model the user picks — the ChatPanel shows an inline key
334
+ // prompt if the selected BYOK model doesn't have a key yet, and guards
335
+ // the send path. Coercion only happens on init and when keys are removed
336
+ // (via setChatHasByokKey).
340
337
  try {
341
338
  const key = getModelStorageKey(get().chatStorageUserId);
342
- localStorage.setItem(key, nextModel);
339
+ localStorage.setItem(key, chatActiveModel);
343
340
  } catch { /* ignore */ }
344
- set({ chatActiveModel: nextModel });
341
+ set({ chatActiveModel });
345
342
  },
346
343
 
347
344
  setChatAutoExecute: (chatAutoExecute) => {
@@ -400,51 +397,17 @@ export const createChatSlice: StateCreator<ChatSlice, [], [], ChatSlice> = (set,
400
397
 
401
398
  setChatViewportScreenshot: (chatViewportScreenshot) => set({ chatViewportScreenshot }),
402
399
 
403
- setChatAuthToken: (chatAuthToken) => set({ chatAuthToken }),
404
-
405
- setChatHasPro: (chatHasPro) => {
406
- const nextModel = coerceModelForEntitlement(get().chatActiveModel, chatHasPro);
400
+ setChatHasByokKey: (chatHasByokKey) => {
401
+ const nextModel = coerceModelForEntitlement(get().chatActiveModel, chatHasByokKey);
407
402
  try {
408
403
  const key = getModelStorageKey(get().chatStorageUserId);
409
404
  localStorage.setItem(key, nextModel);
410
405
  } catch { /* ignore */ }
411
- set({ chatHasPro, chatActiveModel: nextModel });
406
+ set({ chatHasByokKey, chatActiveModel: nextModel });
412
407
  },
413
408
 
414
409
  setChatUsage: (chatUsage) => set({ chatUsage }),
415
410
 
416
- switchChatUserContext: (chatStorageUserId, chatHasPro, options) => {
417
- const state = get();
418
- state.chatAbortController?.abort();
419
- if (options?.clearPersistedCurrent) {
420
- try {
421
- localStorage.removeItem(getMessagesStorageKey(state.chatStorageUserId));
422
- } catch { /* ignore */ }
423
- }
424
- const restoredModel = coerceModelForEntitlement(
425
- loadStoredModel(chatStorageUserId, state.chatActiveModel),
426
- chatHasPro,
427
- );
428
- const restoredMessages = options?.restoreMessages === false
429
- ? []
430
- : loadStoredMessages(chatStorageUserId);
431
- set({
432
- chatStorageUserId,
433
- chatHasPro,
434
- chatActiveModel: restoredModel,
435
- chatMessages: restoredMessages,
436
- chatStatus: 'idle',
437
- chatStreamingContent: '',
438
- chatError: null,
439
- chatAbortController: null,
440
- chatAttachments: [],
441
- chatPendingPrompt: null,
442
- chatPendingRepairRequest: null,
443
- chatViewportScreenshot: null,
444
- chatUsage: null,
445
- });
446
- },
447
-
448
411
  sendErrorFeedback: (code, error) => {
449
412
  const feedbackMessage: ChatMessage = {
450
413
  id: crypto.randomUUID(),
@@ -9,12 +9,28 @@
9
9
  import type { StateCreator } from 'zustand';
10
10
  import type { IfcDataStore } from '@ifc-lite/parser';
11
11
  import type { GeometryResult, CoordinateInfo } from '@ifc-lite/geometry';
12
+ import type { FederatedModel } from '../types.js';
12
13
  import { DATA_DEFAULTS } from '../constants.js';
13
14
 
15
+ /**
16
+ * Cross-slice state that dataSlice reads/writes via the combined store.
17
+ *
18
+ * Data updaters sync `ifcDataStore` / `geometryResult` into the per-model
19
+ * entry inside the ModelSlice `models` map so that federation stays
20
+ * consistent. The types below describe the minimal ModelSlice surface
21
+ * that dataSlice accesses through the merged Zustand state.
22
+ */
23
+ interface DataCrossSliceState {
24
+ activeModelId: string | null;
25
+ models: Map<string, FederatedModel>;
26
+ }
27
+
14
28
  export interface DataSlice {
15
29
  // State
16
30
  ifcDataStore: IfcDataStore | null;
17
31
  geometryResult: GeometryResult | null;
32
+ geometryUpdateTick: number;
33
+ boundedGeometryMode: boolean;
18
34
  /** Transient overlay colors (lens/IDS/sdk overlays). */
19
35
  pendingColorUpdates: Map<number, [number, number, number, number]> | null;
20
36
  /** Persistent mesh color updates (IFC deferred style/material colors). */
@@ -23,7 +39,9 @@ export interface DataSlice {
23
39
  // Actions
24
40
  setIfcDataStore: (result: IfcDataStore | null) => void;
25
41
  setGeometryResult: (result: GeometryResult | null) => void;
42
+ setBoundedGeometryMode: (enabled: boolean) => void;
26
43
  appendGeometryBatch: (meshes: GeometryResult['meshes'], coordinateInfo?: CoordinateInfo) => void;
44
+ releaseGeometryMemory: () => void;
27
45
  /** Persist mesh color changes in geometryResult (used for IFC style/material updates). */
28
46
  updateMeshColors: (updates: Map<number, [number, number, number, number]>) => void;
29
47
  /** Set pending color updates for the renderer without cloning mesh data.
@@ -49,17 +67,53 @@ const getDefaultCoordinateInfo = (): CoordinateInfo => ({
49
67
  hasLargeCoordinates: DATA_DEFAULTS.HAS_LARGE_COORDINATES,
50
68
  });
51
69
 
52
- export const createDataSlice: StateCreator<DataSlice, [], [], DataSlice> = (set) => ({
70
+ const EMPTY_POSITIONS = new Float32Array(0);
71
+ const EMPTY_NORMALS = new Float32Array(0);
72
+ const EMPTY_INDICES = new Uint32Array(0);
73
+
74
+ export const createDataSlice: StateCreator<DataSlice & DataCrossSliceState, [], [], DataSlice> = (set, get) => ({
53
75
  // Initial state
54
76
  ifcDataStore: null,
55
77
  geometryResult: null,
78
+ geometryUpdateTick: 0,
79
+ boundedGeometryMode: false,
56
80
  pendingColorUpdates: null,
57
81
  pendingMeshColorUpdates: null,
58
82
 
59
83
  // Actions
60
- setIfcDataStore: (ifcDataStore) => set({ ifcDataStore }),
84
+ setIfcDataStore: (ifcDataStore) => set((state) => {
85
+ const modelId = state.activeModelId;
86
+ if (!modelId) {
87
+ return { ifcDataStore };
88
+ }
89
+
90
+ const model = state.models.get(modelId);
91
+ if (!model) {
92
+ return { ifcDataStore };
93
+ }
94
+
95
+ const models = new Map(state.models);
96
+ models.set(modelId, { ...model, ifcDataStore });
97
+ return { ifcDataStore, models };
98
+ }),
61
99
 
62
- setGeometryResult: (geometryResult) => set({ geometryResult }),
100
+ setGeometryResult: (geometryResult) => set((state) => {
101
+ const modelId = state.activeModelId;
102
+ if (!modelId) {
103
+ return { geometryResult, geometryUpdateTick: state.geometryUpdateTick + 1 };
104
+ }
105
+
106
+ const model = state.models.get(modelId);
107
+ if (!model) {
108
+ return { geometryResult, geometryUpdateTick: state.geometryUpdateTick + 1 };
109
+ }
110
+
111
+ const models = new Map(state.models);
112
+ models.set(modelId, { ...model, geometryResult });
113
+ return { geometryResult, models, geometryUpdateTick: state.geometryUpdateTick + 1 };
114
+ }),
115
+
116
+ setBoundedGeometryMode: (boundedGeometryMode) => set({ boundedGeometryMode }),
63
117
 
64
118
  appendGeometryBatch: (meshes, coordinateInfo) => set((state) => {
65
119
  // Incremental totals: O(batch_size) instead of O(total_accumulated) .reduce()
@@ -71,33 +125,81 @@ export const createDataSlice: StateCreator<DataSlice, [], [], DataSlice> = (set)
71
125
  }
72
126
 
73
127
  if (!state.geometryResult) {
74
- return {
75
- geometryResult: {
76
- meshes: meshes.slice(),
77
- totalTriangles: batchTriangles,
78
- totalVertices: batchVertices,
79
- coordinateInfo: coordinateInfo || getDefaultCoordinateInfo(),
80
- },
128
+ const geometryResult = {
129
+ meshes: meshes.slice(),
130
+ totalTriangles: batchTriangles,
131
+ totalVertices: batchVertices,
132
+ coordinateInfo: coordinateInfo || getDefaultCoordinateInfo(),
81
133
  };
134
+ const modelId = state.activeModelId;
135
+ if (!modelId) {
136
+ return { geometryResult, geometryUpdateTick: state.geometryUpdateTick + 1 };
137
+ }
138
+ const model = state.models.get(modelId);
139
+ if (!model) {
140
+ return { geometryResult, geometryUpdateTick: state.geometryUpdateTick + 1 };
141
+ }
142
+ const models = new Map(state.models);
143
+ models.set(modelId, { ...model, geometryResult });
144
+ return { geometryResult, models, geometryUpdateTick: state.geometryUpdateTick + 1 };
82
145
  }
83
146
 
84
- // PERF FIX: Push into existing array O(batch_size) instead of O(total).
85
- // The old [...old, ...new] spread copied ALL accumulated meshes every batch,
86
- // causing O(N²) total work (e.g., 176K meshes × 350 batches = 31M copies).
87
- // Zustand detects changes via the new geometryResult object reference below.
88
- const existing = state.geometryResult.meshes;
147
+ // Mutate the existing array in-place (O(batch) per append) instead of
148
+ // .concat() (O(total) per append) to avoid O(N²) for large files.
149
+ // The new geometryResult object reference below is sufficient for
150
+ // Zustand/React change detection array identity doesn't need to change.
151
+ const existingMeshes = state.geometryResult.meshes;
89
152
  for (let i = 0; i < meshes.length; i++) {
90
- existing.push(meshes[i]);
153
+ existingMeshes.push(meshes[i]);
91
154
  }
92
155
 
93
- return {
94
- geometryResult: {
95
- ...state.geometryResult,
96
- totalTriangles: state.geometryResult.totalTriangles + batchTriangles,
97
- totalVertices: state.geometryResult.totalVertices + batchVertices,
98
- coordinateInfo: coordinateInfo || state.geometryResult.coordinateInfo,
99
- },
156
+ const geometryResult = {
157
+ ...state.geometryResult,
158
+ meshes: existingMeshes,
159
+ totalTriangles: state.geometryResult.totalTriangles + batchTriangles,
160
+ totalVertices: state.geometryResult.totalVertices + batchVertices,
161
+ coordinateInfo: coordinateInfo || state.geometryResult.coordinateInfo,
162
+ };
163
+ const modelId = state.activeModelId;
164
+ if (!modelId) {
165
+ return { geometryResult, geometryUpdateTick: state.geometryUpdateTick + 1 };
166
+ }
167
+ const model = state.models.get(modelId);
168
+ if (!model) {
169
+ return { geometryResult, geometryUpdateTick: state.geometryUpdateTick + 1 };
170
+ }
171
+ const models = new Map(state.models);
172
+ models.set(modelId, { ...model, geometryResult });
173
+ return { geometryResult, models, geometryUpdateTick: state.geometryUpdateTick + 1 };
174
+ }),
175
+
176
+ releaseGeometryMemory: () => set((state) => {
177
+ if (!state.geometryResult || !state.boundedGeometryMode) {
178
+ return {};
179
+ }
180
+
181
+ const meshes = state.geometryResult.meshes;
182
+ for (let i = 0; i < meshes.length; i++) {
183
+ meshes[i].positions = EMPTY_POSITIONS;
184
+ meshes[i].normals = EMPTY_NORMALS;
185
+ meshes[i].indices = EMPTY_INDICES;
186
+ }
187
+
188
+ const geometryResult = {
189
+ ...state.geometryResult,
190
+ meshes,
100
191
  };
192
+ const modelId = state.activeModelId;
193
+ if (!modelId) {
194
+ return { geometryResult, geometryUpdateTick: state.geometryUpdateTick + 1 };
195
+ }
196
+ const model = state.models.get(modelId);
197
+ if (!model) {
198
+ return { geometryResult, geometryUpdateTick: state.geometryUpdateTick + 1 };
199
+ }
200
+ const models = new Map(state.models);
201
+ models.set(modelId, { ...model, geometryResult });
202
+ return { geometryResult, models, geometryUpdateTick: state.geometryUpdateTick + 1 };
101
203
  }),
102
204
 
103
205
  updateMeshColors: (updates) => set((state) => {
@@ -136,11 +238,20 @@ export const createDataSlice: StateCreator<DataSlice, [], [], DataSlice> = (set)
136
238
 
137
239
  updateCoordinateInfo: (coordinateInfo) => set((state) => {
138
240
  if (!state.geometryResult) return {};
139
- return {
140
- geometryResult: {
141
- ...state.geometryResult,
142
- coordinateInfo,
143
- },
241
+ const geometryResult = {
242
+ ...state.geometryResult,
243
+ coordinateInfo,
144
244
  };
245
+ const modelId = state.activeModelId;
246
+ if (!modelId) {
247
+ return { geometryResult, geometryUpdateTick: state.geometryUpdateTick + 1 };
248
+ }
249
+ const model = state.models.get(modelId);
250
+ if (!model) {
251
+ return { geometryResult, geometryUpdateTick: state.geometryUpdateTick + 1 };
252
+ }
253
+ const models = new Map(state.models);
254
+ models.set(modelId, { ...model, geometryResult });
255
+ return { geometryResult, models, geometryUpdateTick: state.geometryUpdateTick + 1 };
145
256
  }),
146
257
  });
@@ -0,0 +1,86 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+
5
+ import type { StateCreator } from 'zustand';
6
+ import {
7
+ getDefaultDesktopEntitlement,
8
+ type DesktopEntitlement,
9
+ type DesktopEntitlementSource,
10
+ type DesktopEntitlementStatus,
11
+ } from '@/lib/desktop-product';
12
+
13
+ const STORAGE_KEY = 'ifc-lite:desktop-entitlement:v1';
14
+
15
+ function sanitizeTimestamp(value: unknown): number | null {
16
+ return typeof value === 'number' && Number.isFinite(value) ? value : null;
17
+ }
18
+
19
+ function parseStoredEntitlement(raw: string | null): DesktopEntitlement {
20
+ if (!raw) {
21
+ return getDefaultDesktopEntitlement();
22
+ }
23
+
24
+ try {
25
+ const parsed = JSON.parse(raw) as Partial<DesktopEntitlement> | null;
26
+ const fallback = getDefaultDesktopEntitlement();
27
+ return {
28
+ tier: parsed?.tier === 'pro' ? 'pro' : 'free',
29
+ status: isEntitlementStatus(parsed?.status) ? parsed.status : fallback.status,
30
+ source: isEntitlementSource(parsed?.source) ? parsed.source : fallback.source,
31
+ userId: typeof parsed?.userId === 'string' ? parsed.userId : null,
32
+ validatedAt: sanitizeTimestamp(parsed?.validatedAt),
33
+ graceUntil: sanitizeTimestamp(parsed?.graceUntil),
34
+ trialEndsAt: sanitizeTimestamp(parsed?.trialEndsAt),
35
+ };
36
+ } catch {
37
+ return getDefaultDesktopEntitlement();
38
+ }
39
+ }
40
+
41
+ function isEntitlementStatus(value: unknown): value is DesktopEntitlementStatus {
42
+ return value === 'anonymous'
43
+ || value === 'signed_out'
44
+ || value === 'active'
45
+ || value === 'trial'
46
+ || value === 'expired'
47
+ || value === 'grace_offline';
48
+ }
49
+
50
+ function isEntitlementSource(value: unknown): value is DesktopEntitlementSource {
51
+ return value === 'anonymous' || value === 'clerk_claims' || value === 'cached';
52
+ }
53
+
54
+ function persistEntitlement(entitlement: DesktopEntitlement): void {
55
+ try {
56
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(entitlement));
57
+ } catch {
58
+ // ignore storage failures
59
+ }
60
+ }
61
+
62
+ export interface DesktopEntitlementSlice {
63
+ desktopEntitlement: DesktopEntitlement;
64
+ setDesktopEntitlement: (entitlement: DesktopEntitlement) => void;
65
+ clearDesktopEntitlement: () => void;
66
+ }
67
+
68
+ export const createDesktopEntitlementSlice: StateCreator<
69
+ DesktopEntitlementSlice,
70
+ [],
71
+ [],
72
+ DesktopEntitlementSlice
73
+ > = (set) => ({
74
+ desktopEntitlement: parseStoredEntitlement(typeof localStorage === 'undefined' ? null : localStorage.getItem(STORAGE_KEY)),
75
+
76
+ setDesktopEntitlement: (desktopEntitlement) => {
77
+ persistEntitlement(desktopEntitlement);
78
+ set({ desktopEntitlement });
79
+ },
80
+
81
+ clearDesktopEntitlement: () => {
82
+ const next = getDefaultDesktopEntitlement();
83
+ persistEntitlement(next);
84
+ set({ desktopEntitlement: next });
85
+ },
86
+ });
@@ -11,23 +11,35 @@ import type { StateCreator } from 'zustand';
11
11
  export interface LoadingSlice {
12
12
  // State
13
13
  loading: boolean;
14
- progress: { phase: string; percent: number } | null;
14
+ geometryStreamingActive: boolean;
15
+ progress: { phase: string; percent: number; indeterminate?: boolean } | null;
16
+ geometryProgress: { phase: string; percent: number; indeterminate?: boolean } | null;
17
+ metadataProgress: { phase: string; percent: number; indeterminate?: boolean } | null;
15
18
  error: string | null;
16
19
 
17
20
  // Actions
18
21
  setLoading: (loading: boolean) => void;
19
- setProgress: (progress: { phase: string; percent: number } | null) => void;
22
+ setGeometryStreamingActive: (active: boolean) => void;
23
+ setProgress: (progress: { phase: string; percent: number; indeterminate?: boolean } | null) => void;
24
+ setGeometryProgress: (progress: { phase: string; percent: number; indeterminate?: boolean } | null) => void;
25
+ setMetadataProgress: (progress: { phase: string; percent: number; indeterminate?: boolean } | null) => void;
20
26
  setError: (error: string | null) => void;
21
27
  }
22
28
 
23
29
  export const createLoadingSlice: StateCreator<LoadingSlice, [], [], LoadingSlice> = (set) => ({
24
30
  // Initial state
25
31
  loading: false,
32
+ geometryStreamingActive: false,
26
33
  progress: null,
34
+ geometryProgress: null,
35
+ metadataProgress: null,
27
36
  error: null,
28
37
 
29
38
  // Actions
30
39
  setLoading: (loading) => set({ loading }),
40
+ setGeometryStreamingActive: (geometryStreamingActive) => set({ geometryStreamingActive }),
31
41
  setProgress: (progress) => set({ progress }),
42
+ setGeometryProgress: (geometryProgress) => set({ geometryProgress }),
43
+ setMetadataProgress: (metadataProgress) => set({ metadataProgress }),
32
44
  setError: (error) => set({ error }),
33
45
  });
@@ -25,6 +25,10 @@ export interface ModelSlice {
25
25
  // Actions
26
26
  /** Add a new model to the federation */
27
27
  addModel: (model: FederatedModel) => void;
28
+ /** Add or merge a model in place */
29
+ upsertModel: (model: FederatedModel) => void;
30
+ /** Update an existing model with partial fields */
31
+ updateModel: (modelId: string, patch: Partial<FederatedModel>) => void;
28
32
  /** Remove a model from the federation */
29
33
  removeModel: (modelId: string) => void;
30
34
  /** Clear all models */
@@ -81,7 +85,12 @@ export const createModelSlice: StateCreator<ModelSlice, [], [], ModelSlice> = (s
81
85
  // If first model, make it active
82
86
  // If adding more models, collapse all existing by default
83
87
  if (state.models.size === 0) {
84
- return { models: newModels, activeModelId: model.id };
88
+ return {
89
+ models: newModels,
90
+ activeModelId: model.id,
91
+ ifcDataStore: model.ifcDataStore ?? null,
92
+ geometryResult: model.geometryResult ?? null,
93
+ };
85
94
  } else {
86
95
  // Collapse existing models when adding new ones
87
96
  for (const [id, m] of newModels) {
@@ -93,6 +102,36 @@ export const createModelSlice: StateCreator<ModelSlice, [], [], ModelSlice> = (s
93
102
  }
94
103
  }),
95
104
 
105
+ upsertModel: (model) => set((state) => {
106
+ const newModels = new Map(state.models);
107
+ const existing = newModels.get(model.id);
108
+ newModels.set(model.id, existing ? { ...existing, ...model } : model);
109
+ const activeModelId = state.activeModelId ?? model.id;
110
+ const activeModel = newModels.get(activeModelId) ?? null;
111
+
112
+ return {
113
+ models: newModels,
114
+ activeModelId,
115
+ ifcDataStore: activeModel?.ifcDataStore ?? null,
116
+ geometryResult: activeModel?.geometryResult ?? null,
117
+ };
118
+ }),
119
+
120
+ updateModel: (modelId, patch) => set((state) => {
121
+ const model = state.models.get(modelId);
122
+ if (!model) return {};
123
+
124
+ const updatedModel = { ...model, ...patch };
125
+ const newModels = new Map(state.models);
126
+ newModels.set(modelId, updatedModel);
127
+
128
+ return {
129
+ models: newModels,
130
+ ifcDataStore: state.activeModelId === modelId ? updatedModel.ifcDataStore : state.ifcDataStore,
131
+ geometryResult: state.activeModelId === modelId ? updatedModel.geometryResult : state.geometryResult,
132
+ };
133
+ }),
134
+
96
135
  removeModel: (modelId) => set((state) => {
97
136
  const newModels = new Map(state.models);
98
137
  newModels.delete(modelId);
@@ -107,7 +146,14 @@ export const createModelSlice: StateCreator<ModelSlice, [], [], ModelSlice> = (s
107
146
  newActiveId = remaining.length > 0 ? remaining[0] : null;
108
147
  }
109
148
 
110
- return { models: newModels, activeModelId: newActiveId };
149
+ const activeModel = newActiveId ? newModels.get(newActiveId) : null;
150
+
151
+ return {
152
+ models: newModels,
153
+ activeModelId: newActiveId,
154
+ ifcDataStore: activeModel?.ifcDataStore ?? null,
155
+ geometryResult: activeModel?.geometryResult ?? null,
156
+ };
111
157
  }),
112
158
 
113
159
  clearAllModels: () => {
@@ -116,10 +162,19 @@ export const createModelSlice: StateCreator<ModelSlice, [], [], ModelSlice> = (s
116
162
  return set({
117
163
  models: new Map(),
118
164
  activeModelId: null,
165
+ ifcDataStore: null,
166
+ geometryResult: null,
119
167
  });
120
168
  },
121
169
 
122
- setActiveModel: (modelId) => set({ activeModelId: modelId }),
170
+ setActiveModel: (modelId) => set((state) => {
171
+ const activeModel = modelId ? state.models.get(modelId) : null;
172
+ return {
173
+ activeModelId: modelId,
174
+ ifcDataStore: activeModel?.ifcDataStore ?? null,
175
+ geometryResult: activeModel?.geometryResult ?? null,
176
+ };
177
+ }),
123
178
 
124
179
  setModelVisibility: (modelId, visible) => set((state) => {
125
180
  const model = state.models.get(modelId);