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
@@ -68,7 +68,8 @@
68
68
  !(current_target instanceof Node) ||
69
69
  !(next_target instanceof Node) ||
70
70
  !current_target.contains(next_target)
71
- ) menu_open = false
71
+ )
72
+ menu_open = false
72
73
  }
73
74
 
74
75
  function handle_key_down(event: KeyboardEvent, submit_on_enter: boolean = false) {
@@ -113,9 +114,9 @@
113
114
  style="--spinner-border-width: 2px; --spinner-size: 1em; --spinner-margin: 0; display: inline-block; vertical-align: middle"
114
115
  />
115
116
  {:else}
116
- {cell_type !== `original` ? `${cell_labels[cell_type]} ` : ``}{
117
- format_supercell_label(supercell_scaling)
118
- }
117
+ {cell_type !== `original` ? `${cell_labels[cell_type]} ` : ``}{format_supercell_label(
118
+ supercell_scaling,
119
+ )}
119
120
  {/if}
120
121
  </button>
121
122
 
@@ -131,8 +132,8 @@
131
132
  {@const disabled = type !== `original` && !sym_data}
132
133
  {@const label = cell_labels[type]}
133
134
  {@const tooltip_text = disabled
134
- ? `${cell_tooltips[type]} - requires symmetry data`
135
- : cell_tooltips[type]}
135
+ ? `${cell_tooltips[type]} - requires symmetry data`
136
+ : cell_tooltips[type]}
136
137
  <button
137
138
  class="cell-type-btn"
138
139
  class:selected={cell_type === type}
@@ -282,16 +283,8 @@
282
283
  }
283
284
  .cell-type-btn.selected {
284
285
  color: var(--cell-select-accent);
285
- background: color-mix(
286
- in srgb,
287
- var(--cell-select-accent) 18%,
288
- var(--cell-select-surface)
289
- );
290
- border-color: color-mix(
291
- in srgb,
292
- var(--cell-select-accent) 45%,
293
- var(--cell-select-border)
294
- );
286
+ background: color-mix(in srgb, var(--cell-select-accent) 18%, var(--cell-select-surface));
287
+ border-color: color-mix(in srgb, var(--cell-select-accent) 45%, var(--cell-select-border));
295
288
  }
296
289
  .cell-type-btn.disabled {
297
290
  opacity: 0.4;
@@ -319,16 +312,8 @@
319
312
  }
320
313
  .preset-btn.selected {
321
314
  color: var(--cell-select-accent);
322
- background: color-mix(
323
- in srgb,
324
- var(--cell-select-accent) 18%,
325
- var(--cell-select-surface)
326
- );
327
- border-color: color-mix(
328
- in srgb,
329
- var(--cell-select-accent) 45%,
330
- var(--cell-select-border)
331
- );
315
+ background: color-mix(in srgb, var(--cell-select-accent) 18%, var(--cell-select-surface));
316
+ border-color: color-mix(in srgb, var(--cell-select-accent) 45%, var(--cell-select-border));
332
317
  }
333
318
 
