matterviz 0.3.7 → 0.4.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 (486) hide show
  1. package/dist/Icon.svelte +7 -4
  2. package/dist/MillerIndexInput.svelte +1 -1
  3. package/dist/api/optimade.js +32 -26
  4. package/dist/app.css +0 -3
  5. package/dist/brillouin/BrillouinZone.svelte +76 -148
  6. package/dist/brillouin/BrillouinZone.svelte.d.ts +6 -14
  7. package/dist/brillouin/BrillouinZoneExportPane.svelte +43 -96
  8. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
  9. package/dist/brillouin/BrillouinZoneInfoPane.svelte +9 -32
  10. package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +2 -3
  11. package/dist/brillouin/BrillouinZoneScene.svelte +97 -205
  12. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +4 -23
  13. package/dist/brillouin/BrillouinZoneTooltip.svelte +16 -25
  14. package/dist/brillouin/ReciprocalVectors.svelte +39 -0
  15. package/dist/brillouin/ReciprocalVectors.svelte.d.ts +9 -0
  16. package/dist/brillouin/compute.d.ts +2 -0
  17. package/dist/brillouin/compute.js +89 -90
  18. package/dist/brillouin/geometry.d.ts +8 -0
  19. package/dist/brillouin/geometry.js +57 -0
  20. package/dist/brillouin/index.d.ts +2 -0
  21. package/dist/brillouin/index.js +2 -0
  22. package/dist/brillouin/types.d.ts +2 -2
  23. package/dist/chempot-diagram/ChemPotDiagram.svelte +14 -13
  24. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +1 -1
  25. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +109 -203
  26. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +4 -1
  27. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +180 -470
  28. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +7 -1
  29. package/dist/chempot-diagram/async-compute.svelte.js +3 -1
  30. package/dist/chempot-diagram/chempot-worker.js +2 -1
  31. package/dist/chempot-diagram/color.d.ts +3 -6
  32. package/dist/chempot-diagram/color.js +5 -5
  33. package/dist/chempot-diagram/compute.d.ts +4 -4
  34. package/dist/chempot-diagram/compute.js +20 -20
  35. package/dist/chempot-diagram/controls-state.svelte.d.ts +10 -0
  36. package/dist/chempot-diagram/controls-state.svelte.js +42 -0
  37. package/dist/chempot-diagram/export.d.ts +47 -0
  38. package/dist/chempot-diagram/export.js +133 -0
  39. package/dist/chempot-diagram/index.d.ts +1 -0
  40. package/dist/chempot-diagram/index.js +1 -0
  41. package/dist/chempot-diagram/pointer.d.ts +0 -10
  42. package/dist/chempot-diagram/pointer.js +4 -4
  43. package/dist/chempot-diagram/types.d.ts +3 -3
  44. package/dist/colors/index.js +8 -7
  45. package/dist/composition/FormulaFilter.svelte +18 -11
  46. package/dist/composition/PieChart.svelte +11 -10
  47. package/dist/composition/chem-sys.d.ts +8 -0
  48. package/dist/composition/chem-sys.js +86 -0
  49. package/dist/composition/format.js +7 -4
  50. package/dist/composition/index.d.ts +1 -0
  51. package/dist/composition/index.js +1 -0
  52. package/dist/composition/parse.d.ts +0 -1
  53. package/dist/composition/parse.js +41 -31
  54. package/dist/controls.d.ts +1 -0
  55. package/dist/controls.js +0 -1
  56. package/dist/convex-hull/ConvexHull.svelte +8 -10
  57. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -4
  58. package/dist/convex-hull/ConvexHull2D.svelte +106 -185
  59. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  60. package/dist/convex-hull/ConvexHull3D.svelte +179 -683
  61. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  62. package/dist/convex-hull/ConvexHull4D.svelte +183 -687
  63. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  64. package/dist/convex-hull/ConvexHullChrome.svelte +268 -0
  65. package/dist/convex-hull/ConvexHullChrome.svelte.d.ts +30 -0
  66. package/dist/convex-hull/ConvexHullControls.svelte +88 -7
  67. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +7 -6
  68. package/dist/convex-hull/ConvexHullInfoPane.svelte +18 -5
  69. package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +6 -5
  70. package/dist/convex-hull/ConvexHullStats.svelte +36 -175
  71. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +3 -1
  72. package/dist/convex-hull/ConvexHullTooltip.svelte +11 -2
  73. package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +2 -1
  74. package/dist/convex-hull/GasPressureControls.svelte +4 -4
  75. package/dist/convex-hull/TemperatureSlider.svelte +2 -2
  76. package/dist/convex-hull/barycentric-coords.d.ts +2 -4
  77. package/dist/convex-hull/barycentric-coords.js +6 -33
  78. package/dist/convex-hull/canvas-interactions.svelte.d.ts +79 -0
  79. package/dist/convex-hull/canvas-interactions.svelte.js +278 -0
  80. package/dist/convex-hull/demo-temperature.d.ts +1 -1
  81. package/dist/convex-hull/demo-temperature.js +20 -22
  82. package/dist/convex-hull/gas-thermodynamics.d.ts +2 -2
  83. package/dist/convex-hull/gas-thermodynamics.js +22 -30
  84. package/dist/convex-hull/helpers.d.ts +42 -7
  85. package/dist/convex-hull/helpers.js +171 -78
  86. package/dist/convex-hull/hull-state.svelte.d.ts +44 -0
  87. package/dist/convex-hull/hull-state.svelte.js +124 -0
  88. package/dist/convex-hull/index.d.ts +10 -8
  89. package/dist/convex-hull/index.js +7 -2
  90. package/dist/convex-hull/thermodynamics.js +136 -960
  91. package/dist/convex-hull/types.d.ts +13 -5
  92. package/dist/convex-hull/types.js +12 -0
  93. package/dist/coordination/CoordinationBarPlot.svelte +27 -34
  94. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
  95. package/dist/element/BohrAtom.svelte +2 -1
  96. package/dist/element/index.d.ts +4 -0
  97. package/dist/element/index.js +18 -0
  98. package/dist/feedback/DragOverlay.svelte +3 -1
  99. package/dist/feedback/DragOverlay.svelte.d.ts +1 -0
  100. package/dist/feedback/StatusMessage.svelte +13 -3
  101. package/dist/fermi-surface/FermiSlice.svelte +13 -5
  102. package/dist/fermi-surface/FermiSurface.svelte +78 -151
  103. package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -14
  104. package/dist/fermi-surface/FermiSurfaceControls.svelte +1 -1
  105. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  106. package/dist/fermi-surface/FermiSurfaceScene.svelte +72 -221
  107. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +3 -23
  108. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +8 -34
  109. package/dist/fermi-surface/compute.js +67 -66
  110. package/dist/fermi-surface/export.js +6 -16
  111. package/dist/fermi-surface/index.d.ts +0 -1
  112. package/dist/fermi-surface/index.js +0 -1
  113. package/dist/fermi-surface/parse.d.ts +1 -1
  114. package/dist/fermi-surface/parse.js +71 -79
  115. package/dist/fermi-surface/types.d.ts +3 -2
  116. package/dist/heatmap-matrix/HeatmapMatrix.svelte +69 -52
  117. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +4 -3
  118. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +3 -2
  119. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +5 -5
  120. package/dist/heatmap-matrix/index.d.ts +3 -2
  121. package/dist/heatmap-matrix/index.js +1 -1
  122. package/dist/index.d.ts +1 -0
  123. package/dist/index.js +1 -0
  124. package/dist/io/ExportPane.svelte +166 -0
  125. package/dist/io/ExportPane.svelte.d.ts +17 -0
  126. package/dist/io/decompress.js +5 -4
  127. package/dist/io/export.d.ts +9 -5
  128. package/dist/io/export.js +77 -51
  129. package/dist/io/fetch.d.ts +2 -1
  130. package/dist/io/fetch.js +5 -1
  131. package/dist/io/file-drop.d.ts +8 -1
  132. package/dist/io/file-drop.js +48 -36
  133. package/dist/io/index.d.ts +2 -0
  134. package/dist/io/index.js +10 -0
  135. package/dist/io/types.d.ts +13 -0
  136. package/dist/io/url-drop.js +64 -33
  137. package/dist/isosurface/parse.js +52 -51
  138. package/dist/isosurface/slice.js +5 -4
  139. package/dist/isosurface/types.js +1 -1
  140. package/dist/keyboard.d.ts +3 -0
  141. package/dist/keyboard.js +23 -0
  142. package/dist/labels.d.ts +1 -1
  143. package/dist/labels.js +9 -8
  144. package/dist/layout/FullscreenButton.svelte +33 -0
  145. package/dist/layout/FullscreenButton.svelte.d.ts +10 -0
  146. package/dist/layout/FullscreenToggle.svelte +8 -14
  147. package/dist/layout/PropertyFilter.svelte +3 -2
  148. package/dist/layout/SettingsSection.svelte +1 -1
  149. package/dist/layout/ViewerChrome.svelte +116 -0
  150. package/dist/layout/ViewerChrome.svelte.d.ts +17 -0
  151. package/dist/layout/fullscreen.d.ts +4 -0
  152. package/dist/layout/fullscreen.svelte.d.ts +8 -0
  153. package/dist/layout/fullscreen.svelte.js +37 -0
  154. package/dist/layout/index.d.ts +3 -0
  155. package/dist/layout/index.js +3 -0
  156. package/dist/layout/json-tree/JsonNode.svelte +1 -1
  157. package/dist/layout/json-tree/JsonTree.svelte +2 -2
  158. package/dist/layout/json-tree/utils.js +5 -4
  159. package/dist/marching-cubes.js +8 -13
  160. package/dist/math.d.ts +12 -4
  161. package/dist/math.js +42 -30
  162. package/dist/overlays/DraggablePane.svelte +4 -4
  163. package/dist/overlays/index.d.ts +4 -0
  164. package/dist/periodic-table/PeriodicTable.svelte +27 -15
  165. package/dist/periodic-table/PropertySelect.svelte +1 -0
  166. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +9 -3
  167. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
  168. package/dist/phase-diagram/PhaseDiagramControls.svelte +3 -2
  169. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +4 -3
  170. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +4 -2
  171. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +2 -3
  172. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +47 -132
  173. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +3 -4
  174. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +1 -1
  175. package/dist/phase-diagram/build-diagram.js +2 -2
  176. package/dist/phase-diagram/colors.js +1 -1
  177. package/dist/phase-diagram/parse.d.ts +2 -1
  178. package/dist/phase-diagram/parse.js +6 -5
  179. package/dist/phase-diagram/types.d.ts +1 -1
  180. package/dist/phase-diagram/utils.d.ts +3 -3
  181. package/dist/phase-diagram/utils.js +8 -12
  182. package/dist/plot/{BarPlot.svelte → bar/BarPlot.svelte} +246 -841
  183. package/dist/plot/{BarPlot.svelte.d.ts → bar/BarPlot.svelte.d.ts} +8 -16
  184. package/dist/plot/{BarPlotControls.svelte → bar/BarPlotControls.svelte} +6 -5
  185. package/dist/plot/{BarPlotControls.svelte.d.ts → bar/BarPlotControls.svelte.d.ts} +3 -3
  186. package/dist/plot/{SpacegroupBarPlot.svelte → bar/SpacegroupBarPlot.svelte} +8 -7
  187. package/dist/plot/{SpacegroupBarPlot.svelte.d.ts → bar/SpacegroupBarPlot.svelte.d.ts} +1 -1
  188. package/dist/plot/bar/data.d.ts +40 -0
  189. package/dist/plot/bar/data.js +154 -0
  190. package/dist/plot/bar/geometry.d.ts +39 -0
  191. package/dist/plot/bar/geometry.js +60 -0
  192. package/dist/plot/bar/index.d.ts +3 -0
  193. package/dist/plot/bar/index.js +3 -0
  194. package/dist/plot/box/BoxPlot.svelte +1292 -0
  195. package/dist/plot/box/BoxPlot.svelte.d.ts +95 -0
  196. package/dist/plot/box/BoxPlotControls.svelte +109 -0
  197. package/dist/plot/box/BoxPlotControls.svelte.d.ts +19 -0
  198. package/dist/plot/box/Violin.svelte +14 -0
  199. package/dist/plot/box/Violin.svelte.d.ts +70 -0
  200. package/dist/plot/box/box-plot.d.ts +56 -0
  201. package/dist/plot/box/box-plot.js +129 -0
  202. package/dist/plot/box/index.d.ts +5 -0
  203. package/dist/plot/box/index.js +5 -0
  204. package/dist/plot/box/kde.d.ts +17 -0
  205. package/dist/plot/box/kde.js +160 -0
  206. package/dist/plot/box/quantile.d.ts +3 -0
  207. package/dist/plot/box/quantile.js +53 -0
  208. package/dist/plot/{auto-place.d.ts → core/auto-place.d.ts} +1 -1
  209. package/dist/plot/{auto-place.js → core/auto-place.js} +6 -3
  210. package/dist/plot/core/axis-utils.d.ts +46 -0
  211. package/dist/plot/core/axis-utils.js +110 -0
  212. package/dist/plot/{AxisLabel.svelte → core/components/AxisLabel.svelte} +2 -2
  213. package/dist/plot/{AxisLabel.svelte.d.ts → core/components/AxisLabel.svelte.d.ts} +1 -1
  214. package/dist/plot/{ColorBar.svelte → core/components/ColorBar.svelte} +41 -38
  215. package/dist/plot/{ColorBar.svelte.d.ts → core/components/ColorBar.svelte.d.ts} +7 -6
  216. package/dist/plot/{ColorScaleSelect.svelte → core/components/ColorScaleSelect.svelte} +4 -3
  217. package/dist/plot/{ColorScaleSelect.svelte.d.ts → core/components/ColorScaleSelect.svelte.d.ts} +2 -2
  218. package/dist/plot/core/components/ControlPane.svelte +46 -0
  219. package/dist/plot/core/components/ControlPane.svelte.d.ts +13 -0
  220. package/dist/plot/{FillArea.svelte → core/components/FillArea.svelte} +17 -6
  221. package/dist/plot/{FillArea.svelte.d.ts → core/components/FillArea.svelte.d.ts} +1 -1
  222. package/dist/plot/{InteractiveAxisLabel.svelte → core/components/InteractiveAxisLabel.svelte} +3 -3
  223. package/dist/plot/{InteractiveAxisLabel.svelte.d.ts → core/components/InteractiveAxisLabel.svelte.d.ts} +2 -2
  224. package/dist/plot/{Line.svelte → core/components/Line.svelte} +33 -15
  225. package/dist/plot/{Line.svelte.d.ts → core/components/Line.svelte.d.ts} +3 -2
  226. package/dist/plot/{PlotAxis.svelte → core/components/PlotAxis.svelte} +9 -6
  227. package/dist/plot/{PlotAxis.svelte.d.ts → core/components/PlotAxis.svelte.d.ts} +5 -3
  228. package/dist/plot/{PlotControls.svelte → core/components/PlotControls.svelte} +17 -29
  229. package/dist/plot/core/components/PlotControls.svelte.d.ts +4 -0
  230. package/dist/plot/{PlotLegend.svelte → core/components/PlotLegend.svelte} +21 -10
  231. package/dist/plot/{PlotLegend.svelte.d.ts → core/components/PlotLegend.svelte.d.ts} +3 -2
  232. package/dist/plot/{PlotTooltip.svelte → core/components/PlotTooltip.svelte} +17 -1
  233. package/dist/plot/{PlotTooltip.svelte.d.ts → core/components/PlotTooltip.svelte.d.ts} +8 -0
  234. package/dist/plot/{PortalSelect.svelte → core/components/PortalSelect.svelte} +11 -7
  235. package/dist/plot/{ReferenceLine.svelte → core/components/ReferenceLine.svelte} +3 -3
  236. package/dist/plot/{ReferenceLine.svelte.d.ts → core/components/ReferenceLine.svelte.d.ts} +1 -1
  237. package/dist/plot/{ReferenceLine3D.svelte → core/components/ReferenceLine3D.svelte} +5 -5
  238. package/dist/plot/{ReferenceLine3D.svelte.d.ts → core/components/ReferenceLine3D.svelte.d.ts} +5 -5
  239. package/dist/plot/{ReferencePlane.svelte → core/components/ReferencePlane.svelte} +8 -8
  240. package/dist/plot/{ReferencePlane.svelte.d.ts → core/components/ReferencePlane.svelte.d.ts} +5 -5
  241. package/dist/plot/{ZeroLines.svelte → core/components/ZeroLines.svelte} +3 -3
  242. package/dist/plot/{ZeroLines.svelte.d.ts → core/components/ZeroLines.svelte.d.ts} +3 -3
  243. package/dist/plot/{ZoomRect.svelte → core/components/ZoomRect.svelte} +1 -1
  244. package/dist/plot/{ZoomRect.svelte.d.ts → core/components/ZoomRect.svelte.d.ts} +1 -1
  245. package/dist/plot/core/components/index.d.ts +17 -0
  246. package/dist/plot/core/components/index.js +17 -0
  247. package/dist/plot/{data-cleaning.d.ts → core/data-cleaning.d.ts} +71 -1
  248. package/dist/plot/{data-cleaning.js → core/data-cleaning.js} +21 -23
  249. package/dist/plot/{data-transform.d.ts → core/data-transform.d.ts} +2 -2
  250. package/dist/plot/{data-transform.js → core/data-transform.js} +3 -3
  251. package/dist/plot/core/fill-utils.d.ts +34 -0
  252. package/dist/plot/core/fill-utils.js +391 -0
  253. package/dist/plot/core/index.d.ts +10 -0
  254. package/dist/plot/core/index.js +11 -0
  255. package/dist/plot/core/interactions.d.ts +39 -0
  256. package/dist/plot/core/interactions.js +209 -0
  257. package/dist/plot/{layout.d.ts → core/layout.d.ts} +1 -0
  258. package/dist/plot/{layout.js → core/layout.js} +16 -8
  259. package/dist/plot/core/pan-zoom.svelte.d.ts +35 -0
  260. package/dist/plot/core/pan-zoom.svelte.js +221 -0
  261. package/dist/plot/core/placed-tween.svelte.d.ts +21 -0
  262. package/dist/plot/core/placed-tween.svelte.js +68 -0
  263. package/dist/plot/{reference-line.d.ts → core/reference-line.d.ts} +11 -11
  264. package/dist/plot/{reference-line.js → core/reference-line.js} +29 -42
  265. package/dist/plot/core/scales.d.ts +40 -0
  266. package/dist/plot/{scales.js → core/scales.js} +94 -93
  267. package/dist/plot/core/svg.d.ts +3 -0
  268. package/dist/plot/core/svg.js +41 -0
  269. package/dist/plot/{types.d.ts → core/types.d.ts} +36 -85
  270. package/dist/plot/{types.js → core/types.js} +1 -1
  271. package/dist/plot/{utils → core/utils}/label-placement.d.ts +3 -3
  272. package/dist/plot/{utils → core/utils}/label-placement.js +3 -3
  273. package/dist/plot/core/utils/series-visibility.d.ts +26 -0
  274. package/dist/plot/{utils → core/utils}/series-visibility.js +29 -2
  275. package/dist/plot/core/utils.d.ts +12 -0
  276. package/dist/plot/core/utils.js +27 -0
  277. package/dist/plot/{Histogram.svelte → histogram/Histogram.svelte} +174 -551
  278. package/dist/plot/{Histogram.svelte.d.ts → histogram/Histogram.svelte.d.ts} +2 -2
  279. package/dist/plot/{HistogramControls.svelte → histogram/HistogramControls.svelte} +6 -6
  280. package/dist/plot/{HistogramControls.svelte.d.ts → histogram/HistogramControls.svelte.d.ts} +4 -4
  281. package/dist/plot/histogram/index.d.ts +2 -0
  282. package/dist/plot/histogram/index.js +2 -0
  283. package/dist/plot/index.d.ts +8 -41
  284. package/dist/plot/index.js +10 -39
  285. package/dist/plot/sankey/Sankey.svelte +697 -0
  286. package/dist/plot/sankey/Sankey.svelte.d.ts +74 -0
  287. package/dist/plot/sankey/SankeyControls.svelte +98 -0
  288. package/dist/plot/sankey/SankeyControls.svelte.d.ts +19 -0
  289. package/dist/plot/sankey/index.d.ts +4 -0
  290. package/dist/plot/sankey/index.js +3 -0
  291. package/dist/plot/sankey/sankey-types.d.ts +42 -0
  292. package/dist/plot/sankey/sankey-types.js +4 -0
  293. package/dist/plot/sankey/sankey.d.ts +52 -0
  294. package/dist/plot/sankey/sankey.js +189 -0
  295. package/dist/plot/{BinnedScatterPlot.svelte → scatter/BinnedScatterPlot.svelte} +64 -64
  296. package/dist/plot/{BinnedScatterPlot.svelte.d.ts → scatter/BinnedScatterPlot.svelte.d.ts} +6 -6
  297. package/dist/plot/{ElementScatter.svelte → scatter/ElementScatter.svelte} +6 -6
  298. package/dist/plot/{ElementScatter.svelte.d.ts → scatter/ElementScatter.svelte.d.ts} +2 -2
  299. package/dist/plot/{ScatterPlot.svelte → scatter/ScatterPlot.svelte} +297 -1008
  300. package/dist/plot/{ScatterPlot.svelte.d.ts → scatter/ScatterPlot.svelte.d.ts} +10 -18
  301. package/dist/plot/{ScatterPlotControls.svelte → scatter/ScatterPlotControls.svelte} +6 -5
  302. package/dist/plot/{ScatterPlotControls.svelte.d.ts → scatter/ScatterPlotControls.svelte.d.ts} +2 -2
  303. package/dist/plot/{ScatterPoint.svelte → scatter/ScatterPoint.svelte} +7 -7
  304. package/dist/plot/{ScatterPoint.svelte.d.ts → scatter/ScatterPoint.svelte.d.ts} +3 -3
  305. package/dist/plot/{adaptive-density.d.ts → scatter/adaptive-density.d.ts} +14 -4
  306. package/dist/plot/{adaptive-density.js → scatter/adaptive-density.js} +46 -20
  307. package/dist/plot/{binned-scatter-types.d.ts → scatter/binned-scatter-types.d.ts} +5 -12
  308. package/dist/plot/scatter/index.d.ts +7 -0
  309. package/dist/plot/scatter/index.js +5 -0
  310. package/dist/plot/scatter/scatter-data.d.ts +19 -0
  311. package/dist/plot/scatter/scatter-data.js +212 -0
  312. package/dist/plot/{ScatterPlot3D.svelte → scatter-3d/ScatterPlot3D.svelte} +25 -34
  313. package/dist/plot/{ScatterPlot3D.svelte.d.ts → scatter-3d/ScatterPlot3D.svelte.d.ts} +9 -17
  314. package/dist/plot/{ScatterPlot3DControls.svelte → scatter-3d/ScatterPlot3DControls.svelte} +14 -14
  315. package/dist/plot/{ScatterPlot3DControls.svelte.d.ts → scatter-3d/ScatterPlot3DControls.svelte.d.ts} +6 -6
  316. package/dist/plot/{ScatterPlot3DScene.svelte → scatter-3d/ScatterPlot3DScene.svelte} +129 -128
  317. package/dist/plot/{ScatterPlot3DScene.svelte.d.ts → scatter-3d/ScatterPlot3DScene.svelte.d.ts} +6 -15
  318. package/dist/plot/{Surface3D.svelte → scatter-3d/Surface3D.svelte} +7 -6
  319. package/dist/plot/{Surface3D.svelte.d.ts → scatter-3d/Surface3D.svelte.d.ts} +5 -4
  320. package/dist/plot/scatter-3d/index.d.ts +4 -0
  321. package/dist/plot/scatter-3d/index.js +4 -0
  322. package/dist/plot/sunburst/Sunburst.svelte +1041 -0
  323. package/dist/plot/sunburst/Sunburst.svelte.d.ts +97 -0
  324. package/dist/plot/sunburst/SunburstControls.svelte +200 -0
  325. package/dist/plot/sunburst/SunburstControls.svelte.d.ts +26 -0
  326. package/dist/plot/sunburst/index.d.ts +4 -0
  327. package/dist/plot/sunburst/index.js +4 -0
  328. package/dist/plot/sunburst/render.d.ts +34 -0
  329. package/dist/plot/sunburst/render.js +122 -0
  330. package/dist/plot/sunburst/sunburst.d.ts +62 -0
  331. package/dist/plot/sunburst/sunburst.js +269 -0
  332. package/dist/rdf/RdfPlot.svelte +2 -1
  333. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  334. package/dist/rdf/calc-rdf.js +11 -24
  335. package/dist/sanitize.js +14 -3
  336. package/dist/scene/SceneCamera.svelte +62 -0
  337. package/dist/scene/SceneCamera.svelte.d.ts +19 -0
  338. package/dist/scene/bind-renderer.svelte.d.ts +2 -0
  339. package/dist/scene/bind-renderer.svelte.js +14 -0
  340. package/dist/scene/index.d.ts +4 -0
  341. package/dist/scene/index.js +5 -0
  342. package/dist/scene/props.js +52 -0
  343. package/dist/scene/types.d.ts +26 -0
  344. package/dist/scene/types.js +1 -0
  345. package/dist/settings.d.ts +79 -3
  346. package/dist/settings.js +321 -1
  347. package/dist/spectral/Bands.svelte +47 -36
  348. package/dist/spectral/Bands.svelte.d.ts +6 -6
  349. package/dist/spectral/BandsAndDos.svelte +23 -25
  350. package/dist/spectral/BrillouinBandsDos.svelte +42 -30
  351. package/dist/spectral/Dos.svelte +15 -23
  352. package/dist/spectral/Dos.svelte.d.ts +4 -3
  353. package/dist/spectral/helpers.d.ts +8 -6
  354. package/dist/spectral/helpers.js +137 -65
  355. package/dist/state.svelte.d.ts +0 -7
  356. package/dist/state.svelte.js +0 -6
  357. package/dist/structure/Arrow.svelte +2 -4
  358. package/dist/structure/AtomLegend.svelte +8 -9
  359. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  360. package/dist/structure/CanvasTooltip.svelte +1 -0
  361. package/dist/structure/CellSelect.svelte +12 -5
  362. package/dist/structure/CellSelect.svelte.d.ts +2 -1
  363. package/dist/structure/Cylinder.svelte +12 -8
  364. package/dist/structure/Cylinder.svelte.d.ts +4 -1
  365. package/dist/structure/Lattice.svelte +2 -2
  366. package/dist/structure/Structure.svelte +365 -423
  367. package/dist/structure/Structure.svelte.d.ts +5 -15
  368. package/dist/structure/StructureControls.svelte +217 -2
  369. package/dist/structure/StructureControls.svelte.d.ts +5 -3
  370. package/dist/structure/StructureExportPane.svelte +54 -156
  371. package/dist/structure/StructureExportPane.svelte.d.ts +4 -5
  372. package/dist/structure/StructureInfoPane.svelte +10 -9
  373. package/dist/structure/StructureInfoPane.svelte.d.ts +5 -5
  374. package/dist/structure/StructureScene.svelte +376 -208
  375. package/dist/structure/StructureScene.svelte.d.ts +22 -20
  376. package/dist/structure/{label-placement.d.ts → atom-label-placement.d.ts} +3 -3
  377. package/dist/structure/{label-placement.js → atom-label-placement.js} +15 -5
  378. package/dist/structure/atom-properties.d.ts +1 -1
  379. package/dist/structure/atom-properties.js +17 -22
  380. package/dist/structure/bond-order-perception.js +3 -5
  381. package/dist/structure/bonding.d.ts +4 -0
  382. package/dist/structure/bonding.js +134 -63
  383. package/dist/structure/export.d.ts +24 -4
  384. package/dist/structure/export.js +89 -143
  385. package/dist/structure/index.d.ts +4 -4
  386. package/dist/structure/index.js +3 -3
  387. package/dist/structure/measure.d.ts +3 -2
  388. package/dist/structure/measure.js +6 -5
  389. package/dist/structure/parse.d.ts +3 -2
  390. package/dist/structure/parse.js +419 -438
  391. package/dist/structure/partial-occupancy.d.ts +0 -1
  392. package/dist/structure/partial-occupancy.js +1 -1
  393. package/dist/structure/pbc.d.ts +1 -1
  394. package/dist/structure/pbc.js +190 -13
  395. package/dist/structure/polyhedra.d.ts +41 -0
  396. package/dist/structure/polyhedra.js +602 -0
  397. package/dist/structure/site.d.ts +4 -0
  398. package/dist/structure/site.js +1 -0
  399. package/dist/structure/supercell.js +3 -2
  400. package/dist/structure/validation.js +5 -6
  401. package/dist/symmetry/SymmetryElementControls.svelte +69 -0
  402. package/dist/symmetry/SymmetryElementControls.svelte.d.ts +9 -0
  403. package/dist/symmetry/SymmetryElements.svelte +354 -0
  404. package/dist/symmetry/SymmetryElements.svelte.d.ts +24 -0
  405. package/dist/symmetry/SymmetryStats.svelte +113 -8
  406. package/dist/symmetry/WyckoffTable.svelte +68 -7
  407. package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -0
  408. package/dist/symmetry/cell-transform.js +7 -14
  409. package/dist/symmetry/index.d.ts +14 -4
  410. package/dist/symmetry/index.js +291 -72
  411. package/dist/symmetry/spacegroups.d.ts +12 -1
  412. package/dist/symmetry/spacegroups.js +63 -14
  413. package/dist/symmetry/symmetry-elements.d.ts +33 -0
  414. package/dist/symmetry/symmetry-elements.js +521 -0
  415. package/dist/symmetry/wyckoff-db.d.ts +9 -0
  416. package/dist/symmetry/wyckoff-db.js +87 -0
  417. package/dist/table/HeatmapTable.svelte +66 -25
  418. package/dist/table/HeatmapTable.svelte.d.ts +1 -1
  419. package/dist/table/index.d.ts +1 -3
  420. package/dist/table/index.js +1 -1
  421. package/dist/theme/index.js +8 -8
  422. package/dist/tooltip/KCoords.svelte +45 -0
  423. package/dist/tooltip/KCoords.svelte.d.ts +8 -0
  424. package/dist/tooltip/index.d.ts +1 -0
  425. package/dist/tooltip/index.js +1 -0
  426. package/dist/trajectory/Trajectory.svelte +123 -100
  427. package/dist/trajectory/Trajectory.svelte.d.ts +11 -22
  428. package/dist/trajectory/TrajectoryExportPane.svelte +17 -25
  429. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +4 -5
  430. package/dist/trajectory/TrajectoryInfoPane.svelte +5 -3
  431. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -2
  432. package/dist/trajectory/constants.js +6 -2
  433. package/dist/trajectory/extract.js +17 -37
  434. package/dist/trajectory/format-detect.d.ts +1 -1
  435. package/dist/trajectory/format-detect.js +27 -19
  436. package/dist/trajectory/frame-reader.d.ts +0 -1
  437. package/dist/trajectory/frame-reader.js +63 -162
  438. package/dist/trajectory/helpers.d.ts +10 -2
  439. package/dist/trajectory/helpers.js +56 -36
  440. package/dist/trajectory/index.js +1 -1
  441. package/dist/trajectory/parse/ase.d.ts +9 -1
  442. package/dist/trajectory/parse/ase.js +47 -32
  443. package/dist/trajectory/parse/diagnostics.d.ts +3 -0
  444. package/dist/trajectory/parse/diagnostics.js +14 -0
  445. package/dist/trajectory/parse/hdf5.js +1 -1
  446. package/dist/trajectory/parse/index.d.ts +1 -1
  447. package/dist/trajectory/parse/index.js +65 -105
  448. package/dist/trajectory/parse/lammps.d.ts +0 -2
  449. package/dist/trajectory/parse/lammps.js +8 -6
  450. package/dist/trajectory/parse/pymatgen.d.ts +2 -0
  451. package/dist/trajectory/parse/pymatgen.js +74 -0
  452. package/dist/trajectory/parse/vasp.js +38 -18
  453. package/dist/trajectory/parse/xyz.d.ts +13 -1
  454. package/dist/trajectory/parse/xyz.js +102 -94
  455. package/dist/trajectory/plotting.d.ts +1 -2
  456. package/dist/trajectory/plotting.js +16 -113
  457. package/dist/utils.d.ts +2 -0
  458. package/dist/utils.js +7 -5
  459. package/dist/xrd/XrdPlot.svelte +16 -30
  460. package/dist/xrd/broadening.d.ts +2 -1
  461. package/dist/xrd/calc-xrd.js +18 -20
  462. package/dist/xrd/index.d.ts +2 -2
  463. package/dist/xrd/parse.js +2 -2
  464. package/package.json +43 -26
  465. package/dist/element/data.json +0 -11864
  466. package/dist/fermi-surface/marching-cubes.d.ts +0 -2
  467. package/dist/fermi-surface/marching-cubes.js +0 -2
  468. package/dist/plot/PlotControls.svelte.d.ts +0 -4
  469. package/dist/plot/axis-utils.d.ts +0 -19
  470. package/dist/plot/axis-utils.js +0 -78
  471. package/dist/plot/defaults.d.ts +0 -19
  472. package/dist/plot/defaults.js +0 -9
  473. package/dist/plot/fill-utils.d.ts +0 -46
  474. package/dist/plot/fill-utils.js +0 -322
  475. package/dist/plot/hover-lock.svelte.d.ts +0 -14
  476. package/dist/plot/hover-lock.svelte.js +0 -46
  477. package/dist/plot/interactions.d.ts +0 -12
  478. package/dist/plot/interactions.js +0 -101
  479. package/dist/plot/scales.d.ts +0 -48
  480. package/dist/plot/svg.d.ts +0 -1
  481. package/dist/plot/svg.js +0 -11
  482. package/dist/plot/utils/series-visibility.d.ts +0 -15
  483. package/dist/plot/utils.d.ts +0 -1
  484. package/dist/plot/utils.js +0 -14
  485. /package/dist/plot/{PortalSelect.svelte.d.ts → core/components/PortalSelect.svelte.d.ts} +0 -0
  486. /package/dist/plot/{binned-scatter-types.js → scatter/binned-scatter-types.js} +0 -0
