matterviz 0.4.1 → 0.4.3

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 (499) hide show
  1. package/dist/EmptyState.svelte +10 -4
  2. package/dist/FilePicker.svelte +48 -60
  3. package/dist/Icon.svelte +7 -4
  4. package/dist/MillerIndexInput.svelte +2 -2
  5. package/dist/api/optimade.js +10 -7
  6. package/dist/app.css +68 -0
  7. package/dist/brillouin/BrillouinZone.svelte +90 -91
  8. package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -7
  9. package/dist/brillouin/BrillouinZoneControls.svelte +3 -6
  10. package/dist/brillouin/BrillouinZoneExportPane.svelte +18 -14
  11. package/dist/brillouin/BrillouinZoneInfoPane.svelte +6 -10
  12. package/dist/brillouin/BrillouinZoneScene.svelte +46 -68
  13. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  14. package/dist/brillouin/compute.js +10 -16
  15. package/dist/brillouin/geometry.js +2 -2
  16. package/dist/chempot-diagram/ChemPotDiagram.svelte +48 -50
  17. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +61 -169
  18. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +1 -1
  19. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +559 -755
  20. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +1 -1
  21. package/dist/chempot-diagram/async-compute.svelte.js +13 -14
  22. package/dist/chempot-diagram/color.d.ts +21 -1
  23. package/dist/chempot-diagram/color.js +70 -1
  24. package/dist/chempot-diagram/compute.d.ts +7 -0
  25. package/dist/chempot-diagram/compute.js +85 -26
  26. package/dist/chempot-diagram/controls-state.svelte.js +1 -1
  27. package/dist/chempot-diagram/export.js +1 -6
  28. package/dist/chempot-diagram/temperature.js +9 -10
  29. package/dist/colors/index.d.ts +0 -4
  30. package/dist/colors/index.js +19 -20
  31. package/dist/composition/BarChart.svelte +30 -26
  32. package/dist/composition/BubbleChart.svelte +17 -17
  33. package/dist/composition/Composition.svelte +10 -19
  34. package/dist/composition/Formula.svelte +20 -27
  35. package/dist/composition/FormulaFilter.svelte +115 -184
  36. package/dist/composition/PieChart.svelte +55 -41
  37. package/dist/composition/format.js +7 -9
  38. package/dist/composition/index.d.ts +2 -0
  39. package/dist/composition/index.js +14 -0
  40. package/dist/composition/parse.d.ts +2 -2
  41. package/dist/composition/parse.js +61 -115
  42. package/dist/constants.d.ts +0 -1
  43. package/dist/constants.js +17 -26
  44. package/dist/convex-hull/ConvexHull.svelte +12 -15
  45. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  46. package/dist/convex-hull/ConvexHull2D.svelte +93 -94
  47. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  48. package/dist/convex-hull/ConvexHull3D.svelte +127 -186
  49. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  50. package/dist/convex-hull/ConvexHull4D.svelte +131 -180
  51. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  52. package/dist/convex-hull/ConvexHullChrome.svelte +36 -40
  53. package/dist/convex-hull/ConvexHullControls.svelte +46 -48
  54. package/dist/convex-hull/ConvexHullStats.svelte +193 -195
  55. package/dist/convex-hull/ConvexHullTooltip.svelte +5 -12
  56. package/dist/convex-hull/GasPressureControls.svelte +5 -12
  57. package/dist/convex-hull/StructurePopup.svelte +18 -22
  58. package/dist/convex-hull/StructurePopup.svelte.d.ts +2 -0
  59. package/dist/convex-hull/TemperatureSlider.svelte +4 -10
  60. package/dist/convex-hull/canvas-interactions.svelte.js +2 -1
  61. package/dist/convex-hull/gas-thermodynamics.js +21 -53
  62. package/dist/convex-hull/helpers.d.ts +8 -10
  63. package/dist/convex-hull/helpers.js +37 -43
  64. package/dist/convex-hull/hull-state.svelte.d.ts +1 -1
  65. package/dist/convex-hull/thermodynamics.js +37 -44
  66. package/dist/coordination/CoordinationBarPlot.svelte +49 -53
  67. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
  68. package/dist/coordination/calc-coordination.d.ts +1 -1
  69. package/dist/coordination/calc-coordination.js +28 -25
  70. package/dist/element/BohrAtom.svelte +5 -9
  71. package/dist/element/ElementHeading.svelte +4 -1
  72. package/dist/element/ElementPhoto.svelte +11 -9
  73. package/dist/element/ElementStats.svelte +12 -10
  74. package/dist/element/ElementTile.svelte +44 -67
  75. package/dist/element/Nucleus.svelte +4 -2
  76. package/dist/element/data.d.ts +3 -2
  77. package/dist/element/data.js +5 -1
  78. package/dist/element/helpers.d.ts +4 -0
  79. package/dist/element/helpers.js +18 -0
  80. package/dist/element/index.d.ts +2 -5
  81. package/dist/element/index.js +4 -19
  82. package/dist/feedback/DragOverlay.svelte +5 -5
  83. package/dist/feedback/DragOverlay.svelte.d.ts +2 -2
  84. package/dist/feedback/StatusMessage.svelte +7 -4
  85. package/dist/fermi-surface/FermiSlice.svelte +21 -18
  86. package/dist/fermi-surface/FermiSurface.svelte +35 -44
  87. package/dist/fermi-surface/FermiSurface.svelte.d.ts +7 -13
  88. package/dist/fermi-surface/FermiSurfaceControls.svelte +6 -20
  89. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  90. package/dist/fermi-surface/FermiSurfaceScene.svelte +64 -136
  91. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  92. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +9 -6
  93. package/dist/fermi-surface/compute.js +25 -58
  94. package/dist/fermi-surface/parse.js +54 -88
  95. package/dist/file-viewer/JsonBrowser.svelte +1043 -0
  96. package/dist/file-viewer/JsonBrowser.svelte.d.ts +9 -0
  97. package/dist/file-viewer/PlotPanel.svelte +350 -0
  98. package/dist/file-viewer/PlotPanel.svelte.d.ts +9 -0
  99. package/dist/file-viewer/TrajectoryWithDos.svelte +30 -0
  100. package/dist/file-viewer/TrajectoryWithDos.svelte.d.ts +10 -0
  101. package/dist/file-viewer/detect.d.ts +11 -0
  102. package/dist/file-viewer/detect.js +381 -0
  103. package/dist/file-viewer/eligibility.d.ts +4 -0
  104. package/dist/file-viewer/eligibility.js +53 -0
  105. package/dist/file-viewer/host-protocol.d.ts +50 -0
  106. package/dist/file-viewer/host-transfer.d.ts +25 -0
  107. package/dist/file-viewer/host-transfer.js +42 -0
  108. package/dist/file-viewer/index.d.ts +5 -0
  109. package/dist/file-viewer/index.js +5 -0
  110. package/dist/file-viewer/main.d.ts +44 -0
  111. package/dist/file-viewer/main.js +535 -0
  112. package/dist/file-viewer/parse.d.ts +9 -0
  113. package/dist/file-viewer/parse.js +170 -0
  114. package/dist/file-viewer/plot-utils.d.ts +24 -0
  115. package/dist/file-viewer/plot-utils.js +191 -0
  116. package/dist/file-viewer/types.d.ts +4 -0
  117. package/dist/file-viewer/types.js +5 -0
  118. package/dist/heatmap-matrix/HeatmapMatrix.svelte +153 -219
  119. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +2 -2
  120. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +9 -7
  121. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
  122. package/dist/heatmap-matrix/index.d.ts +5 -0
  123. package/dist/icons.d.ts +4 -0
  124. package/dist/icons.js +4 -0
  125. package/dist/index.d.ts +2 -2
  126. package/dist/index.js +1 -1
  127. package/dist/io/ExportPane.svelte +11 -7
  128. package/dist/io/decompress.d.ts +4 -1
  129. package/dist/io/decompress.js +24 -36
  130. package/dist/io/export.d.ts +11 -4
  131. package/dist/io/export.js +75 -19
  132. package/dist/io/fetch.d.ts +0 -3
  133. package/dist/io/fetch.js +0 -11
  134. package/dist/io/file-drop.js +60 -35
  135. package/dist/io/index.d.ts +0 -1
  136. package/dist/io/index.js +2 -9
  137. package/dist/io/is-binary.d.ts +9 -0
  138. package/dist/io/is-binary.js +45 -1
  139. package/dist/io/url-drop.d.ts +2 -0
  140. package/dist/io/url-drop.js +40 -40
  141. package/dist/isosurface/Isosurface.svelte +700 -215
  142. package/dist/isosurface/Isosurface.svelte.d.ts +7 -1
  143. package/dist/isosurface/IsosurfaceControls.svelte +590 -116
  144. package/dist/isosurface/IsosurfaceControls.svelte.d.ts +1 -1
  145. package/dist/isosurface/VolumeSlice.svelte +224 -0
  146. package/dist/isosurface/VolumeSlice.svelte.d.ts +28 -0
  147. package/dist/isosurface/coloring.d.ts +20 -0
  148. package/dist/isosurface/coloring.js +118 -0
  149. package/dist/isosurface/geometry-worker-types.d.ts +38 -0
  150. package/dist/isosurface/geometry.worker.d.ts +1 -0
  151. package/dist/isosurface/geometry.worker.js +59 -0
  152. package/dist/isosurface/grid.d.ts +10 -0
  153. package/dist/isosurface/grid.js +31 -0
  154. package/dist/isosurface/index.d.ts +4 -0
  155. package/dist/isosurface/index.js +4 -0
  156. package/dist/isosurface/parse-vaspwave.d.ts +3 -0
  157. package/dist/isosurface/parse-vaspwave.js +138 -0
  158. package/dist/isosurface/parse.js +6 -6
  159. package/dist/isosurface/profile.d.ts +12 -0
  160. package/dist/isosurface/profile.js +19 -0
  161. package/dist/isosurface/sampling.d.ts +34 -0
  162. package/dist/isosurface/sampling.js +408 -0
  163. package/dist/isosurface/slice-rendering.d.ts +13 -0
  164. package/dist/isosurface/slice-rendering.js +79 -0
  165. package/dist/isosurface/slice.d.ts +22 -2
  166. package/dist/isosurface/slice.js +200 -116
  167. package/dist/isosurface/types.d.ts +24 -1
  168. package/dist/isosurface/types.js +120 -8
  169. package/dist/json-path.d.ts +4 -0
  170. package/dist/json-path.js +89 -0
  171. package/dist/labels.d.ts +6 -2
  172. package/dist/labels.js +44 -14
  173. package/dist/layout/FullscreenButton.svelte +2 -1
  174. package/dist/layout/FullscreenToggle.svelte +10 -4
  175. package/dist/layout/InfoCard.svelte +8 -21
  176. package/dist/layout/InfoTag.svelte +1 -3
  177. package/dist/layout/NumberRangeInput.svelte +46 -0
  178. package/dist/layout/NumberRangeInput.svelte.d.ts +12 -0
  179. package/dist/layout/PropertyFilter.svelte +2 -6
  180. package/dist/layout/SettingsSection.svelte +57 -62
  181. package/dist/layout/SettingsSection.svelte.d.ts +6 -7
  182. package/dist/layout/SubpageGrid.svelte +3 -1
  183. package/dist/layout/ViewerChrome.svelte +16 -11
  184. package/dist/layout/ViewerChrome.svelte.d.ts +2 -1
  185. package/dist/layout/fullscreen.js +3 -5
  186. package/dist/layout/fullscreen.svelte.js +1 -2
  187. package/dist/layout/index.d.ts +1 -0
  188. package/dist/layout/index.js +1 -0
  189. package/dist/layout/json-tree/JsonNode.svelte +22 -59
  190. package/dist/layout/json-tree/JsonTree.svelte +101 -172
  191. package/dist/layout/json-tree/JsonValue.svelte +9 -32
  192. package/dist/layout/json-tree/utils.d.ts +0 -3
  193. package/dist/layout/json-tree/utils.js +50 -188
  194. package/dist/marching-cubes.d.ts +8 -1
  195. package/dist/marching-cubes.js +115 -48
  196. package/dist/math.d.ts +5 -2
  197. package/dist/math.js +48 -38
  198. package/dist/overlays/ContextMenu.svelte +19 -34
  199. package/dist/overlays/CopyButton.svelte +11 -5
  200. package/dist/overlays/DragControlTab.svelte +6 -1
  201. package/dist/overlays/DraggablePane.svelte +110 -74
  202. package/dist/overlays/DraggablePane.svelte.d.ts +2 -1
  203. package/dist/overlays/GlassChip.svelte +32 -0
  204. package/dist/overlays/GlassChip.svelte.d.ts +8 -0
  205. package/dist/overlays/InfoPaneCards.svelte +11 -23
  206. package/dist/overlays/index.d.ts +7 -0
  207. package/dist/overlays/index.js +26 -0
  208. package/dist/overlays/portal.d.ts +2 -0
  209. package/dist/overlays/portal.js +14 -0
  210. package/dist/periodic-table/PeriodicTable.svelte +113 -145
  211. package/dist/periodic-table/PeriodicTable.svelte.d.ts +5 -3
  212. package/dist/periodic-table/PeriodicTableControls.svelte +37 -115
  213. package/dist/periodic-table/TableInset.svelte +9 -4
  214. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +68 -105
  215. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -8
  216. package/dist/phase-diagram/PhaseDiagramControls.svelte +70 -94
  217. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  218. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
  219. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +12 -12
  220. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +54 -58
  221. package/dist/phase-diagram/TdbInfoPanel.svelte +21 -15
  222. package/dist/phase-diagram/build-diagram.js +4 -9
  223. package/dist/phase-diagram/diagram-input.d.ts +1 -2
  224. package/dist/phase-diagram/parse.js +15 -15
  225. package/dist/phase-diagram/svg-to-diagram.js +28 -27
  226. package/dist/phase-diagram/utils.js +2 -3
  227. package/dist/plot/bar/BarPlot.svelte +461 -426
  228. package/dist/plot/bar/BarPlot.svelte.d.ts +2 -0
  229. package/dist/plot/bar/BarPlotControls.svelte +1 -3
  230. package/dist/plot/bar/BarPlotControls.svelte.d.ts +4 -6
  231. package/dist/plot/bar/SpacegroupBarPlot.svelte +46 -77
  232. package/dist/plot/bar/data.d.ts +5 -4
  233. package/dist/plot/bar/data.js +2 -1
  234. package/dist/plot/box/BoxPlot.svelte +322 -226
  235. package/dist/plot/box/BoxPlot.svelte.d.ts +2 -0
  236. package/dist/plot/box/Violin.svelte.d.ts +1 -0
  237. package/dist/plot/box/box-plot.js +1 -1
  238. package/dist/plot/core/auto-place.d.ts +1 -1
  239. package/dist/plot/core/auto-place.js +2 -2
  240. package/dist/plot/core/axis-utils.d.ts +12 -7
  241. package/dist/plot/core/axis-utils.js +48 -48
  242. package/dist/plot/core/components/AxisLabel.svelte +82 -20
  243. package/dist/plot/core/components/AxisLabel.svelte.d.ts +1 -0
  244. package/dist/plot/core/components/ColorBar.svelte +101 -106
  245. package/dist/plot/core/components/ColorScaleSelect.svelte +1 -1
  246. package/dist/plot/core/components/FillArea.svelte +10 -17
  247. package/dist/plot/core/components/HierarchyControls.svelte +249 -0
  248. package/dist/plot/{sunburst/SunburstControls.svelte.d.ts → core/components/HierarchyControls.svelte.d.ts} +12 -8
  249. package/dist/plot/core/components/InteractiveAxisLabel.svelte +1 -1
  250. package/dist/plot/core/components/InteractiveAxisLabel.svelte.d.ts +1 -1
  251. package/dist/plot/core/components/Line.svelte +18 -9
  252. package/dist/plot/core/components/Line.svelte.d.ts +2 -0
  253. package/dist/plot/core/components/PlotAxis.svelte +40 -17
  254. package/dist/plot/core/components/PlotControls.svelte +65 -41
  255. package/dist/plot/core/components/PlotLegend.svelte +31 -35
  256. package/dist/plot/core/components/PlotMarginals.svelte +616 -0
  257. package/dist/plot/core/components/PlotMarginals.svelte.d.ts +15 -0
  258. package/dist/plot/core/components/PlotTooltip.svelte +1 -1
  259. package/dist/plot/core/components/PortalSelect.svelte +4 -8
  260. package/dist/plot/core/components/ReferenceLine.svelte +27 -24
  261. package/dist/plot/core/components/ReferenceLine3D.svelte +54 -57
  262. package/dist/plot/core/components/ReferencePlane.svelte +7 -8
  263. package/dist/plot/core/components/ZeroLines.svelte +4 -8
  264. package/dist/plot/core/components/ZoomRect.svelte +1 -2
  265. package/dist/plot/core/components/index.d.ts +1 -0
  266. package/dist/plot/core/components/index.js +1 -0
  267. package/dist/plot/core/data-cleaning-signal.d.ts +46 -0
  268. package/dist/plot/core/data-cleaning-signal.js +467 -0
  269. package/dist/plot/core/data-cleaning.d.ts +2 -42
  270. package/dist/plot/core/data-cleaning.js +27 -474
  271. package/dist/plot/core/data-transform.d.ts +1 -2
  272. package/dist/plot/core/data-transform.js +9 -15
  273. package/dist/plot/core/fill-utils.d.ts +3 -1
  274. package/dist/plot/core/fill-utils.js +28 -6
  275. package/dist/plot/core/index.d.ts +1 -0
  276. package/dist/plot/core/index.js +1 -0
  277. package/dist/plot/core/interactions.js +0 -2
  278. package/dist/plot/core/layout.d.ts +15 -6
  279. package/dist/plot/core/layout.js +57 -38
  280. package/dist/plot/core/marginals.d.ts +170 -0
  281. package/dist/plot/core/marginals.js +436 -0
  282. package/dist/plot/core/pan-zoom.svelte.d.ts +2 -4
  283. package/dist/plot/core/pan-zoom.svelte.js +34 -17
  284. package/dist/plot/core/placed-tween.svelte.d.ts +3 -0
  285. package/dist/plot/core/placed-tween.svelte.js +68 -21
  286. package/dist/plot/core/reference-line.js +1 -1
  287. package/dist/plot/core/scales.d.ts +23 -0
  288. package/dist/plot/core/scales.js +39 -13
  289. package/dist/plot/core/svg.js +0 -1
  290. package/dist/plot/core/types/fills.d.ts +101 -0
  291. package/dist/plot/core/types/fills.js +15 -0
  292. package/dist/plot/core/types/plot-3d.d.ts +87 -0
  293. package/dist/plot/core/types/plot-3d.js +4 -0
  294. package/dist/plot/core/types/reference-lines.d.ts +140 -0
  295. package/dist/plot/core/types/reference-lines.js +9 -0
  296. package/dist/plot/core/types.d.ts +29 -324
  297. package/dist/plot/core/types.js +23 -20
  298. package/dist/plot/core/utils/hierarchy-chart.d.ts +52 -0
  299. package/dist/plot/core/utils/hierarchy-chart.js +191 -0
  300. package/dist/plot/core/utils/hierarchy-labels.d.ts +20 -0
  301. package/dist/plot/core/utils/hierarchy-labels.js +100 -0
  302. package/dist/plot/core/utils/label-placement.js +2 -2
  303. package/dist/plot/histogram/Histogram.svelte +314 -340
  304. package/dist/plot/histogram/Histogram.svelte.d.ts +7 -7
  305. package/dist/plot/histogram/HistogramControls.svelte +30 -28
  306. package/dist/plot/histogram/histogram.d.ts +31 -0
  307. package/dist/plot/histogram/histogram.js +70 -0
  308. package/dist/plot/histogram/index.d.ts +1 -0
  309. package/dist/plot/histogram/index.js +1 -0
  310. package/dist/plot/index.d.ts +1 -0
  311. package/dist/plot/index.js +1 -0
  312. package/dist/plot/sankey/Sankey.svelte +78 -69
  313. package/dist/plot/sankey/Sankey.svelte.d.ts +2 -2
  314. package/dist/plot/sankey/SankeyControls.svelte +22 -16
  315. package/dist/plot/sankey/sankey.js +13 -9
  316. package/dist/plot/scatter/BinnedScatterPlot.svelte +311 -141
  317. package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +7 -0
  318. package/dist/plot/scatter/ElementScatter.svelte +4 -1
  319. package/dist/plot/scatter/ScatterPlot.svelte +517 -410
  320. package/dist/plot/scatter/ScatterPlot.svelte.d.ts +2 -0
  321. package/dist/plot/scatter/ScatterPlotControls.svelte +18 -19
  322. package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
  323. package/dist/plot/scatter/ScatterPoint.svelte +16 -9
  324. package/dist/plot/scatter/adaptive-density.d.ts +1 -1
  325. package/dist/plot/scatter/adaptive-density.js +36 -20
  326. package/dist/plot/scatter/binned-scatter-types.d.ts +3 -2
  327. package/dist/plot/scatter/binned-scatter-types.js +6 -1
  328. package/dist/plot/scatter/scatter-data.d.ts +1 -1
  329. package/dist/plot/scatter/scatter-data.js +8 -7
  330. package/dist/plot/scatter-3d/ScatterPlot3D.svelte +25 -34
  331. package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +2 -2
  332. package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +8 -5
  333. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +113 -116
  334. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +2 -2
  335. package/dist/plot/scatter-3d/Surface3D.svelte +4 -13
  336. package/dist/plot/sunburst/Sunburst.svelte +269 -347
  337. package/dist/plot/sunburst/Sunburst.svelte.d.ts +2 -2
  338. package/dist/plot/sunburst/index.d.ts +1 -1
  339. package/dist/plot/sunburst/index.js +2 -1
  340. package/dist/plot/sunburst/render.d.ts +2 -2
  341. package/dist/plot/sunburst/render.js +47 -22
  342. package/dist/plot/sunburst/sunburst.d.ts +5 -1
  343. package/dist/plot/sunburst/sunburst.js +10 -3
  344. package/dist/plot/treemap/Treemap.svelte +1022 -0
  345. package/dist/plot/treemap/Treemap.svelte.d.ts +90 -0
  346. package/dist/plot/treemap/index.d.ts +4 -0
  347. package/dist/plot/treemap/index.js +4 -0
  348. package/dist/plot/treemap/labels.d.ts +38 -0
  349. package/dist/plot/treemap/labels.js +80 -0
  350. package/dist/plot/treemap/treemap.d.ts +28 -0
  351. package/dist/plot/treemap/treemap.js +102 -0
  352. package/dist/rdf/RdfPlot.svelte +37 -59
  353. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  354. package/dist/rdf/calc-rdf.js +63 -52
  355. package/dist/rdf/index.d.ts +0 -1
  356. package/dist/sanitize.js +85 -27
  357. package/dist/scene/SceneCamera.svelte +1 -1
  358. package/dist/scene/SceneCamera.svelte.d.ts +1 -1
  359. package/dist/scene/bind-renderer.svelte.js +14 -6
  360. package/dist/scene/index.d.ts +1 -2
  361. package/dist/scene/index.js +1 -1
  362. package/dist/scene/{props.js → props.svelte.js} +15 -1
  363. package/dist/settings.d.ts +19 -9
  364. package/dist/settings.js +229 -525
  365. package/dist/spectral/Bands.svelte +207 -221
  366. package/dist/spectral/BandsAndDos.svelte +11 -9
  367. package/dist/spectral/BrillouinBandsDos.svelte +19 -42
  368. package/dist/spectral/Dos.svelte +92 -93
  369. package/dist/spectral/helpers.d.ts +3 -3
  370. package/dist/spectral/helpers.js +65 -140
  371. package/dist/state.svelte.js +5 -18
  372. package/dist/structure/Arrow.svelte +5 -18
  373. package/dist/structure/ArrowInstances.svelte +160 -0
  374. package/dist/structure/ArrowInstances.svelte.d.ts +16 -0
  375. package/dist/structure/AtomLegend.svelte +120 -85
  376. package/dist/structure/AtomLegend.svelte.d.ts +2 -3
  377. package/dist/structure/Bond.svelte +31 -23
  378. package/dist/structure/CanvasTooltip.svelte +15 -3
  379. package/dist/structure/CellSelect.svelte +45 -35
  380. package/dist/structure/Cylinder.svelte +24 -40
  381. package/dist/structure/InstancedAtoms.svelte +114 -0
  382. package/dist/structure/InstancedAtoms.svelte.d.ts +15 -0
  383. package/dist/structure/Lattice.svelte +85 -149
  384. package/dist/structure/SiteLabels.svelte +122 -0
  385. package/dist/structure/SiteLabels.svelte.d.ts +18 -0
  386. package/dist/structure/Structure.svelte +636 -504
  387. package/dist/structure/Structure.svelte.d.ts +4 -2
  388. package/dist/structure/StructureCarousel.svelte +637 -0
  389. package/dist/structure/StructureCarousel.svelte.d.ts +19 -0
  390. package/dist/structure/StructureControls.svelte +165 -425
  391. package/dist/structure/StructureControls.svelte.d.ts +1 -1
  392. package/dist/structure/StructureExportPane.svelte +17 -21
  393. package/dist/structure/StructureInfoPane.svelte +128 -133
  394. package/dist/structure/StructureInfoPane.svelte.d.ts +1 -1
  395. package/dist/structure/StructureScene.svelte +535 -578
  396. package/dist/structure/StructureScene.svelte.d.ts +6 -2
  397. package/dist/structure/StructureViewport.svelte +451 -0
  398. package/dist/structure/StructureViewport.svelte.d.ts +65 -0
  399. package/dist/structure/atom-label-placement.d.ts +16 -12
  400. package/dist/structure/atom-label-placement.js +70 -37
  401. package/dist/structure/atom-properties.d.ts +2 -0
  402. package/dist/structure/atom-properties.js +105 -38
  403. package/dist/structure/bond-order-perception.js +3 -8
  404. package/dist/structure/bonding.d.ts +9 -3
  405. package/dist/structure/bonding.js +95 -46
  406. package/dist/structure/edit-history.d.ts +6 -0
  407. package/dist/structure/edit-history.js +27 -0
  408. package/dist/structure/export.d.ts +1 -0
  409. package/dist/structure/export.js +89 -105
  410. package/dist/structure/format-detect.d.ts +1 -0
  411. package/dist/structure/format-detect.js +20 -0
  412. package/dist/structure/geometry.d.ts +9 -0
  413. package/dist/structure/geometry.js +27 -0
  414. package/dist/structure/index.d.ts +16 -1
  415. package/dist/structure/index.js +15 -10
  416. package/dist/structure/measure.d.ts +1 -1
  417. package/dist/structure/measure.js +6 -12
  418. package/dist/structure/parse.d.ts +2 -1
  419. package/dist/structure/parse.js +272 -313
  420. package/dist/structure/partial-occupancy.js +10 -5
  421. package/dist/structure/pbc.js +85 -107
  422. package/dist/structure/polyhedra.d.ts +0 -1
  423. package/dist/structure/polyhedra.js +7 -21
  424. package/dist/structure/prop-groups.d.ts +85 -0
  425. package/dist/structure/prop-groups.js +18 -0
  426. package/dist/structure/supercell.d.ts +1 -2
  427. package/dist/structure/supercell.js +7 -13
  428. package/dist/symmetry/SymmetryElements.svelte +11 -15
  429. package/dist/symmetry/SymmetryStats.svelte +55 -71
  430. package/dist/symmetry/WyckoffTable.svelte +10 -28
  431. package/dist/symmetry/cell-transform.js +6 -14
  432. package/dist/symmetry/index.d.ts +1 -0
  433. package/dist/symmetry/index.js +13 -10
  434. package/dist/symmetry/spacegroups.js +3 -2
  435. package/dist/table/HeatmapTable.svelte +1142 -447
  436. package/dist/table/HeatmapTable.svelte.d.ts +12 -2
  437. package/dist/table/ToggleMenu.svelte +168 -53
  438. package/dist/table/ToggleMenu.svelte.d.ts +1 -1
  439. package/dist/table/index.d.ts +21 -6
  440. package/dist/table/index.js +34 -21
  441. package/dist/theme/ThemeControl.svelte +16 -8
  442. package/dist/theme/embedded.d.ts +18 -0
  443. package/dist/theme/embedded.js +206 -0
  444. package/dist/theme/index.d.ts +5 -5
  445. package/dist/theme/index.js +5 -12
  446. package/dist/theme/themes.mjs +44 -66
  447. package/dist/tooltip/KCoords.svelte +4 -1
  448. package/dist/tooltip/TooltipContent.svelte +3 -6
  449. package/dist/tooltip/TooltipContent.svelte.d.ts +1 -1
  450. package/dist/tooltip/index.d.ts +8 -1
  451. package/dist/trajectory/Trajectory.svelte +613 -386
  452. package/dist/trajectory/Trajectory.svelte.d.ts +1 -1
  453. package/dist/trajectory/TrajectoryError.svelte +12 -74
  454. package/dist/trajectory/TrajectoryExportPane.svelte +14 -32
  455. package/dist/trajectory/TrajectoryInfoPane.svelte +127 -164
  456. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +2 -1
  457. package/dist/trajectory/extract.js +61 -49
  458. package/dist/trajectory/format-detect.d.ts +2 -0
  459. package/dist/trajectory/format-detect.js +17 -13
  460. package/dist/trajectory/frame-reader.d.ts +2 -0
  461. package/dist/trajectory/frame-reader.js +35 -32
  462. package/dist/trajectory/helpers.d.ts +2 -0
  463. package/dist/trajectory/helpers.js +34 -56
  464. package/dist/trajectory/index.d.ts +1 -0
  465. package/dist/trajectory/index.js +5 -8
  466. package/dist/trajectory/parse/ase.js +1 -1
  467. package/dist/trajectory/parse/h5-utils.d.ts +13 -0
  468. package/dist/trajectory/parse/h5-utils.js +109 -0
  469. package/dist/trajectory/parse/hdf5.d.ts +1 -1
  470. package/dist/trajectory/parse/hdf5.js +116 -106
  471. package/dist/trajectory/parse/index.d.ts +6 -6
  472. package/dist/trajectory/parse/index.js +25 -33
  473. package/dist/trajectory/parse/lammps.js +8 -12
  474. package/dist/trajectory/parse/vasp.js +10 -7
  475. package/dist/trajectory/parse/vaspout-electronic.d.ts +13 -0
  476. package/dist/trajectory/parse/vaspout-electronic.js +207 -0
  477. package/dist/trajectory/parse/vaspout-h5.d.ts +4 -0
  478. package/dist/trajectory/parse/vaspout-h5.js +281 -0
  479. package/dist/trajectory/parse/xyz.js +59 -9
  480. package/dist/trajectory/plotting.d.ts +8 -9
  481. package/dist/trajectory/plotting.js +113 -64
  482. package/dist/utils.d.ts +3 -0
  483. package/dist/utils.js +7 -0
  484. package/dist/xrd/XrdPlot.svelte +79 -118
  485. package/dist/xrd/broadening.js +2 -1
  486. package/dist/xrd/calc-xrd.js +24 -62
  487. package/dist/xrd/parse.d.ts +0 -1
  488. package/dist/xrd/parse.js +69 -95
  489. package/package.json +94 -34
  490. package/readme.md +6 -5
  491. package/dist/api/mp.d.ts +0 -6
  492. package/dist/api/mp.js +0 -22
  493. package/dist/plot/sunburst/SunburstControls.svelte +0 -200
  494. package/dist/scene/types.d.ts +0 -26
  495. package/dist/tooltip/types.d.ts +0 -8
  496. package/dist/trajectory/constants.d.ts +0 -6
  497. package/dist/trajectory/constants.js +0 -11
  498. /package/dist/{scene/types.js → file-viewer/host-protocol.js} +0 -0
  499. /package/dist/{tooltip/types.js → isosurface/geometry-worker-types.js} +0 -0
