@zendir/ui 0.2.21 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/CHANGELOG.md +183 -1
  2. package/README.md +70 -28
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +73 -64
  5. package/dist/index.js.map +1 -1
  6. package/dist/react/3d/CesiumCaptureSource.d.ts +1 -1
  7. package/dist/react/3d/CesiumCaptureSource.js +1 -1
  8. package/dist/react/3d/CesiumCaptureSource.js.map +1 -1
  9. package/dist/react/3d/ZenSpace3D.js +1254 -0
  10. package/dist/react/3d/ZenSpace3D.js.map +1 -0
  11. package/dist/react/3d/ZenSpace3DCesium.js +579 -0
  12. package/dist/react/3d/ZenSpace3DCesium.js.map +1 -0
  13. package/dist/react/3d/ZenSpace3DShaders.js +478 -0
  14. package/dist/react/3d/ZenSpace3DShaders.js.map +1 -0
  15. package/dist/react/3d/ZenSpace3DTypes.d.ts +28 -1
  16. package/dist/react/3d/ZenSpace3DUtils.d.ts +17 -173
  17. package/dist/react/3d/ZenSpace3DUtils.js +20 -1
  18. package/dist/react/3d/ZenSpace3DUtils.js.map +1 -1
  19. package/dist/react/3d/capturePngAnalysis.js +42 -0
  20. package/dist/react/3d/capturePngAnalysis.js.map +1 -0
  21. package/dist/react/3d/index.d.ts +6 -12
  22. package/dist/react/3d/index.js +57 -0
  23. package/dist/react/3d/index.js.map +1 -0
  24. package/dist/react/3d/threeLoader.js +22 -0
  25. package/dist/react/3d/threeLoader.js.map +1 -0
  26. package/dist/react/astro/ClassificationBanner.js +1 -1
  27. package/dist/react/astro/GlobalStatusBar.js +1 -1
  28. package/dist/react/astro/MissionClock.js +8 -5
  29. package/dist/react/astro/MissionClock.js.map +1 -1
  30. package/dist/react/astro/MonitoringIcon.js +2 -2
  31. package/dist/react/astro/MonitoringIcon.js.map +1 -1
  32. package/dist/react/astro/Notification.js +1 -1
  33. package/dist/react/astro/Progress.js +1 -1
  34. package/dist/react/astro/SimulationControls.js +3 -3
  35. package/dist/react/astro/SimulationControls.js.map +1 -1
  36. package/dist/react/astro/StatusIndicator.js +1 -1
  37. package/dist/react/astro/UnifiedTimeline.js +5 -5
  38. package/dist/react/astro/UnifiedTimeline.js.map +1 -1
  39. package/dist/react/astro/index.js +34 -0
  40. package/dist/react/astro/index.js.map +1 -0
  41. package/dist/react/cards/AccessCard.js +410 -0
  42. package/dist/react/cards/AccessCard.js.map +1 -0
  43. package/dist/react/cards/OrbitCard.js +372 -0
  44. package/dist/react/cards/OrbitCard.js.map +1 -0
  45. package/dist/react/cards/SpacecraftCard.js +941 -0
  46. package/dist/react/cards/SpacecraftCard.js.map +1 -0
  47. package/dist/react/cards/TelemetryCard.js +742 -0
  48. package/dist/react/cards/TelemetryCard.js.map +1 -0
  49. package/dist/react/cards/TelemetryStreamCard.js +309 -0
  50. package/dist/react/cards/TelemetryStreamCard.js.map +1 -0
  51. package/dist/react/cards/index.js +13 -0
  52. package/dist/react/cards/index.js.map +1 -0
  53. package/dist/react/charts/GroundTrackMap.d.ts +2 -15
  54. package/dist/react/charts/GroundTrackMap.js +1 -1
  55. package/dist/react/charts/GroundTrackMap.js.map +1 -1
  56. package/dist/react/charts/GroundTrackMapLeaflet.js +1 -1
  57. package/dist/react/charts/index.js +104 -0
  58. package/dist/react/charts/index.js.map +1 -0
  59. package/dist/react/charts/unified/AstroChart.js +35 -14
  60. package/dist/react/charts/unified/AstroChart.js.map +1 -1
  61. package/dist/react/charts/unified/PowerOverviewChart.js +488 -0
  62. package/dist/react/charts/unified/PowerOverviewChart.js.map +1 -0
  63. package/dist/react/charts/unified/domain.js +3168 -0
  64. package/dist/react/charts/unified/domain.js.map +1 -0
  65. package/dist/react/charts/unified/generators.js +518 -0
  66. package/dist/react/charts/unified/generators.js.map +1 -0
  67. package/dist/react/charts/unified/presets.js +1000 -0
  68. package/dist/react/charts/unified/presets.js.map +1 -0
  69. package/dist/react/charts/unified/sync.js +219 -0
  70. package/dist/react/charts/unified/sync.js.map +1 -0
  71. package/dist/react/charts/unified/theme.js +331 -4
  72. package/dist/react/charts/unified/theme.js.map +1 -1
  73. package/dist/react/charts/unified/useChartStream.js +226 -0
  74. package/dist/react/charts/unified/useChartStream.js.map +1 -0
  75. package/dist/react/chatgpt/AppCard.d.ts +0 -4
  76. package/dist/react/chatgpt/index.d.ts +0 -19
  77. package/dist/react/chatgpt/index.js +163 -0
  78. package/dist/react/chatgpt/index.js.map +1 -0
  79. package/dist/react/context/SpatialSelectionContext.d.ts +40 -0
  80. package/dist/react/context/SpatialSelectionContext.js +10 -0
  81. package/dist/react/context/SpatialSelectionContext.js.map +1 -0
  82. package/dist/react/context/index.d.ts +2 -0
  83. package/dist/react/core/{DataTable.d.ts → data/DataTable.d.ts} +1 -1
  84. package/dist/react/core/{DataTable.js → data/DataTable.js} +4 -4
  85. package/dist/react/core/data/DataTable.js.map +1 -0
  86. package/dist/react/core/{DataValue.d.ts → data/DataValue.d.ts} +2 -2
  87. package/dist/react/core/{DataValue.js → data/DataValue.js} +2 -2
  88. package/dist/react/core/data/DataValue.js.map +1 -0
  89. package/dist/react/core/{propertyConfig.d.ts → data/propertyConfig.d.ts} +2 -2
  90. package/dist/react/core/data/propertyConfig.js.map +1 -0
  91. package/dist/react/core/{AstroIcon.js → display/AstroIcon.js} +1 -1
  92. package/dist/react/core/display/AstroIcon.js.map +1 -0
  93. package/dist/react/core/{Badge.d.ts → display/Badge.d.ts} +1 -1
  94. package/dist/react/core/{Badge.js → display/Badge.js} +2 -2
  95. package/dist/react/core/display/Badge.js.map +1 -0
  96. package/dist/react/core/{CardHeader.d.ts → display/CardHeader.d.ts} +1 -1
  97. package/dist/react/core/{CardHeader.js → display/CardHeader.js} +2 -2
  98. package/dist/react/core/display/CardHeader.js.map +1 -0
  99. package/dist/react/core/{Container.d.ts → display/Container.d.ts} +1 -1
  100. package/dist/react/core/{Container.js → display/Container.js} +3 -3
  101. package/dist/react/core/display/Container.js.map +1 -0
  102. package/dist/react/core/{CopyButton.js → display/CopyButton.js} +1 -1
  103. package/dist/react/core/display/CopyButton.js.map +1 -0
  104. package/dist/react/core/{GlassCard.d.ts → display/GlassCard.d.ts} +1 -1
  105. package/dist/react/core/{GlassCard.js → display/GlassCard.js} +2 -2
  106. package/dist/react/core/display/GlassCard.js.map +1 -0
  107. package/dist/react/core/{HeaderIconWithStatus.d.ts → display/HeaderIconWithStatus.d.ts} +1 -1
  108. package/dist/react/core/{HeaderIconWithStatus.js → display/HeaderIconWithStatus.js} +1 -1
  109. package/dist/react/core/display/HeaderIconWithStatus.js.map +1 -0
  110. package/dist/react/core/{Icon.d.ts → display/Icon.d.ts} +1 -1
  111. package/dist/react/core/{Icon.js → display/Icon.js} +1 -1
  112. package/dist/react/core/display/Icon.js.map +1 -0
  113. package/dist/react/core/{Typography.d.ts → display/Typography.d.ts} +13 -4
  114. package/dist/react/core/{Typography.js → display/Typography.js} +1 -1
  115. package/dist/react/core/display/Typography.js.map +1 -0
  116. package/dist/react/core/{ConfirmDialog.js → feedback/ConfirmDialog.js} +1 -1
  117. package/dist/react/core/feedback/ConfirmDialog.js.map +1 -0
  118. package/dist/react/core/{Dialog.js → feedback/Dialog.js} +2 -2
  119. package/dist/react/core/feedback/Dialog.js.map +1 -0
  120. package/dist/react/core/{Toast.js → feedback/Toast.js} +3 -3
  121. package/dist/react/core/feedback/Toast.js.map +1 -0
  122. package/dist/react/core/index.d.ts +85 -85
  123. package/dist/react/core/index.js +161 -0
  124. package/dist/react/core/index.js.map +1 -0
  125. package/dist/react/core/{Button.js → inputs/Button.js} +2 -2
  126. package/dist/react/core/inputs/Button.js.map +1 -0
  127. package/dist/react/core/{Checkbox.js → inputs/Checkbox.js} +2 -2
  128. package/dist/react/core/inputs/Checkbox.js.map +1 -0
  129. package/dist/react/core/{Input.d.ts → inputs/Input.d.ts} +1 -1
  130. package/dist/react/core/{Input.js → inputs/Input.js} +3 -3
  131. package/dist/react/core/inputs/Input.js.map +1 -0
  132. package/dist/react/core/{LimitsBar.js → inputs/LimitsBar.js} +1 -1
  133. package/dist/react/core/inputs/LimitsBar.js.map +1 -0
  134. package/dist/react/core/{NumberInput.d.ts → inputs/NumberInput.d.ts} +2 -2
  135. package/dist/react/core/{NumberInput.js → inputs/NumberInput.js} +3 -3
  136. package/dist/react/core/inputs/NumberInput.js.map +1 -0
  137. package/dist/react/core/{PinInput.js → inputs/PinInput.js} +2 -2
  138. package/dist/react/core/inputs/PinInput.js.map +1 -0
  139. package/dist/react/core/{Select.js → inputs/Select.js} +3 -3
  140. package/dist/react/core/inputs/Select.js.map +1 -0
  141. package/dist/react/core/{Toggle.js → inputs/Toggle.js} +2 -2
  142. package/dist/react/core/inputs/Toggle.js.map +1 -0
  143. package/dist/react/core/layout/Box.js +1 -1
  144. package/dist/react/core/layout/Flex.js +1 -1
  145. package/dist/react/core/layout/Grid.js +1 -1
  146. package/dist/react/core/layout/Stack.js +1 -1
  147. package/dist/react/core/{AppBar.d.ts → navigation/AppBar.d.ts} +1 -1
  148. package/dist/react/core/{AppBar.js → navigation/AppBar.js} +7 -7
  149. package/dist/react/core/navigation/AppBar.js.map +1 -0
  150. package/dist/react/core/{Pagination.js → navigation/Pagination.js} +2 -2
  151. package/dist/react/core/navigation/Pagination.js.map +1 -0
  152. package/dist/react/core/{SideNav.d.ts → navigation/SideNav.d.ts} +1 -1
  153. package/dist/react/core/{SideNav.js → navigation/SideNav.js} +3 -3
  154. package/dist/react/core/navigation/SideNav.js.map +1 -0
  155. package/dist/react/core/{Tabs.js → navigation/Tabs.js} +2 -2
  156. package/dist/react/core/navigation/Tabs.js.map +1 -0
  157. package/dist/react/core/{Popover.js → overlays/Popover.js} +1 -1
  158. package/dist/react/core/overlays/Popover.js.map +1 -0
  159. package/dist/react/core/{SidePanel.js → overlays/SidePanel.js} +3 -3
  160. package/dist/react/core/overlays/SidePanel.js.map +1 -0
  161. package/dist/react/core/{Tooltip.js → overlays/Tooltip.js} +2 -2
  162. package/dist/react/core/overlays/Tooltip.js.map +1 -0
  163. package/dist/react/core/{ActivityPlanner.js → widgets/ActivityPlanner.js} +1 -1
  164. package/dist/react/core/widgets/ActivityPlanner.js.map +1 -0
  165. package/dist/react/core/{Capture.js → widgets/Capture.js} +3 -3
  166. package/dist/react/core/widgets/Capture.js.map +1 -0
  167. package/dist/react/core/{ChatPanel.d.ts → widgets/ChatPanel.d.ts} +1 -1
  168. package/dist/react/core/{ChatPanel.js → widgets/ChatPanel.js} +2 -2
  169. package/dist/react/core/widgets/ChatPanel.js.map +1 -0
  170. package/dist/react/core/{ColorPickerPanel.d.ts → widgets/ColorPickerPanel.d.ts} +1 -1
  171. package/dist/react/core/{ColorPickerPanel.js → widgets/ColorPickerPanel.js} +3 -3
  172. package/dist/react/core/widgets/ColorPickerPanel.js.map +1 -0
  173. package/dist/react/core/{CommandBuilder.js → widgets/CommandBuilder.js} +1 -1
  174. package/dist/react/core/widgets/CommandBuilder.js.map +1 -0
  175. package/dist/react/core/{ConnectionForm.d.ts → widgets/ConnectionForm.d.ts} +1 -1
  176. package/dist/react/core/{ConnectionForm.js → widgets/ConnectionForm.js} +2 -2
  177. package/dist/react/core/widgets/ConnectionForm.js.map +1 -0
  178. package/dist/react/core/{FileExplorer.js → widgets/FileExplorer.js} +2 -2
  179. package/dist/react/core/widgets/FileExplorer.js.map +1 -0
  180. package/dist/react/core/{HexViewer.js → widgets/HexViewer.js} +1 -1
  181. package/dist/react/core/widgets/HexViewer.js.map +1 -0
  182. package/dist/react/core/{ImageGallery.d.ts → widgets/ImageGallery.d.ts} +1 -1
  183. package/dist/react/core/{ImageGallery.js → widgets/ImageGallery.js} +3 -3
  184. package/dist/react/core/widgets/ImageGallery.js.map +1 -0
  185. package/dist/react/core/{LogViewer.d.ts → widgets/LogViewer.d.ts} +13 -3
  186. package/dist/react/core/{LogViewer.js → widgets/LogViewer.js} +28 -8
  187. package/dist/react/core/widgets/LogViewer.js.map +1 -0
  188. package/dist/react/core/{MessageStream.d.ts → widgets/MessageStream.d.ts} +2 -2
  189. package/dist/react/core/{MessageStream.js → widgets/MessageStream.js} +4 -4
  190. package/dist/react/core/widgets/MessageStream.js.map +1 -0
  191. package/dist/react/core/{MissionCalendar.js → widgets/MissionCalendar.js} +2 -2
  192. package/dist/react/core/widgets/MissionCalendar.js.map +1 -0
  193. package/dist/react/core/{PacketViewer.js → widgets/PacketViewer.js} +1 -1
  194. package/dist/react/core/widgets/PacketViewer.js.map +1 -0
  195. package/dist/react/core/widgets/capture-placeholder.png.js.map +1 -0
  196. package/dist/react/hooks/index.d.ts +9 -11
  197. package/dist/react/hooks/useAccessWindows.d.ts +15 -19
  198. package/dist/react/hooks/useCompactMode.js +1 -1
  199. package/dist/react/hooks/useGroundTrackHistory.d.ts +34 -0
  200. package/dist/react/hooks/useSimulationScene.d.ts +141 -0
  201. package/dist/react/hooks/useSimulationScene.js +401 -0
  202. package/dist/react/hooks/useSimulationScene.js.map +1 -0
  203. package/dist/react/hooks/useZendirSession.d.ts +44 -69
  204. package/dist/react/index.d.ts +7 -3
  205. package/dist/react/panels/LayerControlPanel.d.ts +54 -0
  206. package/dist/react/panels/LayerControlPanel.js +184 -0
  207. package/dist/react/panels/LayerControlPanel.js.map +1 -0
  208. package/dist/react/panels/ObjectInventoryPanel.d.ts +57 -0
  209. package/dist/react/panels/ObjectInventoryPanel.js +261 -0
  210. package/dist/react/panels/ObjectInventoryPanel.js.map +1 -0
  211. package/dist/react/panels/index.d.ts +15 -0
  212. package/dist/react/panels/index.js +8 -0
  213. package/dist/react/panels/index.js.map +1 -0
  214. package/dist/react/theme/ThemeProvider.d.ts +2 -0
  215. package/dist/react/theme/ThemeProvider.js +50 -72
  216. package/dist/react/theme/ThemeProvider.js.map +1 -1
  217. package/dist/react/theme/config.js +30 -0
  218. package/dist/react/theme/config.js.map +1 -0
  219. package/dist/react/theme/index.js +19 -0
  220. package/dist/react/theme/index.js.map +1 -0
  221. package/dist/react/types.d.ts +32 -3
  222. package/dist/react/types.js.map +1 -1
  223. package/dist/react/utils/index.js +8 -0
  224. package/dist/react/utils/index.js.map +1 -1
  225. package/dist/react.js +73 -64
  226. package/dist/react.js.map +1 -1
  227. package/dist/shaders/atmosphere.frag.js +5 -0
  228. package/dist/shaders/atmosphere.frag.js.map +1 -0
  229. package/dist/shaders/atmosphere.vert.js +5 -0
  230. package/dist/shaders/atmosphere.vert.js.map +1 -0
  231. package/dist/shaders/stars.frag.js +5 -0
  232. package/dist/shaders/stars.frag.js.map +1 -0
  233. package/dist/shaders/stars.vert.js +5 -0
  234. package/dist/shaders/stars.vert.js.map +1 -0
  235. package/dist/style.css +6 -4
  236. package/dist/tokens/css-vars.d.ts +91 -0
  237. package/dist/tokens/css-vars.js +228 -0
  238. package/dist/tokens/css-vars.js.map +1 -0
  239. package/dist/tokens/index.d.ts +71 -18
  240. package/dist/tokens/index.js +206 -97
  241. package/dist/tokens/index.js.map +1 -1
  242. package/dist/tokens/tokens.css +50 -50
  243. package/package.json +70 -58
  244. package/sdk-stub.js +10 -5
  245. package/dist/react/3d/EarthViewer.d.ts +0 -46
  246. package/dist/react/3d/SolarSystemViewer.d.ts +0 -43
  247. package/dist/react/chatgpt/ChatGPTCard.d.ts +0 -6
  248. package/dist/react/core/ActivityPlanner.js.map +0 -1
  249. package/dist/react/core/AppBar.js.map +0 -1
  250. package/dist/react/core/AstroIcon.js.map +0 -1
  251. package/dist/react/core/Badge.js.map +0 -1
  252. package/dist/react/core/Button.js.map +0 -1
  253. package/dist/react/core/Capture.js.map +0 -1
  254. package/dist/react/core/CardHeader.js.map +0 -1
  255. package/dist/react/core/ChatPanel.js.map +0 -1
  256. package/dist/react/core/Checkbox.js.map +0 -1
  257. package/dist/react/core/ColorPickerPanel.js.map +0 -1
  258. package/dist/react/core/CommandBuilder.js.map +0 -1
  259. package/dist/react/core/ConfirmDialog.js.map +0 -1
  260. package/dist/react/core/ConnectionForm.js.map +0 -1
  261. package/dist/react/core/Container.js.map +0 -1
  262. package/dist/react/core/CopyButton.js.map +0 -1
  263. package/dist/react/core/DataTable.js.map +0 -1
  264. package/dist/react/core/DataValue.js.map +0 -1
  265. package/dist/react/core/Dialog.js.map +0 -1
  266. package/dist/react/core/FileExplorer.js.map +0 -1
  267. package/dist/react/core/GlassCard.js.map +0 -1
  268. package/dist/react/core/HeaderIconWithStatus.js.map +0 -1
  269. package/dist/react/core/HexViewer.js.map +0 -1
  270. package/dist/react/core/Icon.js.map +0 -1
  271. package/dist/react/core/ImageGallery.js.map +0 -1
  272. package/dist/react/core/Input.js.map +0 -1
  273. package/dist/react/core/LimitsBar.js.map +0 -1
  274. package/dist/react/core/LogViewer.js.map +0 -1
  275. package/dist/react/core/MessageStream.js.map +0 -1
  276. package/dist/react/core/MissionCalendar.js.map +0 -1
  277. package/dist/react/core/NumberInput.js.map +0 -1
  278. package/dist/react/core/PacketViewer.js.map +0 -1
  279. package/dist/react/core/Pagination.js.map +0 -1
  280. package/dist/react/core/PinInput.js.map +0 -1
  281. package/dist/react/core/Popover.js.map +0 -1
  282. package/dist/react/core/Select.js.map +0 -1
  283. package/dist/react/core/SideNav.js.map +0 -1
  284. package/dist/react/core/SidePanel.js.map +0 -1
  285. package/dist/react/core/Tabs.js.map +0 -1
  286. package/dist/react/core/Toast.js.map +0 -1
  287. package/dist/react/core/Toggle.js.map +0 -1
  288. package/dist/react/core/Tooltip.js.map +0 -1
  289. package/dist/react/core/Typography.js.map +0 -1
  290. package/dist/react/core/capture-placeholder.png.js.map +0 -1
  291. package/dist/react/core/propertyConfig.js.map +0 -1
  292. package/dist/react/hooks/useSimulationTime.d.ts +0 -61
  293. package/dist/react/hooks/useSpacecraftPosition.d.ts +0 -50
  294. package/dist/react/hooks/useTelemetry.d.ts +0 -55
  295. package/dist/types.d.ts +0 -1
  296. package/dist/types.js +0 -2
  297. package/dist/types.js.map +0 -1
  298. /package/dist/react/core/{propertyConfig.js → data/propertyConfig.js} +0 -0
  299. /package/dist/react/core/{AstroIcon.d.ts → display/AstroIcon.d.ts} +0 -0
  300. /package/dist/react/core/{CopyButton.d.ts → display/CopyButton.d.ts} +0 -0
  301. /package/dist/react/core/{ConfirmDialog.d.ts → feedback/ConfirmDialog.d.ts} +0 -0
  302. /package/dist/react/core/{Dialog.d.ts → feedback/Dialog.d.ts} +0 -0
  303. /package/dist/react/core/{Toast.d.ts → feedback/Toast.d.ts} +0 -0
  304. /package/dist/react/core/{Button.d.ts → inputs/Button.d.ts} +0 -0
  305. /package/dist/react/core/{Checkbox.d.ts → inputs/Checkbox.d.ts} +0 -0
  306. /package/dist/react/core/{LimitsBar.d.ts → inputs/LimitsBar.d.ts} +0 -0
  307. /package/dist/react/core/{PinInput.d.ts → inputs/PinInput.d.ts} +0 -0
  308. /package/dist/react/core/{Select.d.ts → inputs/Select.d.ts} +0 -0
  309. /package/dist/react/core/{Toggle.d.ts → inputs/Toggle.d.ts} +0 -0
  310. /package/dist/react/core/{Pagination.d.ts → navigation/Pagination.d.ts} +0 -0
  311. /package/dist/react/core/{Tabs.d.ts → navigation/Tabs.d.ts} +0 -0
  312. /package/dist/react/core/{Popover.d.ts → overlays/Popover.d.ts} +0 -0
  313. /package/dist/react/core/{SidePanel.d.ts → overlays/SidePanel.d.ts} +0 -0
  314. /package/dist/react/core/{Tooltip.d.ts → overlays/Tooltip.d.ts} +0 -0
  315. /package/dist/react/core/{ActivityPlanner.d.ts → widgets/ActivityPlanner.d.ts} +0 -0
  316. /package/dist/react/core/{Capture.d.ts → widgets/Capture.d.ts} +0 -0
  317. /package/dist/react/core/{CommandBuilder.d.ts → widgets/CommandBuilder.d.ts} +0 -0
  318. /package/dist/react/core/{FileExplorer.d.ts → widgets/FileExplorer.d.ts} +0 -0
  319. /package/dist/react/core/{HexViewer.d.ts → widgets/HexViewer.d.ts} +0 -0
  320. /package/dist/react/core/{MissionCalendar.d.ts → widgets/MissionCalendar.d.ts} +0 -0
  321. /package/dist/react/core/{PacketViewer.d.ts → widgets/PacketViewer.d.ts} +0 -0
  322. /package/dist/react/core/{capture-placeholder.png.js → widgets/capture-placeholder.png.js} +0 -0
