matterviz 0.3.6 → 0.3.7

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 (863) hide show
  1. package/dist/EmptyState.svelte.d.ts +9 -0
  2. package/dist/FilePicker.svelte +360 -0
  3. package/dist/FilePicker.svelte.d.ts +17 -0
  4. package/dist/Icon.svelte.d.ts +13 -0
  5. package/dist/MillerIndexInput.svelte +66 -0
  6. package/dist/MillerIndexInput.svelte.d.ts +7 -0
  7. package/dist/api/mp.d.ts +6 -0
  8. package/dist/api/mp.js +22 -0
  9. package/dist/api/optimade.d.ts +45 -0
  10. package/dist/api/optimade.js +135 -0
  11. package/dist/brillouin/BrillouinZone.svelte +549 -0
  12. package/dist/brillouin/BrillouinZone.svelte.d.ts +83 -0
  13. package/dist/brillouin/BrillouinZoneControls.svelte +144 -0
  14. package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +17 -0
  15. package/dist/brillouin/BrillouinZoneExportPane.svelte +146 -0
  16. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +15 -0
  17. package/dist/brillouin/BrillouinZoneInfoPane.svelte +146 -0
  18. package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +13 -0
  19. package/dist/brillouin/BrillouinZoneScene.svelte +476 -0
  20. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +48 -0
  21. package/dist/brillouin/BrillouinZoneTooltip.svelte +92 -0
  22. package/dist/brillouin/BrillouinZoneTooltip.svelte.d.ts +8 -0
  23. package/dist/brillouin/compute.d.ts +17 -0
  24. package/dist/brillouin/compute.js +426 -0
  25. package/dist/brillouin/index.d.ts +8 -0
  26. package/dist/brillouin/index.js +7 -0
  27. package/dist/brillouin/types.d.ts +43 -0
  28. package/dist/brillouin/types.js +1 -0
  29. package/dist/chempot-diagram/ChemPotDiagram.svelte +327 -0
  30. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
  31. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +846 -0
  32. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
  33. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +3193 -0
  34. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
  35. package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
  36. package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
  37. package/dist/chempot-diagram/async-compute.svelte.js +78 -0
  38. package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
  39. package/dist/chempot-diagram/chempot-worker.js +11 -0
  40. package/dist/chempot-diagram/color.d.ts +10 -0
  41. package/dist/chempot-diagram/color.js +32 -0
  42. package/dist/chempot-diagram/compute.d.ts +48 -0
  43. package/dist/chempot-diagram/compute.js +806 -0
  44. package/dist/chempot-diagram/index.d.ts +6 -0
  45. package/dist/chempot-diagram/index.js +6 -0
  46. package/dist/chempot-diagram/pointer.d.ts +16 -0
  47. package/dist/chempot-diagram/pointer.js +40 -0
  48. package/dist/chempot-diagram/temperature.d.ts +15 -0
  49. package/dist/chempot-diagram/temperature.js +34 -0
  50. package/dist/chempot-diagram/types.d.ts +81 -0
  51. package/dist/chempot-diagram/types.js +28 -0
  52. package/dist/colors/index.d.ts +47 -0
  53. package/dist/colors/index.js +203 -0
  54. package/dist/composition/BarChart.svelte +297 -0
  55. package/dist/composition/BarChart.svelte.d.ts +39 -0
  56. package/dist/composition/BubbleChart.svelte +218 -0
  57. package/dist/composition/BubbleChart.svelte.d.ts +28 -0
  58. package/dist/composition/Composition.svelte +165 -0
  59. package/dist/composition/Composition.svelte.d.ts +15 -0
  60. package/dist/composition/Formula.svelte +268 -0
  61. package/dist/composition/Formula.svelte.d.ts +19 -0
  62. package/dist/composition/FormulaFilter.svelte +1257 -0
  63. package/dist/composition/FormulaFilter.svelte.d.ts +51 -0
  64. package/dist/composition/PieChart.svelte +323 -0
  65. package/dist/composition/PieChart.svelte.d.ts +37 -0
  66. package/dist/composition/format.d.ts +15 -0
  67. package/dist/composition/format.js +109 -0
  68. package/dist/composition/index.d.ts +20 -0
  69. package/dist/composition/index.js +14 -0
  70. package/dist/composition/parse.d.ts +56 -0
  71. package/dist/composition/parse.js +474 -0
  72. package/dist/constants.d.ts +29 -0
  73. package/dist/constants.js +99 -0
  74. package/dist/controls.d.ts +14 -0
  75. package/dist/controls.js +30 -0
  76. package/dist/convex-hull/ConvexHull.svelte +157 -0
  77. package/dist/convex-hull/ConvexHull.svelte.d.ts +13 -0
  78. package/dist/convex-hull/ConvexHull2D.svelte +825 -0
  79. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +11 -0
  80. package/dist/convex-hull/ConvexHull3D.svelte +1801 -0
  81. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +8 -0
  82. package/dist/convex-hull/ConvexHull4D.svelte +1398 -0
  83. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +8 -0
  84. package/dist/convex-hull/ConvexHullControls.svelte +535 -0
  85. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +48 -0
  86. package/dist/convex-hull/ConvexHullInfoPane.svelte +125 -0
  87. package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +20 -0
  88. package/dist/convex-hull/ConvexHullStats.svelte +929 -0
  89. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +17 -0
  90. package/dist/convex-hull/ConvexHullTooltip.svelte +131 -0
  91. package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +33 -0
  92. package/dist/convex-hull/GasPressureControls.svelte +247 -0
  93. package/dist/convex-hull/GasPressureControls.svelte.d.ts +11 -0
  94. package/dist/convex-hull/StructurePopup.svelte +151 -0
  95. package/dist/convex-hull/StructurePopup.svelte.d.ts +18 -0
  96. package/dist/convex-hull/TemperatureSlider.svelte.d.ts +8 -0
  97. package/dist/convex-hull/barycentric-coords.d.ts +18 -0
  98. package/dist/convex-hull/barycentric-coords.js +182 -0
  99. package/dist/convex-hull/demo-temperature.d.ts +6 -0
  100. package/dist/convex-hull/demo-temperature.js +40 -0
  101. package/dist/convex-hull/gas-thermodynamics.d.ts +16 -0
  102. package/dist/convex-hull/gas-thermodynamics.js +314 -0
  103. package/dist/convex-hull/helpers.d.ts +114 -0
  104. package/dist/convex-hull/helpers.js +710 -0
  105. package/dist/convex-hull/index.d.ts +119 -0
  106. package/dist/convex-hull/index.js +58 -0
  107. package/dist/convex-hull/thermodynamics.d.ts +67 -0
  108. package/dist/convex-hull/thermodynamics.js +1752 -0
  109. package/dist/convex-hull/types.d.ts +162 -0
  110. package/dist/convex-hull/types.js +36 -0
  111. package/dist/coordination/CoordinationBarPlot.svelte +311 -0
  112. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +30 -0
  113. package/dist/coordination/calc-coordination.d.ts +15 -0
  114. package/dist/coordination/calc-coordination.js +63 -0
  115. package/dist/coordination/index.d.ts +8 -0
  116. package/dist/coordination/index.js +7 -0
  117. package/dist/effects.svelte.d.ts +12 -0
  118. package/dist/effects.svelte.js +37 -0
  119. package/dist/element/BohrAtom.svelte.d.ts +20 -0
  120. package/dist/element/ElementHeading.svelte +26 -0
  121. package/dist/element/ElementHeading.svelte.d.ts +8 -0
  122. package/dist/element/ElementPhoto.svelte +57 -0
  123. package/dist/element/ElementPhoto.svelte.d.ts +9 -0
  124. package/dist/element/ElementStats.svelte +80 -0
  125. package/dist/element/ElementStats.svelte.d.ts +8 -0
  126. package/dist/element/ElementTile.svelte +484 -0
  127. package/dist/element/ElementTile.svelte.d.ts +29 -0
  128. package/dist/element/Nucleus.svelte.d.ts +17 -0
  129. package/dist/element/data.d.ts +2 -0
  130. package/dist/element/data.js +2 -0
  131. package/dist/element/index.d.ts +8 -0
  132. package/dist/element/index.js +7 -0
  133. package/dist/element/types.d.ts +57 -0
  134. package/dist/element/types.js +1 -0
  135. package/dist/feedback/ClickFeedback.svelte +58 -0
  136. package/dist/feedback/ClickFeedback.svelte.d.ts +12 -0
  137. package/dist/feedback/DragOverlay.svelte +42 -0
  138. package/dist/feedback/DragOverlay.svelte.d.ts +7 -0
  139. package/dist/feedback/Spinner.svelte.d.ts +7 -0
  140. package/dist/feedback/StatusMessage.svelte.d.ts +9 -0
  141. package/dist/feedback/index.d.ts +4 -0
  142. package/dist/feedback/index.js +4 -0
  143. package/dist/fermi-surface/FermiSlice.svelte +189 -0
  144. package/dist/fermi-surface/FermiSlice.svelte.d.ts +24 -0
  145. package/dist/fermi-surface/FermiSurface.svelte +600 -0
  146. package/dist/fermi-surface/FermiSurface.svelte.d.ts +83 -0
  147. package/dist/fermi-surface/FermiSurfaceControls.svelte +448 -0
  148. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +35 -0
  149. package/dist/fermi-surface/FermiSurfaceScene.svelte +794 -0
  150. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +50 -0
  151. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +111 -0
  152. package/dist/fermi-surface/FermiSurfaceTooltip.svelte.d.ts +8 -0
  153. package/dist/fermi-surface/compute.d.ts +5 -0
  154. package/dist/fermi-surface/compute.js +538 -0
  155. package/dist/fermi-surface/constants.d.ts +9 -0
  156. package/dist/fermi-surface/constants.js +27 -0
  157. package/dist/fermi-surface/export.d.ts +5 -0
  158. package/dist/fermi-surface/export.js +50 -0
  159. package/dist/fermi-surface/index.d.ts +12 -0
  160. package/dist/fermi-surface/index.js +13 -0
  161. package/dist/fermi-surface/marching-cubes.d.ts +2 -0
  162. package/dist/fermi-surface/marching-cubes.js +2 -0
  163. package/dist/fermi-surface/parse.d.ts +2 -0
  164. package/dist/fermi-surface/parse.js +491 -0
  165. package/dist/fermi-surface/symmetry.d.ts +3 -0
  166. package/dist/fermi-surface/symmetry.js +46 -0
  167. package/dist/fermi-surface/types.d.ts +110 -0
  168. package/dist/fermi-surface/types.js +4 -0
  169. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1545 -0
  170. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
  171. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +225 -0
  172. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +30 -0
  173. package/dist/heatmap-matrix/index.d.ts +53 -0
  174. package/dist/heatmap-matrix/index.js +100 -0
  175. package/dist/heatmap-matrix/shared.d.ts +2 -0
  176. package/dist/heatmap-matrix/shared.js +4 -0
  177. package/dist/icons.d.ts +569 -0
  178. package/dist/icons.js +648 -0
  179. package/dist/index.d.ts +39 -0
  180. package/dist/index.js +39 -0
  181. package/dist/io/decompress.d.ts +11 -0
  182. package/dist/io/decompress.js +74 -0
  183. package/dist/io/export.d.ts +16 -0
  184. package/dist/io/export.js +316 -0
  185. package/dist/io/fetch.d.ts +5 -0
  186. package/dist/io/fetch.js +39 -0
  187. package/dist/io/file-drop.d.ts +7 -0
  188. package/dist/io/file-drop.js +43 -0
  189. package/dist/io/index.d.ts +7 -0
  190. package/dist/io/index.js +6 -0
  191. package/dist/io/is-binary.d.ts +1 -0
  192. package/dist/io/is-binary.js +20 -0
  193. package/dist/io/types.d.ts +8 -0
  194. package/dist/io/types.js +1 -0
  195. package/dist/io/url-drop.d.ts +2 -0
  196. package/dist/io/url-drop.js +123 -0
  197. package/dist/isosurface/Isosurface.svelte +285 -0
  198. package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
  199. package/dist/isosurface/IsosurfaceControls.svelte +277 -0
  200. package/dist/isosurface/IsosurfaceControls.svelte.d.ts +9 -0
  201. package/dist/isosurface/index.d.ts +5 -0
  202. package/dist/isosurface/index.js +6 -0
  203. package/dist/isosurface/parse.d.ts +6 -0
  204. package/dist/isosurface/parse.js +553 -0
  205. package/dist/isosurface/slice.d.ts +11 -0
  206. package/dist/isosurface/slice.js +140 -0
  207. package/dist/isosurface/types.d.ts +56 -0
  208. package/dist/isosurface/types.js +227 -0
  209. package/dist/labels.d.ts +53 -0
  210. package/dist/labels.js +277 -0
  211. package/dist/layout/FullscreenToggle.svelte +50 -0
  212. package/dist/layout/FullscreenToggle.svelte.d.ts +7 -0
  213. package/dist/layout/InfoCard.svelte +120 -0
  214. package/dist/layout/InfoCard.svelte.d.ts +21 -0
  215. package/dist/layout/InfoTag.svelte +185 -0
  216. package/dist/layout/InfoTag.svelte.d.ts +19 -0
  217. package/dist/layout/PropertyFilter.svelte +246 -0
  218. package/dist/layout/PropertyFilter.svelte.d.ts +24 -0
  219. package/dist/layout/SettingsSection.svelte +148 -0
  220. package/dist/layout/SettingsSection.svelte.d.ts +17 -0
  221. package/dist/layout/SubpageGrid.svelte +82 -0
  222. package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
  223. package/dist/layout/fullscreen.d.ts +9 -0
  224. package/dist/layout/fullscreen.js +53 -0
  225. package/dist/layout/index.d.ts +10 -0
  226. package/dist/layout/index.js +8 -0
  227. package/dist/layout/json-tree/JsonNode.svelte +548 -0
  228. package/dist/layout/json-tree/JsonNode.svelte.d.ts +11 -0
  229. package/dist/layout/json-tree/JsonTree.svelte +1230 -0
  230. package/dist/layout/json-tree/JsonTree.svelte.d.ts +6 -0
  231. package/dist/layout/json-tree/JsonValue.svelte.d.ts +9 -0
  232. package/dist/layout/json-tree/index.d.ts +3 -0
  233. package/dist/layout/json-tree/index.js +3 -0
  234. package/dist/layout/json-tree/types.d.ts +74 -0
  235. package/dist/layout/json-tree/types.js +2 -0
  236. package/dist/layout/json-tree/utils.d.ts +29 -0
  237. package/dist/layout/json-tree/utils.js +641 -0
  238. package/dist/marching-cubes.d.ts +14 -0
  239. package/dist/marching-cubes.js +540 -0
  240. package/dist/math.d.ts +101 -0
  241. package/dist/math.js +905 -0
  242. package/dist/overlays/ContextMenu.svelte +162 -0
  243. package/dist/overlays/ContextMenu.svelte.d.ts +25 -0
  244. package/dist/overlays/CopyButton.svelte +45 -0
  245. package/dist/overlays/CopyButton.svelte.d.ts +8 -0
  246. package/dist/overlays/DragControlTab.svelte +98 -0
  247. package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
  248. package/dist/overlays/DraggablePane.svelte +487 -0
  249. package/dist/overlays/DraggablePane.svelte.d.ts +36 -0
  250. package/dist/overlays/InfoPaneCards.svelte +149 -0
  251. package/dist/overlays/InfoPaneCards.svelte.d.ts +22 -0
  252. package/dist/overlays/index.d.ts +3 -0
  253. package/dist/overlays/index.js +3 -0
  254. package/dist/periodic-table/PeriodicTable.svelte +469 -0
  255. package/dist/periodic-table/PeriodicTable.svelte.d.ts +55 -0
  256. package/dist/periodic-table/PeriodicTableControls.svelte +557 -0
  257. package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +24 -0
  258. package/dist/periodic-table/PropertySelect.svelte +37 -0
  259. package/dist/periodic-table/PropertySelect.svelte.d.ts +13 -0
  260. package/dist/periodic-table/TableInset.svelte.d.ts +9 -0
  261. package/dist/periodic-table/index.d.ts +10 -0
  262. package/dist/periodic-table/index.js +4 -0
  263. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +1086 -0
  264. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +44 -0
  265. package/dist/phase-diagram/PhaseDiagramControls.svelte +444 -0
  266. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +30 -0
  267. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +126 -0
  268. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
  269. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +184 -0
  270. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +19 -0
  271. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +391 -0
  272. package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +16 -0
  273. package/dist/phase-diagram/TdbInfoPanel.svelte +203 -0
  274. package/dist/phase-diagram/TdbInfoPanel.svelte.d.ts +12 -0
  275. package/dist/phase-diagram/build-diagram.d.ts +11 -0
  276. package/dist/phase-diagram/build-diagram.js +160 -0
  277. package/dist/phase-diagram/colors.d.ts +35 -0
  278. package/dist/phase-diagram/colors.js +51 -0
  279. package/dist/phase-diagram/diagram-input.d.ts +29 -0
  280. package/dist/phase-diagram/diagram-input.js +3 -0
  281. package/dist/phase-diagram/index.d.ts +13 -0
  282. package/dist/phase-diagram/index.js +11 -0
  283. package/dist/phase-diagram/parse.d.ts +55 -0
  284. package/dist/phase-diagram/parse.js +272 -0
  285. package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
  286. package/dist/phase-diagram/svg-to-diagram.js +867 -0
  287. package/dist/phase-diagram/types.d.ts +93 -0
  288. package/dist/phase-diagram/types.js +1 -0
  289. package/dist/phase-diagram/utils.d.ts +118 -0
  290. package/dist/phase-diagram/utils.js +604 -0
  291. package/dist/plot/AxisLabel.svelte +51 -0
  292. package/dist/plot/AxisLabel.svelte.d.ts +16 -0
  293. package/dist/plot/BarPlot.svelte +2113 -0
  294. package/dist/plot/BarPlot.svelte.d.ts +84 -0
  295. package/dist/plot/BarPlotControls.svelte +66 -0
  296. package/dist/plot/BarPlotControls.svelte.d.ts +18 -0
  297. package/dist/plot/BinnedScatterPlot.svelte +1114 -0
  298. package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
  299. package/dist/plot/ColorBar.svelte +721 -0
  300. package/dist/plot/ColorBar.svelte.d.ts +31 -0
  301. package/dist/plot/ColorScaleSelect.svelte +54 -0
  302. package/dist/plot/ColorScaleSelect.svelte.d.ts +15 -0
  303. package/dist/plot/ElementScatter.svelte +63 -0
  304. package/dist/plot/ElementScatter.svelte.d.ts +14 -0
  305. package/dist/plot/FillArea.svelte.d.ts +21 -0
  306. package/dist/plot/Histogram.svelte +1558 -0
  307. package/dist/plot/Histogram.svelte.d.ts +50 -0
  308. package/dist/plot/HistogramControls.svelte +212 -0
  309. package/dist/plot/HistogramControls.svelte.d.ts +22 -0
  310. package/dist/plot/InteractiveAxisLabel.svelte +96 -0
  311. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +14 -0
  312. package/dist/plot/Line.svelte +84 -0
  313. package/dist/plot/Line.svelte.d.ts +15 -0
  314. package/dist/plot/PlotAxis.svelte +169 -0
  315. package/dist/plot/PlotAxis.svelte.d.ts +24 -0
  316. package/dist/plot/PlotControls.svelte +537 -0
  317. package/dist/plot/PlotControls.svelte.d.ts +4 -0
  318. package/dist/plot/PlotLegend.svelte +569 -0
  319. package/dist/plot/PlotLegend.svelte.d.ts +29 -0
  320. package/dist/plot/PlotTooltip.svelte +67 -0
  321. package/dist/plot/PlotTooltip.svelte.d.ts +17 -0
  322. package/dist/plot/PortalSelect.svelte +253 -0
  323. package/dist/plot/PortalSelect.svelte.d.ts +16 -0
  324. package/dist/plot/ReferenceLine.svelte.d.ts +20 -0
  325. package/dist/plot/ReferenceLine3D.svelte +156 -0
  326. package/dist/plot/ReferenceLine3D.svelte.d.ts +14 -0
  327. package/dist/plot/ReferencePlane.svelte +175 -0
  328. package/dist/plot/ReferencePlane.svelte.d.ts +14 -0
  329. package/dist/plot/ScatterPlot.svelte +2778 -0
  330. package/dist/plot/ScatterPlot.svelte.d.ts +96 -0
  331. package/dist/plot/ScatterPlot3D.svelte +529 -0
  332. package/dist/plot/ScatterPlot3D.svelte.d.ts +95 -0
  333. package/dist/plot/ScatterPlot3DControls.svelte +437 -0
  334. package/dist/plot/ScatterPlot3DControls.svelte.d.ts +20 -0
  335. package/dist/plot/ScatterPlot3DScene.svelte +912 -0
  336. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +74 -0
  337. package/dist/plot/ScatterPlotControls.svelte +306 -0
  338. package/dist/plot/ScatterPlotControls.svelte.d.ts +17 -0
  339. package/dist/plot/ScatterPoint.svelte +182 -0
  340. package/dist/plot/ScatterPoint.svelte.d.ts +22 -0
  341. package/dist/plot/SpacegroupBarPlot.svelte +293 -0
  342. package/dist/plot/SpacegroupBarPlot.svelte.d.ts +9 -0
  343. package/dist/plot/Surface3D.svelte +197 -0
  344. package/dist/plot/Surface3D.svelte.d.ts +13 -0
  345. package/dist/plot/ZeroLines.svelte +97 -0
  346. package/dist/plot/ZeroLines.svelte.d.ts +33 -0
  347. package/dist/plot/ZoomRect.svelte +23 -0
  348. package/dist/plot/ZoomRect.svelte.d.ts +8 -0
  349. package/dist/plot/adaptive-density.d.ts +69 -0
  350. package/dist/plot/adaptive-density.js +191 -0
  351. package/dist/plot/auto-place.d.ts +43 -0
  352. package/dist/plot/auto-place.js +122 -0
  353. package/dist/plot/axis-utils.d.ts +19 -0
  354. package/dist/plot/axis-utils.js +78 -0
  355. package/dist/plot/binned-scatter-types.d.ts +59 -0
  356. package/dist/plot/binned-scatter-types.js +1 -0
  357. package/dist/plot/data-cleaning.d.ts +37 -0
  358. package/dist/plot/data-cleaning.js +855 -0
  359. package/dist/plot/data-transform.d.ts +16 -0
  360. package/dist/plot/data-transform.js +45 -0
  361. package/dist/plot/defaults.d.ts +19 -0
  362. package/dist/plot/defaults.js +9 -0
  363. package/dist/plot/fill-utils.d.ts +46 -0
  364. package/dist/plot/fill-utils.js +322 -0
  365. package/dist/plot/hover-lock.svelte.d.ts +14 -0
  366. package/dist/plot/hover-lock.svelte.js +46 -0
  367. package/dist/plot/index.d.ts +41 -0
  368. package/dist/plot/index.js +39 -0
  369. package/dist/plot/interactions.d.ts +12 -0
  370. package/dist/plot/interactions.js +101 -0
  371. package/dist/plot/layout.d.ts +78 -0
  372. package/dist/plot/layout.js +273 -0
  373. package/dist/plot/reference-line.d.ts +60 -0
  374. package/dist/plot/reference-line.js +314 -0
  375. package/dist/plot/scales.d.ts +48 -0
  376. package/dist/plot/scales.js +481 -0
  377. package/dist/plot/svg.d.ts +1 -0
  378. package/dist/plot/svg.js +11 -0
  379. package/dist/plot/types.d.ts +831 -0
  380. package/dist/plot/types.js +99 -0
  381. package/dist/plot/utils/label-placement.d.ts +68 -0
  382. package/dist/plot/utils/label-placement.js +326 -0
  383. package/dist/plot/utils/series-visibility.d.ts +15 -0
  384. package/dist/plot/utils/series-visibility.js +85 -0
  385. package/dist/plot/utils.d.ts +1 -0
  386. package/dist/plot/utils.js +14 -0
  387. package/dist/rdf/RdfPlot.svelte +247 -0
  388. package/dist/rdf/RdfPlot.svelte.d.ts +27 -0
  389. package/dist/rdf/calc-rdf.d.ts +4 -0
  390. package/dist/rdf/calc-rdf.js +111 -0
  391. package/dist/rdf/index.d.ts +23 -0
  392. package/dist/rdf/index.js +2 -0
  393. package/dist/sanitize.d.ts +6 -0
  394. package/dist/sanitize.js +116 -0
  395. package/dist/settings.d.ts +255 -0
  396. package/dist/settings.js +1132 -0
  397. package/dist/spectral/Bands.svelte +1040 -0
  398. package/dist/spectral/Bands.svelte.d.ts +40 -0
  399. package/dist/spectral/BandsAndDos.svelte +134 -0
  400. package/dist/spectral/BandsAndDos.svelte.d.ts +18 -0
  401. package/dist/spectral/BrillouinBandsDos.svelte +252 -0
  402. package/dist/spectral/BrillouinBandsDos.svelte.d.ts +20 -0
  403. package/dist/spectral/Dos.svelte +697 -0
  404. package/dist/spectral/Dos.svelte.d.ts +29 -0
  405. package/dist/spectral/helpers.d.ts +119 -0
  406. package/dist/spectral/helpers.js +1032 -0
  407. package/dist/spectral/index.d.ts +6 -0
  408. package/dist/spectral/index.js +6 -0
  409. package/dist/spectral/types.d.ts +84 -0
  410. package/dist/spectral/types.js +2 -0
  411. package/dist/state.svelte.d.ts +25 -0
  412. package/dist/state.svelte.js +45 -0
  413. package/dist/structure/Arrow.svelte +72 -0
  414. package/dist/structure/Arrow.svelte.d.ts +15 -0
  415. package/dist/structure/AtomLegend.svelte +815 -0
  416. package/dist/structure/AtomLegend.svelte.d.ts +35 -0
  417. package/dist/structure/Bond.svelte +140 -0
  418. package/dist/structure/Bond.svelte.d.ts +9 -0
  419. package/dist/structure/CanvasTooltip.svelte +33 -0
  420. package/dist/structure/CanvasTooltip.svelte.d.ts +12 -0
  421. package/dist/structure/CellSelect.svelte +349 -0
  422. package/dist/structure/CellSelect.svelte.d.ts +13 -0
  423. package/dist/structure/Cylinder.svelte +45 -0
  424. package/dist/structure/Cylinder.svelte.d.ts +10 -0
  425. package/dist/structure/Lattice.svelte +196 -0
  426. package/dist/structure/Lattice.svelte.d.ts +17 -0
  427. package/dist/structure/Structure.svelte +2248 -0
  428. package/dist/structure/Structure.svelte.d.ts +89 -0
  429. package/dist/structure/StructureControls.svelte +1273 -0
  430. package/dist/structure/StructureControls.svelte.d.ts +31 -0
  431. package/dist/structure/StructureExportPane.svelte +252 -0
  432. package/dist/structure/StructureExportPane.svelte.d.ts +17 -0
  433. package/dist/structure/StructureInfoPane.svelte +737 -0
  434. package/dist/structure/StructureInfoPane.svelte.d.ts +19 -0
  435. package/dist/structure/StructureScene.svelte +2255 -0
  436. package/dist/structure/StructureScene.svelte.d.ts +111 -0
  437. package/dist/structure/atom-properties.d.ts +37 -0
  438. package/dist/structure/atom-properties.js +200 -0
  439. package/dist/structure/bond-order-perception.d.ts +13 -0
  440. package/dist/structure/bond-order-perception.js +384 -0
  441. package/dist/structure/bonding.d.ts +68 -0
  442. package/dist/structure/bonding.js +696 -0
  443. package/dist/structure/export.d.ts +20 -0
  444. package/dist/structure/export.js +727 -0
  445. package/dist/structure/index.d.ts +126 -0
  446. package/dist/structure/index.js +169 -0
  447. package/dist/structure/label-placement.d.ts +14 -0
  448. package/dist/structure/label-placement.js +72 -0
  449. package/dist/structure/measure.d.ts +6 -0
  450. package/dist/structure/measure.js +29 -0
  451. package/dist/structure/parse.d.ts +66 -0
  452. package/dist/structure/parse.js +1392 -0
  453. package/dist/structure/partial-occupancy.d.ts +25 -0
  454. package/dist/structure/partial-occupancy.js +99 -0
  455. package/dist/structure/pbc.d.ts +9 -0
  456. package/dist/structure/pbc.js +123 -0
  457. package/dist/structure/supercell.d.ts +8 -0
  458. package/dist/structure/supercell.js +170 -0
  459. package/dist/structure/validation.d.ts +2 -0
  460. package/dist/structure/validation.js +10 -0
  461. package/dist/symmetry/SymmetryStats.svelte +226 -0
  462. package/dist/symmetry/SymmetryStats.svelte.d.ts +21 -0
  463. package/dist/symmetry/WyckoffTable.svelte +120 -0
  464. package/dist/symmetry/WyckoffTable.svelte.d.ts +11 -0
  465. package/dist/symmetry/cell-transform.d.ts +12 -0
  466. package/dist/symmetry/cell-transform.js +91 -0
  467. package/dist/symmetry/index.d.ts +43 -0
  468. package/dist/symmetry/index.js +228 -0
  469. package/dist/symmetry/spacegroups.d.ts +9 -0
  470. package/dist/symmetry/spacegroups.js +394 -0
  471. package/dist/table/HeatmapTable.svelte +1833 -0
  472. package/dist/table/HeatmapTable.svelte.d.ts +49 -0
  473. package/dist/table/ToggleMenu.svelte +385 -0
  474. package/dist/table/ToggleMenu.svelte.d.ts +11 -0
  475. package/dist/table/index.d.ts +74 -0
  476. package/dist/table/index.js +38 -0
  477. package/dist/theme/ThemeControl.svelte +53 -0
  478. package/dist/theme/ThemeControl.svelte.d.ts +9 -0
  479. package/dist/theme/index.d.ts +29 -0
  480. package/dist/theme/index.js +79 -0
  481. package/dist/time.d.ts +4 -0
  482. package/dist/time.js +70 -0
  483. package/dist/tooltip/TooltipContent.svelte +58 -0
  484. package/dist/tooltip/TooltipContent.svelte.d.ts +31 -0
  485. package/dist/tooltip/index.d.ts +2 -0
  486. package/dist/tooltip/index.js +1 -0
  487. package/dist/tooltip/types.d.ts +8 -0
  488. package/dist/tooltip/types.js +1 -0
  489. package/dist/trajectory/Trajectory.svelte +1545 -0
  490. package/dist/trajectory/Trajectory.svelte.d.ts +77 -0
  491. package/dist/trajectory/TrajectoryError.svelte +128 -0
  492. package/dist/trajectory/TrajectoryError.svelte.d.ts +13 -0
  493. package/dist/trajectory/TrajectoryExportPane.svelte +357 -0
  494. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +17 -0
  495. package/dist/trajectory/TrajectoryInfoPane.svelte +313 -0
  496. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +17 -0
  497. package/dist/trajectory/constants.d.ts +6 -0
  498. package/dist/trajectory/constants.js +7 -0
  499. package/dist/trajectory/extract.d.ts +5 -0
  500. package/dist/trajectory/extract.js +162 -0
  501. package/dist/trajectory/format-detect.d.ts +9 -0
  502. package/dist/trajectory/format-detect.js +76 -0
  503. package/dist/trajectory/frame-reader.d.ts +17 -0
  504. package/dist/trajectory/frame-reader.js +332 -0
  505. package/dist/trajectory/helpers.d.ts +15 -0
  506. package/dist/trajectory/helpers.js +164 -0
  507. package/dist/trajectory/index.d.ts +63 -0
  508. package/dist/trajectory/index.js +126 -0
  509. package/dist/trajectory/parse/ase.d.ts +2 -0
  510. package/dist/trajectory/parse/ase.js +73 -0
  511. package/dist/trajectory/parse/hdf5.d.ts +2 -0
  512. package/dist/trajectory/parse/hdf5.js +127 -0
  513. package/dist/trajectory/parse/index.d.ts +12 -0
  514. package/dist/trajectory/parse/index.js +298 -0
  515. package/dist/trajectory/parse/lammps.d.ts +5 -0
  516. package/dist/trajectory/parse/lammps.js +179 -0
  517. package/dist/trajectory/parse/vasp.d.ts +2 -0
  518. package/dist/trajectory/parse/vasp.js +68 -0
  519. package/dist/trajectory/parse/xyz.d.ts +2 -0
  520. package/dist/trajectory/parse/xyz.js +110 -0
  521. package/dist/trajectory/plotting.d.ts +28 -0
  522. package/dist/trajectory/plotting.js +423 -0
  523. package/dist/trajectory/types.d.ts +11 -0
  524. package/dist/trajectory/types.js +1 -0
  525. package/dist/utils.d.ts +6 -0
  526. package/dist/utils.js +45 -0
  527. package/dist/xrd/XrdPlot.svelte +615 -0
  528. package/dist/xrd/XrdPlot.svelte.d.ts +28 -0
  529. package/dist/xrd/broadening.d.ts +20 -0
  530. package/dist/xrd/broadening.js +97 -0
  531. package/dist/xrd/calc-xrd.d.ts +37 -0
  532. package/dist/xrd/calc-xrd.js +336 -0
  533. package/dist/xrd/index.d.ts +37 -0
  534. package/dist/xrd/index.js +4 -0
  535. package/dist/xrd/parse.d.ts +13 -0
  536. package/dist/xrd/parse.js +749 -0
  537. package/license +1 -1
  538. package/package.json +232 -1457
  539. package/readme.md +98 -171
  540. package/.vscode/launch.json +0 -13
  541. package/.vscodeignore +0 -7
  542. package/dist/assets/STLExporter-BpTH3YHE.js +0 -8
  543. package/dist/assets/browser-DdDecX_W.js +0 -1
  544. package/dist/assets/export-qgn-H9y6.js +0 -2
  545. package/dist/assets/main-DiKYzti2.css +0 -1
  546. package/dist/assets/moyo_wasm_bg-0ocwg7xY.wasm +0 -0
  547. package/dist/extension.js +0 -31293
  548. package/dist/src/lib/FilePicker.svelte +0 -360
  549. package/dist/src/lib/MillerIndexInput.svelte +0 -66
  550. package/dist/src/lib/api/mp.ts +0 -26
  551. package/dist/src/lib/api/optimade.ts +0 -204
  552. package/dist/src/lib/brillouin/BrillouinZone.svelte +0 -549
  553. package/dist/src/lib/brillouin/BrillouinZoneControls.svelte +0 -144
  554. package/dist/src/lib/brillouin/BrillouinZoneExportPane.svelte +0 -146
  555. package/dist/src/lib/brillouin/BrillouinZoneInfoPane.svelte +0 -146
  556. package/dist/src/lib/brillouin/BrillouinZoneScene.svelte +0 -476
  557. package/dist/src/lib/brillouin/BrillouinZoneTooltip.svelte +0 -92
  558. package/dist/src/lib/brillouin/compute.ts +0 -529
  559. package/dist/src/lib/brillouin/index.ts +0 -8
  560. package/dist/src/lib/brillouin/types.ts +0 -51
  561. package/dist/src/lib/chempot-diagram/ChemPotDiagram.svelte +0 -327
  562. package/dist/src/lib/chempot-diagram/ChemPotDiagram2D.svelte +0 -846
  563. package/dist/src/lib/chempot-diagram/ChemPotDiagram3D.svelte +0 -3193
  564. package/dist/src/lib/chempot-diagram/async-compute.svelte.ts +0 -94
  565. package/dist/src/lib/chempot-diagram/chempot-worker.ts +0 -11
  566. package/dist/src/lib/chempot-diagram/color.ts +0 -42
  567. package/dist/src/lib/chempot-diagram/compute.ts +0 -1014
  568. package/dist/src/lib/chempot-diagram/index.ts +0 -6
  569. package/dist/src/lib/chempot-diagram/pointer.ts +0 -56
  570. package/dist/src/lib/chempot-diagram/temperature.ts +0 -77
  571. package/dist/src/lib/chempot-diagram/types.ts +0 -130
  572. package/dist/src/lib/colors/index.ts +0 -249
  573. package/dist/src/lib/composition/BarChart.svelte +0 -297
  574. package/dist/src/lib/composition/BubbleChart.svelte +0 -218
  575. package/dist/src/lib/composition/Composition.svelte +0 -165
  576. package/dist/src/lib/composition/Formula.svelte +0 -268
  577. package/dist/src/lib/composition/FormulaFilter.svelte +0 -1257
  578. package/dist/src/lib/composition/PieChart.svelte +0 -323
  579. package/dist/src/lib/composition/format.ts +0 -155
  580. package/dist/src/lib/composition/index.ts +0 -37
  581. package/dist/src/lib/composition/parse.ts +0 -605
  582. package/dist/src/lib/constants.ts +0 -134
  583. package/dist/src/lib/controls.ts +0 -42
  584. package/dist/src/lib/convex-hull/ConvexHull.svelte +0 -157
  585. package/dist/src/lib/convex-hull/ConvexHull2D.svelte +0 -825
  586. package/dist/src/lib/convex-hull/ConvexHull3D.svelte +0 -1801
  587. package/dist/src/lib/convex-hull/ConvexHull4D.svelte +0 -1398
  588. package/dist/src/lib/convex-hull/ConvexHullControls.svelte +0 -535
  589. package/dist/src/lib/convex-hull/ConvexHullInfoPane.svelte +0 -125
  590. package/dist/src/lib/convex-hull/ConvexHullStats.svelte +0 -929
  591. package/dist/src/lib/convex-hull/ConvexHullTooltip.svelte +0 -131
  592. package/dist/src/lib/convex-hull/GasPressureControls.svelte +0 -247
  593. package/dist/src/lib/convex-hull/StructurePopup.svelte +0 -151
  594. package/dist/src/lib/convex-hull/barycentric-coords.ts +0 -246
  595. package/dist/src/lib/convex-hull/demo-temperature.ts +0 -63
  596. package/dist/src/lib/convex-hull/gas-thermodynamics.ts +0 -405
  597. package/dist/src/lib/convex-hull/helpers.ts +0 -932
  598. package/dist/src/lib/convex-hull/index.ts +0 -202
  599. package/dist/src/lib/convex-hull/thermodynamics.ts +0 -2192
  600. package/dist/src/lib/convex-hull/types.ts +0 -267
  601. package/dist/src/lib/coordination/CoordinationBarPlot.svelte +0 -311
  602. package/dist/src/lib/coordination/calc-coordination.ts +0 -93
  603. package/dist/src/lib/coordination/index.ts +0 -9
  604. package/dist/src/lib/effects.svelte.ts +0 -48
  605. package/dist/src/lib/element/ElementHeading.svelte +0 -26
  606. package/dist/src/lib/element/ElementPhoto.svelte +0 -57
  607. package/dist/src/lib/element/ElementStats.svelte +0 -80
  608. package/dist/src/lib/element/ElementTile.svelte +0 -484
  609. package/dist/src/lib/element/data.ts +0 -14
  610. package/dist/src/lib/element/index.ts +0 -8
  611. package/dist/src/lib/element/types.ts +0 -62
  612. package/dist/src/lib/feedback/ClickFeedback.svelte +0 -58
  613. package/dist/src/lib/feedback/DragOverlay.svelte +0 -42
  614. package/dist/src/lib/feedback/index.ts +0 -4
  615. package/dist/src/lib/fermi-surface/FermiSlice.svelte +0 -189
  616. package/dist/src/lib/fermi-surface/FermiSurface.svelte +0 -600
  617. package/dist/src/lib/fermi-surface/FermiSurfaceControls.svelte +0 -448
  618. package/dist/src/lib/fermi-surface/FermiSurfaceScene.svelte +0 -794
  619. package/dist/src/lib/fermi-surface/FermiSurfaceTooltip.svelte +0 -111
  620. package/dist/src/lib/fermi-surface/compute.ts +0 -728
  621. package/dist/src/lib/fermi-surface/constants.ts +0 -32
  622. package/dist/src/lib/fermi-surface/export.ts +0 -64
  623. package/dist/src/lib/fermi-surface/index.ts +0 -14
  624. package/dist/src/lib/fermi-surface/marching-cubes.ts +0 -3
  625. package/dist/src/lib/fermi-surface/parse.ts +0 -574
  626. package/dist/src/lib/fermi-surface/symmetry.ts +0 -56
  627. package/dist/src/lib/fermi-surface/types.ts +0 -159
  628. package/dist/src/lib/heatmap-matrix/HeatmapMatrix.svelte +0 -1545
  629. package/dist/src/lib/heatmap-matrix/HeatmapMatrixControls.svelte +0 -225
  630. package/dist/src/lib/heatmap-matrix/index.ts +0 -167
  631. package/dist/src/lib/heatmap-matrix/shared.ts +0 -7
  632. package/dist/src/lib/icons.ts +0 -650
  633. package/dist/src/lib/index.ts +0 -61
  634. package/dist/src/lib/io/decompress.ts +0 -92
  635. package/dist/src/lib/io/export.ts +0 -385
  636. package/dist/src/lib/io/fetch.ts +0 -46
  637. package/dist/src/lib/io/file-drop.ts +0 -51
  638. package/dist/src/lib/io/index.ts +0 -7
  639. package/dist/src/lib/io/is-binary.ts +0 -24
  640. package/dist/src/lib/io/types.ts +0 -8
  641. package/dist/src/lib/io/url-drop.ts +0 -141
  642. package/dist/src/lib/isosurface/Isosurface.svelte +0 -285
  643. package/dist/src/lib/isosurface/IsosurfaceControls.svelte +0 -277
  644. package/dist/src/lib/isosurface/index.ts +0 -7
  645. package/dist/src/lib/isosurface/parse.ts +0 -656
  646. package/dist/src/lib/isosurface/slice.ts +0 -175
  647. package/dist/src/lib/isosurface/types.ts +0 -309
  648. package/dist/src/lib/labels.ts +0 -320
  649. package/dist/src/lib/layout/FullscreenToggle.svelte +0 -50
  650. package/dist/src/lib/layout/InfoCard.svelte +0 -120
  651. package/dist/src/lib/layout/InfoTag.svelte +0 -185
  652. package/dist/src/lib/layout/PropertyFilter.svelte +0 -246
  653. package/dist/src/lib/layout/SettingsSection.svelte +0 -148
  654. package/dist/src/lib/layout/SubpageGrid.svelte +0 -82
  655. package/dist/src/lib/layout/fullscreen.ts +0 -65
  656. package/dist/src/lib/layout/index.ts +0 -11
  657. package/dist/src/lib/layout/json-tree/JsonNode.svelte +0 -548
  658. package/dist/src/lib/layout/json-tree/JsonTree.svelte +0 -1230
  659. package/dist/src/lib/layout/json-tree/index.ts +0 -3
  660. package/dist/src/lib/layout/json-tree/types.ts +0 -126
  661. package/dist/src/lib/layout/json-tree/utils.ts +0 -682
  662. package/dist/src/lib/marching-cubes.ts +0 -614
  663. package/dist/src/lib/math.ts +0 -1081
  664. package/dist/src/lib/overlays/ContextMenu.svelte +0 -162
  665. package/dist/src/lib/overlays/CopyButton.svelte +0 -45
  666. package/dist/src/lib/overlays/DragControlTab.svelte +0 -98
  667. package/dist/src/lib/overlays/DraggablePane.svelte +0 -487
  668. package/dist/src/lib/overlays/InfoPaneCards.svelte +0 -149
  669. package/dist/src/lib/overlays/index.ts +0 -3
  670. package/dist/src/lib/periodic-table/PeriodicTable.svelte +0 -469
  671. package/dist/src/lib/periodic-table/PeriodicTableControls.svelte +0 -557
  672. package/dist/src/lib/periodic-table/PropertySelect.svelte +0 -37
  673. package/dist/src/lib/periodic-table/index.ts +0 -12
  674. package/dist/src/lib/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +0 -1086
  675. package/dist/src/lib/phase-diagram/PhaseDiagramControls.svelte +0 -444
  676. package/dist/src/lib/phase-diagram/PhaseDiagramEditorPane.svelte +0 -126
  677. package/dist/src/lib/phase-diagram/PhaseDiagramExportPane.svelte +0 -184
  678. package/dist/src/lib/phase-diagram/PhaseDiagramTooltip.svelte +0 -391
  679. package/dist/src/lib/phase-diagram/TdbInfoPanel.svelte +0 -203
  680. package/dist/src/lib/phase-diagram/build-diagram.ts +0 -186
  681. package/dist/src/lib/phase-diagram/colors.ts +0 -58
  682. package/dist/src/lib/phase-diagram/diagram-input.ts +0 -40
  683. package/dist/src/lib/phase-diagram/index.ts +0 -13
  684. package/dist/src/lib/phase-diagram/parse.ts +0 -348
  685. package/dist/src/lib/phase-diagram/svg-to-diagram.ts +0 -1023
  686. package/dist/src/lib/phase-diagram/types.ts +0 -144
  687. package/dist/src/lib/phase-diagram/utils.ts +0 -775
  688. package/dist/src/lib/plot/AxisLabel.svelte +0 -51
  689. package/dist/src/lib/plot/BarPlot.svelte +0 -2113
  690. package/dist/src/lib/plot/BarPlotControls.svelte +0 -66
  691. package/dist/src/lib/plot/BinnedScatterPlot.svelte +0 -1114
  692. package/dist/src/lib/plot/ColorBar.svelte +0 -721
  693. package/dist/src/lib/plot/ColorScaleSelect.svelte +0 -54
  694. package/dist/src/lib/plot/ElementScatter.svelte +0 -63
  695. package/dist/src/lib/plot/Histogram.svelte +0 -1558
  696. package/dist/src/lib/plot/HistogramControls.svelte +0 -212
  697. package/dist/src/lib/plot/InteractiveAxisLabel.svelte +0 -96
  698. package/dist/src/lib/plot/Line.svelte +0 -84
  699. package/dist/src/lib/plot/PlotAxis.svelte +0 -169
  700. package/dist/src/lib/plot/PlotControls.svelte +0 -537
  701. package/dist/src/lib/plot/PlotLegend.svelte +0 -569
  702. package/dist/src/lib/plot/PlotTooltip.svelte +0 -67
  703. package/dist/src/lib/plot/PortalSelect.svelte +0 -253
  704. package/dist/src/lib/plot/ReferenceLine3D.svelte +0 -156
  705. package/dist/src/lib/plot/ReferencePlane.svelte +0 -175
  706. package/dist/src/lib/plot/ScatterPlot.svelte +0 -2778
  707. package/dist/src/lib/plot/ScatterPlot3D.svelte +0 -529
  708. package/dist/src/lib/plot/ScatterPlot3DControls.svelte +0 -437
  709. package/dist/src/lib/plot/ScatterPlot3DScene.svelte +0 -912
  710. package/dist/src/lib/plot/ScatterPlotControls.svelte +0 -306
  711. package/dist/src/lib/plot/ScatterPoint.svelte +0 -182
  712. package/dist/src/lib/plot/SpacegroupBarPlot.svelte +0 -293
  713. package/dist/src/lib/plot/Surface3D.svelte +0 -197
  714. package/dist/src/lib/plot/ZeroLines.svelte +0 -97
  715. package/dist/src/lib/plot/ZoomRect.svelte +0 -23
  716. package/dist/src/lib/plot/adaptive-density.ts +0 -316
  717. package/dist/src/lib/plot/auto-place.ts +0 -184
  718. package/dist/src/lib/plot/axis-utils.ts +0 -122
  719. package/dist/src/lib/plot/binned-scatter-types.ts +0 -83
  720. package/dist/src/lib/plot/data-cleaning.ts +0 -1069
  721. package/dist/src/lib/plot/data-transform.ts +0 -69
  722. package/dist/src/lib/plot/defaults.ts +0 -9
  723. package/dist/src/lib/plot/fill-utils.ts +0 -494
  724. package/dist/src/lib/plot/hover-lock.svelte.ts +0 -60
  725. package/dist/src/lib/plot/index.ts +0 -53
  726. package/dist/src/lib/plot/interactions.ts +0 -119
  727. package/dist/src/lib/plot/layout.ts +0 -425
  728. package/dist/src/lib/plot/reference-line.ts +0 -426
  729. package/dist/src/lib/plot/scales.ts +0 -654
  730. package/dist/src/lib/plot/svg.ts +0 -23
  731. package/dist/src/lib/plot/types.ts +0 -1144
  732. package/dist/src/lib/plot/utils/label-placement.ts +0 -541
  733. package/dist/src/lib/plot/utils/series-visibility.ts +0 -140
  734. package/dist/src/lib/plot/utils.ts +0 -11
  735. package/dist/src/lib/rdf/RdfPlot.svelte +0 -247
  736. package/dist/src/lib/rdf/calc-rdf.ts +0 -167
  737. package/dist/src/lib/rdf/index.ts +0 -27
  738. package/dist/src/lib/sanitize.ts +0 -126
  739. package/dist/src/lib/settings.ts +0 -1479
  740. package/dist/src/lib/spectral/Bands.svelte +0 -1040
  741. package/dist/src/lib/spectral/BandsAndDos.svelte +0 -134
  742. package/dist/src/lib/spectral/BrillouinBandsDos.svelte +0 -252
  743. package/dist/src/lib/spectral/Dos.svelte +0 -697
  744. package/dist/src/lib/spectral/helpers.ts +0 -1381
  745. package/dist/src/lib/spectral/index.ts +0 -8
  746. package/dist/src/lib/spectral/types.ts +0 -112
  747. package/dist/src/lib/state.svelte.ts +0 -64
  748. package/dist/src/lib/structure/Arrow.svelte +0 -72
  749. package/dist/src/lib/structure/AtomLegend.svelte +0 -815
  750. package/dist/src/lib/structure/Bond.svelte +0 -140
  751. package/dist/src/lib/structure/CanvasTooltip.svelte +0 -33
  752. package/dist/src/lib/structure/CellSelect.svelte +0 -349
  753. package/dist/src/lib/structure/Cylinder.svelte +0 -45
  754. package/dist/src/lib/structure/Lattice.svelte +0 -196
  755. package/dist/src/lib/structure/Structure.svelte +0 -2248
  756. package/dist/src/lib/structure/StructureControls.svelte +0 -1273
  757. package/dist/src/lib/structure/StructureExportPane.svelte +0 -252
  758. package/dist/src/lib/structure/StructureInfoPane.svelte +0 -737
  759. package/dist/src/lib/structure/StructureScene.svelte +0 -2255
  760. package/dist/src/lib/structure/atom-properties.ts +0 -316
  761. package/dist/src/lib/structure/bond-order-perception.ts +0 -447
  762. package/dist/src/lib/structure/bonding.ts +0 -944
  763. package/dist/src/lib/structure/export.ts +0 -861
  764. package/dist/src/lib/structure/index.ts +0 -291
  765. package/dist/src/lib/structure/label-placement.ts +0 -130
  766. package/dist/src/lib/structure/measure.ts +0 -45
  767. package/dist/src/lib/structure/parse.ts +0 -1705
  768. package/dist/src/lib/structure/partial-occupancy.ts +0 -183
  769. package/dist/src/lib/structure/pbc.ts +0 -164
  770. package/dist/src/lib/structure/supercell.ts +0 -226
  771. package/dist/src/lib/structure/validation.ts +0 -11
  772. package/dist/src/lib/symmetry/SymmetryStats.svelte +0 -226
  773. package/dist/src/lib/symmetry/WyckoffTable.svelte +0 -120
  774. package/dist/src/lib/symmetry/cell-transform.ts +0 -118
  775. package/dist/src/lib/symmetry/index.ts +0 -348
  776. package/dist/src/lib/symmetry/spacegroups.ts +0 -404
  777. package/dist/src/lib/table/HeatmapTable.svelte +0 -1833
  778. package/dist/src/lib/table/ToggleMenu.svelte +0 -385
  779. package/dist/src/lib/table/index.ts +0 -139
  780. package/dist/src/lib/theme/ThemeControl.svelte +0 -53
  781. package/dist/src/lib/theme/index.ts +0 -107
  782. package/dist/src/lib/time.ts +0 -71
  783. package/dist/src/lib/tooltip/TooltipContent.svelte +0 -58
  784. package/dist/src/lib/tooltip/index.ts +0 -2
  785. package/dist/src/lib/tooltip/types.ts +0 -13
  786. package/dist/src/lib/trajectory/Trajectory.svelte +0 -1545
  787. package/dist/src/lib/trajectory/TrajectoryError.svelte +0 -128
  788. package/dist/src/lib/trajectory/TrajectoryExportPane.svelte +0 -357
  789. package/dist/src/lib/trajectory/TrajectoryInfoPane.svelte +0 -313
  790. package/dist/src/lib/trajectory/constants.ts +0 -7
  791. package/dist/src/lib/trajectory/extract.ts +0 -196
  792. package/dist/src/lib/trajectory/format-detect.ts +0 -96
  793. package/dist/src/lib/trajectory/frame-reader.ts +0 -456
  794. package/dist/src/lib/trajectory/helpers.ts +0 -217
  795. package/dist/src/lib/trajectory/index.ts +0 -218
  796. package/dist/src/lib/trajectory/parse/ase.ts +0 -109
  797. package/dist/src/lib/trajectory/parse/hdf5.ts +0 -173
  798. package/dist/src/lib/trajectory/parse/index.ts +0 -411
  799. package/dist/src/lib/trajectory/parse/lammps.ts +0 -215
  800. package/dist/src/lib/trajectory/parse/vasp.ts +0 -102
  801. package/dist/src/lib/trajectory/parse/xyz.ts +0 -143
  802. package/dist/src/lib/trajectory/plotting.ts +0 -599
  803. package/dist/src/lib/trajectory/types.ts +0 -13
  804. package/dist/src/lib/utils.ts +0 -56
  805. package/dist/src/lib/xrd/XrdPlot.svelte +0 -615
  806. package/dist/src/lib/xrd/broadening.ts +0 -130
  807. package/dist/src/lib/xrd/calc-xrd.ts +0 -397
  808. package/dist/src/lib/xrd/index.ts +0 -38
  809. package/dist/src/lib/xrd/parse.ts +0 -858
  810. package/dist/webview.js +0 -29421
  811. package/icon.png +0 -0
  812. package/matterviz-0.3.2.vsix +0 -0
  813. package/matterviz-0.3.4.vsix +0 -0
  814. package/matterviz-0.3.5.vsix +0 -0
  815. package/scripts/sync-config.ts +0 -101
  816. package/src/declarations.d.ts +0 -2
  817. package/src/extension.ts +0 -972
  818. package/src/node-io.ts +0 -65
  819. package/src/types.ts +0 -17
  820. package/src/webview/JsonBrowser.svelte +0 -1079
  821. package/src/webview/PlotPanel.svelte +0 -346
  822. package/src/webview/detect.ts +0 -444
  823. package/src/webview/main.ts +0 -764
  824. package/src/webview/plot-utils.ts +0 -250
  825. package/test-fixtures/all-viz-types.json.gz +0 -0
  826. package/test-fixtures/plot-demo-data.json.gz +0 -0
  827. package/tests/detect.test.ts +0 -604
  828. package/tests/extension.test.ts +0 -2041
  829. package/tests/node-io.test.ts +0 -39
  830. package/tests/plot-utils.test.ts +0 -302
  831. package/tests/vite-plugin-json-gz.test.ts +0 -114
  832. package/tests/vscode-mock.ts +0 -18
  833. package/tests/webview.test.ts +0 -231
  834. package/tsconfig.json +0 -20
  835. package/vite-plugin-json-gz.ts +0 -29
  836. package/vite.config.ts +0 -34
  837. package/vite.extension.config.ts +0 -34
  838. /package/dist/{src/lib/EmptyState.svelte → EmptyState.svelte} +0 -0
  839. /package/dist/{src/lib/Icon.svelte → Icon.svelte} +0 -0
  840. /package/dist/{src/lib/app.css → app.css} +0 -0
  841. /package/dist/{src/lib/chempot-diagram → chempot-diagram}/ChemPotScene3D.svelte +0 -0
  842. /package/dist/{src/lib/colors → colors}/alloy-colors.json +0 -0
  843. /package/dist/{src/lib/colors → colors}/dark-mode-colors.json +0 -0
  844. /package/dist/{src/lib/colors → colors}/jmol-colors.json +0 -0
  845. /package/dist/{src/lib/colors → colors}/muted-colors.json +0 -0
  846. /package/dist/{src/lib/colors → colors}/pastel-colors.json +0 -0
  847. /package/dist/{src/lib/colors → colors}/vesta-colors.json +0 -0
  848. /package/dist/{src/lib/convex-hull → convex-hull}/TemperatureSlider.svelte +0 -0
  849. /package/dist/{src/lib/element → element}/BohrAtom.svelte +0 -0
  850. /package/dist/{src/lib/element → element}/Nucleus.svelte +0 -0
  851. /package/dist/{src/lib/element → element}/data.json +0 -0
  852. /package/dist/{src/lib/element → element}/data.json.gz +0 -0
  853. /package/dist/{src/lib/element → element}/data.json.gz.d.ts +0 -0
  854. /package/dist/{src/lib/element → element}/data.schema.json +0 -0
  855. /package/dist/{src/lib/element-image-urls.json → element-image-urls.json} +0 -0
  856. /package/dist/{src/lib/feedback → feedback}/Spinner.svelte +0 -0
  857. /package/dist/{src/lib/feedback → feedback}/StatusMessage.svelte +0 -0
  858. /package/dist/{src/lib/layout → layout}/json-tree/JsonValue.svelte +0 -0
  859. /package/dist/{src/lib/periodic-table → periodic-table}/TableInset.svelte +0 -0
  860. /package/dist/{src/lib/plot → plot}/FillArea.svelte +0 -0
  861. /package/dist/{src/lib/plot → plot}/ReferenceLine.svelte +0 -0
  862. /package/dist/{src/lib/theme → theme}/themes.mjs +0 -0
  863. /package/dist/{src/lib/xrd → xrd}/atomic_scattering_params.json +0 -0
