@crystaldesign/real-time-viewer-next 26.11.0-beta.18

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 (529) hide show
  1. package/build/esm/DeckCutoutSubsystem-76dfe828.js +2536 -0
  2. package/build/esm/SunLensflare-e4ab3f81.js +483 -0
  3. package/build/esm/WaterSurface-93383fdf.js +2041 -0
  4. package/build/esm/index-920dd901.js +23273 -0
  5. package/build/esm/index.js +32 -0
  6. package/build/types/real-time-viewer-next/src/RealTimeRendererNext.d.ts +58 -0
  7. package/build/types/real-time-viewer-next/src/RealTimeRendererNext.d.ts.map +1 -0
  8. package/build/types/real-time-viewer-next/src/analyzerComponents.d.ts +23 -0
  9. package/build/types/real-time-viewer-next/src/analyzerComponents.d.ts.map +1 -0
  10. package/build/types/real-time-viewer-next/src/analyzerStageContext.d.ts +9 -0
  11. package/build/types/real-time-viewer-next/src/analyzerStageContext.d.ts.map +1 -0
  12. package/build/types/real-time-viewer-next/src/capture/applyShot.d.ts +8 -0
  13. package/build/types/real-time-viewer-next/src/capture/applyShot.d.ts.map +1 -0
  14. package/build/types/real-time-viewer-next/src/capture/blob.d.ts +11 -0
  15. package/build/types/real-time-viewer-next/src/capture/blob.d.ts.map +1 -0
  16. package/build/types/real-time-viewer-next/src/capture/materialMute.d.ts +16 -0
  17. package/build/types/real-time-viewer-next/src/capture/materialMute.d.ts.map +1 -0
  18. package/build/types/real-time-viewer-next/src/capture/shotState.d.ts +24 -0
  19. package/build/types/real-time-viewer-next/src/capture/shotState.d.ts.map +1 -0
  20. package/build/types/real-time-viewer-next/src/capture/types.d.ts +80 -0
  21. package/build/types/real-time-viewer-next/src/capture/types.d.ts.map +1 -0
  22. package/build/types/real-time-viewer-next/src/capture/useCaptureEngine.d.ts +7 -0
  23. package/build/types/real-time-viewer-next/src/capture/useCaptureEngine.d.ts.map +1 -0
  24. package/build/types/real-time-viewer-next/src/config/descriptor.d.ts +156 -0
  25. package/build/types/real-time-viewer-next/src/config/descriptor.d.ts.map +1 -0
  26. package/build/types/real-time-viewer-next/src/config/descriptor.test.d.ts +2 -0
  27. package/build/types/real-time-viewer-next/src/config/descriptor.test.d.ts.map +1 -0
  28. package/build/types/real-time-viewer-next/src/config/environment.config.d.ts +511 -0
  29. package/build/types/real-time-viewer-next/src/config/environment.config.d.ts.map +1 -0
  30. package/build/types/real-time-viewer-next/src/config/environment.config.test.d.ts +5 -0
  31. package/build/types/real-time-viewer-next/src/config/environment.config.test.d.ts.map +1 -0
  32. package/build/types/real-time-viewer-next/src/core/BBoxPreloader.d.ts +15 -0
  33. package/build/types/real-time-viewer-next/src/core/BBoxPreloader.d.ts.map +1 -0
  34. package/build/types/real-time-viewer-next/src/core/FloorGrid.d.ts +3 -0
  35. package/build/types/real-time-viewer-next/src/core/FloorGrid.d.ts.map +1 -0
  36. package/build/types/real-time-viewer-next/src/core/GeoBBoxReporter.d.ts +10 -0
  37. package/build/types/real-time-viewer-next/src/core/GeoBBoxReporter.d.ts.map +1 -0
  38. package/build/types/real-time-viewer-next/src/core/GeoInstance.d.ts +13 -0
  39. package/build/types/real-time-viewer-next/src/core/GeoInstance.d.ts.map +1 -0
  40. package/build/types/real-time-viewer-next/src/core/PaletteDragPreview.d.ts +19 -0
  41. package/build/types/real-time-viewer-next/src/core/PaletteDragPreview.d.ts.map +1 -0
  42. package/build/types/real-time-viewer-next/src/core/PerfLog.d.ts +38 -0
  43. package/build/types/real-time-viewer-next/src/core/PerfLog.d.ts.map +1 -0
  44. package/build/types/real-time-viewer-next/src/core/PlannerGrid.d.ts +83 -0
  45. package/build/types/real-time-viewer-next/src/core/PlannerGrid.d.ts.map +1 -0
  46. package/build/types/real-time-viewer-next/src/core/R3FAssetBoundary.d.ts +31 -0
  47. package/build/types/real-time-viewer-next/src/core/R3FAssetBoundary.d.ts.map +1 -0
  48. package/build/types/real-time-viewer-next/src/core/RTVErrorBoundary.d.ts +16 -0
  49. package/build/types/real-time-viewer-next/src/core/RTVErrorBoundary.d.ts.map +1 -0
  50. package/build/types/real-time-viewer-next/src/core/SceneRenderer.d.ts +3 -0
  51. package/build/types/real-time-viewer-next/src/core/SceneRenderer.d.ts.map +1 -0
  52. package/build/types/real-time-viewer-next/src/core/SceneTree.d.ts +16 -0
  53. package/build/types/real-time-viewer-next/src/core/SceneTree.d.ts.map +1 -0
  54. package/build/types/real-time-viewer-next/src/core/VariantMeshOverride.d.ts +62 -0
  55. package/build/types/real-time-viewer-next/src/core/VariantMeshOverride.d.ts.map +1 -0
  56. package/build/types/real-time-viewer-next/src/core/camera/CameraController.d.ts +3 -0
  57. package/build/types/real-time-viewer-next/src/core/camera/CameraController.d.ts.map +1 -0
  58. package/build/types/real-time-viewer-next/src/core/camera/cameraAnimationEngine.d.ts +69 -0
  59. package/build/types/real-time-viewer-next/src/core/camera/cameraAnimationEngine.d.ts.map +1 -0
  60. package/build/types/real-time-viewer-next/src/core/camera/cameraPoseBook.d.ts +24 -0
  61. package/build/types/real-time-viewer-next/src/core/camera/cameraPoseBook.d.ts.map +1 -0
  62. package/build/types/real-time-viewer-next/src/core/camera/controlsLock.d.ts +25 -0
  63. package/build/types/real-time-viewer-next/src/core/camera/controlsLock.d.ts.map +1 -0
  64. package/build/types/real-time-viewer-next/src/core/camera/sectorLimits.d.ts +38 -0
  65. package/build/types/real-time-viewer-next/src/core/camera/sectorLimits.d.ts.map +1 -0
  66. package/build/types/real-time-viewer-next/src/core/camera/sectorLimits.test.d.ts +2 -0
  67. package/build/types/real-time-viewer-next/src/core/camera/sectorLimits.test.d.ts.map +1 -0
  68. package/build/types/real-time-viewer-next/src/core/camera/useAutoFrame.d.ts +29 -0
  69. package/build/types/real-time-viewer-next/src/core/camera/useAutoFrame.d.ts.map +1 -0
  70. package/build/types/real-time-viewer-next/src/core/camera/useAutoRotate.d.ts +8 -0
  71. package/build/types/real-time-viewer-next/src/core/camera/useAutoRotate.d.ts.map +1 -0
  72. package/build/types/real-time-viewer-next/src/core/camera/useCameraActions.d.ts +13 -0
  73. package/build/types/real-time-viewer-next/src/core/camera/useCameraActions.d.ts.map +1 -0
  74. package/build/types/real-time-viewer-next/src/core/camera/useCameraAnimation.d.ts +15 -0
  75. package/build/types/real-time-viewer-next/src/core/camera/useCameraAnimation.d.ts.map +1 -0
  76. package/build/types/real-time-viewer-next/src/core/camera/useCameraConstraints.d.ts +25 -0
  77. package/build/types/real-time-viewer-next/src/core/camera/useCameraConstraints.d.ts.map +1 -0
  78. package/build/types/real-time-viewer-next/src/core/camera/useCameraSmoothing.d.ts +57 -0
  79. package/build/types/real-time-viewer-next/src/core/camera/useCameraSmoothing.d.ts.map +1 -0
  80. package/build/types/real-time-viewer-next/src/core/camera/useMaterialFade.d.ts +5 -0
  81. package/build/types/real-time-viewer-next/src/core/camera/useMaterialFade.d.ts.map +1 -0
  82. package/build/types/real-time-viewer-next/src/core/camera/useViewModeTransition.d.ts +19 -0
  83. package/build/types/real-time-viewer-next/src/core/camera/useViewModeTransition.d.ts.map +1 -0
  84. package/build/types/real-time-viewer-next/src/core/dimension-lines/DimensionLine2D.d.ts +28 -0
  85. package/build/types/real-time-viewer-next/src/core/dimension-lines/DimensionLine2D.d.ts.map +1 -0
  86. package/build/types/real-time-viewer-next/src/core/dimension-lines/DimensionLines2D.d.ts +3 -0
  87. package/build/types/real-time-viewer-next/src/core/dimension-lines/DimensionLines2D.d.ts.map +1 -0
  88. package/build/types/real-time-viewer-next/src/core/dimension-lines/DimensionLines3D.d.ts +3 -0
  89. package/build/types/real-time-viewer-next/src/core/dimension-lines/DimensionLines3D.d.ts.map +1 -0
  90. package/build/types/real-time-viewer-next/src/core/dimension-lines/dimensionGeometry.d.ts +34 -0
  91. package/build/types/real-time-viewer-next/src/core/dimension-lines/dimensionGeometry.d.ts.map +1 -0
  92. package/build/types/real-time-viewer-next/src/core/dimension-lines/dimensionLineBuilders.test.d.ts +2 -0
  93. package/build/types/real-time-viewer-next/src/core/dimension-lines/dimensionLineBuilders.test.d.ts.map +1 -0
  94. package/build/types/real-time-viewer-next/src/core/dimension-lines/dimensionLineBuilders2D.d.ts +82 -0
  95. package/build/types/real-time-viewer-next/src/core/dimension-lines/dimensionLineBuilders2D.d.ts.map +1 -0
  96. package/build/types/real-time-viewer-next/src/core/dimension-lines/dimensionLineBuilders3D.d.ts +76 -0
  97. package/build/types/real-time-viewer-next/src/core/dimension-lines/dimensionLineBuilders3D.d.ts.map +1 -0
  98. package/build/types/real-time-viewer-next/src/core/dimension-lines/dimensionLines.config.d.ts +25 -0
  99. package/build/types/real-time-viewer-next/src/core/dimension-lines/dimensionLines.config.d.ts.map +1 -0
  100. package/build/types/real-time-viewer-next/src/core/dimension-lines/dimensionLines.config.test.d.ts +2 -0
  101. package/build/types/real-time-viewer-next/src/core/dimension-lines/dimensionLines.config.test.d.ts.map +1 -0
  102. package/build/types/real-time-viewer-next/src/core/dimension-lines/index.d.ts +3 -0
  103. package/build/types/real-time-viewer-next/src/core/dimension-lines/index.d.ts.map +1 -0
  104. package/build/types/real-time-viewer-next/src/core/dimension-lines/useDimensionFade.d.ts +12 -0
  105. package/build/types/real-time-viewer-next/src/core/dimension-lines/useDimensionFade.d.ts.map +1 -0
  106. package/build/types/real-time-viewer-next/src/core/dimension-lines/useLabelScale.d.ts +11 -0
  107. package/build/types/real-time-viewer-next/src/core/dimension-lines/useLabelScale.d.ts.map +1 -0
  108. package/build/types/real-time-viewer-next/src/core/dimension-lines/utils.d.ts +26 -0
  109. package/build/types/real-time-viewer-next/src/core/dimension-lines/utils.d.ts.map +1 -0
  110. package/build/types/real-time-viewer-next/src/core/environment/EnvironmentDome.d.ts +14 -0
  111. package/build/types/real-time-viewer-next/src/core/environment/EnvironmentDome.d.ts.map +1 -0
  112. package/build/types/real-time-viewer-next/src/core/environment/EnvironmentSceneLoader.d.ts +14 -0
  113. package/build/types/real-time-viewer-next/src/core/environment/EnvironmentSceneLoader.d.ts.map +1 -0
  114. package/build/types/real-time-viewer-next/src/core/environment/EnvironmentSources.d.ts +33 -0
  115. package/build/types/real-time-viewer-next/src/core/environment/EnvironmentSources.d.ts.map +1 -0
  116. package/build/types/real-time-viewer-next/src/core/environment/EnvironmentSunLensflare.d.ts +3 -0
  117. package/build/types/real-time-viewer-next/src/core/environment/EnvironmentSunLensflare.d.ts.map +1 -0
  118. package/build/types/real-time-viewer-next/src/core/environment/LightingRig.d.ts +28 -0
  119. package/build/types/real-time-viewer-next/src/core/environment/LightingRig.d.ts.map +1 -0
  120. package/build/types/real-time-viewer-next/src/core/environment/PlainGround.d.ts +21 -0
  121. package/build/types/real-time-viewer-next/src/core/environment/PlainGround.d.ts.map +1 -0
  122. package/build/types/real-time-viewer-next/src/core/environment/RuntimePerfAdjuster.d.ts +15 -0
  123. package/build/types/real-time-viewer-next/src/core/environment/RuntimePerfAdjuster.d.ts.map +1 -0
  124. package/build/types/real-time-viewer-next/src/core/environment/SceneEnvironment.d.ts +19 -0
  125. package/build/types/real-time-viewer-next/src/core/environment/SceneEnvironment.d.ts.map +1 -0
  126. package/build/types/real-time-viewer-next/src/core/environment/SkydomeBackground.d.ts +11 -0
  127. package/build/types/real-time-viewer-next/src/core/environment/SkydomeBackground.d.ts.map +1 -0
  128. package/build/types/real-time-viewer-next/src/core/environment/SunLensflare.d.ts +29 -0
  129. package/build/types/real-time-viewer-next/src/core/environment/SunLensflare.d.ts.map +1 -0
  130. package/build/types/real-time-viewer-next/src/core/environment/SunLensflareLazy.d.ts +11 -0
  131. package/build/types/real-time-viewer-next/src/core/environment/SunLensflareLazy.d.ts.map +1 -0
  132. package/build/types/real-time-viewer-next/src/core/environment/adaptive.config.d.ts +24 -0
  133. package/build/types/real-time-viewer-next/src/core/environment/adaptive.config.d.ts.map +1 -0
  134. package/build/types/real-time-viewer-next/src/core/environment/adaptive.config.test.d.ts +2 -0
  135. package/build/types/real-time-viewer-next/src/core/environment/adaptive.config.test.d.ts.map +1 -0
  136. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/DeckCutoutArticleSync.d.ts +22 -0
  137. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/DeckCutoutArticleSync.d.ts.map +1 -0
  138. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/DeckCutoutCollar.d.ts +15 -0
  139. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/DeckCutoutCollar.d.ts.map +1 -0
  140. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/DeckCutoutLazy.d.ts +10 -0
  141. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/DeckCutoutLazy.d.ts.map +1 -0
  142. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/DeckCutoutSubsystem.d.ts +9 -0
  143. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/DeckCutoutSubsystem.d.ts.map +1 -0
  144. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/anchorElements.d.ts +40 -0
  145. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/anchorElements.d.ts.map +1 -0
  146. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/anchorElements.test.d.ts +2 -0
  147. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/anchorElements.test.d.ts.map +1 -0
  148. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/articleFootprint.d.ts +62 -0
  149. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/articleFootprint.d.ts.map +1 -0
  150. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/articleFootprint.test.d.ts +2 -0
  151. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/articleFootprint.test.d.ts.map +1 -0
  152. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/buildCollarGeometry.d.ts +25 -0
  153. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/buildCollarGeometry.d.ts.map +1 -0
  154. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/buildCollarGeometry.test.d.ts +2 -0
  155. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/buildCollarGeometry.test.d.ts.map +1 -0
  156. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/collectDeckTriangles.d.ts +86 -0
  157. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/collectDeckTriangles.d.ts.map +1 -0
  158. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/deriveWaterVolume.d.ts +28 -0
  159. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/deriveWaterVolume.d.ts.map +1 -0
  160. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/deriveWaterVolume.test.d.ts +2 -0
  161. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/deriveWaterVolume.test.d.ts.map +1 -0
  162. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/measureArticle.d.ts +49 -0
  163. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/measureArticle.d.ts.map +1 -0
  164. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/measureArticle.test.d.ts +2 -0
  165. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/measureArticle.test.d.ts.map +1 -0
  166. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/measureDiagnostics.d.ts +20 -0
  167. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/measureDiagnostics.d.ts.map +1 -0
  168. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/useCollarTextures.d.ts +16 -0
  169. package/build/types/real-time-viewer-next/src/core/environment/deckCutout/useCollarTextures.d.ts.map +1 -0
  170. package/build/types/real-time-viewer-next/src/core/environment/dome.config.d.ts +191 -0
  171. package/build/types/real-time-viewer-next/src/core/environment/dome.config.d.ts.map +1 -0
  172. package/build/types/real-time-viewer-next/src/core/environment/dome.config.test.d.ts +2 -0
  173. package/build/types/real-time-viewer-next/src/core/environment/dome.config.test.d.ts.map +1 -0
  174. package/build/types/real-time-viewer-next/src/core/environment/ground.config.d.ts +130 -0
  175. package/build/types/real-time-viewer-next/src/core/environment/ground.config.d.ts.map +1 -0
  176. package/build/types/real-time-viewer-next/src/core/environment/ground.config.test.d.ts +2 -0
  177. package/build/types/real-time-viewer-next/src/core/environment/ground.config.test.d.ts.map +1 -0
  178. package/build/types/real-time-viewer-next/src/core/environment/lighting.config.d.ts +297 -0
  179. package/build/types/real-time-viewer-next/src/core/environment/lighting.config.d.ts.map +1 -0
  180. package/build/types/real-time-viewer-next/src/core/environment/lighting.config.test.d.ts +2 -0
  181. package/build/types/real-time-viewer-next/src/core/environment/lighting.config.test.d.ts.map +1 -0
  182. package/build/types/real-time-viewer-next/src/core/environment/scene.config.d.ts +440 -0
  183. package/build/types/real-time-viewer-next/src/core/environment/scene.config.d.ts.map +1 -0
  184. package/build/types/real-time-viewer-next/src/core/environment/scene.config.test.d.ts +2 -0
  185. package/build/types/real-time-viewer-next/src/core/environment/scene.config.test.d.ts.map +1 -0
  186. package/build/types/real-time-viewer-next/src/core/environment/useEnvironmentMap.d.ts +19 -0
  187. package/build/types/real-time-viewer-next/src/core/environment/useEnvironmentMap.d.ts.map +1 -0
  188. package/build/types/real-time-viewer-next/src/core/environment/useStudioLightEffects.d.ts +28 -0
  189. package/build/types/real-time-viewer-next/src/core/environment/useStudioLightEffects.d.ts.map +1 -0
  190. package/build/types/real-time-viewer-next/src/core/frameOrder.d.ts +91 -0
  191. package/build/types/real-time-viewer-next/src/core/frameOrder.d.ts.map +1 -0
  192. package/build/types/real-time-viewer-next/src/core/handles.d.ts +35 -0
  193. package/build/types/real-time-viewer-next/src/core/handles.d.ts.map +1 -0
  194. package/build/types/real-time-viewer-next/src/core/interaction/AccessoryDropController.d.ts +9 -0
  195. package/build/types/real-time-viewer-next/src/core/interaction/AccessoryDropController.d.ts.map +1 -0
  196. package/build/types/real-time-viewer-next/src/core/interaction/AccessoryFollowController.d.ts +15 -0
  197. package/build/types/real-time-viewer-next/src/core/interaction/AccessoryFollowController.d.ts.map +1 -0
  198. package/build/types/real-time-viewer-next/src/core/interaction/DragController.d.ts +2 -0
  199. package/build/types/real-time-viewer-next/src/core/interaction/DragController.d.ts.map +1 -0
  200. package/build/types/real-time-viewer-next/src/core/interaction/ElementOverlay.d.ts +16 -0
  201. package/build/types/real-time-viewer-next/src/core/interaction/ElementOverlay.d.ts.map +1 -0
  202. package/build/types/real-time-viewer-next/src/core/interaction/ElementOverlayIcons.d.ts +18 -0
  203. package/build/types/real-time-viewer-next/src/core/interaction/ElementOverlayIcons.d.ts.map +1 -0
  204. package/build/types/real-time-viewer-next/src/core/interaction/FreeGridLayer.d.ts +10 -0
  205. package/build/types/real-time-viewer-next/src/core/interaction/FreeGridLayer.d.ts.map +1 -0
  206. package/build/types/real-time-viewer-next/src/core/interaction/InteractionGuides.d.ts +3 -0
  207. package/build/types/real-time-viewer-next/src/core/interaction/InteractionGuides.d.ts.map +1 -0
  208. package/build/types/real-time-viewer-next/src/core/interaction/accessoryCellTargeting.d.ts +31 -0
  209. package/build/types/real-time-viewer-next/src/core/interaction/accessoryCellTargeting.d.ts.map +1 -0
  210. package/build/types/real-time-viewer-next/src/core/interaction/selection.config.d.ts +65 -0
  211. package/build/types/real-time-viewer-next/src/core/interaction/selection.config.d.ts.map +1 -0
  212. package/build/types/real-time-viewer-next/src/core/interaction/selection.config.test.d.ts +2 -0
  213. package/build/types/real-time-viewer-next/src/core/interaction/selection.config.test.d.ts.map +1 -0
  214. package/build/types/real-time-viewer-next/src/core/interaction/useAccessoryMoveDrag.d.ts +21 -0
  215. package/build/types/real-time-viewer-next/src/core/interaction/useAccessoryMoveDrag.d.ts.map +1 -0
  216. package/build/types/real-time-viewer-next/src/core/interaction/useElementInteraction.d.ts +35 -0
  217. package/build/types/real-time-viewer-next/src/core/interaction/useElementInteraction.d.ts.map +1 -0
  218. package/build/types/real-time-viewer-next/src/core/lazySubsystems.d.ts +16 -0
  219. package/build/types/real-time-viewer-next/src/core/lazySubsystems.d.ts.map +1 -0
  220. package/build/types/real-time-viewer-next/src/core/materials/MaterialContext.d.ts +23 -0
  221. package/build/types/real-time-viewer-next/src/core/materials/MaterialContext.d.ts.map +1 -0
  222. package/build/types/real-time-viewer-next/src/core/materials/MaterialManager.d.ts +4 -0
  223. package/build/types/real-time-viewer-next/src/core/materials/MaterialManager.d.ts.map +1 -0
  224. package/build/types/real-time-viewer-next/src/core/materials/apply.d.ts +17 -0
  225. package/build/types/real-time-viewer-next/src/core/materials/apply.d.ts.map +1 -0
  226. package/build/types/real-time-viewer-next/src/core/materials/caches.d.ts +44 -0
  227. package/build/types/real-time-viewer-next/src/core/materials/caches.d.ts.map +1 -0
  228. package/build/types/real-time-viewer-next/src/core/materials/factory.d.ts +37 -0
  229. package/build/types/real-time-viewer-next/src/core/materials/factory.d.ts.map +1 -0
  230. package/build/types/real-time-viewer-next/src/core/materials/materials.config.d.ts +13 -0
  231. package/build/types/real-time-viewer-next/src/core/materials/materials.config.d.ts.map +1 -0
  232. package/build/types/real-time-viewer-next/src/core/materials/materials.config.test.d.ts +2 -0
  233. package/build/types/real-time-viewer-next/src/core/materials/materials.config.test.d.ts.map +1 -0
  234. package/build/types/real-time-viewer-next/src/core/materials/textureCache.d.ts +26 -0
  235. package/build/types/real-time-viewer-next/src/core/materials/textureCache.d.ts.map +1 -0
  236. package/build/types/real-time-viewer-next/src/core/materials/types.d.ts +5 -0
  237. package/build/types/real-time-viewer-next/src/core/materials/types.d.ts.map +1 -0
  238. package/build/types/real-time-viewer-next/src/core/meshBVH.d.ts +22 -0
  239. package/build/types/real-time-viewer-next/src/core/meshBVH.d.ts.map +1 -0
  240. package/build/types/real-time-viewer-next/src/core/meshBVH.test.d.ts +2 -0
  241. package/build/types/real-time-viewer-next/src/core/meshBVH.test.d.ts.map +1 -0
  242. package/build/types/real-time-viewer-next/src/core/postprocessing/PostProcessingDynamicEffects.d.ts +11 -0
  243. package/build/types/real-time-viewer-next/src/core/postprocessing/PostProcessingDynamicEffects.d.ts.map +1 -0
  244. package/build/types/real-time-viewer-next/src/core/postprocessing/PostProcessingStack.d.ts +28 -0
  245. package/build/types/real-time-viewer-next/src/core/postprocessing/PostProcessingStack.d.ts.map +1 -0
  246. package/build/types/real-time-viewer-next/src/core/postprocessing/applyRendererToneMapping.d.ts +10 -0
  247. package/build/types/real-time-viewer-next/src/core/postprocessing/applyRendererToneMapping.d.ts.map +1 -0
  248. package/build/types/real-time-viewer-next/src/core/postprocessing/index.d.ts +2 -0
  249. package/build/types/real-time-viewer-next/src/core/postprocessing/index.d.ts.map +1 -0
  250. package/build/types/real-time-viewer-next/src/core/postprocessing/postProcessing.config.d.ts +453 -0
  251. package/build/types/real-time-viewer-next/src/core/postprocessing/postProcessing.config.d.ts.map +1 -0
  252. package/build/types/real-time-viewer-next/src/core/postprocessing/postProcessing.config.test.d.ts +2 -0
  253. package/build/types/real-time-viewer-next/src/core/postprocessing/postProcessing.config.test.d.ts.map +1 -0
  254. package/build/types/real-time-viewer-next/src/core/renderer.config.d.ts +55 -0
  255. package/build/types/real-time-viewer-next/src/core/renderer.config.d.ts.map +1 -0
  256. package/build/types/real-time-viewer-next/src/core/renderer.config.test.d.ts +2 -0
  257. package/build/types/real-time-viewer-next/src/core/renderer.config.test.d.ts.map +1 -0
  258. package/build/types/real-time-viewer-next/src/core/shadows/SceneShadowSystem.d.ts +18 -0
  259. package/build/types/real-time-viewer-next/src/core/shadows/SceneShadowSystem.d.ts.map +1 -0
  260. package/build/types/real-time-viewer-next/src/core/shadows/SunShadow.d.ts +29 -0
  261. package/build/types/real-time-viewer-next/src/core/shadows/SunShadow.d.ts.map +1 -0
  262. package/build/types/real-time-viewer-next/src/core/shadows/index.d.ts +4 -0
  263. package/build/types/real-time-viewer-next/src/core/shadows/index.d.ts.map +1 -0
  264. package/build/types/real-time-viewer-next/src/core/shadows/shadowMapSize.d.ts +20 -0
  265. package/build/types/real-time-viewer-next/src/core/shadows/shadowMapSize.d.ts.map +1 -0
  266. package/build/types/real-time-viewer-next/src/core/shadows/shadowMapSize.test.d.ts +2 -0
  267. package/build/types/real-time-viewer-next/src/core/shadows/shadowMapSize.test.d.ts.map +1 -0
  268. package/build/types/real-time-viewer-next/src/core/shadows/shadowRegistry.d.ts +24 -0
  269. package/build/types/real-time-viewer-next/src/core/shadows/shadowRegistry.d.ts.map +1 -0
  270. package/build/types/real-time-viewer-next/src/core/shadows/shadows.config.d.ts +75 -0
  271. package/build/types/real-time-viewer-next/src/core/shadows/shadows.config.d.ts.map +1 -0
  272. package/build/types/real-time-viewer-next/src/core/shadows/shadows.config.test.d.ts +2 -0
  273. package/build/types/real-time-viewer-next/src/core/shadows/shadows.config.test.d.ts.map +1 -0
  274. package/build/types/real-time-viewer-next/src/core/shadows/useShadowDirty.d.ts +14 -0
  275. package/build/types/real-time-viewer-next/src/core/shadows/useShadowDirty.d.ts.map +1 -0
  276. package/build/types/real-time-viewer-next/src/core/shadows/useShadowFlags.d.ts +28 -0
  277. package/build/types/real-time-viewer-next/src/core/shadows/useShadowFlags.d.ts.map +1 -0
  278. package/build/types/real-time-viewer-next/src/core/shadows/useShadowRebake.d.ts +14 -0
  279. package/build/types/real-time-viewer-next/src/core/shadows/useShadowRebake.d.ts.map +1 -0
  280. package/build/types/real-time-viewer-next/src/core/useFrameloopVisibility.d.ts +37 -0
  281. package/build/types/real-time-viewer-next/src/core/useFrameloopVisibility.d.ts.map +1 -0
  282. package/build/types/real-time-viewer-next/src/core/view2d/DockingPoints2D.d.ts +17 -0
  283. package/build/types/real-time-viewer-next/src/core/view2d/DockingPoints2D.d.ts.map +1 -0
  284. package/build/types/real-time-viewer-next/src/core/view2d/Element2DPlane.d.ts +18 -0
  285. package/build/types/real-time-viewer-next/src/core/view2d/Element2DPlane.d.ts.map +1 -0
  286. package/build/types/real-time-viewer-next/src/core/view2d/ElementAnnotation2D.d.ts +16 -0
  287. package/build/types/real-time-viewer-next/src/core/view2d/ElementAnnotation2D.d.ts.map +1 -0
  288. package/build/types/real-time-viewer-next/src/core/view2d/Scene2DOverlay.d.ts +10 -0
  289. package/build/types/real-time-viewer-next/src/core/view2d/Scene2DOverlay.d.ts.map +1 -0
  290. package/build/types/real-time-viewer-next/src/core/viewMode/ViewModeRuntimeContext.d.ts +20 -0
  291. package/build/types/real-time-viewer-next/src/core/viewMode/ViewModeRuntimeContext.d.ts.map +1 -0
  292. package/build/types/real-time-viewer-next/src/core/viewMode/index.d.ts +4 -0
  293. package/build/types/real-time-viewer-next/src/core/viewMode/index.d.ts.map +1 -0
  294. package/build/types/real-time-viewer-next/src/core/viewMode/selectViewModeRuntime.d.ts +9 -0
  295. package/build/types/real-time-viewer-next/src/core/viewMode/selectViewModeRuntime.d.ts.map +1 -0
  296. package/build/types/real-time-viewer-next/src/core/viewMode/selectViewModeRuntime.test.d.ts +2 -0
  297. package/build/types/real-time-viewer-next/src/core/viewMode/selectViewModeRuntime.test.d.ts.map +1 -0
  298. package/build/types/real-time-viewer-next/src/core/viewMode/types.d.ts +67 -0
  299. package/build/types/real-time-viewer-next/src/core/viewMode/types.d.ts.map +1 -0
  300. package/build/types/real-time-viewer-next/src/core/water/CausticReceiver.d.ts +49 -0
  301. package/build/types/real-time-viewer-next/src/core/water/CausticReceiver.d.ts.map +1 -0
  302. package/build/types/real-time-viewer-next/src/core/water/CausticsTexture.d.ts +48 -0
  303. package/build/types/real-time-viewer-next/src/core/water/CausticsTexture.d.ts.map +1 -0
  304. package/build/types/real-time-viewer-next/src/core/water/Heightfield.d.ts +88 -0
  305. package/build/types/real-time-viewer-next/src/core/water/Heightfield.d.ts.map +1 -0
  306. package/build/types/real-time-viewer-next/src/core/water/PoolHeightMap.d.ts +36 -0
  307. package/build/types/real-time-viewer-next/src/core/water/PoolHeightMap.d.ts.map +1 -0
  308. package/build/types/real-time-viewer-next/src/core/water/RefractionCapture.d.ts +73 -0
  309. package/build/types/real-time-viewer-next/src/core/water/RefractionCapture.d.ts.map +1 -0
  310. package/build/types/real-time-viewer-next/src/core/water/RefractionCapture.test.d.ts +2 -0
  311. package/build/types/real-time-viewer-next/src/core/water/RefractionCapture.test.d.ts.map +1 -0
  312. package/build/types/real-time-viewer-next/src/core/water/SceneCapture.d.ts +66 -0
  313. package/build/types/real-time-viewer-next/src/core/water/SceneCapture.d.ts.map +1 -0
  314. package/build/types/real-time-viewer-next/src/core/water/WaterSurface.d.ts +8 -0
  315. package/build/types/real-time-viewer-next/src/core/water/WaterSurface.d.ts.map +1 -0
  316. package/build/types/real-time-viewer-next/src/core/water/WaterSurfaceLazy.d.ts +10 -0
  317. package/build/types/real-time-viewer-next/src/core/water/WaterSurfaceLazy.d.ts.map +1 -0
  318. package/build/types/real-time-viewer-next/src/core/water/WaterSurfaceRenderer.d.ts +71 -0
  319. package/build/types/real-time-viewer-next/src/core/water/WaterSurfaceRenderer.d.ts.map +1 -0
  320. package/build/types/real-time-viewer-next/src/core/water/useCausticReceivers.d.ts +11 -0
  321. package/build/types/real-time-viewer-next/src/core/water/useCausticReceivers.d.ts.map +1 -0
  322. package/build/types/real-time-viewer-next/src/core/water/useWaterPointer.d.ts +13 -0
  323. package/build/types/real-time-viewer-next/src/core/water/useWaterPointer.d.ts.map +1 -0
  324. package/build/types/real-time-viewer-next/src/core/water/useWaveSimulation.d.ts +44 -0
  325. package/build/types/real-time-viewer-next/src/core/water/useWaveSimulation.d.ts.map +1 -0
  326. package/build/types/real-time-viewer-next/src/core/water/useWaveSimulation.test.d.ts +2 -0
  327. package/build/types/real-time-viewer-next/src/core/water/useWaveSimulation.test.d.ts.map +1 -0
  328. package/build/types/real-time-viewer-next/src/core/water/water.config.d.ts +90 -0
  329. package/build/types/real-time-viewer-next/src/core/water/water.config.d.ts.map +1 -0
  330. package/build/types/real-time-viewer-next/src/core/water/water.config.test.d.ts +2 -0
  331. package/build/types/real-time-viewer-next/src/core/water/water.config.test.d.ts.map +1 -0
  332. package/build/types/real-time-viewer-next/src/core/water/waterDebug.d.ts +14 -0
  333. package/build/types/real-time-viewer-next/src/core/water/waterDebug.d.ts.map +1 -0
  334. package/build/types/real-time-viewer-next/src/core/water/waterShaders.d.ts +9 -0
  335. package/build/types/real-time-viewer-next/src/core/water/waterShaders.d.ts.map +1 -0
  336. package/build/types/real-time-viewer-next/src/core/water/waterSurfaceMaterial.d.ts +21 -0
  337. package/build/types/real-time-viewer-next/src/core/water/waterSurfaceMaterial.d.ts.map +1 -0
  338. package/build/types/real-time-viewer-next/src/core/water/waterUniforms.d.ts +51 -0
  339. package/build/types/real-time-viewer-next/src/core/water/waterUniforms.d.ts.map +1 -0
  340. package/build/types/real-time-viewer-next/src/hooks/useAssembledScene.d.ts +17 -0
  341. package/build/types/real-time-viewer-next/src/hooks/useAssembledScene.d.ts.map +1 -0
  342. package/build/types/real-time-viewer-next/src/hooks/useHostPropsSync.d.ts +20 -0
  343. package/build/types/real-time-viewer-next/src/hooks/useHostPropsSync.d.ts.map +1 -0
  344. package/build/types/real-time-viewer-next/src/index.d.ts +17 -0
  345. package/build/types/real-time-viewer-next/src/index.d.ts.map +1 -0
  346. package/build/types/real-time-viewer-next/src/internals.d.ts +61 -0
  347. package/build/types/real-time-viewer-next/src/internals.d.ts.map +1 -0
  348. package/build/types/real-time-viewer-next/src/loadingGates.d.ts +34 -0
  349. package/build/types/real-time-viewer-next/src/loadingGates.d.ts.map +1 -0
  350. package/build/types/real-time-viewer-next/src/parser/parseRenderScript.d.ts +51 -0
  351. package/build/types/real-time-viewer-next/src/parser/parseRenderScript.d.ts.map +1 -0
  352. package/build/types/real-time-viewer-next/src/parser/types.d.ts +58 -0
  353. package/build/types/real-time-viewer-next/src/parser/types.d.ts.map +1 -0
  354. package/build/types/real-time-viewer-next/src/presets/mergePresetBundle.d.ts +33 -0
  355. package/build/types/real-time-viewer-next/src/presets/mergePresetBundle.d.ts.map +1 -0
  356. package/build/types/real-time-viewer-next/src/presets/polyfaser-planner.d.ts +4 -0
  357. package/build/types/real-time-viewer-next/src/presets/polyfaser-planner.d.ts.map +1 -0
  358. package/build/types/real-time-viewer-next/src/presets/polyfaser-pool.d.ts +4 -0
  359. package/build/types/real-time-viewer-next/src/presets/polyfaser-pool.d.ts.map +1 -0
  360. package/build/types/real-time-viewer-next/src/presets/polyfaserPlannerOverride.d.ts +9 -0
  361. package/build/types/real-time-viewer-next/src/presets/polyfaserPlannerOverride.d.ts.map +1 -0
  362. package/build/types/real-time-viewer-next/src/presets/villa-cliff.d.ts +4 -0
  363. package/build/types/real-time-viewer-next/src/presets/villa-cliff.d.ts.map +1 -0
  364. package/build/types/real-time-viewer-next/src/publicApi.d.ts +35 -0
  365. package/build/types/real-time-viewer-next/src/publicApi.d.ts.map +1 -0
  366. package/build/types/real-time-viewer-next/src/publicPath.d.ts +1 -0
  367. package/build/types/real-time-viewer-next/src/publicPath.d.ts.map +1 -0
  368. package/build/types/real-time-viewer-next/src/store/index.d.ts +18 -0
  369. package/build/types/real-time-viewer-next/src/store/index.d.ts.map +1 -0
  370. package/build/types/real-time-viewer-next/src/store/shared.d.ts +25 -0
  371. package/build/types/real-time-viewer-next/src/store/shared.d.ts.map +1 -0
  372. package/build/types/real-time-viewer-next/src/store/slices/accessory.d.ts +147 -0
  373. package/build/types/real-time-viewer-next/src/store/slices/accessory.d.ts.map +1 -0
  374. package/build/types/real-time-viewer-next/src/store/slices/analyzerGate.d.ts +15 -0
  375. package/build/types/real-time-viewer-next/src/store/slices/analyzerGate.d.ts.map +1 -0
  376. package/build/types/real-time-viewer-next/src/store/slices/camera.d.ts +66 -0
  377. package/build/types/real-time-viewer-next/src/store/slices/camera.d.ts.map +1 -0
  378. package/build/types/real-time-viewer-next/src/store/slices/capture.d.ts +60 -0
  379. package/build/types/real-time-viewer-next/src/store/slices/capture.d.ts.map +1 -0
  380. package/build/types/real-time-viewer-next/src/store/slices/config.d.ts +52 -0
  381. package/build/types/real-time-viewer-next/src/store/slices/config.d.ts.map +1 -0
  382. package/build/types/real-time-viewer-next/src/store/slices/deckCutout.d.ts +29 -0
  383. package/build/types/real-time-viewer-next/src/store/slices/deckCutout.d.ts.map +1 -0
  384. package/build/types/real-time-viewer-next/src/store/slices/environment.d.ts +47 -0
  385. package/build/types/real-time-viewer-next/src/store/slices/environment.d.ts.map +1 -0
  386. package/build/types/real-time-viewer-next/src/store/slices/glGeneration.d.ts +18 -0
  387. package/build/types/real-time-viewer-next/src/store/slices/glGeneration.d.ts.map +1 -0
  388. package/build/types/real-time-viewer-next/src/store/slices/hostSelection.test.d.ts +5 -0
  389. package/build/types/real-time-viewer-next/src/store/slices/hostSelection.test.d.ts.map +1 -0
  390. package/build/types/real-time-viewer-next/src/store/slices/interaction.d.ts +53 -0
  391. package/build/types/real-time-viewer-next/src/store/slices/interaction.d.ts.map +1 -0
  392. package/build/types/real-time-viewer-next/src/store/slices/performanceProfile.d.ts +71 -0
  393. package/build/types/real-time-viewer-next/src/store/slices/performanceProfile.d.ts.map +1 -0
  394. package/build/types/real-time-viewer-next/src/store/slices/plannerUi.d.ts +46 -0
  395. package/build/types/real-time-viewer-next/src/store/slices/plannerUi.d.ts.map +1 -0
  396. package/build/types/real-time-viewer-next/src/store/slices/scene.d.ts +26 -0
  397. package/build/types/real-time-viewer-next/src/store/slices/scene.d.ts.map +1 -0
  398. package/build/types/real-time-viewer-next/src/store/slices/sceneLoad.d.ts +75 -0
  399. package/build/types/real-time-viewer-next/src/store/slices/sceneLoad.d.ts.map +1 -0
  400. package/build/types/real-time-viewer-next/src/store/slices/sceneLoad.test.d.ts +5 -0
  401. package/build/types/real-time-viewer-next/src/store/slices/sceneLoad.test.d.ts.map +1 -0
  402. package/build/types/real-time-viewer-next/src/store/slices/selection.d.ts +66 -0
  403. package/build/types/real-time-viewer-next/src/store/slices/selection.d.ts.map +1 -0
  404. package/build/types/real-time-viewer-next/src/store/slices/versions.d.ts +34 -0
  405. package/build/types/real-time-viewer-next/src/store/slices/versions.d.ts.map +1 -0
  406. package/build/types/real-time-viewer-next/src/store/slices/viewMode.d.ts +16 -0
  407. package/build/types/real-time-viewer-next/src/store/slices/viewMode.d.ts.map +1 -0
  408. package/build/types/real-time-viewer-next/src/store/types.d.ts +96 -0
  409. package/build/types/real-time-viewer-next/src/store/types.d.ts.map +1 -0
  410. package/build/types/real-time-viewer-next/src/testUtils/deepDiff.d.ts +26 -0
  411. package/build/types/real-time-viewer-next/src/testUtils/deepDiff.d.ts.map +1 -0
  412. package/build/types/real-time-viewer-next/src/testUtils/deepDiff.test.d.ts +11 -0
  413. package/build/types/real-time-viewer-next/src/testUtils/deepDiff.test.d.ts.map +1 -0
  414. package/build/types/real-time-viewer-next/src/testUtils/divaCoreMock.d.ts +47 -0
  415. package/build/types/real-time-viewer-next/src/testUtils/divaCoreMock.d.ts.map +1 -0
  416. package/build/types/real-time-viewer-next/src/testUtils/resolvedConfigSnapshots.d.ts +36 -0
  417. package/build/types/real-time-viewer-next/src/testUtils/resolvedConfigSnapshots.d.ts.map +1 -0
  418. package/build/types/real-time-viewer-next/src/testUtils/structuredClonePolyfill.d.ts +2 -0
  419. package/build/types/real-time-viewer-next/src/testUtils/structuredClonePolyfill.d.ts.map +1 -0
  420. package/build/types/real-time-viewer-next/src/types/accessoryGrids.d.ts +134 -0
  421. package/build/types/real-time-viewer-next/src/types/accessoryGrids.d.ts.map +1 -0
  422. package/build/types/real-time-viewer-next/src/types/camera.d.ts +288 -0
  423. package/build/types/real-time-viewer-next/src/types/camera.d.ts.map +1 -0
  424. package/build/types/real-time-viewer-next/src/types/environment.d.ts +146 -0
  425. package/build/types/real-time-viewer-next/src/types/environment.d.ts.map +1 -0
  426. package/build/types/real-time-viewer-next/src/types/plannerUi.d.ts +68 -0
  427. package/build/types/real-time-viewer-next/src/types/plannerUi.d.ts.map +1 -0
  428. package/build/types/real-time-viewer-next/src/types/scene2d.d.ts +168 -0
  429. package/build/types/real-time-viewer-next/src/types/scene2d.d.ts.map +1 -0
  430. package/build/types/real-time-viewer-next/src/utils/bootPhase.d.ts +75 -0
  431. package/build/types/real-time-viewer-next/src/utils/bootPhase.d.ts.map +1 -0
  432. package/build/types/real-time-viewer-next/src/utils/bootPhase.test.d.ts +5 -0
  433. package/build/types/real-time-viewer-next/src/utils/bootPhase.test.d.ts.map +1 -0
  434. package/build/types/real-time-viewer-next/src/utils/camera.d.ts +8 -0
  435. package/build/types/real-time-viewer-next/src/utils/camera.d.ts.map +1 -0
  436. package/build/types/real-time-viewer-next/src/utils/cameraFraming.d.ts +47 -0
  437. package/build/types/real-time-viewer-next/src/utils/cameraFraming.d.ts.map +1 -0
  438. package/build/types/real-time-viewer-next/src/utils/collisionTargets.d.ts +34 -0
  439. package/build/types/real-time-viewer-next/src/utils/collisionTargets.d.ts.map +1 -0
  440. package/build/types/real-time-viewer-next/src/utils/collisionTargets.test.d.ts +2 -0
  441. package/build/types/real-time-viewer-next/src/utils/collisionTargets.test.d.ts.map +1 -0
  442. package/build/types/real-time-viewer-next/src/utils/cursorStack.d.ts +21 -0
  443. package/build/types/real-time-viewer-next/src/utils/cursorStack.d.ts.map +1 -0
  444. package/build/types/real-time-viewer-next/src/utils/detectDeviceTier.d.ts +24 -0
  445. package/build/types/real-time-viewer-next/src/utils/detectDeviceTier.d.ts.map +1 -0
  446. package/build/types/real-time-viewer-next/src/utils/detectDeviceTier.test.d.ts +5 -0
  447. package/build/types/real-time-viewer-next/src/utils/detectDeviceTier.test.d.ts.map +1 -0
  448. package/build/types/real-time-viewer-next/src/utils/dockingGroups.d.ts +7 -0
  449. package/build/types/real-time-viewer-next/src/utils/dockingGroups.d.ts.map +1 -0
  450. package/build/types/real-time-viewer-next/src/utils/elementIds.d.ts +27 -0
  451. package/build/types/real-time-viewer-next/src/utils/elementIds.d.ts.map +1 -0
  452. package/build/types/real-time-viewer-next/src/utils/equirectCache.d.ts +45 -0
  453. package/build/types/real-time-viewer-next/src/utils/equirectCache.d.ts.map +1 -0
  454. package/build/types/real-time-viewer-next/src/utils/equirectUrl.d.ts +22 -0
  455. package/build/types/real-time-viewer-next/src/utils/equirectUrl.d.ts.map +1 -0
  456. package/build/types/real-time-viewer-next/src/utils/equirectUrl.test.d.ts +2 -0
  457. package/build/types/real-time-viewer-next/src/utils/equirectUrl.test.d.ts.map +1 -0
  458. package/build/types/real-time-viewer-next/src/utils/footprint.d.ts +15 -0
  459. package/build/types/real-time-viewer-next/src/utils/footprint.d.ts.map +1 -0
  460. package/build/types/real-time-viewer-next/src/utils/footprint.test.d.ts +2 -0
  461. package/build/types/real-time-viewer-next/src/utils/footprint.test.d.ts.map +1 -0
  462. package/build/types/real-time-viewer-next/src/utils/footprintTrace.d.ts +55 -0
  463. package/build/types/real-time-viewer-next/src/utils/footprintTrace.d.ts.map +1 -0
  464. package/build/types/real-time-viewer-next/src/utils/footprintTrace.test.d.ts +2 -0
  465. package/build/types/real-time-viewer-next/src/utils/footprintTrace.test.d.ts.map +1 -0
  466. package/build/types/real-time-viewer-next/src/utils/geoViewAngle.d.ts +17 -0
  467. package/build/types/real-time-viewer-next/src/utils/geoViewAngle.d.ts.map +1 -0
  468. package/build/types/real-time-viewer-next/src/utils/gltfLoader.d.ts +34 -0
  469. package/build/types/real-time-viewer-next/src/utils/gltfLoader.d.ts.map +1 -0
  470. package/build/types/real-time-viewer-next/src/utils/gridGeometryApi.d.ts +17 -0
  471. package/build/types/real-time-viewer-next/src/utils/gridGeometryApi.d.ts.map +1 -0
  472. package/build/types/real-time-viewer-next/src/utils/localUVSampler.d.ts +89 -0
  473. package/build/types/real-time-viewer-next/src/utils/localUVSampler.d.ts.map +1 -0
  474. package/build/types/real-time-viewer-next/src/utils/localUVSampler.test.d.ts +2 -0
  475. package/build/types/real-time-viewer-next/src/utils/localUVSampler.test.d.ts.map +1 -0
  476. package/build/types/real-time-viewer-next/src/utils/overlayGeometry.d.ts +28 -0
  477. package/build/types/real-time-viewer-next/src/utils/overlayGeometry.d.ts.map +1 -0
  478. package/build/types/real-time-viewer-next/src/utils/overlayGeometry.test.d.ts +2 -0
  479. package/build/types/real-time-viewer-next/src/utils/overlayGeometry.test.d.ts.map +1 -0
  480. package/build/types/real-time-viewer-next/src/utils/planarTransform.d.ts +20 -0
  481. package/build/types/real-time-viewer-next/src/utils/planarTransform.d.ts.map +1 -0
  482. package/build/types/real-time-viewer-next/src/utils/planarTransform.test.d.ts +2 -0
  483. package/build/types/real-time-viewer-next/src/utils/planarTransform.test.d.ts.map +1 -0
  484. package/build/types/real-time-viewer-next/src/utils/polygon2d.d.ts +25 -0
  485. package/build/types/real-time-viewer-next/src/utils/polygon2d.d.ts.map +1 -0
  486. package/build/types/real-time-viewer-next/src/utils/preloadEnvironment.d.ts +15 -0
  487. package/build/types/real-time-viewer-next/src/utils/preloadEnvironment.d.ts.map +1 -0
  488. package/build/types/real-time-viewer-next/src/utils/profiles.d.ts +113 -0
  489. package/build/types/real-time-viewer-next/src/utils/profiles.d.ts.map +1 -0
  490. package/build/types/real-time-viewer-next/src/utils/profiles.test.d.ts +17 -0
  491. package/build/types/real-time-viewer-next/src/utils/profiles.test.d.ts.map +1 -0
  492. package/build/types/real-time-viewer-next/src/utils/rasterMask.d.ts +31 -0
  493. package/build/types/real-time-viewer-next/src/utils/rasterMask.d.ts.map +1 -0
  494. package/build/types/real-time-viewer-next/src/utils/rasterMask.test.d.ts +2 -0
  495. package/build/types/real-time-viewer-next/src/utils/rasterMask.test.d.ts.map +1 -0
  496. package/build/types/real-time-viewer-next/src/utils/resolveEnvironment.d.ts +16 -0
  497. package/build/types/real-time-viewer-next/src/utils/resolveEnvironment.d.ts.map +1 -0
  498. package/build/types/real-time-viewer-next/src/utils/resolveGridCells.d.ts +35 -0
  499. package/build/types/real-time-viewer-next/src/utils/resolveGridCells.d.ts.map +1 -0
  500. package/build/types/real-time-viewer-next/src/utils/scene.d.ts +3 -0
  501. package/build/types/real-time-viewer-next/src/utils/scene.d.ts.map +1 -0
  502. package/build/types/real-time-viewer-next/src/utils/screenProjection.d.ts +42 -0
  503. package/build/types/real-time-viewer-next/src/utils/screenProjection.d.ts.map +1 -0
  504. package/build/types/real-time-viewer-next/src/utils/screenProjection.test.d.ts +2 -0
  505. package/build/types/real-time-viewer-next/src/utils/screenProjection.test.d.ts.map +1 -0
  506. package/build/types/real-time-viewer-next/src/utils/selectionScopeNames.d.ts +6 -0
  507. package/build/types/real-time-viewer-next/src/utils/selectionScopeNames.d.ts.map +1 -0
  508. package/build/types/real-time-viewer-next/src/utils/selectionScopeScene.d.ts +8 -0
  509. package/build/types/real-time-viewer-next/src/utils/selectionScopeScene.d.ts.map +1 -0
  510. package/build/types/real-time-viewer-next/src/utils/smoothDamp.d.ts +19 -0
  511. package/build/types/real-time-viewer-next/src/utils/smoothDamp.d.ts.map +1 -0
  512. package/build/types/real-time-viewer-next/src/utils/sunAngles.d.ts +29 -0
  513. package/build/types/real-time-viewer-next/src/utils/sunAngles.d.ts.map +1 -0
  514. package/build/types/real-time-viewer-next/src/utils/suspense.d.ts +11 -0
  515. package/build/types/real-time-viewer-next/src/utils/suspense.d.ts.map +1 -0
  516. package/build/types/real-time-viewer-next/src/utils/whiteRoomPreset.d.ts +48 -0
  517. package/build/types/real-time-viewer-next/src/utils/whiteRoomPreset.d.ts.map +1 -0
  518. package/build/types/real-time-viewer-next/src/utils/withRenderTarget.d.ts +48 -0
  519. package/build/types/real-time-viewer-next/src/utils/withRenderTarget.d.ts.map +1 -0
  520. package/build/umd/114.real-time-viewer-next.umd.min.js +2 -0
  521. package/build/umd/114.real-time-viewer-next.umd.min.js.LICENSE.txt +1 -0
  522. package/build/umd/699.real-time-viewer-next.umd.min.js +2 -0
  523. package/build/umd/699.real-time-viewer-next.umd.min.js.LICENSE.txt +1 -0
  524. package/build/umd/964.real-time-viewer-next.umd.min.js +2 -0
  525. package/build/umd/964.real-time-viewer-next.umd.min.js.LICENSE.txt +1 -0
  526. package/build/umd/real-time-viewer-next.umd.min.js +2 -0
  527. package/build/umd/real-time-viewer-next.umd.min.js.LICENSE.txt +117 -0
  528. package/build/umd/report.html +38 -0
  529. package/package.json +31 -0