@@ -436,6 +436,17 @@ export interface ZenSpace3DProps {
436
436
  timeScale?: number;
437
437
  /** Auto-play on mount */
438
438
  autoPlay?: boolean;
439
+ /**
440
+ * Reference time used to convert ECI / J2000 positions into the
441
+ * Earth-Fixed (ECEF) frame Cesium renders. Should be the **simulation
442
+ * clock as a real UTC Date** (sim epoch + sim seconds) so the
443
+ * sub-satellite point on Earth lines up with the actual ground track.
444
+ *
445
+ * If omitted, the Cesium backend falls back to wall-clock now —
446
+ * geometry stays self-consistent but the ground track will drift from
447
+ * the engine's truth as Earth rotates.
448
+ */
449
+ referenceTime?: Date;
439
450
  /**
440
451
  * Sun direction vector for lighting and atmosphere effects
441
452
  * Typically from Zendir SDK sun position calculation
@@ -485,8 +496,24 @@ export interface ZenSpace3DProps {
485
496
  showAxisHelper?: boolean;
486
497
  /** Maneuver nodes */
487
498
  maneuverNodes?: ManeuverNode[];
488
- /** Layer visibility overrides */
499
+ /**
500
+ * Render-flag layers — affect HOW objects are drawn.
501
+ * `labels` — name labels next to satellite / GS markers (default off)
502
+ * `coverage` — sensor footprint ellipses + cones (default off)
503
+ * `orbits` — historical orbit polylines (default on)
504
+ */
489
505
  layers?: Partial<LayerVisibility>;
506
+ /**
507
+ * Object-group visibility — toggle WHOLE categories on/off without
508
+ * unmounting the viewer. Defaults to "everything visible". Drives the
509
+ * upcoming `<LayerControlPanel />` — also usable directly for headless
510
+ * apps that want pre-set visibility.
511
+ */
512
+ visibility?: {
513
+ spacecraft?: boolean;
514
+ groundStations?: boolean;
515
+ celestialBodies?: boolean;
516
+ };
490
517
  /** Show controls panel */
491
518
  showControls?: boolean;
492
519
  /** Show timeline */
@@ -1,183 +1,27 @@
1
- import { Vector3D, LatLonAlt, SphericalCoords, TLEData, Satellite, OrbitPath, CoverageHexGrid } from './ZenSpace3DTypes';
1
+ import { Vector3D } from './ZenSpace3DTypes';
2
2
 
3
- /** Earth's radius in km */
3
+ /** Earth's mean radius in km. */
4
4
  export declare const EARTH_RADIUS_KM = 6371;
5
- /** Earth's gravitational parameter (km³/s²) */
6
- export declare const EARTH_MU = 398600.4418;
7
- /** Astronomical Unit in km */
8
- export declare const AU_KM = 149597870.7;
9
- /** Degrees to radians */
5
+ /** Degrees radians. */
10
6
  export declare const DEG_TO_RAD: number;
11
- /** Radians to degrees */
7
+ /** Radians degrees. */
12
8
  export declare const RAD_TO_DEG: number;
13
- /** J2000 epoch (January 1, 2000, 12:00 TT) */
14
- export declare const J2000_EPOCH: Date;
15
- /** Seconds per day */
16
- export declare const SECONDS_PER_DAY = 86400;
17
- /** Minutes per day */
18
- export declare const MINUTES_PER_DAY = 1440;
19
- /** Scene Earth radius (render units) */
9
+ /** Earth radius in scene units (Three.js render space). */
20
10
  export declare const SCENE_EARTH_RADIUS = 3000;
21
- /** Scene scale factor (km to render units) */
11
+ /** Conversion factor: 1 km scene units. */
22
12
  export declare const KM_TO_SCENE: number;
23
- /** Scene scale for Solar System (different scale) */
24
- export declare const SOLAR_SYSTEM_SCALE = 1;
25
13
  /**
26
- * Convert latitude/longitude/altitude to Cartesian (ECI-like for rendering)
27
- * @param lat Latitude in degrees
28
- * @param lon Longitude in degrees
29
- * @param altKm Altitude in kilometers
30
- * @param earthRadius Scene radius for Earth
31
- * @returns Cartesian coordinates
14
+ * Convert lat/lon/alt to a Cartesian point in scene space.
15
+ *
16
+ * Result is in *render units* (scaled by `KM_TO_SCENE`), suitable for
17
+ * direct use in the Three.js scene graph. For ECI→ECEF on the Cesium
18
+ * backend, use `Cesium.Transforms.computeTemeToPseudoFixedMatrix`.
19
+ *
20
+ * @param lat Latitude in degrees.
21
+ * @param lon Longitude in degrees.
22
+ * @param altKm Altitude above Earth surface in km (default 0).
23
+ * @param earthRadius Scene radius for Earth (default `SCENE_EARTH_RADIUS`).
32
24
  */
33
25
  export declare function latLonAltToCartesian(lat: number, lon: number, altKm?: number, earthRadius?: number): Vector3D;
34
- /**
35
- * Convert Cartesian to latitude/longitude/altitude
36
- * @param position Cartesian position
37
- * @param earthRadius Scene radius for Earth
38
- * @returns Lat/Lon/Alt
39
- */
40
- export declare function cartesianToLatLonAlt(position: Vector3D, earthRadius?: number): LatLonAlt;
41
- /**
42
- * Convert Cartesian to spherical coordinates
43
- */
44
- export declare function cartesianToSpherical(position: Vector3D): SphericalCoords;
45
- /**
46
- * Convert spherical to Cartesian coordinates
47
- */
48
- export declare function sphericalToCartesian(coords: SphericalCoords): Vector3D;
49
- /**
50
- * Convert ECI (Earth-Centered Inertial) to ECEF (Earth-Centered Earth-Fixed)
51
- * @param eci ECI position (km)
52
- * @param gmst Greenwich Mean Sidereal Time (radians)
53
- */
54
- export declare function eciToEcef(eci: Vector3D, gmst: number): Vector3D;
55
- /**
56
- * Calculate Greenwich Mean Sidereal Time
57
- * @param date Date/time
58
- * @returns GMST in radians
59
- */
60
- export declare function calculateGMST(date: Date): number;
61
- /**
62
- * Convert Date to Julian Date
63
- */
64
- export declare function dateToJulianDate(date: Date): number;
65
- /**
66
- * Parse Two-Line Element set
67
- */
68
- export declare function parseTLE(line1: string, line2: string): TLEData | null;
69
- /**
70
- * Simplified SGP4 propagation
71
- * @param tle TLE data
72
- * @param minutesFromEpoch Minutes from TLE epoch
73
- * @returns Position in km (ECI coordinates)
74
- */
75
- export declare function propagateSGP4Simple(tle: TLEData, minutesFromEpoch: number): Vector3D;
76
- /**
77
- * Propagate satellite to specific time
78
- * @param satellite Satellite with TLE
79
- * @param time Target time
80
- * @returns Position in km (ECI)
81
- */
82
- export declare function propagateSatellite(satellite: Satellite, time: Date): Vector3D | null;
83
- /**
84
- * Generate orbit path for a satellite
85
- * @param satellite Satellite with TLE
86
- * @param startTime Start time
87
- * @param duration Duration in minutes
88
- * @param steps Number of steps
89
- */
90
- export declare function generateOrbitPath(satellite: Satellite, startTime: Date, duration?: number, steps?: number): OrbitPath | null;
91
- /**
92
- * Calculate if a satellite is visible from a ground station
93
- * @param satPos Satellite position (scene units)
94
- * @param gsLatLon Ground station lat/lon
95
- * @param minElevation Minimum elevation angle (degrees)
96
- */
97
- export declare function isVisible(satPos: Vector3D, gsLatLon: {
98
- latitude: number;
99
- longitude: number;
100
- }, minElevation?: number): boolean;
101
- /**
102
- * Calculate visibility cone vertices for rendering
103
- * @param gsLatLon Ground station position
104
- * @param minElevation Minimum elevation angle
105
- * @param altitude Altitude for cone apex (km)
106
- * @param segments Number of segments for cone circle
107
- */
108
- export declare function calculateVisibilityConeGeometry(gsLatLon: {
109
- latitude: number;
110
- longitude: number;
111
- }, minElevation?: number, altitude?: number, segments?: number): Vector3D[];
112
- /**
113
- * Generate footprint polygon for a satellite
114
- * @param satPos Satellite position (scene units)
115
- * @param minElevation Minimum elevation angle
116
- * @param segments Number of segments
117
- */
118
- export declare function calculateFootprint(satPos: Vector3D, minElevation?: number, segments?: number): Array<{
119
- latitude: number;
120
- longitude: number;
121
- }>;
122
- /**
123
- * Generate a hexagonal grid covering the globe
124
- * @param resolution Grid resolution (lower = fewer hexagons)
125
- */
126
- export declare function generateHexGrid(resolution?: number): CoverageHexGrid;
127
- /**
128
- * Update hex grid coverage values based on satellite footprints
129
- */
130
- export declare function updateHexGridCoverage(grid: CoverageHexGrid, satellites: Satellite[], time: Date): CoverageHexGrid;
131
- export declare function dot(a: Vector3D, b: Vector3D): number;
132
- export declare function cross(a: Vector3D, b: Vector3D): Vector3D;
133
- export declare function magnitude(v: Vector3D): number;
134
- export declare function normalize(v: Vector3D): Vector3D;
135
- export declare function subtract(a: Vector3D, b: Vector3D): Vector3D;
136
- export declare function add(a: Vector3D, b: Vector3D): Vector3D;
137
- export declare function scale(v: Vector3D, s: number): Vector3D;
138
- export declare function distance(a: Vector3D, b: Vector3D): number;
139
- export declare function lerp(a: Vector3D, b: Vector3D, t: number): Vector3D;
140
- /**
141
- * Ease-out cubic function
142
- */
26
+ /** Cubic ease-out curve, used by camera fly-to animations. */
143
27
  export declare function easeOutCubic(t: number): number;
144
- /**
145
- * Ease-in-out cubic function
146
- */
147
- export declare function easeInOutCubic(t: number): number;
148
- /**
149
- * Smooth step function
150
- */
151
- export declare function smoothstep(edge0: number, edge1: number, x: number): number;
152
- /**
153
- * Interpolate between two colors
154
- */
155
- export declare function lerpColor(color1: string, color2: string, t: number): string;
156
- /**
157
- * Hex to RGB
158
- */
159
- export declare function hexToRgb(hex: string): {
160
- r: number;
161
- g: number;
162
- b: number;
163
- } | null;
164
- /**
165
- * Get color from value (0-1) on a gradient scale
166
- */
167
- export declare function getGradientColor(value: number, colors?: string[]): string;
168
- /**
169
- * Format time duration as HH:MM:SS
170
- */
171
- export declare function formatDuration(seconds: number): string;
172
- /**
173
- * Format distance in appropriate units
174
- */
175
- export declare function formatDistance(km: number): string;
176
- /**
177
- * Format velocity
178
- */
179
- export declare function formatVelocity(kmPerSec: number): string;
180
- /**
181
- * Format date/time for display
182
- */
183
- export declare function formatDateTime(date: Date): string;
@@ -1,9 +1,28 @@
1
1
  const EARTH_RADIUS_KM = 6371;
2
2
  const DEG_TO_RAD = Math.PI / 180;
3
3
  const RAD_TO_DEG = 180 / Math.PI;
4
+ const SCENE_EARTH_RADIUS = 3e3;
5
+ const KM_TO_SCENE = SCENE_EARTH_RADIUS / EARTH_RADIUS_KM;
6
+ function latLonAltToCartesian(lat, lon, altKm = 0, earthRadius = SCENE_EARTH_RADIUS) {
7
+ const r = earthRadius + altKm * KM_TO_SCENE;
8
+ const phi = (90 - lat) * DEG_TO_RAD;
9
+ const theta = (lon + 180) * DEG_TO_RAD;
10
+ return {
11
+ x: -r * Math.sin(phi) * Math.cos(theta),
12
+ y: r * Math.cos(phi),
13
+ z: r * Math.sin(phi) * Math.sin(theta)
14
+ };
15
+ }
16
+ function easeOutCubic(t) {
17
+ return 1 - Math.pow(1 - t, 3);
18
+ }
4
19
  export {
5
20
  DEG_TO_RAD,
6
21
  EARTH_RADIUS_KM,
7
- RAD_TO_DEG
22
+ KM_TO_SCENE,
23
+ RAD_TO_DEG,
24
+ SCENE_EARTH_RADIUS,
25
+ easeOutCubic,
26
+ latLonAltToCartesian
8
27
  };
9
28
  //# sourceMappingURL=ZenSpace3DUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ZenSpace3DUtils.js","sources":["../../../src/react/3d/ZenSpace3DUtils.ts"],"sourcesContent":["/**\r\n * @zendir/ui - ZenSpace3D Utility Functions\r\n * \r\n * Coordinate transformations, TLE propagation, coverage calculations,\r\n * and other utilities for 3D space visualization.\r\n */\r\n\r\nimport type {\r\n Vector3D,\r\n LatLonAlt,\r\n SphericalCoords,\r\n TLEData,\r\n Satellite,\r\n OrbitPath,\r\n CoverageHexGrid,\r\n VisibilityCone as _VisibilityCone,\r\n} from './ZenSpace3DTypes';\r\n\r\n// =============================================================================\r\n// Constants\r\n// =============================================================================\r\n\r\n/** Earth's radius in km */\r\nexport const EARTH_RADIUS_KM = 6371;\r\n\r\n/** Earth's gravitational parameter (km³/s²) */\r\nexport const EARTH_MU = 398600.4418;\r\n\r\n/** Astronomical Unit in km */\r\nexport const AU_KM = 149597870.7;\r\n\r\n/** Degrees to radians */\r\nexport const DEG_TO_RAD = Math.PI / 180;\r\n\r\n/** Radians to degrees */\r\nexport const RAD_TO_DEG = 180 / Math.PI;\r\n\r\n/** J2000 epoch (January 1, 2000, 12:00 TT) */\r\nexport const J2000_EPOCH = new Date('2000-01-01T12:00:00Z');\r\n\r\n/** Seconds per day */\r\nexport const SECONDS_PER_DAY = 86400;\r\n\r\n/** Minutes per day */\r\nexport const MINUTES_PER_DAY = 1440;\r\n\r\n// =============================================================================\r\n// Scene Scale Constants\r\n// =============================================================================\r\n\r\n/** Scene Earth radius (render units) */\r\nexport const SCENE_EARTH_RADIUS = 3000;\r\n\r\n/** Scene scale factor (km to render units) */\r\nexport const KM_TO_SCENE = SCENE_EARTH_RADIUS / EARTH_RADIUS_KM;\r\n\r\n/** Scene scale for Solar System (different scale) */\r\nexport const SOLAR_SYSTEM_SCALE = 1; // 1 unit = 1 km in solar system mode\r\n\r\n// =============================================================================\r\n// Coordinate Conversions\r\n// =============================================================================\r\n\r\n/**\r\n * Convert latitude/longitude/altitude to Cartesian (ECI-like for rendering)\r\n * @param lat Latitude in degrees\r\n * @param lon Longitude in degrees\r\n * @param altKm Altitude in kilometers\r\n * @param earthRadius Scene radius for Earth\r\n * @returns Cartesian coordinates\r\n */\r\nexport function latLonAltToCartesian(\r\n lat: number,\r\n lon: number,\r\n altKm: number = 0,\r\n earthRadius: number = SCENE_EARTH_RADIUS\r\n): Vector3D {\r\n const r = earthRadius + altKm * KM_TO_SCENE;\r\n const phi = (90 - lat) * DEG_TO_RAD;\r\n const theta = (lon + 180) * DEG_TO_RAD;\r\n \r\n return {\r\n x: -r * Math.sin(phi) * Math.cos(theta),\r\n y: r * Math.cos(phi),\r\n z: r * Math.sin(phi) * Math.sin(theta),\r\n };\r\n}\r\n\r\n/**\r\n * Convert Cartesian to latitude/longitude/altitude\r\n * @param position Cartesian position\r\n * @param earthRadius Scene radius for Earth\r\n * @returns Lat/Lon/Alt\r\n */\r\nexport function cartesianToLatLonAlt(\r\n position: Vector3D,\r\n earthRadius: number = SCENE_EARTH_RADIUS\r\n): LatLonAlt {\r\n const r = Math.sqrt(position.x ** 2 + position.y ** 2 + position.z ** 2);\r\n const lat = 90 - Math.acos(position.y / r) * RAD_TO_DEG;\r\n const lon = Math.atan2(position.z, -position.x) * RAD_TO_DEG - 180;\r\n const alt = (r - earthRadius) / KM_TO_SCENE;\r\n \r\n return { latitude: lat, longitude: lon, altitude: alt };\r\n}\r\n\r\n/**\r\n * Convert Cartesian to spherical coordinates\r\n */\r\nexport function cartesianToSpherical(position: Vector3D): SphericalCoords {\r\n const radius = Math.sqrt(position.x ** 2 + position.y ** 2 + position.z ** 2);\r\n const theta = Math.atan2(position.z, position.x);\r\n const phi = Math.acos(position.y / radius);\r\n \r\n return { radius, theta, phi };\r\n}\r\n\r\n/**\r\n * Convert spherical to Cartesian coordinates\r\n */\r\nexport function sphericalToCartesian(coords: SphericalCoords): Vector3D {\r\n return {\r\n x: coords.radius * Math.sin(coords.phi) * Math.cos(coords.theta),\r\n y: coords.radius * Math.cos(coords.phi),\r\n z: coords.radius * Math.sin(coords.phi) * Math.sin(coords.theta),\r\n };\r\n}\r\n\r\n/**\r\n * Convert ECI (Earth-Centered Inertial) to ECEF (Earth-Centered Earth-Fixed)\r\n * @param eci ECI position (km)\r\n * @param gmst Greenwich Mean Sidereal Time (radians)\r\n */\r\nexport function eciToEcef(eci: Vector3D, gmst: number): Vector3D {\r\n const cosGmst = Math.cos(gmst);\r\n const sinGmst = Math.sin(gmst);\r\n \r\n return {\r\n x: eci.x * cosGmst + eci.y * sinGmst,\r\n y: -eci.x * sinGmst + eci.y * cosGmst,\r\n z: eci.z,\r\n };\r\n}\r\n\r\n/**\r\n * Calculate Greenwich Mean Sidereal Time\r\n * @param date Date/time\r\n * @returns GMST in radians\r\n */\r\nexport function calculateGMST(date: Date): number {\r\n const jd = dateToJulianDate(date);\r\n const t = (jd - 2451545.0) / 36525.0;\r\n \r\n // GMST in degrees\r\n let gmst = 280.46061837 + \r\n 360.98564736629 * (jd - 2451545.0) + \r\n 0.000387933 * t * t - \r\n t * t * t / 38710000.0;\r\n \r\n // Normalize to 0-360\r\n gmst = gmst % 360;\r\n if (gmst < 0) gmst += 360;\r\n \r\n return gmst * DEG_TO_RAD;\r\n}\r\n\r\n/**\r\n * Convert Date to Julian Date\r\n */\r\nexport function dateToJulianDate(date: Date): number {\r\n const year = date.getUTCFullYear();\r\n const month = date.getUTCMonth() + 1;\r\n const day = date.getUTCDate();\r\n const hour = date.getUTCHours();\r\n const minute = date.getUTCMinutes();\r\n const second = date.getUTCSeconds();\r\n \r\n let y = year;\r\n let m = month;\r\n \r\n if (m <= 2) {\r\n y -= 1;\r\n m += 12;\r\n }\r\n \r\n const a = Math.floor(y / 100);\r\n const b = 2 - a + Math.floor(a / 4);\r\n \r\n const jd = Math.floor(365.25 * (y + 4716)) +\r\n Math.floor(30.6001 * (m + 1)) +\r\n day + b - 1524.5 +\r\n (hour + minute / 60 + second / 3600) / 24;\r\n \r\n return jd;\r\n}\r\n\r\n// =============================================================================\r\n// TLE Parsing & Propagation (Simplified SGP4)\r\n// =============================================================================\r\n\r\n/**\r\n * Parse Two-Line Element set\r\n */\r\nexport function parseTLE(line1: string, line2: string): TLEData | null {\r\n try {\r\n // Line 1 parsing\r\n const epochYear = parseInt(line1.substring(18, 20));\r\n const epochDay = parseFloat(line1.substring(20, 32));\r\n const bstar = parseScientificNotation(line1.substring(53, 61));\r\n \r\n // Line 2 parsing\r\n const inclination = parseFloat(line2.substring(8, 16));\r\n const raan = parseFloat(line2.substring(17, 25));\r\n const eccentricityStr = '0.' + line2.substring(26, 33);\r\n const eccentricity = parseFloat(eccentricityStr);\r\n const argOfPerigee = parseFloat(line2.substring(34, 42));\r\n const meanAnomaly = parseFloat(line2.substring(43, 51));\r\n const meanMotion = parseFloat(line2.substring(52, 63));\r\n \r\n // Calculate epoch date\r\n const fullYear = epochYear < 57 ? 2000 + epochYear : 1900 + epochYear;\r\n const epoch = new Date(Date.UTC(fullYear, 0, 1));\r\n epoch.setTime(epoch.getTime() + (epochDay - 1) * SECONDS_PER_DAY * 1000);\r\n \r\n return {\r\n line1,\r\n line2,\r\n epoch,\r\n meanMotion,\r\n eccentricity,\r\n inclination,\r\n raan,\r\n argOfPerigee,\r\n meanAnomaly,\r\n bstar,\r\n };\r\n } catch (e) {\r\n if (import.meta.env.DEV) {\r\n console.error('Failed to parse TLE:', e);\r\n }\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Parse TLE scientific notation (e.g., \" 12345-4\" = 0.12345e-4)\r\n */\r\nfunction parseScientificNotation(str: string): number {\r\n const trimmed = str.trim();\r\n if (trimmed.length === 0) return 0;\r\n \r\n // Find the position of the exponent sign\r\n let mantissa: string;\r\n let exponent: number;\r\n \r\n const lastSignPos = Math.max(trimmed.lastIndexOf('+'), trimmed.lastIndexOf('-'));\r\n if (lastSignPos > 0) {\r\n mantissa = '0.' + trimmed.substring(0, lastSignPos).replace(/[^0-9]/g, '');\r\n exponent = parseInt(trimmed.substring(lastSignPos));\r\n } else {\r\n mantissa = '0.' + trimmed.replace(/[^0-9]/g, '');\r\n exponent = 0;\r\n }\r\n \r\n return parseFloat(mantissa) * Math.pow(10, exponent);\r\n}\r\n\r\n/**\r\n * Simplified SGP4 propagation\r\n * @param tle TLE data\r\n * @param minutesFromEpoch Minutes from TLE epoch\r\n * @returns Position in km (ECI coordinates)\r\n */\r\nexport function propagateSGP4Simple(tle: TLEData, minutesFromEpoch: number): Vector3D {\r\n // Semi-major axis from mean motion\r\n const n = tle.meanMotion * 2 * Math.PI / MINUTES_PER_DAY; // rad/min\r\n const a = Math.pow(EARTH_MU / (n * n / 60 / 60), 1/3); // km\r\n \r\n // Current mean anomaly\r\n const M = (tle.meanAnomaly + (360 * tle.meanMotion * minutesFromEpoch / MINUTES_PER_DAY)) % 360;\r\n const M_rad = M * DEG_TO_RAD;\r\n \r\n // Solve Kepler's equation for eccentric anomaly (simplified Newton-Raphson)\r\n let E = M_rad;\r\n for (let i = 0; i < 10; i++) {\r\n E = M_rad + tle.eccentricity * Math.sin(E);\r\n }\r\n \r\n // True anomaly\r\n const cosE = Math.cos(E);\r\n const sinE = Math.sin(E);\r\n const nu = Math.atan2(\r\n Math.sqrt(1 - tle.eccentricity ** 2) * sinE,\r\n cosE - tle.eccentricity\r\n );\r\n \r\n // Distance\r\n const r = a * (1 - tle.eccentricity * cosE);\r\n \r\n // Position in orbital plane\r\n const xOrb = r * Math.cos(nu);\r\n const yOrb = r * Math.sin(nu);\r\n \r\n // RAAN and inclination with simple precession\r\n const raanRad = tle.raan * DEG_TO_RAD;\r\n const incRad = tle.inclination * DEG_TO_RAD;\r\n const argPeriRad = tle.argOfPerigee * DEG_TO_RAD;\r\n \r\n // Rotation matrices\r\n const cosRaan = Math.cos(raanRad);\r\n const sinRaan = Math.sin(raanRad);\r\n const cosInc = Math.cos(incRad);\r\n const sinInc = Math.sin(incRad);\r\n const cosArgPeri = Math.cos(argPeriRad);\r\n const sinArgPeri = Math.sin(argPeriRad);\r\n \r\n // Transform to ECI\r\n const x = (cosRaan * cosArgPeri - sinRaan * sinArgPeri * cosInc) * xOrb +\r\n (-cosRaan * sinArgPeri - sinRaan * cosArgPeri * cosInc) * yOrb;\r\n const y = (sinRaan * cosArgPeri + cosRaan * sinArgPeri * cosInc) * xOrb +\r\n (-sinRaan * sinArgPeri + cosRaan * cosArgPeri * cosInc) * yOrb;\r\n const z = (sinArgPeri * sinInc) * xOrb + (cosArgPeri * sinInc) * yOrb;\r\n \r\n return { x, y, z };\r\n}\r\n\r\n/**\r\n * Propagate satellite to specific time\r\n * @param satellite Satellite with TLE\r\n * @param time Target time\r\n * @returns Position in km (ECI)\r\n */\r\nexport function propagateSatellite(satellite: Satellite, time: Date): Vector3D | null {\r\n if (!satellite.tle) return null;\r\n \r\n const minutesFromEpoch = (time.getTime() - satellite.tle.epoch.getTime()) / 60000;\r\n return propagateSGP4Simple(satellite.tle, minutesFromEpoch);\r\n}\r\n\r\n/**\r\n * Generate orbit path for a satellite\r\n * @param satellite Satellite with TLE\r\n * @param startTime Start time\r\n * @param duration Duration in minutes\r\n * @param steps Number of steps\r\n */\r\nexport function generateOrbitPath(\r\n satellite: Satellite,\r\n startTime: Date,\r\n duration: number = 90,\r\n steps: number = 180\r\n): OrbitPath | null {\r\n if (!satellite.tle) return null;\r\n \r\n const points: Vector3D[] = [];\r\n const startMinutes = (startTime.getTime() - satellite.tle.epoch.getTime()) / 60000;\r\n \r\n for (let i = 0; i <= steps; i++) {\r\n const minutesFromEpoch = startMinutes + (i / steps) * duration;\r\n const pos = propagateSGP4Simple(satellite.tle, minutesFromEpoch);\r\n \r\n // Convert to scene coordinates\r\n points.push({\r\n x: pos.x * KM_TO_SCENE,\r\n y: pos.z * KM_TO_SCENE, // Swap Y/Z for Three.js\r\n z: pos.y * KM_TO_SCENE,\r\n });\r\n }\r\n \r\n return {\r\n objectId: satellite.id,\r\n points,\r\n timeSpan: duration * 60,\r\n isFuture: true,\r\n color: satellite.color || '#22d3ee',\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// Coverage & Visibility Calculations\r\n// =============================================================================\r\n\r\n/**\r\n * Calculate if a satellite is visible from a ground station\r\n * @param satPos Satellite position (scene units)\r\n * @param gsLatLon Ground station lat/lon\r\n * @param minElevation Minimum elevation angle (degrees)\r\n */\r\nexport function isVisible(\r\n satPos: Vector3D,\r\n gsLatLon: { latitude: number; longitude: number },\r\n minElevation: number = 5\r\n): boolean {\r\n const gsPos = latLonAltToCartesian(gsLatLon.latitude, gsLatLon.longitude, 0);\r\n \r\n // Vector from ground station to satellite\r\n const toSat = {\r\n x: satPos.x - gsPos.x,\r\n y: satPos.y - gsPos.y,\r\n z: satPos.z - gsPos.z,\r\n };\r\n \r\n // Ground station \"up\" vector (normal to Earth surface)\r\n const up = normalize(gsPos);\r\n \r\n // Calculate elevation angle\r\n const elevation = 90 - Math.acos(dot(normalize(toSat), up)) * RAD_TO_DEG;\r\n \r\n return elevation >= minElevation;\r\n}\r\n\r\n/**\r\n * Calculate visibility cone vertices for rendering\r\n * @param gsLatLon Ground station position\r\n * @param minElevation Minimum elevation angle\r\n * @param altitude Altitude for cone apex (km)\r\n * @param segments Number of segments for cone circle\r\n */\r\nexport function calculateVisibilityConeGeometry(\r\n gsLatLon: { latitude: number; longitude: number },\r\n minElevation: number = 5,\r\n altitude: number = 2000,\r\n segments: number = 32\r\n): Vector3D[] {\r\n const gsPos = latLonAltToCartesian(gsLatLon.latitude, gsLatLon.longitude, 0);\r\n const vertices: Vector3D[] = [];\r\n \r\n // Cone apex is at ground station\r\n vertices.push(gsPos);\r\n \r\n // Calculate cone opening angle\r\n const coneAngle = (90 - minElevation) * DEG_TO_RAD;\r\n const coneRadius = altitude * Math.tan(coneAngle);\r\n \r\n // Get local tangent plane vectors\r\n const up = normalize(gsPos);\r\n const east = normalize(cross({ x: 0, y: 1, z: 0 }, up));\r\n const north = cross(up, east);\r\n \r\n // Generate cone base circle\r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const basePoint = {\r\n x: gsPos.x + up.x * altitude * KM_TO_SCENE + \r\n (east.x * Math.cos(angle) + north.x * Math.sin(angle)) * coneRadius * KM_TO_SCENE,\r\n y: gsPos.y + up.y * altitude * KM_TO_SCENE + \r\n (east.y * Math.cos(angle) + north.y * Math.sin(angle)) * coneRadius * KM_TO_SCENE,\r\n z: gsPos.z + up.z * altitude * KM_TO_SCENE + \r\n (east.z * Math.cos(angle) + north.z * Math.sin(angle)) * coneRadius * KM_TO_SCENE,\r\n };\r\n vertices.push(basePoint);\r\n }\r\n \r\n return vertices;\r\n}\r\n\r\n/**\r\n * Generate footprint polygon for a satellite\r\n * @param satPos Satellite position (scene units)\r\n * @param minElevation Minimum elevation angle\r\n * @param segments Number of segments\r\n */\r\nexport function calculateFootprint(\r\n satPos: Vector3D,\r\n minElevation: number = 5,\r\n segments: number = 36\r\n): Array<{ latitude: number; longitude: number }> {\r\n const satLla = cartesianToLatLonAlt(satPos);\r\n const footprint: Array<{ latitude: number; longitude: number }> = [];\r\n \r\n // Simplified footprint calculation\r\n // Central angle of visibility circle\r\n const earthAngularRadius = Math.asin(EARTH_RADIUS_KM / (EARTH_RADIUS_KM + satLla.altitude));\r\n const elevAngle = minElevation * DEG_TO_RAD;\r\n const nadir = Math.PI / 2 - elevAngle - earthAngularRadius;\r\n const footprintRadius = nadir * RAD_TO_DEG;\r\n \r\n for (let i = 0; i < segments; i++) {\r\n const bearing = (i / segments) * 360;\r\n const point = destinationPoint(\r\n satLla.latitude,\r\n satLla.longitude,\r\n footprintRadius * 111.32, // Approximate km per degree\r\n bearing\r\n );\r\n footprint.push(point);\r\n }\r\n \r\n return footprint;\r\n}\r\n\r\n/**\r\n * Calculate destination point given start, distance, and bearing\r\n */\r\nfunction destinationPoint(\r\n lat: number,\r\n lon: number,\r\n distanceKm: number,\r\n bearing: number\r\n): { latitude: number; longitude: number } {\r\n const R = EARTH_RADIUS_KM;\r\n const d = distanceKm / R;\r\n const brng = bearing * DEG_TO_RAD;\r\n const lat1 = lat * DEG_TO_RAD;\r\n const lon1 = lon * DEG_TO_RAD;\r\n \r\n const lat2 = Math.asin(\r\n Math.sin(lat1) * Math.cos(d) +\r\n Math.cos(lat1) * Math.sin(d) * Math.cos(brng)\r\n );\r\n \r\n const lon2 = lon1 + Math.atan2(\r\n Math.sin(brng) * Math.sin(d) * Math.cos(lat1),\r\n Math.cos(d) - Math.sin(lat1) * Math.sin(lat2)\r\n );\r\n \r\n return {\r\n latitude: lat2 * RAD_TO_DEG,\r\n longitude: lon2 * RAD_TO_DEG,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// Hexagonal Grid for Coverage\r\n// =============================================================================\r\n\r\n/**\r\n * Generate a hexagonal grid covering the globe\r\n * @param resolution Grid resolution (lower = fewer hexagons)\r\n */\r\nexport function generateHexGrid(resolution: number = 2): CoverageHexGrid {\r\n const hexagons: CoverageHexGrid['hexagons'] = [];\r\n \r\n // Simplified hex grid generation (not true H3, but visually similar)\r\n const latStep = 180 / (resolution * 8);\r\n const lonStep = 360 / (resolution * 16);\r\n \r\n let id = 0;\r\n for (let lat = -90 + latStep / 2; lat < 90; lat += latStep) {\r\n // Adjust longitude step for latitude (narrower near poles)\r\n const adjustedLonStep = lonStep / Math.cos(lat * DEG_TO_RAD);\r\n const offset = (Math.floor((lat + 90) / latStep) % 2) * (adjustedLonStep / 2);\r\n \r\n for (let lon = -180 + offset; lon < 180; lon += adjustedLonStep) {\r\n hexagons.push({\r\n id: `hex_${id++}`,\r\n value: 0,\r\n center: { latitude: lat, longitude: lon },\r\n });\r\n }\r\n }\r\n \r\n return {\r\n resolution,\r\n hexagons,\r\n colorScale: { min: '#1a1a2e', max: '#00ff88' },\r\n };\r\n}\r\n\r\n/**\r\n * Update hex grid coverage values based on satellite footprints\r\n */\r\nexport function updateHexGridCoverage(\r\n grid: CoverageHexGrid,\r\n satellites: Satellite[],\r\n time: Date\r\n): CoverageHexGrid {\r\n // Clone grid\r\n const updatedGrid = {\r\n ...grid,\r\n hexagons: grid.hexagons.map(h => ({ ...h, value: 0 })),\r\n };\r\n \r\n satellites.forEach(sat => {\r\n const pos = propagateSatellite(sat, time);\r\n if (!pos) return;\r\n \r\n const scenePos = {\r\n x: pos.x * KM_TO_SCENE,\r\n y: pos.z * KM_TO_SCENE,\r\n z: pos.y * KM_TO_SCENE,\r\n };\r\n \r\n const footprint = calculateFootprint(scenePos);\r\n \r\n // Check each hexagon\r\n updatedGrid.hexagons.forEach(hex => {\r\n const inFootprint = isPointInPolygon(hex.center, footprint);\r\n if (inFootprint) {\r\n hex.value = Math.min(1, hex.value + 0.2);\r\n }\r\n });\r\n });\r\n \r\n return updatedGrid;\r\n}\r\n\r\n/**\r\n * Point-in-polygon test (simplified)\r\n */\r\nfunction isPointInPolygon(\r\n point: { latitude: number; longitude: number },\r\n polygon: Array<{ latitude: number; longitude: number }>\r\n): boolean {\r\n let inside = false;\r\n const n = polygon.length;\r\n \r\n for (let i = 0, j = n - 1; i < n; j = i++) {\r\n const xi = polygon[i].longitude;\r\n const yi = polygon[i].latitude;\r\n const xj = polygon[j].longitude;\r\n const yj = polygon[j].latitude;\r\n \r\n if (((yi > point.latitude) !== (yj > point.latitude)) &&\r\n (point.longitude < (xj - xi) * (point.latitude - yi) / (yj - yi) + xi)) {\r\n inside = !inside;\r\n }\r\n }\r\n \r\n return inside;\r\n}\r\n\r\n// =============================================================================\r\n// Vector Math Utilities\r\n// =============================================================================\r\n\r\nexport function dot(a: Vector3D, b: Vector3D): number {\r\n return a.x * b.x + a.y * b.y + a.z * b.z;\r\n}\r\n\r\nexport function cross(a: Vector3D, b: Vector3D): Vector3D {\r\n return {\r\n x: a.y * b.z - a.z * b.y,\r\n y: a.z * b.x - a.x * b.z,\r\n z: a.x * b.y - a.y * b.x,\r\n };\r\n}\r\n\r\nexport function magnitude(v: Vector3D): number {\r\n return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);\r\n}\r\n\r\nexport function normalize(v: Vector3D): Vector3D {\r\n const m = magnitude(v);\r\n if (m === 0) return { x: 0, y: 0, z: 0 };\r\n return { x: v.x / m, y: v.y / m, z: v.z / m };\r\n}\r\n\r\nexport function subtract(a: Vector3D, b: Vector3D): Vector3D {\r\n return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };\r\n}\r\n\r\nexport function add(a: Vector3D, b: Vector3D): Vector3D {\r\n return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };\r\n}\r\n\r\nexport function scale(v: Vector3D, s: number): Vector3D {\r\n return { x: v.x * s, y: v.y * s, z: v.z * s };\r\n}\r\n\r\nexport function distance(a: Vector3D, b: Vector3D): number {\r\n return magnitude(subtract(a, b));\r\n}\r\n\r\nexport function lerp(a: Vector3D, b: Vector3D, t: number): Vector3D {\r\n return {\r\n x: a.x + (b.x - a.x) * t,\r\n y: a.y + (b.y - a.y) * t,\r\n z: a.z + (b.z - a.z) * t,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// Animation Utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Ease-out cubic function\r\n */\r\nexport function easeOutCubic(t: number): number {\r\n return 1 - Math.pow(1 - t, 3);\r\n}\r\n\r\n/**\r\n * Ease-in-out cubic function\r\n */\r\nexport function easeInOutCubic(t: number): number {\r\n return t < 0.5\r\n ? 4 * t * t * t\r\n : 1 - Math.pow(-2 * t + 2, 3) / 2;\r\n}\r\n\r\n/**\r\n * Smooth step function\r\n */\r\nexport function smoothstep(edge0: number, edge1: number, x: number): number {\r\n const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));\r\n return t * t * (3 - 2 * t);\r\n}\r\n\r\n// =============================================================================\r\n// Color Utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Interpolate between two colors\r\n */\r\nexport function lerpColor(color1: string, color2: string, t: number): string {\r\n const c1 = hexToRgb(color1);\r\n const c2 = hexToRgb(color2);\r\n \r\n if (!c1 || !c2) return color1;\r\n \r\n const r = Math.round(c1.r + (c2.r - c1.r) * t);\r\n const g = Math.round(c1.g + (c2.g - c1.g) * t);\r\n const b = Math.round(c1.b + (c2.b - c1.b) * t);\r\n \r\n return `rgb(${r}, ${g}, ${b})`;\r\n}\r\n\r\n/**\r\n * Hex to RGB\r\n */\r\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } | null {\r\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\r\n return result\r\n ? {\r\n r: parseInt(result[1], 16),\r\n g: parseInt(result[2], 16),\r\n b: parseInt(result[3], 16),\r\n }\r\n : null;\r\n}\r\n\r\n/**\r\n * Get color from value (0-1) on a gradient scale\r\n */\r\nexport function getGradientColor(\r\n value: number,\r\n colors: string[] = ['#1a1a2e', '#0f3460', '#16c79a', '#ff6b6b']\r\n): string {\r\n const clampedValue = Math.max(0, Math.min(1, value));\r\n const scaledValue = clampedValue * (colors.length - 1);\r\n const index = Math.floor(scaledValue);\r\n const t = scaledValue - index;\r\n \r\n if (index >= colors.length - 1) return colors[colors.length - 1];\r\n \r\n return lerpColor(colors[index], colors[index + 1], t);\r\n}\r\n\r\n// =============================================================================\r\n// Format Utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Format time duration as HH:MM:SS\r\n */\r\nexport function formatDuration(seconds: number): string {\r\n const h = Math.floor(seconds / 3600);\r\n const m = Math.floor((seconds % 3600) / 60);\r\n const s = Math.floor(seconds % 60);\r\n \r\n return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\r\n}\r\n\r\n/**\r\n * Format distance in appropriate units\r\n */\r\nexport function formatDistance(km: number): string {\r\n if (km < 1) {\r\n return `${(km * 1000).toFixed(0)} m`;\r\n } else if (km < 1000) {\r\n return `${km.toFixed(1)} km`;\r\n } else if (km < AU_KM / 100) {\r\n return `${(km / 1000).toFixed(2)} thousand km`;\r\n } else {\r\n return `${(km / AU_KM).toFixed(4)} AU`;\r\n }\r\n}\r\n\r\n/**\r\n * Format velocity\r\n */\r\nexport function formatVelocity(kmPerSec: number): string {\r\n return `${kmPerSec.toFixed(3)} km/s`;\r\n}\r\n\r\n/**\r\n * Format date/time for display\r\n */\r\nexport function formatDateTime(date: Date): string {\r\n return date.toISOString().replace('T', ' ').split('.')[0] + ' UTC';\r\n}\r\n"],"names":[],"mappings":"AAuBO,MAAM,kBAAkB;AASxB,MAAM,aAAa,KAAK,KAAK;AAG7B,MAAM,aAAa,MAAM,KAAK;"}
1
+ {"version":3,"file":"ZenSpace3DUtils.js","sources":["../../../src/react/3d/ZenSpace3DUtils.ts"],"sourcesContent":["/**\n * @zendir/ui - ZenSpace3D rendering math\n *\n * The minimal helper set needed by the live 3D backends:\n * • Earth + scene scaling constants used by the Three.js path\n * (`ZenSpace3D.tsx`) and the Cesium capture source\n * (`CesiumCaptureSource.ts`)\n * • `latLonAltToCartesian` — lat/lon/alt → render-space Cartesian\n * • `easeOutCubic` — camera-fly-to easing\n *\n * Higher-level orbital math (TLE/SGP4 propagation, GMST, visibility cones,\n * hex-grid coverage) was removed — those weren't consumed by either\n * backend. The Cesium backend uses Cesium's own `Transforms` for\n * ECI→ECEF, and the Three.js backend draws coverage from explicit\n * `SatelliteCoverage` props rather than computing it locally.\n */\n\nimport type { Vector3D } from './ZenSpace3DTypes';\n\n// ── Constants ─────────────────────────────────────────────────────────────────\n\n/** Earth's mean radius in km. */\nexport const EARTH_RADIUS_KM = 6371;\n\n/** Degrees → radians. */\nexport const DEG_TO_RAD = Math.PI / 180;\n\n/** Radians → degrees. */\nexport const RAD_TO_DEG = 180 / Math.PI;\n\n/** Earth radius in scene units (Three.js render space). */\nexport const SCENE_EARTH_RADIUS = 3000;\n\n/** Conversion factor: 1 km → scene units. */\nexport const KM_TO_SCENE = SCENE_EARTH_RADIUS / EARTH_RADIUS_KM;\n\n// ── Coordinate conversion ─────────────────────────────────────────────────────\n\n/**\n * Convert lat/lon/alt to a Cartesian point in scene space.\n *\n * Result is in *render units* (scaled by `KM_TO_SCENE`), suitable for\n * direct use in the Three.js scene graph. For ECI→ECEF on the Cesium\n * backend, use `Cesium.Transforms.computeTemeToPseudoFixedMatrix`.\n *\n * @param lat Latitude in degrees.\n * @param lon Longitude in degrees.\n * @param altKm Altitude above Earth surface in km (default 0).\n * @param earthRadius Scene radius for Earth (default `SCENE_EARTH_RADIUS`).\n */\nexport function latLonAltToCartesian(\n lat: number,\n lon: number,\n altKm: number = 0,\n earthRadius: number = SCENE_EARTH_RADIUS,\n): Vector3D {\n const r = earthRadius + altKm * KM_TO_SCENE;\n const phi = (90 - lat) * DEG_TO_RAD;\n const theta = (lon + 180) * DEG_TO_RAD;\n return {\n x: -r * Math.sin(phi) * Math.cos(theta),\n y: r * Math.cos(phi),\n z: r * Math.sin(phi) * Math.sin(theta),\n };\n}\n\n// ── Easing ────────────────────────────────────────────────────────────────────\n\n/** Cubic ease-out curve, used by camera fly-to animations. */\nexport function easeOutCubic(t: number): number {\n return 1 - Math.pow(1 - t, 3);\n}\n"],"names":[],"mappings":"AAsBO,MAAM,kBAAkB;AAGxB,MAAM,aAAa,KAAK,KAAK;AAG7B,MAAM,aAAa,MAAM,KAAK;AAG9B,MAAM,qBAAqB;AAG3B,MAAM,cAAc,qBAAqB;AAgBzC,SAAS,qBACd,KACA,KACA,QAAgB,GAChB,cAAsB,oBACZ;AACV,QAAM,IAAI,cAAc,QAAQ;AAChC,QAAM,OAAO,KAAK,OAAO;AACzB,QAAM,SAAS,MAAM,OAAO;AAC5B,SAAO;AAAA,IACL,GAAG,CAAC,IAAI,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK;AAAA,IACtC,GAAG,IAAI,KAAK,IAAI,GAAG;AAAA,IACnB,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK;AAAA,EAAA;AAEzC;AAKO,SAAS,aAAa,GAAmB;AAC9C,SAAO,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;AAC9B;"}
@@ -0,0 +1,42 @@
1
+ function rgbToLuma(r, g, b) {
2
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
3
+ }
4
+ async function meanLuminanceFromPngBytes(png) {
5
+ var _a;
6
+ if (typeof createImageBitmap !== "function" || typeof document === "undefined") {
7
+ return 0;
8
+ }
9
+ try {
10
+ const blob = new Blob([png], { type: "image/png" });
11
+ const bmp = await createImageBitmap(blob);
12
+ const w = bmp.width;
13
+ const h = bmp.height;
14
+ const canvas = document.createElement("canvas");
15
+ const step = Math.max(1, Math.floor(Math.sqrt(w * h / 4096)));
16
+ canvas.width = Math.ceil(w / step);
17
+ canvas.height = Math.ceil(h / step);
18
+ const ctx = canvas.getContext("2d");
19
+ if (!ctx) return 0;
20
+ ctx.drawImage(bmp, 0, 0, w, h, 0, 0, canvas.width, canvas.height);
21
+ const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height);
22
+ let sum = 0;
23
+ const n = data.length / 4;
24
+ for (let i = 0; i < data.length; i += 4) {
25
+ sum += rgbToLuma(data[i], data[i + 1], data[i + 2]);
26
+ }
27
+ (_a = bmp.close) == null ? void 0 : _a.call(bmp);
28
+ return n > 0 ? sum / n : 0;
29
+ } catch {
30
+ return 0;
31
+ }
32
+ }
33
+ async function isPngMostlyBlack(png, threshold = 5) {
34
+ const m = await meanLuminanceFromPngBytes(png);
35
+ return m < threshold;
36
+ }
37
+ export {
38
+ isPngMostlyBlack,
39
+ meanLuminanceFromPngBytes,
40
+ rgbToLuma
41
+ };
42
+ //# sourceMappingURL=capturePngAnalysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capturePngAnalysis.js","sources":["../../../src/react/3d/capturePngAnalysis.ts"],"sourcesContent":["/**\r\n * Lightweight PNG analysis for capture QA (brightness / \"all black\" detection).\r\n * Used by tests and optional runtime checks — keep dependency-free (no pngjs).\r\n */\r\n\r\n/** ITU-R BT.709 luma from RGB */\r\nexport function rgbToLuma(r: number, g: number, b: number): number {\r\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\r\n}\r\n\r\n/**\r\n * Sample mean luma of PNG bytes by drawing to a small canvas (browser / happy-dom).\r\n * Returns 0 if decode fails. For very large images, samples a grid (max ~4096 samples).\r\n */\r\nexport async function meanLuminanceFromPngBytes(png: Uint8Array): Promise<number> {\r\n if (typeof createImageBitmap !== 'function' || typeof document === 'undefined') {\r\n return 0;\r\n }\r\n try {\r\n const blob = new Blob([png as unknown as BlobPart], { type: 'image/png' });\r\n const bmp = await createImageBitmap(blob);\r\n const w = bmp.width;\r\n const h = bmp.height;\r\n const canvas = document.createElement('canvas');\r\n const step = Math.max(1, Math.floor(Math.sqrt((w * h) / 4096)));\r\n canvas.width = Math.ceil(w / step);\r\n canvas.height = Math.ceil(h / step);\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return 0;\r\n ctx.drawImage(bmp, 0, 0, w, h, 0, 0, canvas.width, canvas.height);\r\n const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height);\r\n let sum = 0;\r\n const n = data.length / 4;\r\n for (let i = 0; i < data.length; i += 4) {\r\n sum += rgbToLuma(data[i], data[i + 1], data[i + 2]);\r\n }\r\n bmp.close?.();\r\n return n > 0 ? sum / n : 0;\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\n/**\r\n * True if the image is uniformly dark (likely failed render / empty GL buffer).\r\n * Threshold is mean luma on 0–255 scale (default 5 ≈ pure black).\r\n */\r\nexport async function isPngMostlyBlack(png: Uint8Array, threshold = 5): Promise<boolean> {\r\n const m = await meanLuminanceFromPngBytes(png);\r\n return m < threshold;\r\n}\r\n"],"names":[],"mappings":"AAMO,SAAS,UAAU,GAAW,GAAW,GAAmB;AACjE,SAAO,SAAS,IAAI,SAAS,IAAI,SAAS;AAC5C;AAMA,eAAsB,0BAA0B,KAAkC;AAR3E;AASL,MAAI,OAAO,sBAAsB,cAAc,OAAO,aAAa,aAAa;AAC9E,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,OAAO,IAAI,KAAK,CAAC,GAA0B,GAAG,EAAE,MAAM,aAAa;AACzE,UAAM,MAAM,MAAM,kBAAkB,IAAI;AACxC,UAAM,IAAI,IAAI;AACd,UAAM,IAAI,IAAI;AACd,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,UAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,KAAM,IAAI,IAAK,IAAI,CAAC,CAAC;AAC9D,WAAO,QAAQ,KAAK,KAAK,IAAI,IAAI;AACjC,WAAO,SAAS,KAAK,KAAK,IAAI,IAAI;AAClC,UAAM,MAAM,OAAO,WAAW,IAAI;AAClC,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,UAAU,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAChE,UAAM,EAAE,KAAA,IAAS,IAAI,aAAa,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AACnE,QAAI,MAAM;AACV,UAAM,IAAI,KAAK,SAAS;AACxB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,aAAO,UAAU,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;AAAA,IACpD;AACA,cAAI,UAAJ;AACA,WAAO,IAAI,IAAI,MAAM,IAAI;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,eAAsB,iBAAiB,KAAiB,YAAY,GAAqB;AACvF,QAAM,IAAI,MAAM,0BAA0B,GAAG;AAC7C,SAAO,IAAI;AACb;"}
@@ -1,19 +1,15 @@
1
1
  /**
2
2
  * @zendir/ui - 3D Components
3
3
  *
4
- * ZenSpace3D uses Cesium by default when installed (optional peer); falls back to Three.js.
5
- * Install `cesium` for the best globe/orbit experience; otherwise Three.js is used.
6
- *
7
- * Components:
8
- * - ZenSpace3D: Unified 3D space visualization (Cesium default, Three.js fallback)
9
- * - EarthViewer: Earth-focused 3D (Three.js, legacy)
10
- * - SolarSystemViewer: Solar system (Three.js, legacy)
4
+ * `ZenSpace3D` is the single canonical 3D viewer. Cesium is used when the
5
+ * peer dep is installed (production path); a Three.js renderer is used
6
+ * otherwise. Pair it with `useSimulationScene` for live-data integration.
11
7
  */