334
319
  .custom-input-row {
@@ -2,48 +2,32 @@
2
2
  import type { Vec3 } from '../math'
3
3
  import { T } from '@threlte/core'
4
4
  import type { ComponentProps } from 'svelte'
5
- import { Euler, Quaternion, Vector3 } from 'three'
5
+ import { cylinder_between } from './geometry'
6
6
 
7
- let { from, to, color = `#808080`, thickness = 0.1, opacity = 1, ...rest }:
8
- & ComponentProps<typeof T.Mesh>
9
- & {
10
- from: Vec3
11
- to: Vec3
12
- color?: string
13
- thickness?: number
14
- opacity?: number // < 1 renders semi/fully transparent (e.g. invisible hover proxies)
15
- } = $props()
7
+ let {
8
+ from,
9
+ to,
10
+ color = `#808080`,
11
+ thickness = 0.1,
12
+ opacity = 1,
13
+ ...rest
14
+ }: ComponentProps<typeof T.Mesh> & {
15
+ from: Vec3
16
+ to: Vec3
17
+ color?: string
18
+ thickness?: number
19
+ opacity?: number // < 1 renders semi/fully transparent (e.g. invisible hover proxies)
20
+ } = $props()
16
21
 
17
- let from_vec = $derived(new Vector3(...from))
18
- let to_vec = $derived(new Vector3(...to))
19
- let { position, rotation, height } = $derived(calc_bond(from_vec, to_vec))
20
-
21
- function calc_bond(
22
- start_vec: Vector3,
23
- end_vec: Vector3,
24
- ): { position: Vec3; rotation: Vec3; height: number } {
25
- // find the axis of the cylinder
26
- const delta_vec = end_vec.clone().sub(start_vec)
27
- // length of the cylinder
28
- const bond_height = delta_vec.length()
29
- // calculate position (midpoint between from and to)
30
- const bond_position = start_vec
31
- .clone()
32
- .add(delta_vec.multiplyScalar(0.5))
33
- .toArray() as Vec3
34
- // calculate rotation
35
- const quaternion = new Quaternion().setFromUnitVectors(
36
- new Vector3(0, 1, 0),
37
- delta_vec.normalize(),
38
- )
39
- const euler = new Euler().setFromQuaternion(quaternion)
40
- const bond_rotation: Vec3 = [euler.x, euler.y, euler.z]
41
- // return results
42
- return { height: bond_height, position: bond_position, rotation: bond_rotation }
43
- }
22
+ let { position, rotation, length } = $derived(cylinder_between(from, to))
44
23
  </script>
45
24
 
46
- <T.Mesh {...rest} {position} {rotation} scale={[thickness, height, thickness]}>
47
- <T.CylinderGeometry args={[thickness, thickness, 1, 8]} />
48
- <T.MeshStandardMaterial {color} transparent={opacity < 1} {opacity} depthWrite={opacity >= 1} />
25
+ <T.Mesh {...rest} {position} {rotation} scale={[thickness, length, thickness]}>
26
+ <T.CylinderGeometry args={[1, 1, 1, 8]} />
27
+ <T.MeshStandardMaterial
28
+ {color}
29
+ transparent={opacity < 1}
30
+ {opacity}
31
+ depthWrite={opacity >= 1}
32
+ />
49
33
  </T.Mesh>
@@ -0,0 +1,114 @@
1
+ <script lang="ts">
2
+ // All atoms of one visual class (base or ghosted PBC image) in a single
3
+ // THREE.InstancedMesh: one draw call and zero per-atom Svelte components.
4
+ // Per-atom colors live in the instanceColor buffer, per-atom position/radius
5
+ // in the instanceMatrix buffer. Pointer handlers spread onto the mesh receive
6
+ // threlte intersection events whose `instanceId` indexes into `atoms`.
7
+ //
8
+ // This replaces one <extras.Instance> component (plus one scene-graph Group and
9
+ // one interactivity registration) per atom, which made structure changes on
10
+ // supercells block the main thread for seconds and hover raycasts O(n²).
11
+ import type { Vec3 } from '../math'
12
+ import { T, useThrelte } from '@threlte/core'
13
+ import { untrack } from 'svelte'
14
+ import { Color, InstancedMesh, Matrix4, MeshStandardMaterial, SphereGeometry } from 'three'
15
+
16
+ type InstancedAtom = {
17
+ position: Vec3
18
+ radius: number
19
+ color?: string
20
+ }
21
+
22
+ let {
23
+ atoms,
24
+ sphere_segments = 20,
25
+ ghost = false,
26
+ ...pointer_props
27
+ }: {
28
+ atoms: InstancedAtom[]
29
+ sphere_segments?: number
30
+ // edit-mode PBC image atoms: desaturated + translucent
31
+ ghost?: boolean
32
+ // threlte interactivity handlers (onpointerenter, onclick, ...) forwarded to the mesh
33
+ [key: string]: unknown
34
+ } = $props()
35
+
36
+ const { invalidate } = useThrelte()
37
+
38
+ // One material shared across mesh recreations; per-atom colors come from the
39
+ // instanceColor buffer so the base color stays white.
40
+ const material = new MeshStandardMaterial()
41
+ $effect(() => () => material.dispose())
42
+
43
+ $effect(() => {
44
+ material.transparent = ghost
45
+ material.opacity = ghost ? 0.5 : 1
46
+ material.needsUpdate = true
47
+ invalidate()
48
+ })
49
+
50
+ let geometry = $state.raw<SphereGeometry | null>(null)
51
+ $effect(() => {
52
+ const geo = new SphereGeometry(0.5, sphere_segments, sphere_segments)
53
+ geometry = geo
54
+ return () => geo.dispose()
55
+ })
56
+
57
+ // Recreate the mesh only when capacity must change (instanceMatrix buffer size
58
+ // is fixed at construction); data updates just rewrite the buffers below.
59
+ let mesh = $state.raw<InstancedMesh | null>(null)
60
+ $effect(() => {
61
+ const count = atoms.length
62
+ const prev = untrack(() => mesh)
63
+ if (prev && prev.count === count) return
64
+ prev?.dispose()
65
+ if (count === 0) {
66
+ mesh = null
67
+ return
68
+ }
69
+ const next = new InstancedMesh(untrack(() => geometry) ?? undefined, material, count)
70
+ next.frustumCulled = false
71
+ // export.ts reads per-instance colors (instead of the material color) when set
72
+ next.userData.per_instance_color = true
73
+ mesh = next
74
+ })
75
+ // Unmount-only cleanup (a cleanup on the effect above would dispose the mesh
76
+ // on every re-run, including runs that keep it; cleanups run untracked)
77
+ $effect(() => () => mesh?.dispose())
78
+
79
+ $effect(() => {
80
+ if (mesh && geometry && mesh.geometry !== geometry) {
81
+ mesh.geometry = geometry
82
+ invalidate()
83
+ }
84
+ })
85
+
86
+ const scratch_matrix = new Matrix4()
87
+ const scratch_color = new Color()
88
+ const gray = new Color(0x999999)
89
+
90
+ $effect(() => {
91
+ const current = mesh
92
+ if (!current) return
93
+ const limit = Math.min(atoms.length, current.count)
94
+ for (let idx = 0; idx < limit; idx++) {
95
+ const { position, radius, color } = atoms[idx]
96
+ scratch_matrix
97
+ .makeScale(radius, radius, radius)
98
+ .setPosition(position[0], position[1], position[2])
99
+ current.setMatrixAt(idx, scratch_matrix)
100
+ scratch_color.set(color ?? gray)
101
+ if (ghost) scratch_color.lerp(gray, 0.4)
102
+ current.setColorAt(idx, scratch_color)
103
+ }
104
+ current.instanceMatrix.needsUpdate = true
105
+ if (current.instanceColor) current.instanceColor.needsUpdate = true
106
+ // keep the whole-mesh bounding sphere in sync so raycasts can early-reject
107
+ current.computeBoundingSphere()
108
+ invalidate()
109
+ })
110
+ </script>
111
+
112
+ {#if mesh}
113
+ <T is={mesh} {...pointer_props} />
114
+ {/if}
@@ -0,0 +1,15 @@
1
+ import type { Vec3 } from '../math';
2
+ type InstancedAtom = {
3
+ position: Vec3;
4
+ radius: number;
5
+ color?: string;
6
+ };
7
+ type $$ComponentProps = {
8
+ atoms: InstancedAtom[];
9
+ sphere_segments?: number;
10
+ ghost?: boolean;
11
+ [key: string]: unknown;
12
+ };
13
+ declare const InstancedAtoms: import("svelte").Component<$$ComponentProps, {}, "">;
14
+ type InstancedAtoms = ReturnType<typeof InstancedAtoms>;
15
+ export default InstancedAtoms;
@@ -5,15 +5,10 @@
5
5
  import * as math from '../math'
6
6
  import { DEFAULTS } from '../settings'
7
7
  import { CanvasTooltip } from './'
8
+ import Arrow from './Arrow.svelte'
9
+ import Cylinder from './Cylinder.svelte'
8
10
  import { T } from '@threlte/core'
9
- import {
10
- BoxGeometry,
11
- EdgesGeometry,
12
- Euler,
13
- Matrix4,
14
- Quaternion,
15
- Vector3,
16
- } from 'three'
11
+ import { BoxGeometry, EdgesGeometry, Matrix4, Vector3 } from 'three'
17
12
 
18
13
  let {
19
14
  matrix = undefined,
@@ -24,7 +19,7 @@
24
19
  cell_surface_opacity = DEFAULTS.structure.cell_surface_opacity,
25
20
  show_cell_vectors = true,
26
21
  vector_colors = [`red`, `green`, `blue`],
27
- vector_origin = [-1, -1, -1] satisfies Vec3,
22
+ vector_origin = [-1, -1, -1],
28
23
  float_fmt = `.2f`,
29
24
  }: {
30
25
  matrix?: math.Matrix3x3
@@ -40,157 +35,98 @@
40
35
  } = $props()
41
36
 
42
37
  let hovered_idx = $state<number | null>(null) // track hovered vector
43
- let lattice_center = $derived(
44
- matrix
45
- ? (math.scale(math.add(...matrix), 0.5) satisfies Vec3)
46
- : ([0, 0, 0] satisfies Vec3),
38
+ let lattice_center: Vec3 = $derived(
39
+ matrix ? math.scale(math.add(...matrix), 0.5) : [0, 0, 0],
47
40
  )
48
41
 
49
- // Extract line segments from EdgesGeometry for cylinder-based thick lines
50
- function get_edge_segments(edges_geometry: EdgesGeometry): [Vector3, Vector3][] {
51
- const positions = edges_geometry.getAttribute(`position`).array as Float32Array
52
- const segments: [Vector3, Vector3][] = []
53
-
54
- for (let idx = 0; idx < positions.length; idx += 6) {
55
- const start = new Vector3(
56
- positions[idx + 0],
57
- positions[idx + 1],
58
- positions[idx + 2],
59
- )
60
- const end = new Vector3(
61
- positions[idx + 3],
62
- positions[idx + 4],
63
- positions[idx + 5],
64
- )
65
- segments.push([start, end])
66
- }
67
-
68
- return segments
69
- }
70
-
71
- // Calculate cylinder transform for a line segment
72
- function get_cylinder_transform(
73
- start: Vector3,
74
- end: Vector3,
75
- ): { position: Vec3; rotation: Vec3; length: number } {
76
- const direction = end.clone().sub(start)
77
- const length = direction.length()
78
- const center = start.clone().add(end).multiplyScalar(0.5)
79
-
80
- if (length === 0) { // Zero-length: no rotation; render a degenerate cylinder
81
- return { position: center.toArray(), rotation: [0, 0, 0], length }
42
+ // Build the sheared box geometry in an effect so the previous one is disposed on
43
+ // matrix change / unmount (same disposal pattern as the polyhedra in StructureScene).
44
+ let box_geometry = $state<BoxGeometry | null>(null)
45
+ $effect(() => {
46
+ if (!matrix) {
47
+ box_geometry = null
48
+ return
82
49
  }
83
- // Calculate rotation to align cylinder with the line (zero-length guarded above)
84
- const quaternion = new Quaternion().setFromUnitVectors(
85
- new Vector3(0, 1, 0),
86
- direction.normalize(),
50
+ const shear_matrix = new Matrix4().makeBasis(
51
+ new Vector3(...matrix[0]),
52
+ new Vector3(...matrix[1]),
53
+ new Vector3(...matrix[2]),
87
54
  )
88
- const euler = new Euler().setFromQuaternion(quaternion)
55
+ const geo = new BoxGeometry(1, 1, 1).applyMatrix4(shear_matrix)
56
+ box_geometry = geo
57
+ return () => geo.dispose()
58
+ })
89
59
 
90
- return {
91
- position: center.toArray(),
92
- rotation: euler.toArray().slice(0, 3) as Vec3,
93
- length,
60
+ // Edge segments (Cartesian endpoint pairs) from the box geometry; the transient
61
+ // EdgesGeometry is disposed inline since only its extracted positions are kept.
62
+ let edge_segments = $derived.by<[Vec3, Vec3][]>(() => {
63
+ if (!box_geometry || !(cell_edge_opacity > 0)) return []
64
+ const edges_geometry = new EdgesGeometry(box_geometry)
65
+ const positions = edges_geometry.getAttribute(`position`).array as Float32Array
66
+ edges_geometry.dispose()
67
+ const segments: [Vec3, Vec3][] = []
68
+ // each edge is two consecutive xyz triplets (6 floats)
69
+ for (let idx = 0; idx < positions.length; idx += 6) {
70
+ segments.push([
71
+ [positions[idx], positions[idx + 1], positions[idx + 2]],
72
+ [positions[idx + 3], positions[idx + 4], positions[idx + 5]],
73
+ ])
94
74
  }
95
- }
75
+ return segments
76
+ })
96
77
  </script>
97
78
 
98
- {#if matrix}
99
- {#key matrix}
100
- {@const shear_matrix = new Matrix4().makeBasis(
101
- new Vector3(...matrix[0]),
102
- new Vector3(...matrix[1]),
103
- new Vector3(...matrix[2]),
104
- )}
105
- {@const box_geometry = new BoxGeometry(1, 1, 1).applyMatrix4(shear_matrix)}
106
-
107
- <!-- Render wireframe edges if edge opacity > 0 -->
108
- {#if cell_edge_opacity > 0}
109
- {@const edges_geometry = new EdgesGeometry(box_geometry)}
110
- {@const edge_segments = get_edge_segments(edges_geometry)}
111
-
112
- <!-- Use cylinders for thick wireframe lines -->
113
- <T.Group position={lattice_center}>
114
- {#each edge_segments as [start, end], idx (idx)}
115
- {@const { position, rotation, length } = get_cylinder_transform(start, end)}
116
- <T.Mesh {position} {rotation}>
117
- <T.CylinderGeometry
118
- args={[cell_edge_width * 0.01, cell_edge_width * 0.01, length, 8]}
119
- />
120
- <T.MeshStandardMaterial
121
- color={cell_edge_color}
122
- opacity={cell_edge_opacity}
123
- transparent
124
- depthWrite={false}
125
- />
126
- </T.Mesh>
127
- {/each}
128
- </T.Group>
129
- {/if}
130
-
131
- <!-- Render transparent surfaces if surface opacity > 0 -->
132
- {#if cell_surface_opacity > 0}
133
- <T.Mesh geometry={box_geometry} position={lattice_center}>
134
- <T.MeshStandardMaterial
135
- color={cell_surface_color}
136
- opacity={cell_surface_opacity}
137
- transparent
138
- depthWrite={false}
79
+ {#if matrix && box_geometry}
80
+ <!-- Wireframe edges (thick lines via cylinders) when edge opacity > 0 -->
81
+ {#if cell_edge_opacity > 0}
82
+ <T.Group position={lattice_center}>
83
+ {#each edge_segments as [start, end], idx (idx)}
84
+ <Cylinder
85
+ from={start}
86
+ to={end}
87
+ thickness={cell_edge_width * 0.01}
88
+ color={cell_edge_color}
89
+ opacity={cell_edge_opacity}
139
90
  />
140
- </T.Mesh>
141
- {/if}
91
+ {/each}
92
+ </T.Group>
93
+ {/if}
142
94
 
143
- <!-- NOTE below is an untested fix for the lattice vectors being much too small when deployed even though they look correct in local dev -->
144
- {#if show_cell_vectors}
145
- <T.Group position={vector_origin}>
146
- {#each matrix as vec, idx (vec)}
147
- {@const shaft_length = Math.hypot(...vec) * 0.85}
148
- <!-- Shaft goes to 85% of vector length -->
149
- {@const tip_start_position = math.scale(vec, 0.85)}
150
- <!-- Calculate rotation to align with vector direction -->
151
- {@const quaternion = new Quaternion().setFromUnitVectors(
152
- new Vector3(0, 1, 0), // Default up direction for cylinder/cone
153
- new Vector3(...vec).normalize(),
154
- )}
155
- {@const rotation = new Euler()
156
- .setFromQuaternion(quaternion)
157
- .toArray()
158
- .slice(0, 3) as Vec3}
159
- <!-- Arrow shaft - position at center of shaft length -->
160
- {@const shaft_center = math.scale(vec, 0.425)}
161
- <!-- Center at 42.5% = half of 85% -->
162
- <T.Mesh
163
- position={shaft_center}
164
- {rotation}
165
- onpointerenter={() => hovered_idx = idx}
166
- onpointerleave={() => hovered_idx = null}
167
- >
168
- <T.CylinderGeometry args={[0.05, 0.05, shaft_length, 16]} />
169
- <T.MeshStandardMaterial color={vector_colors[idx]} />
170
- </T.Mesh>
95
+ <!-- Render transparent surfaces if surface opacity > 0 -->
96
+ {#if cell_surface_opacity > 0}
97
+ <T.Mesh geometry={box_geometry} position={lattice_center}>
98
+ <T.MeshStandardMaterial
99
+ color={cell_surface_color}
100
+ opacity={cell_surface_opacity}
101
+ transparent
102
+ depthWrite={false}
103
+ />
104
+ </T.Mesh>
105
+ {/if}
171
106
 
172
- <!-- Arrow tip -->
173
- <T.Mesh
174
- position={tip_start_position}
175
- {rotation}
176
- onpointerenter={() => hovered_idx = idx}
177
- onpointerleave={() => hovered_idx = null}
178
- >
179
- <T.ConeGeometry args={[0.175, 0.5, 16]} />
180
- <T.MeshStandardMaterial color={vector_colors[idx]} />
181
- </T.Mesh>
182
- {/each}
183
- </T.Group>
107
+ {#if show_cell_vectors}
108
+ {#each matrix as vec, idx (vec)}
109
+ <Arrow
110
+ position={vector_origin}
111
+ vector={vec}
112
+ scale={0.5}
113
+ color={vector_colors[idx]}
114
+ shaft_radius={0.1}
115
+ arrow_head_radius={0.2}
116
+ arrow_head_length={0.8}
117
+ onpointerenter={() => (hovered_idx = idx)}
118
+ onpointerleave={() => (hovered_idx = null)}
119
+ />
120
+ {/each}
184
121
 
185
- <!-- Tooltip for hovered vector -->
186
- {#if hovered_idx !== null && matrix}
187
- {@const hovered_vec = matrix[hovered_idx]}
188
- {@const tooltip_position = math.add(vector_origin, hovered_vec)}
189
- <CanvasTooltip position={tooltip_position}>
190
- <strong>{[`A`, `B`, `C`][hovered_idx]}</strong>
191
- ({hovered_vec.map((coord) => format_num(coord, float_fmt)).join(`, `)}) Å
192
- </CanvasTooltip>
193
- {/if}
122
+ <!-- Tooltip for hovered vector -->
123
+ {#if hovered_idx !== null && matrix}
124
+ {@const hovered_vec = matrix[hovered_idx]}
125
+ {@const tooltip_position = math.add(vector_origin, hovered_vec)}
126
+ <CanvasTooltip position={tooltip_position}>
127
+ <strong>{[`A`, `B`, `C`][hovered_idx]}</strong>
128
+ ({hovered_vec.map((coord) => format_num(coord, float_fmt)).join(`, `)}) Å
129
+ </CanvasTooltip>
194
130
  {/if}
195
- {/key}
131
+ {/if}
196
132
  {/if}
@@ -0,0 +1,122 @@
1
+ <script lang="ts">
2
+ // Single overlay for all site labels: one portaled DOM container plus one
3
+ // per-frame position pass. Replaces per-label threlte <HTML> components (each
4
+ // of which carries its own portal, per-frame task and matrix updates), which
5
+ // made labels on large structures/supercells unusable.
6
+ import type { Vec3 } from '../math'
7
+ import { T, useTask, useThrelte } from '@threlte/core'
8
+ import type { Snippet } from 'svelte'
9
+ import { Group } from 'three'
10
+ import { type LabelPlacement, LabelProjector } from './atom-label-placement'
11
+
12
+ type SiteLabelEntry = {
13
+ site_idx: number
14
+ position: Vec3 // in the local space of the surrounding rotation groups
15
+ radius: number // visual atom scale (SphereGeometry(0.5) scale factor)
16
+ }
17
+
18
+ let {
19
+ entries,
20
+ get_offset,
21
+ screen_margin,
22
+ label,
23
+ }: {
24
+ entries: SiteLabelEntry[]
25
+ get_offset: (site_idx: number) => Vec3
26
+ screen_margin: number
27
+ label: Snippet<[{ site_idx: number }]>
28
+ } = $props()
29
+
30
+ const { camera, size, dom, renderStage } = useThrelte()
31
+
32
+ // Anchor object inside the scene's rotation groups so label positions follow
33
+ // the same transform as the atoms they annotate.
34
+ const anchor = new Group()
35
+ let container = $state<HTMLDivElement>()
36
+
37
+ const projector = new LabelProjector()
38
+ const placement: LabelPlacement = { x: 0, y: 0, visible: false }
39
+ // Cache last-applied transform per label to skip redundant style writes
40
+ let last_transforms: string[] = []
41
+
42
+ function update_positions() {
43
+ const cam = camera.current
44
+ if (!container || !cam) return
45
+ cam.updateMatrixWorld()
46
+ anchor.updateWorldMatrix(true, false)
47
+ projector.update(cam, anchor.matrixWorld, size.current, screen_margin)
48
+ // Read reactive props once, not per label (prop getters cross a component
49
+ // boundary and would otherwise run 2-3x per label per frame)
50
+ const items = entries
51
+ const offset_of = get_offset
52
+ const kids = container.children
53
+ for (let idx = 0; idx < items.length; idx++) {
54
+ const el = kids[idx] as HTMLElement | undefined
55
+ if (!el) break
56
+ const entry = items[idx]
57
+ projector.place(entry.position, offset_of(entry.site_idx), entry.radius * 0.5, placement)
58
+ // Hide labels behind the camera (same check as threlte's <HTML>)
59
+ if (!placement.visible) {
60
+ if (el.style.display !== `none`) el.style.display = `none`
61
+ continue
62
+ }
63
+ if (el.style.display === `none`) el.style.display = ``
64
+ const transform = `translate(-50%, -50%) translate3d(${placement.x.toFixed(1)}px, ${placement.y.toFixed(
65
+ 1,
66
+ )}px, 0)`
67
+ if (last_transforms[idx] !== transform) {
68
+ last_transforms[idx] = transform
69
+ el.style.transform = transform
70
+ }
71
+ }
72
+ }
73
+
74
+ // Follow camera motion (runs only on rendered frames, like threlte's <HTML>)
75
+ useTask(update_positions, { stage: renderStage, autoInvalidate: false })
76
+
77
+ // Immediate repositioning when label data, offsets or viewport size changes.
78
+ // update_positions is deliberately tracked: it reads entries, screen_margin and
79
+ // (via get_offset) the scene's offset state, so offset changes re-run this
80
+ // effect even when no frame is scheduled.
81
+ $effect(() => {
82
+ void $size
83
+ last_transforms = []
84
+ update_positions()
85
+ })
86
+
87
+ const portal_action = (el: HTMLElement) => {
88
+ if (!dom) return
89
+ dom.append(el)
90
+ return { destroy: () => el.remove() }
91
+ }
92
+ </script>
93
+
94
+ <T is={anchor} />
95
+
96
+ <div bind:this={container} class="site-labels-overlay" use:portal_action>
97
+ {#each entries as entry (entry.site_idx)}
98
+ <div class="site-label">
99
+ {@render label({ site_idx: entry.site_idx })}
100
+ </div>
101
+ {/each}
102
+ </div>
103
+
104
+ <style>
105
+ .site-labels-overlay {
106
+ position: absolute;
107
+ top: 0;
108
+ left: 0;
109
+ pointer-events: none;
110
+ }
111
+ .site-label {
112
+ position: absolute;
113
+ top: 0;
114
+ left: 0;
115
+ pointer-events: auto;
116
+ white-space: nowrap;
117
+ /* measured A/B (888 labels, 2x2x2 supercell, auto-rotating, dpr 2): 60fps
118
+ with will-change vs ~34fps without - promoting labels to their own layers
119
+ avoids repaints when only transforms change */
120
+ will-change: transform;
121
+ }
122
+ </style>
@@ -0,0 +1,18 @@
1
+ import type { Vec3 } from '../math';
2
+ import type { Snippet } from 'svelte';
3
+ type SiteLabelEntry = {
4
+ site_idx: number;
5
+ position: Vec3;
6
+ radius: number;
7
+ };
8
+ type $$ComponentProps = {
9
+ entries: SiteLabelEntry[];
10
+ get_offset: (site_idx: number) => Vec3;
11
+ screen_margin: number;
12
+ label: Snippet<[{
13
+ site_idx: number;
14
+ }]>;
15
+ };
16
+ declare const SiteLabels: import("svelte").Component<$$ComponentProps, {}, "">;
17
+ type SiteLabels = ReturnType<typeof SiteLabels>;
18
+ export default SiteLabels;