@@ -1,8 +1,6 @@
1
1
  // Bonding algorithms for structure visualization
2
- import { element_data } from '../element';
2
+ import element_data, { element_by_symbol } from '../element/data';
3
3
  import * as math from '../math';
4
- // Shared per-symbol element data lookup (also used by pbc.ts and polyhedra.ts)
5
- export const element_lookup = new Map(element_data.map((el) => [el.symbol, el]));
6
4
  const covalent_radii = new Map(element_data.flatMap((el) => el.covalent_radius === null ? [] : [[el.symbol, el.covalent_radius]]));
7
5
  // Majority-occupancy element of a (possibly disordered) site
8
6
  export const get_majority_element = (site) => {
@@ -10,12 +8,39 @@ export const get_majority_element = (site) => {
10
8
  return null;
11
9
  return site.species.reduce((max, spec) => (spec.occu > max.occu ? spec : max)).element;
12
10
  };
11
+ // Large low-valent A-site cations whose coordination polyhedra (CN 8-12) tend to
12
+ // obscure the structural framework. VESTA-style figures draw the framework
13
+ // (e.g. TiO6 in BaTiO3, FeO6/PO4 in LiFePO4) and leave these as plain spheres.
14
+ // They still get polyhedra when they are the only qualifying cations (e.g. NaCl)
15
+ // or when force-included via `included_center_elements`. Shared by polyhedra.ts
16
+ // (vertex/center selection) and pbc.ts (phase-2 boundary completion) so the bond
17
+ // graph and the polyhedra it feeds stay consistent.
18
+ const HEAVY_ALKALINE_EARTHS = new Set([`Ca`, `Sr`, `Ba`, `Ra`]);
19
+ export const is_spectator_center = (element) => element_by_symbol.get(element)?.category === `alkali metal` ||
20
+ HEAVY_ALKALINE_EARTHS.has(element);
21
+ // True if the composition contains a framework cation: a non-spectator element
22
+ // strictly less electronegative than the most electronegative element present
23
+ // (i.e. one that can coordinate the anions). When true, spectator A-site cations
24
+ // are hidden from coordination polyhedra (compute_polyhedra) and skipped by phase-2
25
+ // boundary completion (find_image_atoms) - sharing this keeps the bond graph and
26
+ // the polyhedra it feeds consistent. Purely ionic binaries (NaCl, Li2O) return
27
+ // false, so the spectator IS the framework and keeps its polyhedra/completions.
28
+ export function has_framework_potential(elements) {
29
+ const els = [...new Set(elements)]; // dedupe so callers can pass per-site element lists
30
+ let max_en = -Infinity;
31
+ for (const el of els) {
32
+ const en = element_by_symbol.get(el)?.electronegativity;
33
+ if (en != null && en > max_en)
34
+ max_en = en;
35
+ }
36
+ return els.some((el) => {
37
+ if (is_spectator_center(el))
38
+ return false;
39
+ const en = element_by_symbol.get(el)?.electronegativity;
40
+ return en != null && en < max_en;
41
+ });
42
+ }
13
43
  const is_zero_cell_shift = (cell_shift) => cell_shift === undefined || cell_shift.every((val) => val === 0);
14
- const format_cell_shift = (cell_shift) => {
15
- if (cell_shift === undefined || is_zero_cell_shift(cell_shift))
16
- return ``;
17
- return `@${cell_shift.join(`,`)}`;
18
- };
19
44
  const negate_cell_shift = (cell_shift) => [
20
45
  cell_shift[0] === 0 ? 0 : -cell_shift[0],
21
46
  cell_shift[1] === 0 ? 0 : -cell_shift[1],
@@ -50,7 +75,10 @@ export const normalize_structure_bond = (site_idx_1, site_idx_2, order, cell_shi
50
75
  };
51
76
  export const get_bond_key = (idx_1, idx_2, cell_shift) => {
52
77
  const normalized = normalize_bond_endpoints(idx_1, idx_2, cell_shift);
53
- return `${normalized.site_idx_1}-${normalized.site_idx_2}${format_cell_shift(normalized.cell_shift)}`;
78
+ const shift_suffix = normalized.cell_shift === undefined || is_zero_cell_shift(normalized.cell_shift)
79
+ ? ``
80
+ : `@${normalized.cell_shift.join(`,`)}`;
81
+ return `${normalized.site_idx_1}-${normalized.site_idx_2}${shift_suffix}`;
54
82
  };
55
83
  // Remap explicit bond metadata after site deletion: drop bonds touching deleted
56
84
  // sites and shift each surviving index down by the number of deleted indices below it.
@@ -247,7 +275,6 @@ export const merge_bond_edits = (base_bonds, added, removed, overrides) => {
247
275
  }
248
276
  return [...merged.values()];
249
277
  };
250
- const is_record = (value) => typeof value === `object` && value !== null;
251
278
  export function normalize_bond_order(order) {
252
279
  if (order === `aromatic`)
253
280
  return order;
@@ -305,13 +332,14 @@ export function get_explicit_bond_metadata(structure) {
305
332
  }
306
333
  const explicit_bonds = new Map();
307
334
  for (const [entry_idx, raw_bond] of raw_bonds.entries()) {
308
- if (!is_record(raw_bond)) {
335
+ if (typeof raw_bond !== `object` || raw_bond === null) {
309
336
  console.warn(`Ignoring invalid explicit bond at index ${entry_idx}: expected object`);
310
337
  continue;
311
338
  }
312
- const { order } = raw_bond;
313
- const site_idx_1 = raw_bond.site_idx_1;
314
- const site_idx_2 = raw_bond.site_idx_2;
339
+ const bond_record = raw_bond;
340
+ const { order } = bond_record;
341
+ const site_idx_1 = bond_record.site_idx_1;
342
+ const site_idx_2 = bond_record.site_idx_2;
315
343
  if (typeof site_idx_1 !== `number` ||
316
344
  typeof site_idx_2 !== `number` ||
317
345
  !Number.isInteger(site_idx_1) ||
@@ -331,7 +359,7 @@ export function get_explicit_bond_metadata(structure) {
331
359
  console.warn(`Ignoring invalid explicit bond at index ${entry_idx}: unsupported order ${String(order)}`);
332
360
  continue;
333
361
  }
334
- const cell_shift = normalize_cell_shift(raw_bond.cell_shift);
362
+ const cell_shift = normalize_cell_shift(bond_record.cell_shift);
335
363
  if (cell_shift === null) {
336
364
  console.warn(`Ignoring invalid explicit bond at index ${entry_idx}: cell_shift must be three integers`);
337
365
  continue;
@@ -340,9 +368,7 @@ export function get_explicit_bond_metadata(structure) {
340
368
  console.warn(`Ignoring invalid explicit bond at index ${entry_idx}: endpoints match`);
341
369
  continue;
342
370
  }
343
- if (cell_shift !== undefined &&
344
- !is_zero_cell_shift(cell_shift) &&
345
- !(`lattice` in structure)) {
371
+ if (!is_zero_cell_shift(cell_shift) && !(`lattice` in structure)) {
346
372
  console.warn(`Ignoring invalid explicit bond at index ${entry_idx}: cell_shift requires a crystal lattice`);
347
373
  continue;
348
374
  }
@@ -501,11 +527,22 @@ export function compute_bond_transform(pos_1, pos_2) {
501
527
  1,
502
528
  ]);
503
529
  }
530
+ // Build a BondPair between two sites (shared by electroneg_ratio and solid_angle)
531
+ const make_bond = (sites, idx_1, idx_2, bond_length, strength) => ({
532
+ pos_1: sites[idx_1].xyz,
533
+ pos_2: sites[idx_2].xyz,
534
+ site_idx_1: idx_1,
535
+ site_idx_2: idx_2,
536
+ bond_length,
537
+ strength,
538
+ transform_matrix: compute_bond_transform(sites[idx_1].xyz, sites[idx_2].xyz),
539
+ });
504
540
  // Pack quantized cell coordinates into one integer key (exact for cell coords in
505
541
  // [-512, 511], i.e. structures up to ~1000 cells per axis - far beyond any real
506
542
  // case). Integer Map keys avoid per-lookup string building in the hot pair loop.
543
+ // Also used by pbc.ts for its phase-2 boundary-completion grid.
507
544
  const CELL_OFFSET = 512;
508
- const pack_cell_key = (x, y, z) => (x + CELL_OFFSET) * 1048576 + (y + CELL_OFFSET) * 1024 + (z + CELL_OFFSET);
545
+ export const pack_cell_key = (x, y, z) => (x + CELL_OFFSET) * 1048576 + (y + CELL_OFFSET) * 1024 + (z + CELL_OFFSET);
509
546
  // Build spatial grid by dividing 3D space into cubic cells.
510
547
  function build_spatial_grid(sites, cell_size) {
511
548
  const grid = new Map();
@@ -520,24 +557,28 @@ function build_spatial_grid(sites, cell_size) {
520
557
  return grid;
521
558
  }
522
559
  // Get all site indices in 3x3x3 cube of cells around position.
560
+ // Fills and returns a REUSED module-level array (valid until the next call):
561
+ // this runs once per bond center, so per-call allocations would dominate GC
562
+ // pressure when computing bonds for large supercells.
563
+ const scratch_neighbors = [];
523
564
  function get_neighbors_from_grid(pos, grid, cell_size) {
524
565
  const [cx, cy, cz] = [
525
566
  Math.floor(pos[0] / cell_size),
526
567
  Math.floor(pos[1] / cell_size),
527
568
  Math.floor(pos[2] / cell_size),
528
569
  ];
529
- const neighbors = [];
570
+ scratch_neighbors.length = 0;
530
571
  for (let dx = -1; dx <= 1; dx++) {
531
572
  for (let dy = -1; dy <= 1; dy++) {
532
573
  for (let dz = -1; dz <= 1; dz++) {
533
574
  const cell = grid.get(pack_cell_key(cx + dx, cy + dy, cz + dz));
534
575
  if (cell)
535
- for (const idx of cell)
536
- neighbors.push(idx);
576
+ for (const site_idx of cell)
577
+ scratch_neighbors.push(site_idx);
537
578
  }
538
579
  }
539
580
  }
540
- return neighbors;
581
+ return scratch_neighbors;
541
582
  }
542
583
  // Setup spatial decomposition for structures with >50 atoms.
543
584
  function setup_spatial_grid(sites, cutoff) {
@@ -549,6 +590,23 @@ const get_candidates = (pos, sites, spatial) => spatial
549
590
  ? get_neighbors_from_grid(pos, spatial.grid, spatial.cell_size)
550
591
  : Array.from({ length: sites.length }, (_, idx) => idx);
551
592
  export const BONDING_STRATEGIES = { electroneg_ratio, solid_angle };
593
+ // Memo for the costly neighbor search: WeakMap keyed by structure (GC'd with it), each holding a
594
+ // per-signature (strategy + JSON options) map of results. The multi-side view's 4 panes share one
595
+ // search (identical inputs, one flush); the per-signature map also lets alternating
596
+ // strategies/options on the same structure reuse earlier results instead of thrashing one slot.
597
+ const bond_memo = new WeakMap();
598
+ export function compute_bonds(structure, strategy, options = {}) {
599
+ const sig = `${strategy}:${JSON.stringify(options)}`;
600
+ let by_sig = bond_memo.get(structure);
601
+ const cached = by_sig?.get(sig);
602
+ if (cached)
603
+ return cached;
604
+ const bonds = BONDING_STRATEGIES[strategy](structure, options);
605
+ if (!by_sig)
606
+ bond_memo.set(structure, (by_sig = new Map()));
607
+ by_sig.set(sig, bonds);
608
+ return bonds;
609
+ }
552
610
  // Electronegativity-based bonding with chemical preferences.
553
611
  // This algorithm considers electronegativity differences between atoms, metal/nonmetal
554
612
  // properties, and distance to determine bond strength. Bonds are only created if the
@@ -561,7 +619,11 @@ metal_nonmetal_bonus = 1.5, // Strength bonus for metal-nonmetal bonds
561
619
  similar_electronegativity_bonus = 1.2, // Bonus for similar electronegativity
562
620
  same_species_penalty = 0.5, // Penalty for bonds between same element
563
621
  strength_threshold = 0.3, // Minimum bond strength to include in results
564
- } = {}) {
622
+ // Only iterate the first `center_count` sites as bond centers (default: all).
623
+ // Coordination coloring sets this to the original-atom count so appended PBC image
624
+ // atoms are used as neighbors but not iterated as centers — identical coordination
625
+ // for the originals (by translational symmetry), far cheaper when images dominate.
626
+ center_count = Infinity, } = {}) {
565
627
  const { sites } = structure;
566
628
  if (sites.length < 2)
567
629
  return [];
@@ -571,6 +633,7 @@ strength_threshold = 0.3, // Minimum bond strength to include in results
571
633
  // millions of candidate pairs in large supercells, so object property chains
572
634
  // and Map lookups are replaced with indexed array reads.
573
635
  const n_sites = sites.length;
636
+ const n_center = Math.min(center_count, n_sites - 1);
574
637
  const electronegs = new Float64Array(n_sites);
575
638
  const radii = new Float64Array(n_sites); // 0 = no covalent radius known
576
639
  const metal_flags = new Uint8Array(n_sites);
@@ -580,7 +643,7 @@ strength_threshold = 0.3, // Minimum bond strength to include in results
580
643
  const elem_id_lookup = new Map();
581
644
  for (let idx = 0; idx < n_sites; idx++) {
582
645
  const elem = get_majority_element(sites[idx]);
583
- const data = elem ? element_lookup.get(elem) : undefined;
646
+ const data = elem ? element_by_symbol.get(elem) : undefined;
584
647
  electronegs[idx] = data?.electronegativity ?? 2.0;
585
648
  metal_flags[idx] = data?.metal ? 1 : 0;
586
649
  nonmetal_flags[idx] = data?.nonmetal ? 1 : 0;
@@ -608,7 +671,7 @@ strength_threshold = 0.3, // Minimum bond strength to include in results
608
671
  const max_cutoff = max_radius * 2 * max_distance_ratio;
609
672
  const spatial = setup_spatial_grid(sites, max_cutoff);
610
673
  const potential_bonds = [];
611
- for (let idx_a = 0; idx_a < sites.length - 1; idx_a++) {
674
+ for (let idx_a = 0; idx_a < n_center; idx_a++) {
612
675
  const radius_a = radii[idx_a];
613
676
  if (radius_a === 0)
614
677
  continue; // no covalent radius -> no pairs (symmetric: idx_b skips too)
@@ -700,15 +763,7 @@ strength_threshold = 0.3, // Minimum bond strength to include in results
700
763
  strength *= Math.exp(-(norm_dist / closest_dist_b - 1) / 0.5);
701
764
  }
702
765
  if (strength > strength_threshold) {
703
- bonds.push({
704
- pos_1: sites[site_idx_1].xyz,
705
- pos_2: sites[site_idx_2].xyz,
706
- site_idx_1,
707
- site_idx_2,
708
- bond_length: dist,
709
- strength,
710
- transform_matrix: compute_bond_transform(sites[site_idx_1].xyz, sites[site_idx_2].xyz),
711
- });
766
+ bonds.push(make_bond(sites, site_idx_1, site_idx_2, dist, strength));
712
767
  }
713
768
  }
714
769
  return apply_explicit_bond_metadata(structure, bonds);
@@ -718,7 +773,8 @@ strength_threshold = 0.3, // Minimum bond strength to include in results
718
773
  // This algorithm computes bond strength based on the solid angle subtended by atoms
719
774
  // and their distance penalty. Bonds are only created if the computed strength exceeds
720
775
  // the strength_threshold parameter.
721
- export function solid_angle(structure, { min_solid_angle = 0.01, min_face_area = 0.05, max_distance = 5.0, min_bond_dist = 0.4, strength_threshold = 0.05, } = {}) {
776
+ export function solid_angle(structure, { min_solid_angle = 0.01, min_face_area = 0.05, max_distance = 5.0, min_bond_dist = 0.4, strength_threshold = 0.05, center_count = Infinity, // see electroneg_ratio: limit bond centers to first N sites
777
+ } = {}) {
722
778
  const { sites } = structure;
723
779
  if (sites.length < 2)
724
780
  return [];
@@ -726,7 +782,8 @@ export function solid_angle(structure, { min_solid_angle = 0.01, min_face_area =
726
782
  const min_dist_sq = min_bond_dist ** 2;
727
783
  const max_dist_sq = max_distance ** 2;
728
784
  const spatial = setup_spatial_grid(sites, max_distance);
729
- for (let idx_a = 0; idx_a < sites.length - 1; idx_a++) {
785
+ const n_center = Math.min(center_count, sites.length - 1);
786
+ for (let idx_a = 0; idx_a < n_center; idx_a++) {
730
787
  const [x1, y1, z1] = sites[idx_a].xyz;
731
788
  const elem_a = get_majority_element(sites[idx_a]);
732
789
  const radius_a = elem_a ? covalent_radii.get(elem_a) : undefined;
@@ -751,15 +808,7 @@ export function solid_angle(structure, { min_solid_angle = 0.01, min_face_area =
751
808
  const angle_strength = Math.min(bond_solid_angle / (4.0 * Math.PI), 1.0);
752
809
  const strength = angle_strength * dist_penalty;
753
810
  if (strength > strength_threshold) {
754
- bonds.push({
755
- pos_1: sites[idx_a].xyz,
756
- pos_2: sites[idx_b].xyz,
757
- site_idx_1: idx_a,
758
- site_idx_2: idx_b,
759
- bond_length: dist,
760
- strength,
761
- transform_matrix: compute_bond_transform(sites[idx_a].xyz, sites[idx_b].xyz),
762
- });
811
+ bonds.push(make_bond(sites, idx_a, idx_b, dist, strength));
763
812
  }
764
813
  }
765
814
  }
@@ -0,0 +1,6 @@
1
+ export type HistoryStacks<T> = [undo_stack: T[], redo_stack: T[]];
2
+ export declare function push_edit<T>([undo_stack]: HistoryStacks<T>, snapshot: T, max_history: number): HistoryStacks<T>;
3
+ export declare function step_history<T>([undo_stack, redo_stack]: HistoryStacks<T>, direction: `undo` | `redo`, current: T): {
4
+ stacks: HistoryStacks<T>;
5
+ restored: T;
6
+ } | null;
@@ -0,0 +1,27 @@
1
+ // Pure undo/redo stack mechanics for Structure.svelte's edit-atoms history.
2
+ // Stacks are treated as immutable (updates return new arrays) so they work with
3
+ // $state.raw holders where only reassignment is reactive. Kept free of
4
+ // component state so the real logic (not a test-local mirror) is unit-testable.
5
+ // Record a new edit: push `snapshot` onto the undo stack (trimming to
6
+ // `max_history` entries) and invalidate the redo stack.
7
+ export function push_edit([undo_stack], snapshot, max_history) {
8
+ const trimmed = undo_stack.length >= max_history
9
+ ? undo_stack.slice(undo_stack.length - max_history + 1)
10
+ : undo_stack;
11
+ return [[...trimmed, snapshot], []];
12
+ }
13
+ // Step the history in `direction`: pop that stack's top as the state to
14
+ // restore, pushing `current` onto the opposite stack. Returns null when there
15
+ // is nothing to step to (callers should snapshot `current` lazily by checking
16
+ // stack length first if snapshots are expensive).
17
+ export function step_history([undo_stack, redo_stack], direction, current) {
18
+ const source = direction === `undo` ? undo_stack : redo_stack;
19
+ const restored = source.at(-1);
20
+ if (restored === undefined)
21
+ return null;
22
+ const remaining = source.slice(0, -1);
23
+ const stacks = direction === `undo`
24
+ ? [remaining, [...redo_stack, current]]
25
+ : [[...undo_stack, current], remaining];
26
+ return { stacks, restored };
27
+ }
@@ -7,6 +7,7 @@ export declare function has_color_property(mat: Material): mat is Material & {
7
7
  export declare function extract_bond_color_for_instance(geometry: BufferGeometry, instance_idx: number): Color | null;
8
8
  export declare function clean_geometry_for_export(geometry: BufferGeometry): void;
9
9
  export declare function generate_mtl_content(scene: Scene): string;
10
+ export declare function convert_instanced_meshes_to_regular(scene: Scene): Scene;
10
11
  export declare function create_structure_filename(structure: AnyStructure | undefined, extension: string): string;
11
12
  export declare function structure_to_xyz_str(structure?: AnyStructure): string;
12
13
  export declare function structure_to_cif_str(structure?: AnyStructure): string;
@@ -6,22 +6,15 @@ import { Color, Group, Matrix4, Mesh, MeshStandardMaterial, ShaderMaterial } fro
6
6
  import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';
7
7
  import { OBJExporter } from 'three/examples/jsm/exporters/OBJExporter.js';
8
8
  // @internal exported only for tests - not part of the public API.
9
- // Type guard to check if a material has a color property (duck typing for bundler
10
- // compatibility across different Three.js instances - Threlte vs vanilla Three.js).
9
+ // Type guard to check if a material has a Color-like property with numeric r/g/b
10
+ // channels (duck typing for bundler compatibility across different Three.js
11
+ // instances - Threlte vs vanilla Three.js).
11
12
  export function has_color_property(mat) {
12
- if (!(`color` in mat))
13
- return false;
14
13
  const color = mat.color;
15
14
  if (!color || typeof color !== `object`)
16
15
  return false;
17
- // Check for Color-like object with numeric r/g/b channels (duck typing)
18
- const color_obj = color;
19
- const red_channel = color_obj.r;
20
- const green_channel = color_obj.g;
21
- const blue_channel = color_obj.b;
22
- return (typeof red_channel === `number` &&
23
- typeof green_channel === `number` &&
24
- typeof blue_channel === `number`);
16
+ const { r: red, g: green, b: blue } = color;
17
+ return typeof red === `number` && typeof green === `number` && typeof blue === `number`;
25
18
  }
26
19
  // Extract color from a ShaderMaterial by checking common color uniform patterns
27
20
  function extract_shader_color(shader_mat) {
@@ -34,8 +27,8 @@ function extract_shader_color(shader_mat) {
34
27
  return uniforms[key].value.clone();
35
28
  }
36
29
  }
37
- // For gradient bonds, try to extract midpoint color from instanceColorStart/End attributes
38
- // These are set as geometry attributes, not uniforms, so we return a default gray
30
+ // Gradient bonds store colors as instanceColorStart/End geometry attributes,
31
+ // not uniforms nothing to extract here (caller falls back to gray)
39
32
  return null;
40
33
  }
41
34
  // Convert ShaderMaterial to MeshStandardMaterial for export compatibility
@@ -123,9 +116,10 @@ export function generate_mtl_content(scene) {
123
116
  // Get diffuse color (main color)
124
117
  if (has_color_property(mat)) {
125
118
  const color = mat.color;
126
- lines.push(`Kd ${color.r.toFixed(6)} ${color.g.toFixed(6)} ${color.b.toFixed(6)}`);
119
+ const fmt = (val) => val.toFixed(6);
120
+ lines.push(`Kd ${fmt(color.r)} ${fmt(color.g)} ${fmt(color.b)}`);
127
121
  // Ambient is typically a fraction of diffuse
128
- lines.push(`Ka ${(color.r * 0.2).toFixed(6)} ${(color.g * 0.2).toFixed(6)} ${(color.b * 0.2).toFixed(6)}`);
122
+ lines.push(`Ka ${fmt(color.r * 0.2)} ${fmt(color.g * 0.2)} ${fmt(color.b * 0.2)}`);
129
123
  }
130
124
  else {
131
125
  // Default white if no color
@@ -145,19 +139,33 @@ export function generate_mtl_content(scene) {
145
139
  });
146
140
  return lines.join(`\n`);
147
141
  }
148
- // Extract color from material, returning RGB values or null if not found
149
- function extract_material_color(mat) {
150
- if (has_color_property(mat)) {
151
- return { r: mat.color.r, g: mat.color.g, b: mat.color.b };
152
- }
153
- return null;
154
- }
155
142
  // Helper function to convert InstancedMesh to regular Mesh objects for export
156
143
  // This is necessary because GLB/OBJ exporters don't handle InstancedMesh properly
157
144
  // Note: Threlte's InstancedMesh sets isInstancedMesh=true but type remains "Mesh"
158
145
  // Type guard for InstancedMesh (Three.js uses isInstancedMesh property, not exposed in Object3D type)
159
146
  const is_instanced_mesh = (obj) => obj.isInstancedMesh || obj.type === `InstancedMesh`;
160
- function convert_instanced_meshes_to_regular(scene) {
147
+ // Resolve the export color for one instance of an InstancedMesh. Precedence:
148
+ // gradient bond midpoints (shader bonds), then per-instance colors on meshes
149
+ // flagged userData.per_instance_color (atoms/arrows keep a white base material
150
+ // and store real colors in the instanceColor buffer), then the shared material
151
+ // color (legacy threlte-instanced meshes carry an all-white instanceColor that
152
+ // must NOT win), then instanceColor as a last resort. null = keep default.
153
+ function resolve_instance_material_color(instanced_mesh, instance_idx, bond_colors, stored_color) {
154
+ const bond_color = bond_colors?.get(instance_idx);
155
+ if (bond_color)
156
+ return bond_color;
157
+ const { instanceColor } = instanced_mesh;
158
+ const per_instance = instanceColor
159
+ ? new Color(instanceColor.getX(instance_idx), instanceColor.getY(instance_idx), instanceColor.getZ(instance_idx))
160
+ : null;
161
+ if (instanced_mesh.userData.per_instance_color && per_instance)
162
+ return per_instance;
163
+ if (stored_color)
164
+ return new Color(stored_color.r, stored_color.g, stored_color.b);
165
+ return per_instance;
166
+ }
167
+ // @internal exported only for tests - not part of the public API.
168
+ export function convert_instanced_meshes_to_regular(scene) {
161
169
  // STEP 1: Collect material colors from ORIGINAL scene BEFORE cloning
162
170
  // This is crucial because scene.clone() may not properly preserve Threlte's material colors
163
171
  const material_colors = new Map();
@@ -187,25 +195,29 @@ function convert_instanced_meshes_to_regular(scene) {
187
195
  else {
188
196
  // Extract shared material color for atoms
189
197
  const single_mat = Array.isArray(mat) ? mat[0] : mat;
190
- const color = extract_material_color(single_mat);
191
- if (color) {
192
- material_colors.set(mesh_id, color);
198
+ if (has_color_property(single_mat)) {
199
+ material_colors.set(mesh_id, {
200
+ r: single_mat.color.r,
201
+ g: single_mat.color.g,
202
+ b: single_mat.color.b,
203
+ });
193
204
  }
194
205
  }
195
206
  });
196
207
  // STEP 2: Clone the scene
197
208
  const cloned_scene = scene.clone();
198
- // STEP 3: Find all InstancedMesh objects in the cloned scene and build uuid mapping
199
- const original_meshes = [];
200
- const cloned_meshes = [];
201
- scene.traverse((object) => {
202
- if (is_instanced_mesh(object))
203
- original_meshes.push(object);
204
- });
205
- cloned_scene.traverse((object) => {
206
- if (is_instanced_mesh(object))
207
- cloned_meshes.push(object);
208
- });
209
+ // STEP 3: Find all InstancedMesh objects in original + cloned scene (same traversal
210
+ // order) to map cloned meshes back to their original uuid
211
+ const collect_instanced = (root) => {
212
+ const meshes = [];
213
+ root.traverse((object) => {
214
+ if (is_instanced_mesh(object))
215
+ meshes.push(object);
216
+ });
217
+ return meshes;
218
+ };
219
+ const original_meshes = collect_instanced(scene);
220
+ const cloned_meshes = collect_instanced(cloned_scene);
209
221
  // STEP 4: Convert each InstancedMesh to individual Mesh objects
210
222
  for (let mesh_idx = 0; mesh_idx < cloned_meshes.length; mesh_idx++) {
211
223
  const instanced_mesh = cloned_meshes[mesh_idx];
@@ -244,24 +256,10 @@ function convert_instanced_meshes_to_regular(scene) {
244
256
  roughness: 0.5,
245
257
  });
246
258
  new_material.name = `material_${mesh_idx}_${idx}`;
247
- // Apply the correct color
248
- const bond_color = stored_bond_colors?.get(idx);
249
- if (bond_color) {
250
- // Bond with gradient color - use stored midpoint color
251
- new_material.color.copy(bond_color);
252
- }
253
- else if (stored_color) {
254
- // Atom with shared material color
255
- new_material.color.setRGB(stored_color.r, stored_color.g, stored_color.b);
256
- }
257
- else if (instanced_mesh.instanceColor) {
258
- // Fallback: per-instance colors from instanceColor attribute
259
- const color_r = instanced_mesh.instanceColor.getX(idx);
260
- const color_g = instanced_mesh.instanceColor.getY(idx);
261
- const color_b = instanced_mesh.instanceColor.getZ(idx);
262
- new_material.color.setRGB(color_r, color_g, color_b);
263
- }
264
- // If no color found, material stays default white
259
+ // Apply the correct color (null = no color found, material stays default white)
260
+ const resolved_color = resolve_instance_material_color(instanced_mesh, idx, stored_bond_colors, stored_color);
261
+ if (resolved_color)
262
+ new_material.color.copy(resolved_color);
265
263
  const mesh = new Mesh(cloned_geometry, new_material);
266
264
  // Combine base transform with instance transform
267
265
  const combined_matrix = new Matrix4();
@@ -321,26 +319,18 @@ export function create_structure_filename(structure, extension) {
321
319
  if (formula && formula !== `Unknown`) {
322
320
  safe_push(formula.replaceAll(` `, ``));
323
321
  }
324
- // Add space group if available
325
- if (`symmetry` in structure &&
326
- structure.symmetry &&
327
- typeof structure.symmetry === `object` &&
328
- `space_group_symbol` in structure.symmetry) {
329
- const space_group = structure.symmetry.space_group_symbol;
330
- if (space_group && typeof space_group === `string`) {
331
- safe_push(space_group.replaceAll(` `, ``));
332
- }
333
- }
334
- // Add lattice system if available
335
- if (`lattice` in structure &&
336
- structure.lattice &&
337
- typeof structure.lattice === `object` &&
338
- `lattice_system` in structure.lattice) {
339
- const lattice_system = structure.lattice.lattice_system;
340
- if (lattice_system && typeof lattice_system === `string`) {
341
- safe_push(lattice_system);
342
- }
322
+ // Add space group and lattice system if available
323
+ const symmetry = `symmetry` in structure && is_plain_object(structure.symmetry)
324
+ ? structure.symmetry
325
+ : undefined;
326
+ if (typeof symmetry?.space_group_symbol === `string`) {
327
+ safe_push(symmetry.space_group_symbol.replaceAll(` `, ``));
343
328
  }
329
+ const lattice = `lattice` in structure && is_plain_object(structure.lattice)
330
+ ? structure.lattice
331
+ : undefined;
332
+ if (lattice && `lattice_system` in lattice && typeof lattice.lattice_system === `string`)
333
+ safe_push(lattice.lattice_system);
344
334
  // Add number of sites
345
335
  if (structure.sites?.length)
346
336
  parts.push(`${structure.sites.length}sites`);
@@ -372,9 +362,12 @@ export function structure_to_xyz_str(structure) {
372
362
  const formula = get_electro_neg_formula(structure, true);
373
363
  if (formula && formula !== `Unknown`)
374
364
  comment_parts.push(formula);
365
+ const lattice_matrix = `lattice` in structure && structure.lattice?.matrix?.length === 3
366
+ ? structure.lattice.matrix
367
+ : null;
375
368
  // Include extended XYZ lattice information when available so round-trips preserve lattice
376
- if (`lattice` in structure && structure.lattice?.matrix?.length === 3) {
377
- const lattice_values = structure.lattice.matrix
369
+ if (lattice_matrix) {
370
+ const lattice_values = lattice_matrix
378
371
  .flatMap((row) => row.map((value) => (Number.isFinite(value) ? value : 0).toFixed(8)))
379
372
  .join(` `);
380
373
  comment_parts.push(`Lattice="${lattice_values}"`);
@@ -382,9 +375,7 @@ export function structure_to_xyz_str(structure) {
382
375
  const comment = comment_parts.length > 0 ? comment_parts.join(` `) : `Generated from structure`;
383
376
  lines.push(comment);
384
377
  // Cache converter for fractional→Cartesian (if lattice available)
385
- const frac_to_cart = `lattice` in structure && structure.lattice?.matrix?.length === 3
386
- ? math.create_frac_to_cart(structure.lattice.matrix)
387
- : null;
378
+ const frac_to_cart = lattice_matrix ? math.create_frac_to_cart(lattice_matrix) : null;
388
379
  // Atom lines: element symbol followed by x, y, z coordinates
389
380
  for (const site of structure.sites) {
390
381
  const element_symbol = site_element(site);
@@ -456,21 +447,14 @@ export function structure_to_cif_str(structure) {
456
447
  }
457
448
  const lines = [];
458
449
  // CIF header with data block (required by pymatgen and CIF spec)
459
- lines.push(`# CIF file generated by MatterViz`);
460
- const block_name = get_cif_block_name(structure);
461
- lines.push(`data_${block_name}`);
462
- lines.push(``);
450
+ lines.push(`# CIF file generated by MatterViz`, `data_${get_cif_block_name(structure)}`, ``);
463
451
  // Cell parameters
464
452
  const lattice = structure.lattice;
465
453
  if (lattice.a && lattice.b && lattice.c) {
466
- lines.push(`_cell_length_a ${lattice.a.toFixed(6)}`);
467
- lines.push(`_cell_length_b ${lattice.b.toFixed(6)}`);
468
- lines.push(`_cell_length_c ${lattice.c.toFixed(6)}`);
454
+ lines.push(`_cell_length_a ${lattice.a.toFixed(6)}`, `_cell_length_b ${lattice.b.toFixed(6)}`, `_cell_length_c ${lattice.c.toFixed(6)}`);
469
455
  }
470
456
  if (lattice.alpha && lattice.beta && lattice.gamma) {
471
- lines.push(`_cell_angle_alpha ${lattice.alpha.toFixed(6)}`);
472
- lines.push(`_cell_angle_beta ${lattice.beta.toFixed(6)}`);
473
- lines.push(`_cell_angle_gamma ${lattice.gamma.toFixed(6)}`);
457
+ lines.push(`_cell_angle_alpha ${lattice.alpha.toFixed(6)}`, `_cell_angle_beta ${lattice.beta.toFixed(6)}`, `_cell_angle_gamma ${lattice.gamma.toFixed(6)}`);
474
458
  }
475
459
  // Space group information
476
460
  if (`symmetry` in structure && is_plain_object(structure.symmetry)) {
@@ -489,13 +473,7 @@ export function structure_to_cif_str(structure) {
489
473
  // full P1 list, so without it parsers would re-apply the H-M ops and multiply sites
490
474
  lines.push(`loop_`, `_symmetry_equiv_pos_as_xyz`, ` 'x, y, z'`, ``);
491
475
  // Atom site loop header
492
- lines.push(`loop_`);
493
- lines.push(`_atom_site_label`);
494
- lines.push(`_atom_site_type_symbol`);
495
- lines.push(`_atom_site_fract_x`);
496
- lines.push(`_atom_site_fract_y`);
497
- lines.push(`_atom_site_fract_z`);
498
- lines.push(`_atom_site_occupancy`);
476
+ lines.push(`loop_`, `_atom_site_label`, `_atom_site_type_symbol`, `_atom_site_fract_x`, `_atom_site_fract_y`, `_atom_site_fract_z`, `_atom_site_occupancy`);
499
477
  // Cache inverse transpose for Cartesian→fractional conversion (avoids recomputing per site)
500
478
  const cart_to_frac = lattice.matrix?.length === 3 ? math.create_cart_to_frac(lattice.matrix) : null;
501
479
  // Atom sites: one row per species entry so disordered (multi-species) sites
@@ -536,11 +514,10 @@ export function structure_to_poscar_str(structure) {
536
514
  lines.push(`1.0`); // Scale factor (1.0 for direct coordinates)
537
515
  const lattice = structure.lattice;
538
516
  if (lattice.matrix && Array.isArray(lattice.matrix) && lattice.matrix.length >= 3) {
539
- // Convert 3x3 matrix to 3 vectors
540
- const matrix = lattice.matrix;
541
- lines.push(`${matrix[0][0].toFixed(8)} ${matrix[0][1].toFixed(8)} ${matrix[0][2].toFixed(8)}`);
542
- lines.push(`${matrix[1][0].toFixed(8)} ${matrix[1][1].toFixed(8)} ${matrix[1][2].toFixed(8)}`);
543
- lines.push(`${matrix[2][0].toFixed(8)} ${matrix[2][1].toFixed(8)} ${matrix[2][2].toFixed(8)}`);
517
+ // One line per lattice vector, exactly 3 components at 8-decimal fixed precision
518
+ for (const vec of lattice.matrix.slice(0, 3)) {
519
+ lines.push([vec[0], vec[1], vec[2]].map((coord) => coord.toFixed(8)).join(` `));
520
+ }
544
521
  }
545
522
  else {
546
523
  throw new Error(`No valid lattice matrix for POSCAR export`);
@@ -572,16 +549,23 @@ export function structure_to_poscar_str(structure) {
572
549
  for (const group of sites_by_element.values()) {
573
550
  for (const site of group) {
574
551
  const frac_coords = get_frac_coords(site, cart_to_frac);
575
- let selective_dynamics_str = ``;
552
+ const coords_str = frac_coords
553
+ .slice(0, 3)
554
+ .map((coord) => coord.toFixed(8))
555
+ .join(` `);
556
+ let sel_dyn_str = ``;
576
557
  if (has_selective_dynamics) {
577
558
  const sel_dyn = (site.properties?.selective_dynamics ?? [
578
559
  true,
579
560
  true,
580
561
  true,
581
562
  ]);
582
- selective_dynamics_str = ` ${sel_dyn[0] ? `T` : `F`} ${sel_dyn[1] ? `T` : `F`} ${sel_dyn[2] ? `T` : `F`}`;
563
+ sel_dyn_str = ` ${sel_dyn
564
+ .slice(0, 3)
565
+ .map((flag) => (flag ? `T` : `F`))
566
+ .join(` `)}`;
583
567
  }
584
- lines.push(`${frac_coords[0].toFixed(8)} ${frac_coords[1].toFixed(8)} ${frac_coords[2].toFixed(8)}${selective_dynamics_str}`);
568
+ lines.push(`${coords_str}${sel_dyn_str}`);
585
569
  }
586
570
  }
587
571
  return lines.join(`\n`);
@@ -0,0 +1 @@
1
+ export declare function is_structure_file(filename: string): boolean;