12
8
  export { ZenSpace3D, default as ZenSpace3DDefault } from './ZenSpace3D';
13
9
  export { ZenSpace3DCesium } from './ZenSpace3DCesium';
14
10
  export type { ZenSpace3DCesiumProps } from './ZenSpace3DCesium';
15
11
  export type { ZenSpace3DProps, ZenSpace3DHandle, ViewMode, CameraMode, ObjectCategory, SpaceObject, Satellite, Debris, SpaceStation, Asteroid, TLEData, OrbitPath, ManeuverNode, VisibilityCone, SatelliteCoverage, CoverageRegion, CoverageHexGrid, OverpassInfo, OrbitDesignArc, CoverageCell, TimeState, SelectionState, CameraState, LayerVisibility, ToolType, ToolState, Vector3D, LatLonAlt, SphericalCoords, SceneConfig, SceneObject, ZenSpace3DCallbacks, } from './ZenSpace3DTypes';
16
- export { latLonAltToCartesian, cartesianToLatLonAlt, cartesianToSpherical, sphericalToCartesian, eciToEcef, calculateGMST, dateToJulianDate, parseTLE, propagateSGP4Simple, propagateSatellite, generateOrbitPath, isVisible, calculateVisibilityConeGeometry, calculateFootprint, generateHexGrid, updateHexGridCoverage, dot, cross, magnitude, normalize, subtract, add, scale, distance, lerp, easeOutCubic, easeInOutCubic, smoothstep, lerpColor, hexToRgb, getGradientColor, formatDuration, formatDistance, formatVelocity, formatDateTime, EARTH_RADIUS_KM, EARTH_MU, AU_KM, DEG_TO_RAD, RAD_TO_DEG, J2000_EPOCH, SCENE_EARTH_RADIUS, KM_TO_SCENE, } from './ZenSpace3DUtils';
12
+ export { latLonAltToCartesian, easeOutCubic, EARTH_RADIUS_KM, DEG_TO_RAD, RAD_TO_DEG, SCENE_EARTH_RADIUS, KM_TO_SCENE, } from './ZenSpace3DUtils';
17
13
  export { atmosphereVertexShader, atmosphereFragmentShader, starsVertexShader, starsFragmentShader, coverageVertexShader, coverageFragmentShader, visibilityConeVertexShader, visibilityConeFragmentShader, orbitLineVertexShader, orbitLineFragmentShader, objectGlowVertexShader, objectGlowFragmentShader, selectionRingVertexShader, selectionRingFragmentShader, terminatorVertexShader, terminatorFragmentShader, gridVertexShader, gridFragmentShader, planetRingVertexShader, planetRingFragmentShader, debrisVertexShader, debrisFragmentShader, createAtmosphereUniforms, createStarsUniforms, createVisibilityConeUniforms, } from './ZenSpace3DShaders';