package/dist/io/export.js CHANGED
@@ -1,28 +1,21 @@
1
1
  import { download } from './fetch';
2
2
  import { create_structure_filename } from '../structure/export';
3
+ import { to_error } from '../utils';
3
4
  import { Vector2 } from 'three';
4
- function is_webgl_renderer_like(value) {
5
- if (typeof value !== `object` || !value)
6
- return false;
7
- const renderer_obj = value;
8
- return (typeof renderer_obj.render === `function` &&
9
- typeof renderer_obj.getPixelRatio === `function` &&
10
- typeof renderer_obj.setPixelRatio === `function` &&
11
- typeof renderer_obj.getSize === `function` &&
12
- typeof renderer_obj.setSize === `function`);
13
- }
14
- function get_canvas_renderer(canvas) {
15
- const renderer_val = canvas[`__renderer`];
16
- return is_webgl_renderer_like(renderer_val) ? renderer_val : undefined;
17
- }
5
+ // Maps a Threlte canvas to its WebGLRenderer so PNG export can look up the renderer for a
6
+ // given canvas without mutating the DOM element. Populated by bind_renderer (scene/).
7
+ export const renderer_registry = new WeakMap();
8
+ // PNG DPI -> render scale relative to the 72 DPI baseline, capped at 10x. DPI floors
9
+ // at 1 (non-finite -> 72) so bad inputs can't yield 0x0 canvases or NaN pixel ratios.
10
+ export const dpi_to_scale = (png_dpi) => Math.min(Math.max(1, Number.isFinite(png_dpi) ? png_dpi : 72) / 72, 10);
18
11
  // Capture a WebGL canvas as a PNG Blob at the given DPI.
