matterviz 0.4.1 → 0.4.2

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 (395) hide show
  1. package/dist/EmptyState.svelte +10 -4
  2. package/dist/FilePicker.svelte +12 -14
  3. package/dist/Icon.svelte +7 -4
  4. package/dist/MillerIndexInput.svelte +2 -2
  5. package/dist/app.css +53 -0
  6. package/dist/brillouin/BrillouinZone.svelte +75 -85
  7. package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -7
  8. package/dist/brillouin/BrillouinZoneControls.svelte +3 -6
  9. package/dist/brillouin/BrillouinZoneExportPane.svelte +18 -14
  10. package/dist/brillouin/BrillouinZoneInfoPane.svelte +6 -10
  11. package/dist/brillouin/BrillouinZoneScene.svelte +26 -39
  12. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  13. package/dist/chempot-diagram/ChemPotDiagram.svelte +33 -38
  14. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +62 -74
  15. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +1 -1
  16. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +511 -547
  17. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +1 -1
  18. package/dist/chempot-diagram/async-compute.svelte.js +1 -1
  19. package/dist/chempot-diagram/controls-state.svelte.js +1 -1
  20. package/dist/colors/index.d.ts +0 -4
  21. package/dist/colors/index.js +19 -20
  22. package/dist/composition/BarChart.svelte +37 -31
  23. package/dist/composition/BubbleChart.svelte +17 -17
  24. package/dist/composition/Composition.svelte +7 -11
  25. package/dist/composition/Formula.svelte +18 -25
  26. package/dist/composition/FormulaFilter.svelte +92 -95
  27. package/dist/composition/PieChart.svelte +55 -41
  28. package/dist/composition/format.js +1 -1
  29. package/dist/composition/index.d.ts +2 -0
  30. package/dist/composition/index.js +14 -0
  31. package/dist/composition/parse.d.ts +2 -2
  32. package/dist/composition/parse.js +11 -10
  33. package/dist/constants.js +11 -9
  34. package/dist/convex-hull/ConvexHull.svelte +12 -15
  35. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  36. package/dist/convex-hull/ConvexHull2D.svelte +93 -92
  37. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  38. package/dist/convex-hull/ConvexHull3D.svelte +109 -140
  39. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  40. package/dist/convex-hull/ConvexHull4D.svelte +75 -94
  41. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  42. package/dist/convex-hull/ConvexHullChrome.svelte +36 -40
  43. package/dist/convex-hull/ConvexHullControls.svelte +46 -48
  44. package/dist/convex-hull/ConvexHullStats.svelte +193 -195
  45. package/dist/convex-hull/ConvexHullTooltip.svelte +5 -12
  46. package/dist/convex-hull/GasPressureControls.svelte +5 -12
  47. package/dist/convex-hull/StructurePopup.svelte +17 -21
  48. package/dist/convex-hull/StructurePopup.svelte.d.ts +2 -0
  49. package/dist/convex-hull/TemperatureSlider.svelte +4 -10
  50. package/dist/convex-hull/canvas-interactions.svelte.js +2 -1
  51. package/dist/convex-hull/helpers.d.ts +8 -10
  52. package/dist/convex-hull/helpers.js +36 -36
  53. package/dist/convex-hull/hull-state.svelte.d.ts +1 -1
  54. package/dist/convex-hull/thermodynamics.js +18 -17
  55. package/dist/coordination/CoordinationBarPlot.svelte +38 -33
  56. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
  57. package/dist/coordination/calc-coordination.d.ts +1 -1
  58. package/dist/coordination/calc-coordination.js +28 -25
  59. package/dist/element/BohrAtom.svelte +5 -8
  60. package/dist/element/ElementHeading.svelte +4 -1
  61. package/dist/element/ElementPhoto.svelte +11 -9
  62. package/dist/element/ElementStats.svelte +12 -10
  63. package/dist/element/ElementTile.svelte +24 -29
  64. package/dist/element/Nucleus.svelte +4 -2
  65. package/dist/element/data.d.ts +1 -2
  66. package/dist/element/helpers.d.ts +4 -0
  67. package/dist/element/helpers.js +18 -0
  68. package/dist/element/index.d.ts +1 -4
  69. package/dist/element/index.js +3 -18
  70. package/dist/feedback/DragOverlay.svelte +5 -5
  71. package/dist/feedback/DragOverlay.svelte.d.ts +2 -2
  72. package/dist/feedback/StatusMessage.svelte +7 -4
  73. package/dist/fermi-surface/FermiSlice.svelte +21 -18
  74. package/dist/fermi-surface/FermiSurface.svelte +14 -22
  75. package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -7
  76. package/dist/fermi-surface/FermiSurfaceControls.svelte +6 -20
  77. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  78. package/dist/fermi-surface/FermiSurfaceScene.svelte +37 -64
  79. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  80. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +9 -6
  81. package/dist/fermi-surface/compute.js +3 -3
  82. package/dist/fermi-surface/parse.js +22 -24
  83. package/dist/heatmap-matrix/HeatmapMatrix.svelte +109 -148
  84. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +2 -2
  85. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +9 -7
  86. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
  87. package/dist/heatmap-matrix/index.d.ts +5 -0
  88. package/dist/icons.d.ts +4 -0
  89. package/dist/icons.js +4 -0
  90. package/dist/io/ExportPane.svelte +10 -6
  91. package/dist/io/decompress.d.ts +2 -1
  92. package/dist/io/decompress.js +22 -35
  93. package/dist/io/export.d.ts +4 -0
  94. package/dist/io/export.js +5 -1
  95. package/dist/io/fetch.d.ts +0 -3
  96. package/dist/io/fetch.js +0 -11
  97. package/dist/io/index.d.ts +0 -1
  98. package/dist/io/index.js +2 -9
  99. package/dist/io/is-binary.d.ts +9 -0
  100. package/dist/io/is-binary.js +45 -1
  101. package/dist/io/url-drop.js +13 -25
  102. package/dist/isosurface/Isosurface.svelte +17 -23
  103. package/dist/isosurface/IsosurfaceControls.svelte +37 -42
  104. package/dist/isosurface/parse-vaspwave.d.ts +3 -0
  105. package/dist/isosurface/parse-vaspwave.js +138 -0
  106. package/dist/isosurface/parse.js +6 -6
  107. package/dist/labels.d.ts +6 -2
  108. package/dist/labels.js +43 -13
  109. package/dist/layout/FullscreenButton.svelte +2 -1
  110. package/dist/layout/FullscreenToggle.svelte +10 -4
  111. package/dist/layout/InfoCard.svelte +7 -18
  112. package/dist/layout/InfoTag.svelte +1 -3
  113. package/dist/layout/NumberRangeInput.svelte +46 -0
  114. package/dist/layout/NumberRangeInput.svelte.d.ts +12 -0
  115. package/dist/layout/PropertyFilter.svelte +2 -6
  116. package/dist/layout/SettingsSection.svelte +21 -17
  117. package/dist/layout/SubpageGrid.svelte +3 -1
  118. package/dist/layout/ViewerChrome.svelte +9 -10
  119. package/dist/layout/ViewerChrome.svelte.d.ts +2 -1
  120. package/dist/layout/fullscreen.js +3 -5
  121. package/dist/layout/fullscreen.svelte.js +1 -2
  122. package/dist/layout/index.d.ts +1 -0
  123. package/dist/layout/index.js +1 -0
  124. package/dist/layout/json-tree/JsonNode.svelte +8 -11
  125. package/dist/layout/json-tree/JsonTree.svelte +53 -77
  126. package/dist/layout/json-tree/JsonValue.svelte +7 -15
  127. package/dist/layout/json-tree/utils.js +14 -23
  128. package/dist/math.d.ts +2 -0
  129. package/dist/math.js +19 -0
  130. package/dist/overlays/ContextMenu.svelte +4 -2
  131. package/dist/overlays/CopyButton.svelte +11 -5
  132. package/dist/overlays/DragControlTab.svelte +6 -1
  133. package/dist/overlays/DraggablePane.svelte +81 -26
  134. package/dist/overlays/DraggablePane.svelte.d.ts +1 -0
  135. package/dist/overlays/GlassChip.svelte +30 -0
  136. package/dist/overlays/GlassChip.svelte.d.ts +8 -0
  137. package/dist/overlays/InfoPaneCards.svelte +11 -23
  138. package/dist/overlays/index.d.ts +7 -0
  139. package/dist/overlays/index.js +26 -0
  140. package/dist/overlays/portal.d.ts +2 -0
  141. package/dist/overlays/portal.js +14 -0
  142. package/dist/periodic-table/PeriodicTable.svelte +113 -145
  143. package/dist/periodic-table/PeriodicTable.svelte.d.ts +5 -3
  144. package/dist/periodic-table/PeriodicTableControls.svelte +11 -63
  145. package/dist/periodic-table/TableInset.svelte +9 -4
  146. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +50 -71
  147. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -8
  148. package/dist/phase-diagram/PhaseDiagramControls.svelte +70 -94
  149. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  150. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
  151. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +12 -12
  152. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +54 -58
  153. package/dist/phase-diagram/TdbInfoPanel.svelte +21 -15
  154. package/dist/phase-diagram/build-diagram.js +3 -3
  155. package/dist/phase-diagram/diagram-input.d.ts +1 -2
  156. package/dist/phase-diagram/parse.js +15 -15
  157. package/dist/phase-diagram/svg-to-diagram.js +21 -15
  158. package/dist/phase-diagram/utils.js +2 -3
  159. package/dist/plot/bar/BarPlot.svelte +430 -391
  160. package/dist/plot/bar/BarPlot.svelte.d.ts +2 -0
  161. package/dist/plot/bar/BarPlotControls.svelte +1 -3
  162. package/dist/plot/bar/BarPlotControls.svelte.d.ts +4 -6
  163. package/dist/plot/bar/SpacegroupBarPlot.svelte +29 -36
  164. package/dist/plot/bar/data.d.ts +5 -4
  165. package/dist/plot/bar/data.js +2 -1
  166. package/dist/plot/box/BoxPlot.svelte +301 -209
  167. package/dist/plot/box/BoxPlot.svelte.d.ts +2 -0
  168. package/dist/plot/box/Violin.svelte.d.ts +1 -0
  169. package/dist/plot/box/box-plot.js +1 -1
  170. package/dist/plot/core/auto-place.js +1 -1
  171. package/dist/plot/core/axis-utils.d.ts +12 -7
  172. package/dist/plot/core/axis-utils.js +48 -48
  173. package/dist/plot/core/components/AxisLabel.svelte +82 -20
  174. package/dist/plot/core/components/AxisLabel.svelte.d.ts +1 -0
  175. package/dist/plot/core/components/ColorBar.svelte +101 -106
  176. package/dist/plot/core/components/ColorScaleSelect.svelte +1 -1
  177. package/dist/plot/core/components/FillArea.svelte +10 -17
  178. package/dist/plot/core/components/HierarchyControls.svelte +249 -0
  179. package/dist/plot/{sunburst/SunburstControls.svelte.d.ts → core/components/HierarchyControls.svelte.d.ts} +12 -8
  180. package/dist/plot/core/components/InteractiveAxisLabel.svelte +1 -1
  181. package/dist/plot/core/components/InteractiveAxisLabel.svelte.d.ts +1 -1
  182. package/dist/plot/core/components/Line.svelte +18 -9
  183. package/dist/plot/core/components/Line.svelte.d.ts +2 -0
  184. package/dist/plot/core/components/PlotAxis.svelte +40 -17
  185. package/dist/plot/core/components/PlotControls.svelte +65 -41
  186. package/dist/plot/core/components/PlotLegend.svelte +31 -35
  187. package/dist/plot/core/components/PlotMarginals.svelte +616 -0
  188. package/dist/plot/core/components/PlotMarginals.svelte.d.ts +15 -0
  189. package/dist/plot/core/components/PlotTooltip.svelte +1 -1
  190. package/dist/plot/core/components/PortalSelect.svelte +4 -8
  191. package/dist/plot/core/components/ReferenceLine.svelte +27 -24
  192. package/dist/plot/core/components/ReferenceLine3D.svelte +54 -57
  193. package/dist/plot/core/components/ReferencePlane.svelte +7 -8
  194. package/dist/plot/core/components/ZeroLines.svelte +4 -8
  195. package/dist/plot/core/components/ZoomRect.svelte +1 -2
  196. package/dist/plot/core/components/index.d.ts +1 -0
  197. package/dist/plot/core/components/index.js +1 -0
  198. package/dist/plot/core/data-cleaning-signal.d.ts +46 -0
  199. package/dist/plot/core/data-cleaning-signal.js +467 -0
  200. package/dist/plot/core/data-cleaning.d.ts +2 -42
  201. package/dist/plot/core/data-cleaning.js +27 -474
  202. package/dist/plot/core/data-transform.js +9 -5
  203. package/dist/plot/core/fill-utils.d.ts +3 -1
  204. package/dist/plot/core/fill-utils.js +28 -6
  205. package/dist/plot/core/index.d.ts +1 -0
  206. package/dist/plot/core/index.js +1 -0
  207. package/dist/plot/core/interactions.js +0 -2
  208. package/dist/plot/core/layout.d.ts +3 -1
  209. package/dist/plot/core/layout.js +22 -13
  210. package/dist/plot/core/marginals.d.ts +170 -0
  211. package/dist/plot/core/marginals.js +436 -0
  212. package/dist/plot/core/reference-line.js +1 -1
  213. package/dist/plot/core/scales.d.ts +23 -0
  214. package/dist/plot/core/scales.js +39 -13
  215. package/dist/plot/core/types/fills.d.ts +101 -0
  216. package/dist/plot/core/types/fills.js +15 -0
  217. package/dist/plot/core/types/plot-3d.d.ts +87 -0
  218. package/dist/plot/core/types/plot-3d.js +4 -0
  219. package/dist/plot/core/types/reference-lines.d.ts +140 -0
  220. package/dist/plot/core/types/reference-lines.js +9 -0
  221. package/dist/plot/core/types.d.ts +29 -324
  222. package/dist/plot/core/types.js +23 -20
  223. package/dist/plot/core/utils/hierarchy-chart.d.ts +51 -0
  224. package/dist/plot/core/utils/hierarchy-chart.js +179 -0
  225. package/dist/plot/core/utils/hierarchy-labels.d.ts +20 -0
  226. package/dist/plot/core/utils/hierarchy-labels.js +99 -0
  227. package/dist/plot/core/utils/label-placement.js +2 -2
  228. package/dist/plot/histogram/Histogram.svelte +304 -325
  229. package/dist/plot/histogram/Histogram.svelte.d.ts +7 -7
  230. package/dist/plot/histogram/HistogramControls.svelte +30 -28
  231. package/dist/plot/histogram/histogram.d.ts +31 -0
  232. package/dist/plot/histogram/histogram.js +70 -0
  233. package/dist/plot/histogram/index.d.ts +1 -0
  234. package/dist/plot/histogram/index.js +1 -0
  235. package/dist/plot/index.d.ts +1 -0
  236. package/dist/plot/index.js +1 -0
  237. package/dist/plot/sankey/Sankey.svelte +78 -69
  238. package/dist/plot/sankey/Sankey.svelte.d.ts +2 -2
  239. package/dist/plot/sankey/SankeyControls.svelte +22 -16
  240. package/dist/plot/scatter/BinnedScatterPlot.svelte +263 -109
  241. package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +7 -0
  242. package/dist/plot/scatter/ElementScatter.svelte +4 -1
  243. package/dist/plot/scatter/ScatterPlot.svelte +477 -385
  244. package/dist/plot/scatter/ScatterPlot.svelte.d.ts +2 -0
  245. package/dist/plot/scatter/ScatterPlotControls.svelte +18 -19
  246. package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
  247. package/dist/plot/scatter/ScatterPoint.svelte +16 -9
  248. package/dist/plot/scatter/binned-scatter-types.d.ts +3 -2
  249. package/dist/plot/scatter/binned-scatter-types.js +6 -1
  250. package/dist/plot/scatter/scatter-data.d.ts +1 -1
  251. package/dist/plot/scatter/scatter-data.js +8 -7
  252. package/dist/plot/scatter-3d/ScatterPlot3D.svelte +25 -34
  253. package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +2 -2
  254. package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +8 -5
  255. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +113 -116
  256. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +2 -2
  257. package/dist/plot/scatter-3d/Surface3D.svelte +4 -13
  258. package/dist/plot/sunburst/Sunburst.svelte +251 -329
  259. package/dist/plot/sunburst/Sunburst.svelte.d.ts +2 -2
  260. package/dist/plot/sunburst/index.d.ts +1 -1
  261. package/dist/plot/sunburst/index.js +2 -1
  262. package/dist/plot/sunburst/render.d.ts +2 -2
  263. package/dist/plot/sunburst/render.js +47 -22
  264. package/dist/plot/sunburst/sunburst.d.ts +5 -1
  265. package/dist/plot/sunburst/sunburst.js +10 -3
  266. package/dist/plot/treemap/Treemap.svelte +907 -0
  267. package/dist/plot/treemap/Treemap.svelte.d.ts +84 -0
  268. package/dist/plot/treemap/index.d.ts +3 -0
  269. package/dist/plot/treemap/index.js +4 -0
  270. package/dist/plot/treemap/treemap.d.ts +26 -0
  271. package/dist/plot/treemap/treemap.js +99 -0
  272. package/dist/rdf/RdfPlot.svelte +22 -26
  273. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  274. package/dist/rdf/calc-rdf.js +4 -8
  275. package/dist/sanitize.js +1 -1
  276. package/dist/scene/bind-renderer.svelte.js +14 -6
  277. package/dist/settings.d.ts +19 -9
  278. package/dist/settings.js +77 -50
  279. package/dist/spectral/Bands.svelte +223 -230
  280. package/dist/spectral/BandsAndDos.svelte +11 -9
  281. package/dist/spectral/BrillouinBandsDos.svelte +19 -27
  282. package/dist/spectral/Dos.svelte +70 -73
  283. package/dist/spectral/helpers.d.ts +3 -3
  284. package/dist/spectral/helpers.js +25 -35
  285. package/dist/state.svelte.js +5 -18
  286. package/dist/structure/Arrow.svelte +5 -18
  287. package/dist/structure/ArrowInstances.svelte +160 -0
  288. package/dist/structure/ArrowInstances.svelte.d.ts +16 -0
  289. package/dist/structure/AtomLegend.svelte +115 -75
  290. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  291. package/dist/structure/Bond.svelte +31 -23
  292. package/dist/structure/CanvasTooltip.svelte +15 -3
  293. package/dist/structure/CellSelect.svelte +11 -26
  294. package/dist/structure/Cylinder.svelte +24 -40
  295. package/dist/structure/InstancedAtoms.svelte +114 -0
  296. package/dist/structure/InstancedAtoms.svelte.d.ts +15 -0
  297. package/dist/structure/Lattice.svelte +85 -149
  298. package/dist/structure/SiteLabels.svelte +122 -0
  299. package/dist/structure/SiteLabels.svelte.d.ts +18 -0
  300. package/dist/structure/Structure.svelte +473 -419
  301. package/dist/structure/Structure.svelte.d.ts +4 -2
  302. package/dist/structure/StructureCarousel.svelte +630 -0
  303. package/dist/structure/StructureCarousel.svelte.d.ts +19 -0
  304. package/dist/structure/StructureControls.svelte +157 -399
  305. package/dist/structure/StructureControls.svelte.d.ts +1 -1
  306. package/dist/structure/StructureExportPane.svelte +17 -21
  307. package/dist/structure/StructureInfoPane.svelte +72 -66
  308. package/dist/structure/StructureInfoPane.svelte.d.ts +1 -1
  309. package/dist/structure/StructureScene.svelte +467 -476
  310. package/dist/structure/StructureScene.svelte.d.ts +3 -1
  311. package/dist/structure/StructureViewport.svelte +386 -0
  312. package/dist/structure/StructureViewport.svelte.d.ts +63 -0
  313. package/dist/structure/atom-label-placement.d.ts +16 -12
  314. package/dist/structure/atom-label-placement.js +70 -37
  315. package/dist/structure/atom-properties.d.ts +2 -0
  316. package/dist/structure/atom-properties.js +104 -38
  317. package/dist/structure/bonding.d.ts +10 -3
  318. package/dist/structure/bonding.js +84 -28
  319. package/dist/structure/edit-history.d.ts +6 -0
  320. package/dist/structure/edit-history.js +27 -0
  321. package/dist/structure/export.d.ts +1 -0
  322. package/dist/structure/export.js +39 -31
  323. package/dist/structure/format-detect.d.ts +1 -0
  324. package/dist/structure/format-detect.js +22 -0
  325. package/dist/structure/geometry.d.ts +9 -0
  326. package/dist/structure/geometry.js +27 -0
  327. package/dist/structure/index.d.ts +16 -1
  328. package/dist/structure/index.js +13 -2
  329. package/dist/structure/measure.d.ts +1 -1
  330. package/dist/structure/measure.js +6 -12
  331. package/dist/structure/parse.d.ts +2 -1
  332. package/dist/structure/parse.js +243 -222
  333. package/dist/structure/partial-occupancy.js +4 -2
  334. package/dist/structure/pbc.js +78 -98
  335. package/dist/structure/polyhedra.d.ts +0 -1
  336. package/dist/structure/polyhedra.js +3 -18
  337. package/dist/structure/supercell.d.ts +1 -2
  338. package/dist/structure/supercell.js +7 -13
  339. package/dist/symmetry/SymmetryElements.svelte +11 -15
  340. package/dist/symmetry/SymmetryStats.svelte +56 -68
  341. package/dist/symmetry/WyckoffTable.svelte +5 -24
  342. package/dist/symmetry/cell-transform.js +1 -0
  343. package/dist/symmetry/index.d.ts +1 -0
  344. package/dist/symmetry/index.js +8 -2
  345. package/dist/symmetry/spacegroups.js +3 -2
  346. package/dist/table/HeatmapTable.svelte +1102 -365
  347. package/dist/table/HeatmapTable.svelte.d.ts +12 -2
  348. package/dist/table/ToggleMenu.svelte +5 -12
  349. package/dist/table/index.d.ts +21 -6
  350. package/dist/table/index.js +34 -21
  351. package/dist/theme/ThemeControl.svelte +16 -8
  352. package/dist/theme/index.d.ts +1 -5
  353. package/dist/theme/index.js +4 -10
  354. package/dist/theme/themes.mjs +14 -7
  355. package/dist/tooltip/KCoords.svelte +4 -1
  356. package/dist/tooltip/TooltipContent.svelte +2 -5
  357. package/dist/trajectory/Trajectory.svelte +515 -308
  358. package/dist/trajectory/Trajectory.svelte.d.ts +1 -1
  359. package/dist/trajectory/TrajectoryError.svelte +11 -8
  360. package/dist/trajectory/TrajectoryExportPane.svelte +14 -31
  361. package/dist/trajectory/TrajectoryInfoPane.svelte +85 -97
  362. package/dist/trajectory/extract.js +56 -34
  363. package/dist/trajectory/format-detect.js +11 -9
  364. package/dist/trajectory/frame-reader.d.ts +2 -0
  365. package/dist/trajectory/frame-reader.js +33 -29
  366. package/dist/trajectory/helpers.d.ts +2 -0
  367. package/dist/trajectory/helpers.js +18 -7
  368. package/dist/trajectory/index.d.ts +1 -0
  369. package/dist/trajectory/index.js +3 -0
  370. package/dist/trajectory/parse/h5-utils.d.ts +13 -0
  371. package/dist/trajectory/parse/h5-utils.js +109 -0
  372. package/dist/trajectory/parse/hdf5.d.ts +1 -1
  373. package/dist/trajectory/parse/hdf5.js +116 -106
  374. package/dist/trajectory/parse/index.d.ts +2 -3
  375. package/dist/trajectory/parse/index.js +17 -20
  376. package/dist/trajectory/parse/lammps.js +8 -12
  377. package/dist/trajectory/parse/vasp.js +10 -7
  378. package/dist/trajectory/parse/vaspout-electronic.d.ts +13 -0
  379. package/dist/trajectory/parse/vaspout-electronic.js +207 -0
  380. package/dist/trajectory/parse/vaspout-h5.d.ts +5 -0
  381. package/dist/trajectory/parse/vaspout-h5.js +284 -0
  382. package/dist/trajectory/parse/xyz.js +11 -7
  383. package/dist/trajectory/plotting.d.ts +8 -9
  384. package/dist/trajectory/plotting.js +99 -27
  385. package/dist/utils.d.ts +3 -0
  386. package/dist/utils.js +7 -0
  387. package/dist/xrd/XrdPlot.svelte +47 -61
  388. package/dist/xrd/broadening.js +2 -1
  389. package/dist/xrd/calc-xrd.js +2 -4
  390. package/dist/xrd/parse.d.ts +0 -1
  391. package/dist/xrd/parse.js +56 -73
  392. package/package.json +61 -33
  393. package/dist/api/mp.d.ts +0 -6
  394. package/dist/api/mp.js +0 -22
  395. package/dist/plot/sunburst/SunburstControls.svelte +0 -200
