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
@@ -34,24 +34,11 @@ export const convert_atomic_numbers = (numbers) => numbers.map((num) => {
34
34
  }
35
35
  return symbol;
36
36
  });
37
- // Cache inverse matrices by original matrix reference for performance
38
- // IMPORTANT: This cache assumes lattice matrices are immutable. Mutating a cached
39
- // matrix in place yields incorrect inverses. Always create new matrix instances
40
- // if modifications are needed.
41
- const matrix_cache = new WeakMap();
42
- export const get_inverse_matrix = (matrix) => {
43
- const cached = matrix_cache.get(matrix);
44
- if (cached)
45
- return cached;
46
- const inverse = math.matrix_inverse_3x3(matrix);
47
- matrix_cache.set(matrix, inverse);
48
- return inverse;
49
- };
50
37
  export const create_structure = (positions, elements, lattice_matrix, pbc, force_data) => {
51
38
  if (positions.length !== elements.length) {
52
39
  throw new Error(`create_structure requires matching positions and elements lengths, got positions=${positions.length}, elements=${elements.length}`);
53
40
  }
54
- const inv_matrix = lattice_matrix ? get_inverse_matrix(lattice_matrix) : null;
41
+ const cart_to_frac = lattice_matrix ? math.create_cart_to_frac(lattice_matrix) : null;
55
42
  const is_valid_vec3 = (coords) => Array.isArray(coords) &&
56
43
  coords.length === 3 &&
57
44
  coords.every((value) => typeof value === `number` && Number.isFinite(value));
@@ -60,9 +47,7 @@ export const create_structure = (positions, elements, lattice_matrix, pbc, force
60
47
  throw new Error(`Invalid position at index ${idx}: expected 3 finite coordinates`);
61
48
  }
62
49
  const xyz = pos;
63
- const abc = inv_matrix
64
- ? math.mat3x3_vec3_multiply(inv_matrix, xyz)
65
- : [0, 0, 0];
50
+ const abc = cart_to_frac ? cart_to_frac(xyz) : [0, 0, 0];
66
51
  const force = force_data?.[idx];
67
52
  const properties = is_valid_vec3(force) ? { force } : {};
68
53
  return {
@@ -3,6 +3,7 @@ export { default as TrajectoryError } from './TrajectoryError.svelte';
3
3
  export { default as TrajectoryExportPane } from './TrajectoryExportPane.svelte';
4
4
  export { default as TrajectoryInfoPane } from './TrajectoryInfoPane.svelte';
5
5
  export function validate_trajectory(trajectory) {
6
+ // with detailed error reporting
6
7
  const errors = [];
7
8
  const { frames, total_frames, indexed_frames, plot_metadata, is_indexed } = trajectory;
8
9
  if (!frames?.length)
@@ -42,8 +43,7 @@ export function validate_trajectory(trajectory) {
42
43
  else if (frame_idx.frame_number < 0) {
43
44
  errors.push(`indexed_frames[${idx}] frame_number (${frame_idx.frame_number}) must be non-negative`);
44
45
  }
45
- else if (idx > 0 &&
46
- frame_idx.frame_number <= indexed_frames[idx - 1].frame_number) {
46
+ else if (idx > 0 && frame_idx.frame_number <= indexed_frames[idx - 1].frame_number) {
47
47
  errors.push(`indexed_frames[${idx}] frame_number (${frame_idx.frame_number}) must be strictly increasing`);
48
48
  }
49
49
  if (typeof frame_idx.byte_offset !== `number`) {
@@ -85,16 +85,18 @@ export function get_trajectory_stats(trajectory) {
85
85
  if (frames.length > 0) {
86
86
  const [first_frame, last_frame] = [frames[0], frames.at(-1) ?? frames[0]];
87
87
  const max_sample = 100;
88
- const sampled = frames.length <= max_sample ? frames : (() => {
89
- const interval = Math.floor(frames.length / max_sample);
90
- const result = [first_frame];
91
- for (let idx = interval; idx < frames.length - 1; idx += interval) {
92
- result.push(frames[idx]);
93
- }
94
- if (result.at(-1) !== last_frame)
95
- result.push(last_frame);
96
- return result;
97
- })();
88
+ const sampled = frames.length <= max_sample
89
+ ? frames
90
+ : (() => {
91
+ const interval = Math.floor(frames.length / max_sample);
92
+ const result = [first_frame];
93
+ for (let idx = interval; idx < frames.length - 1; idx += interval) {
94
+ result.push(frames[idx]);
95
+ }
96
+ if (result.at(-1) !== last_frame)
97
+ result.push(last_frame);
98
+ return result;
99
+ })();
98
100
  const counts = sampled.map((frame) => frame.structure.sites.length);
99
101
  const constant = counts.every((c) => c === counts[0]);
100
102
  const all_counts = constant
@@ -15,8 +15,7 @@ export function parse_ase_trajectory(buffer, filename) {
15
15
  const offsets_pos = Number(view.getBigInt64(offset, true));
16
16
  if (n_items <= 0)
17
17
  throw new Error(`Invalid frame count`);
18
- if (offsets_pos < 0 ||
19
- offsets_pos + n_items * 8 > buffer.byteLength) {
18
+ if (offsets_pos < 0 || offsets_pos + n_items * 8 > buffer.byteLength) {
20
19
  throw new Error(`Invalid ASE frame offsets table bounds: offsets_pos=${offsets_pos}, n_items=${n_items}, byte_length=${buffer.byteLength}`);
21
20
  }
22
21
  const frame_offsets = Array.from({ length: n_items }, (_, idx) => Number(view.getBigInt64(offsets_pos + idx * 8, true)));
@@ -61,8 +60,10 @@ export function parse_ase_trajectory(buffer, filename) {
61
60
  if (frames.length === 0)
62
61
  throw new Error(`No valid frames found`);
63
62
  const first_struct = frames[0]?.structure;
64
- const periodic_boundary_conditions = first_struct !== null && first_struct !== undefined &&
65
- typeof first_struct === `object` && `lattice` in first_struct
63
+ const periodic_boundary_conditions = first_struct !== null &&
64
+ first_struct !== undefined &&
65
+ typeof first_struct === `object` &&
66
+ `lattice` in first_struct
66
67
  ? first_struct.lattice.pbc
67
68
  : [true, true, true];
68
69
  const metadata = {
@@ -2,11 +2,14 @@
2
2
  import { calc_lattice_params, transpose_3x3_matrix } from '../../math';
3
3
  import * as h5wasm from 'h5wasm';
4
4
  import { convert_atomic_numbers, create_trajectory_frame, validate_3x3_matrix, } from '../helpers';
5
- const is_hdf5_dataset = (entity) => entity !== null && (`to_array` in entity && entity instanceof h5wasm.Dataset);
6
- const is_hdf5_group = (entity) => entity !== null && (`keys` in entity && entity instanceof h5wasm.Group);
5
+ const is_hdf5_dataset = (entity) => entity !== null && `to_array` in entity && entity instanceof h5wasm.Dataset;
6
+ const is_hdf5_group = (entity) => entity !== null && `keys` in entity && entity instanceof h5wasm.Group;
7
7
  export async function parse_torch_sim_hdf5(buffer, filename) {
8
8
  const { FS } = await h5wasm.ready;
9
- const file_basename = filename?.split(`/`).at(-1)?.replace(/[^\w.-]/g, `_`) || `temp`;
9
+ const file_basename = filename
10
+ ?.split(`/`)
11
+ .at(-1)
12
+ ?.replace(/[^\w.-]/g, `_`) || `temp`;
10
13
  const unique_suffix = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
11
14
  const temp_filename = `${file_basename}-${unique_suffix}.h5`;
12
15
  FS.writeFile(temp_filename, new Uint8Array(buffer));
@@ -37,9 +40,13 @@ export async function parse_torch_sim_hdf5(buffer, filename) {
37
40
  };
38
41
  return discover(h5_file);
39
42
  };
40
- const positions_data = find_dataset([`positions`, `coords`, `coordinates`])
41
- ?.to_array();
42
- const atomic_numbers_data = find_dataset([`atomic_numbers`, `numbers`, `Z`, `species`])?.to_array();
43
+ const positions_data = find_dataset([`positions`, `coords`, `coordinates`])?.to_array();
44
+ const atomic_numbers_data = find_dataset([
45
+ `atomic_numbers`,
46
+ `numbers`,
47
+ `Z`,
48
+ `species`,
49
+ ])?.to_array();
43
50
  const cells_data = find_dataset([`cell`, `cells`, `lattice`])?.to_array();
44
51
  const energies_data = find_dataset([`potential_energy`, `energy`])?.to_array();
45
52
  if (!positions_data || !atomic_numbers_data) {
@@ -68,9 +75,7 @@ export async function parse_torch_sim_hdf5(buffer, filename) {
68
75
  const frame_atomic_numbers = atomic_numbers[idx] || atomic_numbers[0];
69
76
  const frame_elements = convert_atomic_numbers(frame_atomic_numbers);
70
77
  const cell = cells_data?.[idx];
71
- const lattice_mat = cell
72
- ? transpose_3x3_matrix(validate_3x3_matrix(cell))
73
- : undefined;
78
+ const lattice_mat = cell ? transpose_3x3_matrix(validate_3x3_matrix(cell)) : undefined;
74
79
  const energy_entry = energies_data?.[idx];
75
80
  const energy = Array.isArray(energy_entry) ? energy_entry[0] : energy_entry;
76
81
  const metadata = {};
@@ -82,27 +87,28 @@ export async function parse_torch_sim_hdf5(buffer, filename) {
82
87
  const pbc = lattice_mat ? [true, true, true] : [false, false, false];
83
88
  return create_trajectory_frame(frame_pos, frame_elements, lattice_mat, pbc, idx, metadata);
84
89
  });
85
- const first_frame_elements = frames[0]?.structure.sites.map((site) => site.species[0].element) ??
86
- [];
90
+ const first_frame_elements = frames[0]?.structure.sites.map((site) => site.species[0].element) ?? [];
87
91
  return {
88
92
  frames,
89
93
  metadata: {
90
94
  source_format: `hdf5_trajectory`,
91
95
  frame_count: frames.length,
92
96
  num_atoms: first_frame_elements.length,
93
- periodic_boundary_conditions: cells_data
94
- ? [true, true, true]
95
- : [false, false, false],
97
+ periodic_boundary_conditions: cells_data ? [true, true, true] : [false, false, false],
96
98
  element_counts: first_frame_elements.reduce((counts, element) => {
97
99
  counts[element] = (counts[element] || 0) + 1;
98
100
  return counts;
99
101
  }, {}),
100
102
  discovered_datasets: {
101
- positions: found_paths.positions || found_paths.coords ||
103
+ positions: found_paths.positions ||
104
+ found_paths.coords ||
102
105
  found_paths.coordinates ||
103
106
  `unknown`,
104
- atomic_numbers: found_paths.atomic_numbers || found_paths.numbers ||
105
- found_paths.Z || found_paths.species || `unknown`,
107
+ atomic_numbers: found_paths.atomic_numbers ||
108
+ found_paths.numbers ||
109
+ found_paths.Z ||
110
+ found_paths.species ||
111
+ `unknown`,
106
112
  cells: found_paths.cell || found_paths.cells || found_paths.lattice,
107
113
  energies: found_paths.potential_energy || found_paths.energy,
108
114
  },
@@ -116,6 +122,8 @@ export async function parse_torch_sim_hdf5(buffer, filename) {
116
122
  try {
117
123
  FS.unlink(temp_filename);
118
124
  }
119
- catch { /* temp file cleanup is best-effort */ }
125
+ catch {
126
+ /* temp file cleanup is best-effort */
127
+ }
120
128
  }
121
129
  }
@@ -10,9 +10,8 @@ import { parse_torch_sim_hdf5 } from './hdf5';
10
10
  import { parse_lammps_trajectory } from './lammps';
11
11
  import { parse_vasp_xdatcar } from './vasp';
12
12
  import { parse_xyz_trajectory } from './xyz';
13
- const log_parse_debug = (message, error) => {
14
- console.debug(message, error);
15
- };
13
+ // Silently swallow expected parse fallbacks — the caller throws if ALL formats fail
14
+ const log_parse_debug = (_message, _error) => { };
16
15
  // Re-export constants and types for consumers
17
16
  export { INDEX_SAMPLE_RATE, LARGE_FILE_THRESHOLD, MAX_BIN_FILE_SIZE, MAX_METADATA_SIZE, MAX_SAFE_STRING_LENGTH, MAX_TEXT_FILE_SIZE, } from '../constants';
18
17
  export { is_trajectory_file, TrajFrameReader };
@@ -56,7 +55,7 @@ export async function parse_trajectory_data(data, filename, atom_type_mapping) {
56
55
  }
57
56
  catch (error) {
58
57
  log_parse_debug(`JSON parse failed for ${filename ?? `unknown file`}:`, error);
59
- throw new Error(`Unsupported text format`);
58
+ throw new Error(`Unsupported text format`, { cause: error });
60
59
  }
61
60
  }
62
61
  if (!data || typeof data !== `object`)
@@ -89,7 +88,8 @@ export async function parse_trajectory_data(data, filename, atom_type_mapping) {
89
88
  const raw_properties = frame_properties[idx] || {};
90
89
  const processed_properties = {};
91
90
  Object.entries(raw_properties).forEach(([key, value]) => {
92
- if (value && typeof value === `object` &&
91
+ if (value &&
92
+ typeof value === `object` &&
93
93
  value[`@class`] === `array`) {
94
94
  // Extract numpy array data
95
95
  const array_obj = value;
@@ -99,9 +99,8 @@ export async function parse_trajectory_data(data, filename, atom_type_mapping) {
99
99
  const forces = array_obj.data;
100
100
  const force_magnitudes = forces.map((force) => Math.hypot(...force));
101
101
  if (force_magnitudes.length > 0) {
102
- processed_properties.force_max = force_magnitudes.reduce((max_val, magnitude) => magnitude > max_val ? magnitude : max_val, force_magnitudes[0]);
103
- processed_properties.force_norm = Math.sqrt(force_magnitudes.reduce((sum, f) => sum + f ** 2, 0) /
104
- force_magnitudes.length);
102
+ processed_properties.force_max = force_magnitudes.reduce((max_val, magnitude) => (magnitude > max_val ? magnitude : max_val), force_magnitudes[0]);
103
+ processed_properties.force_norm = Math.sqrt(force_magnitudes.reduce((sum, f) => sum + f ** 2, 0) / force_magnitudes.length);
105
104
  }
106
105
  }
107
106
  // Calculate stress statistics for stress tensor
@@ -193,9 +192,7 @@ export async function parse_trajectory_async(data, filename, on_progress, option
193
192
  const update_progress = (current, stage) => on_progress?.({ current, total: 100, stage });
194
193
  try {
195
194
  update_progress(0, `Detecting format...`);
196
- const data_size = data instanceof ArrayBuffer
197
- ? data.byteLength
198
- : new TextEncoder().encode(data).byteLength;
195
+ const data_size = data instanceof ArrayBuffer ? data.byteLength : new TextEncoder().encode(data).byteLength;
199
196
  const is_large_file = data_size > LARGE_FILE_THRESHOLD;
200
197
  const should_use_indexing = use_indexing ?? is_large_file;
201
198
  if (is_large_file) {
@@ -260,14 +257,12 @@ async function parse_with_unified_loader(data, filename, options, on_progress) {
260
257
  }
261
258
  const stage = `Ready: ${total_frames} frames indexed`;
262
259
  on_progress?.({ current: 100, total: 100, stage });
260
+ const source_format = filename.toLowerCase().endsWith(`.traj`)
261
+ ? `ase_trajectory`
262
+ : `xyz_trajectory`;
263
263
  return {
264
264
  frames,
265
- metadata: {
266
- source_format: filename.toLowerCase().endsWith(`.traj`)
267
- ? `ase_trajectory`
268
- : `xyz_trajectory`,
269
- frame_count: total_frames,
270
- },
265
+ metadata: { source_format, frame_count: total_frames },
271
266
  total_frames,
272
267
  indexed_frames: frame_index,
273
268
  plot_metadata,
@@ -277,7 +272,7 @@ async function parse_with_unified_loader(data, filename, options, on_progress) {
277
272
  }
278
273
  // Factory function for frame loader (simplified)
279
274
  export function create_frame_loader(filename) {
280
- if (!filename.toLowerCase().match(/\.(xyz|extxyz|traj)$/)) {
275
+ if (!/\.(xyz|extxyz|traj)$/.exec(filename.toLowerCase())) {
281
276
  throw new Error(`Unsupported format for frame loading: ${filename}`);
282
277
  }
283
278
  return new TrajFrameReader(filename);
@@ -15,15 +15,22 @@ export function parse_lammps_box(box_lines, is_triclinic) {
15
15
  if (!is_triclinic) {
16
16
  // Orthogonal: bounds = [lo, hi] per dimension
17
17
  const [[lo_x, hi_x], [lo_y, hi_y], [lo_z, hi_z]] = bounds;
18
- return [[hi_x - lo_x, 0, 0], [0, hi_y - lo_y, 0], [0, 0, hi_z - lo_z]];
18
+ return [
19
+ [hi_x - lo_x, 0, 0],
20
+ [0, hi_y - lo_y, 0],
21
+ [0, 0, hi_z - lo_z],
22
+ ];
19
23
  }
20
24
  // Triclinic: bounds = [lo_bound, hi_bound, tilt] with tilts xy, xz, yz
21
25
  const [[xlo_b, xhi_b, xy], [ylo_b, yhi_b, xz], [zlo_b, zhi_b, yz]] = bounds;
22
- const lx = (xhi_b - Math.max(0, xy, xz, xy + xz)) -
23
- (xlo_b - Math.min(0, xy, xz, xy + xz));
24
- const ly = (yhi_b - Math.max(0, yz)) - (ylo_b - Math.min(0, yz));
26
+ const lx = xhi_b - Math.max(0, xy, xz, xy + xz) - (xlo_b - Math.min(0, xy, xz, xy + xz));
27
+ const ly = yhi_b - Math.max(0, yz) - (ylo_b - Math.min(0, yz));
25
28
  const lz = zhi_b - zlo_b;
26
- return [[lx, 0, 0], [xy, ly, 0], [xz, yz, lz]];
29
+ return [
30
+ [lx, 0, 0],
31
+ [xy, ly, 0],
32
+ [xz, yz, lz],
33
+ ];
27
34
  }
28
35
  // Parse LAMMPS trajectory (.lammpstrj). Atom types mapped to elements via atom_type_mapping
29
36
  // or by default: 1→H, 2→He, etc. Supports orthogonal and triclinic simulation boxes.
@@ -140,7 +147,10 @@ export function parse_lammps_trajectory(content, filename, atom_type_mapping) {
140
147
  }
141
148
  if (positions.length === elements.length && positions.length === num_atoms) {
142
149
  const { volume } = math.calc_lattice_params(lattice_matrix);
143
- frames.push(create_trajectory_frame(positions, elements, lattice_matrix, pbc, timestep, { volume, timestep }));
150
+ frames.push(create_trajectory_frame(positions, elements, lattice_matrix, pbc, timestep, {
151
+ volume,
152
+ timestep,
153
+ }));
144
154
  }
145
155
  }
146
156
  if (frames.length === 0) {
@@ -159,7 +169,7 @@ export function parse_lammps_trajectory(content, filename, atom_type_mapping) {
159
169
  source_format: `lammps_trajectory`,
160
170
  frame_count: frames.length,
161
171
  total_atoms: first_frame.structure.sites.length,
162
- periodic_boundary_conditions: (`lattice` in first_frame.structure)
172
+ periodic_boundary_conditions: `lattice` in first_frame.structure
163
173
  ? first_frame.structure.lattice.pbc
164
174
  : [true, true, true],
165
175
  atom_types: Array.from(atom_types_found).sort((a, b) => a - b),
@@ -7,7 +7,10 @@ export function parse_vasp_xdatcar(content, filename) {
7
7
  const scale = parseFloat(lines[1]);
8
8
  if (isNaN(scale))
9
9
  throw new Error(`Invalid scale factor`);
10
- const lattice_matrix = validate_3x3_matrix(lines.slice(2, 5).map((line) => line.trim().split(/\s+/).map((x) => parseFloat(x) * scale)));
10
+ const lattice_matrix = validate_3x3_matrix(lines.slice(2, 5).map((line) => line
11
+ .trim()
12
+ .split(/\s+/)
13
+ .map((x) => parseFloat(x) * scale)));
11
14
  const element_names = lines[5].trim().split(/\s+/);
12
15
  const element_counts = lines[6].trim().split(/\s+/).map(Number);
13
16
  if (element_names.length !== element_counts.length) {
@@ -32,7 +35,7 @@ export function parse_vasp_xdatcar(content, filename) {
32
35
  break;
33
36
  const config_line = lines[config_idx];
34
37
  line_idx = config_idx + 1;
35
- const step_match = config_line.match(/configuration=\s*(\d+)/);
38
+ const step_match = /configuration=\s*(\d+)/.exec(config_line);
36
39
  const step = step_match ? parseInt(step_match[1]) : frames.length + 1;
37
40
  const positions = [];
38
41
  for (let idx = 0; idx < elements.length && line_idx < lines.length; idx++) {
@@ -36,16 +36,16 @@ export function parse_xyz_trajectory(content) {
36
36
  metadata[key] = parseFloat(match[1]);
37
37
  });
38
38
  // Extract lattice matrix
39
- const lattice_match = comment.match(/Lattice\s*=\s*"([^"]+)"/i);
39
+ const lattice_match = /Lattice\s*=\s*"([^"]+)"/i.exec(comment);
40
40
  let lattice_matrix;
41
41
  if (lattice_match) {
42
42
  const values = lattice_match[1].split(/\s+/).map(Number);
43
43
  if (values.length === 9 && values.every((value) => Number.isFinite(value))) {
44
- lattice_matrix = [[values[0], values[1], values[2]], [
45
- values[3],
46
- values[4],
47
- values[5],
48
- ], [values[6], values[7], values[8]]];
44
+ lattice_matrix = [
45
+ [values[0], values[1], values[2]],
46
+ [values[3], values[4], values[5]],
47
+ [values[6], values[7], values[8]],
48
+ ];
49
49
  metadata.volume = math.calc_lattice_params(lattice_matrix).volume;
50
50
  }
51
51
  }
@@ -63,7 +63,8 @@ export function parse_xyz_trajectory(content) {
63
63
  const x_coord = parseFloat(parts[1]);
64
64
  const y_coord = parseFloat(parts[2]);
65
65
  const z_coord = parseFloat(parts[3]);
66
- if (!Number.isFinite(x_coord) || !Number.isFinite(y_coord) ||
66
+ if (!Number.isFinite(x_coord) ||
67
+ !Number.isFinite(y_coord) ||
67
68
  !Number.isFinite(z_coord)) {
68
69
  console.warn(`Skipping XYZ atom with invalid coordinates in frame ${frames.length} at line ${line_idx + 1}`);
69
70
  continue;
@@ -107,7 +107,8 @@ function group_and_assign_series(series, default_visible_properties) {
107
107
  unit_map.set(unit, group);
108
108
  }
109
109
  // Create unit groups with priority and visibility
110
- const groups = Array.from(unit_map.entries()).map(([unit, group_series]) => {
110
+ const groups = Array.from(unit_map.entries())
111
+ .map(([unit, group_series]) => {
111
112
  const priority = calculate_priority(unit, group_series);
112
113
  const has_default_visible = group_series.some((srs) => {
113
114
  const metadata = Array.isArray(srs.metadata) ? srs.metadata[0] : srs.metadata;
@@ -115,7 +116,8 @@ function group_and_assign_series(series, default_visible_properties) {
115
116
  return is_default_visible(property_key, default_visible_properties);
116
117
  });
117
118
  return { unit, series: group_series, priority, is_visible: has_default_visible };
118
- }).sort((a, b) => a.priority - b.priority);
119
+ })
120
+ .sort((a, b) => a.priority - b.priority);
119
121
  // Apply 2-group visibility limit
120
122
  const visible_groups = groups.filter((g) => g.is_visible);
121
123
  if (visible_groups.length > 2) {
@@ -183,7 +185,11 @@ function calculate_priority(unit, group_series) {
183
185
  }
184
186
  // Normalize property keys for robust matching (handles case, underscores, and common aliases)
185
187
  const normalize_property_key = (key) => {
186
- const normalized = key.toLowerCase().replace(/<[^>]*>/g, ``).replace(/_/g, ` `).trim();
188
+ const normalized = key
189
+ .toLowerCase()
190
+ .replace(/<[^>]*>/g, ``)
191
+ .replace(/_/g, ` `)
192
+ .trim();
187
193
  // Map common force property aliases to canonical form
188
194
  return [`fmax`, `f`, `force maximum`].includes(normalized) ? `force max` : normalized;
189
195
  };
@@ -213,7 +219,8 @@ export function toggle_series_visibility(series, target_series_idx) {
213
219
  const visible_groups = unit_groups.filter((group) => group.is_visible);
214
220
  if (visible_groups.length >= 2) {
215
221
  // Hide lowest priority group (highest priority number)
216
- const lowest_priority_group = visible_groups.sort((g1, g2) => g1.priority - g2.priority)
222
+ const lowest_priority_group = visible_groups
223
+ .sort((g1, g2) => g1.priority - g2.priority)
217
224
  .pop(); // Get the last (lowest priority) group
218
225
  if (lowest_priority_group) {
219
226
  lowest_priority_group.is_visible = false;
@@ -358,8 +365,7 @@ export function generate_streaming_plot_series(metadata_list, options = {}) {
358
365
  if (!is_energy && !has_significant_variation(data_points.map((p) => p.y)))
359
366
  continue;
360
367
  const { clean_label, unit } = extract_label_and_unit(property_key, property_config);
361
- const is_visible = is_default_visible(property_key, default_visible_properties) ||
362
- color_idx < 2;
368
+ const is_visible = is_default_visible(property_key, default_visible_properties) || color_idx < 2;
363
369
  const color = colors[color_idx % colors.length];
364
370
  if (is_visible)
365
371
  visible_props.push({ property: property_key, unit });
@@ -411,8 +417,7 @@ function determine_axis_from_groups(property, unit, visible_properties) {
411
417
  }));
412
418
  const groups = group_and_assign_series(mock_series, new Set([property]));
413
419
  const target_group = groups.find((group) => group.series.some((srs) => srs.label === property && srs.unit === unit));
414
- return target_group &&
415
- groups.filter((group) => group.is_visible).indexOf(target_group) === 1
420
+ return target_group && groups.filter((group) => group.is_visible).indexOf(target_group) === 1
416
421
  ? `y2`
417
422
  : `y1`;
418
423
  }
package/dist/utils.d.ts CHANGED
@@ -2,3 +2,4 @@ export declare function merge_nested<T extends Record<string, unknown>>(obj1: T,
2
2
  export declare const escape_html: (unsafe_string: string) => string;
3
3
  export declare const normalize_unicode_minus: (value: string) => string;
4
4
  export declare const normalize_scientific_notation: (value: string) => string;
5
+ export declare function decode_url_safe_base64(encoded: string): string | undefined;
package/dist/utils.js CHANGED
@@ -21,3 +21,16 @@ export const escape_html = (unsafe_string) => unsafe_string
21
21
  export const normalize_unicode_minus = (value) => value.replace(/−/g, `-`);
22
22
  // Normalize scientific notation variants (d/D exponent, Mathematica *^).
23
23
  export const normalize_scientific_notation = (value) => normalize_unicode_minus(value).toLowerCase().replace(/d/g, `e`).replace(/\*\^/g, `e`);
24
+ // Decode a URL-safe base64 string (RFC 4648 §5) to its original text.
25
+ // Converts `-` → `+`, `_` → `/`, restores padding, then decodes.
26
+ // Returns undefined if decoding fails.
27
+ export function decode_url_safe_base64(encoded) {
28
+ const std_b64 = encoded.replace(/-/g, `+`).replace(/_/g, `/`);
29
+ const padded = std_b64 + `=`.repeat((4 - (std_b64.length % 4)) % 4);
30
+ try {
31
+ return atob(padded);
32
+ }
33
+ catch {
34
+ return undefined;
35
+ }
36
+ }