19
12
  // Temporarily adjusts renderer pixel ratio for high-res capture, then restores.
20
13
  // Returns data directly (no browser download), suitable for programmatic capture
21
14
  // in test suites, server-side rendering, or Python widget integration via anywidget.
22
15
  // DPI is converted to a resolution multiplier relative to 72 DPI baseline, capped at 10x.
23
16
  export function canvas_to_png_blob(canvas, png_dpi = 150, scene = null, camera = null) {
24
- const resolution_multiplier = Math.min(png_dpi / 72, 10);
25
- const renderer = get_canvas_renderer(canvas);
17
+ const resolution_multiplier = dpi_to_scale(png_dpi);
18
+ const renderer = renderer_registry.get(canvas);
26
19
  if (resolution_multiplier <= 1.1 || !renderer) {
27
20
  if (renderer && scene && camera)
28
21
  renderer.render(scene, camera);
@@ -36,7 +29,7 @@ export function canvas_to_png_blob(canvas, png_dpi = 150, scene = null, camera =
36
29
  }, `image/png`);
37
30
  }
38
31
  catch (error) {
39
- reject(error);
32
+ reject(to_error(error));
40
33
  }
41
34
  });
42
35
  }
@@ -63,7 +56,7 @@ export function canvas_to_png_blob(canvas, png_dpi = 150, scene = null, camera =
63
56
  }
