matterviz 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/dist/EmptyState.svelte +10 -2
  2. package/dist/FilePicker.svelte +123 -82
  3. package/dist/Icon.svelte +18 -12
  4. package/dist/MillerIndexInput.svelte +27 -21
  5. package/dist/api/optimade.js +6 -6
  6. package/dist/app.css +216 -207
  7. package/dist/brillouin/BrillouinZone.svelte +292 -149
  8. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  9. package/dist/brillouin/BrillouinZoneControls.svelte +32 -5
  10. package/dist/brillouin/BrillouinZoneExportPane.svelte +69 -42
  11. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
  12. package/dist/brillouin/BrillouinZoneInfoPane.svelte +99 -68
  13. package/dist/brillouin/BrillouinZoneScene.svelte +275 -163
  14. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  15. package/dist/brillouin/BrillouinZoneTooltip.svelte +17 -7
  16. package/dist/brillouin/compute.js +11 -6
  17. package/dist/chempot-diagram/ChemPotDiagram.svelte +162 -27
  18. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +451 -281
  19. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2148 -1642
  20. package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -5
  21. package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
  22. package/dist/chempot-diagram/async-compute.svelte.js +77 -0
  23. package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
  24. package/dist/chempot-diagram/chempot-worker.js +11 -0
  25. package/dist/chempot-diagram/color.js +1 -2
  26. package/dist/chempot-diagram/compute.d.ts +10 -0
  27. package/dist/chempot-diagram/compute.js +250 -88
  28. package/dist/chempot-diagram/index.d.ts +2 -1
  29. package/dist/chempot-diagram/index.js +2 -1
  30. package/dist/chempot-diagram/temperature.js +8 -9
  31. package/dist/chempot-diagram/types.d.ts +3 -0
  32. package/dist/chempot-diagram/types.js +1 -0
  33. package/dist/colors/index.d.ts +1 -1
  34. package/dist/colors/index.js +5 -3
  35. package/dist/composition/BarChart.svelte +128 -55
  36. package/dist/composition/BubbleChart.svelte +102 -49
  37. package/dist/composition/Composition.svelte +100 -79
  38. package/dist/composition/Formula.svelte +108 -62
  39. package/dist/composition/FormulaFilter.svelte +665 -537
  40. package/dist/composition/PieChart.svelte +183 -108
  41. package/dist/composition/format.d.ts +5 -0
  42. package/dist/composition/format.js +20 -3
  43. package/dist/composition/parse.js +14 -9
  44. package/dist/convex-hull/ConvexHull.svelte +93 -40
  45. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  46. package/dist/convex-hull/ConvexHull2D.svelte +549 -360
  47. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  48. package/dist/convex-hull/ConvexHull3D.svelte +1296 -827
  49. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  50. package/dist/convex-hull/ConvexHull4D.svelte +1004 -688
  51. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  52. package/dist/convex-hull/ConvexHullControls.svelte +115 -28
  53. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +1 -1
  54. package/dist/convex-hull/ConvexHullInfoPane.svelte +29 -3
  55. package/dist/convex-hull/ConvexHullStats.svelte +425 -328
  56. package/dist/convex-hull/ConvexHullTooltip.svelte +40 -16
  57. package/dist/convex-hull/GasPressureControls.svelte +104 -61
  58. package/dist/convex-hull/StructurePopup.svelte +25 -4
  59. package/dist/convex-hull/TemperatureSlider.svelte +45 -25
  60. package/dist/convex-hull/barycentric-coords.js +13 -7
  61. package/dist/convex-hull/demo-temperature.js +8 -4
  62. package/dist/convex-hull/gas-thermodynamics.js +17 -12
  63. package/dist/convex-hull/helpers.d.ts +9 -0
  64. package/dist/convex-hull/helpers.js +77 -34
  65. package/dist/convex-hull/thermodynamics.js +61 -56
  66. package/dist/convex-hull/types.d.ts +9 -14
  67. package/dist/convex-hull/types.js +0 -17
  68. package/dist/coordination/CoordinationBarPlot.svelte +227 -154
  69. package/dist/element/BohrAtom.svelte +55 -12
  70. package/dist/element/ElementHeading.svelte +7 -2
  71. package/dist/element/ElementPhoto.svelte +15 -9
  72. package/dist/element/ElementStats.svelte +10 -4
  73. package/dist/element/ElementTile.svelte +137 -73
  74. package/dist/element/Nucleus.svelte +39 -11
  75. package/dist/feedback/ClickFeedback.svelte +16 -5
  76. package/dist/feedback/DragOverlay.svelte +10 -2
  77. package/dist/feedback/Spinner.svelte +4 -2
  78. package/dist/feedback/StatusMessage.svelte +8 -2
  79. package/dist/fermi-surface/FermiSlice.svelte +118 -88
  80. package/dist/fermi-surface/FermiSurface.svelte +328 -187
  81. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  82. package/dist/fermi-surface/FermiSurfaceControls.svelte +113 -46
  83. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  84. package/dist/fermi-surface/FermiSurfaceScene.svelte +535 -342
  85. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  86. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +14 -5
  87. package/dist/fermi-surface/compute.js +16 -20
  88. package/dist/fermi-surface/parse.js +24 -14
  89. package/dist/fermi-surface/symmetry.js +2 -7
  90. package/dist/fermi-surface/types.d.ts +3 -5
  91. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1019 -765
  92. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +1 -1
  93. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +76 -22
  94. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +2 -3
  95. package/dist/icons.js +47 -0
  96. package/dist/index.d.ts +2 -1
  97. package/dist/index.js +2 -1
  98. package/dist/io/decompress.js +1 -1
  99. package/dist/io/export.d.ts +3 -0
  100. package/dist/io/export.js +129 -143
  101. package/dist/io/is-binary.js +2 -3
  102. package/dist/io/url-drop.js +1 -2
  103. package/dist/isosurface/Isosurface.svelte +202 -148
  104. package/dist/isosurface/IsosurfaceControls.svelte +46 -28
  105. package/dist/isosurface/parse.js +34 -29
  106. package/dist/isosurface/slice.js +5 -10
  107. package/dist/isosurface/types.d.ts +2 -1
  108. package/dist/isosurface/types.js +61 -12
  109. package/dist/labels.js +11 -8
  110. package/dist/layout/FullscreenToggle.svelte +11 -2
  111. package/dist/layout/InfoCard.svelte +38 -6
  112. package/dist/layout/InfoTag.svelte +63 -32
  113. package/dist/layout/PropertyFilter.svelte +82 -37
  114. package/dist/layout/SettingsSection.svelte +85 -55
  115. package/dist/layout/SubpageGrid.svelte +10 -2
  116. package/dist/layout/json-tree/JsonNode.svelte +183 -138
  117. package/dist/layout/json-tree/JsonTree.svelte +499 -413
  118. package/dist/layout/json-tree/JsonValue.svelte +127 -99
  119. package/dist/layout/json-tree/utils.js +4 -2
  120. package/dist/marching-cubes.js +25 -2
  121. package/dist/math.d.ts +13 -17
  122. package/dist/math.js +133 -67
  123. package/dist/overlays/ContextMenu.svelte +65 -40
  124. package/dist/overlays/DraggablePane.svelte +211 -139
  125. package/dist/periodic-table/PeriodicTable.svelte +278 -145
  126. package/dist/periodic-table/PeriodicTableControls.svelte +178 -128
  127. package/dist/periodic-table/PropertySelect.svelte +25 -7
  128. package/dist/periodic-table/TableInset.svelte +8 -3
  129. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +446 -309
  130. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
  131. package/dist/phase-diagram/PhaseDiagramControls.svelte +102 -43
  132. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  133. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +63 -40
  134. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +71 -28
  135. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +1 -1
  136. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +158 -101
  137. package/dist/phase-diagram/TdbInfoPanel.svelte +28 -4
  138. package/dist/phase-diagram/build-diagram.js +9 -9
  139. package/dist/phase-diagram/colors.js +1 -3
  140. package/dist/phase-diagram/parse.js +10 -9
  141. package/dist/phase-diagram/svg-to-diagram.js +53 -49
  142. package/dist/phase-diagram/utils.d.ts +1 -0
  143. package/dist/phase-diagram/utils.js +80 -25
  144. package/dist/plot/AxisLabel.svelte +28 -3
  145. package/dist/plot/BarPlot.svelte +1182 -734
  146. package/dist/plot/BarPlot.svelte.d.ts +2 -2
  147. package/dist/plot/BarPlotControls.svelte +31 -5
  148. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  149. package/dist/plot/ColorBar.svelte +479 -329
  150. package/dist/plot/ColorScaleSelect.svelte +27 -6
  151. package/dist/plot/ElementScatter.svelte +36 -15
  152. package/dist/plot/FillArea.svelte +152 -95
  153. package/dist/plot/Histogram.svelte +934 -571
  154. package/dist/plot/Histogram.svelte.d.ts +1 -1
  155. package/dist/plot/HistogramControls.svelte +53 -9
  156. package/dist/plot/HistogramControls.svelte.d.ts +1 -1
  157. package/dist/plot/InteractiveAxisLabel.svelte +34 -11
  158. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
  159. package/dist/plot/Line.svelte +63 -28
  160. package/dist/plot/PlotControls.svelte +157 -114
  161. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  162. package/dist/plot/PlotLegend.svelte +174 -91
  163. package/dist/plot/PlotTooltip.svelte +45 -6
  164. package/dist/plot/PortalSelect.svelte +175 -147
  165. package/dist/plot/ReferenceLine.svelte +76 -22
  166. package/dist/plot/ReferenceLine3D.svelte +132 -107
  167. package/dist/plot/ReferencePlane.svelte +146 -121
  168. package/dist/plot/ScatterPlot.svelte +1681 -1091
  169. package/dist/plot/ScatterPlot.svelte.d.ts +2 -2
  170. package/dist/plot/ScatterPlot3D.svelte +256 -131
  171. package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
  172. package/dist/plot/ScatterPlot3DControls.svelte +113 -63
  173. package/dist/plot/ScatterPlot3DControls.svelte.d.ts +2 -1
  174. package/dist/plot/ScatterPlot3DScene.svelte +608 -403
  175. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
  176. package/dist/plot/ScatterPlotControls.svelte +65 -25
  177. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  178. package/dist/plot/ScatterPoint.svelte +98 -26
  179. package/dist/plot/ScatterPoint.svelte.d.ts +1 -0
  180. package/dist/plot/SpacegroupBarPlot.svelte +142 -85
  181. package/dist/plot/Surface3D.svelte +159 -108
  182. package/dist/plot/ZeroLines.svelte +55 -3
  183. package/dist/plot/ZoomRect.svelte +4 -2
  184. package/dist/plot/axis-utils.js +1 -3
  185. package/dist/plot/data-cleaning.js +12 -28
  186. package/dist/plot/data-transform.js +2 -1
  187. package/dist/plot/fill-utils.js +2 -0
  188. package/dist/plot/layout.d.ts +4 -1
  189. package/dist/plot/layout.js +33 -14
  190. package/dist/plot/reference-line.d.ts +2 -2
  191. package/dist/plot/reference-line.js +7 -5
  192. package/dist/plot/scales.js +24 -36
  193. package/dist/plot/types.d.ts +11 -23
  194. package/dist/plot/types.js +6 -11
  195. package/dist/plot/utils/label-placement.d.ts +32 -15
  196. package/dist/plot/utils/label-placement.js +227 -66
  197. package/dist/plot/utils/series-visibility.js +2 -3
  198. package/dist/rdf/RdfPlot.svelte +143 -91
  199. package/dist/rdf/calc-rdf.js +4 -5
  200. package/dist/sanitize.d.ts +4 -0
  201. package/dist/sanitize.js +107 -0
  202. package/dist/settings.d.ts +18 -6
  203. package/dist/settings.js +46 -16
  204. package/dist/spectral/Bands.svelte +632 -453
  205. package/dist/spectral/BandsAndDos.svelte +90 -49
  206. package/dist/spectral/BrillouinBandsDos.svelte +151 -93
  207. package/dist/spectral/Dos.svelte +389 -258
  208. package/dist/spectral/helpers.js +55 -43
  209. package/dist/state.svelte.d.ts +1 -1
  210. package/dist/state.svelte.js +3 -2
  211. package/dist/structure/Arrow.svelte +59 -20
  212. package/dist/structure/AtomLegend.svelte +215 -134
  213. package/dist/structure/Bond.svelte +73 -47
  214. package/dist/structure/CanvasTooltip.svelte +10 -2
  215. package/dist/structure/CellSelect.svelte +72 -45
  216. package/dist/structure/Cylinder.svelte +33 -17
  217. package/dist/structure/Lattice.svelte +88 -33
  218. package/dist/structure/Structure.svelte +1063 -797
  219. package/dist/structure/Structure.svelte.d.ts +1 -1
  220. package/dist/structure/StructureControls.svelte +349 -118
  221. package/dist/structure/StructureExportPane.svelte +124 -89
  222. package/dist/structure/StructureExportPane.svelte.d.ts +1 -1
  223. package/dist/structure/StructureInfoPane.svelte +304 -237
  224. package/dist/structure/StructureScene.svelte +879 -443
  225. package/dist/structure/StructureScene.svelte.d.ts +15 -7
  226. package/dist/structure/atom-properties.js +8 -8
  227. package/dist/structure/bonding.js +6 -7
  228. package/dist/structure/export.js +14 -29
  229. package/dist/structure/ferrox-wasm.js +1 -1
  230. package/dist/structure/index.d.ts +13 -3
  231. package/dist/structure/index.js +83 -23
  232. package/dist/structure/measure.d.ts +2 -2
  233. package/dist/structure/measure.js +4 -44
  234. package/dist/structure/parse.js +113 -141
  235. package/dist/structure/partial-occupancy.js +7 -10
  236. package/dist/structure/pbc.d.ts +1 -0
  237. package/dist/structure/pbc.js +16 -6
  238. package/dist/structure/supercell.d.ts +2 -2
  239. package/dist/structure/supercell.js +12 -22
  240. package/dist/structure/validation.js +1 -2
  241. package/dist/symmetry/SymmetryStats.svelte +84 -41
  242. package/dist/symmetry/WyckoffTable.svelte +26 -6
  243. package/dist/symmetry/cell-transform.js +5 -3
  244. package/dist/symmetry/index.js +8 -7
  245. package/dist/symmetry/spacegroups.js +148 -148
  246. package/dist/table/HeatmapTable.svelte +790 -554
  247. package/dist/table/HeatmapTable.svelte.d.ts +1 -1
  248. package/dist/table/ToggleMenu.svelte +125 -92
  249. package/dist/table/index.js +2 -4
  250. package/dist/theme/ThemeControl.svelte +21 -12
  251. package/dist/time.js +4 -1
  252. package/dist/tooltip/TooltipContent.svelte +33 -8
  253. package/dist/trajectory/Trajectory.svelte +758 -558
  254. package/dist/trajectory/TrajectoryError.svelte +14 -3
  255. package/dist/trajectory/TrajectoryExportPane.svelte +137 -83
  256. package/dist/trajectory/TrajectoryInfoPane.svelte +272 -143
  257. package/dist/trajectory/extract.js +10 -26
  258. package/dist/trajectory/format-detect.js +5 -5
  259. package/dist/trajectory/frame-reader.d.ts +1 -1
  260. package/dist/trajectory/frame-reader.js +5 -12
  261. package/dist/trajectory/helpers.d.ts +0 -1
  262. package/dist/trajectory/helpers.js +2 -17
  263. package/dist/trajectory/index.js +14 -12
  264. package/dist/trajectory/parse/ase.js +5 -4
  265. package/dist/trajectory/parse/hdf5.js +26 -18
  266. package/dist/trajectory/parse/index.js +13 -18
  267. package/dist/trajectory/parse/lammps.js +17 -7
  268. package/dist/trajectory/parse/vasp.js +5 -2
  269. package/dist/trajectory/parse/xyz.js +8 -7
  270. package/dist/trajectory/plotting.js +13 -8
  271. package/dist/utils.d.ts +1 -0
  272. package/dist/utils.js +13 -0
  273. package/dist/xrd/XrdPlot.svelte +337 -247
  274. package/dist/xrd/broadening.js +14 -9
  275. package/dist/xrd/calc-xrd.js +12 -18
  276. package/dist/xrd/parse.d.ts +1 -1
  277. package/dist/xrd/parse.js +17 -17
  278. package/package.json +99 -103
  279. package/readme.md +1 -1
  280. /package/dist/theme/{themes.js → themes.mjs} +0 -0