@@ -73,7 +73,9 @@
73
73
  {@attach section.tooltip
74
74
  ? tooltip({ allow_html: true, content: sanitize_html(section.tooltip) })
75
75
  : () => {}}
76
- >{section.title}</h4>
76
+ >
77
+ {section.title}
78
+ </h4>
77
79
  {/if}
78
80
  <div class="export-grid">
79
81
  {#each section.items as item, item_idx (item.label)}
@@ -81,9 +83,9 @@
81
83
  <!-- not a <label>: it would forward label-text clicks to the first (download) button -->
82
84
  <span class="export-item">
83
85
  {#if item.hint}
84
- <span
85
- {@attach tooltip({ allow_html: true, content: sanitize_html(item.hint) })}
86
- >{item.label}</span>
86
+ <span {@attach tooltip({ allow_html: true, content: sanitize_html(item.hint) })}
87
+ >{item.label}</span
88
+ >
87
89
  {:else}
88
90
  {item.label}
89
91
  {/if}
@@ -110,14 +112,16 @@
110
112
  </button>
111
113
  {/if}
112
114
  {#if item.show_dpi}
113
- <span class="dpi-input">(DPI: <input
115
+ <span class="dpi-input"
116
+ >(DPI: <input
114
117
  type="number"
115
118
  min={dpi_range[0]}
116
119
  max={dpi_range[1]}
117
120
  bind:value={png_dpi}
118
121
  onchange={clamp_dpi}
119
122
  title="Export resolution in dots per inch"
120
- />)</span>
123
+ />)</span
124
+ >
121
125
  {/if}
122
126
  </span>
123
127
  {/each}
@@ -1,11 +1,12 @@
1
1
  import type { COMPRESSION_EXTENSIONS } from '../constants';
2
2
  import { COMPRESSION_FORMATS } from '../constants';
3
+ export declare function strip_compression_extensions(filename: string): string;
3
4
  export type CompressionFormat = keyof typeof COMPRESSION_FORMATS;
4
5
  export type CompressionExtension = (typeof COMPRESSION_EXTENSIONS)[number];
5
6
  export declare function detect_compression_format(filename: string): CompressionFormat | null;
6
7
  export declare function decompress_data(data: ArrayBuffer | ReadableStream<Uint8Array> | null, format: CompressionFormat): Promise<string>;
7
8
  export declare function decompress_data_binary(data: ArrayBuffer | ReadableStream<Uint8Array> | null, format: CompressionFormat): Promise<ArrayBuffer>;
8
9
  export declare function decompress_file(file: File): Promise<{
9
- content: string;
10
+ content: string | ArrayBuffer;
10
11
  filename: string;
11
12
  }>;
@@ -1,5 +1,13 @@
1
1
  import { COMPRESSION_EXTENSIONS_REGEX, COMPRESSION_FORMATS } from '../constants';
2
- import { to_error } from '../utils';
2
+ import { is_binary_payload } from './is-binary';
3
+ // Lowercase a filename and strip all trailing compression extensions (.gz, .zip, ...)
4
+ export function strip_compression_extensions(filename) {
5
+ let base_name = filename.toLowerCase();
6
+ while (COMPRESSION_EXTENSIONS_REGEX.test(base_name)) {
7
+ base_name = base_name.replace(COMPRESSION_EXTENSIONS_REGEX, ``);
8
+ }
9
+ return base_name;
10
+ }
3
11
  export function detect_compression_format(filename) {
4
12
  const lower = filename.toLowerCase();
5
13
  for (const [format, extensions] of Object.entries(COMPRESSION_FORMATS)) {
@@ -37,39 +45,18 @@ export async function decompress_data_binary(data, format) {
37
45
  throw new Error(`Failed to decompress ${format} file: ${error}`, { cause: error });
38
46
  }
39
47
  }
40
- export function decompress_file(file) {
48
+ const to_content = (filename, buffer) => is_binary_payload(filename, buffer) ? buffer : new TextDecoder().decode(buffer);
49
+ // Read a dropped file, decompressing supported formats. Binary payloads (by extension or
50
+ // magic bytes) return as ArrayBuffer so parsers get raw bytes; text decodes to string.
51
+ export async function decompress_file(file) {
41
52
  const format = detect_compression_format(file.name);
42
- const is_supported = format !== null && format !== `zip` && format !== `xz` && format !== `bz2`;
43
- return new Promise((resolve, reject) => {
44
- const reader = new FileReader();
45
- reader.addEventListener(`load`, () => {
46
- try {
47
- const result = reader.result;
48
- // strict null check: empty files legitimately read as '' (falsy)
49
- if (result === null)
50
- throw new Error(`Failed to read file`);
51
- if (is_supported && format) {
52
- if (!(result instanceof ArrayBuffer))
53
- throw new Error(`Expected binary file data`);
54
- decompress_data(result, format).then((content) => {
55
- const filename = file.name.replace(COMPRESSION_EXTENSIONS_REGEX, ``);
56
- resolve({ content, filename });
57
- }, reject);
58
- }
59
- else {
60
- if (typeof result !== `string`)
61
- throw new Error(`Expected text file data`);
62
- resolve({ content: result, filename: file.name });
63
- }
64
- }
65
- catch (error) {
66
- reject(to_error(error));
67
- }
68
- }, { once: true });
69
- reader.addEventListener(`error`, () => reject(new Error(`Failed to read file ${file.name}`)));
70
- if (is_supported)
71
- reader.readAsArrayBuffer(file);
72
- else
73
- reader.readAsText(file);
74
- });
53
+ // zip/xz/bz2 are handled by their own code paths; null = not compressed
54
+ const decompressible = format !== null && format !== `zip` && format !== `xz` && format !== `bz2` ? format : null;
55
+ const buffer = await file.arrayBuffer();
56
+ if (decompressible) {
57
+ const filename = file.name.replace(COMPRESSION_EXTENSIONS_REGEX, ``);
58
+ const decompressed = await decompress_data_binary(buffer, decompressible);
59
+ return { content: to_content(filename, decompressed), filename };
60
+ }
61
+ return { content: to_content(file.name, buffer), filename: file.name };
75
62
  }
@@ -1,6 +1,10 @@
1
1
  import type { AnyStructure } from '../structure';
2
2
  import { type Camera, type Scene, type WebGLRenderer } from 'three';
3
3
  export declare const renderer_registry: WeakMap<HTMLCanvasElement, WebGLRenderer>;
4
+ export declare const scene_registry: WeakMap<HTMLCanvasElement, {
5
+ scene: Scene;
6
+ camera: Camera;
7
+ }>;
4
8
  export declare const dpi_to_scale: (png_dpi: number) => number;
5
9
  export declare function canvas_to_png_blob(canvas: HTMLCanvasElement, png_dpi?: number, scene?: Scene | null, camera?: Camera | null): Promise<Blob>;
6
10
  export declare function export_canvas_as_png(canvas: HTMLCanvasElement | null, structure_or_filename: AnyStructure | string | undefined, png_dpi?: number, scene?: Scene | null, camera?: Camera | null): void;
package/dist/io/export.js CHANGED
@@ -5,6 +5,10 @@ import { Vector2 } from 'three';
5
5
  // Maps a Threlte canvas to its WebGLRenderer so PNG export can look up the renderer for a
6
6
  // given canvas without mutating the DOM element. Populated by bind_renderer (scene/).
7
7
  export const renderer_registry = new WeakMap();
8
+ // Companion scene+camera mapping: WebGL buffers are cleared after present
9
+ // (preserveDrawingBuffer is off), so any capture of a live canvas must
10
+ // re-render synchronously first — which needs the scene and active camera.
11
+ export const scene_registry = new WeakMap();
8
12
  // PNG DPI -> render scale relative to the 72 DPI baseline, capped at 10x. DPI floors
9
13
  // at 1 (non-finite -> 72) so bad inputs can't yield 0x0 canvases or NaN pixel ratios.
10
14
  export const dpi_to_scale = (png_dpi) => Math.min(Math.max(1, Number.isFinite(png_dpi) ? png_dpi : 72) / 72, 10);
@@ -303,7 +307,7 @@ export async function export_trajectory_video(canvas, filename, options = {}) {
303
307
  is_resolved = true;
304
308
  try {
305
309
  const blob = new Blob(chunks, { type: `video/webm` });
306
- const webm_filename = filename.replace(/\.(mp4|webm)$/i, `.webm`);
310
+ const webm_filename = filename.replace(/\.(?:mp4|webm)$/i, `.webm`);
307
311
  download(blob, webm_filename, `video/webm`);
308
312
  on_progress?.(100);
309
313
  resolve();
@@ -1,6 +1,3 @@
1
1
  export declare const to_query: (params: Record<string, string | number | undefined>) => string;
2
- export declare function fetch_zipped<T>(url: string, { unzip }?: {
3
- unzip?: boolean | undefined;
4
- }): Promise<T | null>;
5
2
  export type DownloadData = string | Blob | ArrayBuffer | ArrayBufferView<ArrayBuffer>;
6
3
  export declare function download(data: DownloadData, filename: string, type: string): void;
package/dist/io/fetch.js CHANGED
@@ -1,19 +1,8 @@
1
- import { decompress_data } from './decompress';
2
1
  // Convert params object to URL query string, omitting empty/undefined values.
3
2
  // Example: {foo: "bar", baz: 42, empty: ""} → "foo=bar&baz=42"
4
3
  export const to_query = (params) => new URLSearchParams(Object.entries(params)
5
4
  .filter(([, val]) => val !== `` && val !== undefined)
6
5
  .map(([key, val]) => [key, String(val)])).toString();
7
- export async function fetch_zipped(url, { unzip = true } = {}) {
8
- const response = await fetch(url);
9
- if (!response.ok) {
10
- console.error(`${response.status} ${response.statusText} for ${response.url}`);
11
- return null;
12
- }
13
- if (!unzip)
14
- return (await response.blob());
15
- return JSON.parse(await decompress_data(response.body, `gzip`));
16
- }
17
6
  // Original download implementation
18
7
  function default_download(data, filename, type) {
19
8
  const file = new Blob([data], { type });
@@ -6,4 +6,3 @@ export * from './file-drop';
6
6
  export * from './is-binary';
7
7
  export type * from './types';
8
8
  export * from './url-drop';
9
- export declare function strip_compression_extensions(filename: string): string;
package/dist/io/index.js CHANGED
@@ -1,16 +1,9 @@
1
- import { COMPRESSION_EXTENSIONS_REGEX } from '../constants';
2
1
  export { default as ExportPane } from './ExportPane.svelte';
2
+ // strip_compression_extensions lives in ./decompress (Svelte-free) so parser
3
+ // modules can import it inside Web Workers; re-exported here.
3
4
  export * from './decompress';
4
5
  export * from './export';
5
6
  export * from './fetch';
6
7
  export * from './file-drop';
7
8
  export * from './is-binary';
8
9
  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
- }
@@ -1 +1,10 @@
1
1
  export declare const is_binary: (content: string) => boolean;
2
+ export declare const has_gzip_magic: (bytes: Uint8Array) => boolean;
3
+ export declare const has_hdf5_magic: (bytes: Uint8Array) => boolean;
4
+ export declare const has_binary_magic: (bytes: Uint8Array) => boolean;
5
+ export declare const ext_of: (name: string) => string;
6
+ export declare const BINARY_EXTENSIONS: Set<string>;
7
+ export declare const is_known_text_file: (basename: string) => boolean;
8
+ export declare const strip_gz_ext: (filename: string) => string;
9
+ export declare const has_binary_inner_ext: (filename: string) => boolean;
10
+ export declare const is_binary_payload: (filename: string, buffer: ArrayBuffer) => boolean;
@@ -1,4 +1,8 @@
1
- // Simplified binary detection
1
+ // Single source of truth for binary-vs-text detection in the io layer (used by
2
+ // decompress.ts and url-drop.ts): (1) is_binary string heuristic, (2) has_*_magic byte
3
+ // signatures, (3) extension/filename classification.
4
+ // === (1) string-content heuristic ===
5
+ // Detect binary from decoded text: a NUL byte or a high ratio of non-printable chars.
2
6
  export const is_binary = (content) => {
3
7
  if (!content)
4
8
  return false;
@@ -18,3 +22,43 @@ export const is_binary = (content) => {
18
22
  }
19
23
  return (binary_char_count / content.length > 0.1 || printable_ascii_count / content.length < 0.7);
20
24
  };
25
+ // === (2) magic-byte signatures ===
26
+ const starts_with = (bytes, sig) => bytes.length >= sig.length && sig.every((byte, idx) => bytes[idx] === byte);
27
+ // gzip member header
28
+ export const has_gzip_magic = (bytes) => starts_with(bytes, [0x1f, 0x8b]);
29
+ // Full 8-byte HDF5 superblock signature "\x89HDF\r\n\x1a\n" — used to validate that a file
30
+ // claiming a .h5/.hdf5 extension really is HDF5 (stricter than the binary sniff below).
31
+ export const has_hdf5_magic = (bytes) => starts_with(bytes, [0x89, 0x48, 0x44, 0x46, 0x0d, 0x0a, 0x1a, 0x0a]);
32
+ // Leading bytes that mark a payload as binary so a lossy UTF-8 decode would corrupt it.
33
+ // HDF5 is matched by its 4-byte "\x89HDF" prefix (the non-ASCII 0x89 already rules out text
34
+ // starting with "HDF"); the full 4-byte ZIP signatures rule out text merely starting "PK".
35
+ export const has_binary_magic = (bytes) => has_gzip_magic(bytes) ||
36
+ starts_with(bytes, [0x89, 0x48, 0x44, 0x46]) || // HDF5 "\x89HDF"
37
+ starts_with(bytes, [0x50, 0x4b, 0x03, 0x04]) || // ZIP local file
38
+ starts_with(bytes, [0x50, 0x4b, 0x05, 0x06]) || // ZIP empty archive (EOCD)
39
+ starts_with(bytes, [0x50, 0x4b, 0x07, 0x08]) || // ZIP spanned
40
+ starts_with(bytes, [0x2d, 0x20, 0x6f, 0x66, 0x20, 0x55, 0x6c, 0x6d]); // ASE .traj "- of Ulm"
41
+ // === (3) extension / filename classification ===
42
+ export const ext_of = (name) => name.split(`.`).pop()?.toLowerCase() ?? ``;
43
+ // Binary data formats whose lossy UTF-8 decode would corrupt bytes (post-decompression)
44
+ const BINARY_DATA_EXTENSIONS = new Set(`h5 hdf5 traj npz pkl dat brml raw`.split(` `));
45
+ // All extensions treated as binary: data formats + compressed wrappers that must be
46
+ // downloaded/kept as raw bytes (used for binary-fetch mode and .gz inner-format checks)
47
+ export const BINARY_EXTENSIONS = new Set([
48
+ ...BINARY_DATA_EXTENSIONS,
49
+ ...`gz gzip zip bz2 xz`.split(` `),
50
+ ]);
51
+ // Known text formats (plus extensionless VASP files) — safe to fetch/sniff as text
52
+ const TEXT_EXTENSIONS = new Set(`xyz extxyz json cif poscar yaml yml txt md py js ts css html xml`.split(` `));
53
+ const VASP_BASENAME_RE = /^(?:poscar|xdatcar|contcar)$/i;
54
+ export const is_known_text_file = (basename) => TEXT_EXTENSIONS.has(ext_of(basename)) || VASP_BASENAME_RE.test(basename);
55
+ const GZ_EXT_RE = /\.(?:gz|gzip)$/i;
56
+ // Strip a trailing .gz/.gzip wrapper extension, leaving any inner extension intact
57
+ export const strip_gz_ext = (filename) => filename.replace(GZ_EXT_RE, ``);
58
+ // Whether the file inside a .gz/.gzip wrapper is a known binary format that a lossy text
59
+ // decode would corrupt (bytes >= 0x80 -> U+FFFD)
60
+ export const has_binary_inner_ext = (filename) => BINARY_EXTENSIONS.has(ext_of(strip_gz_ext(filename)));
61
+ // Binary if the (post-decompression) extension is a known binary data format or the leading
62
+ // bytes match a magic signature
63
+ export const is_binary_payload = (filename, buffer) => BINARY_DATA_EXTENSIONS.has(ext_of(filename)) ||
64
+ has_binary_magic(new Uint8Array(buffer.slice(0, 8)));
@@ -1,9 +1,6 @@
1
1
  import { load_binary_traj } from '../trajectory/parse';
2
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(` `));
4
- const TEXT_EXTENSIONS = new Set(`xyz extxyz json cif poscar yaml yml txt md py js ts css html xml`.split(` `));
5
- const VASP_BASENAME_RE = /^(poscar|xdatcar|contcar)$/i;
6
- const GZ_EXT_RE = /\.(gz|gzip)$/i;
3
+ import { BINARY_EXTENSIONS, ext_of, has_binary_inner_ext, has_binary_magic, has_gzip_magic, has_hdf5_magic, is_known_text_file, strip_gz_ext, } from './is-binary';
7
4
  // Extract filename from Content-Disposition header, falling back to url_basename.
8
5
  function extract_filename(headers, fallback) {
9
6
  if (!headers)
@@ -11,11 +8,11 @@ function extract_filename(headers, fallback) {
11
8
  const content_disposition_str = headers.get(`content-disposition`);
12
9
  if (!content_disposition_str)
13
10
  return fallback;
14
- const star_match = /filename\*=([^;]+)/i.exec(content_disposition_str);
11
+ const star_match = /filename\*=(?<value>[^;]+)/i.exec(content_disposition_str);
15
12
  if (star_match?.[1]) {
16
13
  let raw = star_match[1].trim().replaceAll(/^"|"$/g, ``);
17
14
  // Strip any RFC 5987 charset'language' prefix; bare values pass through unchanged
18
- const ext_value_match = /^[\w!#$%&+^`{}~-]+'[\w-]*'(.*)$/.exec(raw);
15
+ const ext_value_match = /^[\w!#$%&+^`{}~-]+'[\w-]*'(?<value>.*)$/.exec(raw);
19
16
  if (ext_value_match)
20
17
  raw = ext_value_match[1];
21
18
  try {
@@ -25,17 +22,13 @@ function extract_filename(headers, fallback) {
25
22
  return raw;
26
23
  }
27
24
  }
28
- const plain_match = /filename\s*=\s*"?([^";]+)"?/i.exec(content_disposition_str);
25
+ const plain_match = /filename\s*=\s*"?(?<value>[^";]+)"?/i.exec(content_disposition_str);
29
26
  // truthiness check (not ??) so whitespace-only `filename=` values fall back too
30
27
  const name = plain_match?.[1]?.trim();
31
28
  if (!name)
32
29
  return fallback;
33
30
  return name;
34
31
  }
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
32
  // Gunzip a fetched payload → [content, filename] with .gz/.gzip stripped; content
40
33
  // stays an ArrayBuffer for binary inner formats, decoded string otherwise
41
34
  async function decompress_gz_payload(buffer, filename) {
@@ -43,7 +36,7 @@ async function decompress_gz_payload(buffer, filename) {
43
36
  const content = has_binary_inner_ext(filename)
44
37
  ? decompressed
45
38
  : new TextDecoder().decode(decompressed);
46
- return [content, filename.replace(GZ_EXT_RE, ``)];
39
+ return [content, strip_gz_ext(filename)];
47
40
  }
48
41
  // Handle URL-based file drop data by fetching content lazily
49
42
  export async function handle_url_drop(drag_event, callback) {
@@ -87,12 +80,10 @@ export async function load_from_url(url, callback) {
87
80
  if (ext === `h5` || ext === `hdf5`) {
88
81
  const result = await load_binary_traj(resp, `H5`, true);
89
82
  // Log warning if signature doesn't match (only for ArrayBuffer results)
90
- if (result instanceof ArrayBuffer && result.byteLength >= 8) {
91
- const view = new Uint8Array(result.slice(0, 8));
92
- const hdf5_signature = [0x89, 0x48, 0x44, 0x46, 0x0d, 0x0a, 0x1a, 0x0a];
93
- if (!hdf5_signature.every((byte, idx) => view[idx] === byte)) {
94
- console.warn(`File has .h5/.hdf5 extension but missing HDF5 signature`);
95
- }
83
+ if (result instanceof ArrayBuffer &&
84
+ result.byteLength >= 8 &&
85
+ !has_hdf5_magic(new Uint8Array(result.slice(0, 8)))) {
86
+ console.warn(`File has .h5/.hdf5 extension but missing HDF5 signature`);
96
87
  }
97
88
  return callback(result, filename);
98
89
  }
@@ -108,7 +99,7 @@ export async function load_from_url(url, callback) {
108
99
  }
109
100
  // Skip Range requests for known text formats to avoid production server issues
110
101
  // Include VASP files that don't have extensions (POSCAR, XDATCAR, CONTCAR)
111
- const is_known_text = TEXT_EXTENSIONS.has(ext) || VASP_BASENAME_RE.test(url_basename);
102
+ const is_known_text = is_known_text_file(url_basename);
112
103
  let sniffed_callback_args;
113
104
  if (!is_known_text) {
114
105
  // Only the Range sniff is guarded (failure → plain text fetch). Once magic bytes
@@ -121,13 +112,10 @@ export async function load_from_url(url, callback) {
121
112
  const head = await fetch(url, { headers: { Range: `bytes=0-15` } });
122
113
  if (head.ok) {
123
114
  const buf = new Uint8Array(await head.arrayBuffer());
124
- const is_gzip = buf[0] === 0x1f && buf[1] === 0x8b;
125
- const is_hdf5 = buf[0] === 0x89 && buf[1] === 0x48 && buf[2] === 0x44 && buf[3] === 0x46;
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)
115
+ // gzip is gunzipped downstream; other binary magic (HDF5, ZIP, ASE Ulm) stays raw
116
+ if (has_gzip_magic(buf))
129
117
  sniffed = `gzip`;
130
- else if (is_hdf5 || is_ase_traj)
118
+ else if (has_binary_magic(buf))
131
119
  sniffed = `binary`;
132
120
  }
133
121
  }
@@ -14,13 +14,12 @@
14
14
  Uint32BufferAttribute,
15
15
  } from 'three'
16
16
  import type { IsosurfaceLayer, IsosurfaceSettings, VolumetricData } from './types'
17
- import {
18
- DEFAULT_ISOSURFACE_SETTINGS,
19
- downsample_grid,
20
- pad_periodic_grid,
21
- } from './types'
17
+ import { DEFAULT_ISOSURFACE_SETTINGS, downsample_grid, pad_periodic_grid } from './types'
22
18
 
23
- let { volume, settings = DEFAULT_ISOSURFACE_SETTINGS }: {
19
+ let {
20
+ volume,
21
+ settings = DEFAULT_ISOSURFACE_SETTINGS,
22
+ }: {
24
23
  volume: VolumetricData
25
24
  settings?: IsosurfaceSettings
26
25
  } = $props()
@@ -28,23 +27,22 @@
28
27
  // Resolve layers: use explicit layers array if provided, else build from single-isovalue settings
29
28
  let resolved_layers = $derived.by((): IsosurfaceLayer[] => {
30
29
  if (settings.layers?.length) return settings.layers
31
- return [{
32
- isovalue: settings.isovalue,
33
- color: settings.positive_color,
34
- opacity: settings.opacity,
35
- visible: true,
36
- show_negative: settings.show_negative,
37
- negative_color: settings.negative_color,
38
- }]
30
+ return [
31
+ {
32
+ isovalue: settings.isovalue,
33
+ color: settings.positive_color,
34
+ opacity: settings.opacity,
35
+ visible: true,
36
+ show_negative: settings.show_negative,
37
+ negative_color: settings.negative_color,
38
+ },
39
+ ]
39
40
  })
40
41
 
41
42
  // Build indexed BufferGeometry from marching cubes output.
42
43
  // Uses Three.js index buffer to avoid tripling vertex data, and
43
44
  // computeVertexNormals() for fast GPU-friendly normals.
44
- function build_geometry(
45
- vertices: Vec3[],
46
- faces: number[][],
47
- ): BufferGeometry | null {
45
+ function build_geometry(vertices: Vec3[], faces: number[][]): BufferGeometry | null {
48
46
  if (vertices.length === 0 || faces.length === 0) return null
49
47
 
50
48
  // Flatten vertices: Vec3[] → Float32Array
@@ -242,11 +240,7 @@
242
240
  </T.Mesh>
243
241
  {:else if entry.opacity < 1}
244
242
  <!-- Two-pass rendering for correct transparency -->
245
- <T.Mesh
246
- geometry={entry.geometry}
247
- renderOrder={entry.render_order}
248
- frustumCulled={false}
249
- >
243
+ <T.Mesh geometry={entry.geometry} renderOrder={entry.render_order} frustumCulled={false}>
250
244
  <T.MeshStandardMaterial
251
245
  color={entry.color}
252
246
  transparent
@@ -45,7 +45,7 @@
45
45
  function update_layer(idx: number, updates: Partial<IsosurfaceLayer>) {
46
46
  if (!settings.layers) return
47
47
  settings.layers = settings.layers.map((layer, layer_idx) =>
48
- layer_idx === idx ? { ...layer, ...updates } : layer
48
+ layer_idx === idx ? { ...layer, ...updates } : layer,
49
49
  )
50
50
  }
51
51
  </script>
@@ -68,7 +68,9 @@
68
68
  <div class="pane-row compact-row">
69
69
  {#if volumes.length > 1}
70
70
  <label
71
- {@attach tooltip({ content: `Select which volume to display (e.g. charge vs magnetization)` })}
71
+ {@attach tooltip({
72
+ content: `Select which volume to display (e.g. charge vs magnetization)`,
73
+ })}
72
74
  >
73
75
  <span>Volume:</span>
74
76
  <select bind:value={active_volume_idx}>
@@ -79,13 +81,14 @@
79
81
  </label>
80
82
  {/if}
81
83
  <label
82
- {@attach tooltip({ content: `Number of isosurface shells at different density thresholds` })}
84
+ {@attach tooltip({
85
+ content: `Number of isosurface shells at different density thresholds`,
86
+ })}
83
87
  >
84
88
  <span>Layers:</span>
85
89
  <select
86
90
  value={n_layers}
87
- onchange={(event) =>
88
- set_layer_count(Number(event.currentTarget.value))}
91
+ onchange={(event) => set_layer_count(Number(event.currentTarget.value))}
89
92
  >
90
93
  {#each [1, 2, 3, 4, 5] as count (count)}
91
94
  <option value={count}>{count}</option>
@@ -95,14 +98,16 @@
95
98
  <!-- Sync both settings.show_negative (single-layer fallback) and all layer entries
96
99
  so the toggle works consistently regardless of which mode is active -->
97
100
  <label
98
- {@attach tooltip({ content: `Show negative lobe at −isovalue (for orbitals, ESP, magnetization)` })}
101
+ {@attach tooltip({
102
+ content: `Show negative lobe at −isovalue (for orbitals, ESP, magnetization)`,
103
+ })}
99
104
  >
100
105
  <span>Neg. lobe</span>
101
106
  <input
102
107
  type="checkbox"
103
108
  checked={is_multi_layer
104
- ? settings.layers?.some((layer) => layer.show_negative) ?? false
105
- : settings.show_negative}
109
+ ? (settings.layers?.some((layer) => layer.show_negative) ?? false)
110
+ : settings.show_negative}
106
111
  onchange={(event) => {
107
112
  const checked = event.currentTarget.checked
108
113
  settings.show_negative = checked
@@ -115,9 +120,7 @@
115
120
  }}
116
121
  />
117
122
  </label>
118
- <label
119
- {@attach tooltip({ content: `Render as wireframe mesh instead of solid surface` })}
120
- >
123
+ <label {@attach tooltip({ content: `Render as wireframe mesh instead of solid surface` })}>
121
124
  <span>Wireframe</span>
122
125
  <input type="checkbox" bind:checked={settings.wireframe} />
123
126
  </label>
@@ -135,8 +138,7 @@
135
138
  <input
136
139
  type="color"
137
140
  value={layer.color}
138
- onchange={(event) =>
139
- update_layer(idx, { color: event.currentTarget.value })}
141
+ onchange={(event) => update_layer(idx, { color: event.currentTarget.value })}
140
142
  />
141
143
  <input
142
144
  type="range"
@@ -145,9 +147,9 @@
145
147
  {step}
146
148
  value={layer.isovalue}
147
149
  oninput={(event) =>
148
- update_layer(idx, {
149
- isovalue: Number(event.currentTarget.value),
150
- })}
150
+ update_layer(idx, {
151
+ isovalue: Number(event.currentTarget.value),
152
+ })}
151
153
  style="flex: 1; min-width: 60px"
152
154
  />
153
155
  <span class="layer-value">{format_num(layer.isovalue, `.3~g`)}</span>
@@ -158,9 +160,9 @@
158
160
  step={0.05}
159
161
  value={layer.opacity}
160
162
  oninput={(event) =>
161
- update_layer(idx, {
162
- opacity: Number(event.currentTarget.value),
163
- })}
163
+ update_layer(idx, {
164
+ opacity: Number(event.currentTarget.value),
165
+ })}
164
166
  style="width: 50px"
165
167
  title="Opacity: {format_num(layer.opacity, `.2f`)}"
166
168
  />
@@ -169,23 +171,21 @@
169
171
  {:else}
170
172
  <!-- Single-layer: isovalue slider full width -->
171
173
  <label
172
- {@attach tooltip({ content: `Density threshold — surface is drawn where grid values equal this` })}
174
+ {@attach tooltip({
175
+ content: `Density threshold — surface is drawn where grid values equal this`,
176
+ })}
173
177
  >
174
178
  <span>Isovalue:</span>
175
- <input
176
- type="range"
177
- min={step}
178
- max={slider_max}
179
- {step}
180
- bind:value={settings.isovalue}
181
- />
179
+ <input type="range" min={step} max={slider_max} {step} bind:value={settings.isovalue} />
182
180
  <span class="value">{format_num(settings.isovalue, `.4~g`)}</span>
183
181
  </label>
184
182
 
185
183
  <!-- Opacity + colors on one row -->
186
184
  <div class="pane-row compact-row">
187
185
  <label
188
- {@attach tooltip({ content: `Surface transparency — lower values reveal inner structure` })}
186
+ {@attach tooltip({
187
+ content: `Surface transparency — lower values reveal inner structure`,
188
+ })}
189
189
  >
190
190
  <span>Opacity:</span>
191
191
  <input
@@ -203,9 +203,7 @@
203
203
  <input type="color" bind:value={settings.positive_color} />
204
204
  </label>
205
205
  {#if settings.show_negative}
206
- <label
207
- {@attach tooltip({ content: `Color for the negative (−isovalue) surface` })}
208
- >
206
+ <label {@attach tooltip({ content: `Color for the negative (−isovalue) surface` })}>
209
207
  <span>&minus; Color</span>
210
208
  <input type="color" bind:value={settings.negative_color} />
211
209
  </label>
@@ -215,24 +213,21 @@
215
213
 
216
214
  {#if volumes?.[active_volume_idx]?.periodic}
217
215
  <label
218
- {@attach tooltip({ content: `Extend isosurface beyond cell boundaries to close partial spheres (fraction of cell)` })}
216
+ {@attach tooltip({
217
+ content: `Extend isosurface beyond cell boundaries to close partial spheres (fraction of cell)`,
218
+ })}
219
219
  >
220
220
  Halo: {format_num(settings.halo, `.2f`)}
221
- <input
222
- type="range"
223
- min={0}
224
- max={0.5}
225
- step={0.01}
226
- bind:value={settings.halo}
227
- />
221
+ <input type="range" min={0} max={0.5} step={0.01} bind:value={settings.halo} />
228
222
  </label>
229
223
  {/if}
230
224
 
231
225
  {#if volumes[active_volume_idx]}
232
226
  <div class="grid-info">
233
- {volumes[active_volume_idx].grid_dims.join(` × `)} grid &nbsp;|&nbsp; [{
234
- format_num(data_range.min, `.3~g`)
235
- }, {format_num(data_range.max, `.3~g`)}]
227
+ {volumes[active_volume_idx].grid_dims.join(` × `)} grid &nbsp;|&nbsp; [{format_num(
228
+ data_range.min,
229
+ `.3~g`,
230
+ )}, {format_num(data_range.max, `.3~g`)}]
236
231
  </div>
237
232
  {/if}
238
233
  </SettingsSection>
@@ -0,0 +1,3 @@
1
+ import type { VolumetricFileData } from './types';
2
+ export declare const is_vaspwave_filename: (filename: string) => boolean;
3
+ export declare function parse_vaspwave_charge(buffer: ArrayBuffer, filename?: string): Promise<VolumetricFileData>;