18
14
  export { createCesiumCaptureSource, ecefMetersToSdkPosition, eulerXyzToHpr, ecefEulerXyzToHpr, computeDofBlurPx } from './CesiumCaptureSource';
19
15
  export type { CesiumCaptureSourceOptions, CesiumCaptureSourceHandle } from './CesiumCaptureSource';
@@ -21,7 +17,5 @@ export type { CesiumCaptureSourceOptions, CesiumCaptureSourceHandle } from './Ce
21
17
  export { rgbToLuma, meanLuminanceFromPngBytes, isPngMostlyBlack } from './capturePngAnalysis';
22
18
  export { loadThree, isThreeLoaded } from './threeLoader';
23
19
  export type { ThreeModule, OrbitControlsType } from './threeLoader';
24
- export { EarthViewer } from './EarthViewer';
25
- export type { EarthViewerProps } from './EarthViewer';
26
- export { SolarSystemViewer } from './SolarSystemViewer';
27
- export type { SolarSystemViewerProps, PlanetPosition } from './SolarSystemViewer';
20
+ export { useSimulationScene } from '../hooks/useSimulationScene';
21
+ export type { CelestialBody, PositionTickDiag, SimulationSceneClient, SimulationSceneObject, StructureDiag, UseSimulationSceneOptions, UseSimulationSceneResult, } from '../hooks/useSimulationScene';
@@ -0,0 +1,57 @@
1
+ import { ZenSpace3D, ZenSpace3D as ZenSpace3D2 } from "./ZenSpace3D.js";
2
+ import { ZenSpace3DCesium } from "./ZenSpace3DCesium.js";
3
+ import { DEG_TO_RAD, EARTH_RADIUS_KM, KM_TO_SCENE, RAD_TO_DEG, SCENE_EARTH_RADIUS, easeOutCubic, latLonAltToCartesian } from "./ZenSpace3DUtils.js";
4
+ import { atmosphereFragmentShader, atmosphereVertexShader, coverageFragmentShader, coverageVertexShader, createAtmosphereUniforms, createStarsUniforms, createVisibilityConeUniforms, debrisFragmentShader, debrisVertexShader, gridFragmentShader, gridVertexShader, objectGlowFragmentShader, objectGlowVertexShader, orbitLineFragmentShader, orbitLineVertexShader, planetRingFragmentShader, planetRingVertexShader, selectionRingFragmentShader, selectionRingVertexShader, starsFragmentShader, starsVertexShader, terminatorFragmentShader, terminatorVertexShader, visibilityConeFragmentShader, visibilityConeVertexShader } from "./ZenSpace3DShaders.js";
5
+ import { computeDofBlurPx, createCesiumCaptureSource, ecefEulerXyzToHpr, ecefMetersToSdkPosition, eulerXyzToHpr } from "./CesiumCaptureSource.js";
6
+ import { isPngMostlyBlack, meanLuminanceFromPngBytes, rgbToLuma } from "./capturePngAnalysis.js";
7
+ import { isThreeLoaded, loadThree } from "./threeLoader.js";
8
+ import { useSimulationScene } from "../hooks/useSimulationScene.js";
9
+ export {
10
+ DEG_TO_RAD,
11
+ EARTH_RADIUS_KM,
12
+ KM_TO_SCENE,
13
+ RAD_TO_DEG,
14
+ SCENE_EARTH_RADIUS,
15
+ ZenSpace3D,
16
+ ZenSpace3DCesium,
17
+ ZenSpace3D2 as ZenSpace3DDefault,
18
+ atmosphereFragmentShader,
19
+ atmosphereVertexShader,
20
+ computeDofBlurPx,
21
+ coverageFragmentShader,
22
+ coverageVertexShader,
23
+ createAtmosphereUniforms,
24
+ createCesiumCaptureSource,
25
+ createStarsUniforms,
26
+ createVisibilityConeUniforms,
27
+ debrisFragmentShader,
28
+ debrisVertexShader,
29
+ easeOutCubic,
30
+ ecefEulerXyzToHpr,
31
+ ecefMetersToSdkPosition,
32
+ eulerXyzToHpr,
33
+ gridFragmentShader,
34
+ gridVertexShader,
35
+ isPngMostlyBlack,
36
+ isThreeLoaded,
37
+ latLonAltToCartesian,
38
+ loadThree,
39
+ meanLuminanceFromPngBytes,
40
+ objectGlowFragmentShader,
41
+ objectGlowVertexShader,
42
+ orbitLineFragmentShader,
43
+ orbitLineVertexShader,
44
+ planetRingFragmentShader,
45
+ planetRingVertexShader,
46
+ rgbToLuma,
47
+ selectionRingFragmentShader,
48
+ selectionRingVertexShader,
49
+ starsFragmentShader,
50
+ starsVertexShader,
51
+ terminatorFragmentShader,
52
+ terminatorVertexShader,
53
+ useSimulationScene,
54
+ visibilityConeFragmentShader,
55
+ visibilityConeVertexShader
56
+ };
57
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
@@ -0,0 +1,22 @@
1
+ let loadPromise = null;
2
+ async function loadThree() {
3
+ if (loadPromise) {
4
+ return loadPromise;
5
+ }
6
+ loadPromise = (async () => {
7
+ const [THREE, { OrbitControls }] = await Promise.all([
8
+ import("three"),
9
+ import("three/examples/jsm/controls/OrbitControls.js")
10
+ ]);
11
+ return { THREE, OrbitControls };
12
+ })();
13
+ return loadPromise;
14
+ }
15
+ function isThreeLoaded() {
16
+ return loadPromise !== null;
17
+ }
18
+ export {
19
+ isThreeLoaded,
20
+ loadThree
21
+ };
22
+ //# sourceMappingURL=threeLoader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threeLoader.js","sources":["../../../src/react/3d/threeLoader.ts"],"sourcesContent":["/**\r\n * Shared Three.js loader\r\n * \r\n * Ensures only one instance of Three.js is loaded across all 3D components.\r\n * This prevents the \"Multiple instances of Three.js being imported\" warning.\r\n */\r\n\r\nexport type ThreeModule = typeof import('three');\r\nexport type OrbitControlsType = typeof import('three/examples/jsm/controls/OrbitControls.js').OrbitControls;\r\n\r\ninterface ThreeLoaderResult {\r\n THREE: ThreeModule;\r\n OrbitControls: OrbitControlsType;\r\n}\r\n\r\n// Cached promise to ensure single load\r\nlet loadPromise: Promise<ThreeLoaderResult> | null = null;\r\n\r\n/**\r\n * Load Three.js and OrbitControls\r\n * Returns cached instance if already loaded\r\n */\r\nexport async function loadThree(): Promise<ThreeLoaderResult> {\r\n if (loadPromise) {\r\n return loadPromise;\r\n }\r\n\r\n loadPromise = (async () => {\r\n const [THREE, { OrbitControls }] = await Promise.all([\r\n import('three'),\r\n import('three/examples/jsm/controls/OrbitControls.js'),\r\n ]);\r\n \r\n return { THREE, OrbitControls };\r\n })();\r\n\r\n return loadPromise;\r\n}\r\n\r\n/**\r\n * Check if Three.js is already loaded\r\n */\r\nexport function isThreeLoaded(): boolean {\r\n return loadPromise !== null;\r\n}\r\n"],"names":[],"mappings":"AAgBA,IAAI,cAAiD;AAMrD,eAAsB,YAAwC;AAC5D,MAAI,aAAa;AACf,WAAO;AAAA,EACT;AAEA,iBAAe,YAAY;AACzB,UAAM,CAAC,OAAO,EAAE,cAAA,CAAe,IAAI,MAAM,QAAQ,IAAI;AAAA,MACnD,OAAO,OAAO;AAAA,MACd,OAAO,8CAA8C;AAAA,IAAA,CACtD;AAED,WAAO,EAAE,OAAO,cAAA;AAAA,EAClB,GAAA;AAEA,SAAO;AACT;AAKO,SAAS,gBAAyB;AACvC,SAAO,gBAAgB;AACzB;"}
@@ -1,7 +1,7 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { memo } from "react";
3
- import { classNames } from "../utils/index.js";
4
3
  import { useTheme } from "../theme/ThemeProvider.js";