@@ -1,2255 +0,0 @@
1
- <script lang="ts">
2
- import type { D3InterpolateName } from '$lib/colors'
3
- import { AXIS_COLORS, get_d3_interpolator, NEG_AXIS_COLORS } from '$lib/colors'
4
- import type { ElementSymbol } from '$lib/element'
5
- import { element_data } from '$lib/element'
6
- import Isosurface from '$lib/isosurface/Isosurface.svelte'
7
- import type { IsosurfaceSettings, VolumetricData } from '$lib/isosurface/types'
8
- import { DEFAULT_ISOSURFACE_SETTINGS } from '$lib/isosurface/types'
9
- import { format_num } from '$lib/labels'
10
- import type { Vec3 } from '$lib/math'
11
- import * as math from '$lib/math'
12
- import type {
13
- CameraProjection,
14
- ShowBonds,
15
- VectorColorMode,
16
- VectorLayerConfig,
17
- } from '$lib/settings'
18
- import { DEFAULTS } from '$lib/settings'
19
- import { create_pulse_animation } from '$lib/effects.svelte'
20
- import { colors } from '$lib/state.svelte'
21
- import type {
22
- AnyStructure,
23
- BondEditMode,
24
- BondOrder,
25
- BondPair,
26
- MeasureMode,
27
- Site,
28
- StructureBond,
29
- } from '$lib/structure'
30
- import {
31
- Arrow,
32
- atomic_radii,
33
- Cylinder,
34
- get_all_site_vectors,
35
- get_center_of_mass,
36
- get_structure_vector_keys,
37
- Lattice,
38
- VECTOR_PALETTE,
39
- } from '$lib/structure'
40
- import type { AtomColorConfig } from '$lib/structure/atom-properties'
41
- import {
42
- get_orig_site_idx,
43
- get_property_colors,
44
- } from '$lib/structure/atom-properties'
45
- import * as measure from '$lib/structure/measure'
46
- import {
47
- compute_slice_geometry,
48
- merge_split_partial_sites,
49
- PARTIAL_OCCUPANCY_CAP_ARC,
50
- } from '$lib/structure/partial-occupancy'
51
- import type { MoyoDataset } from '@spglib/moyo-wasm'
52
- import { T, useThrelte } from '@threlte/core'
53
- import * as extras from '@threlte/extras'
54
- import { type ComponentProps, type Snippet, untrack } from 'svelte'
55
- import { SvelteMap, SvelteSet } from 'svelte/reactivity'
56
- import { type Camera, Color, type Mesh, type Object3D, type Scene, Vector3 } from 'three'
57
- import Bond from './Bond.svelte'
58
- import type { BondEditResult, BondingStrategy, BondKeyTarget } from './bonding'
59
- import {
60
- add_or_restore_bond,
61
- BONDING_STRATEGIES,
62
- BOND_ORDER_OPTIONS,
63
- canonicalize_bond_target,
64
- delete_bond as apply_delete_bond,
65
- get_bond_key,
66
- get_bond_render_matrices,
67
- get_explicit_bond_metadata,
68
- set_bond_order as apply_set_bond_order,
69
- structure_bond_to_bond_pair,
70
- } from './bonding'
71
- import {
72
- CanvasTooltip,
73
- compose_perceived_bonds,
74
- perceive_bond_orders,
75
- } from './index'
76
- import {
77
- choose_site_label_offset,
78
- LABEL_OFFSET_EPS,
79
- make_label_position_calculator,
80
- } from './label-placement'
81
-
82
- type InstancedAtomGroup = {
83
- element: string
84
- radius: number
85
- color: string
86
- is_image_atom: boolean
87
- atoms: (typeof atom_data)[number][]
88
- }
89
-
90
- function instanced_atom_group_key(
91
- { element, radius, color, is_image_atom, atoms }: InstancedAtomGroup,
92
- measure_mode: MeasureMode,
93
- ): string {
94
- const edit_mode_image = measure_mode === `edit-atoms` && is_image_atom
95
- return `${element}-${format_num(radius, `.3~`)}-${color}-${
96
- is_image_atom ? `img` : `base`
97
- }-${edit_mode_image}-${atoms.length}`
98
- }
99
-
100
- type EditableAtomHitTarget = {
101
- site_idx: number
102
- position: Vec3
103
- radius: number
104
- }
105
-
106
- type BondContextMenu = {
107
- site_idx_1: number
108
- site_idx_2: number
109
- cell_shift?: Vec3
110
- position: Vec3
111
- }
112
-
113
- type BondPointerEvent = PointerEvent & {
114
- nativeEvent?: PointerEvent
115
- object?: Object3D
116
- point?: Vector3
117
- }
118
-
119
- type BondContextMenuEvent = MouseEvent & {
120
- nativeEvent?: MouseEvent
121
- object?: Object3D
122
- point?: Vector3
123
- }
124
-
125
- let {
126
- structure = undefined,
127
- base_structure = undefined,
128
- atom_radius = DEFAULTS.structure.atom_radius,
129
- same_size_atoms = false,
130
- camera_position = DEFAULTS.structure.camera_position,
131
- camera_target = undefined,
132
- camera_projection = DEFAULTS.structure.camera_projection,
133
- rotation_damping = DEFAULTS.structure.rotation_damping,
134
- max_zoom = DEFAULTS.structure.max_zoom,
135
- min_zoom = DEFAULTS.structure.min_zoom,
136
- rotate_speed = DEFAULTS.structure.rotate_speed,
137
- zoom_speed = DEFAULTS.structure.zoom_speed,
138
- pan_speed = DEFAULTS.structure.pan_speed,
139
- zoom_to_cursor = DEFAULTS.structure.zoom_to_cursor,
140
- show_atoms = DEFAULTS.structure.show_atoms,
141
- show_bonds = DEFAULTS.structure.show_bonds,
142
- show_site_labels = DEFAULTS.structure.show_site_labels,
143
- show_site_indices = DEFAULTS.structure.show_site_indices,
144
- site_label_size = DEFAULTS.structure.site_label_size,
145
- site_label_offset = $bindable(DEFAULTS.structure.site_label_offset),
146
- site_label_bg_color = DEFAULTS.structure.site_label_bg_color,
147
- site_label_color = DEFAULTS.structure.site_label_color,
148
- site_label_padding = DEFAULTS.structure.site_label_padding,
149
- vector_configs = $bindable<Record<string, VectorLayerConfig>>({}),
150
- vector_scale = DEFAULTS.structure.vector_scale,
151
- vector_color = DEFAULTS.structure.vector_color,
152
- vector_color_mode = DEFAULTS.structure.vector_color_mode as VectorColorMode,
153
- vector_color_scale = DEFAULTS.structure.vector_color_scale,
154
- vector_normalize = DEFAULTS.structure.vector_normalize,
155
- vector_uniform_thickness = DEFAULTS.structure.vector_uniform_thickness,
156
- vector_origin_gap = DEFAULTS.structure.vector_origin_gap,
157
- vector_shaft_radius = DEFAULTS.structure.vector_shaft_radius,
158
- vector_arrow_head_radius = DEFAULTS.structure.vector_arrow_head_radius,
159
- vector_arrow_head_length = DEFAULTS.structure.vector_arrow_head_length,
160
- gizmo = DEFAULTS.structure.show_gizmo,
161
- hovered_idx = $bindable(null),
162
- hovered_site = $bindable(null),
163
- float_fmt = `.3~f`,
164
- auto_rotate = DEFAULTS.structure.auto_rotate,
165
- bond_thickness = DEFAULTS.structure.bond_thickness,
166
- bond_color = DEFAULTS.structure.bond_color,
167
- bonding_strategy = DEFAULTS.structure.bonding_strategy,
168
- auto_bond_order = DEFAULTS.structure.auto_bond_order,
169
- aromatic_display = DEFAULTS.structure.aromatic_display,
170
- bonding_options = {},
171
- fov = DEFAULTS.structure.fov,
172
- initial_zoom = DEFAULTS.structure.initial_zoom,
173
- ambient_light = DEFAULTS.structure.ambient_light,
174
- directional_light = DEFAULTS.structure.directional_light,
175
- sphere_segments = DEFAULTS.structure.sphere_segments,
176
- lattice_props = {},
177
- atom_label,
178
- camera_is_moving = $bindable(false),
179
- width = 0,
180
- height = 0,
181
- measure_mode = `distance`,
182
- selected_sites = $bindable([]),
183
- measured_sites = $bindable([]),
184
- added_bonds = $bindable([]),
185
- removed_bonds = $bindable([]),
186
- bond_order_overrides = $bindable([]),
187
- bond_edits_enabled = true,
188
- bond_edit_mode = $bindable<BondEditMode>(`add`),
189
- bond_edit_order = 1,
190
- selection_highlight_color = `#6cf0ff`,
191
- // Active highlight group with different color
192
- active_sites = $bindable([]),
193
- active_highlight_color = `var(--struct-active-highlight-color, #2563eb)`,
194
- rotation = DEFAULTS.structure.rotation,
195
- scene = $bindable(),
196
- camera = $bindable(),
197
- orbit_controls = $bindable(),
198
- rotation_target_ref = $bindable(),
199
- initial_computed_zoom = $bindable(),
200
- hidden_elements = $bindable(new SvelteSet()),
201
- hidden_prop_vals = $bindable(new SvelteSet<number | string>()),
202
- element_radius_overrides = $bindable<Partial<Record<ElementSymbol, number>>>({}),
203
- site_radius_overrides = $bindable<SvelteMap<number, number>>(new SvelteMap()),
204
- atom_color_config = {
205
- mode: DEFAULTS.structure.atom_color_mode,
206
- scale: DEFAULTS.structure.atom_color_scale as D3InterpolateName,
207
- scale_type: DEFAULTS.structure.atom_color_scale_type,
208
- },
209
- sym_data = null,
210
- // Edit-atoms mode callbacks
211
- on_sites_moved,
212
- on_operation_start,
213
- on_bond_edit_start,
214
- on_add_atom,
215
- add_atom_mode = $bindable(false),
216
- add_element = $bindable(`C`),
217
- cursor = $bindable(`default`),
218
- dragging_atoms = $bindable(false),
219
- volumetric_data = undefined,
220
- isosurface_settings = DEFAULT_ISOSURFACE_SETTINGS,
221
- }: {
222
- structure?: AnyStructure
223
- base_structure?: AnyStructure // The original structure without image atoms, used for property color calculation
224
- atom_radius?: number // scale factor for atomic radii
225
- same_size_atoms?: boolean // whether to use the same radius for all atoms. if not, the radius will be
226
- // determined by the atomic radius of the element
227
- camera_position?: [x: number, y: number, z: number] // initial camera position from which to render the scene
228
- camera_target?: Vec3 // external orbit-controls target for pan synchronization
229
- camera_projection?: CameraProjection // camera projection type
230
- rotation_damping?: number // rotation damping factor (how quickly the rotation comes to rest after mouse release)
231
- // zoom level of the camera
232
- max_zoom?: number
233
- min_zoom?: number
234
- rotate_speed?: number // rotation speed. set to 0 to disable rotation.
235
- zoom_speed?: number // zoom speed. set to 0 to disable zooming.
236
- pan_speed?: number // pan speed. set to 0 to disable panning.
237
- zoom_to_cursor?: boolean // zoom toward cursor position instead of scene center
238
- show_atoms?: boolean
239
- show_bonds?: ShowBonds
240
- show_site_labels?: boolean
241
- show_site_indices?: boolean
242
- vector_configs?: Record<string, VectorLayerConfig>
243
- vector_scale?: number
244
- vector_color?: string
245
- vector_color_mode?: VectorColorMode
246
- vector_color_scale?: D3InterpolateName
247
- vector_normalize?: boolean
248
- vector_uniform_thickness?: boolean
249
- vector_origin_gap?: number
250
- vector_shaft_radius?: number
251
- vector_arrow_head_radius?: number
252
- vector_arrow_head_length?: number
253
- gizmo?: boolean | ComponentProps<typeof extras.Gizmo>
254
- hovered_idx?: number | null
255
- hovered_site?: Site | null
256
- float_fmt?: string
257
- auto_rotate?: number
258
- initial_zoom?: number
259
- bond_thickness?: number
260
- bond_color?: string
261
- bonding_strategy?: BondingStrategy
262
- auto_bond_order?: boolean
263
- aromatic_display?: `aromatic` | `kekule`
264
- bonding_options?: Record<string, unknown>
265
- fov?: number
266
- ambient_light?: number
267
- directional_light?: number
268
- sphere_segments?: number
269
- lattice_props?: ComponentProps<typeof Lattice>
270
- atom_label?: Snippet<[{ site: Site; site_idx: number }]>
271
- site_label_size?: number
272
- site_label_offset?: Vec3
273
- site_label_bg_color?: string
274
- site_label_color?: string
275
- site_label_padding?: number
276
- camera_is_moving?: boolean // used to prevent tooltip from showing while camera is moving
277
- width?: number // Viewer dimensions for responsive zoom
278
- height?: number
279
- // measurement props
280
- measure_mode?: MeasureMode
281
- selected_sites?: number[]
282
- measured_sites?: number[]
283
- added_bonds?: StructureBond[]
284
- removed_bonds?: StructureBond[]
285
- bond_order_overrides?: StructureBond[]
286
- bond_edits_enabled?: boolean
287
- bond_edit_mode?: BondEditMode
288
- bond_edit_order?: BondOrder
289
- selection_highlight_color?: string
290
- // Support for active highlight group with different color
291
- active_sites?: number[]
292
- active_highlight_color?: string
293
- rotation?: Vec3 // rotation control prop
294
- // Expose scene and camera for external use (e.g. export pane)
295
- scene?: Scene
296
- camera?: Camera
297
- orbit_controls?: ComponentProps<typeof extras.OrbitControls>[`ref`] // OrbitControls instance
298
- rotation_target_ref?: Vec3 // Expose rotation target for reset
299
- initial_computed_zoom?: number // Expose initial zoom for reset
300
- hidden_elements?: Set<ElementSymbol>
301
- hidden_prop_vals?: Set<number | string> // Track hidden property values (e.g. Wyckoff positions, coordination numbers)
302
- element_radius_overrides?: Partial<Record<ElementSymbol, number>> // Per-element absolute radius in Angstroms
303
- site_radius_overrides?: Map<number, number> | SvelteMap<number, number> // Per-site absolute radius in Angstroms
304
- atom_color_config?: Partial<AtomColorConfig> // Atom coloring configuration
305
- sym_data?: MoyoDataset | null // Symmetry data for Wyckoff coloring
306
- // Edit-atoms mode callbacks and state
307
- on_sites_moved?: (scene_indices: number[], delta: Vec3) => void
308
- on_operation_start?: () => void
309
- on_bond_edit_start?: () => void
310
- on_add_atom?: (xyz: Vec3, element: ElementSymbol) => void
311
- add_atom_mode?: boolean // whether user is in click-to-place add-atom sub-mode
312
- add_element?: ElementSymbol // element to add when clicking in add-atom mode
313
- cursor?: string // cursor style for the 3D canvas
314
- dragging_atoms?: boolean // true while TransformControls drag is active (skips expensive recalculations)
315
- volumetric_data?: VolumetricData // Active volumetric data for isosurface rendering
316
- isosurface_settings?: IsosurfaceSettings // Isosurface rendering settings
317
- } = $props()
318
-
319
- const pulse = create_pulse_animation(
320
- () => selected_sites.length > 0 || active_sites.length > 0,
321
- { step: 0.015, frequency: 5 },
322
- )
323
- let pulse_opacity = $derived(0.15 + 0.25 * pulse.unit)
324
-
325
- const threlte = useThrelte()
326
- $effect(() => {
327
- scene = threlte.scene
328
- camera = threlte.camera.current
329
- if (threlte.renderer) {
330
- Object.assign(threlte.renderer.domElement, { __renderer: threlte.renderer })
331
- }
332
- })
333
-
334
- // Expose rotation target for external reset
335
- $effect(() => {
336
- rotation_target_ref = rotation_target
337
- })
338
-
339
- // Track initial computed zoom for reset
340
- let stored_initial_zoom = $state<number | undefined>(undefined)
341
- $effect(() => {
342
- if (stored_initial_zoom === undefined && computed_zoom > 0) {
343
- stored_initial_zoom = computed_zoom
344
- }
345
- initial_computed_zoom = stored_initial_zoom
346
- })
347
-
348
- let bond_pairs: BondPair[] = $state([])
349
- let atom_tooltip_active = $state(false)
350
- let hovered_bond_key = $state<string | null>(null)
351
- const ATOM_HOVER_CLEAR_DELAY_MS = 200
352
- let clear_atom_hover_timeout: ReturnType<typeof setTimeout> | null = null
353
-
354
- function cancel_atom_hover_clear(): void {
355
- if (clear_atom_hover_timeout == null) return
356
- clearTimeout(clear_atom_hover_timeout)
357
- clear_atom_hover_timeout = null
358
- }
359
-
360
- function set_atom_hover(site_idx: number): void {
361
- cancel_atom_hover_clear()
362
- if (hovered_idx !== site_idx) hovered_idx = site_idx
363
- if (!atom_tooltip_active) atom_tooltip_active = true
364
- }
365
-
366
- function schedule_atom_hover_clear(site_idx: number): void {
367
- cancel_atom_hover_clear()
368
- clear_atom_hover_timeout = setTimeout(() => {
369
- clear_atom_hover_timeout = null
370
- if (hovered_idx !== site_idx) return
371
- hovered_idx = null
372
- atom_tooltip_active = false
373
- }, ATOM_HOVER_CLEAR_DELAY_MS)
374
- }
375
-
376
- const atom_hover_props = (site_idx: number | null, disabled = false) => ({
377
- onpointerenter: () => {
378
- if (!disabled && site_idx != null) set_atom_hover(site_idx)
379
- },
380
- onpointermove: () => {
381
- if (!disabled && site_idx != null) set_atom_hover(site_idx)
382
- },
383
- onpointerleave: () => {
384
- if (!disabled && site_idx != null) schedule_atom_hover_clear(site_idx)
385
- },
386
- })
387
-
388
- // Cursor style for the canvas, derived from mode and hover state
389
- let canvas_cursor = $derived.by(() => {
390
- if (measure_mode === `edit-atoms` && add_atom_mode) return `crosshair`
391
- if (measure_mode === `edit-bonds` && hovered_bond_key != null) {
392
- return bond_edits_enabled ? `pointer` : `not-allowed`
393
- }
394
- if (hovered_idx != null) {
395
- if (measure_mode === `edit-bonds`) {
396
- return bond_edit_mode === `add` && can_select_bond_site(hovered_idx)
397
- ? `pointer`
398
- : `not-allowed`
399
- }
400
- if (measure_mode === `edit-atoms`) {
401
- const site = structure?.sites?.[hovered_idx]
402
- if (site?.properties?.orig_site_idx != null) return `not-allowed`
403
- return `pointer`
404
- }
405
- return `pointer`
406
- }
407
- return `default`
408
- })
409
-
410
- // Desaturate a color by blending it toward gray (for ghosting image atoms in edit mode)
411
- const gray = new Color(0x999999)
412
- function desaturate(hex: string | undefined, amount = 0.4): string {
413
- return `#${new Color(hex ?? 0x999999).lerp(gray, amount).getHexString()}`
414
- }
415
-
416
- // === Edit-atoms mode state ===
417
- let transform_object = $state<Mesh | undefined>(undefined)
418
- // Plain variable — only used imperatively in TransformControls drag handlers
419
- let drag_start_centroid: Vec3 | null = null
420
- // Frozen centroid set on drag start. While non-null, the TransformControls mesh
421
- // position stays at this fixed value so Svelte's reactive centroid updates (from
422
- // PBC wrapping) don't fight TransformControls. Cleared on mouseUp so the mesh
423
- // snaps to the new wrapped centroid.
424
- let frozen_centroid = $state<Vec3 | null>(null)
425
-
426
- let bond_context_menu = $state<BondContextMenu | null>(null)
427
- // Threlte/HTML pointer events can close the visible menu before a button
428
- // handler runs, so keep the target bond separately for menu actions.
429
- let bond_context_target: BondContextMenu | null = null
430
-
431
- function close_bond_context_menu() {
432
- bond_context_menu = null
433
- bond_context_target = null
434
- }
435
-
436
- const canonical_bond_target = (bond: BondKeyTarget): BondKeyTarget =>
437
- canonicalize_bond_target(bond, structure?.sites)
438
-
439
- const bond_key_for = (bond: BondKeyTarget): string => {
440
- const target = canonical_bond_target(bond)
441
- return get_bond_key(target.site_idx_1, target.site_idx_2, target.cell_shift)
442
- }
443
- const rendered_bond_key_for = (bond: BondKeyTarget): string =>
444
- get_bond_key(bond.site_idx_1, bond.site_idx_2, bond.cell_shift)
445
-
446
- const matches_bond_key = (bond: BondKeyTarget, key: string): boolean =>
447
- bond_key_for(bond) === key
448
-
449
- const find_added_bond_by_rendered_key = (key: string): StructureBond | undefined =>
450
- added_bonds.find((bond) => rendered_bond_key_for(bond) === key)
451
-
452
- function resolve_bond_edit_target(
453
- site_idx_1: number,
454
- site_idx_2: number,
455
- cell_shift?: Vec3,
456
- ): BondKeyTarget {
457
- const rendered_target = { site_idx_1, site_idx_2, cell_shift }
458
- const rendered_key = rendered_bond_key_for(rendered_target)
459
- return find_added_bond_by_rendered_key(rendered_key) ??
460
- canonical_bond_target(rendered_target)
461
- }
462
-
463
- const is_image_bond_site = (site_idx: number): boolean =>
464
- structure?.sites?.[site_idx]?.properties?.orig_site_idx != null
465
-
466
- const can_select_bond_site = (site_idx: number): boolean =>
467
- bond_edits_enabled && structure?.sites?.[site_idx] != null
468
-
469
- const can_edit_bond = (bond: BondKeyTarget): boolean => {
470
- const target = canonical_bond_target(bond)
471
- return bond_edits_enabled &&
472
- !is_image_bond_site(target.site_idx_1) &&
473
- !is_image_bond_site(target.site_idx_2)
474
- }
475
-
476
- const format_bond_order = (order: BondOrder | undefined): string =>
477
- order === undefined ? `1` : `${order}`
478
-
479
- function get_current_bond_order(
480
- site_idx_1: number,
481
- site_idx_2: number,
482
- cell_shift?: Vec3,
483
- ): BondOrder | undefined {
484
- const key = get_bond_key(site_idx_1, site_idx_2, cell_shift)
485
- return find_added_bond_by_rendered_key(key)?.order ??
486
- bond_order_overrides.find((bond) => matches_bond_key(bond, key))?.order ??
487
- added_bonds.find((bond) => matches_bond_key(bond, key))?.order ??
488
- filtered_bond_pairs.find((bond) => matches_bond_key(bond, key))?.bond_order
489
- }
490
-
491
- const midpoint = (pos_1: Vec3, pos_2: Vec3): Vec3 => [
492
- (pos_1[0] + pos_2[0]) / 2,
493
- (pos_1[1] + pos_2[1]) / 2,
494
- (pos_1[2] + pos_2[2]) / 2,
495
- ]
496
-
497
- const BOND_ENDPOINT_HIT_FRACTION = 0.3
498
- const BOND_ENDPOINT_SITE_MATCH_TOLERANCE = 1e-6
499
- const EDITABLE_ATOM_HIT_RADIUS_SCALE = 1.15
500
- const skip_raycast = (): void => undefined
501
-
502
- function apply_bond_transform(mesh: Mesh, bond: BondPair): void {
503
- mesh.matrix.fromArray(bond.transform_matrix)
504
- mesh.matrixWorldNeedsUpdate = true
505
- }
506
-
507
- function apply_non_raycastable_bond_hit_transform(mesh: Mesh, bond: BondPair): void {
508
- apply_bond_transform(mesh, bond)
509
- disable_raycast(mesh)
510
- }
511
-
512
- function disable_raycast(mesh: Mesh): void {
513
- mesh.raycast = skip_raycast
514
- }
515
-
516
- function site_world_position(parent: Object3D, site: Site): Vector3 {
517
- const position = new Vector3(...site.xyz)
518
- return parent.localToWorld(position)
519
- }
520
-
521
- function get_bond_endpoint_site_idx(
522
- site_idx: number,
523
- world_position: Vector3,
524
- parent: Object3D,
525
- ): number {
526
- if (!structure?.sites) return site_idx
527
- const site = structure.sites[site_idx]
528
- if (!site) return site_idx
529
-
530
- const matches_world_position = (candidate_site: Site): boolean =>
531
- site_world_position(parent, candidate_site).distanceTo(world_position) <=
532
- BOND_ENDPOINT_SITE_MATCH_TOLERANCE
533
-
534
- if (matches_world_position(site)) {
535
- return site_idx
536
- }
537
-
538
- const image_site_idx = structure.sites.findIndex((candidate_site) =>
539
- candidate_site.properties?.orig_site_idx === site_idx &&
540
- matches_world_position(candidate_site)
541
- )
542
- return image_site_idx === -1 ? site_idx : image_site_idx
543
- }
544
-
545
- function get_bond_endpoint_hit_site_idx(
546
- bond: BondPair,
547
- event: BondPointerEvent,
548
- ): number | null {
549
- if (!event.point) return null
550
- const parent = event.object?.parent
551
- if (!parent) return null
552
-
553
- const world_pos_1 = new Vector3(...bond.pos_1)
554
- const world_pos_2 = new Vector3(...bond.pos_2)
555
- parent.localToWorld(world_pos_1)
556
- parent.localToWorld(world_pos_2)
557
-
558
- const bond_vec = world_pos_2.clone().sub(world_pos_1)
559
- const length_sq = bond_vec.lengthSq()
560
- if (length_sq <= math.EPS) return null
561
-
562
- const hit_vec = event.point.clone().sub(world_pos_1)
563
- const bond_fraction = hit_vec.dot(bond_vec) / length_sq
564
- if (bond_fraction <= BOND_ENDPOINT_HIT_FRACTION) {
565
- return get_bond_endpoint_site_idx(bond.site_idx_1, world_pos_1, parent)
566
- }
567
- if (bond_fraction >= 1 - BOND_ENDPOINT_HIT_FRACTION) {
568
- return get_bond_endpoint_site_idx(bond.site_idx_2, world_pos_2, parent)
569
- }
570
- return null
571
- }
572
-
573
- let label_screen_margin = $derived(site_label_size * 10 + site_label_padding)
574
-
575
- function get_bond_context_menu_position(
576
- bond: BondPair,
577
- event?: BondContextMenuEvent,
578
- ): Vec3 {
579
- const parent = event?.object?.parent
580
- if (!event?.point || !parent) return midpoint(bond.pos_1, bond.pos_2)
581
-
582
- const local_point = event.point.clone()
583
- parent.worldToLocal(local_point)
584
- return [local_point.x, local_point.y, local_point.z]
585
- }
586
-
587
- function open_bond_context_menu(bond: BondPair, event?: BondContextMenuEvent) {
588
- if (!can_edit_bond(bond)) return
589
- bond_context_target = {
590
- site_idx_1: bond.site_idx_1,
591
- site_idx_2: bond.site_idx_2,
592
- cell_shift: bond.cell_shift,
593
- position: get_bond_context_menu_position(bond, event),
594
- }
595
- bond_context_menu = bond_context_target
596
- }
597
-
598
- const current_bond_edit_state = () => ({
599
- added_bonds,
600
- removed_bonds,
601
- bond_order_overrides,
602
- })
603
-
604
- function apply_bond_edit_result(result: BondEditResult, close_menu = true) {
605
- if (!result.changed) return
606
- on_bond_edit_start?.()
607
- added_bonds = result.state.added_bonds
608
- removed_bonds = result.state.removed_bonds
609
- bond_order_overrides = result.state.bond_order_overrides
610
- if (close_menu) close_bond_context_menu()
611
- }
612
-
613
- const find_visible_bond = (
614
- target: BondKeyTarget,
615
- canonical_target: BondKeyTarget = target,
616
- ): BondPair | undefined => {
617
- const rendered_key = rendered_bond_key_for(target)
618
- const canonical_key = bond_key_for(canonical_target)
619
- return filtered_bond_pairs.find((bond) => rendered_bond_key_for(bond) === rendered_key) ??
620
- filtered_bond_pairs.find((bond) => bond_key_for(bond) === canonical_key)
621
- }
622
-
623
- function open_bond_order_menu_for_target(
624
- target: BondKeyTarget,
625
- canonical_target: BondKeyTarget = target,
626
- ) {
627
- const bond = find_visible_bond(target, canonical_target)
628
- if (bond) open_bond_context_menu(bond)
629
- }
630
-
631
- function add_or_restore_pair(site_idx_1: number, site_idx_2: number) {
632
- const rendered_target = { site_idx_1, site_idx_2 }
633
- if (!can_edit_bond(rendered_target)) return
634
- const edit_state = current_bond_edit_state()
635
- const canonical_target = canonical_bond_target(rendered_target)
636
- const canonical_result = add_or_restore_bond(
637
- edit_state,
638
- canonical_target,
639
- editable_perceived_bond_pairs,
640
- bond_edit_order,
641
- )
642
- const use_rendered_target =
643
- canonical_result.action === `added` &&
644
- rendered_bond_key_for(canonical_target) !== rendered_bond_key_for(rendered_target)
645
- const target = use_rendered_target ? rendered_target : canonical_target
646
- const result = use_rendered_target
647
- ? add_or_restore_bond(
648
- edit_state,
649
- rendered_target,
650
- editable_perceived_bond_pairs,
651
- bond_edit_order,
652
- )
653
- : canonical_result
654
- if (result.action === `already-visible`) {
655
- open_bond_order_menu_for_target(rendered_target, target)
656
- return
657
- }
658
- apply_bond_edit_result(result, false)
659
- }
660
-
661
- function set_bond_order(
662
- site_idx_1: number,
663
- site_idx_2: number,
664
- order: BondOrder,
665
- cell_shift?: Vec3,
666
- ) {
667
- const target = resolve_bond_edit_target(site_idx_1, site_idx_2, cell_shift)
668
- if (!can_edit_bond(target)) return
669
- apply_bond_edit_result(
670
- apply_set_bond_order(
671
- current_bond_edit_state(),
672
- target,
673
- editable_perceived_bond_pairs,
674
- order,
675
- ),
676
- )
677
- }
678
-
679
- function set_context_bond_order(order: BondOrder) {
680
- const menu = bond_context_target ?? bond_context_menu
681
- if (!menu) return
682
- set_bond_order(menu.site_idx_1, menu.site_idx_2, order, menu.cell_shift)
683
- }
684
-
685
- function remove_bond(site_idx_1: number, site_idx_2: number, cell_shift?: Vec3) {
686
- const target = resolve_bond_edit_target(site_idx_1, site_idx_2, cell_shift)
687
- if (!can_edit_bond(target)) return
688
- apply_bond_edit_result(
689
- apply_delete_bond(
690
- current_bond_edit_state(),
691
- target,
692
- editable_perceived_bond_pairs,
693
- ),
694
- )
695
- }
696
-
697
- function remove_context_bond() {
698
- const menu = bond_context_target ?? bond_context_menu
699
- if (!menu) return
700
- remove_bond(menu.site_idx_1, menu.site_idx_2, menu.cell_shift)
701
- }
702
-
703
- // Deduplicate clicks: when a highlight sphere and the underlying atom both
704
- // intercept the same native click, only the first intersection should fire.
705
- // All threlte intersection events from one click share the same nativeEvent ref.
706
- let last_native_event: Event | null = null
707
- // extras.Instance does not always emit pointerdown, so edit-bonds also falls
708
- // back to click. When pointerdown did fire, skip the matching click once.
709
- let last_edit_bonds_pointerdown_site_idx: number | null = null
710
- let clear_edit_bonds_pointerdown_site_timeout:
711
- | ReturnType<typeof setTimeout>
712
- | null = null
713
-
714
- function remember_edit_bonds_pointerdown_site(site_idx: number) {
715
- last_edit_bonds_pointerdown_site_idx = site_idx
716
- if (clear_edit_bonds_pointerdown_site_timeout != null) {
717
- clearTimeout(clear_edit_bonds_pointerdown_site_timeout)
718
- }
719
- clear_edit_bonds_pointerdown_site_timeout = setTimeout(() => {
720
- last_edit_bonds_pointerdown_site_idx = null
721
- clear_edit_bonds_pointerdown_site_timeout = null
722
- }, 250)
723
- }
724
-
725
- function select_edit_bonds_site(site_idx: number, event: Event): void {
726
- toggle_selection(site_idx, event)
727
- remember_edit_bonds_pointerdown_site(site_idx)
728
- }
729
-
730
- function skip_duplicate_edit_bonds_click(site_idx: number) {
731
- if (last_edit_bonds_pointerdown_site_idx !== site_idx) return false
732
-
733
- last_edit_bonds_pointerdown_site_idx = null
734
- if (clear_edit_bonds_pointerdown_site_timeout != null) {
735
- clearTimeout(clear_edit_bonds_pointerdown_site_timeout)
736
- clear_edit_bonds_pointerdown_site_timeout = null
737
- }
738
- return true
739
- }
740
-
741
- function toggle_selection(site_index: number, evt?: Event) {
742
- evt?.stopPropagation?.()
743
- const event_with_native = evt as Event & { nativeEvent?: unknown } | undefined
744
- const native_event = event_with_native?.nativeEvent ?? evt
745
- if (native_event instanceof Event) {
746
- if (native_event === last_native_event) return
747
- last_native_event = native_event
748
- }
749
-
750
- if (measure_mode === `edit-bonds`) {
751
- if (bond_edit_mode === `delete`) {
752
- measured_sites = []
753
- selected_sites = []
754
- return
755
- }
756
- if (!can_select_bond_site(site_index)) return
757
- // In Add mode, select atom pairs without making existing bonds destructive.
758
- const new_sites = measured_sites.includes(site_index)
759
- ? measured_sites.filter((idx) => idx !== site_index)
760
- : [...measured_sites, site_index]
761
-
762
- measured_sites = new_sites
763
- selected_sites = new_sites
764
-
765
- // When two atoms are selected, add/restore or open order editing.
766
- if (new_sites.length === 2) {
767
- add_or_restore_pair(new_sites[0], new_sites[1])
768
- measured_sites = []
769
- selected_sites = []
770
- }
771
- return
772
- }
773
-
774
- if (measure_mode === `edit-atoms`) {
775
- // Block image atoms (detected by orig_site_idx property from PBC)
776
- const site = structure?.sites?.[site_index]
777
- if (site?.properties?.orig_site_idx != null) return
778
-
779
- const is_selected = selected_sites.includes(site_index)
780
- const is_shift = evt instanceof MouseEvent && evt.shiftKey
781
-
782
- // In edit-atoms mode, selected_sites and measured_sites always stay in sync
783
- let new_sites: number[]
784
- if (is_shift) {
785
- // Multi-select: toggle this site in/out of selection
786
- new_sites = is_selected
787
- ? selected_sites.filter((idx) => idx !== site_index)
788
- : [...selected_sites, site_index]
789
- } else {
790
- // Single-select: replace selection (or deselect if already selected)
791
- new_sites = is_selected ? [] : [site_index]
792
- }
793
- selected_sites = new_sites
794
- measured_sites = new_sites
795
- return
796
- }
797
-
798
- if (
799
- !measured_sites.includes(site_index) &&
800
- measured_sites.length >= measure.MAX_SELECTED_SITES
801
- ) {
802
- console.warn(
803
- `Selection size limit reached (${measure.MAX_SELECTED_SITES}). Deselect some sites first.`,
804
- )
805
- return
806
- }
807
-
808
- measured_sites = measured_sites.includes(site_index)
809
- ? measured_sites.filter((idx) => idx !== site_index)
810
- : [...measured_sites, site_index]
811
- selected_sites = selected_sites.includes(site_index)
812
- ? selected_sites.filter((idx) => idx !== site_index)
813
- : [...selected_sites, site_index]
814
- }
815
-
816
- $effect(() => {
817
- void structure
818
- void measure_mode
819
- void bond_edit_mode
820
- void bond_edits_enabled
821
- untrack(() => {
822
- close_bond_context_menu()
823
- hovered_bond_key = null
824
- })
825
- })
826
-
827
- $effect(() => {
828
- const count = structure?.sites?.length ?? 0
829
- if (count <= 0) {
830
- measured_sites = []
831
- return
832
- }
833
- untrack(() => {
834
- measured_sites = measured_sites.filter((idx) => idx >= 0 && idx < count)
835
- })
836
- })
837
-
838
- $effect(() => {
839
- cursor = canvas_cursor
840
- })
841
-
842
- extras.interactivity()
843
- $effect.pre(() => {
844
- hovered_site = structure?.sites?.[hovered_idx ?? -1] ?? null
845
- })
846
- let lattice = $derived(
847
- structure && `lattice` in structure ? structure.lattice : null,
848
- )
849
-
850
- let visual_lattice = $derived(
851
- base_structure && `lattice` in base_structure ? base_structure.lattice : lattice,
852
- )
853
-
854
- let rotation_target = $derived(
855
- lattice
856
- ? (math.scale(math.add(...lattice.matrix), 0.5) as Vec3)
857
- : structure
858
- ? get_center_of_mass(structure)
859
- : [0, 0, 0] as Vec3,
860
- )
861
-
862
- let structure_size = $derived.by(() => {
863
- if (lattice) return (lattice.a + lattice.b + lattice.c) / 2
864
- if (!structure?.sites?.length) return 10
865
-
866
- const ranges = [0, 1, 2].map((axis_idx) => {
867
- const coords = structure.sites.map((site) => site.xyz[axis_idx])
868
- return Math.max(...coords) - Math.min(...coords)
869
- })
870
- return Math.max(1, ...ranges)
871
- })
872
-
873
- // Characteristic inter-atomic spacing: cube root of volume per atom.
874
- // Excludes PBC image atoms (orig_site_idx) so toggling image atoms doesn't affect arrow sizing.
875
- let char_atom_spacing = $derived.by(() => {
876
- if (!lattice || !structure?.sites?.length) return structure_size
877
- const n_real = structure.sites.filter((site) =>
878
- site.properties?.orig_site_idx == null
879
- ).length
880
- return n_real > 0 ? Math.cbrt(lattice.volume / n_real) : structure_size
881
- })
882
-
883
- // When uniform thickness is on, convert negative (length-relative) radii to
884
- // positive (absolute) values scaled by inter-atomic spacing.
885
- // Already-positive (absolute) values are preserved as-is.
886
- let eff_shaft_radius = $derived(
887
- vector_uniform_thickness && vector_shaft_radius < 0
888
- ? char_atom_spacing * -vector_shaft_radius
889
- : vector_shaft_radius,
890
- )
891
- let eff_head_radius = $derived(
892
- vector_uniform_thickness && vector_arrow_head_radius < 0
893
- ? char_atom_spacing * -vector_arrow_head_radius
894
- : vector_arrow_head_radius,
895
- )
896
- let eff_head_length = $derived(
897
- vector_uniform_thickness && vector_arrow_head_length < 0
898
- ? char_atom_spacing * -vector_arrow_head_length
899
- : vector_arrow_head_length,
900
- )
901
-
902
- // Compute dynamic camera clipping planes based on structure size
903
- // This prevents z-fighting and disappearing objects when zooming in close on large supercells
904
- let camera_near = $derived(Math.max(0.01, structure_size * 0.01))
905
- let camera_far = $derived(Math.max(1000, structure_size * 100))
906
-
907
- // Using $state because this is mutated in an effect based on viewport/structure size
908
- let computed_zoom = $state(untrack(() => initial_zoom))
909
- $effect(() => {
910
- if (!(width > 0) || !(height > 0)) return
911
- const structure_max_dim = Math.max(1, untrack(() => structure_size))
912
- const viewer_min_dim = Math.min(width, height)
913
- const scale_factor = viewer_min_dim / (structure_max_dim * 50) // 50px per unit
914
- let new_zoom = initial_zoom * scale_factor
915
- if (min_zoom && min_zoom > 0) new_zoom = Math.max(min_zoom, new_zoom)
916
- if (max_zoom && max_zoom > 0) new_zoom = Math.min(max_zoom, new_zoom)
917
- computed_zoom = new_zoom
918
- })
919
-
920
- $effect.pre(() => { // Simple initial camera auto-position: proportional to structure size and fov
921
- if (camera_position.every((val) => val === 0) && structure) {
922
- stored_initial_zoom = undefined
923
- const distance = Math.max(1, structure_size) * (60 / fov)
924
- camera_position = [distance, distance * 0.3, distance * 0.8]
925
- }
926
- })
927
- $effect(() => {
928
- if (structure && show_bonds !== `never`) {
929
- // Determine if we should show bonds based on the setting and structure type
930
- const should_show_bonds = show_bonds === `always` ||
931
- (show_bonds === `crystals` && lattice) ||
932
- (show_bonds === `molecules` && !lattice)
933
-
934
- if (should_show_bonds) {
935
- bond_pairs = BONDING_STRATEGIES[bonding_strategy](structure, bonding_options)
936
- } else bond_pairs = []
937
- } else bond_pairs = []
938
- })
939
-
940
- // Compute property-based colors when not using element coloring
941
- // Use base_structure (original unit cell) for color calculation
942
- let property_colors = $derived(
943
- get_property_colors(
944
- base_structure || structure,
945
- atom_color_config,
946
- bonding_strategy,
947
- sym_data,
948
- ),
949
- )
950
- // Compute weighted average radius for a site based on species occupancies
951
- // Normalizes by total occupancy so vacancy-containing sites render at full size
952
- const calc_weighted_radius = (site: Site): number => {
953
- const total_occu = site.species.reduce((sum, { occu }) => sum + occu, 0)
954
- const weighted_sum = site.species.reduce((sum, { element, occu }) => {
955
- const override = element_radius_overrides?.[element as ElementSymbol]
956
- return sum + occu * (override ?? atomic_radii[element] ?? 1)
957
- }, 0)
958
- return total_occu > 0 ? weighted_sum / total_occu : 1
959
- }
960
-
961
- let atom_data = $derived.by(() => {
962
- if (!show_atoms || !structure?.sites) return []
963
- const render_sites = merge_split_partial_sites(structure.sites, hidden_elements)
964
- return render_sites.flatMap(({ site_idx, site, is_image_atom }) => {
965
- const orig_idx = get_orig_site_idx(site, site_idx)
966
-
967
- // Skip sites with hidden property values
968
- const prop_val = property_colors?.values[orig_idx]
969
- if (prop_val !== undefined && hidden_prop_vals.has(prop_val)) return []
970
-
971
- // Calculate radius: same_size > site override > element override > default
972
- // All radii scale uniformly with atom_radius for consistent slider behavior
973
- const base_radius = same_size_atoms
974
- ? 1
975
- : site_radius_overrides?.get(site_idx) ?? calc_weighted_radius(site)
976
- const radius = base_radius * atom_radius
977
-
978
- // Use property color if available (e.g. coordination number, Wyckoff position)
979
- // Otherwise, each species gets its own element color (important for disordered sites)
980
- const site_property_color = property_colors?.colors[orig_idx]
981
-
982
- const visible_species = site.species.filter(({ element }) =>
983
- !hidden_elements.has(element)
984
- )
985
- const slice_geometry = compute_slice_geometry(visible_species)
986
- return slice_geometry.map((slice_data) => {
987
- return {
988
- site_idx,
989
- element: slice_data.element,
990
- occupancy: slice_data.occupancy,
991
- position: site.xyz,
992
- radius,
993
- color: site_property_color ?? colors.element?.[slice_data.element],
994
- has_partial_occupancy: slice_data.occupancy < 1,
995
- start_phi: slice_data.start_phi,
996
- end_phi: slice_data.end_phi,
997
- phi_length: slice_data.phi_length,
998
- render_start_cap: slice_data.render_start_cap,
999
- render_end_cap: slice_data.render_end_cap,
1000
- is_image_atom,
1001
- }
1002
- })
1003
- })
1004
- })
1005
-
1006
- // Shared visibility check: site has at least one non-hidden element and
1007
- // its property value (if any) isn't hidden. Used by both bond and vector filtering.
1008
- const is_site_visible = (site_idx: number): boolean => {
1009
- if (!structure?.sites) return false
1010
- const site = structure.sites[site_idx]
1011
- const has_visible_element = site?.species.some(({ element }) =>
1012
- !hidden_elements.has(element)
1013
- )
1014
- const orig_idx = get_orig_site_idx(site, site_idx)
1015
- const prop_val = property_colors?.values[orig_idx]
1016
- const prop_visible = prop_val === undefined ||
1017
- !hidden_prop_vals.has(prop_val)
1018
- return has_visible_element && prop_visible
1019
- }
1020
-
1021
- // Perception layer: bond_pairs with optional bond-order perception applied.
1022
- // Off by default (pass-through). Manual overrides are applied downstream in
1023
- // filtered_bond_pairs, so they still win over perceived orders.
1024
- let perceived_bond_pairs: BondPair[] = $derived.by(() => {
1025
- if (!auto_bond_order || !structure?.sites || bond_pairs.length === 0) {
1026
- return bond_pairs
1027
- }
1028
- const total_charge = (`charge` in structure ? structure.charge : 0) ?? 0
1029
- const perceived = perceive_bond_orders(structure.sites, bond_pairs, {
1030
- total_charge,
1031
- })
1032
- // Explicit structure.properties.bonds are user-authoritative and must
1033
- // never be clobbered by perception. Composition + precedence is a pure,
1034
- // unit-tested helper (see compose_perceived_bonds).
1035
- return compose_perceived_bonds(
1036
- perceived,
1037
- get_explicit_bond_metadata(structure),
1038
- aromatic_display,
1039
- )
1040
- })
1041
-
1042
- let editable_perceived_bond_pairs = $derived(
1043
- perceived_bond_pairs.map((bond) => ({ ...bond, ...canonical_bond_target(bond) })),
1044
- )
1045
-
1046
- let filtered_bond_pairs = $derived.by(() => {
1047
- if (!structure?.sites) return perceived_bond_pairs
1048
-
1049
- // Build set of removed bond keys for efficient lookup
1050
- const removed_keys = new Set(
1051
- removed_bonds.map(bond_key_for),
1052
- )
1053
- const added_keys = new Set(
1054
- added_bonds.map(bond_key_for),
1055
- )
1056
- const order_overrides = new Map(
1057
- bond_order_overrides.map((bond) => [bond_key_for(bond), bond.order]),
1058
- )
1059
-
1060
- // Filter calculated bonds: exclude removed, replaced by manual additions, and hidden.
1061
- const calculated = perceived_bond_pairs
1062
- .filter((bond) => {
1063
- const key = bond_key_for(bond)
1064
- if (removed_keys.has(key) || added_keys.has(key)) return false
1065
- return is_site_visible(bond.site_idx_1) && is_site_visible(bond.site_idx_2)
1066
- })
1067
- .map((bond) => {
1068
- const override = order_overrides.get(bond_key_for(bond))
1069
- return override === undefined ? bond : { ...bond, bond_order: override }
1070
- })
1071
-
1072
- // Create BondPair objects for manually added bonds
1073
- const added: BondPair[] = []
1074
- for (const added_bond of added_bonds) {
1075
- const { site_idx_1: idx_i, site_idx_2: idx_j } = added_bond
1076
- if (!is_site_visible(idx_i) || !is_site_visible(idx_j)) continue
1077
- added.push(structure_bond_to_bond_pair(structure, added_bond))
1078
- }
1079
-
1080
- return [...calculated, ...added]
1081
- })
1082
-
1083
- let editable_bond_pairs = $derived(
1084
- bond_edits_enabled ? filtered_bond_pairs.filter(can_edit_bond) : [],
1085
- )
1086
-
1087
- let smart_site_label_offsets = $derived.by(() => {
1088
- const offsets = new SvelteMap<number, Vec3>()
1089
- if (filtered_bond_pairs.length === 0) return offsets
1090
-
1091
- const bond_directions_by_site = new SvelteMap<number, Vec3[]>()
1092
- const add_bond_direction = (site_idx: number, pos_1: Vec3, pos_2: Vec3) => {
1093
- const direction = math.normalize_vec3(
1094
- math.subtract(pos_2, pos_1),
1095
- [0, 0, 0],
1096
- )
1097
- if (Math.hypot(...direction) < LABEL_OFFSET_EPS) return
1098
- bond_directions_by_site.set(site_idx, [
1099
- ...(bond_directions_by_site.get(site_idx) ?? []),
1100
- direction,
1101
- ])
1102
- }
1103
-
1104
- for (const { site_idx_1, site_idx_2, pos_1, pos_2 } of filtered_bond_pairs) {
1105
- add_bond_direction(site_idx_1, pos_1, pos_2)
1106
- add_bond_direction(site_idx_2, pos_2, pos_1)
1107
- }
1108
- for (const [site_idx, bond_directions] of bond_directions_by_site) {
1109
- offsets.set(site_idx, choose_site_label_offset(bond_directions, site_label_offset))
1110
- }
1111
- return offsets
1112
- })
1113
-
1114
- let instanced_bond_groups = $derived.by(() => {
1115
- if (!structure?.sites || filtered_bond_pairs.length === 0) return []
1116
-
1117
- const group = {
1118
- thickness: bond_thickness,
1119
- ambient_light,
1120
- directional_light,
1121
- instances: [] as {
1122
- matrix: Float32Array
1123
- color_start: string
1124
- color_end: string
1125
- }[],
1126
- }
1127
-
1128
- for (const bond_data of filtered_bond_pairs) {
1129
- const site_a = structure.sites[bond_data.site_idx_1]
1130
- const site_b = structure.sites[bond_data.site_idx_2]
1131
-
1132
- const get_majority_color = (site: typeof site_a) => {
1133
- if (!site?.species || site.species.length === 0) return bond_color
1134
- const majority_species = site.species.reduce((max, spec) =>
1135
- spec.occu > max.occu ? spec : max
1136
- )
1137
- return colors.element?.[majority_species.element] || bond_color
1138
- }
1139
-
1140
- const color_start = get_majority_color(site_a)
1141
- const color_end = get_majority_color(site_b)
1142
- for (const matrix of get_bond_render_matrices(bond_data, bond_thickness)) {
1143
- group.instances.push({ matrix, color_start, color_end })
1144
- }
1145
- }
1146
-
1147
- return group.instances.length > 0 ? [group] : []
1148
- })
1149
-
1150
- let radius_by_site_idx = $derived.by(() => {
1151
- const map = new SvelteMap<number, number>()
1152
- for (const atom of atom_data) {
1153
- if (!map.has(atom.site_idx)) map.set(atom.site_idx, atom.radius)
1154
- }
1155
- return map
1156
- })
1157
-
1158
- let editable_atom_hit_targets = $derived.by(() => {
1159
- if (
1160
- measure_mode !== `edit-bonds` ||
1161
- bond_edit_mode !== `add` ||
1162
- !bond_edits_enabled
1163
- ) {
1164
- return []
1165
- }
1166
-
1167
- const targets = new SvelteMap<number, EditableAtomHitTarget>()
1168
- for (const atom of atom_data) {
1169
- if (!can_select_bond_site(atom.site_idx)) continue
1170
- if (targets.has(atom.site_idx)) continue
1171
- targets.set(atom.site_idx, {
1172
- site_idx: atom.site_idx,
1173
- position: atom.position,
1174
- radius: atom.radius,
1175
- })
1176
- }
1177
- return [...targets.values()]
1178
- })
1179
-
1180
- // Get radius for a site (for highlight fallback when site is hidden/filtered)
1181
- // Checks site_radius_overrides first for consistency with visible atoms
1182
- const get_site_radius = (site: Site, site_idx: number | null): number => {
1183
- const override = site_idx !== null
1184
- ? site_radius_overrides?.get(site_idx)
1185
- : undefined
1186
- const base_radius = same_size_atoms ? 1 : override ?? calc_weighted_radius(site)
1187
- return base_radius * atom_radius
1188
- }
1189
-
1190
- // Interpolate between spin-down (#3498db blue) and spin-up (#e74c3c red)
1191
- // based on the z-component direction of a magnetic vector
1192
- function spin_direction_color(vec: Vec3): string {
1193
- const mag = Math.hypot(...vec)
1194
- const z_frac = mag > 1e-10 ? (vec[2] / mag + 1) / 2 : 0.5 // 0=down, 1=up
1195
- const red = Math.round(52 + (231 - 52) * z_frac)
1196
- const grn = Math.round(152 + (76 - 152) * z_frac)
1197
- const blu = Math.round(219 + (60 - 219) * z_frac)
1198
- return `#${red.toString(16).padStart(2, `0`)}${
1199
- grn.toString(16).padStart(2, `0`)
1200
- }${blu.toString(16).padStart(2, `0`)}`
1201
- }
1202
-
1203
- // Build one arrow layer per visible vector key. Auto-scales the longest
1204
- // vector to 1.8× char_atom_spacing (cube root of volume per atom).
1205
- // When vector_normalize is on, effective_max is 1 so all arrows get equal length.
1206
- // Single active key preserves legacy coloring (element for force,
1207
- // spin-direction for magmom/spin). Multiple keys use flat palette colors.
1208
- let vector_layers = $derived.by(() => {
1209
- if (!structure?.sites) return []
1210
- const keys = get_structure_vector_keys(structure)
1211
- const active_keys = keys.filter((key) => vector_configs[key]?.visible !== false)
1212
- if (active_keys.length === 0) return []
1213
-
1214
- // Build per-site lookup; skip hidden sites so they don't contribute
1215
- // arrows or affect autoscaling. null entries = hidden site.
1216
- const active_set = new Set(active_keys)
1217
- let max_mag = 0
1218
- const site_vec_maps = structure.sites.map((site, site_idx) => {
1219
- if (!is_site_visible(site_idx)) return null
1220
- const map = new SvelteMap<string, Vec3>()
1221
- for (const { key, vec } of get_all_site_vectors(site)) {
1222
- map.set(key, vec)
1223
- if (active_set.has(key)) {
1224
- max_mag = Math.max(max_mag, Math.hypot(...vec))
1225
- }
1226
- }
1227
- return map
1228
- })
1229
-
1230
- // When normalize is on, treat all magnitudes as 1 so arrows have equal length
1231
- const effective_max = vector_normalize ? 1 : max_mag
1232
- const auto_scale = effective_max > 1e-10
1233
- ? (char_atom_spacing * 1.8) / effective_max
1234
- : 1
1235
- const is_single = active_keys.length === 1
1236
- const effective_global_scale = auto_scale * vector_scale
1237
-
1238
- // When vector_origin_gap > 0 and multiple vectors exist at a site,
1239
- // arrange arrow origins on a regular polygon centered on the atom, in a
1240
- // plane perpendicular to the mean vector direction. The gap is a fraction
1241
- // of the visual atom radius (0 = center, 0.5 = halfway to surface).
1242
- // get_site_radius() returns the uniform scale applied to SphereGeometry(0.5),
1243
- // so visual_radius = get_site_radius() * 0.5.
1244
- const site_offsets = (vector_origin_gap > 0 && !is_single)
1245
- ? structure.sites.map((site, site_idx) => {
1246
- const vec_map = site_vec_maps[site_idx]
1247
- if (!vec_map) return null
1248
- const site_keys = active_keys.filter((key) => vec_map.has(key))
1249
- const n_keys = site_keys.length
1250
- if (n_keys <= 1) return null
1251
- const visual_radius = get_site_radius(site, site_idx) * 0.5
1252
- const gap_abs = vector_origin_gap * visual_radius
1253
- let mean: Vec3 = [0, 0, 0]
1254
- for (const key of site_keys) {
1255
- const vec = vec_map.get(key)
1256
- if (vec) mean = math.add(mean, math.normalize_vec3(vec)) as Vec3
1257
- }
1258
- const mean_dir = math.normalize_vec3(mean, [0, 1, 0] as Vec3)
1259
- const [u_vec, v_vec] = math.compute_in_plane_basis(mean_dir)
1260
- const offsets = new SvelteMap<string, Vec3>()
1261
- for (const [idx, key] of site_keys.entries()) {
1262
- const angle = (2 * Math.PI * idx) / n_keys
1263
- const dx = math.scale(u_vec, gap_abs * Math.cos(angle)) as Vec3
1264
- const dy = math.scale(v_vec, gap_abs * Math.sin(angle)) as Vec3
1265
- offsets.set(key, math.add(dx, dy) as Vec3)
1266
- }
1267
- return offsets
1268
- })
1269
- : null
1270
-
1271
- const mag_interpolator = get_d3_interpolator(vector_color_scale)
1272
-
1273
- return active_keys.map((key, layer_idx) => {
1274
- const layer_cfg = vector_configs[key]
1275
- const layer_scale = effective_global_scale * (layer_cfg?.scale ?? 1.0)
1276
- const layer_color = layer_cfg?.color ??
1277
- VECTOR_PALETTE[layer_idx % VECTOR_PALETTE.length]
1278
-
1279
- const arrows = structure.sites
1280
- .map((site, site_idx) => {
1281
- const vec_map = site_vec_maps[site_idx]
1282
- if (!vec_map) return null
1283
- const vec = vec_map.get(key)
1284
- if (!vec) return null
1285
-
1286
- // Resolve color mode: explicit per-key color always wins,
1287
- // then multi-key uses palette, then mode-based coloring
1288
- let arrow_color: string
1289
- if (layer_cfg?.color) {
1290
- arrow_color = layer_cfg.color
1291
- } else if (!is_single) arrow_color = layer_color
1292
- else {
1293
- const effective_mode = vector_color_mode === `auto`
1294
- ? (key.startsWith(`magmom`) || key.startsWith(`spin`)
1295
- ? `spin_direction`
1296
- : `element`)
1297
- : vector_color_mode
1298
- if (effective_mode === `magnitude`) {
1299
- const mag = Math.hypot(...vec)
1300
- const norm = max_mag > 1e-10 ? mag / max_mag : 0
1301
- arrow_color = mag_interpolator(norm)
1302
- } else if (effective_mode === `spin_direction`) {
1303
- arrow_color = spin_direction_color(vec)
1304
- } else if (effective_mode === `uniform`) {
1305
- arrow_color = vector_color
1306
- } else {
1307
- const majority_element = site.species.length > 0
1308
- ? site.species.reduce((max, spec) =>
1309
- spec.occu > max.occu ? spec : max
1310
- ).element
1311
- : undefined
1312
- arrow_color =
1313
- (majority_element && colors.element?.[majority_element]) ||
1314
- vector_color
1315
- }
1316
- }
1317
-
1318
- const offset = site_offsets?.[site_idx]?.get(key)
1319
- const position = offset ? math.add(site.xyz, offset) as Vec3 : site.xyz
1320
- const arrow_vec = vector_normalize ? math.normalize_vec3(vec) : vec
1321
-
1322
- return {
1323
- site_idx,
1324
- position,
1325
- vector: arrow_vec,
1326
- scale: layer_scale,
1327
- color: arrow_color,
1328
- }
1329
- })
1330
- .filter((item): item is NonNullable<typeof item> => item !== null)
1331
-
1332
- return { key, arrows }
1333
- })
1334
- })
1335
-
1336
- let instanced_atom_groups = $derived(
1337
- Object.values(
1338
- atom_data
1339
- .filter((atom) => !atom.has_partial_occupancy)
1340
- .reduce(
1341
- (groups, atom) => {
1342
- const { element, radius, color, is_image_atom } = atom
1343
- // Separate image atoms into their own groups for distinct styling in edit-atoms mode
1344
- const key = `${element}-${format_num(radius, `.3~`)}-${color}-${
1345
- is_image_atom ? `img` : `base`
1346
- }`
1347
- const bucket = groups[key] ||
1348
- (groups[key] = { element, radius, color, is_image_atom, atoms: [] })
1349
- bucket.atoms.push(atom)
1350
- return groups
1351
- },
1352
- {} as Record<string, InstancedAtomGroup>,
1353
- ),
1354
- ),
1355
- )
1356
-
1357
- let unique_instanced_atoms = $derived(
1358
- Object.values(
1359
- instanced_atom_groups
1360
- .flatMap((group) => group.atoms)
1361
- .reduce((acc, atom) => {
1362
- acc[atom.site_idx] = atom
1363
- return acc
1364
- }, {} as Record<number, (typeof atom_data)[number]>),
1365
- ),
1366
- )
1367
-
1368
- let gizmo_props = $derived.by(() => {
1369
- const axis_options = Object.fromEntries(
1370
- [...AXIS_COLORS, ...NEG_AXIS_COLORS].map(([axis, color, hover_color]) => [
1371
- axis,
1372
- {
1373
- color,
1374
- labelColor: `#111`,
1375
- opacity: axis.startsWith(`n`) ? 0.9 : 0.8,
1376
- hover: {
1377
- color: hover_color,
1378
- labelColor: `#222222`,
1379
- opacity: axis.startsWith(`n`) ? 1 : 0.9,
1380
- },
1381
- },
1382
- ]),
1383
- )
1384
- return {
1385
- background: { enabled: false },
1386
- className: `responsive-gizmo`,
1387
- ...axis_options,
1388
- ...(typeof gizmo === `boolean` ? {} : gizmo),
1389
- offset: { left: 5, bottom: 5 },
1390
- }
1391
- })
1392
-
1393
- let orbit_controls_props = $derived({
1394
- position: [0, 0, 0],
1395
- enableRotate: rotate_speed > 0,
1396
- rotateSpeed: rotate_speed,
1397
- enableZoom: zoom_speed > 0,
1398
- zoomSpeed: camera_projection === `orthographic` ? zoom_speed * 2 : zoom_speed,
1399
- zoomToCursor: zoom_to_cursor,
1400
- enablePan: pan_speed > 0,
1401
- panSpeed: pan_speed,
1402
- target: camera_target ?? rotation_target,
1403
- maxZoom: max_zoom,
1404
- minZoom: min_zoom,
1405
- autoRotate: Boolean(auto_rotate),
1406
- autoRotateSpeed: auto_rotate,
1407
- enableDamping: Boolean(rotation_damping),
1408
- dampingFactor: rotation_damping,
1409
- onstart: () => {
1410
- camera_is_moving = true
1411
- cancel_atom_hover_clear()
1412
- hovered_idx = null
1413
- bond_context_menu = null
1414
- },
1415
- onend: () => {
1416
- camera_is_moving = false
1417
- },
1418
- })
1419
-
1420
- let measure_line_color = $derived.by(() => {
1421
- if (typeof window === `undefined`) return
1422
- const root_styles = getComputedStyle(document.documentElement)
1423
- const text_color = root_styles.getPropertyValue(`--text-color`).trim()
1424
- return text_color || `#808080`
1425
- })
1426
- </script>
1427
-
1428
- {#snippet bond_instanced_mesh_snippet(
1429
- group: ComponentProps<typeof Bond>[`group`],
1430
- )}
1431
- {#key group.instances.length}
1432
- <Bond {group} />
1433
- {/key}
1434
- {/snippet}
1435
-
1436
- {#snippet site_label_snippet(position: Vec3, site_idx: number)}
1437
- {@const site = structure!.sites[site_idx]}
1438
- {@const visual_radius = (radius_by_site_idx.get(site_idx) ?? 1) * 0.5}
1439
- <extras.HTML
1440
- center
1441
- position={position}
1442
- calculatePosition={make_label_position_calculator(
1443
- position,
1444
- () => smart_site_label_offsets.get(site_idx) ?? site_label_offset,
1445
- visual_radius,
1446
- label_screen_margin,
1447
- )}
1448
- >
1449
- {#if atom_label}
1450
- {@render atom_label({ site, site_idx })}
1451
- {:else}
1452
- <button
1453
- type="button"
1454
- class="atom-label"
1455
- style:font-size="{site_label_size * 0.85}em"
1456
- style:background={site_label_bg_color}
1457
- style:padding="{site_label_padding}px"
1458
- style:color={site_label_color}
1459
- onpointerdown={(event) => {
1460
- event.preventDefault()
1461
- event.stopImmediatePropagation()
1462
- toggle_selection(site_idx, event)
1463
- }}
1464
- onclick={(event) => {
1465
- event.preventDefault()
1466
- event.stopImmediatePropagation()
1467
- }}
1468
- onkeydown={(event) => {
1469
- if (event.key !== `Enter` && event.key !== ` `) return
1470
- event.preventDefault()
1471
- event.stopPropagation()
1472
- toggle_selection(site_idx, event)
1473
- }}
1474
- >
1475
- {#if show_site_labels}
1476
- {#if site.species.length === 1}
1477
- {site.species[0].element}{#if show_site_indices}-{site_idx + 1}{/if}
1478
- {:else}
1479
- {#each site.species as
1480
- { element, occu, oxidation_state }
1481
- (`${element}-${occu}-${oxidation_state}`)
1482
- }
1483
- {element}<sub>{format_num(occu, `.3~`).replace(`0.`, `.`)}</sub>
1484
- {/each}
1485
- {#if show_site_indices}-{site_idx + 1}{/if}
1486
- {/if}
1487
- {:else if show_site_indices}
1488
- {site_idx + 1}
1489
- {/if}
1490
- </button>
1491
- {/if}
1492
- </extras.HTML>
1493
- {/snippet}
1494
-
1495
- {#if camera_projection === `perspective`}
1496
- <T.PerspectiveCamera
1497
- makeDefault
1498
- position={camera_position}
1499
- {fov}
1500
- near={camera_near}
1501
- far={camera_far}
1502
- >
1503
- <extras.OrbitControls bind:ref={orbit_controls} {...orbit_controls_props}>
1504
- {#if gizmo}<extras.Gizmo {...gizmo_props} />{/if}
1505
- </extras.OrbitControls>
1506
- </T.PerspectiveCamera>
1507
- {:else}
1508
- <T.OrthographicCamera
1509
- makeDefault
1510
- position={camera_position}
1511
- zoom={computed_zoom}
1512
- near={-100}
1513
- far={camera_far}
1514
- >
1515
- <extras.OrbitControls bind:ref={orbit_controls} {...orbit_controls_props}>
1516
- {#if gizmo}<extras.Gizmo {...gizmo_props} />{/if}
1517
- </extras.OrbitControls>
1518
- </T.OrthographicCamera>
1519
- {/if}
1520
-
1521
- <T.DirectionalLight position={[3, 10, 10]} intensity={directional_light} />
1522
- <T.AmbientLight intensity={ambient_light} />
1523
-
1524
- <!-- Apply manual rotation around center: translate to origin, rotate, translate back -->
1525
- <T.Group position={rotation_target}>
1526
- <T.Group {rotation}>
1527
- <T.Group position={math.scale(rotation_target, -1)}>
1528
- {#if show_atoms}
1529
- <!-- Instanced rendering for full occupancy atoms -->
1530
- {#each instanced_atom_groups as atom_group (instanced_atom_group_key(atom_group, measure_mode))}
1531
- {@const { element, radius, color, is_image_atom, atoms } = atom_group}
1532
- {@const edit_mode_image = measure_mode === `edit-atoms` && is_image_atom}
1533
- <extras.InstancedMesh
1534
- key={instanced_atom_group_key(atom_group, measure_mode)}
1535
- limit={atoms.length}
1536
- range={atoms.length}
1537
- frustumCulled={false}
1538
- >
1539
- <T.SphereGeometry args={[0.5, sphere_segments, sphere_segments]} />
1540
- <T.MeshStandardMaterial
1541
- color={edit_mode_image ? desaturate(color) : color}
1542
- opacity={edit_mode_image ? 0.5 : 1}
1543
- transparent={edit_mode_image}
1544
- />
1545
- {#each atoms as atom (atom.site_idx)}
1546
- <extras.Instance
1547
- position={atom.position}
1548
- scale={atom.radius}
1549
- {...atom_hover_props(atom.site_idx, edit_mode_image)}
1550
- onpointerdown={(event: PointerEvent) => {
1551
- if (
1552
- edit_mode_image ||
1553
- measure_mode !== `edit-bonds` ||
1554
- bond_edit_mode !== `add`
1555
- ) {
1556
- return
1557
- }
1558
- select_edit_bonds_site(atom.site_idx, event)
1559
- }}
1560
- onclick={(event: MouseEvent) => {
1561
- if (edit_mode_image) return
1562
- if (measure_mode === `edit-bonds`) {
1563
- if (bond_edit_mode !== `add`) return
1564
- if (skip_duplicate_edit_bonds_click(atom.site_idx)) {
1565
- event.stopPropagation()
1566
- return
1567
- }
1568
- }
1569
- toggle_selection(atom.site_idx, event)
1570
- }}
1571
- />
1572
- {/each}
1573
- </extras.InstancedMesh>
1574
- {/each}
1575
-
1576
- <!-- Regular rendering for partial occupancy atoms -->
1577
- {#each atom_data.filter((atom) => atom.has_partial_occupancy) as
1578
- atom
1579
- (atom.site_idx + atom.element + atom.occupancy)
1580
- }
1581
- {@const partial_edit_image = measure_mode === `edit-atoms` && atom.is_image_atom}
1582
- {@const ghost_opacity = partial_edit_image ? 0.5 : 1}
1583
- <T.Group
1584
- position={atom.position}
1585
- scale={atom.radius}
1586
- {...atom_hover_props(atom.site_idx, partial_edit_image)}
1587
- onpointerdown={(event: PointerEvent) => {
1588
- if (
1589
- partial_edit_image ||
1590
- measure_mode !== `edit-bonds` ||
1591
- bond_edit_mode !== `add`
1592
- ) {
1593
- return
1594
- }
1595
- select_edit_bonds_site(atom.site_idx, event)
1596
- }}
1597
- onclick={(event: MouseEvent) => {
1598
- if (partial_edit_image) return
1599
- if (measure_mode === `edit-bonds`) {
1600
- if (bond_edit_mode !== `add`) return
1601
- if (skip_duplicate_edit_bonds_click(atom.site_idx)) {
1602
- event.stopPropagation()
1603
- return
1604
- }
1605
- }
1606
- toggle_selection(atom.site_idx, event)
1607
- }}
1608
- >
1609
- {@const partial_color = partial_edit_image
1610
- ? desaturate(atom.color)
1611
- : atom.color}
1612
- <T.Mesh>
1613
- <T.SphereGeometry
1614
- args={[
1615
- 0.5,
1616
- sphere_segments,
1617
- sphere_segments,
1618
- atom.start_phi,
1619
- atom.phi_length,
1620
- ]}
1621
- />
1622
- <T.MeshStandardMaterial
1623
- color={partial_color}
1624
- opacity={ghost_opacity}
1625
- transparent={partial_edit_image}
1626
- />
1627
- </T.Mesh>
1628
-
1629
- {#if atom.has_partial_occupancy && atom.render_start_cap}
1630
- <T.Mesh rotation={[0, atom.start_phi, 0]}>
1631
- <T.CircleGeometry
1632
- args={[
1633
- 0.5,
1634
- sphere_segments,
1635
- PARTIAL_OCCUPANCY_CAP_ARC.start_cap_arc_start,
1636
- PARTIAL_OCCUPANCY_CAP_ARC.arc_length,
1637
- ]}
1638
- />
1639
- <T.MeshStandardMaterial
1640
- color={partial_color}
1641
- side={2}
1642
- opacity={ghost_opacity}
1643
- transparent={partial_edit_image}
1644
- />
1645
- </T.Mesh>
1646
- {/if}
1647
- {#if atom.has_partial_occupancy && atom.render_end_cap}
1648
- <T.Mesh rotation={[0, atom.end_phi, 0]}>
1649
- <T.CircleGeometry
1650
- args={[
1651
- 0.5,
1652
- sphere_segments,
1653
- PARTIAL_OCCUPANCY_CAP_ARC.end_cap_arc_start,
1654
- PARTIAL_OCCUPANCY_CAP_ARC.arc_length,
1655
- ]}
1656
- />
1657
- <T.MeshStandardMaterial
1658
- color={partial_color}
1659
- side={2}
1660
- opacity={ghost_opacity}
1661
- transparent={partial_edit_image}
1662
- />
1663
- </T.Mesh>
1664
- {/if}
1665
- </T.Group>
1666
-
1667
- <!-- Render label only for the first species of this site to avoid duplicates -->
1668
- {#if (show_site_labels || show_site_indices) &&
1669
- atom.element === structure!.sites[atom.site_idx].species[0].element}
1670
- {@render site_label_snippet(atom.position, atom.site_idx)}
1671
- {/if}
1672
- {/each}
1673
-
1674
- <!-- Site labels/indices for instanced atoms -->
1675
- {#if show_site_labels || show_site_indices}
1676
- {#each unique_instanced_atoms as atom (atom.site_idx)}
1677
- {@render site_label_snippet(atom.position, atom.site_idx)}
1678
- {/each}
1679
- {/if}
1680
- {/if}
1681
-
1682
- {#each vector_layers as layer (layer.key)}
1683
- {#each layer.arrows as arrow (`${layer.key}-${arrow.site_idx}`)}
1684
- <Arrow
1685
- {...arrow}
1686
- shaft_radius={eff_shaft_radius}
1687
- arrow_head_radius={eff_head_radius}
1688
- arrow_head_length={eff_head_length}
1689
- />
1690
- {/each}
1691
- {/each}
1692
-
1693
- <!-- Instanced bond rendering with gradient colors -->
1694
- {#if instanced_bond_groups.length > 0}
1695
- {#each instanced_bond_groups as group (group.thickness + group.instances.length)}
1696
- {@render bond_instanced_mesh_snippet(group)}
1697
- {/each}
1698
- {/if}
1699
-
1700
- <!-- Clickable bond hit-test cylinders in edit-bonds mode -->
1701
- {#if measure_mode === `edit-bonds` && editable_bond_pairs.length > 0}
1702
- {#each editable_bond_pairs as
1703
- bond
1704
- (`bond-hit-${bond_edit_mode}-${rendered_bond_key_for(bond)}`)
1705
- }
1706
- {@const bond_key = rendered_bond_key_for(bond)}
1707
- {@const is_hovered = hovered_bond_key === bond_key}
1708
- {@const is_delete_mode = bond_edit_mode === `delete`}
1709
- {@const bond_hit_radius =
1710
- bond_thickness * (is_delete_mode ? 5 : 1.25)}
1711
- {@const bond_hover_radius = bond_thickness * 1.1}
1712
- <T.Mesh
1713
- matrixAutoUpdate={false}
1714
- oncreate={(ref) => apply_bond_transform(ref, bond)}
1715
- onpointerdown={(event: BondPointerEvent) => {
1716
- if (event.nativeEvent?.button === 2) return
1717
- event.stopPropagation()
1718
- if (is_delete_mode) {
1719
- remove_bond(bond.site_idx_1, bond.site_idx_2, bond.cell_shift)
1720
- measured_sites = []
1721
- selected_sites = []
1722
- hovered_bond_key = null
1723
- } else {
1724
- const endpoint_site_idx = get_bond_endpoint_hit_site_idx(bond, event)
1725
- if (endpoint_site_idx != null) {
1726
- select_edit_bonds_site(endpoint_site_idx, event)
1727
- }
1728
- }
1729
- }}
1730
- oncontextmenu={(event: BondContextMenuEvent) => {
1731
- event.nativeEvent?.preventDefault()
1732
- event.stopPropagation?.()
1733
- open_bond_context_menu(bond, event)
1734
- }}
1735
- onpointerenter={() => (hovered_bond_key = bond_key)}
1736
- onpointermove={() => (hovered_bond_key = bond_key)}
1737
- onpointerleave={() => (hovered_bond_key = null)}
1738
- >
1739
- <T.CylinderGeometry
1740
- args={[
1741
- bond_hit_radius,
1742
- bond_hit_radius,
1743
- 1,
1744
- 6,
1745
- ]}
1746
- />
1747
- <T.MeshBasicMaterial
1748
- transparent
1749
- opacity={0}
1750
- depthWrite={false}
1751
- />
1752
- </T.Mesh>
1753
- {#if is_hovered}
1754
- <T.Mesh
1755
- matrixAutoUpdate={false}
1756
- oncreate={(ref) => apply_non_raycastable_bond_hit_transform(ref, bond)}
1757
- >
1758
- <T.CylinderGeometry args={[bond_hover_radius, bond_hover_radius, 1, 6]} />
1759
- <T.MeshBasicMaterial
1760
- transparent
1761
- opacity={0.25}
1762
- color={is_delete_mode ? `#ff4444` : `#6cf0ff`}
1763
- depthWrite={false}
1764
- />
1765
- </T.Mesh>
1766
- {/if}
1767
- {/each}
1768
- {/if}
1769
-
1770
- {#if editable_atom_hit_targets.length > 0}
1771
- {#each editable_atom_hit_targets as atom_hit (atom_hit.site_idx)}
1772
- <T.Mesh
1773
- position={atom_hit.position}
1774
- scale={atom_hit.radius * EDITABLE_ATOM_HIT_RADIUS_SCALE}
1775
- {...atom_hover_props(atom_hit.site_idx)}
1776
- onpointerdown={(event: PointerEvent) => {
1777
- select_edit_bonds_site(atom_hit.site_idx, event)
1778
- }}
1779
- >
1780
- <T.SphereGeometry args={[0.5, 12, 12]} />
1781
- <T.MeshBasicMaterial
1782
- transparent
1783
- opacity={0}
1784
- depthWrite={false}
1785
- />
1786
- </T.Mesh>
1787
- {/each}
1788
- {/if}
1789
-
1790
- {#if measure_mode === `edit-bonds` && bond_context_menu}
1791
- {@const current_order = get_current_bond_order(
1792
- bond_context_menu.site_idx_1,
1793
- bond_context_menu.site_idx_2,
1794
- bond_context_menu.cell_shift,
1795
- )}
1796
- <extras.HTML autoRender={false} position={bond_context_menu.position}>
1797
- <div class="bond-context-menu">
1798
- <strong>Bond Order ({format_bond_order(current_order)})</strong>
1799
- {#each BOND_ORDER_OPTIONS as { order, label } (label)}
1800
- <button
1801
- type="button"
1802
- onpointerdown={(event: PointerEvent) => {
1803
- event.preventDefault()
1804
- event.stopPropagation()
1805
- set_context_bond_order(order)
1806
- }}
1807
- onkeydown={(event: KeyboardEvent) => {
1808
- if (event.key !== `Enter` && event.key !== ` `) return
1809
- event.preventDefault()
1810
- event.stopPropagation()
1811
- set_context_bond_order(order)
1812
- }}
1813
- >
1814
- {label}
1815
- </button>
1816
- {/each}
1817
- <button
1818
- type="button"
1819
- class="remove"
1820
- onpointerdown={(event: PointerEvent) => {
1821
- event.preventDefault()
1822
- event.stopPropagation()
1823
- remove_context_bond()
1824
- }}
1825
- onkeydown={(event: KeyboardEvent) => {
1826
- if (event.key !== `Enter` && event.key !== ` `) return
1827
- event.preventDefault()
1828
- event.stopPropagation()
1829
- remove_context_bond()
1830
- }}
1831
- >
1832
- Remove
1833
- </button>
1834
- <button
1835
- type="button"
1836
- onpointerdown={(event: PointerEvent) => {
1837
- event.preventDefault()
1838
- event.stopPropagation()
1839
- close_bond_context_menu()
1840
- }}
1841
- onkeydown={(event: KeyboardEvent) => {
1842
- if (event.key !== `Enter` && event.key !== ` `) return
1843
- event.preventDefault()
1844
- event.stopPropagation()
1845
- close_bond_context_menu()
1846
- }}
1847
- >
1848
- Close
1849
- </button>
1850
- </div>
1851
- </extras.HTML>
1852
- {/if}
1853
-
1854
- <!-- highlight hovered, active and selected sites -->
1855
- {#each [
1856
- {
1857
- kind: `hover`,
1858
- site: hovered_site,
1859
- opacity: 0.28,
1860
- color: `white`,
1861
- site_idx: hovered_idx,
1862
- },
1863
- ...((selected_sites ?? []).map((idx) => ({
1864
- kind: `selected`,
1865
- site: structure?.sites?.[idx] ?? null,
1866
- site_idx: idx,
1867
- opacity: pulse_opacity,
1868
- color: selection_highlight_color,
1869
- }))),
1870
- ...((active_sites ?? []).map((idx) => ({
1871
- kind: `active`,
1872
- site: structure?.sites?.[idx] ?? null,
1873
- site_idx: idx,
1874
- opacity: pulse_opacity, // Let it pulse freely
1875
- color: active_highlight_color,
1876
- }))),
1877
- ] as
1878
- entry
1879
- (`${entry.kind}-${entry.site_idx}`)
1880
- }
1881
- {@const { site, opacity, color, kind, site_idx } = entry}
1882
- {#if site}
1883
- {@const xyz = site.xyz}
1884
- {@const highlight_radius = site_idx !== null
1885
- ? radius_by_site_idx.get(site_idx) ?? get_site_radius(site, site_idx)
1886
- : get_site_radius(site, site_idx)}
1887
- <T.Mesh
1888
- position={xyz}
1889
- scale={1.2 * highlight_radius}
1890
- oncreate={disable_raycast}
1891
- >
1892
- <T.SphereGeometry args={[0.5, 22, 22]} />
1893
- <T.MeshStandardMaterial
1894
- {color}
1895
- transparent
1896
- {opacity}
1897
- emissive={color}
1898
- emissiveIntensity={kind === `selected` || kind === `active` ? 0.7 : 0.2}
1899
- depthTest={false}
1900
- depthWrite={false}
1901
- />
1902
- </T.Mesh>
1903
- {/if}
1904
- {/each}
1905
-
1906
- <!-- selection order labels (1, 2, 3, ...) for measurements and bond editing -->
1907
- {#if structure?.sites && (measured_sites?.length ?? 0) > 0 &&
1908
- (measure_mode === `distance` || measure_mode === `angle` ||
1909
- measure_mode === `edit-bonds`)}
1910
- {#each measured_sites as site_index, loop_idx (site_index)}
1911
- {@const site = structure.sites[site_index]}
1912
- {#if site}
1913
- <!-- shift selected site labels down to avoid overlapping regular site labels-->
1914
- {@const selection_offset = math.add(site_label_offset, [0, -0.5, 0])}
1915
- {@const pos = math.add(site.xyz, selection_offset) as Vec3}
1916
- <extras.HTML center position={pos}>
1917
- <span class="selection-label">{loop_idx + 1}</span>
1918
- </extras.HTML>
1919
- {/if}
1920
- {/each}
1921
- {/if}
1922
-
1923
- <!-- hovered site tooltip -->
1924
- {#if hovered_site && !camera_is_moving &&
1925
- (atom_tooltip_active || active_sites.includes(hovered_idx ?? -1))}
1926
- {@const abc = hovered_site.abc.map((val) => format_num(val, float_fmt)).join(
1927
- `, `,
1928
- )}
1929
- {@const xyz = hovered_site.xyz.map((val) => format_num(val, float_fmt)).join(
1930
- `, `,
1931
- )}
1932
- {@const bond_neighbors = (() => {
1933
- if (hovered_idx == null || !structure?.sites) return []
1934
- return filtered_bond_pairs
1935
- .filter((bond) =>
1936
- bond.site_idx_1 === hovered_idx || bond.site_idx_2 === hovered_idx
1937
- )
1938
- .map((bond) => {
1939
- const neighbor_idx = bond.site_idx_1 === hovered_idx
1940
- ? bond.site_idx_2
1941
- : bond.site_idx_1
1942
- return structure.sites[neighbor_idx]?.species[0]?.element ?? `?`
1943
- })
1944
- })()}
1945
- {@const bond_summary = (() => {
1946
- if (bond_neighbors.length === 0) return ``
1947
- const counts: Record<string, number> = {}
1948
- for (const elem of bond_neighbors) {
1949
- counts[elem] = (counts[elem] ?? 0) + 1
1950
- }
1951
- const parts = Object.entries(counts)
1952
- .sort(([a], [b]) => a.localeCompare(b))
1953
- .map(([elem, count]) => `${elem}: ${count}`)
1954
- return ` (${parts.join(`, `)})`
1955
- })()}
1956
- <CanvasTooltip position={hovered_site.xyz}>
1957
- <!-- Element symbols with occupancies for disordered sites -->
1958
- <div class="elements">
1959
- {#each hovered_site.species ?? [] as
1960
- { element, occu, oxidation_state: oxi_state },
1961
- idx
1962
- (`${element ?? ``}-${occu ?? ``}-${oxi_state ?? ``}-${idx}`)
1963
- }
1964
- {@const element_name = element_data.find((elem) =>
1965
- elem.symbol === element
1966
- )?.name ??
1967
- ``}
1968
- {#if idx > 0}&thinsp;{/if}
1969
- {#if occu !== 1}<span class="occupancy">{
1970
- format_num(occu, `.3~f`)
1971
- }</span>{/if}
1972
- <strong>
1973
- {element}{#if oxi_state != null && oxi_state !== 0}<sup>{Math.abs(
1974
- oxi_state,
1975
- )}{oxi_state > 0 ? `+` : `−`}</sup>{/if}
1976
- </strong>
1977
- {#if element_name}<span class="elem-name">{element_name}</span>{/if}
1978
- {/each}
1979
- </div>
1980
- <div class="coordinates fractional">abc: ({abc})</div>
1981
- <div class="coordinates cartesian">xyz: ({xyz}) Å</div>
1982
- {#if bond_neighbors.length > 0}
1983
- <div class="coordinates">Bonds: {bond_neighbors.length}{bond_summary}</div>
1984
- {/if}
1985
- </CanvasTooltip>
1986
- {/if}
1987
-
1988
- {#if visual_lattice}
1989
- <Lattice matrix={visual_lattice.matrix} {...lattice_props} />
1990
- {/if}
1991
-
1992
- <!-- TransformControls for editing atoms in edit-atoms mode -->
1993
- {#if measure_mode === `edit-atoms` && selected_sites.length > 0 &&
1994
- structure?.sites}
1995
- {@const selected_atoms = selected_sites
1996
- .map((idx) => structure?.sites?.[idx])
1997
- .filter((site): site is Site => site != null)}
1998
- {#if selected_atoms.length > 0}
1999
- {@const avg = (dim: number) =>
2000
- selected_atoms.reduce((sum, atom) => sum + atom.xyz[dim], 0) /
2001
- selected_atoms.length}
2002
- {@const centroid = [avg(0), avg(1), avg(2)] as Vec3}
2003
- <!-- Invisible mesh at centroid for TransformControls to manipulate.
2004
- During drag, use frozen_centroid so Svelte doesn't override TransformControls
2005
- with the wrapped centroid (which jumps on PBC boundary crossings). -->
2006
- <T.Mesh
2007
- position={frozen_centroid ?? centroid}
2008
- bind:ref={transform_object}
2009
- >
2010
- <T.SphereGeometry args={[0.01, 4, 4]} />
2011
- <T.MeshBasicMaterial transparent opacity={0} />
2012
- </T.Mesh>
2013
- <extras.TransformControls
2014
- object={transform_object}
2015
- translationSnap={0.1}
2016
- size={1.2}
2017
- space="world"
2018
- onobjectChange={() => {
2019
- if (!transform_object?.position || !drag_start_centroid) return
2020
- const { x: tx, y: ty, z: tz } = transform_object.position
2021
- const delta: Vec3 = [
2022
- tx - drag_start_centroid[0],
2023
- ty - drag_start_centroid[1],
2024
- tz - drag_start_centroid[2],
2025
- ]
2026
- // Update reference point so deltas are incremental, not cumulative.
2027
- // Without this, each frame compounds: sites already moved by previous
2028
- // delta get the full cumulative delta re-applied.
2029
- drag_start_centroid = [tx, ty, tz]
2030
- on_sites_moved?.(selected_sites, delta)
2031
- }}
2032
- onmouseDown={() => {
2033
- dragging_atoms = true
2034
- drag_start_centroid = frozen_centroid = [...centroid] as Vec3
2035
- on_operation_start?.()
2036
- }}
2037
- onmouseUp={() => {
2038
- dragging_atoms = false
2039
- frozen_centroid = null
2040
- drag_start_centroid = null
2041
- }}
2042
- />
2043
- {/if}
2044
- {/if}
2045
-
2046
- <!-- Invisible plane for click-to-place atom in add-atom mode -->
2047
- <!-- Uses onBeforeRender to orient normal toward camera so raycasts always hit -->
2048
- {#if measure_mode === `edit-atoms` && add_atom_mode}
2049
- {@const center = rotation_target ?? [0, 0, 0]}
2050
- <T.Mesh
2051
- position={center}
2052
- onBeforeRender={(mesh: Mesh) => {
2053
- if (camera) {
2054
- mesh.lookAt(camera.position)
2055
- }
2056
- }}
2057
- onclick={(event: { point: { x: number; y: number; z: number } }) => {
2058
- const { x, y, z } = event.point
2059
- on_add_atom?.([x, y, z] as Vec3, add_element as ElementSymbol)
2060
- }}
2061
- >
2062
- <T.PlaneGeometry
2063
- args={[
2064
- Math.max(200, structure_size * 4),
2065
- Math.max(200, structure_size * 4),
2066
- ]}
2067
- />
2068
- <T.MeshBasicMaterial transparent opacity={0} side={2} depthWrite={false} />
2069
- </T.Mesh>
2070
- {/if}
2071
-
2072
- <!-- Isosurface rendering from volumetric data (CHGCAR, .cube files) -->
2073
- {#if volumetric_data && isosurface_settings}
2074
- <Isosurface volume={volumetric_data} settings={isosurface_settings} />
2075
- {/if}
2076
-
2077
- <!-- Measurement overlays for measured sites -->
2078
- {#if structure?.sites && (measured_sites?.length ?? 0) > 0}
2079
- {#if measure_mode === `distance`}
2080
- {#each measured_sites as idx_i, loop_idx (idx_i)}
2081
- {#each measured_sites.slice(loop_idx + 1) as idx_j (idx_i + `-` + idx_j)}
2082
- {@const site_i = structure.sites[idx_i]}
2083
- {@const site_j = structure.sites[idx_j]}
2084
- {@const pos_i = site_i.xyz}
2085
- {@const pos_j = site_j.xyz}
2086
- <Cylinder
2087
- from={pos_i}
2088
- to={pos_j}
2089
- thickness={0.12}
2090
- color={measure_line_color}
2091
- />
2092
- {@const midpoint = [
2093
- (pos_i[0] + pos_j[0]) / 2,
2094
- (pos_i[1] + pos_j[1]) / 2,
2095
- (pos_i[2] + pos_j[2]) / 2,
2096
- ] as Vec3}
2097
- {@const direct = math.euclidean_dist(pos_i, pos_j)}
2098
- {@const pbc = lattice
2099
- ? measure.distance_pbc(pos_i, pos_j, lattice.matrix)
2100
- : direct}
2101
- {@const differ = lattice ? Math.abs(pbc - direct) > 1e-6 : false}
2102
- <extras.HTML center position={midpoint}>
2103
- <span class="measure-label">
2104
- {#if differ}
2105
- PBC: {format_num(pbc, float_fmt)} Å<br /><small>
2106
- Direct: {format_num(direct, float_fmt)} Å</small>
2107
- {:else}
2108
- {format_num(pbc, float_fmt)} Å
2109
- {/if}
2110
- </span>
2111
- </extras.HTML>
2112
- {/each}
2113
- {/each}
2114
- {:else if measure_mode === `angle` && measured_sites.length >= 3}
2115
- {#each measured_sites as idx_center (idx_center)}
2116
- {@const center = structure.sites[idx_center]}
2117
- {#each measured_sites.filter((idx) => idx !== idx_center) as
2118
- idx_a,
2119
- loop_idx
2120
- (idx_center + `-` + idx_a)
2121
- }
2122
- {#each measured_sites.filter((idx) => idx !== idx_center).slice(loop_idx + 1) as
2123
- idx_b
2124
- (idx_center + `-` + idx_a + `-` + idx_b)
2125
- }
2126
- {@const site_a = structure.sites[idx_a]}
2127
- {@const site_b = structure.sites[idx_b]}
2128
- {@const v1 = measure.displacement_pbc(center.xyz, site_a.xyz, lattice?.matrix)}
2129
- {@const v2 = measure.displacement_pbc(center.xyz, site_b.xyz, lattice?.matrix)}
2130
- {@const n1 = Math.hypot(v1[0], v1[1], v1[2])}
2131
- {@const n2 = Math.hypot(v2[0], v2[1], v2[2])}
2132
- {@const angle_deg = measure.angle_between_vectors(v1, v2, `degrees`)}
2133
- {#if n1 > math.EPS && n2 > math.EPS}
2134
- <!-- draw rays from center to the two sites -->
2135
- <Cylinder
2136
- from={center.xyz}
2137
- to={site_a.xyz}
2138
- thickness={0.05}
2139
- color={measure_line_color}
2140
- />
2141
- <Cylinder
2142
- from={center.xyz}
2143
- to={site_b.xyz}
2144
- thickness={0.05}
2145
- color={measure_line_color}
2146
- />
2147
- {@const bisector = math.add(math.scale(v1, 1 / n1), math.scale(v2, 1 / n2))}
2148
- {@const bis_norm = Math.hypot(...bisector) || 1}
2149
- {@const offset_dir = math.scale(bisector, 1 / bis_norm)}
2150
- {@const label_pos = math.add(center.xyz, math.scale(offset_dir, 0.6))}
2151
- <extras.HTML center position={label_pos}>
2152
- <span class="measure-label">{format_num(angle_deg, float_fmt)}°</span>
2153
- </extras.HTML>
2154
- {/if}
2155
- {/each}
2156
- {/each}
2157
- {/each}
2158
- {/if}
2159
- {/if}
2160
- </T.Group>
2161
- </T.Group>
2162
- </T.Group>
2163
-
2164
- <style>
2165
- :global(.structure .responsive-gizmo) {
2166
- width: clamp(70px, 18cqmin, 100px) !important;
2167
- height: clamp(70px, 18cqmin, 100px) !important;
2168
- }
2169
- .atom-label {
2170
- background: var(--struct-atom-label-bg, rgba(0, 0, 0, 0.1));
2171
- border: 0;
2172
- border-radius: var(--struct-atom-label-border-radius, var(--border-radius, 3pt));
2173
- color: inherit;
2174
- cursor: pointer;
2175
- font: inherit;
2176
- padding: var(--struct-atom-label-padding, 0 3px);
2177
- white-space: nowrap;
2178
- }
2179
- .elements {
2180
- margin-bottom: var(--canvas-tooltip-elements-margin);
2181
- }
2182
- .occupancy {
2183
- font-size: var(--canvas-tooltip-occu-font-size);
2184
- opacity: var(--canvas-tooltip-occu-opacity);
2185
- margin-right: var(--canvas-tooltip-occu-margin);
2186
- }
2187
- .elem-name {
2188
- font-size: var(--canvas-tooltip-elem-name-font-size, 0.85em);
2189
- opacity: var(--canvas-tooltip-elem-name-opacity, 0.7);
2190
- margin: var(--canvas-tooltip-elem-name-margin, 0 0 0 0.3em);
2191
- font-weight: var(--canvas-tooltip-elem-name-font-weight, normal);
2192
- }
2193
- .coordinates {
2194
- font-size: var(--canvas-tooltip-coords-font-size);
2195
- margin: var(--canvas-tooltip-coords-margin);
2196
- }
2197
- .measure-label {
2198
- background: var(--measure-label-bg, var(--surface-bg));
2199
- color: var(--measure-label-color, var(--text-color));
2200
- border-radius: var(--border-radius, 3pt);
2201
- padding: 0 5px;
2202
- user-select: none;
2203
- white-space: pre;
2204
- display: grid;
2205
- place-items: center;
2206
- line-height: 1.2;
2207
- font-size: var(--canvas-tooltip-font-size, clamp(8pt, 2cqmin, 18pt));
2208
- box-shadow: var(--measure-label-shadow, 0 1px 6px rgba(0, 0, 0, 0.2));
2209
- }
2210
- .bond-context-menu {
2211
- display: grid;
2212
- min-width: 8rem;
2213
- gap: 2pt;
2214
- padding: 3pt 5pt;
2215
- border-radius: var(--border-radius, 3pt);
2216
- background: var(--surface-bg, Canvas);
2217
- color: var(--text-color, currentColor);
2218
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
2219
- pointer-events: auto;
2220
- strong {
2221
- font-size: 0.85em;
2222
- padding: 0 2pt 2pt;
2223
- white-space: nowrap;
2224
- }
2225
- button {
2226
- border: none;
2227
- border-radius: var(--border-radius, 3pt);
2228
- background: transparent;
2229
- color: inherit;
2230
- cursor: pointer;
2231
- padding: 2pt 5pt;
2232
- text-align: left;
2233
- }
2234
- button:hover {
2235
- background: color-mix(in srgb, currentColor 10%, transparent);
2236
- }
2237
- button.remove {
2238
- color: var(--error-color, #f44336);
2239
- }
2240
- }
2241
- .selection-label {
2242
- display: inline-flex;
2243
- align-items: center;
2244
- justify-content: center;
2245
- min-width: 1.2em;
2246
- height: 1.2em;
2247
- padding: 0 0.25em;
2248
- border-radius: 999px;
2249
- background: var(--pane-btn-bg-hover);
2250
- color: var(--struct-text-color);
2251
- font-size: 0.85em;
2252
- line-height: 1;
2253
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
2254
- }
2255
- </style>