@@ -0,0 +1,2536 @@
1
+ import { p as parseElementKey, u as useRTVStore, b as bootPhase, D as DECK_COLLAR_LOAD_ID } from './index-920dd901.js';
2
+ import { useMemo, useRef, useEffect, useState, useCallback } from 'react';
3
+ import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
4
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
5
+ import { useThree, useFrame } from '@react-three/fiber';
6
+ import { getLogger } from '@crystaldesign/diva-core';
7
+ import { Box3, Matrix4, Vector3, Matrix3, MeshStandardMaterial, Shape, Path, ExtrudeGeometry, BufferAttribute, TextureLoader, SRGBColorSpace, RepeatWrapping } from 'three';
8
+ import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
9
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
+ import '@babel/runtime/helpers/asyncToGenerator';
11
+ import '@babel/runtime/regenerator';
12
+ import 'three/examples/jsm/loaders/DRACOLoader.js';
13
+ import 'three/examples/jsm/loaders/GLTFLoader.js';
14
+ import 'zustand';
15
+ import 'zustand/middleware';
16
+ import '@babel/runtime/helpers/typeof';
17
+ import 'postprocessing';
18
+ import '@react-three/drei';
19
+ import '@babel/runtime/helpers/classCallCheck';
20
+ import '@babel/runtime/helpers/createClass';
21
+ import '@babel/runtime/helpers/possibleConstructorReturn';
22
+ import '@babel/runtime/helpers/getPrototypeOf';
23
+ import '@babel/runtime/helpers/inherits';
24
+ import 'classnames';
25
+ import 'three-mesh-bvh';
26
+ import '@babel/runtime/helpers/objectWithoutProperties';
27
+ import 'three/examples/jsm/environments/RoomEnvironment.js';
28
+ import 'three/examples/jsm/loaders/RGBELoader.js';
29
+ import 'three/examples/jsm/loaders/EXRLoader.js';
30
+ import '@react-three/postprocessing';
31
+ import '@babel/runtime/helpers/construct';
32
+ import 'detect-gpu';
33
+
34
+ var ELEMENT_PREFIX = 'Element#';
35
+ var _elementBox = new Box3();
36
+ var _unionBox = new Box3();
37
+
38
+ /** Article bounds in the deck mesh's local frame. */
39
+
40
+ /** One planner element's article codex and its plan area, for the rule lookup. */
41
+
42
+ /** Top-level planner element groups (no `Element#` ancestor) — the ones the anchor moves and the projection walks. */
43
+ function topLevelElements(elementObjects) {
44
+ return elementObjects.filter(function (obj) {
45
+ for (var p = obj.parent; p; p = p.parent) {
46
+ if (p.name.startsWith(ELEMENT_PREFIX)) return false;
47
+ }
48
+ return true;
49
+ });
50
+ }
51
+
52
+ /** Same rect moved by a floor-local delta. */
53
+ function shiftRect(rect, delta) {
54
+ return {
55
+ minX: rect.minX + delta.dx,
56
+ maxX: rect.maxX + delta.dx,
57
+ minY: rect.minY + delta.dy,
58
+ maxY: rect.maxY + delta.dy,
59
+ minZ: rect.minZ + delta.dz,
60
+ maxZ: rect.maxZ + delta.dz
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Union bounds of every planner `Element#` group, expressed in the floor meshes'
66
+ * shared local space via the first name-matched deck mesh's inverse world
67
+ * matrix. That mesh is the one `meshesMatching` also hands the collar as its
68
+ * reference, so both work in identical coordinates.
69
+ *
70
+ * Returns null while the article or the deck isn't in the scene yet.
71
+ */
72
+ function measureArticle(scene, patterns, elementsInfo) {
73
+ var _floorGeometry$boundi, _floorGeometry$boundi2;
74
+ var elementObjects = [];
75
+ var codexesByArea = [];
76
+ // Single-element holder rather than a `let`: the reference is assigned inside
77
+ // the traversal callback, which TypeScript's flow analysis does not follow.
78
+ var floorMatch = [];
79
+ _unionBox.makeEmpty();
80
+ scene.traverse(function (obj) {
81
+ var _elementsInfo$get;
82
+ // Same pre-order and same first-match rule as `meshesMatching`, folded into
83
+ // this traversal: a measure runs every frame while the pipeline converges,
84
+ // and walking the whole scene twice for it is the avoidable half.
85
+ if (floorMatch.length === 0) {
86
+ var mesh = obj;
87
+ if (mesh.isMesh && patterns.some(function (p) {
88
+ return mesh.name.includes(p);
89
+ })) floorMatch.push(mesh);
90
+ }
91
+ if (!obj.name.startsWith(ELEMENT_PREFIX)) return;
92
+ elementObjects.push(obj);
93
+ _elementBox.setFromObject(obj);
94
+ if (_elementBox.isEmpty()) return;
95
+ _unionBox.union(_elementBox);
96
+ var codex = (_elementsInfo$get = elementsInfo.get(parseElementKey(obj.name))) === null || _elementsInfo$get === void 0 ? void 0 : _elementsInfo$get.articleCodex;
97
+ if (codex !== undefined) {
98
+ codexesByArea.push({
99
+ codex: codex,
100
+ area: (_elementBox.max.x - _elementBox.min.x) * (_elementBox.max.z - _elementBox.min.z)
101
+ });
102
+ }
103
+ });
104
+ codexesByArea.sort(function (a, b) {
105
+ return b.area - a.area;
106
+ });
107
+ if (_unionBox.isEmpty()) return null;
108
+ var floorMesh = floorMatch[0];
109
+ if (!floorMesh) return null;
110
+ var floorLocal = new Matrix4().copy(floorMesh.matrixWorld).invert();
111
+ var floorGeometry = floorMesh.geometry;
112
+ if (!floorGeometry.boundingBox) floorGeometry.computeBoundingBox();
113
+ var floorTopY = (_floorGeometry$boundi = (_floorGeometry$boundi2 = floorGeometry.boundingBox) === null || _floorGeometry$boundi2 === void 0 ? void 0 : _floorGeometry$boundi2.max.y) !== null && _floorGeometry$boundi !== void 0 ? _floorGeometry$boundi : 0;
114
+ var worldBottomY = _unionBox.min.y;
115
+ // applyMatrix4 transforms all 8 corners and re-wraps them axis-aligned —
116
+ // exactly the article's footprint in floor-local space.
117
+ _unionBox.applyMatrix4(floorLocal);
118
+ return {
119
+ rect: {
120
+ minX: _unionBox.min.x,
121
+ maxX: _unionBox.max.x,
122
+ minY: _unionBox.min.y,
123
+ maxY: _unionBox.max.y,
124
+ minZ: _unionBox.min.z,
125
+ maxZ: _unionBox.max.z
126
+ },
127
+ worldBottomY: worldBottomY,
128
+ elementObjects: elementObjects,
129
+ codexesByArea: codexesByArea,
130
+ floorWorld: floorMesh.matrixWorld,
131
+ floorLocal: floorLocal,
132
+ floorTopY: floorTopY
133
+ };
134
+ }
135
+
136
+ function _createForOfIteratorHelper$6(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$6(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
137
+ function _unsupportedIterableToArray$6(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$6(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$6(r, a) : void 0; } }
138
+ function _arrayLikeToArray$6(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
139
+ /*
140
+ * 2D polygon primitives — area, simplification, self-intersection guard, hull.
141
+ */
142
+
143
+ /** 2D point; axis meaning depends on context (path space: x/y, floor space: x/z). */
144
+
145
+ var EPS$2 = 1e-9;
146
+
147
+ /** Shoelace signed area — positive for counter-clockwise winding (y-up convention). */
148
+ function polygonSignedArea(points) {
149
+ var area = 0;
150
+ for (var i = 0; i < points.length; i++) {
151
+ var _points$i = _slicedToArray(points[i], 2),
152
+ x1 = _points$i[0],
153
+ y1 = _points$i[1];
154
+ var _points = _slicedToArray(points[(i + 1) % points.length], 2),
155
+ x2 = _points[0],
156
+ y2 = _points[1];
157
+ area += x1 * y2 - x2 * y1;
158
+ }
159
+ return area / 2;
160
+ }
161
+
162
+ /** Douglas–Peucker on an open chain (endpoints kept). */
163
+ function simplifyChain(points, tolerance, out) {
164
+ if (points.length < 3) {
165
+ for (var i = 0; i < points.length - 1; i++) out.push(points[i]);
166
+ return;
167
+ }
168
+ var _points$ = _slicedToArray(points[0], 2),
169
+ ax = _points$[0],
170
+ az = _points$[1];
171
+ var _points2 = _slicedToArray(points[points.length - 1], 2),
172
+ bx = _points2[0],
173
+ bz = _points2[1];
174
+ var len = Math.hypot(bx - ax, bz - az) || EPS$2;
175
+ var maxDist = -1;
176
+ var maxIdx = -1;
177
+ for (var _i = 1; _i < points.length - 1; _i++) {
178
+ var _points$_i = _slicedToArray(points[_i], 2),
179
+ px = _points$_i[0],
180
+ pz = _points$_i[1];
181
+ var dist = Math.abs((bx - ax) * (az - pz) - (ax - px) * (bz - az)) / len;
182
+ if (dist > maxDist) {
183
+ maxDist = dist;
184
+ maxIdx = _i;
185
+ }
186
+ }
187
+ if (maxDist <= tolerance) {
188
+ out.push(points[0]);
189
+ return;
190
+ }
191
+ simplifyChain(points.slice(0, maxIdx + 1), tolerance, out);
192
+ simplifyChain(points.slice(maxIdx), tolerance, out);
193
+ }
194
+
195
+ /** Douglas–Peucker for a closed polygon: split at the point farthest from the start, simplify both halves. */
196
+ function simplifyClosedPolygon(points, tolerance) {
197
+ if (points.length < 4 || tolerance <= 0) return _toConsumableArray(points);
198
+ var _points$2 = _slicedToArray(points[0], 2),
199
+ sx = _points$2[0],
200
+ sz = _points$2[1];
201
+ var farIdx = 1;
202
+ var farDist = -1;
203
+ for (var i = 1; i < points.length; i++) {
204
+ var d = Math.hypot(points[i][0] - sx, points[i][1] - sz);
205
+ if (d > farDist) {
206
+ farDist = d;
207
+ farIdx = i;
208
+ }
209
+ }
210
+ var out = [];
211
+ simplifyChain(points.slice(0, farIdx + 1), tolerance, out);
212
+ simplifyChain([].concat(_toConsumableArray(points.slice(farIdx)), [points[0]]), tolerance, out);
213
+ return out;
214
+ }
215
+
216
+ /** Do the closed segments a→b and c→d properly cross? Shared endpoints don't count. */
217
+ function segmentsCross(ax, az, bx, bz, cx, cz, dx, dz) {
218
+ var cross = function cross(px, pz, qx, qz, rx, rz) {
219
+ return (qx - px) * (rz - pz) - (qz - pz) * (rx - px);
220
+ };
221
+ var d1 = cross(ax, az, bx, bz, cx, cz);
222
+ var d2 = cross(ax, az, bx, bz, dx, dz);
223
+ var d3 = cross(cx, cz, dx, dz, ax, az);
224
+ var d4 = cross(cx, cz, dx, dz, bx, bz);
225
+ // Strict sign change on both segments = a proper crossing. Collinear/touching
226
+ // cases are deliberately NOT flagged: traced outlines touch constantly and a
227
+ // triangulator handles that fine.
228
+ return (d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d3 > 0 && d4 < 0 || d3 < 0 && d4 > 0);
229
+ }
230
+
231
+ /** True when no two non-adjacent edges of the closed polygon cross. O(n²) — fine for outline-sized input. */
232
+ function isSimplePolygon(points) {
233
+ var n = points.length;
234
+ if (n < 4) return true;
235
+ for (var i = 0; i < n; i++) {
236
+ var _points$i2 = _slicedToArray(points[i], 2),
237
+ ax = _points$i2[0],
238
+ az = _points$i2[1];
239
+ var _points3 = _slicedToArray(points[(i + 1) % n], 2),
240
+ bx = _points3[0],
241
+ bz = _points3[1];
242
+ for (var j = i + 1; j < n; j++) {
243
+ // Skip the shared-endpoint neighbours (j === i+1, and the wrap pair).
244
+ if (j === i + 1 || i === 0 && j === n - 1) continue;
245
+ var _points$j = _slicedToArray(points[j], 2),
246
+ cx = _points$j[0],
247
+ cz = _points$j[1];
248
+ var _points4 = _slicedToArray(points[(j + 1) % n], 2),
249
+ dx = _points4[0],
250
+ dz = _points4[1];
251
+ if (segmentsCross(ax, az, bx, bz, cx, cz, dx, dz)) return false;
252
+ }
253
+ }
254
+ return true;
255
+ }
256
+
257
+ /** Convex hull (Andrew's monotone chain), counter-clockwise. */
258
+ function convexHull(points) {
259
+ if (points.length < 3) return _toConsumableArray(points);
260
+ var sorted = _toConsumableArray(points).sort(function (a, b) {
261
+ return a[0] - b[0] || a[1] - b[1];
262
+ });
263
+ var cross = function cross(o, a, b) {
264
+ return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
265
+ };
266
+ var build = function build(input) {
267
+ var chain = [];
268
+ var _iterator = _createForOfIteratorHelper$6(input),
269
+ _step;
270
+ try {
271
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
272
+ var p = _step.value;
273
+ while (chain.length >= 2 && cross(chain[chain.length - 2], chain[chain.length - 1], p) <= 0) chain.pop();
274
+ chain.push(p);
275
+ }
276
+ } catch (err) {
277
+ _iterator.e(err);
278
+ } finally {
279
+ _iterator.f();
280
+ }
281
+ return chain;
282
+ };
283
+ var lower = build(sorted);
284
+ var upper = build(_toConsumableArray(sorted).reverse());
285
+ return [].concat(_toConsumableArray(lower.slice(0, -1)), _toConsumableArray(upper.slice(0, -1)));
286
+ }
287
+
288
+ /**
289
+ * Guarantee a polygon a triangulator can use. A self-intersecting outline is
290
+ * NOT rejected by earcut — it silently produces garbage (a stray wedge across
291
+ * the shape), so anything feeding generated geometry has to be checked first.
292
+ *
293
+ * The repair is the convex hull: a pool/article silhouette is convex or nearly
294
+ * so, which makes the hull a close and always-simple stand-in — visibly a
295
+ * little too generous rather than visibly broken. Returns null when even that
296
+ * degenerates.
297
+ */
298
+ function ensureSimplePolygon(points) {
299
+ if (points.length < 3) return null;
300
+ if (isSimplePolygon(points)) {
301
+ // Collinear points pass the crossing test but enclose nothing, and a polygon the triangulator
302
+ // turns into zero triangles is not one this may hand back as clean.
303
+ if (Math.abs(polygonSignedArea(points)) <= EPS$2) return null;
304
+ return {
305
+ points: _toConsumableArray(points),
306
+ repaired: false
307
+ };
308
+ }
309
+ var hull = convexHull(points);
310
+ // The area check must stay inside the branches: a symmetric bowtie has signed area exactly 0,
311
+ // and it is the hull repair - not a rejection - that such an outline needs.
312
+ if (hull.length < 3 || Math.abs(polygonSignedArea(hull)) <= EPS$2) return null;
313
+ return {
314
+ points: hull,
315
+ repaired: true
316
+ };
317
+ }
318
+
319
+ function _createForOfIteratorHelper$5(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$5(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
320
+ function _unsupportedIterableToArray$5(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$5(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$5(r, a) : void 0; } }
321
+ function _arrayLikeToArray$5(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
322
+ /*
323
+ * Binary raster mask operations — morphology (closing, offsetting, enclosed
324
+ * fill) and marching-squares contouring.
325
+ *
326
+ * A mask is an `nx * nz` Uint8Array of 0/1, row-major, one value per cell
327
+ * centre; `originX/originZ` and `cell` map cell indices back to world units.
328
+ */
329
+
330
+ /**
331
+ * Morphological closing (dilate then erode) with a square kernel of the given
332
+ * radius — bridges seams between separately modelled parts without moving the
333
+ * silhouette.
334
+ *
335
+ * Each of the four passes is a SLIDING-WINDOW box count: the window is updated
336
+ * by one entering and one leaving row/column instead of being re-summed, so
337
+ * the cost is O(cells) independent of radius and every access is sequential.
338
+ * The naive per-cell kernel form (especially its column-strided half) costs an
339
+ * order of magnitude more at a fine raster.
340
+ */
341
+ function closeMask(mask, nx, nz, radius) {
342
+ if (radius < 1) return;
343
+ var scratch = new Uint8Array(mask.length);
344
+ boxPassX(mask, scratch, nx, nz, radius, true);
345
+ boxPassZ(scratch, mask, nx, nz, radius, true);
346
+ boxPassX(mask, scratch, nx, nz, radius, false);
347
+ boxPassZ(scratch, mask, nx, nz, radius, false);
348
+ }
349
+
350
+ /**
351
+ * Turn the mask into the SOLID region its outer contour encloses: flood the
352
+ * background inward from the (always empty) border and set everything the
353
+ * flood could not reach. Returns how many cells were added.
354
+ */
355
+ function fillEnclosed(mask, nx, nz) {
356
+ var reached = new Uint8Array(mask.length);
357
+ var stack = [];
358
+ var visit = function visit(i) {
359
+ if (mask[i] !== 0 || reached[i] !== 0) return;
360
+ reached[i] = 1;
361
+ stack.push(i);
362
+ };
363
+ for (var ix = 0; ix < nx; ix++) {
364
+ visit(ix);
365
+ visit((nz - 1) * nx + ix);
366
+ }
367
+ for (var iz = 0; iz < nz; iz++) {
368
+ visit(iz * nx);
369
+ visit(iz * nx + nx - 1);
370
+ }
371
+ while (stack.length > 0) {
372
+ var i = stack.pop();
373
+ var _ix = i % nx;
374
+ var _iz = (i - _ix) / nx;
375
+ if (_ix > 0) visit(i - 1);
376
+ if (_ix < nx - 1) visit(i + 1);
377
+ if (_iz > 0) visit(i - nx);
378
+ if (_iz < nz - 1) visit(i + nx);
379
+ }
380
+ var added = 0;
381
+ for (var _i = 0; _i < mask.length; _i++) {
382
+ if (mask[_i] === 0 && reached[_i] === 0) {
383
+ mask[_i] = 1;
384
+ added += 1;
385
+ }
386
+ }
387
+ return added;
388
+ }
389
+
390
+ /**
391
+ * Single morphological pass — dilate (grow) or erode (shrink) by a square
392
+ * kernel of the given radius. The raster form of a polygon offset: the same
393
+ * operation applied uniformly to every boundary cell, so it can neither miter
394
+ * a corner off nor cross itself across a concavity. The kernel is a square, so
395
+ * the offset is Chebyshev — exact on axis-aligned edges, up to √2 larger on
396
+ * 45° ones.
397
+ */
398
+ function offsetMask(mask, nx, nz, radius, dilate) {
399
+ var scratch = new Uint8Array(mask.length);
400
+ boxPassX(mask, scratch, nx, nz, radius, dilate);
401
+ boxPassZ(scratch, mask, nx, nz, radius, dilate);
402
+ }
403
+
404
+ /** Per-index window sizes along an axis of length `n`, clipped at both ends (erode compares against these). */
405
+ function windowSizes(radius, n) {
406
+ var sizes = new Int32Array(n);
407
+ for (var i = 0; i < n; i++) sizes[i] = Math.min(n - 1, i + radius) - Math.max(0, i - radius) + 1;
408
+ return sizes;
409
+ }
410
+
411
+ /** Horizontal box pass: `dilate` = any cell set in the window, else = all cells set. */
412
+ function boxPassX(src, dst, nx, nz, radius, dilate) {
413
+ var sizes = windowSizes(radius, nx);
414
+ for (var iz = 0; iz < nz; iz++) {
415
+ var row = iz * nx;
416
+ var count = 0;
417
+ for (var k = 0; k <= radius && k < nx; k++) count += src[row + k];
418
+ for (var ix = 0; ix < nx; ix++) {
419
+ dst[row + ix] = (dilate ? count > 0 : count === sizes[ix]) ? 1 : 0;
420
+ var leaving = ix - radius;
421
+ var entering = ix + radius + 1;
422
+ if (leaving >= 0) count -= src[row + leaving];
423
+ if (entering < nx) count += src[row + entering];
424
+ }
425
+ }
426
+ }
427
+
428
+ /** Vertical box pass, carrying one count per column so rows are read in order. */
429
+ function boxPassZ(src, dst, nx, nz, radius, dilate) {
430
+ var counts = new Int32Array(nx);
431
+ var sizes = windowSizes(radius, nz);
432
+ for (var k = 0; k <= radius && k < nz; k++) {
433
+ var row = k * nx;
434
+ for (var ix = 0; ix < nx; ix++) counts[ix] += src[row + ix];
435
+ }
436
+ for (var iz = 0; iz < nz; iz++) {
437
+ var _row = iz * nx;
438
+ var size = sizes[iz];
439
+ for (var _ix2 = 0; _ix2 < nx; _ix2++) dst[_row + _ix2] = (dilate ? counts[_ix2] > 0 : counts[_ix2] === size) ? 1 : 0;
440
+ var leaving = iz - radius;
441
+ var entering = iz + radius + 1;
442
+ if (leaving >= 0) {
443
+ var o = leaving * nx;
444
+ for (var _ix3 = 0; _ix3 < nx; _ix3++) counts[_ix3] -= src[o + _ix3];
445
+ }
446
+ if (entering < nz) {
447
+ var _o = entering * nx;
448
+ for (var _ix4 = 0; _ix4 < nx; _ix4++) counts[_ix4] += src[_o + _ix4];
449
+ }
450
+ }
451
+ }
452
+
453
+ /**
454
+ * Segment table per marching-squares case. Corners c0=(ix,iz) c1=(ix+1,iz)
455
+ * c2=(ix+1,iz+1) c3=(ix,iz+1); edges e0=c0c1 e1=c1c2 e2=c2c3 e3=c3c0. The
456
+ * saddle cases (5, 10) are split into two separate blobs.
457
+ */
458
+ var MS_SEGMENTS = [[], [[3, 0]], [[0, 1]], [[3, 1]], [[1, 2]], [[3, 0], [1, 2]], [[0, 2]], [[3, 2]], [[2, 3]], [[0, 2]], [[0, 1], [2, 3]], [[1, 2]], [[1, 3]], [[0, 1]], [[3, 0]], []];
459
+
460
+ /** Contour a binary node grid (values at cell centers) into closed loops of edge-midpoint coordinates. */
461
+ function marchingSquaresLoops(mask, nx, nz, originX, originZ, cell) {
462
+ // Edge keys: horizontal edge between nodes (ix,iz)-(ix+1,iz) → 2*(iz*nx+ix); vertical (ix,iz)-(ix,iz+1) → 2*(iz*nx+ix)+1.
463
+ var edgeKey = function edgeKey(edge, ix, iz) {
464
+ if (edge === 0) return 2 * (iz * nx + ix);
465
+ if (edge === 2) return 2 * ((iz + 1) * nx + ix);
466
+ if (edge === 3) return 2 * (iz * nx + ix) + 1;
467
+ return 2 * (iz * nx + ix + 1) + 1;
468
+ };
469
+ var edgePoint = function edgePoint(key) {
470
+ var idx = Math.floor(key / 2);
471
+ var ix = idx % nx;
472
+ var iz = Math.floor(idx / nx);
473
+ return key % 2 === 0 ? [originX + (ix + 1) * cell, originZ + (iz + 0.5) * cell] : [originX + (ix + 0.5) * cell, originZ + (iz + 1) * cell];
474
+ };
475
+ var adjacency = new Map();
476
+ var link = function link(a, b) {
477
+ var la = adjacency.get(a);
478
+ if (la) la.push(b);else adjacency.set(a, [b]);
479
+ var lb = adjacency.get(b);
480
+ if (lb) lb.push(a);else adjacency.set(b, [a]);
481
+ };
482
+ for (var iz = 0; iz < nz - 1; iz++) {
483
+ for (var ix = 0; ix < nx - 1; ix++) {
484
+ var c = mask[iz * nx + ix] | mask[iz * nx + ix + 1] << 1 | mask[(iz + 1) * nx + ix + 1] << 2 | mask[(iz + 1) * nx + ix] << 3;
485
+ // Fully inside / fully outside is the overwhelming majority of cells —
486
+ // returning before the segment lookup keeps the sweep near memory speed.
487
+ if (c === 0 || c === 15) continue;
488
+ var _iterator = _createForOfIteratorHelper$5(MS_SEGMENTS[c]),
489
+ _step;
490
+ try {
491
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
492
+ var _step$value = _slicedToArray(_step.value, 2),
493
+ ea = _step$value[0],
494
+ eb = _step$value[1];
495
+ link(edgeKey(ea, ix, iz), edgeKey(eb, ix, iz));
496
+ }
497
+ } catch (err) {
498
+ _iterator.e(err);
499
+ } finally {
500
+ _iterator.f();
501
+ }
502
+ }
503
+ }
504
+ var visited = new Set();
505
+ var loops = [];
506
+ var _iterator2 = _createForOfIteratorHelper$5(adjacency.keys()),
507
+ _step2;
508
+ try {
509
+ var _loop = function _loop() {
510
+ var start = _step2.value;
511
+ if (visited.has(start)) return 1; // continue
512
+ var loop = [];
513
+ var cur = start;
514
+ var prev = -1;
515
+ while (!visited.has(cur)) {
516
+ var _adjacency$get;
517
+ visited.add(cur);
518
+ loop.push(edgePoint(cur));
519
+ var next = ((_adjacency$get = adjacency.get(cur)) !== null && _adjacency$get !== void 0 ? _adjacency$get : []).find(function (k) {
520
+ return k !== prev && !visited.has(k);
521
+ });
522
+ if (next === undefined) break;
523
+ prev = cur;
524
+ cur = next;
525
+ }
526
+ if (loop.length >= 3) loops.push(loop);
527
+ };
528
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
529
+ if (_loop()) continue;
530
+ }
531
+ } catch (err) {
532
+ _iterator2.e(err);
533
+ } finally {
534
+ _iterator2.f();
535
+ }
536
+ return loops;
537
+ }
538
+
539
+ var EPS$1 = 1e-9;
540
+
541
+ /**
542
+ * Ceiling on the raster's cell count. The extent comes from article geometry, so a mis-scaled
543
+ * model (metres authored as millimetres) can ask for a mask no browser can hold — and
544
+ * `closeMask` / `fillEnclosed` / `offsetMask` each allocate another buffer this size. 16M cells
545
+ * is a 20 m x 20 m article at the default 5 mm cell, far beyond anything real, and refusing is
546
+ * graceful: the caller falls back to the measured rect.
547
+ */
548
+ var MAX_MASK_CELLS = 16000000;
549
+
550
+ /** What a trace did internally — see {@link TraceFootprintOptions.diagnostics}. */
551
+
552
+ /**
553
+ * Trace the outer silhouette of a triangle soup already projected onto the
554
+ * plane: `triangleXZ` holds 6 numbers per triangle (x0 z0 x1 z1 x2 z2). The
555
+ * triangles are rasterized into a binary mask (cell centers + vertices + edge
556
+ * samples, then a 3×3 closing to seal sliver gaps), the mask is contoured with
557
+ * marching squares, and the largest closed loop is simplified. Returns [] when
558
+ * nothing usable comes out (fewer than 3 triangles, degenerate extent).
559
+ */
560
+ function traceFootprintFromTriangles(triangleXZ) {
561
+ var _options$cellSize, _options$simplifyTole, _options$closeGap, _options$offset;
562
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
563
+ var cell = (_options$cellSize = options.cellSize) !== null && _options$cellSize !== void 0 ? _options$cellSize : 0.005;
564
+ var tolerance = (_options$simplifyTole = options.simplifyTolerance) !== null && _options$simplifyTole !== void 0 ? _options$simplifyTole : cell;
565
+ // Closing radius in cells, so the sealed gap stays ~`closeGap` at any resolution.
566
+ var closeGap = (_options$closeGap = options.closeGap) !== null && _options$closeGap !== void 0 ? _options$closeGap : 0.02;
567
+ var closeRadius = closeGap <= 0 ? 0 : Math.max(1, Math.round(closeGap / (cell * 2)));
568
+ var offset = (_options$offset = options.offset) !== null && _options$offset !== void 0 ? _options$offset : 0;
569
+ var offsetRadius = Math.round(Math.abs(offset) / cell);
570
+ var grow = offset > 0;
571
+ var triCount = Math.floor(triangleXZ.length / 6);
572
+ if (triCount < 1 || cell <= 0) return [];
573
+ var minX = Infinity;
574
+ var maxX = -Infinity;
575
+ var minZ = Infinity;
576
+ var maxZ = -Infinity;
577
+ for (var i = 0; i < triCount * 6; i += 2) {
578
+ var x = triangleXZ[i];
579
+ var z = triangleXZ[i + 1];
580
+ if (x < minX) minX = x;
581
+ if (x > maxX) maxX = x;
582
+ if (z < minZ) minZ = z;
583
+ if (z > maxZ) maxZ = z;
584
+ }
585
+ if (!Number.isFinite(minX) || maxX - minX < cell || maxZ - minZ < cell) return [];
586
+
587
+ // Empty border of `closeRadius + 1` cells per side: the closing's dilation
588
+ // must have room to spread without the erosion then eating the shape's
589
+ // outermost cells, and the last ring keeps the contour closed.
590
+ var border = closeRadius + (grow ? offsetRadius : 0) + 1;
591
+ var originX = minX - border * cell;
592
+ var originZ = minZ - border * cell;
593
+ var nx = Math.ceil((maxX - minX) / cell) + 2 * border + 1;
594
+ var nz = Math.ceil((maxZ - minZ) / cell) + 2 * border + 1;
595
+ if (nx * nz > MAX_MASK_CELLS) return [];
596
+ var mask = new Uint8Array(nx * nz);
597
+ var cellOf = function cellOf(v, origin, n) {
598
+ return Math.min(n - border - 1, Math.max(border, Math.floor((v - origin) / cell)));
599
+ };
600
+ var mark = function mark(x, z) {
601
+ mask[cellOf(z, originZ, nz) * nx + cellOf(x, originX, nx)] = 1;
602
+ };
603
+ for (var t = 0; t < triCount; t++) {
604
+ var o = t * 6;
605
+ var x0 = triangleXZ[o];
606
+ var z0 = triangleXZ[o + 1];
607
+ var x1 = triangleXZ[o + 2];
608
+ var z1 = triangleXZ[o + 3];
609
+ var x2 = triangleXZ[o + 4];
610
+ var z2 = triangleXZ[o + 5];
611
+ mark(x0, z0);
612
+ mark(x1, z1);
613
+ mark(x2, z2);
614
+
615
+ // Edge sampling is only needed for SLIVERS — a triangle thinner than a
616
+ // raster row can fall between row centers and be missed by the scanline
617
+ // fill below. Fat triangles (the vast majority in a real mesh) are fully
618
+ // covered by the fill, and skipping their edges is the difference between
619
+ // a fine raster being affordable and not.
620
+ var twiceArea = Math.abs((x1 - x0) * (z2 - z0) - (x2 - x0) * (z1 - z0));
621
+ var longestEdge = Math.max(Math.hypot(x1 - x0, z1 - z0), Math.hypot(x2 - x1, z2 - z1), Math.hypot(x0 - x2, z0 - z2));
622
+ var thickness = longestEdge > EPS$1 ? twiceArea / longestEdge : 0;
623
+ if (thickness < cell * 1.5) {
624
+ var edges = [[x0, z0, x1, z1], [x1, z1, x2, z2], [x2, z2, x0, z0]];
625
+ for (var _i = 0, _edges = edges; _i < _edges.length; _i++) {
626
+ var _edges$_i = _slicedToArray(_edges[_i], 4),
627
+ ax = _edges$_i[0],
628
+ az = _edges$_i[1],
629
+ bx = _edges$_i[2],
630
+ bz = _edges$_i[3];
631
+ var steps = Math.ceil(Math.hypot(bx - ax, bz - az) / (cell * 0.7));
632
+ for (var st = 1; st < steps; st++) {
633
+ var f = st / steps;
634
+ mark(ax + (bx - ax) * f, az + (bz - az) * f);
635
+ }
636
+ }
637
+ }
638
+ // Interior: scanline spans. Each raster row crosses a triangle in exactly
639
+ // one x interval, so the row is filled with a single `fill()` — no
640
+ // per-cell inside test, which is what makes a fine raster affordable.
641
+ var cz0 = cellOf(Math.min(z0, z1, z2), originZ, nz);
642
+ var cz1 = cellOf(Math.max(z0, z1, z2), originZ, nz);
643
+ for (var iz = cz0; iz <= cz1; iz++) {
644
+ var pz = originZ + (iz + 0.5) * cell;
645
+ var xa = Infinity;
646
+ var xb = -Infinity;
647
+ // Half-open [lo, hi) span test per edge ⇒ exactly two crossings, no
648
+ // double-count at shared vertices. Horizontal edges never cross.
649
+ for (var e = 0; e < 3; e++) {
650
+ var _ax = e === 0 ? x0 : e === 1 ? x1 : x2;
651
+ var _az = e === 0 ? z0 : e === 1 ? z1 : z2;
652
+ var _bx = e === 0 ? x1 : e === 1 ? x2 : x0;
653
+ var _bz = e === 0 ? z1 : e === 1 ? z2 : z0;
654
+ if (_az === _bz) continue;
655
+ if (pz < Math.min(_az, _bz) || pz >= Math.max(_az, _bz)) continue;
656
+ var _x = _ax + (pz - _az) / (_bz - _az) * (_bx - _ax);
657
+ if (_x < xa) xa = _x;
658
+ if (_x > xb) xb = _x;
659
+ }
660
+ if (xa > xb) continue;
661
+ // Fill the cells whose CENTER lies inside the span.
662
+ var from = Math.max(border, Math.ceil((xa - originX) / cell - 0.5));
663
+ var to = Math.min(nx - border - 1, Math.floor((xb - originX) / cell - 0.5));
664
+ if (from <= to) mask.fill(1, iz * nx + from, iz * nx + to + 1);
665
+ }
666
+ }
667
+ closeMask(mask, nx, nz, closeRadius);
668
+ // Offset AFTER the closing: seams have to be sealed before the boundary is
669
+ // moved, or the erosion widens them instead. An erosion strong enough to
670
+ // consume a thin shape empties the mask and the trace reports no contour,
671
+ // which the caller handles as a failed trace.
672
+ // Solidify BEFORE offsetting. The caller's slice keeps only geometry near the
673
+ // article's top, so a basin projects as a ring — its rim band with an empty
674
+ // middle. Eroding that ring thins it from both sides and destroys it once it
675
+ // is narrower than the offset, instead of moving the silhouette's outer
676
+ // boundary inward. Filling the enclosed middle first makes the erosion mean
677
+ // what it should. After the closing, so a sealed seam can't leak the fill out.
678
+ var enclosedFilled = fillEnclosed(mask, nx, nz);
679
+ if (offsetRadius >= 1) offsetMask(mask, nx, nz, offsetRadius, grow);
680
+ var diag = options.diagnostics;
681
+ if (diag) {
682
+ diag.enclosedFilled = enclosedFilled;
683
+ var filled = 0;
684
+ for (var _i2 = 0; _i2 < mask.length; _i2++) filled += mask[_i2];
685
+ diag.filledCells = filled;
686
+ }
687
+ var loops = marchingSquaresLoops(mask, nx, nz, originX, originZ, cell);
688
+ if (diag) diag.loops = loops.length;
689
+ if (loops.length === 0) return [];
690
+ var best = loops[0];
691
+ var bestArea = Math.abs(polygonSignedArea(best));
692
+ var totalArea = bestArea;
693
+ for (var _i3 = 1; _i3 < loops.length; _i3++) {
694
+ var a = Math.abs(polygonSignedArea(loops[_i3]));
695
+ totalArea += a;
696
+ if (a > bestArea) {
697
+ bestArea = a;
698
+ best = loops[_i3];
699
+ }
700
+ }
701
+ var simplified = simplifyClosedPolygon(best, tolerance);
702
+ if (diag) {
703
+ diag.chosenAreaShare = totalArea > 0 ? bestArea / totalArea : 0;
704
+ diag.pointsBeforeSimplify = best.length;
705
+ diag.pointsAfterSimplify = simplified.length;
706
+ }
707
+ return simplified.length >= 3 ? simplified : [];
708
+ }
709
+
710
+ function _createForOfIteratorHelper$4(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$4(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
711
+ function _unsupportedIterableToArray$4(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$4(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$4(r, a) : void 0; } }
712
+ function _arrayLikeToArray$4(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
713
+
714
+ /** The subset of a deckCutout article rule the matcher needs. */
715
+
716
+ /**
717
+ * First-match-wins lookup of an article rule by codex. Wildcard rules
718
+ * (`match: '*'` or empty) match even when no codex is known — they double as
719
+ * the fallback entry and keep footprints testable before the host ships
720
+ * per-element codexes.
721
+ */
722
+ function matchArticleRule(rules, articleCodex) {
723
+ var _iterator = _createForOfIteratorHelper$4(rules),
724
+ _step;
725
+ try {
726
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
727
+ var rule = _step.value;
728
+ var m = rule.match.trim();
729
+ if (m === '' || m === '*') return rule;
730
+ if (articleCodex === undefined) continue;
731
+ var hit = m.split(',').map(function (p) {
732
+ return p.trim();
733
+ }).filter(function (p) {
734
+ return p.length > 0;
735
+ }).some(function (p) {
736
+ return articleCodex.includes(p);
737
+ });
738
+ if (hit) return rule;
739
+ }
740
+ } catch (err) {
741
+ _iterator.e(err);
742
+ } finally {
743
+ _iterator.f();
744
+ }
745
+ return null;
746
+ }
747
+
748
+ function _createForOfIteratorHelper$3(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$3(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
749
+ function _unsupportedIterableToArray$3(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$3(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$3(r, a) : void 0; } }
750
+ function _arrayLikeToArray$3(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
751
+
752
+ /**
753
+ * Raster cell (m) for the geometry-derived footprint. 5 mm follows cast-in
754
+ * steps and tight rim radii; the trace runs once per geometry change (cached),
755
+ * so the finer grid costs a one-off, not per-frame work.
756
+ */
757
+ var GEOMETRY_FOOTPRINT_CELL = 0.005;
758
+
759
+ /**
760
+ * Minimum share of the measured article extent a traced outline has to cover on
761
+ * BOTH axes to be believed. Below that it is a detail that happened to reach
762
+ * above the slice plane (a nozzle, a fitting) rather than the article's rim —
763
+ * and its bbox would otherwise drive the article's resting position too.
764
+ */
765
+ var MIN_TRACE_COVERAGE = 0.6;
766
+ /** Smallest usable rect extent (m) — guards the fallback against a margin that would invert it. */
767
+ var MIN_RECT_EXTENT = 0.1;
768
+ var _meshToFloor = new Matrix4();
769
+ var _vertex$1 = new Vector3();
770
+
771
+ /** XZ extents of the article's traced rim. */
772
+
773
+ var EMPTY_TRACE_DIAGNOSTICS = function EMPTY_TRACE_DIAGNOSTICS() {
774
+ return {
775
+ filledCells: 0,
776
+ enclosedFilled: 0,
777
+ loops: 0,
778
+ chosenAreaShare: 0,
779
+ pointsBeforeSimplify: 0,
780
+ pointsAfterSimplify: 0
781
+ };
782
+ };
783
+
784
+ /**
785
+ * Rectangular fallback outline in floor-local XZ: the measured article rect
786
+ * grown by `margin` per side (negative laps the deck over the article). Null
787
+ * when the margin would collapse the rect.
788
+ */
789
+ function measuredRectFootprint(rect, margin) {
790
+ var minX = rect.minX - margin;
791
+ var maxX = rect.maxX + margin;
792
+ var minZ = rect.minZ - margin;
793
+ var maxZ = rect.maxZ + margin;
794
+ if (maxX - minX < MIN_RECT_EXTENT || maxZ - minZ < MIN_RECT_EXTENT) return null;
795
+ return [[minX, minZ], [maxX, minZ], [maxX, maxZ], [minX, maxZ]];
796
+ }
797
+
798
+ /**
799
+ * First rule matching any element's codex, largest element first — but every
800
+ * element gets a look: an accessory bigger in plan than the article it belongs
801
+ * to (a roof, a surround) would otherwise name the scene, match nothing, and
802
+ * leave the deck area with no collar at all. `primaryCodex` reports whichever
803
+ * codex found the rule.
804
+ */
805
+ function pickArticleRule(rules, codexesByArea) {
806
+ var _codexesByArea$;
807
+ var primaryCodex = (_codexesByArea$ = codexesByArea[0]) === null || _codexesByArea$ === void 0 ? void 0 : _codexesByArea$.codex;
808
+ var rule = matchArticleRule(rules, undefined);
809
+ var _iterator = _createForOfIteratorHelper$3(codexesByArea),
810
+ _step;
811
+ try {
812
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
813
+ var candidate = _step.value;
814
+ var hit = matchArticleRule(rules, candidate.codex);
815
+ if (hit) {
816
+ rule = hit;
817
+ primaryCodex = candidate.codex;
818
+ break;
819
+ }
820
+ }
821
+ } catch (err) {
822
+ _iterator.e(err);
823
+ } finally {
824
+ _iterator.f();
825
+ }
826
+ return {
827
+ rule: rule,
828
+ primaryCodex: primaryCodex
829
+ };
830
+ }
831
+
832
+ /**
833
+ * Silhouette of the article meshes projected onto the floor plane: every
834
+ * triangle with a vertex above `minLocalY` (floor-local) is rasterized and the
835
+ * outer contour traced. Expensive (walks all vertices), so the result is
836
+ * cached by a geometry signature and only re-traced when the article's
837
+ * meshes change; anchor moves are pure translations and reuse the cache.
838
+ * Returns the outline in CURRENT floor-local coordinates.
839
+ */
840
+ function traceArticleFootprint(elements, floorLocal, rect, minLocalY, offset, diagnostics, cache) {
841
+ var meshes = [];
842
+ var sigParts = [];
843
+ var _iterator2 = _createForOfIteratorHelper$3(elements),
844
+ _step2;
845
+ try {
846
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
847
+ var el = _step2.value;
848
+ el.traverse(function (obj) {
849
+ var mesh = obj;
850
+ if (!mesh.isMesh || !mesh.visible) return;
851
+ var pos = mesh.geometry.getAttribute('position');
852
+ if (!pos) return;
853
+ meshes.push(mesh);
854
+ sigParts.push("".concat(mesh.name, ":").concat(pos.count));
855
+ });
856
+ }
857
+ } catch (err) {
858
+ _iterator2.e(err);
859
+ } finally {
860
+ _iterator2.f();
861
+ }
862
+ if (meshes.length === 0) return null;
863
+ var sizeX = rect.maxX - rect.minX;
864
+ var sizeY = rect.maxY - rect.minY;
865
+ var sizeZ = rect.maxZ - rect.minZ;
866
+ // The article's top belongs in the signature even though the outline is stored
867
+ // relative to the bbox: the slice plane is fixed, so moving the article
868
+ // VERTICALLY changes which triangles clear it, i.e. the traced shape itself.
869
+ // Without it the anchor's lift would keep returning the pre-lift outline.
870
+ var signature = "".concat(minLocalY.toFixed(3), "|").concat(rect.maxY.toFixed(3), "|").concat(offset.toFixed(3), "|").concat(sizeX.toFixed(3), "x").concat(sizeY.toFixed(3), "x").concat(sizeZ.toFixed(3), "|").concat(sigParts.join(','));
871
+ if (!cache.current || cache.current.signature !== signature) {
872
+ var started = performance.now();
873
+ var xz = [];
874
+ var _triCount = 0;
875
+ var _vertexCount = 0;
876
+ var _iterator3 = _createForOfIteratorHelper$3(meshes),
877
+ _step3;
878
+ try {
879
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
880
+ var mesh = _step3.value;
881
+ var geometry = mesh.geometry;
882
+ var pos = geometry.getAttribute('position');
883
+ _vertexCount += pos.count;
884
+ _meshToFloor.multiplyMatrices(floorLocal, mesh.matrixWorld);
885
+ // Transform every vertex once; triangles then index into the flat array.
886
+ var local = new Float32Array(pos.count * 3);
887
+ for (var i = 0; i < pos.count; i++) {
888
+ _vertex$1.set(pos.getX(i), pos.getY(i), pos.getZ(i)).applyMatrix4(_meshToFloor);
889
+ local[i * 3] = _vertex$1.x;
890
+ local[i * 3 + 1] = _vertex$1.y;
891
+ local[i * 3 + 2] = _vertex$1.z;
892
+ }
893
+ var index = geometry.index;
894
+ var triTotal = index ? Math.floor(index.count / 3) : Math.floor(pos.count / 3);
895
+ for (var t = 0; t < triTotal; t++) {
896
+ var a = index ? index.getX(t * 3) : t * 3;
897
+ var b = index ? index.getX(t * 3 + 1) : t * 3 + 1;
898
+ var c = index ? index.getX(t * 3 + 2) : t * 3 + 2;
899
+ var ya = local[a * 3 + 1];
900
+ var yb = local[b * 3 + 1];
901
+ var yc = local[c * 3 + 1];
902
+ if (ya < minLocalY && yb < minLocalY && yc < minLocalY) continue;
903
+ xz.push(local[a * 3], local[a * 3 + 2], local[b * 3], local[b * 3 + 2], local[c * 3], local[c * 3 + 2]);
904
+ _triCount += 1;
905
+ }
906
+ }
907
+ } catch (err) {
908
+ _iterator3.e(err);
909
+ } finally {
910
+ _iterator3.f();
911
+ }
912
+ var traced = traceFootprintFromTriangles(xz, {
913
+ cellSize: GEOMETRY_FOOTPRINT_CELL,
914
+ offset: offset,
915
+ diagnostics: diagnostics
916
+ });
917
+ cache.current = {
918
+ signature: signature,
919
+ relPoints: traced.map(function (_ref) {
920
+ var _ref2 = _slicedToArray(_ref, 2),
921
+ x = _ref2[0],
922
+ z = _ref2[1];
923
+ return [x - rect.minX, z - rect.minZ];
924
+ }),
925
+ triCount: _triCount,
926
+ vertexCount: _vertexCount
927
+ };
928
+ return {
929
+ points: traced,
930
+ triCount: _triCount,
931
+ vertexCount: _vertexCount,
932
+ retraced: true,
933
+ traceMs: performance.now() - started
934
+ };
935
+ }
936
+ var _cache$current = cache.current,
937
+ relPoints = _cache$current.relPoints,
938
+ triCount = _cache$current.triCount,
939
+ vertexCount = _cache$current.vertexCount;
940
+ return {
941
+ points: relPoints.map(function (_ref3) {
942
+ var _ref4 = _slicedToArray(_ref3, 2),
943
+ x = _ref4[0],
944
+ z = _ref4[1];
945
+ return [x + rect.minX, z + rect.minZ];
946
+ }),
947
+ triCount: triCount,
948
+ vertexCount: vertexCount,
949
+ retraced: false,
950
+ traceMs: 0
951
+ };
952
+ }
953
+
954
+ /**
955
+ * The cutout outline for a measured article — offset by the deck margin, so it
956
+ * comes back as the collar's inner boundary. Needs no calibration: the trace
957
+ * follows the visible rim. Only `footprintFromGeometry` rules produce one;
958
+ * without such a rule the deck's authored hole stays fully open.
959
+ */
960
+ function deriveArticleFootprint(measurement, rule, margin, cache) {
961
+ var _result$points$length, _result$points;
962
+ var result = {
963
+ points: null,
964
+ rim: null,
965
+ sampledCount: 0,
966
+ source: '',
967
+ repairNote: '',
968
+ tracedBounds: '',
969
+ trace: EMPTY_TRACE_DIAGNOSTICS()
970
+ };
971
+ if (!rule || !rule.footprintFromGeometry) return result;
972
+ var rect = measurement.rect,
973
+ floorLocal = measurement.floorLocal,
974
+ floorTopY = measurement.floorTopY,
975
+ elementObjects = measurement.elementObjects;
976
+ var rawSizeX = rect.maxX - rect.minX;
977
+ var rawSizeZ = rect.maxZ - rect.minZ;
978
+ var traced = traceArticleFootprint(topLevelElements(elementObjects), floorLocal, rect, floorTopY - rule.footprintSliceDepth, margin, result.trace, cache);
979
+ var minX = Infinity;
980
+ var maxX = -Infinity;
981
+ var minZ = Infinity;
982
+ var maxZ = -Infinity;
983
+ if (traced && traced.points.length >= 3) {
984
+ var _iterator4 = _createForOfIteratorHelper$3(traced.points),
985
+ _step4;
986
+ try {
987
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
988
+ var _step4$value = _slicedToArray(_step4.value, 2),
989
+ x = _step4$value[0],
990
+ z = _step4$value[1];
991
+ if (x < minX) minX = x;
992
+ if (x > maxX) maxX = x;
993
+ if (z < minZ) minZ = z;
994
+ if (z > maxZ) maxZ = z;
995
+ }
996
+ // The contour comes back with `margin` already applied, so undo it here:
997
+ // what the steps below need is the article's RIM extent (it sizes the
998
+ // water volume), not the collar's inner boundary.
999
+ } catch (err) {
1000
+ _iterator4.e(err);
1001
+ } finally {
1002
+ _iterator4.f();
1003
+ }
1004
+ minX += margin;
1005
+ maxX -= margin;
1006
+ minZ += margin;
1007
+ maxZ -= margin;
1008
+ result.tracedBounds = "X [".concat(minX.toFixed(2), ", ").concat(maxX.toFixed(2), "] Z [").concat(minZ.toFixed(2), ", ").concat(maxZ.toFixed(2), "]");
1009
+ }
1010
+ // A trace covering only a fraction of the measured article is not the rim
1011
+ // (see MIN_TRACE_COVERAGE). Believing it is worse than not tracing at all:
1012
+ // its bbox replaces the measured one, so it would also decide where the
1013
+ // article comes to rest.
1014
+ var believable = maxX > minX && maxX - minX >= rawSizeX * MIN_TRACE_COVERAGE && maxZ - minZ >= rawSizeZ * MIN_TRACE_COVERAGE;
1015
+ if (traced && believable) {
1016
+ var _guarded$points;
1017
+ result.rim = {
1018
+ minX: minX,
1019
+ maxX: maxX,
1020
+ minZ: minZ,
1021
+ maxZ: maxZ
1022
+ };
1023
+ // The margin was applied to the raster, so the contour is already the
1024
+ // collar's inner boundary. It still passes the simple-polygon guard:
1025
+ // marching squares can loop around a thin feature in a way earcut turns
1026
+ // into a stray wedge instead of rejecting.
1027
+ var guarded = ensureSimplePolygon(traced.points);
1028
+ if (guarded !== null && guarded !== void 0 && guarded.repaired) result.repairNote = ' | HULL-REPAIRED, traced outline self-intersects (concavities lost)';
1029
+ if (guarded === null) result.repairNote = ' | outline UNUSABLE even as a hull';
1030
+ result.points = (_guarded$points = guarded === null || guarded === void 0 ? void 0 : guarded.points) !== null && _guarded$points !== void 0 ? _guarded$points : null;
1031
+ result.sampledCount = traced.points.length;
1032
+ result.source = traced.retraced ? "geometry traced in ".concat(traced.traceMs.toFixed(1), " ms (").concat(traced.vertexCount, " verts, ").concat(traced.triCount, " tris in slice)") : "geometry cached (".concat(traced.triCount, " tris in slice)");
1033
+ return result;
1034
+ }
1035
+
1036
+ // Rectangular cutout from the measured rect instead. Correctly sized and
1037
+ // placed, just not shaped — which beats both a hole shaped by a stray detail
1038
+ // and no cutout at all in a deck-sized authored hole.
1039
+ result.points = measuredRectFootprint(rect, margin);
1040
+ result.sampledCount = (_result$points$length = (_result$points = result.points) === null || _result$points === void 0 ? void 0 : _result$points.length) !== null && _result$points$length !== void 0 ? _result$points$length : 0;
1041
+ result.source = maxX > minX ? "geometry: TRACE COVERS ONLY ".concat(((maxX - minX) / rawSizeX * 100).toFixed(0), "%\xD7").concat(((maxZ - minZ) / rawSizeZ * 100).toFixed(0), "% of the article \u2014 fell back to the measured rect") : 'geometry: NO TRIANGLES ABOVE THE SLICE PLANE — fell back to the measured rect';
1042
+ return result;
1043
+ }
1044
+
1045
+ function _createForOfIteratorHelper$2(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$2(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
1046
+ function _unsupportedIterableToArray$2(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$2(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$2(r, a) : void 0; } }
1047
+ function _arrayLikeToArray$2(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
1048
+
1049
+ /** Below this world delta (m) the element anchor correction is considered settled. */
1050
+ var ANCHOR_EPSILON = 1e-3;
1051
+ var _desired = new Vector3();
1052
+ var _measured = new Vector3();
1053
+
1054
+ /**
1055
+ * Distance to move one axis so the anchored part of the measured article lands
1056
+ * on the anchored part of the region. `'min'`/`'max'` pin that edge (the offset
1057
+ * reads as an inset from it) so the article grows away from it; `'center'`
1058
+ * centres, so it grows both ways.
1059
+ */
1060
+ function anchorDelta1D(mode, center, halfExtent, measuredMin, measuredMax, offset) {
1061
+ if (mode === 'min') return center - halfExtent + offset - measuredMin;
1062
+ if (mode === 'max') return center + halfExtent - offset - measuredMax;
1063
+ return center + offset - (measuredMin + measuredMax) / 2;
1064
+ }
1065
+ /**
1066
+ * Nudge the top-level element groups so the measured article rect settles at
1067
+ * the hole center (+ configured fine-tune offsets), optionally lifting it so
1068
+ * its top meets the deck. The measured rect already includes the currently
1069
+ * applied offsets, so the correction is incremental and converges in one
1070
+ * measurement. Null once it is within {@link ANCHOR_EPSILON} — or when there is
1071
+ * no top-level element to move.
1072
+ */
1073
+ function deriveElementAnchor(_ref) {
1074
+ var rect = _ref.rect,
1075
+ hole = _ref.hole,
1076
+ anchor = _ref.anchor,
1077
+ floorWorld = _ref.floorWorld,
1078
+ elementObjects = _ref.elementObjects,
1079
+ deckTopLocalY = _ref.deckTopLocalY,
1080
+ currentOffsets = _ref.currentOffsets;
1081
+ var localDx = anchorDelta1D(anchor.anchorX, hole.centerX, hole.halfExtentX, rect.minX, rect.maxX, anchor.offsetX);
1082
+ var localDz = anchorDelta1D(anchor.anchorZ, hole.centerZ, hole.halfExtentZ, rect.minZ, rect.maxZ, anchor.offsetZ);
1083
+ var centerX = (rect.minX + rect.maxX) / 2;
1084
+ var centerZ = (rect.minZ + rect.maxZ) / 2;
1085
+ // Vertical: HQS places every element on the ground, so a shallower basin
1086
+ // would sit with its rim below the deck — out of the footprint slice, and
1087
+ // visibly sunk. Aligning the TOP instead makes the basin's depth irrelevant.
1088
+ var measuredTopY = rect.maxY;
1089
+ var localDy = (anchor.alignTopToDeck ? deckTopLocalY - measuredTopY : 0) + anchor.offsetY;
1090
+
1091
+ // Convert the local-space correction to world space via two mapped points.
1092
+ _desired.set(centerX + localDx, measuredTopY + localDy, centerZ + localDz).applyMatrix4(floorWorld);
1093
+ _measured.set(centerX, measuredTopY, centerZ).applyMatrix4(floorWorld);
1094
+ var dx = _desired.x - _measured.x;
1095
+ var dy = _desired.y - _measured.y;
1096
+ var dz = _desired.z - _measured.z;
1097
+ if (Math.abs(dx) < ANCHOR_EPSILON && Math.abs(dy) < ANCHOR_EPSILON && Math.abs(dz) < ANCHOR_EPSILON) return null;
1098
+ var topLevel = topLevelElements(elementObjects);
1099
+ if (topLevel.length === 0) return null;
1100
+ var offsets = {};
1101
+ var _iterator = _createForOfIteratorHelper$2(topLevel),
1102
+ _step;
1103
+ try {
1104
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
1105
+ var _currentOffsets$key;
1106
+ var obj = _step.value;
1107
+ // MUST be the same key `ElementGroup` subscribes with — the composite
1108
+ // element key ("2", "2.0.6"), NOT the raw `Element#` name suffix (which
1109
+ // still carries the setId, e.g. "PLANNING_xE2").
1110
+ var key = parseElementKey(obj.name);
1111
+ var prev = (_currentOffsets$key = currentOffsets[key]) !== null && _currentOffsets$key !== void 0 ? _currentOffsets$key : [0, 0, 0];
1112
+ offsets[key] = [prev[0] + dx, prev[1] + dy, prev[2] + dz];
1113
+ }
1114
+ } catch (err) {
1115
+ _iterator.e(err);
1116
+ } finally {
1117
+ _iterator.f();
1118
+ }
1119
+ return {
1120
+ delta: {
1121
+ dx: localDx,
1122
+ dy: localDy,
1123
+ dz: localDz
1124
+ },
1125
+ offsets: offsets
1126
+ };
1127
+ }
1128
+
1129
+ /** Floor for the derived water-volume depth (m) — guards degenerate measurements while geo streams in. */
1130
+ var MIN_WATER_DEPTH = 0.5;
1131
+ var _basis = new Matrix3();
1132
+ var _center = new Vector3();
1133
+ var _extentX = new Vector3();
1134
+ var _extentZ = new Vector3();
1135
+ /**
1136
+ * Water volume following the MEASURED article rect — the water surface is a
1137
+ * property of the pool, not of the cutout, so it tracks the pool wherever the
1138
+ * element anchor settles it. No feedback: water never influences the measurement.
1139
+ *
1140
+ * The DEPTH is derived too: waterline down to the measured article bottom. The
1141
+ * volume only needs to BOUND the pool interior; the PoolHeightMap finds the real
1142
+ * floor within it.
1143
+ */
1144
+ function deriveWaterVolume(_ref) {
1145
+ var rect = _ref.rect,
1146
+ waterSync = _ref.waterSync,
1147
+ floorWorld = _ref.floorWorld,
1148
+ articleWorldBottomY = _ref.articleWorldBottomY,
1149
+ waterlineY = _ref.waterlineY;
1150
+ var inset = waterSync.inset;
1151
+ var sizeX = Math.max(rect.maxX - rect.minX - 2 * inset, 0.1);
1152
+ var sizeZ = Math.max(rect.maxZ - rect.minZ - 2 * inset, 0.1);
1153
+ _center.set((rect.minX + rect.maxX) / 2 + waterSync.offsetX, 0, (rect.minZ + rect.maxZ) / 2 + waterSync.offsetZ);
1154
+ _center.applyMatrix4(floorWorld);
1155
+
1156
+ // World-axis extents of the rotated local rect (scenes rotate in 90° steps,
1157
+ // so this stays exact; diagonal rotations would conservatively grow it).
1158
+ _basis.setFromMatrix4(floorWorld);
1159
+ _extentX.set(sizeX, 0, 0).applyMatrix3(_basis);
1160
+ _extentZ.set(0, 0, sizeZ).applyMatrix3(_basis);
1161
+ var worldSizeX = Math.abs(_extentX.x) + Math.abs(_extentZ.x);
1162
+ var worldSizeZ = Math.abs(_extentX.z) + Math.abs(_extentZ.z);
1163
+ var depth = Math.max(waterlineY - articleWorldBottomY, MIN_WATER_DEPTH);
1164
+ return {
1165
+ center: [_center.x, waterlineY, _center.z],
1166
+ size: [worldSizeX, depth, worldSizeZ]
1167
+ };
1168
+ }
1169
+
1170
+ /**
1171
+ * One line describing the whole cutout pipeline, plus the `key` it changes with:
1172
+ * the caller logs only when the key moves, so the line appears once per codex /
1173
+ * rule / outline state (bounds coarse-rounded to cm) rather than every measure.
1174
+ */
1175
+ function measureLog(_ref) {
1176
+ var _rule$match, _points$length, _fpBounds$map$join;
1177
+ var measurement = _ref.measurement,
1178
+ rule = _ref.rule,
1179
+ primaryCodex = _ref.primaryCodex,
1180
+ footprint = _ref.footprint,
1181
+ hole = _ref.hole;
1182
+ var rect = measurement.rect,
1183
+ floorTopY = measurement.floorTopY;
1184
+ var points = footprint.points;
1185
+ var fpBounds = points ? points.reduce(function (acc, _ref2) {
1186
+ var _ref3 = _slicedToArray(_ref2, 2),
1187
+ x = _ref3[0],
1188
+ z = _ref3[1];
1189
+ return [Math.min(acc[0], x), Math.max(acc[1], x), Math.min(acc[2], z), Math.max(acc[3], z)];
1190
+ }, [Infinity, -Infinity, Infinity, -Infinity]) : null;
1191
+ var key = "".concat(primaryCodex !== null && primaryCodex !== void 0 ? primaryCodex : '', "|").concat((_rule$match = rule === null || rule === void 0 ? void 0 : rule.match) !== null && _rule$match !== void 0 ? _rule$match : '', "|").concat(footprint.sampledCount, "|").concat((_points$length = points === null || points === void 0 ? void 0 : points.length) !== null && _points$length !== void 0 ? _points$length : 0, "|").concat((_fpBounds$map$join = fpBounds === null || fpBounds === void 0 ? void 0 : fpBounds.map(function (v) {
1192
+ return v.toFixed(2);
1193
+ }).join(',')) !== null && _fpBounds$map$join !== void 0 ? _fpBounds$map$join : '');
1194
+ var rawSizeX = rect.maxX - rect.minX;
1195
+ var rawSizeZ = rect.maxZ - rect.minZ;
1196
+ // Where the slice plane sits relative to the article. The plane is anchored to
1197
+ // the DECK top, so an article whose rim doesn't reach that high contributes
1198
+ // nothing but its topmost stray detail.
1199
+ var sliceInfo = rule && rule.footprintFromGeometry ? " | Y: deck top ".concat(floorTopY.toFixed(2), ", article [").concat(rect.minY.toFixed(2), ", ").concat(rect.maxY.toFixed(2), "], slice keeps \u2265 ").concat((floorTopY - rule.footprintSliceDepth).toFixed(2)) : '';
1200
+ var fpInfo;
1201
+ if (footprint.source === '') {
1202
+ fpInfo = ' | NO outline rule matched this codex → NO COLLAR, the authored hole stays fully open';
1203
+ } else if (fpBounds && points) {
1204
+ // Room left between the outline and each authored hole edge. Negative on any
1205
+ // side = the article is bigger than the hole it sits in; the collar clamps
1206
+ // the outline to the hole and degrades toward a solid slab.
1207
+ var slack = [fpBounds[0] - (hole.centerX - hole.halfExtentX), hole.centerX + hole.halfExtentX - fpBounds[1], fpBounds[2] - (hole.centerZ - hole.halfExtentZ), hole.centerZ + hole.halfExtentZ - fpBounds[3]].map(function (v) {
1208
+ return v.toFixed(2);
1209
+ });
1210
+ fpInfo = " | measured ".concat(rawSizeX.toFixed(2), "\xD7").concat(rawSizeZ.toFixed(2)) + (footprint.tracedBounds === '' ? '' : " | traced ".concat(footprint.sampledCount, " pts ").concat(footprint.tracedBounds)) + " | outline ".concat(points.length, " pts X [").concat(fpBounds[0].toFixed(2), ", ").concat(fpBounds[1].toFixed(2), "] Z [").concat(fpBounds[2].toFixed(2), ", ").concat(fpBounds[3].toFixed(2), "]") + " | hole X [".concat((hole.centerX - hole.halfExtentX).toFixed(2), ", ").concat((hole.centerX + hole.halfExtentX).toFixed(2), "] Z [").concat((hole.centerZ - hole.halfExtentZ).toFixed(2), ", ").concat((hole.centerZ + hole.halfExtentZ).toFixed(2), "]") + " | slack X ".concat(slack[0], "/").concat(slack[1], " Z ").concat(slack[2], "/").concat(slack[3]) + " | ".concat(footprint.source).concat(footprint.repairNote) + (footprint.trace.loops > 0 ? " | trace: ".concat(footprint.trace.filledCells, " cells (").concat(footprint.trace.enclosedFilled, " filled in), ").concat(footprint.trace.loops, " loop(s), kept ").concat((footprint.trace.chosenAreaShare * 100).toFixed(0), "% of contour area, ").concat(footprint.trace.pointsBeforeSimplify, " \u2192 ").concat(footprint.trace.pointsAfterSimplify, " pts") : '');
1211
+ } else {
1212
+ fpInfo = " | ".concat(footprint.source, " produced NO usable outline (").concat(footprint.sampledCount, " pts)").concat(footprint.repairNote, " \u2192 NO COLLAR, the authored hole stays fully open");
1213
+ }
1214
+ return {
1215
+ key: key,
1216
+ message: "[DeckCutout] article codex: ".concat(primaryCodex !== null && primaryCodex !== void 0 ? primaryCodex : '(unknown)', " \u2192 rule: ").concat(rule ? "'".concat(rule.match, "'") : '(none — articleSync globals)').concat(sliceInfo).concat(fpInfo)
1217
+ };
1218
+ }
1219
+
1220
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
1221
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1222
+ var LOG$2 = getLogger('RealTimeViewer', 'DeckCutoutArticleSync');
1223
+
1224
+ /** Re-measure cadence in frames — article geo loads/changes are not frame-critical. */
1225
+ var MEASURE_INTERVAL_FRAMES = 30;
1226
+ /**
1227
+ * Consecutive no-change measures after which the pipeline is considered settled
1228
+ * and the cheap idle cadence resumes.
1229
+ *
1230
+ * Deliberately NOT paired with hiding the scene: a scene-load gate registered
1231
+ * from here cannot hide the one frame that matters (the new article paints with
1232
+ * the previous outline before `articleVersion` — a passive effect — can react),
1233
+ * so it would only hide the frames that the folded-in anchor delta already
1234
+ * eliminates, at the price of a blank/overlay flash on every change.
1235
+ */
1236
+ var SETTLE_STABLE_MEASURES = 3;
1237
+
1238
+ /**
1239
+ * Drives the cutout outline, element placement and water volume from the live
1240
+ * article geometry (`deckCutout.articleSync` and friends):
1241
+ *
1242
+ * 1. {@link measureArticle} takes the union AABB of all planner `Element#`
1243
+ * groups in the floor meshes' shared local space.
1244
+ * 2. {@link deriveArticleFootprint} shapes the cutout outline →
1245
+ * `deckCutoutFootprintOverride`, which `DeckCutoutCollar` fills against the
1246
+ * deck's authored hole. Its traced rim replaces the measured extents for the
1247
+ * steps below, so parts under the deck don't inflate placement/water.
1248
+ * 3. {@link deriveElementAnchor} repositions the elements so their bbox rests
1249
+ * inside the authored hole (HQS `PosPivot === 'CENTER'` grows articles from
1250
+ * center, so the resting spot has to be re-derived) → `elementAnchorOffsets`.
1251
+ * 4. {@link deriveWaterVolume} follows the anchored rect → `waterVolumeOverride`.
1252
+ *
1253
+ * Re-converges (per-frame measuring) when article or decor geometry lands, and
1254
+ * otherwise re-measures on a slow idle cadence for the inputs that have no
1255
+ * event (imperative scene-transform edits). All writers are epsilon-compared,
1256
+ * so unchanged measurements are no-ops.
1257
+ */
1258
+ function DeckCutoutArticleSync() {
1259
+ var scene = useThree(function (s) {
1260
+ return s.scene;
1261
+ });
1262
+ var deckCutoutJson = useRTVStore(function (s) {
1263
+ return JSON.stringify(s.resolvedEnvironment.scene.deckCutout);
1264
+ });
1265
+ var deform = useMemo(function () {
1266
+ return JSON.parse(deckCutoutJson);
1267
+ }, [deckCutoutJson]);
1268
+ var setWaterOverride = useRTVStore(function (s) {
1269
+ return s.setWaterVolumeOverride;
1270
+ });
1271
+ var setFootprintOverride = useRTVStore(function (s) {
1272
+ return s.setDeckCutoutFootprintOverride;
1273
+ });
1274
+ var frameRef = useRef(0);
1275
+ // Boot diagnostics: how many measure passes the pipeline needed before it produced an outline.
1276
+ var measureCountRef = useRef(0);
1277
+ var footprintMarkedRef = useRef(false);
1278
+ // One-shot codex/rule log: fires only when the measured codex or matched rule changes.
1279
+ var matchLogRef = useRef(null);
1280
+ var geometryCacheRef = useRef(null);
1281
+ // Settle tracking: measure every frame while the pipeline is still changing.
1282
+ var settlingRef = useRef(false);
1283
+ var stableMeasuresRef = useRef(0);
1284
+ var active = deform.enabled && deform.articleSync.enabled;
1285
+ var anchorActive = active && deform.elementAnchor.enabled;
1286
+ var waterActive = active && deform.waterSync.enabled;
1287
+
1288
+ // Clear derived state when a driver is turned off (and on unmount) so the
1289
+ // manual config values take effect again.
1290
+ // The cleanup is registered even while the driver is ACTIVE: an unmount that leaves
1291
+ // `deckCutout.enabled` on — the host dropping the 3D scene takes `mountScene3D` down while the
1292
+ // water stays on `mountWater` — would otherwise strand the last article's derived geometry, and
1293
+ // the pool would keep that article's centre and size.
1294
+ useEffect(function () {
1295
+ if (!active) setFootprintOverride(null);
1296
+ return function () {
1297
+ return setFootprintOverride(null);
1298
+ };
1299
+ }, [active, setFootprintOverride]);
1300
+ useEffect(function () {
1301
+ var clear = function clear() {
1302
+ if (Object.keys(useRTVStore.getState().elementAnchorOffsets).length > 0) {
1303
+ useRTVStore.getState().setElementAnchorOffsets({});
1304
+ }
1305
+ };
1306
+ if (!anchorActive) clear();
1307
+ return clear;
1308
+ }, [anchorActive]);
1309
+ useEffect(function () {
1310
+ if (!waterActive) setWaterOverride(null);
1311
+ return function () {
1312
+ return setWaterOverride(null);
1313
+ };
1314
+ }, [waterActive, setWaterOverride]);
1315
+ var patterns = useMemo(function () {
1316
+ return deform.nodeMatch.split(',').map(function (p) {
1317
+ return p.trim();
1318
+ }).filter(function (p) {
1319
+ return p.length > 0;
1320
+ });
1321
+ }, [deform.nodeMatch]);
1322
+
1323
+ // `articleVersion` fires from inside the article's Suspense boundary — when a
1324
+ // new article's geometry is fully loaded and live; `decorVersion` when a deck
1325
+ // GLB (the floor frame) has mounted. Those are exactly the moments the
1326
+ // pipeline has to re-converge, and the moments before which nothing should be
1327
+ // shown.
1328
+ var articleVersion = useRTVStore(function (s) {
1329
+ return s.articleVersion;
1330
+ });
1331
+ var decorVersion = useRTVStore(function (s) {
1332
+ return s.decorVersion;
1333
+ });
1334
+ useEffect(function () {
1335
+ if (!active) return;
1336
+ settlingRef.current = true;
1337
+ stableMeasuresRef.current = 0;
1338
+ }, [articleVersion, decorVersion, active]);
1339
+ useFrame(function () {
1340
+ if (!active || patterns.length === 0) return;
1341
+ frameRef.current += 1;
1342
+ // While unsettled, measure EVERY frame: the pipeline converges by
1343
+ // re-measuring (the element anchor corrects against its own last move), so
1344
+ // on the idle cadence each step of that convergence is a visible ~0.5 s
1345
+ // state. Per-frame measuring collapses them into consecutive frames.
1346
+ if (!settlingRef.current && frameRef.current % MEASURE_INTERVAL_FRAMES !== 1) return;
1347
+
1348
+ // A measure that changes nothing marks progress toward "settled". State is
1349
+ // epsilon-compared in the store, so an unchanged write keeps the SAME
1350
+ // object reference — comparing references detects real change exactly.
1351
+ var before = useRTVStore.getState();
1352
+ var beforeWater = before.waterVolumeOverride;
1353
+ var beforeFootprint = before.deckCutoutFootprintOverride;
1354
+ var anchorMoved = false;
1355
+ // `waiting` = the article or floor isn't there yet. Nothing to converge on,
1356
+ // so drop to the idle cadence; their arrival re-arms per-frame measuring
1357
+ // through the version effect above.
1358
+ var finishMeasure = function finishMeasure() {
1359
+ var waiting = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
1360
+ if (waiting) {
1361
+ stableMeasuresRef.current = 0;
1362
+ settlingRef.current = false;
1363
+ return;
1364
+ }
1365
+ var after = useRTVStore.getState();
1366
+ var changed = anchorMoved || after.waterVolumeOverride !== beforeWater || after.deckCutoutFootprintOverride !== beforeFootprint;
1367
+ if (changed) {
1368
+ stableMeasuresRef.current = 0;
1369
+ settlingRef.current = true;
1370
+ return;
1371
+ }
1372
+ stableMeasuresRef.current += 1;
1373
+ if (stableMeasuresRef.current >= SETTLE_STABLE_MEASURES) settlingRef.current = false;
1374
+ };
1375
+ measureCountRef.current += 1;
1376
+ var measured = measureArticle(scene, patterns, useRTVStore.getState().elementsInfo);
1377
+ if (!measured) {
1378
+ setWaterOverride(null);
1379
+ setFootprintOverride(null);
1380
+ finishMeasure(true);
1381
+ return;
1382
+ }
1383
+ var _pickArticleRule = pickArticleRule(deform.articleRules, measured.codexesByArea),
1384
+ rule = _pickArticleRule.rule,
1385
+ primaryCodex = _pickArticleRule.primaryCodex;
1386
+ var traced = deriveArticleFootprint(measured, rule, deform.articleSync.margin, geometryCacheRef);
1387
+ var rect = traced.rim ? _objectSpread(_objectSpread({}, measured.rect), traced.rim) : measured.rect;
1388
+ var log = measureLog({
1389
+ measurement: measured,
1390
+ rule: rule,
1391
+ primaryCodex: primaryCodex,
1392
+ footprint: traced,
1393
+ hole: deform.authoredHole
1394
+ });
1395
+ if (matchLogRef.current !== log.key) {
1396
+ matchLogRef.current = log.key;
1397
+ LOG$2.debug(log.message);
1398
+ }
1399
+
1400
+ // The deck is never reshaped: the collar fills everything between its
1401
+ // authored hole and the article outline, so the hole the article rests in is
1402
+ // a constant of the asset. The anchor MUST use that same `authoredHole` —
1403
+ // anchoring to a different rect strands the article against one edge of the
1404
+ // region and leaves the far side unused (it shows up as clamped outline points).
1405
+ var anchor = anchorActive ? deriveElementAnchor({
1406
+ rect: rect,
1407
+ hole: deform.authoredHole,
1408
+ anchor: deform.elementAnchor,
1409
+ floorWorld: measured.floorWorld,
1410
+ elementObjects: measured.elementObjects,
1411
+ deckTopLocalY: measured.floorTopY,
1412
+ currentOffsets: useRTVStore.getState().elementAnchorOffsets
1413
+ }) : null;
1414
+ anchorMoved = anchor !== null;
1415
+ if (anchor) useRTVStore.getState().setElementAnchorOffsets(anchor.offsets);
1416
+ // The anchor's move only shows from the NEXT frame, so everything derived
1417
+ // from the article's position — the water surface, the shaped outline —
1418
+ // would otherwise describe the old spot and visibly catch up one measure
1419
+ // later. Folding the delta in here makes a single measure produce the final
1420
+ // state: one visible update instead of a chain of them.
1421
+ var anchored = anchor ? shiftRect(rect, anchor.delta) : rect;
1422
+ setFootprintOverride(traced.points && anchor ? traced.points.map(function (_ref) {
1423
+ var _ref2 = _slicedToArray(_ref, 2),
1424
+ x = _ref2[0],
1425
+ z = _ref2[1];
1426
+ return [x + anchor.delta.dx, z + anchor.delta.dz];
1427
+ }) : traced.points);
1428
+ if (!footprintMarkedRef.current && useRTVStore.getState().deckCutoutFootprintOverride !== null) {
1429
+ footprintMarkedRef.current = true;
1430
+ bootPhase('deck: first footprint published', {
1431
+ measures: measureCountRef.current
1432
+ });
1433
+ }
1434
+ if (waterActive) {
1435
+ setWaterOverride(deriveWaterVolume({
1436
+ rect: anchored,
1437
+ waterSync: deform.waterSync,
1438
+ floorWorld: measured.floorWorld,
1439
+ articleWorldBottomY: measured.worldBottomY,
1440
+ waterlineY: useRTVStore.getState().resolvedEnvironment.water.volume.center[1]
1441
+ }));
1442
+ }
1443
+ finishMeasure();
1444
+ });
1445
+ return null;
1446
+ }
1447
+
1448
+ /*
1449
+ * Local UV sampling — continues a mesh's texture mapping onto generated
1450
+ * geometry that sits BESIDE it (e.g. a collar filling a floor's cutout).
1451
+ *
1452
+ * A single global affine mapping fitted over the whole surface only matches
1453
+ * where the surface's unwrap really is one plane at one density. It fails for
1454
+ * per-board UV islands, for surfaces whose density varies (a warped slab whose
1455
+ * pattern anchoring is imperfect), and for neighbours whose unwraps differ.
1456
+ * Sampling the NEAREST triangle's own mapping and extrapolating it sidesteps
1457
+ * all of that: the generated surface continues exactly what its neighbour
1458
+ * shows, locally.
1459
+ *
1460
+ * Deliberately three.js-free: a flat triangle soup in, UV out.
1461
+ */
1462
+
1463
+ /** Floats per triangle in the soup: (x, z, u, v) per vertex. */
1464
+ var UV_TRIANGLE_STRIDE = 12;
1465
+ var EPS = 1e-12;
1466
+
1467
+ /** One affine UV mapping over XZ: `u = ux·x + uz·z + u0`, likewise for v. */
1468
+
1469
+ /** Solve a 3x3 system by Cramer's rule; null when singular. */
1470
+ function solve3(m, b) {
1471
+ var det = m[0] * (m[4] * m[8] - m[5] * m[7]) - m[1] * (m[3] * m[8] - m[5] * m[6]) + m[2] * (m[3] * m[7] - m[4] * m[6]);
1472
+ if (Math.abs(det) < EPS) return null;
1473
+ var d = function d(c0, c1, c2) {
1474
+ return c0 * (m[4] * m[8] - m[5] * m[7]) - m[1] * (c1 * m[8] - m[5] * c2) + m[2] * (c1 * m[7] - m[4] * c2);
1475
+ };
1476
+ var x = d(b[0], b[1], b[2]) / det;
1477
+ var y = (m[0] * (b[1] * m[8] - m[5] * b[2]) - b[0] * (m[3] * m[8] - m[5] * m[6]) + m[2] * (m[3] * b[2] - b[1] * m[6])) / det;
1478
+ var z = (m[0] * (m[4] * b[2] - b[1] * m[7]) - m[1] * (m[3] * b[2] - b[1] * m[6]) + b[0] * (m[3] * m[7] - m[4] * m[6])) / det;
1479
+ return [x, y, z];
1480
+ }
1481
+
1482
+ /**
1483
+ * Least-squares fit of ONE affine mapping over every vertex in the soup.
1484
+ *
1485
+ * Where it fits (a planar unwrap at uniform density), it beats
1486
+ * {@link sampleNearestTriangleUV} on generated geometry: the local sampler
1487
+ * decides per vertex, so two ends of a generated triangle can land on different
1488
+ * source triangles and the interpolation between them blends two mappings —
1489
+ * a visible shear, worst on long thin triangles like those a curved outline
1490
+ * produces. One mapping for every vertex cannot shear. Check
1491
+ * {@link AffineUV.residualMetres} before trusting it.
1492
+ */
1493
+ function fitAffineUV(triangles, triangleCount) {
1494
+ var samples = triangleCount * 3;
1495
+ if (samples < 3) return null;
1496
+ // Normal equations for the design matrix [x, z, 1], shared by u and v.
1497
+ var sxx = 0;
1498
+ var sxz = 0;
1499
+ var sx = 0;
1500
+ var szz = 0;
1501
+ var sz = 0;
1502
+ var sxu = 0;
1503
+ var szu = 0;
1504
+ var su = 0;
1505
+ var sxv = 0;
1506
+ var szv = 0;
1507
+ var sv = 0;
1508
+ for (var i = 0; i < samples; i++) {
1509
+ var o = i * 4;
1510
+ var x = triangles[o];
1511
+ var z = triangles[o + 1];
1512
+ var u = triangles[o + 2];
1513
+ var v = triangles[o + 3];
1514
+ sxx += x * x;
1515
+ sxz += x * z;
1516
+ sx += x;
1517
+ szz += z * z;
1518
+ sz += z;
1519
+ sxu += x * u;
1520
+ szu += z * u;
1521
+ su += u;
1522
+ sxv += x * v;
1523
+ szv += z * v;
1524
+ sv += v;
1525
+ }
1526
+ var m = [sxx, sxz, sx, sxz, szz, sz, sx, sz, samples];
1527
+ var uSol = solve3(m, [sxu, szu, su]);
1528
+ var vSol = solve3(m, [sxv, szv, sv]);
1529
+ if (!uSol || !vSol) return null;
1530
+ var errSq = 0;
1531
+ for (var _i = 0; _i < samples; _i++) {
1532
+ var _o = _i * 4;
1533
+ var _x = triangles[_o];
1534
+ var _z = triangles[_o + 1];
1535
+ var du = uSol[0] * _x + uSol[1] * _z + uSol[2] - triangles[_o + 2];
1536
+ var dv = vSol[0] * _x + vSol[1] * _z + vSol[2] - triangles[_o + 3];
1537
+ errSq += du * du + dv * dv;
1538
+ }
1539
+ // UV error → metres, via the mapping's own uv-per-metre.
1540
+ var perMetre = (Math.hypot(uSol[0], uSol[1]) + Math.hypot(vSol[0], vSol[1])) / 2;
1541
+ var rms = Math.sqrt(errSq / samples);
1542
+ return {
1543
+ ux: uSol[0],
1544
+ uz: uSol[1],
1545
+ u0: uSol[2],
1546
+ vx: vSol[0],
1547
+ vz: vSol[1],
1548
+ v0: vSol[2],
1549
+ residualMetres: perMetre > EPS ? rms / perMetre : Infinity
1550
+ };
1551
+ }
1552
+
1553
+ /** Squared distance from (px, pz) to the segment (ax, az)–(bx, bz). */
1554
+ function segmentDistanceSq(px, pz, ax, az, bx, bz) {
1555
+ var dx = bx - ax;
1556
+ var dz = bz - az;
1557
+ var lengthSq = dx * dx + dz * dz;
1558
+ var t = lengthSq < EPS ? 0 : Math.max(0, Math.min(1, ((px - ax) * dx + (pz - az) * dz) / lengthSq));
1559
+ var cx = ax + t * dx - px;
1560
+ var cz = az + t * dz - pz;
1561
+ return cx * cx + cz * cz;
1562
+ }
1563
+
1564
+ /**
1565
+ * Squared distance from a point to a triangle in the XZ plane — 0 inside it,
1566
+ * else the nearest edge distance.
1567
+ */
1568
+ function triangleDistanceSq(px, pz, x0, z0, x1, z1, x2, z2) {
1569
+ // Zero area makes all three edge signs zero, so the inside test below would answer "contains"
1570
+ // for every point on the plane and this triangle would win every query. It can stand in for
1571
+ // nothing — keep it out of the running.
1572
+ if ((x1 - x0) * (z2 - z0) - (x2 - x0) * (z1 - z0) === 0) return Infinity;
1573
+ // Inside test via consistent edge signs (winding-agnostic).
1574
+ var d0 = (x1 - x0) * (pz - z0) - (z1 - z0) * (px - x0);
1575
+ var d1 = (x2 - x1) * (pz - z1) - (z2 - z1) * (px - x1);
1576
+ var d2 = (x0 - x2) * (pz - z2) - (z0 - z2) * (px - x2);
1577
+ var allNonNeg = d0 >= 0 && d1 >= 0 && d2 >= 0;
1578
+ var allNonPos = d0 <= 0 && d1 <= 0 && d2 <= 0;
1579
+ if (allNonNeg || allNonPos) return 0;
1580
+ return Math.min(segmentDistanceSq(px, pz, x0, z0, x1, z1), segmentDistanceSq(px, pz, x1, z1, x2, z2), segmentDistanceSq(px, pz, x2, z2, x0, z0));
1581
+ }
1582
+
1583
+ /** Nearest triangle by linear scan: minimum distance, ties to the lowest index. */
1584
+ function nearestTriangleLinear(triangles, triangleCount, x, z) {
1585
+ var bestDistance = Infinity;
1586
+ var best = -1;
1587
+ for (var t = 0; t < triangleCount; t++) {
1588
+ var o = t * UV_TRIANGLE_STRIDE;
1589
+ var distance = triangleDistanceSq(x, z, triangles[o], triangles[o + 1], triangles[o + 4], triangles[o + 5], triangles[o + 8], triangles[o + 9]);
1590
+ if (distance < bestDistance) {
1591
+ // A containing triangle (distance 0) is as good as it gets.
1592
+ bestDistance = distance;
1593
+ best = t;
1594
+ if (distance === 0) break;
1595
+ }
1596
+ }
1597
+ return best;
1598
+ }
1599
+
1600
+ /** Below this the scan is already shorter than the ring walk that would replace it. */
1601
+ var MIN_INDEXED_TRIANGLES = 64;
1602
+ /** Cap on the grid's columns and rows — bounds memory when the deck is a long thin strip. */
1603
+ var MAX_GRID_DIM = 256;
1604
+ /** A triangle covering more cells than this is scanned on every query instead of registered in all of them. */
1605
+ var MAX_TRIANGLE_CELLS = 64;
1606
+ /** Give up on the index once this share of the soup would be scanned on every query anyway. */
1607
+ var MAX_EXTRA_SHARE = 0.25;
1608
+ /**
1609
+ * Relative slack on the ring-termination bound. The bound — nothing unvisited is
1610
+ * nearer than the gap to the visited block — holds exactly in real arithmetic;
1611
+ * the slack keeps it true in floating point, so the walk can never stop one
1612
+ * rounding error before the triangle a linear scan would have found.
1613
+ */
1614
+ var RING_SLACK = 1e-9;
1615
+ /** A query this many cells outside the grid is scanned linearly rather than walked to. */
1616
+ var MAX_QUERY_CELL_OFFSET = 1e7;
1617
+
1618
+ /**
1619
+ * Uniform XZ grid over a triangle soup, so a nearest-triangle query touches a
1620
+ * handful of cells instead of every triangle. Build it once per surface with
1621
+ * {@link buildTriangleGridIndex} and pass it to {@link sampleNearestTriangleUV},
1622
+ * which then returns exactly what the linear scan returns — same triangle, same
1623
+ * tie-break, same UV.
1624
+ */
1625
+
1626
+ function isFiniteXZ(x0, z0, x1, z1, x2, z2) {
1627
+ return Number.isFinite(x0) && Number.isFinite(z0) && Number.isFinite(x1) && Number.isFinite(z1) && Number.isFinite(x2) && Number.isFinite(z2);
1628
+ }
1629
+
1630
+ /** Column/row count for one axis, clamped to at least one cell and at most {@link MAX_GRID_DIM}. */
1631
+ function gridDim(extent, cellSize) {
1632
+ return Math.min(MAX_GRID_DIM, Math.max(1, Math.ceil(extent / cellSize)));
1633
+ }
1634
+
1635
+ /** Cell containing `value` on one axis, clamped into the grid (only the far edge needs the clamp). */
1636
+ function cellOf(value, min, cellSize, count) {
1637
+ var i = Math.floor((value - min) / cellSize);
1638
+ if (i < 0) return 0;
1639
+ return i >= count ? count - 1 : i;
1640
+ }
1641
+
1642
+ /**
1643
+ * Uniform grid over the soup's XZ bounds, each triangle registered in every cell
1644
+ * its bounding box overlaps. Build it once per surface — it depends on the soup
1645
+ * alone — and reuse it for every query against that soup.
1646
+ *
1647
+ * Cell size is the larger of the mean triangle extent and the size that puts
1648
+ * about one triangle in a cell: smaller than the triangles themselves only
1649
+ * multiplies registrations without narrowing a query, larger leaves too many
1650
+ * triangles per cell to skip.
1651
+ *
1652
+ * Returns null when an index would not pay for itself or could not be trusted —
1653
+ * too few triangles, a soup that is one point, or too much of it non-finite. The
1654
+ * caller then scans linearly, which is what the index reproduces anyway.
1655
+ */
1656
+ function buildTriangleGridIndex(triangles, triangleCount) {
1657
+ if (triangleCount < MIN_INDEXED_TRIANGLES) return null;
1658
+ var minX = Infinity;
1659
+ var maxX = -Infinity;
1660
+ var minZ = Infinity;
1661
+ var maxZ = -Infinity;
1662
+ var extentSum = 0;
1663
+ var finite = 0;
1664
+ for (var t = 0; t < triangleCount; t++) {
1665
+ var o = t * UV_TRIANGLE_STRIDE;
1666
+ var x0 = triangles[o];
1667
+ var z0 = triangles[o + 1];
1668
+ var x1 = triangles[o + 4];
1669
+ var z1 = triangles[o + 5];
1670
+ var x2 = triangles[o + 8];
1671
+ var z2 = triangles[o + 9];
1672
+ if (!isFiniteXZ(x0, z0, x1, z1, x2, z2)) continue;
1673
+ var tMinX = Math.min(x0, x1, x2);
1674
+ var tMaxX = Math.max(x0, x1, x2);
1675
+ var tMinZ = Math.min(z0, z1, z2);
1676
+ var tMaxZ = Math.max(z0, z1, z2);
1677
+ if (tMinX < minX) minX = tMinX;
1678
+ if (tMaxX > maxX) maxX = tMaxX;
1679
+ if (tMinZ < minZ) minZ = tMinZ;
1680
+ if (tMaxZ > maxZ) maxZ = tMaxZ;
1681
+ extentSum += Math.max(tMaxX - tMinX, tMaxZ - tMinZ);
1682
+ finite += 1;
1683
+ }
1684
+ if (finite < MIN_INDEXED_TRIANGLES || triangleCount - finite > triangleCount * MAX_EXTRA_SHARE) return null;
1685
+ var width = maxX - minX;
1686
+ var depth = maxZ - minZ;
1687
+ var span = Math.max(width, depth);
1688
+ // Every triangle on one spot — no partition can separate them.
1689
+ if (!(span > 0)) return null;
1690
+ var perCell = width * depth / finite;
1691
+ var cellSize = Math.max(extentSum / finite, perCell > 0 ? Math.sqrt(perCell) : 0, span / MAX_GRID_DIM);
1692
+ var cols = gridDim(width, cellSize);
1693
+ var rows = gridDim(depth, cellSize);
1694
+ // An extreme aspect ratio can still ask for far more cells than triangles.
1695
+ var maxCells = Math.max(1024, finite * 4);
1696
+ if (cols * rows > maxCells) {
1697
+ cellSize *= Math.sqrt(cols * rows / maxCells);
1698
+ cols = gridDim(width, cellSize);
1699
+ rows = gridDim(depth, cellSize);
1700
+ }
1701
+ var cellCount = cols * rows;
1702
+ var spans = new Int32Array(triangleCount * 4);
1703
+ // One slot ahead, so the prefix sum below turns counts into CSR offsets in place.
1704
+ var cellStart = new Int32Array(cellCount + 1);
1705
+ var extras = [];
1706
+ for (var _t = 0; _t < triangleCount; _t++) {
1707
+ var _o2 = _t * UV_TRIANGLE_STRIDE;
1708
+ var _x2 = triangles[_o2];
1709
+ var _z2 = triangles[_o2 + 1];
1710
+ var _x3 = triangles[_o2 + 4];
1711
+ var _z3 = triangles[_o2 + 5];
1712
+ var _x4 = triangles[_o2 + 8];
1713
+ var _z4 = triangles[_o2 + 9];
1714
+ // Zero area makes every edge sign zero, so the inside test answers "distance
1715
+ // 0" for any point whatsoever — position tells nothing about such a triangle.
1716
+ if (!isFiniteXZ(_x2, _z2, _x3, _z3, _x4, _z4) || (_x3 - _x2) * (_z4 - _z2) - (_x4 - _x2) * (_z3 - _z2) === 0) {
1717
+ spans[_t * 4] = -1;
1718
+ extras.push(_t);
1719
+ continue;
1720
+ }
1721
+ var i0 = cellOf(Math.min(_x2, _x3, _x4), minX, cellSize, cols);
1722
+ var i1 = cellOf(Math.max(_x2, _x3, _x4), minX, cellSize, cols);
1723
+ var j0 = cellOf(Math.min(_z2, _z3, _z4), minZ, cellSize, rows);
1724
+ var j1 = cellOf(Math.max(_z2, _z3, _z4), minZ, cellSize, rows);
1725
+ if ((i1 - i0 + 1) * (j1 - j0 + 1) > MAX_TRIANGLE_CELLS) {
1726
+ spans[_t * 4] = -1;
1727
+ extras.push(_t);
1728
+ continue;
1729
+ }
1730
+ spans[_t * 4] = i0;
1731
+ spans[_t * 4 + 1] = i1;
1732
+ spans[_t * 4 + 2] = j0;
1733
+ spans[_t * 4 + 3] = j1;
1734
+ for (var j = j0; j <= j1; j++) {
1735
+ for (var i = i0; i <= i1; i++) cellStart[j * cols + i + 1] += 1;
1736
+ }
1737
+ }
1738
+ if (extras.length > triangleCount * MAX_EXTRA_SHARE) return null;
1739
+ for (var c = 0; c < cellCount; c++) cellStart[c + 1] += cellStart[c];
1740
+ var cellItems = new Int32Array(cellStart[cellCount]);
1741
+ var cursor = cellStart.slice(0, cellCount);
1742
+ for (var _t2 = 0; _t2 < triangleCount; _t2++) {
1743
+ var _i2 = spans[_t2 * 4];
1744
+ if (_i2 < 0) continue;
1745
+ var _i3 = spans[_t2 * 4 + 1];
1746
+ var _j = spans[_t2 * 4 + 2];
1747
+ var _j2 = spans[_t2 * 4 + 3];
1748
+ for (var _j3 = _j; _j3 <= _j2; _j3++) {
1749
+ for (var _i4 = _i2; _i4 <= _i3; _i4++) {
1750
+ var _c = _j3 * cols + _i4;
1751
+ cellItems[cursor[_c]] = _t2;
1752
+ cursor[_c] += 1;
1753
+ }
1754
+ }
1755
+ }
1756
+ return {
1757
+ triangleCount: triangleCount,
1758
+ minX: minX,
1759
+ minZ: minZ,
1760
+ cellSize: cellSize,
1761
+ cols: cols,
1762
+ rows: rows,
1763
+ cellStart: cellStart,
1764
+ cellItems: cellItems,
1765
+ extras: Int32Array.from(extras)
1766
+ };
1767
+ }
1768
+
1769
+ /**
1770
+ * Nearest triangle via {@link TriangleGridIndex}: the point's own cell first,
1771
+ * then ring by ring outward.
1772
+ *
1773
+ * A ring may only end the walk once the best distance found is provably below
1774
+ * the gap between the point and the block of cells already visited — every
1775
+ * unvisited triangle lies outside that block, so nothing out there can be
1776
+ * nearer. Ties go to the lowest triangle index whatever order the cells are
1777
+ * walked in, which is what a linear scan's `distance < bestDistance` produces.
1778
+ */
1779
+ function nearestTriangleIndexed(triangles, x, z, index) {
1780
+ var minX = index.minX,
1781
+ minZ = index.minZ,
1782
+ cellSize = index.cellSize,
1783
+ cols = index.cols,
1784
+ rows = index.rows,
1785
+ cellStart = index.cellStart,
1786
+ cellItems = index.cellItems,
1787
+ extras = index.extras;
1788
+ var cx = Math.floor((x - minX) / cellSize);
1789
+ var cz = Math.floor((z - minZ) / cellSize);
1790
+ // A non-finite or absurdly distant query has no cell to start from.
1791
+ if (!Number.isFinite(cx) || !Number.isFinite(cz) || Math.abs(cx) > MAX_QUERY_CELL_OFFSET || Math.abs(cz) > MAX_QUERY_CELL_OFFSET) {
1792
+ return nearestTriangleLinear(triangles, index.triangleCount, x, z);
1793
+ }
1794
+ var bestDistance = Infinity;
1795
+ var best = -1;
1796
+ var consider = function consider(t) {
1797
+ var o = t * UV_TRIANGLE_STRIDE;
1798
+ var distance = triangleDistanceSq(x, z, triangles[o], triangles[o + 1], triangles[o + 4], triangles[o + 5], triangles[o + 8], triangles[o + 9]);
1799
+ // Lowest index wins a tie, so cell order cannot change the answer. NaN and
1800
+ // Infinity fail both tests, exactly as `distance < bestDistance` alone does.
1801
+ if (distance < bestDistance || distance === bestDistance && t < best) {
1802
+ bestDistance = distance;
1803
+ best = t;
1804
+ }
1805
+ };
1806
+ var scanCell = function scanCell(cell) {
1807
+ var end = cellStart[cell + 1];
1808
+ for (var k = cellStart[cell]; k < end; k++) consider(cellItems[k]);
1809
+ };
1810
+ for (var k = 0; k < extras.length; k++) consider(extras[k]);
1811
+
1812
+ // Rings are centred on the point's cell even when that sits outside the grid,
1813
+ // so the gap below grows with distance instead of stalling at a clamped edge.
1814
+ var first = Math.max(0, -cx, cx - cols + 1, -cz, cz - rows + 1);
1815
+ var last = Math.max(cx, cols - 1 - cx, cz, rows - 1 - cz);
1816
+ for (var r = first; r <= last; r++) {
1817
+ var i0 = cx - r;
1818
+ var i1 = cx + r;
1819
+ var j0 = cz - r;
1820
+ var j1 = cz + r;
1821
+ var ia = Math.max(0, i0);
1822
+ var ib = Math.min(cols - 1, i1);
1823
+ if (j0 >= 0 && j0 < rows) {
1824
+ for (var i = ia; i <= ib; i++) scanCell(j0 * cols + i);
1825
+ }
1826
+ if (r > 0) {
1827
+ if (j1 >= 0 && j1 < rows) {
1828
+ for (var _i5 = ia; _i5 <= ib; _i5++) scanCell(j1 * cols + _i5);
1829
+ }
1830
+ var ja = Math.max(0, j0 + 1);
1831
+ var jb = Math.min(rows - 1, j1 - 1);
1832
+ if (i0 >= 0 && i0 < cols) {
1833
+ for (var j = ja; j <= jb; j++) scanCell(j * cols + i0);
1834
+ }
1835
+ if (i1 >= 0 && i1 < cols) {
1836
+ for (var _j4 = ja; _j4 <= jb; _j4++) scanCell(_j4 * cols + i1);
1837
+ }
1838
+ }
1839
+ // Distance from the point to the edge of everything visited so far. Strictly
1840
+ // below it, no unvisited triangle can beat OR tie the best found.
1841
+ var gap = Math.min(x - (minX + i0 * cellSize), minX + (i1 + 1) * cellSize - x, z - (minZ + j0 * cellSize), minZ + (j1 + 1) * cellSize - z);
1842
+ if (gap > 0 && bestDistance < gap * gap * (1 - RING_SLACK)) return best;
1843
+ }
1844
+ return best;
1845
+ }
1846
+
1847
+ /**
1848
+ * UV at (x, z) taken from the triangle nearest to it, evaluated through that
1849
+ * triangle's own affine mapping. Points outside the triangle EXTRAPOLATE it,
1850
+ * which is the point: the sampled position generally lies in the hole beside
1851
+ * the surface, and extrapolating its neighbour's plank mapping continues the
1852
+ * pattern across the seam.
1853
+ *
1854
+ * `triangles` holds {@link UV_TRIANGLE_STRIDE} floats per triangle:
1855
+ * `x0, z0, u0, v0, x1, z1, u1, v1, x2, z2, u2, v2`. Returns null for an empty
1856
+ * soup or when every triangle is degenerate in XZ.
1857
+ *
1858
+ * Pass the soup's {@link TriangleGridIndex} to skip the linear scan over every
1859
+ * triangle; the result is identical either way.
1860
+ */
1861
+ function sampleNearestTriangleUV(triangles, triangleCount, x, z, index) {
1862
+ var best = index && index.triangleCount === triangleCount ? nearestTriangleIndexed(triangles, x, z, index) : nearestTriangleLinear(triangles, triangleCount, x, z);
1863
+ if (best < 0) return null;
1864
+ var o = best * UV_TRIANGLE_STRIDE;
1865
+ var x0 = triangles[o];
1866
+ var z0 = triangles[o + 1];
1867
+ var x1 = triangles[o + 4];
1868
+ var z1 = triangles[o + 5];
1869
+ var x2 = triangles[o + 8];
1870
+ var z2 = triangles[o + 9];
1871
+ var det = (z1 - z2) * (x0 - x2) + (x2 - x1) * (z0 - z2);
1872
+ if (Math.abs(det) < EPS) return null;
1873
+ // Barycentric weights, deliberately unclamped so the mapping extrapolates.
1874
+ var w0 = ((z1 - z2) * (x - x2) + (x2 - x1) * (z - z2)) / det;
1875
+ var w1 = ((z2 - z0) * (x - x2) + (x0 - x2) * (z - z2)) / det;
1876
+ var w2 = 1 - w0 - w1;
1877
+ return [w0 * triangles[o + 2] + w1 * triangles[o + 6] + w2 * triangles[o + 10], w0 * triangles[o + 3] + w1 * triangles[o + 7] + w2 * triangles[o + 11]];
1878
+ }
1879
+
1880
+ function _createForOfIteratorHelper$1(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$1(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
1881
+ function _unsupportedIterableToArray$1(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$1(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$1(r, a) : void 0; } }
1882
+ function _arrayLikeToArray$1(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
1883
+
1884
+ /** Minimum +Y normal for a deck triangle to count as top surface (excludes side faces). */
1885
+ var UP_NORMAL_MIN = 0.9;
1886
+ /**
1887
+ * How far (m) a single fitted mapping may miss the deck's own triangles before
1888
+ * it is rejected in favour of per-vertex sampling. Below this the deck's unwrap
1889
+ * is one plane, and one mapping reproduces it without the shear per-vertex
1890
+ * sampling introduces between neighbouring generated triangles.
1891
+ */
1892
+ var UV_FIT_MAX_RESIDUAL = 0.005;
1893
+ var _toReference = new Matrix4();
1894
+ var _normalMatrix = new Matrix3();
1895
+ var _vertex = new Vector3();
1896
+ var _normal = new Vector3();
1897
+
1898
+ /** What the collar needs to look like a continuation of the deck it fills. */
1899
+
1900
+ /** Every mesh under `root` whose name contains one of `patterns`, in traversal order. */
1901
+ function meshesMatching(root, patterns) {
1902
+ var found = [];
1903
+ root.traverse(function (obj) {
1904
+ var mesh = obj;
1905
+ if (mesh.isMesh && patterns.some(function (p) {
1906
+ return mesh.name.includes(p);
1907
+ })) found.push(mesh);
1908
+ });
1909
+ return found;
1910
+ }
1911
+
1912
+ /**
1913
+ * Deck material for generated geometry. The unique bakes (AO / light map) are
1914
+ * authored in the deck's own 0–1 UV space and would smear arbitrarily across a
1915
+ * mesh that isn't part of that unwrap, so they are dropped; the repeating
1916
+ * pattern maps are kept as they are.
1917
+ */
1918
+ function cloneDeckMaterial(source) {
1919
+ var clone = source.clone();
1920
+ if (clone instanceof MeshStandardMaterial) {
1921
+ clone.aoMap = null;
1922
+ clone.lightMap = null;
1923
+ }
1924
+ clone.needsUpdate = true;
1925
+ return clone;
1926
+ }
1927
+
1928
+ /**
1929
+ * The UV attribute the deck's VISIBLE pattern reads. Read from the material
1930
+ * rather than assumed, because copying the wrong channel of a multi-unwrap
1931
+ * asset yields a pattern that is subtly the wrong size.
1932
+ */
1933
+ function patternAttributeName(material) {
1934
+ var single = Array.isArray(material) ? material[0] : material;
1935
+ if (single instanceof MeshStandardMaterial && single.map) return single.map.channel === 0 ? 'uv' : "uv".concat(single.map.channel);
1936
+ return 'uv';
1937
+ }
1938
+
1939
+ /**
1940
+ * Collect the top-surface triangles of every matched deck mesh as a flat
1941
+ * (x, z, u, v)-per-vertex soup in `reference`'s local space, reading the UV
1942
+ * attribute the deck's pattern actually samples.
1943
+ *
1944
+ * No proximity filter: `nodeMatch` names the deck to continue, so everything it
1945
+ * names is the sample set. Filtering by distance to the cutout drops slabs whose
1946
+ * TRIANGLE CENTROIDS fall outside the radius — which silently discards a deck
1947
+ * modelled as a few large quads and leaves the collar with no material at all.
1948
+ */
1949
+ function collectDeckTriangles(meshes, reference, attributeName) {
1950
+ var referenceInverse = _toReference.copy(reference.matrixWorld).invert().clone();
1951
+ var out = [];
1952
+ var extent = {
1953
+ minX: Infinity,
1954
+ maxX: -Infinity,
1955
+ minZ: Infinity,
1956
+ maxZ: -Infinity
1957
+ };
1958
+ var _iterator = _createForOfIteratorHelper$1(meshes),
1959
+ _step;
1960
+ try {
1961
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
1962
+ var _geometry$getAttribut;
1963
+ var mesh = _step.value;
1964
+ var geometry = mesh.geometry;
1965
+ var position = geometry.getAttribute('position');
1966
+ var uv = (_geometry$getAttribut = geometry.getAttribute(attributeName)) !== null && _geometry$getAttribut !== void 0 ? _geometry$getAttribut : geometry.getAttribute('uv');
1967
+ if (!position || !uv) continue;
1968
+ var normal = geometry.getAttribute('normal');
1969
+
1970
+ // Mesh-local → reference-local (identity for parts sharing the frame, correct otherwise).
1971
+ _toReference.multiplyMatrices(referenceInverse, mesh.matrixWorld);
1972
+ var local = new Float32Array(position.count * 3);
1973
+ for (var i = 0; i < position.count; i++) {
1974
+ _vertex.set(position.getX(i), position.getY(i), position.getZ(i)).applyMatrix4(_toReference);
1975
+ local[i * 3] = _vertex.x;
1976
+ local[i * 3 + 1] = _vertex.y;
1977
+ local[i * 3 + 2] = _vertex.z;
1978
+ if (_vertex.x < extent.minX) extent.minX = _vertex.x;
1979
+ if (_vertex.x > extent.maxX) extent.maxX = _vertex.x;
1980
+ if (_vertex.z < extent.minZ) extent.minZ = _vertex.z;
1981
+ if (_vertex.z > extent.maxZ) extent.maxZ = _vertex.z;
1982
+ }
1983
+ // Normals need the rotation part of the SAME transform the positions took, or a deck part
1984
+ // rotated relative to `reference` is classified against its own axes and its top faces drop out.
1985
+ var localNormalY = new Float32Array(normal ? normal.count : 0);
1986
+ if (normal) {
1987
+ _normalMatrix.getNormalMatrix(_toReference);
1988
+ for (var _i = 0; _i < normal.count; _i++) {
1989
+ _normal.set(normal.getX(_i), normal.getY(_i), normal.getZ(_i)).applyMatrix3(_normalMatrix).normalize();
1990
+ localNormalY[_i] = _normal.y;
1991
+ }
1992
+ }
1993
+
1994
+ // Height fallback when the mesh ships no normals: the top face is the upper half.
1995
+ var yMid = -Infinity;
1996
+ if (!normal) {
1997
+ var yMin = Infinity;
1998
+ var yMax = -Infinity;
1999
+ for (var _i2 = 0; _i2 < position.count; _i2++) {
2000
+ var y = local[_i2 * 3 + 1];
2001
+ if (y < yMin) yMin = y;
2002
+ if (y > yMax) yMax = y;
2003
+ }
2004
+ yMid = (yMin + yMax) / 2;
2005
+ }
2006
+ var index = geometry.index;
2007
+ var triCount = index ? Math.floor(index.count / 3) : Math.floor(position.count / 3);
2008
+ for (var t = 0; t < triCount; t++) {
2009
+ var a = index ? index.getX(t * 3) : t * 3;
2010
+ var b = index ? index.getX(t * 3 + 1) : t * 3 + 1;
2011
+ var c = index ? index.getX(t * 3 + 2) : t * 3 + 2;
2012
+ var isTop = normal ? localNormalY[a] >= UP_NORMAL_MIN && localNormalY[b] >= UP_NORMAL_MIN && localNormalY[c] >= UP_NORMAL_MIN : local[a * 3 + 1] > yMid && local[b * 3 + 1] > yMid && local[c * 3 + 1] > yMid;
2013
+ if (!isTop) continue;
2014
+ for (var _i3 = 0, _arr = [a, b, c]; _i3 < _arr.length; _i3++) {
2015
+ var vi = _arr[_i3];
2016
+ out.push(local[vi * 3], local[vi * 3 + 2], uv.getX(vi), uv.getY(vi));
2017
+ }
2018
+ }
2019
+ }
2020
+ } catch (err) {
2021
+ _iterator.e(err);
2022
+ } finally {
2023
+ _iterator.f();
2024
+ }
2025
+ var triangleCount = out.length / UV_TRIANGLE_STRIDE;
2026
+ if (triangleCount < 1) return null;
2027
+ return {
2028
+ triangles: new Float32Array(out),
2029
+ triangleCount: triangleCount,
2030
+ extent: extent
2031
+ };
2032
+ }
2033
+
2034
+ /**
2035
+ * Sample the deck the collar has to continue: the first name-matched mesh is the
2036
+ * reference frame, all matched meshes feed the UV sample.
2037
+ */
2038
+ function sampleDeckSurface(scene, patterns) {
2039
+ var _meshes$, _bounds$max$y, _collected$triangles, _collected$triangleCo, _collected$extent;
2040
+ var meshes = meshesMatching(scene, patterns);
2041
+ var reference = (_meshes$ = meshes[0]) !== null && _meshes$ !== void 0 ? _meshes$ : null;
2042
+ if (!reference) return {
2043
+ reference: null,
2044
+ surface: null
2045
+ };
2046
+ var geometry = reference.geometry;
2047
+ if (!geometry.boundingBox) geometry.computeBoundingBox();
2048
+ var attributeName = patternAttributeName(reference.material);
2049
+ var collected = collectDeckTriangles(meshes, reference, attributeName);
2050
+ var bounds = geometry.boundingBox;
2051
+ return {
2052
+ reference: reference,
2053
+ surface: {
2054
+ meshName: reference.name,
2055
+ topY: (_bounds$max$y = bounds === null || bounds === void 0 ? void 0 : bounds.max.y) !== null && _bounds$max$y !== void 0 ? _bounds$max$y : 0,
2056
+ slabThickness: bounds ? bounds.max.y - bounds.min.y : 0,
2057
+ material: collected ? cloneDeckMaterial(Array.isArray(reference.material) ? reference.material[0] : reference.material) : null,
2058
+ triangles: (_collected$triangles = collected === null || collected === void 0 ? void 0 : collected.triangles) !== null && _collected$triangles !== void 0 ? _collected$triangles : null,
2059
+ triangleCount: (_collected$triangleCo = collected === null || collected === void 0 ? void 0 : collected.triangleCount) !== null && _collected$triangleCo !== void 0 ? _collected$triangleCo : 0,
2060
+ triangleIndex: collected ? buildTriangleGridIndex(collected.triangles, collected.triangleCount) : null,
2061
+ attributeName: attributeName,
2062
+ uvFit: collected ? fitAffineUV(collected.triangles, collected.triangleCount) : null,
2063
+ extent: (_collected$extent = collected === null || collected === void 0 ? void 0 : collected.extent) !== null && _collected$extent !== void 0 ? _collected$extent : null
2064
+ }
2065
+ };
2066
+ }
2067
+
2068
+ /** Identity of a sampled surface — a fresh surface object rebuilds the collar geometry, so only an actual change may be applied. */
2069
+ function deckSurfaceKey(surface) {
2070
+ return surface ? "".concat(surface.meshName, "|").concat(surface.topY.toFixed(4), "|").concat(surface.attributeName, "|").concat(surface.triangleCount) : 'none';
2071
+ }
2072
+
2073
+ /** One-shot diagnostic lines for a newly acquired deck surface. */
2074
+ function describeDeckSurface(surface, hasOwnMaterial) {
2075
+ var lines = [];
2076
+ var e = surface.extent;
2077
+ if (e) {
2078
+ lines.push("[DeckCutoutCollar] matched deck meshes span X [".concat(e.minX.toFixed(3), ", ").concat(e.maxX.toFixed(3), "] Z [").concat(e.minZ.toFixed(3), ", ").concat(e.maxZ.toFixed(3), "]"));
2079
+ }
2080
+ lines.push("[DeckCutoutCollar] UV source: ".concat(hasOwnMaterial ? 'own material (declared world-planar tiling)' : surface.uvFit === null ? 'no fit possible (per-vertex sampling)' : surface.uvFit.residualMetres <= UV_FIT_MAX_RESIDUAL ? "one fitted mapping, residual ".concat((surface.uvFit.residualMetres * 1000).toFixed(2), " mm") : "per-vertex sampling \u2014 fit residual ".concat((surface.uvFit.residualMetres * 1000).toFixed(1), " mm exceeds ").concat(UV_FIT_MAX_RESIDUAL * 1000, " mm, deck unwrap is not one plane")));
2081
+ return lines;
2082
+ }
2083
+
2084
+ /** How far (m) the outline is held inside the ring's outer boundary. */
2085
+ var CLAMP_INSET = 1e-3;
2086
+ /**
2087
+ * The collar ring, built in the floor meshes' shared local space (outline and
2088
+ * hole rect are floor-local): a skirt is extruded downward along the inner edge
2089
+ * so nothing shows through under the deck, the top sits `collar.recess` below
2090
+ * the deck surface and the outer edge tucks `collar.overlap` under the deck —
2091
+ * the last two kill z-fighting with the slab.
2092
+ */
2093
+ function buildCollarGeometry(_ref) {
2094
+ var footprint = _ref.footprint,
2095
+ hole = _ref.hole,
2096
+ collar = _ref.collar,
2097
+ deck = _ref.deck,
2098
+ ownMaterial = _ref.ownMaterial;
2099
+ // Shape plane (x, y) becomes floor-local (x, z) after rotateX(π/2); the
2100
+ // extrusion depth runs toward -Y (downward skirt). Winding of outer ring
2101
+ // and hole is normalized by ExtrudeGeometry itself.
2102
+ var shape = new Shape();
2103
+ var minX = hole.centerX - hole.halfExtentX - collar.overlap;
2104
+ var maxX = hole.centerX + hole.halfExtentX + collar.overlap;
2105
+ var minZ = hole.centerZ - hole.halfExtentZ - collar.overlap;
2106
+ var maxZ = hole.centerZ + hole.halfExtentZ + collar.overlap;
2107
+ shape.moveTo(minX, minZ);
2108
+ shape.lineTo(maxX, minZ);
2109
+ shape.lineTo(maxX, maxZ);
2110
+ shape.lineTo(minX, maxZ);
2111
+ shape.closePath();
2112
+
2113
+ // The hole path MUST stay strictly inside the ring's outer boundary: a
2114
+ // crossing path makes the triangulator emit garbage (a wedge of floor over
2115
+ // the pool) rather than fail. Clamping degrades to a collar pinched flat
2116
+ // against its outer edge, which is recoverable and obvious.
2117
+ var clamped = 0;
2118
+ var innerMinX = Infinity;
2119
+ var innerMaxX = -Infinity;
2120
+ var innerMinZ = Infinity;
2121
+ var innerMaxZ = -Infinity;
2122
+ var inner = new Path();
2123
+ for (var i = 0; i < footprint.length; i++) {
2124
+ var x = Math.min(maxX - CLAMP_INSET, Math.max(minX + CLAMP_INSET, footprint[i][0]));
2125
+ var z = Math.min(maxZ - CLAMP_INSET, Math.max(minZ + CLAMP_INSET, footprint[i][1]));
2126
+ if (x !== footprint[i][0] || z !== footprint[i][1]) clamped += 1;
2127
+ if (x < innerMinX) innerMinX = x;
2128
+ if (x > innerMaxX) innerMaxX = x;
2129
+ if (z < innerMinZ) innerMinZ = z;
2130
+ if (z > innerMaxZ) innerMaxZ = z;
2131
+ if (i === 0) inner.moveTo(x, z);else inner.lineTo(x, z);
2132
+ }
2133
+ inner.closePath();
2134
+ shape.holes.push(inner);
2135
+ // What the ring actually came out as. `coverage` is the share of the hole
2136
+ // the OPENING keeps: near 1 the collar is a hairline, near 0 it is a solid
2137
+ // slab over the article (no visible cutout at all).
2138
+ var coverage = (innerMaxX - innerMinX) * (innerMaxZ - innerMinZ) / ((maxX - minX) * (maxZ - minZ));
2139
+ var diagnostic = "[DeckCutoutCollar] ring built: hole X [".concat(minX.toFixed(2), ", ").concat(maxX.toFixed(2), "] Z [").concat(minZ.toFixed(2), ", ").concat(maxZ.toFixed(2), "] | opening X [").concat(innerMinX.toFixed(2), ", ").concat(innerMaxX.toFixed(2), "] Z [").concat(innerMinZ.toFixed(2), ", ").concat(innerMaxZ.toFixed(2), "] = ").concat((coverage * 100).toFixed(0), "% of it | ").concat(clamped, "/").concat(footprint.length, " outline pts clamped").concat(clamped > 0 ? ' — THE ARTICLE IS LARGER THAN ITS HOLE' : '');
2140
+
2141
+ // Skirt as thin as the deck itself unless configured otherwise; a floor
2142
+ // with no measurable thickness still needs a non-degenerate extrusion.
2143
+ var skirtDepth = collar.skirtDepth > 0 ? collar.skirtDepth : Math.max(deck.slabThickness, 0.01);
2144
+ var geo = new ExtrudeGeometry(shape, {
2145
+ depth: skirtDepth,
2146
+ bevelEnabled: false
2147
+ });
2148
+ geo.rotateX(Math.PI / 2);
2149
+ geo.translate(0, deck.topY - collar.recess, 0);
2150
+ if (ownMaterial) {
2151
+ // Own material ⇒ the tiling is DECLARED, not inherited: a world-planar
2152
+ // projection at `textureScale` metres per tile. Nothing to fit or sample,
2153
+ // and swapping the maps for a different wood or stone needs no other change.
2154
+ var textureScale = ownMaterial.textureScale,
2155
+ rotationDeg = ownMaterial.rotationDeg,
2156
+ offsetX = ownMaterial.offsetX,
2157
+ offsetZ = ownMaterial.offsetZ;
2158
+ var scale = textureScale > 0 ? textureScale : 1;
2159
+ var angle = rotationDeg * Math.PI / 180;
2160
+ var cos = Math.cos(angle);
2161
+ var sin = Math.sin(angle);
2162
+ var position = geo.getAttribute('position');
2163
+ var uvs = new Float32Array(position.count * 2);
2164
+ for (var _i = 0; _i < position.count; _i++) {
2165
+ var _x = position.getX(_i) + offsetX;
2166
+ var _z = position.getZ(_i) + offsetZ;
2167
+ uvs[_i * 2] = (_x * cos - _z * sin) / scale;
2168
+ uvs[_i * 2 + 1] = (_x * sin + _z * cos) / scale;
2169
+ }
2170
+ geo.setAttribute('uv', new BufferAttribute(uvs, 2));
2171
+ geo.setAttribute('uv1', new BufferAttribute(uvs, 2));
2172
+ } else if (deck.triangles) {
2173
+ // Continue the deck's own mapping. One fitted mapping when the deck's
2174
+ // unwrap is a single plane — it cannot shear, whereas deciding per vertex
2175
+ // lets the two ends of a generated triangle land on different deck
2176
+ // triangles and blend their mappings across it. Per-vertex sampling stays
2177
+ // for the unwraps a single mapping cannot describe (per-board islands,
2178
+ // varying density), where matching locally is the only faithful option.
2179
+ //
2180
+ // Written to BOTH channels so it lands wherever the material's maps look;
2181
+ // the skirt's vertical faces inherit the same planar projection, which
2182
+ // reads as shadow in a recessed band.
2183
+ var fit = deck.uvFit && deck.uvFit.residualMetres <= UV_FIT_MAX_RESIDUAL ? deck.uvFit : null;
2184
+ var _position = geo.getAttribute('position');
2185
+ var _uvs = new Float32Array(_position.count * 2);
2186
+ for (var _i2 = 0; _i2 < _position.count; _i2++) {
2187
+ var _x2 = _position.getX(_i2);
2188
+ var _z2 = _position.getZ(_i2);
2189
+ if (fit) {
2190
+ _uvs[_i2 * 2] = fit.ux * _x2 + fit.uz * _z2 + fit.u0;
2191
+ _uvs[_i2 * 2 + 1] = fit.vx * _x2 + fit.vz * _z2 + fit.v0;
2192
+ continue;
2193
+ }
2194
+ var sampled = sampleNearestTriangleUV(deck.triangles, deck.triangleCount, _x2, _z2, deck.triangleIndex);
2195
+ if (!sampled) continue;
2196
+ _uvs[_i2 * 2] = sampled[0];
2197
+ _uvs[_i2 * 2 + 1] = sampled[1];
2198
+ }
2199
+ geo.setAttribute('uv', new BufferAttribute(_uvs, 2));
2200
+ geo.setAttribute('uv1', new BufferAttribute(_uvs, 2));
2201
+ }
2202
+ return {
2203
+ geometry: geo,
2204
+ diagnostic: diagnostic
2205
+ };
2206
+ }
2207
+
2208
+ var LOG$1 = getLogger('RealTimeViewer', 'DeckCutoutCollar');
2209
+
2210
+ /** Shared loader — the collar's own maps are plain URLs, like `MaterialManager`'s. */
2211
+ var textureLoader = new TextureLoader();
2212
+ /**
2213
+ * Load the collar's declared maps imperatively rather than through
2214
+ * `useTexture`/`useLoader`: those suspend, and the collar mounts outside a
2215
+ * Suspense boundary, so a slow texture would blank the whole scene group.
2216
+ * Returns null until `mapUrl` resolves; the other maps are optional and simply
2217
+ * aren't applied if they fail.
2218
+ */
2219
+ function useCollarTextures(material) {
2220
+ var mapUrl = material.mapUrl,
2221
+ normalMapUrl = material.normalMapUrl,
2222
+ roughnessMapUrl = material.roughnessMapUrl;
2223
+ var _useState = useState(null),
2224
+ _useState2 = _slicedToArray(_useState, 2),
2225
+ loaded = _useState2[0],
2226
+ setLoaded = _useState2[1];
2227
+ useEffect(function () {
2228
+ if (mapUrl === '') {
2229
+ setLoaded(null);
2230
+ return;
2231
+ }
2232
+ var live = true;
2233
+ var opened = [];
2234
+ var load = function load(url) {
2235
+ return url === '' ? Promise.resolve(null) : textureLoader.loadAsync(url).then(function (t) {
2236
+ // A texture resolving after cleanup would never be reached by the
2237
+ // cleanup's dispose loop — dispose it here instead of leaking it.
2238
+ if (!live) {
2239
+ t.dispose();
2240
+ return null;
2241
+ }
2242
+ opened.push(t);
2243
+ return t;
2244
+ }, function () {
2245
+ LOG$1.debug("[DeckCutoutCollar] collar texture failed to load: ".concat(url));
2246
+ return null;
2247
+ });
2248
+ };
2249
+ Promise.all([load(mapUrl), load(normalMapUrl), load(roughnessMapUrl)]).then(function (_ref) {
2250
+ var _ref2 = _slicedToArray(_ref, 3),
2251
+ map = _ref2[0],
2252
+ normalMap = _ref2[1],
2253
+ roughnessMap = _ref2[2];
2254
+ if (!live || !map) return;
2255
+ // Repeat wrapping is what makes the world-planar UVs tile at all; the
2256
+ // colour map is the only one that carries colour (the others are data).
2257
+ map.colorSpace = SRGBColorSpace;
2258
+ for (var _i = 0, _arr = [map, normalMap, roughnessMap]; _i < _arr.length; _i++) {
2259
+ var t = _arr[_i];
2260
+ if (!t) continue;
2261
+ t.wrapS = RepeatWrapping;
2262
+ t.wrapT = RepeatWrapping;
2263
+ t.needsUpdate = true;
2264
+ }
2265
+ setLoaded({
2266
+ map: map,
2267
+ normalMap: normalMap,
2268
+ roughnessMap: roughnessMap
2269
+ });
2270
+ });
2271
+ return function () {
2272
+ live = false;
2273
+ for (var _i2 = 0, _opened = opened; _i2 < _opened.length; _i2++) {
2274
+ var t = _opened[_i2];
2275
+ t.dispose();
2276
+ }
2277
+ setLoaded(null);
2278
+ };
2279
+ }, [mapUrl, normalMapUrl, roughnessMapUrl]);
2280
+ return loaded;
2281
+ }
2282
+
2283
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
2284
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
2285
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
2286
+ var LOG = getLogger('RealTimeViewer', 'DeckCutoutCollar');
2287
+
2288
+ /**
2289
+ * Page-lifetime latch for the collar hold — not the registry's `once`: StrictMode's simulated
2290
+ * unmount runs the cleanup `end`, which would latch a once-id and kill the gate before the real
2291
+ * boot. Flips only on a real completion (first collar geometry applied, or timeout).
2292
+ */
2293
+ var collarGateSettled = false;
2294
+
2295
+ /**
2296
+ * Frames to wait after a decor bump before sampling. Every deck GLB writes its
2297
+ * scene transform from its OWN `useFrame`, and this component's frame callback
2298
+ * can run before theirs — sampling in the same frame would fold a just-mounted,
2299
+ * still-untransformed part and the already-placed ones into one reference frame.
2300
+ * One frame of slack means every mounted deck GLB has written its transform at
2301
+ * least once before the sample reads their world matrices.
2302
+ */
2303
+ var ACQUIRE_DELAY_FRAMES = 1;
2304
+
2305
+ /**
2306
+ * Generated coping collar for footprint-rule cutouts (`deckCutout.articleRules`):
2307
+ * a flat ring filling the space between the deck's authored rectangular hole and
2308
+ * the article's shaped outline. This is what makes the cutout follow the article
2309
+ * — the deck GLB itself is never touched. Rendered only while
2310
+ * `DeckCutoutArticleSync` publishes a footprint outline.
2311
+ *
2312
+ * It wears the DECK's material and continues the deck's own UV mapping (see
2313
+ * {@link buildCollarGeometry}), unless the config declares own maps. The ring
2314
+ * follows a name-matched floor mesh's world matrix every frame, so
2315
+ * scene-transform edits need no rebuild.
2316
+ */
2317
+ function DeckCutoutCollar() {
2318
+ var _deck$material;
2319
+ var scene = useThree(function (s) {
2320
+ return s.scene;
2321
+ });
2322
+ var deckCutoutJson = useRTVStore(function (s) {
2323
+ return JSON.stringify(s.resolvedEnvironment.scene.deckCutout);
2324
+ });
2325
+ var deform = useMemo(function () {
2326
+ return JSON.parse(deckCutoutJson);
2327
+ }, [deckCutoutJson]);
2328
+ var footprint = useRTVStore(function (s) {
2329
+ return s.deckCutoutFootprintOverride;
2330
+ });
2331
+ // Bumps once per mounted GLB — the deck arrives as several part GLBs, so this
2332
+ // is the signal that there may be more meshes to sample than last time.
2333
+ var decorVersion = useRTVStore(function (s) {
2334
+ return s.decorVersion;
2335
+ });
2336
+ var ownTextures = useCollarTextures(deform.collar.material);
2337
+ var meshRef = useRef(null);
2338
+ var floorRef = useRef(null);
2339
+ var surfaceKeyRef = useRef(null);
2340
+ /** Frames left before the armed sample runs; negative means nothing is armed. */
2341
+ var acquireDelayRef = useRef(-1);
2342
+ var _useState = useState(null),
2343
+ _useState2 = _slicedToArray(_useState, 2),
2344
+ deck = _useState2[0],
2345
+ setDeck = _useState2[1];
2346
+ var patterns = useMemo(function () {
2347
+ return deform.nodeMatch.split(',').map(function (p) {
2348
+ return p.trim();
2349
+ }).filter(function (p) {
2350
+ return p.length > 0;
2351
+ });
2352
+ }, [deform.nodeMatch]);
2353
+
2354
+ // Re-acquire the deck when the match config changes or the scene swaps.
2355
+ useEffect(function () {
2356
+ floorRef.current = null;
2357
+ surfaceKeyRef.current = null;
2358
+ setDeck(null);
2359
+ }, [patterns]);
2360
+ var collar = deform.collar;
2361
+ // The area the collar owns, straight from the config. `nodeMatch` names the
2362
+ // deck to CONTINUE, which is a different thing and may sit entirely outside
2363
+ // this rect (see the preset).
2364
+ var holeRect = deform.authoredHole;
2365
+ var enabled = deform.enabled;
2366
+ var active = enabled && footprint !== null && footprint.length >= 3;
2367
+
2368
+ // A configured cutout means a collar WILL appear — hold the reveal until its first GEOMETRY
2369
+ // lands, otherwise it pops in about a second after the scene shows. The footprint needs the
2370
+ // mounted article, so the initial window is generous and tightens once the footprint is in.
2371
+ // Once-latched: later scene swaps rebuild behind the visible scene.
2372
+ useEffect(function () {
2373
+ if (!enabled || collarGateSettled) return;
2374
+ useRTVStore.getState().beginSceneLoad(DECK_COLLAR_LOAD_ID, {
2375
+ timeoutMs: 25000,
2376
+ onTimeout: function onTimeout() {
2377
+ return collarGateSettled = true;
2378
+ }
2379
+ });
2380
+ return function () {
2381
+ return useRTVStore.getState().endSceneLoad(DECK_COLLAR_LOAD_ID);
2382
+ };
2383
+ }, [enabled]);
2384
+ useEffect(function () {
2385
+ if (active && !collarGateSettled) {
2386
+ useRTVStore.getState().beginSceneLoad(DECK_COLLAR_LOAD_ID, {
2387
+ timeoutMs: 8000,
2388
+ onTimeout: function onTimeout() {
2389
+ return collarGateSettled = true;
2390
+ }
2391
+ });
2392
+ }
2393
+ }, [active]);
2394
+ var acquireDeck = useCallback(function () {
2395
+ var _sampleDeckSurface = sampleDeckSurface(scene, patterns),
2396
+ reference = _sampleDeckSurface.reference,
2397
+ surface = _sampleDeckSurface.surface;
2398
+ floorRef.current = reference;
2399
+
2400
+ // A fresh surface object rebuilds the collar geometry, so only apply on an actual change.
2401
+ var key = deckSurfaceKey(surface);
2402
+ if (surfaceKeyRef.current === key) return;
2403
+ surfaceKeyRef.current = key;
2404
+ setDeck(surface);
2405
+ if (!surface) return;
2406
+ bootPhase('deck: surface sampled');
2407
+ var _iterator = _createForOfIteratorHelper(describeDeckSurface(surface, ownTextures !== null)),
2408
+ _step;
2409
+ try {
2410
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
2411
+ var line = _step.value;
2412
+ LOG.debug(line);
2413
+ }
2414
+ } catch (err) {
2415
+ _iterator.e(err);
2416
+ } finally {
2417
+ _iterator.f();
2418
+ }
2419
+ }, [scene, patterns, ownTextures]);
2420
+
2421
+ // Arm the sample on every event that can change what is there to sample: the match config and
2422
+ // every mounted deck GLB (the part GLBs land on different frames, and a sample taken from only
2423
+ // the parts present so far would mis-map the rest of the ring). NOT the article: the sample
2424
+ // reads the name-matched deck meshes only, so waiting for the footprint would serialize it
2425
+ // behind the whole article load for nothing.
2426
+ useEffect(function () {
2427
+ if (!enabled) return;
2428
+ acquireDelayRef.current = ACQUIRE_DELAY_FRAMES;
2429
+ }, [enabled, decorVersion, acquireDeck]);
2430
+
2431
+ // Nothing named by `nodeMatch` is in the scene, so no collar can be built for the outline the
2432
+ // article just published — the case where the hold above runs out instead of settling.
2433
+ useEffect(function () {
2434
+ if (!active || deck !== null) return;
2435
+ LOG.debug("[DeckCutoutCollar] footprint active but NO floor mesh matches '".concat(deform.nodeMatch, "'"));
2436
+ }, [active, deck, deform.nodeMatch]);
2437
+ useFrame(function () {
2438
+ if (!enabled) return;
2439
+ if (acquireDelayRef.current >= 0) {
2440
+ if (acquireDelayRef.current === 0) acquireDeck();
2441
+ acquireDelayRef.current -= 1;
2442
+ }
2443
+ var floor = floorRef.current;
2444
+ // The deck GLB was unmounted (URL cleared / swapped) — look again once; the replacement, if
2445
+ // any, re-arms the effect above when it mounts.
2446
+ if (floor && !floor.parent) acquireDeck();
2447
+ var collarMesh = meshRef.current;
2448
+ if (!floor || !collarMesh) return;
2449
+ collarMesh.matrix.copy(floor.matrixWorld);
2450
+ collarMesh.matrixWorldNeedsUpdate = true;
2451
+ });
2452
+ var geometry = useMemo(function () {
2453
+ if (!enabled || deck === null || footprint === null || footprint.length < 3) return null;
2454
+ var built = buildCollarGeometry({
2455
+ footprint: footprint,
2456
+ hole: holeRect,
2457
+ collar: collar,
2458
+ deck: deck,
2459
+ ownMaterial: ownTextures ? collar.material : null
2460
+ });
2461
+ LOG.debug(built.diagnostic);
2462
+ return built.geometry;
2463
+ }, [enabled, footprint, holeRect.centerX, holeRect.centerZ, holeRect.halfExtentX, holeRect.halfExtentZ, collar, deck, ownTextures]);
2464
+
2465
+ // Settle the hold on the first BUILT collar, not on the deck sample: the sample lands as soon as
2466
+ // the deck GLBs mount, long before the article publishes the outline the geometry needs. Ending
2467
+ // the hold there would reveal the scene and let the collar appear afterwards — the exact pop the
2468
+ // hold exists to prevent. This effect runs after the commit that put the collar mesh in the
2469
+ // scene, so the reveal can only follow it.
2470
+ useEffect(function () {
2471
+ if (!geometry || collarGateSettled) return;
2472
+ collarGateSettled = true;
2473
+ bootPhase('deck: first collar geometry');
2474
+ useRTVStore.getState().endSceneLoad(DECK_COLLAR_LOAD_ID);
2475
+ }, [geometry]);
2476
+ useEffect(function () {
2477
+ return function () {
2478
+ return geometry === null || geometry === void 0 ? void 0 : geometry.dispose();
2479
+ };
2480
+ }, [geometry]);
2481
+
2482
+ // The clone is ours to dispose; its textures are shared with the deck
2483
+ // material and must survive (`Material.dispose` leaves them alone).
2484
+ var deckMaterial = (_deck$material = deck === null || deck === void 0 ? void 0 : deck.material) !== null && _deck$material !== void 0 ? _deck$material : null;
2485
+ useEffect(function () {
2486
+ return function () {
2487
+ return deckMaterial === null || deckMaterial === void 0 ? void 0 : deckMaterial.dispose();
2488
+ };
2489
+ }, [deckMaterial]);
2490
+ if (!geometry) return null;
2491
+ // The collar stands in for deck, so it casts like deck does (the deck edge
2492
+ // over the cliff), whether it fills a hole or spans a whole area.
2493
+ if (ownTextures) return /*#__PURE__*/jsx("mesh", {
2494
+ ref: meshRef,
2495
+ geometry: geometry,
2496
+ matrixAutoUpdate: false,
2497
+ receiveShadow: true,
2498
+ castShadow: true,
2499
+ children: /*#__PURE__*/jsx("meshStandardMaterial", {
2500
+ map: ownTextures.map,
2501
+ normalMap: ownTextures.normalMap,
2502
+ roughnessMap: ownTextures.roughnessMap,
2503
+ color: collar.color,
2504
+ roughness: collar.roughness,
2505
+ metalness: 0
2506
+ })
2507
+ });
2508
+ if (deckMaterial) return /*#__PURE__*/jsx("mesh", {
2509
+ ref: meshRef,
2510
+ geometry: geometry,
2511
+ material: deckMaterial,
2512
+ matrixAutoUpdate: false,
2513
+ receiveShadow: true,
2514
+ castShadow: true
2515
+ });
2516
+ return /*#__PURE__*/jsx("mesh", {
2517
+ ref: meshRef,
2518
+ geometry: geometry,
2519
+ matrixAutoUpdate: false,
2520
+ receiveShadow: true,
2521
+ castShadow: true,
2522
+ children: /*#__PURE__*/jsx("meshStandardMaterial", {
2523
+ color: collar.color,
2524
+ roughness: collar.roughness,
2525
+ metalness: 0
2526
+ })
2527
+ });
2528
+ }
2529
+
2530
+ function DeckCutoutSubsystem() {
2531
+ return /*#__PURE__*/jsxs(Fragment, {
2532
+ children: [/*#__PURE__*/jsx(DeckCutoutArticleSync, {}), /*#__PURE__*/jsx(DeckCutoutCollar, {})]
2533
+ });
2534
+ }
2535
+
2536
+ export { DeckCutoutSubsystem };