4
+ import { classNames } from "../utils/index.js";
5
5
  const CLASSIFICATION_STYLES = {
6
6
  unclassified: {
7
7
  bg: "#007a33",
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { memo } from "react";
3
- import { safeAccentText, classNames } from "../utils/index.js";
4
3
  import { useTheme } from "../theme/ThemeProvider.js";
4
+ import { safeAccentText, classNames } from "../utils/index.js";
5
5
  const GlobalStatusBar = memo(function GlobalStatusBar2({
6
6
  appName = "Zendir",
7
7
  appDomain,
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { memo, useState, useMemo, useCallback, useEffect } from "react";
3
- import { tabularNumsStyle, classNames } from "../utils/index.js";
4
3
  import { useTheme } from "../theme/ThemeProvider.js";
4
+ import { tabularNumsStyle, classNames } from "../utils/index.js";
5
5
  function formatMET(ms, showMilliseconds = false) {
6
6
  const totalSeconds = Math.floor(Math.abs(ms) / 1e3);
7
7
  const days = Math.floor(totalSeconds / 86400);
@@ -342,7 +342,7 @@ const MissionClock = memo(function MissionClock2({
342
342
  }
343
343
  );
344
344
  });
345
- memo(function SimpleTimer2({
345
+ const SimpleTimer = memo(function SimpleTimer2({
346
346
  label,
347
347
  timestamp,
348
348
  direction = "countdown",
@@ -359,7 +359,7 @@ memo(function SimpleTimer2({
359
359
  const timer = { label, timestamp, direction, status, showDays };
360
360
  return /* @__PURE__ */ jsx("div", { className: classNames("zendir-simple-timer", className), children: /* @__PURE__ */ jsx(TimerDisplay, { timer, currentTime: now, tokens }) });
361
361
  });
362
- memo(function MissionElapsedTime2({
362
+ const MissionElapsedTime = memo(function MissionElapsedTime2({
363
363
  launchTime,
364
364
  showMilliseconds = false,
365
365
  className = "",
@@ -378,7 +378,7 @@ memo(function MissionElapsedTime2({
378
378
  }
379
379
  );
380
380
  });
381
- memo(function SimulationClock2({
381
+ const SimulationClock = memo(function SimulationClock2({
382
382
  epoch,
383
383
  elapsedSeconds = 0,
384
384
  timeScale = 1,
@@ -406,6 +406,9 @@ memo(function SimulationClock2({
406
406
  );
407
407
  });
408
408
  export {
409
- MissionClock
409
+ MissionClock,
410
+ MissionElapsedTime,
411
+ SimpleTimer,
412
+ SimulationClock
410
413
  };
411
414
  //# sourceMappingURL=MissionClock.js.map