64
57
  catch (error) {
65
58
  restore();
66
- reject(error);
59
+ reject(to_error(error));
67
60
  }
68
61
  });
69
62
  }
@@ -90,34 +83,56 @@ export function export_canvas_as_png(canvas, structure_or_filename, png_dpi = 15
90
83
  }
91
84
  // Helper to ensure font-family is set on SVG root
92
85
  function set_svg_font_family(svg) {
93
- const style = svg.getAttribute(`style`) || ``;
86
+ const style = svg.getAttribute(`style`) ?? ``;
94
87
  if (!style.includes(`font-family`)) {
95
88
  svg.setAttribute(`style`, `${style}${style ? `;` : ``}font-family:sans-serif;`);
96
89
  }
97
90
  // Also set as attribute for extra robustness
98
91
  svg.setAttribute(`font-family`, `sans-serif`);
99
92
  }
100
- // Serialize an SVG element to a standalone SVG string with proper XML headers.
101
- // Clones the element to avoid mutation, sets font-family/xmlns, and
102
- // prepends XML declaration + SVG DOCTYPE. Returns a complete SVG document string
103
- // suitable for saving to file or further processing.
104
- export function svg_to_svg_string(svg_element) {
105
- const cloned_svg = svg_element.cloneNode(true);
106
- set_svg_font_family(cloned_svg);
107
- if (!cloned_svg.hasAttribute(`xmlns`)) {
108
- cloned_svg.setAttribute(`xmlns`, `http://www.w3.org/2000/svg`);
93
+ // Copy the given computed-style props from each live SVG element to its clone counterpart;
94
+ // identical structure lets querySelectorAll(`*`) walk both in lockstep. Writes clone-only.
95
+ function inline_computed_styles(live, clone, properties) {
96
+ const live_els = [live, ...live.querySelectorAll(`*`)];
97
+ const clone_els = [clone, ...clone.querySelectorAll(`*`)];
98
+ for (const [idx, live_el] of live_els.entries()) {
99
+ const computed = getComputedStyle(live_el);
100
+ for (const prop of properties) {
101
+ const val = computed.getPropertyValue(prop);
102
+ if (val)
103
+ clone_els[idx].setAttribute(prop, val);
104
+ }
105
+ }
106
+ }
107
+ // Clone, inline the given computed-style props, ensure font-family + xmlns, then serialize
108
+ // to a standalone SVG string. Never mutates the live element.
109
+ function serialize_svg_for_export(svg_element, inline_styles = []) {
110
+ const clone = svg_element.cloneNode(true);
111
+ if (inline_styles.length)
112
+ inline_computed_styles(svg_element, clone, inline_styles);
113
+ set_svg_font_family(clone);
114
+ if (!clone.hasAttribute(`xmlns`)) {
115
+ clone.setAttribute(`xmlns`, `http://www.w3.org/2000/svg`);
109
116
  }
110
- const svg_string = new XMLSerializer().serializeToString(cloned_svg);
117
+ return new XMLSerializer().serializeToString(clone);
118
+ }
119
+ // Wrap serialize_svg_for_export's output as a full SVG document string (XML declaration +
120
+ // DOCTYPE + SVG), suitable for saving to file.
121
+ export function svg_to_svg_string(svg_element,
122
+ // CSS props to inline from computed styles as presentation attributes; a standalone SVG
123
+ // drops page stylesheets (e.g. Svelte component styles), so class-based styling is lost.
124
+ inline_styles = []) {
125
+ const svg_string = serialize_svg_for_export(svg_element, inline_styles);
111
126
  return `<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n${svg_string}`;
112
127
  }
113
128
  // Export SVG element as SVG file (triggers browser download)
114
- export function export_svg_as_svg(svg_element, filename) {
129
+ export function export_svg_as_svg(svg_element, filename, inline_styles = []) {
115
130
  if (!svg_element) {
116
131
  console.warn(`SVG element not found for export`);
117
132
  return;
118
133
  }
119
134
  try {
120
- const svg_content = svg_to_svg_string(svg_element);
135
+ const svg_content = svg_to_svg_string(svg_element, inline_styles);
121
136
  download(svg_content, filename, `image/svg+xml;charset=utf-8`);
122
137
  }
123
138
  catch (error) {
@@ -129,7 +144,7 @@ export function export_svg_as_svg(svg_element, filename) {
129
144
  // Image element, and returns the resulting PNG Blob. Rejects if viewBox is
130
145
  // missing or dimensions are invalid (zero width/height).
131
146
  // DPI is converted to a resolution multiplier relative to 72 DPI baseline, capped at 10x.
132
- export function svg_to_png_blob(svg_element, png_dpi = 150) {
147
+ export function svg_to_png_blob(svg_element, png_dpi = 150, inline_styles = []) {
133
148
  const viewBox = svg_element.getAttribute(`viewBox`)?.trim();
134
149
  if (!viewBox)
135
150
  return Promise.reject(new Error(`SVG viewBox not found for PNG export`));
@@ -144,18 +159,17 @@ export function svg_to_png_blob(svg_element, png_dpi = 150) {
144
159
  if (!Number.isFinite(png_dpi) || png_dpi <= 0) {
145
160
  return Promise.reject(new Error(`Invalid PNG DPI for export`));
146
161
  }
147
- const resolution_multiplier = Math.min(png_dpi / 72, 10);
148
- const pixel_width = Math.round(width * resolution_multiplier);
149
- const pixel_height = Math.round(height * resolution_multiplier);
162
+ const resolution_multiplier = dpi_to_scale(png_dpi);
163
+ // Floor at 1px: small viewBoxes at low DPI round to 0 and make toBlob fail confusingly
164
+ const pixel_width = Math.max(1, Math.round(width * resolution_multiplier));
165
+ const pixel_height = Math.max(1, Math.round(height * resolution_multiplier));
150
166
  const canvas = document.createElement(`canvas`);
151
167
  const ctx = canvas.getContext(`2d`);
152
168
  if (!ctx)
153
169
  return Promise.reject(new Error(`Canvas 2D context not available`));
154
170
  canvas.width = pixel_width;
155
171
  canvas.height = pixel_height;
156
- const cloned_svg = svg_element.cloneNode(true);
157
- set_svg_font_family(cloned_svg);
158
- const serialized = new XMLSerializer().serializeToString(cloned_svg);
172
+ const serialized = serialize_svg_for_export(svg_element, inline_styles);
159
173
  const svg_blob = new Blob([serialized], { type: `image/svg+xml;charset=utf-8` });
160
174
  const svg_data_url = URL.createObjectURL(svg_blob);
161
175
  return new Promise((resolve, reject) => {
@@ -172,7 +186,7 @@ export function svg_to_png_blob(svg_element, png_dpi = 150) {
172
186
  }, `image/png`, 1);
173
187
  }
174
188
  catch (error) {
175
- reject(error);
189
+ reject(to_error(error));
176
190
  }
177
191
  finally {
178
192
  URL.revokeObjectURL(svg_data_url);
@@ -186,15 +200,32 @@ export function svg_to_png_blob(svg_element, png_dpi = 150) {
186
200
  });
187
201
  }
188
202
  // Export SVG element as PNG (triggers browser download)
189
- export function export_svg_as_png(svg_element, filename, png_dpi = 150) {
203
+ export function export_svg_as_png(svg_element, filename, png_dpi = 150, inline_styles = []) {
190
204
  if (!svg_element) {
191
205
  console.warn(`SVG element not found for PNG export`);
192
206
  return;
193
207
  }
194
- svg_to_png_blob(svg_element, png_dpi)
208
+ svg_to_png_blob(svg_element, png_dpi, inline_styles)
195
209
  .then((blob) => download(blob, filename, `image/png`))
196
210
  .catch((error) => console.error(`Error exporting PNG:`, error));
197
211
  }
212
+ // Watch a wrapper element for <canvas> insertion/removal: calls set(bool) immediately
213
+ // and on every DOM mutation. Returns a cleanup that disconnects the observer (or
214
+ // undefined when no wrapper is given). Used by export panes to enable canvas exports.
215
+ export function observe_canvas_presence(wrapper, set) {
216
+ if (!wrapper) {
217
+ set(false);
218
+ return undefined;
219
+ }
220
+ const check = () => set(Boolean(wrapper.querySelector(`canvas`)));
221
+ check();
222
+ const observer = new MutationObserver(check);
223
+ observer.observe(wrapper, { childList: true, subtree: true });
224
+ return () => observer.disconnect();
225
+ }
226
+ // Estimate VP9 video bitrate (bits/s) from pixel count and frame rate.
227
+ // VP9 needs ~0.1 bits per pixel per frame for good quality; clamped to [1, 200] Mbps.
228
+ export const estimate_video_bitrate = (pixel_count, fps) => Math.max(1_000_000, Math.min(pixel_count * fps * 0.1, 200_000_000));
198
229
  // Generate FFmpeg command for WebM to MP4 conversion
199
230
  export function get_ffmpeg_conversion_command(input_filename) {
200
231
  const output = input_filename.replace(/\.webm$/i, `.mp4`);
@@ -208,7 +239,7 @@ export async function export_trajectory_video(canvas, filename, options = {}) {
208
239
  typeof MediaRecorder === `undefined` ||
209
240
  !MediaRecorder.isTypeSupported(`video/webm;codecs=vp9`))
210
241
  throw new Error(`WebM video recording not supported in this browser`);
211
- const renderer = get_canvas_renderer(canvas);
242
+ const renderer = renderer_registry.get(canvas);
212
243
  // Store original renderer settings if changing resolution
213
244
  let orig_pixel_ratio;
214
245
  let orig_size;
@@ -220,13 +251,8 @@ export async function export_trajectory_video(canvas, filename, options = {}) {
220
251
  renderer.setSize(orig_size.width, orig_size.height, false);
221
252
  }
222
253
  // Calculate bitrate based on actual video dimensions
223
- // VP9 typically needs 0.08-0.12 bits per pixel per frame for good quality
224
- // canvas dimensions include device pixel ratio and any resolution_multiplier
225
- const pixels_per_frame = canvas.width * canvas.height;
226
- const bits_per_pixel_per_frame = 0.1; // Good quality for VP9
227
- // Clamp bitrate to reasonable bounds (1 Mbps min, 200 Mbps max)
228
- const calculated_bitrate = pixels_per_frame * fps * bits_per_pixel_per_frame;
229
- const bitrate = Math.max(1_000_000, Math.min(calculated_bitrate, 200_000_000));
254
+ // (canvas dimensions include device pixel ratio and any resolution_multiplier)
255
+ const bitrate = estimate_video_bitrate(canvas.width * canvas.height, fps);
230
256
  const stream = canvas.captureStream(0);
231
257
  const chunks = [];
232
258
  const recorder = new MediaRecorder(stream, {
@@ -283,7 +309,7 @@ export async function export_trajectory_video(canvas, filename, options = {}) {
283
309
  resolve();
284
310
  }
285
311
  catch (error) {
286
- reject(error);
312
+ reject(to_error(error));
287
313
  }
288
314
  });
289
315
  recorder.addEventListener(`error`, (event) => {
@@ -309,7 +335,7 @@ export async function export_trajectory_video(canvas, filename, options = {}) {
309
335
  catch (error) {
310
336
  if (!is_resolved) {
311
337
  is_resolved = true;
312
- reject(error);
338
+ reject(to_error(error));
313
339
  }
314
340
  }
315
341
  });
@@ -2,4 +2,5 @@ export declare const to_query: (params: Record<string, string | number | undefin
2
2
  export declare function fetch_zipped<T>(url: string, { unzip }?: {
3
3
  unzip?: boolean | undefined;
4
4
  }): Promise<T | null>;
5
- export declare function download(data: string | Blob, filename: string, type: string): void;
5
+ export type DownloadData = string | Blob | ArrayBuffer | ArrayBufferView<ArrayBuffer>;
6
+ export declare function download(data: DownloadData, filename: string, type: string): void;
package/dist/io/fetch.js CHANGED
@@ -22,7 +22,11 @@ function default_download(data, filename, type) {
22
22
  link.style.display = `none`;
23
23
  link.href = url;
24
24
  link.download = filename;
25
- document.body.appendChild(link);
25
+ // keep the synthetic download click from bubbling to document-level handlers
26
+ // (e.g. DraggablePane's click-outside) that would dismiss an open pane the export
27
+ // button lives in
28
+ link.addEventListener(`click`, (evt) => evt.stopPropagation());
29
+ document.body.append(link);
26
30
  link.click();
27
31
  link.remove();
28
32
  URL.revokeObjectURL(url);
@@ -4,4 +4,11 @@ export interface FileDropOptions {
4
4
  on_error?: (msg: string) => void;
5
5
  set_loading?: (loading: boolean) => void;
6
6
  }
7
- export declare function create_file_drop_handler(opts: FileDropOptions): (event: DragEvent) => Promise<void>;
7
+ export declare const drag_over_handlers: (opts: {
8
+ allow?: () => boolean;
9
+ set_dragover: (over: boolean) => void;
10
+ }) => {
11
+ ondragover: (event: DragEvent) => void;
12
+ ondragleave: () => void;
13
+ };
14
+ export declare const create_file_drop_handler: (opts: FileDropOptions) => ((event: DragEvent) => Promise<void>);
@@ -1,43 +1,55 @@
1
1
  // Shared file-drop handler composable for drag-and-drop file loading.
2
2
  import { decompress_file } from './decompress';
3
3
  import { handle_url_drop } from './url-drop';
4
+ import { to_error } from '../utils';
5
+ // Drag-over visual-state handlers for file-drop zones; spread onto the drop target
6
+ // alongside `ondrop` from create_file_drop_handler
7
+ export const drag_over_handlers = (opts) => ({
8
+ // preventDefault on dragover marks the element as a valid drop target; dragleave
9
+ // has no default action to cancel, so it only clears the visual state
10
+ ondragover: (event) => {
11
+ event.preventDefault();
12
+ if (opts.allow && !opts.allow())
13
+ return;
14
+ opts.set_dragover(true);
15
+ },
16
+ ondragleave: () => opts.set_dragover(false),
17
+ });
4
18
  // Handles URL drops (from FilePicker), direct file drops with decompression,
5
19
  // loading state, and error reporting.
6
- export function create_file_drop_handler(opts) {
7
- return async (event) => {
8
- event.preventDefault();
9
- if (!opts.allow())
20
+ export const create_file_drop_handler = (opts) => async (event) => {
21
+ event.preventDefault();
22
+ if (!opts.allow())
23
+ return;
24
+ opts.set_loading?.(true);
25
+ let drop_filename = ``;
26
+ try {
27
+ let url_error;
28
+ const handled = await handle_url_drop(event, opts.on_drop).catch((exc) => {
29
+ url_error = to_error(exc).message;
30
+ return false;
31
+ });
32
+ if (handled)
33
+ return;
34
+ const file = event.dataTransfer?.files[0];
35
+ if (!file) {
36
+ if (url_error)
37
+ opts.on_error?.(`Failed to load from URL: ${url_error}`);
10
38
  return;
11
- opts.set_loading?.(true);
12
- let drop_filename = ``;
13
- try {
14
- let url_error;
15
- const handled = await handle_url_drop(event, opts.on_drop).catch((exc) => {
16
- url_error = exc instanceof Error ? exc.message : String(exc);
17
- return false;
18
- });
19
- if (handled)
20
- return;
21
- const file = event.dataTransfer?.files[0];
22
- if (!file) {
23
- if (url_error)
24
- opts.on_error?.(`Failed to load from URL: ${url_error}`);
25
- return;
26
- }
27
- drop_filename = file.name;
28
- const { content, filename } = await decompress_file(file);
29
- if (content)
30
- await opts.on_drop(content, filename);
31
- }
32
- catch (exc) {
33
- const detail = exc instanceof Error ? exc.message : String(exc);
34
- const msg = drop_filename
35
- ? `Failed to load file ${drop_filename}: ${detail}`
36
- : `Failed to load file: ${detail}`;
37
- opts.on_error?.(msg);
38
- }
39
- finally {
40
- opts.set_loading?.(false);
41
39
  }
42
- };
43
- }
40
+ drop_filename = file.name;
41
+ const { content, filename } = await decompress_file(file);
42
+ if (content)
43
+ await opts.on_drop(content, filename);
44
+ }
45
+ catch (exc) {
46
+ const detail = to_error(exc).message;
47
+ const msg = drop_filename
48
+ ? `Failed to load file ${drop_filename}: ${detail}`
49
+ : `Failed to load file: ${detail}`;
50
+ opts.on_error?.(msg);
51
+ }
52
+ finally {
53
+ opts.set_loading?.(false);
54
+ }
55
+ };
@@ -1,3 +1,4 @@
1
+ export { default as ExportPane } from './ExportPane.svelte';
1
2
  export * from './decompress';
2
3
  export * from './export';
3
4
  export * from './fetch';
@@ -5,3 +6,4 @@ export * from './file-drop';
5
6
  export * from './is-binary';
6
7
  export type * from './types';
7
8
  export * from './url-drop';
9
+ export declare function strip_compression_extensions(filename: string): string;
package/dist/io/index.js CHANGED
@@ -1,6 +1,16 @@
1
+ import { COMPRESSION_EXTENSIONS_REGEX } from '../constants';
2
+ export { default as ExportPane } from './ExportPane.svelte';
1
3
  export * from './decompress';
2
4
  export * from './export';
3
5
  export * from './fetch';
4
6
  export * from './file-drop';
5
7
  export * from './is-binary';
6
8
  export * from './url-drop';
9
+ // Lowercase a filename and strip all trailing compression extensions (.gz, .zip, ...)
10
+ export function strip_compression_extensions(filename) {
11
+ let base_name = filename.toLowerCase();
12
+ while (COMPRESSION_EXTENSIONS_REGEX.test(base_name)) {
13
+ base_name = base_name.replace(COMPRESSION_EXTENSIONS_REGEX, ``);
14
+ }
15
+ return base_name;
16
+ }
@@ -6,3 +6,16 @@ export interface FileInfo {
6
6
  category?: string;
7
7
  category_icon?: string;
8
8
  }
9
+ export interface ExportItem {
10
+ label: string;
11
+ hint?: string;
12
+ disabled?: boolean;
13
+ on_download?: () => void;
14
+ copy_text?: () => string | null;
15
+ show_dpi?: boolean;
16
+ }
17
+ export interface ExportSection {
18
+ title?: string;
19
+ tooltip?: string;
20
+ items: ExportItem[];
21
+ }
@@ -1,7 +1,9 @@
1
1
  import { load_binary_traj } from '../trajectory/parse';
2
- const BINARY_EXTENSIONS = new Set(`h5 hdf5 traj npz pkl dat gz gzip zip bz2 xz brml`.split(` `));
2
+ import { decompress_data_binary } from './decompress';
3
+ const BINARY_EXTENSIONS = new Set(`h5 hdf5 traj npz pkl dat gz gzip zip bz2 xz brml raw`.split(` `));
3
4
  const TEXT_EXTENSIONS = new Set(`xyz extxyz json cif poscar yaml yml txt md py js ts css html xml`.split(` `));
4
5
  const VASP_BASENAME_RE = /^(poscar|xdatcar|contcar)$/i;
6
+ const GZ_EXT_RE = /\.(gz|gzip)$/i;
5
7
  // Extract filename from Content-Disposition header, falling back to url_basename.
6
8
  function extract_filename(headers, fallback) {
7
9
  if (!headers)
@@ -9,9 +11,13 @@ function extract_filename(headers, fallback) {
9
11
  const content_disposition_str = headers.get(`content-disposition`);
10
12
  if (!content_disposition_str)
11
13
  return fallback;
12
- const star_match = /filename\*=(?:UTF-8''|)([^;]+)/i.exec(content_disposition_str);
14
+ const star_match = /filename\*=([^;]+)/i.exec(content_disposition_str);
13
15
  if (star_match?.[1]) {
14
- const raw = star_match[1].trim().replace(/^"|"$/g, ``);
16
+ let raw = star_match[1].trim().replaceAll(/^"|"$/g, ``);
17
+ // Strip any RFC 5987 charset'language' prefix; bare values pass through unchanged
18
+ const ext_value_match = /^[\w!#$%&+^`{}~-]+'[\w-]*'(.*)$/.exec(raw);
19
+ if (ext_value_match)
20
+ raw = ext_value_match[1];
15
21
  try {
16
22
  return decodeURIComponent(raw);
17
23
  }
@@ -20,7 +26,24 @@ function extract_filename(headers, fallback) {
20
26
  }
21
27
  }
22
28
  const plain_match = /filename\s*=\s*"?([^";]+)"?/i.exec(content_disposition_str);
23
- return plain_match?.[1]?.trim() || fallback;
29
+ // truthiness check (not ??) so whitespace-only `filename=` values fall back too
30
+ const name = plain_match?.[1]?.trim();
31
+ if (!name)
32
+ return fallback;
33
+ return name;
34
+ }
35
+ const ext_of = (name) => name.split(`.`).pop()?.toLowerCase() ?? ``;
36
+ // Whether the file inside a .gz/.gzip wrapper is a known binary format that a
37
+ // lossy text decode would corrupt (bytes >= 0x80 → U+FFFD)
38
+ const has_binary_inner_ext = (filename) => BINARY_EXTENSIONS.has(ext_of(filename.replace(GZ_EXT_RE, ``)));
39
+ // Gunzip a fetched payload → [content, filename] with .gz/.gzip stripped; content
40
+ // stays an ArrayBuffer for binary inner formats, decoded string otherwise
41
+ async function decompress_gz_payload(buffer, filename) {
42
+ const decompressed = await decompress_data_binary(buffer, `gzip`);
43
+ const content = has_binary_inner_ext(filename)
44
+ ? decompressed
45
+ : new TextDecoder().decode(decompressed);
46
+ return [content, filename.replace(GZ_EXT_RE, ``)];
24
47
  }
25
48
  // Handle URL-based file drop data by fetching content lazily
26
49
  export async function handle_url_drop(drag_event, callback) {
@@ -40,8 +63,10 @@ export async function handle_url_drop(drag_event, callback) {
40
63
  return true;
41
64
  }
42
65
  export async function load_from_url(url, callback) {
43
- const url_basename = url.split(`/`).pop() || url;
44
- const ext = url_basename.split(`.`).pop()?.toLowerCase() || ``;
66
+ // Strip query string/hash before basename/extension detection so pre-signed
67
+ // URLs like traj.h5?X-Amz-Expires=300 still hit the right format path
68
+ const url_basename = url.split(/[?#]/)[0].split(`/`).pop() ?? url;
69
+ const ext = ext_of(url_basename);
45
70
  if (BINARY_EXTENSIONS.has(ext)) {
46
71
  // Force binary mode for known binary files to handle GitHub Pages content-type issues
47
72
  const resp = await fetch(url);
@@ -51,17 +76,11 @@ export async function load_from_url(url, callback) {
51
76
  // Handle gzipped files with proper content-encoding detection
52
77
  if (ext === `gz` || ext === `gzip`) {
53
78
  if (resp.headers.get(`content-encoding`) === `gzip`) {
54
- // Browser automatically decompressed it, so it's text
55
- return callback(await resp.text(), filename);
56
- }
57
- else {
58
- // Need to decompress manually
59
- const { decompress_data } = await import(`./decompress`);
60
- const buffer = await resp.arrayBuffer();
61
- const content = await decompress_data(buffer, `gzip`);
62
- // Remove .gz extension when manually decompressing
63
- return callback(content, filename.replace(/\.gz$/, ``));
79
+ // Browser already decompressed the stored .gz (GitHub Pages-style serving), so
80
+ // the body is the inner file — keep binary inner formats (.h5.gz, ...) binary
81
+ return callback(await (has_binary_inner_ext(filename) ? resp.arrayBuffer() : resp.text()), filename);
64
82
  }
83
+ return callback(...(await decompress_gz_payload(await resp.arrayBuffer(), filename)));
65
84
  }
66
85
  // For H5 files, always load as binary regardless of signature
67
86
  // to handle files that have .h5/.hdf5 extensions but may not have the proper HDF5 signature
@@ -82,40 +101,52 @@ export async function load_from_url(url, callback) {
82
101
  const buffer = await load_binary_traj(resp, `.traj`);
83
102
  return callback(buffer, filename);
84
103
  }
85
- if (resp.headers.get(`content-encoding`) === `gzip`) {
86
- return callback(await resp.text(), filename);
87
- }
104
+ // Content-Encoding is transparent transport compression: fetch already
105
+ // decompressed the body, so binary formats (npz, pkl, brml, ...) must still
106
+ // be read as ArrayBuffer — .text() would corrupt them via lossy UTF-8 decode
88
107
  return callback(await resp.arrayBuffer(), filename);
89
108
  }
90
109
  // Skip Range requests for known text formats to avoid production server issues
91
110
  // Include VASP files that don't have extensions (POSCAR, XDATCAR, CONTCAR)
92
111
  const is_known_text = TEXT_EXTENSIONS.has(ext) || VASP_BASENAME_RE.test(url_basename);
93
- let binary_callback_args;
112
+ let sniffed_callback_args;
94
113
  if (!is_known_text) {
114
+ // Only the Range sniff is guarded (failure → plain text fetch). Once magic bytes
115
+ // commit to a binary format, download/decompress errors must propagate instead of
116
+ // falling through to a text fetch that would parse the binary bytes as garbage.
117
+ let sniffed = null;
95
118
  try {
96
- // Check for magic bytes only for unknown formats
119
+ // Check for magic bytes only for unknown formats (covers extensionless URLs
120
+ // like blob: object URLs whose basenames are UUIDs)
97
121
  const head = await fetch(url, { headers: { Range: `bytes=0-15` } });
98
122
  if (head.ok) {
99
123
  const buf = new Uint8Array(await head.arrayBuffer());
100
124
  const is_gzip = buf[0] === 0x1f && buf[1] === 0x8b;
101
125
  const is_hdf5 = buf[0] === 0x89 && buf[1] === 0x48 && buf[2] === 0x44 && buf[3] === 0x46;
102
- if (is_gzip || is_hdf5) {
103
- const resp = await fetch(url);
104
- if (!resp.ok)
105
- throw new Error(`Fetch failed: ${resp.status}`);
106
- binary_callback_args = [
107
- await resp.arrayBuffer(),
108
- extract_filename(resp.headers, url_basename),
109
- ];
110
- }
126
+ // ASE .traj files start with the Ulm signature "- of Ulm"
127
+ const is_ase_traj = [0x2d, 0x20, 0x6f, 0x66, 0x20, 0x55, 0x6c, 0x6d].every((byte, idx) => buf[idx] === byte);
128
+ if (is_gzip)
129
+ sniffed = `gzip`;
130
+ else if (is_hdf5 || is_ase_traj)
131
+ sniffed = `binary`;
111
132
  }
112
133
  }
113
134
  catch {
114
- // Fall through to text fetch if HEAD request fails
135
+ // Fall through to text fetch if the Range HEAD request fails
136
+ }
137
+ if (sniffed) {
138
+ const resp = await fetch(url);
139
+ if (!resp.ok)
140
+ throw new Error(`Fetch failed: ${resp.status}`);
141
+ const filename = extract_filename(resp.headers, url_basename);
142
+ const buffer = await resp.arrayBuffer();
143
+ // Gunzip sniffed gzip — downstream parsers can't handle raw gzip bytes
144
+ sniffed_callback_args =
145
+ sniffed === `gzip` ? await decompress_gz_payload(buffer, filename) : [buffer, filename];
115
146
  }
116
147
  }
117
- if (binary_callback_args)
118
- return callback(...binary_callback_args);
148
+ if (sniffed_callback_args)
149
+ return callback(...sniffed_callback_args);
119
150
  const resp = await fetch(url);
120
151
  if (!resp.ok)
121
152
  throw new Error(`Fetch failed: ${resp.status}`);