@@ -1,14 +1,14 @@
1
+ import type { D3InterpolateName } from '../colors';
1
2
  import type { ElementSymbol } from '../element';
2
3
  import type { IsosurfaceSettings, VolumetricData } from '../isosurface/types';
3
4
  import type { Vec3 } from '../math';
4
- import { type CameraProjection, type ShowBonds } from '../settings';
5
+ import type { CameraProjection, ShowBonds, VectorColorMode, VectorLayerConfig } from '../settings';
5
6
  import type { AnyStructure, MeasureMode, Site } from './';
6
7
  import { Lattice } from './';
7
8
  import type { AtomColorConfig } from './atom-properties';
8
9
  import type { MoyoDataset } from '@spglib/moyo-wasm';
9
10
  import * as extras from '@threlte/extras';
10
- import type { ComponentProps } from 'svelte';
11
- import { type Snippet } from 'svelte';
11
+ import { type ComponentProps, type Snippet } from 'svelte';
12
12
  import { SvelteMap } from 'svelte/reactivity';
13
13
  import { type Camera, type Scene } from 'three';
14
14
  import type { BondingStrategy } from './bonding';
@@ -31,9 +31,17 @@ type $$ComponentProps = {
31
31
  show_bonds?: ShowBonds;
32
32
  show_site_labels?: boolean;
33
33
  show_site_indices?: boolean;
34
- show_force_vectors?: boolean;
35
- force_scale?: number;
36
- force_color?: string;
34
+ vector_configs?: Record<string, VectorLayerConfig>;
35
+ vector_scale?: number;
36
+ vector_color?: string;
37
+ vector_color_mode?: VectorColorMode;
38
+ vector_color_scale?: D3InterpolateName;
39
+ vector_normalize?: boolean;
40
+ vector_uniform_thickness?: boolean;
41
+ vector_origin_gap?: number;
42
+ vector_shaft_radius?: number;
43
+ vector_arrow_head_radius?: number;
44
+ vector_arrow_head_length?: number;
37
45
  gizmo?: boolean | ComponentProps<typeof extras.Gizmo>;
38
46
  hovered_idx?: number | null;
39
47
  hovered_site?: Site | null;
@@ -91,6 +99,6 @@ type $$ComponentProps = {
91
99
  volumetric_data?: VolumetricData;
92
100
  isosurface_settings?: IsosurfaceSettings;
93
101
  };
94
- declare const StructureScene: import("svelte").Component<$$ComponentProps, {}, "cursor" | "site_label_offset" | "scene" | "camera" | "orbit_controls" | "hidden_elements" | "hidden_prop_vals" | "element_radius_overrides" | "site_radius_overrides" | "selected_sites" | "hovered_idx" | "hovered_site" | "camera_is_moving" | "measured_sites" | "added_bonds" | "removed_bonds" | "active_sites" | "rotation_target_ref" | "initial_computed_zoom" | "add_atom_mode" | "add_element" | "dragging_atoms">;
102
+ declare const StructureScene: import("svelte").Component<$$ComponentProps, {}, "cursor" | "site_label_offset" | "vector_configs" | "camera" | "scene" | "orbit_controls" | "hidden_elements" | "hidden_prop_vals" | "element_radius_overrides" | "site_radius_overrides" | "selected_sites" | "hovered_idx" | "hovered_site" | "camera_is_moving" | "measured_sites" | "added_bonds" | "removed_bonds" | "active_sites" | "rotation_target_ref" | "initial_computed_zoom" | "add_atom_mode" | "add_element" | "dragging_atoms">;
95
103
  type StructureScene = ReturnType<typeof StructureScene>;
96
104
  export default StructureScene;
@@ -1,6 +1,7 @@
1
1
  // Utility functions for computing atom properties and applying color scales
2
2
  import { calc_coordination_nums } from '../coordination';
3
3
  import * as math from '../math';
4
+ import { wrap_to_unit_cell } from './pbc';
4
5
  import { rgb } from 'd3-color';
5
6
  import * as d3_sc from 'd3-scale-chromatic';
6
7
  const GRAY = `#808080`;
@@ -15,7 +16,7 @@ const get_interpolator = (scale) => {
15
16
  return interp_fn;
16
17
  };
17
18
  const to_hex = (interp_fn, t) => rgb(interp_fn(t)).formatHex();
18
- const build_image_site = (site, lattice_T, offset, orig_idx) => {
19
+ const build_image_site = (site, frac_to_cart, offset, orig_idx) => {
19
20
  const img_abc = [
20
21
  site.abc[0] + offset[0],
21
22
  site.abc[1] + offset[1],
@@ -24,7 +25,7 @@ const build_image_site = (site, lattice_T, offset, orig_idx) => {
24
25
  return {
25
26
  ...site,
26
27
  abc: img_abc,
27
- xyz: math.mat3x3_vec3_multiply(lattice_T, img_abc),
28
+ xyz: frac_to_cart(img_abc),
28
29
  properties: { ...site.properties, orig_site_idx: orig_idx },
29
30
  };
30
31
  };
@@ -85,23 +86,23 @@ function expand_structure_for_pbc(structure) {
85
86
  return structure;
86
87
  }
87
88
  const { sites, lattice } = structure;
88
- const lattice_T = math.transpose_3x3_matrix(lattice.matrix);
89
+ const frac_to_cart = math.create_frac_to_cart(lattice.matrix);
89
90
  const pbc = lattice.pbc ?? [true, true, true];
90
91
  const all_offsets = get_all_offsets(pbc);
91
92
  // Small structures: expand all atoms
92
93
  if (sites.length < 20 || !pbc.some((periodic) => periodic)) {
93
- const image_sites = sites.flatMap((site, orig_idx) => all_offsets.map((offset) => build_image_site(site, lattice_T, offset, orig_idx)));
94
+ const image_sites = sites.flatMap((site, orig_idx) => all_offsets.map((offset) => build_image_site(site, frac_to_cart, offset, orig_idx)));
94
95
  return { ...structure, sites: [...sites, ...image_sites] };
95
96
  }
96
97
  // Large structures: only expand atoms near boundaries (within 5Å bond distance)
97
98
  const cutoff = [5.0 / lattice.a, 5.0 / lattice.b, 5.0 / lattice.c];
98
99
  const image_sites = sites.flatMap((site, orig_idx) => {
99
- const norm = site.abc.map((coord) => coord - Math.floor(coord));
100
+ const norm = wrap_to_unit_cell(site.abc);
100
101
  return all_offsets
101
102
  .filter(([dx, dy, dz]) => (dx === 0 || (dx === -1 ? norm[0] <= cutoff[0] : norm[0] >= 1 - cutoff[0])) &&
102
103
  (dy === 0 || (dy === -1 ? norm[1] <= cutoff[1] : norm[1] >= 1 - cutoff[1])) &&
103
104
  (dz === 0 || (dz === -1 ? norm[2] <= cutoff[2] : norm[2] >= 1 - cutoff[2])))
104
- .map((offset) => build_image_site(site, lattice_T, offset, orig_idx));
105
+ .map((offset) => build_image_site(site, frac_to_cart, offset, orig_idx));
105
106
  });
106
107
  return { ...structure, sites: [...sites, ...image_sites] };
107
108
  }
@@ -110,8 +111,7 @@ export function get_coordination_colors(structure, strategy = `electroneg_ratio`
110
111
  // Check if structure has periodic boundary conditions
111
112
  const has_lattice = `lattice` in structure && structure.lattice !== undefined;
112
113
  const pbc = has_lattice ? structure.lattice.pbc : undefined;
113
- const has_pbc = has_lattice &&
114
- (pbc === undefined || pbc.some((is_periodic) => is_periodic));
114
+ const has_pbc = has_lattice && (pbc === undefined || pbc.some((is_periodic) => is_periodic));
115
115
  // For PBC structures, expand with images from neighboring cells for accurate coordination
116
116
  const coord_structure = has_pbc ? expand_structure_for_pbc(structure) : structure;
117
117
  // Calculate coordination numbers on the (potentially expanded) structure
@@ -2,7 +2,9 @@
2
2
  import { element_data } from '../element';
3
3
  import * as math from '../math';
4
4
  const element_lookup = new Map(element_data.map((el) => [el.symbol, el]));
5
- const covalent_radii = new Map(element_data.filter((el) => el.covalent_radius !== null).map((el) => [el.symbol, el.covalent_radius]));
5
+ const covalent_radii = new Map(element_data
6
+ .filter((el) => el.covalent_radius !== null)
7
+ .map((el) => [el.symbol, el.covalent_radius]));
6
8
  // Get the species with highest occupancy from a site.
7
9
  const get_majority_species = (site) => (site.species ?? []).reduce((max_species, species) => (species.occu > max_species.occu ? species : max_species), site.species?.[0] ?? { element: ``, occu: -1 });
8
10
  // Helper to extract numeric index from site properties
@@ -67,6 +69,7 @@ export function compute_bond_transform(pos_1, pos_2) {
67
69
  (pos_1[2] + pos_2[2]) / 2,
68
70
  ];
69
71
  return new Float32Array([
72
+ // Return flattened column-major 4x4 matrix for Three.js
70
73
  ...[m00, m10, m20, 0],
71
74
  ...[m01 * height, m11 * height, m21 * height, 0],
72
75
  ...[m02, m12, m22, 0],
@@ -263,17 +266,13 @@ export function solid_angle(structure, { min_solid_angle = 0.01, min_face_area =
263
266
  for (let idx_a = 0; idx_a < sites.length - 1; idx_a++) {
264
267
  const [x1, y1, z1] = sites[idx_a].xyz;
265
268
  const majority_a = get_majority_species(sites[idx_a]);
266
- const radius_a = majority_a.element
267
- ? covalent_radii.get(majority_a.element)
268
- : undefined;
269
+ const radius_a = majority_a.element ? covalent_radii.get(majority_a.element) : undefined;
269
270
  for (const idx_b of get_candidates(sites[idx_a].xyz, sites, spatial)) {
270
271
  if (idx_b <= idx_a)
271
272
  continue;
272
273
  const [x2, y2, z2] = sites[idx_b].xyz;
273
274
  const majority_b = get_majority_species(sites[idx_b]);
274
- const radius_b = majority_b.element
275
- ? covalent_radii.get(majority_b.element)
276
- : undefined;
275
+ const radius_b = majority_b.element ? covalent_radii.get(majority_b.element) : undefined;
277
276
  const [dx, dy, dz] = [x2 - x1, y2 - y1, z2 - z1];
278
277
  const dist_sq = dx * dx + dy * dy + dz * dz;
279
278
  const dist = Math.sqrt(dist_sq);
@@ -17,9 +17,9 @@ export function has_color_property(mat) {
17
17
  const red_channel = color_obj.r;
18
18
  const green_channel = color_obj.g;
19
19
  const blue_channel = color_obj.b;
20
- return typeof red_channel === `number` &&
20
+ return (typeof red_channel === `number` &&
21
21
  typeof green_channel === `number` &&
22
- typeof blue_channel === `number`;
22
+ typeof blue_channel === `number`);
23
23
  }
24
24
  // Extract color from a ShaderMaterial by checking common color uniform patterns
25
25
  function extract_shader_color(shader_mat) {
@@ -129,9 +129,7 @@ export function generate_mtl_content(scene) {
129
129
  lines.push(`Ks 0.500000 0.500000 0.500000`);
130
130
  lines.push(`Ns 96.078431`); // Specular exponent
131
131
  // Transparency (d = 1.0 is fully opaque)
132
- const opacity = `opacity` in mat && typeof mat.opacity === `number`
133
- ? mat.opacity
134
- : 1.0;
132
+ const opacity = `opacity` in mat && typeof mat.opacity === `number` ? mat.opacity : 1.0;
135
133
  lines.push(`d ${opacity.toFixed(6)}`);
136
134
  // Illumination model (2 = highlight on)
137
135
  lines.push(`illum 2`);
@@ -151,7 +149,7 @@ function extract_material_color(mat) {
151
149
  // This is necessary because GLB/OBJ exporters don't handle InstancedMesh properly
152
150
  // Note: Threlte's InstancedMesh sets isInstancedMesh=true but type remains "Mesh"
153
151
  // Type guard for InstancedMesh (Three.js uses isInstancedMesh property, not exposed in Object3D type)
154
- const is_instanced_mesh = (obj) => obj.isInstancedMesh === true || obj.type === `InstancedMesh`;
152
+ const is_instanced_mesh = (obj) => obj.isInstancedMesh || obj.type === `InstancedMesh`;
155
153
  function convert_instanced_meshes_to_regular(scene) {
156
154
  // STEP 1: Collect material colors from ORIGINAL scene BEFORE cloning
157
155
  // This is crucial because scene.clone() may not properly preserve Threlte's material colors
@@ -357,16 +355,14 @@ export function structure_to_xyz_str(structure) {
357
355
  if (formula && formula !== `Unknown`)
358
356
  comment_parts.push(formula);
359
357
  // Include extended XYZ lattice information when available so round-trips preserve lattice
360
- if ((`lattice` in structure) && structure.lattice?.matrix?.length === 3) {
358
+ if (`lattice` in structure && structure.lattice?.matrix?.length === 3) {
361
359
  const lattice_values = structure.lattice.matrix
362
360
  .flat()
363
361
  .map((value) => (Number.isFinite(value) ? value : 0).toFixed(8))
364
362
  .join(` `);
365
363
  comment_parts.push(`Lattice="${lattice_values}"`);
366
364
  }
367
- const comment = comment_parts.length > 0
368
- ? comment_parts.join(` `)
369
- : `Generated from structure`;
365
+ const comment = comment_parts.length > 0 ? comment_parts.join(` `) : `Generated from structure`;
370
366
  lines.push(comment);
371
367
  // Cache converter for fractional→Cartesian (if lattice available)
372
368
  const frac_to_cart = `lattice` in structure && structure.lattice?.matrix?.length === 3
@@ -376,9 +372,7 @@ export function structure_to_xyz_str(structure) {
376
372
  for (const site of structure.sites) {
377
373
  // Extract element symbol from species
378
374
  let element_symbol = `X`; // default fallback
379
- if (site.species &&
380
- Array.isArray(site.species) &&
381
- site.species.length > 0) {
375
+ if (site.species && Array.isArray(site.species) && site.species.length > 0) {
382
376
  // species is an array of Species objects with element property
383
377
  const first_species = site.species[0];
384
378
  if (first_species && `element` in first_species && first_species.element)
@@ -469,7 +463,8 @@ export function structure_to_cif_str(structure) {
469
463
  lines.push(`_cell_angle_gamma ${lattice.gamma.toFixed(6)}`);
470
464
  }
471
465
  // Space group information
472
- if (`symmetry` in structure && structure.symmetry &&
466
+ if (`symmetry` in structure &&
467
+ structure.symmetry &&
473
468
  typeof structure.symmetry === `object`) {
474
469
  const symmetry = structure.symmetry;
475
470
  if (`space_group_symbol` in symmetry && symmetry.space_group_symbol) {
@@ -489,9 +484,7 @@ export function structure_to_cif_str(structure) {
489
484
  lines.push(`_atom_site_fract_z`);
490
485
  lines.push(`_atom_site_occupancy`);
491
486
  // Cache inverse transpose for Cartesian→fractional conversion (avoids recomputing per site)
492
- const cart_to_frac = lattice.matrix?.length === 3
493
- ? math.create_cart_to_frac(lattice.matrix)
494
- : null;
487
+ const cart_to_frac = lattice.matrix?.length === 3 ? math.create_cart_to_frac(lattice.matrix) : null;
495
488
  // Atom sites
496
489
  for (let idx = 0; idx < structure.sites.length; idx++) {
497
490
  const site = structure.sites[idx];
@@ -500,9 +493,7 @@ export function structure_to_cif_str(structure) {
500
493
  // Extract element symbol from species
501
494
  let element_symbol = `X`; // default fallback
502
495
  let occupancy = 1;
503
- if (site.species &&
504
- Array.isArray(site.species) &&
505
- site.species.length > 0) {
496
+ if (site.species && Array.isArray(site.species) && site.species.length > 0) {
506
497
  const first_species = site.species[0];
507
498
  if (first_species && `element` in first_species && first_species.element) {
508
499
  element_symbol = first_species.element;
@@ -556,9 +547,7 @@ export function structure_to_poscar_str(structure) {
556
547
  const element_symbols = [];
557
548
  for (const site of structure.sites) {
558
549
  let element_symbol = `X`; // default fallback
559
- if (site.species &&
560
- Array.isArray(site.species) &&
561
- site.species.length > 0) {
550
+ if (site.species && Array.isArray(site.species) && site.species.length > 0) {
562
551
  const first_species = site.species[0];
563
552
  if (first_species && `element` in first_species && first_species.element) {
564
553
  element_symbol = first_species.element;
@@ -582,16 +571,12 @@ export function structure_to_poscar_str(structure) {
582
571
  // Coordinate mode (Direct = fractional coordinates)
583
572
  lines.push(`Direct`);
584
573
  // Cache inverse transpose for Cartesian→fractional conversion (avoids recomputing per site)
585
- const cart_to_frac = lattice.matrix?.length === 3
586
- ? math.create_cart_to_frac(lattice.matrix)
587
- : null;
574
+ const cart_to_frac = lattice.matrix?.length === 3 ? math.create_cart_to_frac(lattice.matrix) : null;
588
575
  // Atom coordinates grouped by element
589
576
  for (const element_symbol of element_symbols) {
590
577
  for (const site of structure.sites) {
591
578
  let site_element = `X`;
592
- if (site.species &&
593
- Array.isArray(site.species) &&
594
- site.species.length > 0) {
579
+ if (site.species && Array.isArray(site.species) && site.species.length > 0) {
595
580
  const first_species = site.species[0];
596
581
  if (first_species && `element` in first_species && first_species.element) {
597
582
  site_element = first_species.element;
@@ -33,7 +33,7 @@ export function ensure_ferrox_wasm_ready() {
33
33
  catch (err) {
34
34
  // Clear the promise on failure so retry is possible
35
35
  init_promise = null;
36
- throw new Error(`Failed to load matterviz-wasm. Install with: pnpm add matterviz-wasm. Original error: ${err}`);
36
+ throw new Error(`Failed to load matterviz-wasm. Install with: npm add matterviz-wasm. Original error: ${err}`, { cause: err });
37
37
  }
38
38
  })();
39
39
  }
@@ -67,11 +67,21 @@ export declare function format_formula_by_electronegativity(structure: AnyStruct
67
67
  export declare const atomic_radii: CompositionType;
68
68
  export declare function get_density(structure: Crystal): number;
69
69
  export declare function get_center_of_mass(structure: AnyStructure): Vec3;
70
- export declare function get_site_vector_info(site: Site): {
70
+ export declare const VECTOR_KEY_PREFIXES: readonly ["force", "forces", "magmom", "magmoms", "spin", "spins"];
71
+ export declare function is_vector_key(key: string): boolean;
72
+ export declare const VECTOR_PALETTE: readonly ["#e74c3c", "#3498db", "#2ecc71", "#f39c12", "#9b59b6", "#1abc9c"];
73
+ export declare const default_vector_configs: (keys: string[]) => {
74
+ [k: string]: {
75
+ visible: boolean;
76
+ color: "#e74c3c" | "#3498db" | "#2ecc71" | "#f39c12" | "#9b59b6" | "#1abc9c" | null;
77
+ scale: null;
78
+ };
79
+ };
80
+ export declare function get_all_site_vectors(site: Site): {
71
81
  vec: Vec3;
72
82
  key: string;
73
- } | null;
74
- export declare function get_site_vector(site: Site): Vec3 | null;
83
+ }[];
84
+ export declare function get_structure_vector_keys(structure: AnyStructure): string[];
75
85
  export interface StructureHandlerData {
76
86
  structure?: AnyStructure;
77
87
  filename?: string;
@@ -42,16 +42,14 @@ export function format_chemical_formula(structure, sort_fn) {
42
42
  }
43
43
  export function format_formula_by_electronegativity(structure) {
44
44
  // concatenate elements in a structure followed by their amount sorted by electronegativity
45
- return format_chemical_formula(structure, (symbols) => (symbols.sort((el1, el2) => {
46
- const elec_neg1 = element_data.find((el) => el.symbol === el1)?.electronegativity ??
47
- 0;
48
- const elec_neg2 = element_data.find((el) => el.symbol === el2)?.electronegativity ??
49
- 0;
45
+ return format_chemical_formula(structure, (symbols) => symbols.sort((el1, el2) => {
46
+ const elec_neg1 = element_data.find((el) => el.symbol === el1)?.electronegativity ?? 0;
47
+ const elec_neg2 = element_data.find((el) => el.symbol === el2)?.electronegativity ?? 0;
50
48
  // Sort by electronegativity (ascending), then alphabetically for ties
51
49
  if (elec_neg1 !== elec_neg2)
52
50
  return elec_neg1 - elec_neg2;
53
51
  return el1.localeCompare(el2);
54
- })));
52
+ }));
55
53
  }
56
54
  // Atomic radii in Angstroms (used for relative sizing, not absolute rendering scale)
57
55
  export const atomic_radii = Object.fromEntries(element_data.map((el) => [el.symbol, el.atomic_radius ?? 1]));
@@ -84,25 +82,87 @@ export function get_center_of_mass(structure) {
84
82
  }
85
83
  return math.scale(center, 1 / total_weight);
86
84
  }
87
- // Property keys checked for per-site vector data (force, magnetic moment, spin)
88
- const VECTOR_PROPERTY_KEYS = [`force`, `magmom`, `spin`];
89
- // Extract a vector and its source key from a site's properties. Checks force, magmom,
90
- // and spin in priority order. Scalar values are converted to z-directed vectors [0, 0, val].
91
- export function get_site_vector_info(site) {
85
+ // Recognized prefixes for per-site vector data (force, magnetic moment, spin).
86
+ // Both singular and plural forms are accepted. Keys matching exactly or starting
87
+ // with one of these followed by `_` (e.g. `force_DFT`) are treated as vectors.
88
+ export const VECTOR_KEY_PREFIXES = [
89
+ `force`,
90
+ `forces`,
91
+ `magmom`,
92
+ `magmoms`,
93
+ `spin`,
94
+ `spins`,
95
+ ];
96
+ export function is_vector_key(key) {
97
+ return VECTOR_KEY_PREFIXES.some((prefix) => key === prefix || key.startsWith(`${prefix}_`));
98
+ }
99
+ // Default color palette for distinguishing multiple vector layers
100
+ export const VECTOR_PALETTE = [
101
+ `#e74c3c`,
102
+ `#3498db`,
103
+ `#2ecc71`,
104
+ `#f39c12`,
105
+ `#9b59b6`,
106
+ `#1abc9c`,
107
+ ];
108
+ // Single key → null color (semantic coloring); multiple keys → palette colors.
109
+ export const default_vector_configs = (keys) => Object.fromEntries(keys.map((key, idx) => [
110
+ key,
111
+ {
112
+ visible: true,
113
+ color: keys.length > 1 ? VECTOR_PALETTE[idx % VECTOR_PALETTE.length] : null,
114
+ scale: null,
115
+ },
116
+ ]));
117
+ function try_parse_vec3(val) {
118
+ if (Array.isArray(val) &&
119
+ val.length === 3 &&
120
+ val.every((elem) => typeof elem === `number` && isFinite(elem)))
121
+ return val;
122
+ if (typeof val === `number` && isFinite(val))
123
+ return [0, 0, val];
124
+ return null;
125
+ }
126
+ // Priority index for ordering: bare names first in VECTOR_KEY_PREFIXES order,
127
+ // then prefixed keys in the same prefix order, alphabetically within each prefix group.
128
+ function vector_key_sort_order(key) {
129
+ for (const [prefix_idx, prefix] of VECTOR_KEY_PREFIXES.entries()) {
130
+ if (key === prefix)
131
+ return [prefix_idx, 0, ``];
132
+ if (key.startsWith(`${prefix}_`))
133
+ return [prefix_idx, 1, key];
134
+ }
135
+ return [VECTOR_KEY_PREFIXES.length, 0, key];
136
+ }
137
+ function compare_vector_keys(left, right) {
138
+ const ord_l = vector_key_sort_order(left);
139
+ const ord_r = vector_key_sort_order(right);
140
+ return ord_l[0] - ord_r[0] || ord_l[1] - ord_r[1] || ord_l[2].localeCompare(ord_r[2]);
141
+ }
142
+ // Extract ALL vector properties from a site (not just the first match).
143
+ // Returns entries for every key that is_vector_key() and has a valid 3D vector value.
144
+ // Ordered by VECTOR_KEY_PREFIXES priority, then alphabetically for prefixed keys.
145
+ export function get_all_site_vectors(site) {
92
146
  const props = site.properties;
93
147
  if (!props)
94
- return null;
95
- for (const key of VECTOR_PROPERTY_KEYS) {
96
- const val = props[key];
97
- if (Array.isArray(val) && val.length === 3 &&
98
- val.every((elem) => typeof elem === `number` && isFinite(elem)))
99
- return { vec: val, key };
100
- if (typeof val === `number` && isFinite(val))
101
- return { vec: [0, 0, val], key };
148
+ return [];
149
+ const results = [];
150
+ for (const key of Object.keys(props)) {
151
+ if (!is_vector_key(key))
152
+ continue;
153
+ const vec = try_parse_vec3(props[key]);
154
+ if (vec)
155
+ results.push({ vec, key });
102
156
  }
103
- return null;
157
+ return results.sort((left, right) => compare_vector_keys(left.key, right.key));
104
158
  }
105
- // Convenience wrapper returning just the vector (preserves existing API)
106
- export function get_site_vector(site) {
107
- return get_site_vector_info(site)?.vec ?? null;
159
+ // Collect the union of all vector property keys across all sites in a structure,
160
+ // preserving VECTOR_KEY_PREFIXES priority order.
161
+ export function get_structure_vector_keys(structure) {
162
+ const seen = new Set();
163
+ for (const site of structure.sites) {
164
+ for (const { key } of get_all_site_vectors(site))
165
+ seen.add(key);
166
+ }
167
+ return [...seen].sort(compare_vector_keys);
108
168
  }
@@ -1,6 +1,6 @@
1
- import type { Matrix3x3, Vec3 } from '../math';
1
+ import type { LatticeConverters, Matrix3x3, Vec3 } from '../math';
2
2
  export type AngleMode = `degrees` | `radians`;
3
3
  export declare const MAX_SELECTED_SITES = 8;
4
- export declare function displacement_pbc(from: Vec3, to: Vec3, lattice_matrix: Matrix3x3 | null | undefined, lattice_inv?: Matrix3x3): Vec3;
4
+ export declare function displacement_pbc(from: Vec3, to: Vec3, lattice_matrix: Matrix3x3 | null | undefined, converters?: LatticeConverters): Vec3;
5
5
  export declare function distance_pbc(a: Vec3, b: Vec3, lattice_matrix: Matrix3x3): number;
6
6
  export declare function angle_between_vectors(v1: Vec3, v2: Vec3, mode?: AngleMode): number;
@@ -1,55 +1,15 @@
1
1
  // functions for measuring distances and angles between structure sites
2
- import { mat3x3_vec3_multiply, matrix_inverse_3x3, subtract } from '../math';
2
+ import { min_image_displacement, subtract } from '../math';
3
3
  export const MAX_SELECTED_SITES = 8;
4
4
  // Calculate minimum image displacement between two points under PBC
5
5
  // If lattice_matrix is null/undefined, returns Euclidean displacement
6
- export function displacement_pbc(from, to, lattice_matrix, lattice_inv) {
7
- // For non-periodic structures, return direct displacement
6
+ export function displacement_pbc(from, to, lattice_matrix, converters) {
8
7
  if (!lattice_matrix)
9
8
  return subtract(to, from);
10
- const inv_mat = lattice_inv ?? matrix_inverse_3x3(lattice_matrix);
11
- const frac_from = mat3x3_vec3_multiply(inv_mat, from);
12
- const frac_to = mat3x3_vec3_multiply(inv_mat, to);
13
- // Wrap fractional coordinates to [0,1) for easier boundary checking
14
- const frac_from_wrapped = [
15
- frac_from[0] - Math.floor(frac_from[0]),
16
- frac_from[1] - Math.floor(frac_from[1]),
17
- frac_from[2] - Math.floor(frac_from[2]),
18
- ];
19
- const frac_to_wrapped = [
20
- frac_to[0] - Math.floor(frac_to[0]),
21
- frac_to[1] - Math.floor(frac_to[1]),
22
- frac_to[2] - Math.floor(frac_to[2]),
23
- ];
24
- // Find minimum image by testing all nearby lattice translations
25
- let min_dist_sq = Infinity;
26
- let best_displacement = [0, 0, 0];
27
- // Test lattice images in a 3x3x3 neighborhood (sufficient for minimum image)
28
- for (let ii = -1; ii <= 1; ii++) {
29
- for (let jj = -1; jj <= 1; jj++) {
30
- for (let kk = -1; kk <= 1; kk++) {
31
- // Fractional displacement with lattice translation
32
- const frac_diff = [
33
- frac_to_wrapped[0] - frac_from_wrapped[0] + ii,
34
- frac_to_wrapped[1] - frac_from_wrapped[1] + jj,
35
- frac_to_wrapped[2] - frac_from_wrapped[2] + kk,
36
- ];
37
- // Convert to cartesian
38
- const cart_diff = mat3x3_vec3_multiply(lattice_matrix, frac_diff);
39
- const dist_sq = cart_diff[0] ** 2 + cart_diff[1] ** 2 + cart_diff[2] ** 2;
40
- // Keep the shortest displacement
41
- if (dist_sq < min_dist_sq) {
42
- min_dist_sq = dist_sq;
43
- best_displacement = cart_diff;
44
- }
45
- }
46
- }
47
- }
48
- return best_displacement;
9
+ return min_image_displacement(from, to, lattice_matrix, converters);
49
10
  }
50
11
  export function distance_pbc(a, b, lattice_matrix) {
51
- const inv_mat = matrix_inverse_3x3(lattice_matrix);
52
- const [dx, dy, dz] = displacement_pbc(a, b, lattice_matrix, inv_mat);
12
+ const [dx, dy, dz] = displacement_pbc(a, b, lattice_matrix);
53
13
  return Math.hypot(dx, dy, dz);
54
14
  }
55
15
  export function angle_between_vectors(v1, v2, mode = `degrees`) {