matterviz 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/dist/FilePicker.svelte +40 -50
  2. package/dist/api/optimade.js +10 -7
  3. package/dist/app.css +15 -0
  4. package/dist/brillouin/BrillouinZone.svelte +18 -9
  5. package/dist/brillouin/BrillouinZoneScene.svelte +20 -29
  6. package/dist/brillouin/compute.js +10 -16
  7. package/dist/brillouin/geometry.js +2 -2
  8. package/dist/chempot-diagram/ChemPotDiagram.svelte +18 -15
  9. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +17 -113
  10. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +104 -264
  11. package/dist/chempot-diagram/async-compute.svelte.js +12 -13
  12. package/dist/chempot-diagram/color.d.ts +21 -1
  13. package/dist/chempot-diagram/color.js +70 -1
  14. package/dist/chempot-diagram/compute.d.ts +7 -0
  15. package/dist/chempot-diagram/compute.js +85 -26
  16. package/dist/chempot-diagram/export.js +1 -6
  17. package/dist/chempot-diagram/temperature.js +9 -10
  18. package/dist/composition/BarChart.svelte +7 -9
  19. package/dist/composition/Composition.svelte +3 -8
  20. package/dist/composition/Formula.svelte +2 -2
  21. package/dist/composition/FormulaFilter.svelte +27 -93
  22. package/dist/composition/format.js +6 -8
  23. package/dist/composition/parse.js +50 -105
  24. package/dist/constants.d.ts +0 -1
  25. package/dist/constants.js +6 -17
  26. package/dist/convex-hull/ConvexHull2D.svelte +0 -2
  27. package/dist/convex-hull/ConvexHull3D.svelte +19 -47
  28. package/dist/convex-hull/ConvexHull4D.svelte +65 -95
  29. package/dist/convex-hull/StructurePopup.svelte +1 -1
  30. package/dist/convex-hull/gas-thermodynamics.js +21 -53
  31. package/dist/convex-hull/helpers.js +1 -7
  32. package/dist/convex-hull/thermodynamics.js +19 -27
  33. package/dist/coordination/CoordinationBarPlot.svelte +12 -21
  34. package/dist/element/BohrAtom.svelte +0 -1
  35. package/dist/element/ElementTile.svelte +26 -44
  36. package/dist/element/data.d.ts +2 -0
  37. package/dist/element/data.js +5 -1
  38. package/dist/element/index.d.ts +1 -1
  39. package/dist/element/index.js +1 -1
  40. package/dist/fermi-surface/FermiSurface.svelte +22 -23
  41. package/dist/fermi-surface/FermiSurface.svelte.d.ts +2 -6
  42. package/dist/fermi-surface/FermiSurfaceScene.svelte +32 -77
  43. package/dist/fermi-surface/compute.js +22 -55
  44. package/dist/fermi-surface/parse.js +38 -70
  45. package/dist/file-viewer/JsonBrowser.svelte +1043 -0
  46. package/dist/file-viewer/JsonBrowser.svelte.d.ts +9 -0
  47. package/dist/file-viewer/PlotPanel.svelte +350 -0
  48. package/dist/file-viewer/PlotPanel.svelte.d.ts +9 -0
  49. package/dist/file-viewer/TrajectoryWithDos.svelte +30 -0
  50. package/dist/file-viewer/TrajectoryWithDos.svelte.d.ts +10 -0
  51. package/dist/file-viewer/detect.d.ts +11 -0
  52. package/dist/file-viewer/detect.js +381 -0
  53. package/dist/file-viewer/eligibility.d.ts +4 -0
  54. package/dist/file-viewer/eligibility.js +53 -0
  55. package/dist/file-viewer/host-protocol.d.ts +50 -0
  56. package/dist/file-viewer/host-transfer.d.ts +25 -0
  57. package/dist/file-viewer/host-transfer.js +42 -0
  58. package/dist/file-viewer/index.d.ts +5 -0
  59. package/dist/file-viewer/index.js +5 -0
  60. package/dist/file-viewer/main.d.ts +44 -0
  61. package/dist/file-viewer/main.js +535 -0
  62. package/dist/file-viewer/parse.d.ts +9 -0
  63. package/dist/file-viewer/parse.js +170 -0
  64. package/dist/file-viewer/plot-utils.d.ts +24 -0
  65. package/dist/file-viewer/plot-utils.js +191 -0
  66. package/dist/file-viewer/types.d.ts +4 -0
  67. package/dist/file-viewer/types.js +5 -0
  68. package/dist/heatmap-matrix/HeatmapMatrix.svelte +57 -84
  69. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
  70. package/dist/index.d.ts +2 -2
  71. package/dist/index.js +1 -1
  72. package/dist/io/ExportPane.svelte +1 -1
  73. package/dist/io/decompress.d.ts +2 -0
  74. package/dist/io/decompress.js +3 -2
  75. package/dist/io/export.d.ts +7 -4
  76. package/dist/io/export.js +70 -18
  77. package/dist/io/file-drop.js +60 -35
  78. package/dist/io/url-drop.d.ts +2 -0
  79. package/dist/io/url-drop.js +28 -16
  80. package/dist/isosurface/Isosurface.svelte +687 -196
  81. package/dist/isosurface/Isosurface.svelte.d.ts +7 -1
  82. package/dist/isosurface/IsosurfaceControls.svelte +564 -85
  83. package/dist/isosurface/IsosurfaceControls.svelte.d.ts +1 -1
  84. package/dist/isosurface/VolumeSlice.svelte +224 -0
  85. package/dist/isosurface/VolumeSlice.svelte.d.ts +28 -0
  86. package/dist/isosurface/coloring.d.ts +20 -0
  87. package/dist/isosurface/coloring.js +118 -0
  88. package/dist/isosurface/geometry-worker-types.d.ts +38 -0
  89. package/dist/isosurface/geometry.worker.d.ts +1 -0
  90. package/dist/isosurface/geometry.worker.js +59 -0
  91. package/dist/isosurface/grid.d.ts +10 -0
  92. package/dist/isosurface/grid.js +31 -0
  93. package/dist/isosurface/index.d.ts +4 -0
  94. package/dist/isosurface/index.js +4 -0
  95. package/dist/isosurface/profile.d.ts +12 -0
  96. package/dist/isosurface/profile.js +19 -0
  97. package/dist/isosurface/sampling.d.ts +34 -0
  98. package/dist/isosurface/sampling.js +408 -0
  99. package/dist/isosurface/slice-rendering.d.ts +13 -0
  100. package/dist/isosurface/slice-rendering.js +79 -0
  101. package/dist/isosurface/slice.d.ts +22 -2
  102. package/dist/isosurface/slice.js +200 -116
  103. package/dist/isosurface/types.d.ts +24 -1
  104. package/dist/isosurface/types.js +120 -8
  105. package/dist/json-path.d.ts +4 -0
  106. package/dist/json-path.js +89 -0
  107. package/dist/labels.js +1 -1
  108. package/dist/layout/InfoCard.svelte +1 -3
  109. package/dist/layout/SettingsSection.svelte +52 -61
  110. package/dist/layout/SettingsSection.svelte.d.ts +6 -7
  111. package/dist/layout/ViewerChrome.svelte +7 -1
  112. package/dist/layout/json-tree/JsonNode.svelte +14 -48
  113. package/dist/layout/json-tree/JsonTree.svelte +48 -95
  114. package/dist/layout/json-tree/JsonValue.svelte +3 -18
  115. package/dist/layout/json-tree/utils.d.ts +0 -3
  116. package/dist/layout/json-tree/utils.js +50 -179
  117. package/dist/marching-cubes.d.ts +8 -1
  118. package/dist/marching-cubes.js +115 -48
  119. package/dist/math.d.ts +3 -2
  120. package/dist/math.js +29 -38
  121. package/dist/overlays/ContextMenu.svelte +15 -32
  122. package/dist/overlays/DraggablePane.svelte +39 -58
  123. package/dist/overlays/DraggablePane.svelte.d.ts +1 -1
  124. package/dist/overlays/GlassChip.svelte +3 -1
  125. package/dist/periodic-table/PeriodicTableControls.svelte +26 -52
  126. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +18 -34
  127. package/dist/phase-diagram/build-diagram.js +1 -6
  128. package/dist/phase-diagram/svg-to-diagram.js +9 -14
  129. package/dist/plot/bar/BarPlot.svelte +38 -42
  130. package/dist/plot/bar/SpacegroupBarPlot.svelte +18 -42
  131. package/dist/plot/box/BoxPlot.svelte +27 -23
  132. package/dist/plot/core/auto-place.d.ts +1 -1
  133. package/dist/plot/core/auto-place.js +1 -1
  134. package/dist/plot/core/data-transform.d.ts +1 -2
  135. package/dist/plot/core/data-transform.js +0 -10
  136. package/dist/plot/core/layout.d.ts +12 -5
  137. package/dist/plot/core/layout.js +37 -27
  138. package/dist/plot/core/pan-zoom.svelte.d.ts +2 -4
  139. package/dist/plot/core/pan-zoom.svelte.js +34 -17
  140. package/dist/plot/core/placed-tween.svelte.d.ts +3 -0
  141. package/dist/plot/core/placed-tween.svelte.js +68 -21
  142. package/dist/plot/core/svg.js +0 -1
  143. package/dist/plot/core/utils/hierarchy-chart.d.ts +1 -0
  144. package/dist/plot/core/utils/hierarchy-chart.js +12 -0
  145. package/dist/plot/core/utils/hierarchy-labels.js +3 -2
  146. package/dist/plot/histogram/Histogram.svelte +21 -26
  147. package/dist/plot/sankey/sankey.js +13 -9
  148. package/dist/plot/scatter/BinnedScatterPlot.svelte +59 -43
  149. package/dist/plot/scatter/ScatterPlot.svelte +67 -52
  150. package/dist/plot/scatter/adaptive-density.d.ts +1 -1
  151. package/dist/plot/scatter/adaptive-density.js +36 -20
  152. package/dist/plot/sunburst/Sunburst.svelte +20 -20
  153. package/dist/plot/treemap/Treemap.svelte +175 -60
  154. package/dist/plot/treemap/Treemap.svelte.d.ts +6 -0
  155. package/dist/plot/treemap/index.d.ts +1 -0
  156. package/dist/plot/treemap/labels.d.ts +38 -0
  157. package/dist/plot/treemap/labels.js +80 -0
  158. package/dist/plot/treemap/treemap.d.ts +4 -2
  159. package/dist/plot/treemap/treemap.js +5 -2
  160. package/dist/rdf/RdfPlot.svelte +17 -35
  161. package/dist/rdf/calc-rdf.js +59 -44
  162. package/dist/rdf/index.d.ts +0 -1
  163. package/dist/sanitize.js +84 -26
  164. package/dist/scene/SceneCamera.svelte +1 -1
  165. package/dist/scene/SceneCamera.svelte.d.ts +1 -1
  166. package/dist/scene/index.d.ts +1 -2
  167. package/dist/scene/index.js +1 -1
  168. package/dist/scene/{props.js → props.svelte.js} +15 -1
  169. package/dist/settings.js +159 -482
  170. package/dist/spectral/Bands.svelte +151 -158
  171. package/dist/spectral/BrillouinBandsDos.svelte +4 -19
  172. package/dist/spectral/Dos.svelte +26 -24
  173. package/dist/spectral/helpers.js +40 -105
  174. package/dist/structure/AtomLegend.svelte +8 -13
  175. package/dist/structure/AtomLegend.svelte.d.ts +2 -3
  176. package/dist/structure/CellSelect.svelte +35 -10
  177. package/dist/structure/Structure.svelte +177 -99
  178. package/dist/structure/Structure.svelte.d.ts +1 -1
  179. package/dist/structure/StructureCarousel.svelte +10 -3
  180. package/dist/structure/StructureControls.svelte +8 -26
  181. package/dist/structure/StructureControls.svelte.d.ts +1 -1
  182. package/dist/structure/StructureInfoPane.svelte +65 -76
  183. package/dist/structure/StructureScene.svelte +75 -109
  184. package/dist/structure/StructureScene.svelte.d.ts +3 -1
  185. package/dist/structure/StructureViewport.svelte +120 -55
  186. package/dist/structure/StructureViewport.svelte.d.ts +3 -1
  187. package/dist/structure/atom-properties.d.ts +1 -1
  188. package/dist/structure/atom-properties.js +4 -3
  189. package/dist/structure/bond-order-perception.js +3 -8
  190. package/dist/structure/bonding.d.ts +0 -1
  191. package/dist/structure/bonding.js +16 -23
  192. package/dist/structure/export.js +50 -74
  193. package/dist/structure/format-detect.js +5 -7
  194. package/dist/structure/index.js +6 -12
  195. package/dist/structure/parse.js +38 -100
  196. package/dist/structure/partial-occupancy.js +7 -4
  197. package/dist/structure/pbc.js +8 -10
  198. package/dist/structure/polyhedra.js +5 -4
  199. package/dist/structure/prop-groups.d.ts +85 -0
  200. package/dist/structure/prop-groups.js +18 -0
  201. package/dist/symmetry/SymmetryStats.svelte +0 -4
  202. package/dist/symmetry/WyckoffTable.svelte +5 -4
  203. package/dist/symmetry/cell-transform.js +5 -14
  204. package/dist/symmetry/index.js +6 -9
  205. package/dist/table/HeatmapTable.svelte +61 -103
  206. package/dist/table/ToggleMenu.svelte +166 -44
  207. package/dist/table/ToggleMenu.svelte.d.ts +1 -1
  208. package/dist/theme/embedded.d.ts +18 -0
  209. package/dist/theme/embedded.js +206 -0
  210. package/dist/theme/index.d.ts +4 -0
  211. package/dist/theme/index.js +1 -2
  212. package/dist/theme/themes.mjs +31 -60
  213. package/dist/tooltip/TooltipContent.svelte +1 -1
  214. package/dist/tooltip/TooltipContent.svelte.d.ts +1 -1
  215. package/dist/tooltip/index.d.ts +8 -1
  216. package/dist/trajectory/Trajectory.svelte +140 -120
  217. package/dist/trajectory/TrajectoryError.svelte +1 -66
  218. package/dist/trajectory/TrajectoryExportPane.svelte +0 -1
  219. package/dist/trajectory/TrajectoryInfoPane.svelte +55 -80
  220. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +2 -1
  221. package/dist/trajectory/extract.js +19 -29
  222. package/dist/trajectory/format-detect.d.ts +2 -0
  223. package/dist/trajectory/format-detect.js +7 -5
  224. package/dist/trajectory/frame-reader.js +3 -4
  225. package/dist/trajectory/helpers.js +16 -49
  226. package/dist/trajectory/index.js +2 -8
  227. package/dist/trajectory/parse/ase.js +1 -1
  228. package/dist/trajectory/parse/index.d.ts +4 -3
  229. package/dist/trajectory/parse/index.js +12 -17
  230. package/dist/trajectory/parse/vaspout-h5.d.ts +0 -1
  231. package/dist/trajectory/parse/vaspout-h5.js +1 -4
  232. package/dist/trajectory/parse/xyz.js +48 -2
  233. package/dist/trajectory/plotting.js +14 -37
  234. package/dist/xrd/XrdPlot.svelte +43 -68
  235. package/dist/xrd/calc-xrd.js +22 -58
  236. package/dist/xrd/parse.js +13 -22
  237. package/package.json +40 -8
  238. package/readme.md +6 -5
  239. package/dist/scene/types.d.ts +0 -26
  240. package/dist/tooltip/types.d.ts +0 -8
  241. package/dist/trajectory/constants.d.ts +0 -6
  242. package/dist/trajectory/constants.js +0 -11
  243. /package/dist/{scene/types.js → file-viewer/host-protocol.js} +0 -0
  244. /package/dist/{tooltip/types.js → isosurface/geometry-worker-types.js} +0 -0
@@ -1,7 +1,7 @@
1
1
  import * as math from '../../math';
2
2
  import { coerce_elem_symbol } from '../../element/helpers';
3
3
  import { calc_force_stats, create_trajectory_frame, iter_xyz_frames, } from '../helpers';
4
- import { traj_warn } from './diagnostics';
4
+ import { get_traj_parse_warnings, traj_warn } from './diagnostics';
5
5
  // Resolve species/pos/forces column offsets from an extxyz Properties string of
6
6
  // name:type:ncols triples (e.g. "species:S:1:pos:R:3:forces:R:3"), falling back
7
7
  // to the conventional "symbol x y z" layout when absent or malformed
@@ -35,6 +35,45 @@ function parse_extxyz_lattice(comment) {
35
35
  return undefined;
36
36
  return [vals.slice(0, 3), vals.slice(3, 6), vals.slice(6, 9)];
37
37
  }
38
+ const EXTXYZ_BOOL = new Map([
39
+ [`t`, true],
40
+ [`true`, true],
41
+ [`1`, true],
42
+ [`f`, false],
43
+ [`false`, false],
44
+ [`0`, false],
45
+ ]); // Map avoids Object.prototype hits (e.g. `constructor`)
46
+ function lookup_extxyz_bools(tokens) {
47
+ if (tokens.length !== 3)
48
+ return undefined;
49
+ const [first, second, third] = tokens.map((token) => EXTXYZ_BOOL.get(token.toLowerCase()));
50
+ if (first === undefined || second === undefined || third === undefined)
51
+ return undefined;
52
+ return [first, second, third];
53
+ }
54
+ function parse_extxyz_pbc(comment) {
55
+ const match = /\bpbc\s*=\s*(?:"(?<double>[^"]*)"|'(?<single>[^']*)'|(?<bare>\S+(?:\s+\S+){0,2}))/iu.exec(comment);
56
+ const raw = (match?.groups?.double ?? match?.groups?.single ?? match?.groups?.bare)?.trim();
57
+ if (!raw)
58
+ return undefined;
59
+ // Stop before a following `Key=` token that bare matching may have swallowed
60
+ const split = raw.split(/\s+/u);
61
+ const cut = split.findIndex((word) => word.includes(`=`));
62
+ const words = cut === -1 ? split : split.slice(0, cut);
63
+ if (words.length === 0)
64
+ return undefined;
65
+ const [first] = words;
66
+ if (first.length === 3) {
67
+ const compact = lookup_extxyz_bools(first.split(``));
68
+ if (compact)
69
+ return compact;
70
+ }
71
+ if (words.length === 1) {
72
+ const only = EXTXYZ_BOOL.get(first.toLowerCase());
73
+ return only === undefined ? undefined : [only, only, only];
74
+ }
75
+ return lookup_extxyz_bools(words.slice(0, 3));
76
+ }
38
77
  // Keys anchored at ^|\s and followed by [=:] so single-letter keys (E/V/P/T) don't match mid-word
39
78
  const make_pattern = (keys) => new RegExp(`(?:^|\\s)(?:${keys})\\s*[=:]\\s*([-+]?\\d*\\.?\\d+(?:[eE][-+]?\\d+)?)`, `i`);
40
79
  const METADATA_PATTERNS = {
@@ -96,11 +135,18 @@ export function build_xyz_frame(lines, frame, opts) {
96
135
  const { start, num_atoms, comment } = frame;
97
136
  const { step, properties } = parse_xyz_comment_metadata(comment);
98
137
  const lattice_matrix = parse_extxyz_lattice(comment);
138
+ const parsed_pbc = parse_extxyz_pbc(comment);
139
+ if (parsed_pbc === undefined &&
140
+ /\bpbc\s*=/iu.test(comment) &&
141
+ !get_traj_parse_warnings().some((msg) => msg.includes(`Invalid EXTXYZ pbc`))) {
142
+ traj_warn(`Invalid EXTXYZ pbc (first seen in ${opts.frame_label}); defaulting to fully periodic [T, T, T]`);
143
+ }
144
+ const pbc = parsed_pbc ?? [true, true, true];
99
145
  const { elements, positions, force_stats } = parse_xyz_atom_lines(lines, start + 2, num_atoms, comment, opts.frame_label);
100
146
  const metadata = { ...properties, ...force_stats };
101
147
  if (lattice_matrix)
102
148
  metadata.volume = math.calc_lattice_params(lattice_matrix).volume;
103
- return create_trajectory_frame(positions, elements, lattice_matrix, lattice_matrix ? [true, true, true] : undefined, step ?? opts.default_step, metadata);
149
+ return create_trajectory_frame(positions, elements, lattice_matrix, lattice_matrix ? pbc : undefined, step ?? opts.default_step, metadata);
104
150
  }
105
151
  export function parse_xyz_trajectory(content) {
106
152
  const lines = content.trim().split(/\r?\n/);
@@ -72,21 +72,14 @@ function extract_property_statistics(trajectory, data_extractor) {
72
72
  // Convert to final format with variation detection
73
73
  const result = new Map();
74
74
  for (const [key, stat] of property_stats) {
75
- const n_values = stat.values.length;
76
- if (n_values <= 1)
75
+ if (stat.values.length <= 1)
77
76
  continue;
78
- const coefficient_of_variation = get_coefficient_of_variation(stat.values);
79
- const lower_key = key.toLowerCase();
80
- const is_energy = lower_key === `energy`;
81
- const has_variation = coefficient_of_variation >= 1e-6;
77
+ const is_energy = key.toLowerCase() === `energy`;
78
+ const has_variation = get_coefficient_of_variation(stat.values) >= 1e-6;
82
79
  // Skip constant properties except energy
83
80
  if (!has_variation && !is_energy)
84
81
  continue;
85
- result.set(key, {
86
- values: stat.values,
87
- has_variation,
88
- is_energy,
89
- });
82
+ result.set(key, { values: stat.values, has_variation, is_energy });
90
83
  }
91
84
  return result;
92
85
  }
@@ -95,8 +88,6 @@ function create_series_from_stats(property_stats, property_config, colors) {
95
88
  const all_series = [];
96
89
  let color_idx = 0;
97
90
  for (const [key, stat] of property_stats) {
98
- if (!stat)
99
- continue;
100
91
  const n_values = stat.values.length;
101
92
  const { clean_label, unit, axis_group } = extract_label_and_unit(key, property_config);
102
93
  const color = colors[color_idx % colors.length];
@@ -254,19 +245,12 @@ function get_axis_label(axis_series) {
254
245
  if (visible_series.length === 0)
255
246
  return `Value`;
256
247
  const unit_groups = new Map();
257
- visible_series.forEach((srs) => {
258
- const unit = srs.unit ?? ``;
259
- const label = srs.label ?? `Value`;
260
- if (!unit_groups.has(unit))
261
- unit_groups.set(unit, []);
262
- const group = unit_groups.get(unit);
263
- if (group)
264
- group.push(label);
265
- });
266
- const unit_entries = Array.from(unit_groups.entries());
267
- if (unit_entries.length === 0)
268
- return `Value`;
269
- const [unit, labels] = unit_entries[0];
248
+ for (const srs of visible_series) {
249
+ const labels = unit_groups.get(srs.unit ?? ``) ?? [];
250
+ labels.push(srs.label ?? `Value`);
251
+ unit_groups.set(srs.unit ?? ``, labels);
252
+ }
253
+ const [unit, labels] = [...unit_groups.entries()][0];
270
254
  const unique_labels = [...new Set(labels)].sort().join(` / `);
271
255
  return unit ? `${unique_labels} (${unit})` : unique_labels;
272
256
  }
@@ -336,7 +320,8 @@ export function generate_streaming_plot_series(metadata_list, options = {}) {
336
320
  if (data_points.length < 2)
337
321
  continue;
338
322
  const is_energy = property_key.toLowerCase() === `energy`;
339
- if (!is_energy && !has_significant_variation(data_points.map((point) => point.y)))
323
+ const values = data_points.map((point) => point.y);
324
+ if (!is_energy && get_coefficient_of_variation(values) < 1e-6)
340
325
  continue;
341
326
  const { clean_label, unit, axis_group } = extract_label_and_unit(property_key, property_config);
342
327
  const is_visible = is_default_visible(property_key, default_visible_properties) || color_idx < 2;
@@ -362,12 +347,10 @@ export function generate_streaming_plot_series(metadata_list, options = {}) {
362
347
  }
363
348
  return all_series;
364
349
  }
365
- // Helper functions for streaming
350
+ // Down-sample to at most target_points entries (callers guarantee the list is longer)
366
351
  function downsample_metadata(metadata_list, target_points) {
367
352
  const total_count = metadata_list.length;
368
- if (total_count <= target_points)
369
- return metadata_list;
370
- const points = Math.max(2, Math.min(target_points, total_count));
353
+ const points = Math.max(2, target_points);
371
354
  // Evenly spaced indices in [0, total_count-1], guaranteed to include first and last.
372
355
  const sampled = [];
373
356
  for (let idx = 0; idx < points; idx++) {
@@ -378,12 +361,6 @@ function downsample_metadata(metadata_list, target_points) {
378
361
  }
379
362
  return sampled;
380
363
  }
381
- function has_significant_variation(values, tolerance = 1e-6) {
382
- if (values.length <= 1)
383
- return false;
384
- const coefficient_of_variation = get_coefficient_of_variation(values);
385
- return coefficient_of_variation >= tolerance;
386
- }
387
364
  function determine_axis_from_groups(property, unit, visible_properties) {
388
365
  const mock_series = visible_properties.map(({ property: prop, unit: prop_unit, axis_group }) => ({
389
366
  label: prop,
@@ -2,13 +2,7 @@
2
2
  import { add_alpha, PLOT_COLORS } from '../colors'
3
3
  import EmptyState from '../EmptyState.svelte'
4
4
  import StatusMessage from '../feedback/StatusMessage.svelte'
5
- import {
6
- decompress_data_binary,
7
- decompress_file,
8
- detect_compression_format,
9
- drag_over_handlers,
10
- handle_url_drop,
11
- } from '../io'
5
+ import * as io from '../io'
12
6
  import { format_value } from '../labels'
13
7
  import { sanitize_html } from '../sanitize'
14
8
  import SettingsSection from '../layout/SettingsSection.svelte'
@@ -164,18 +158,17 @@
164
158
  const labels: (string | null)[] = []
165
159
 
166
160
  // Determine which peaks to annotate
167
- const intens = ys
168
161
  let selected_indices: number[] = []
169
- if (annotate_peaks && annotate_peaks > 0) {
162
+ if (annotate_peaks > 0) {
170
163
  let candidates: { idx: number; y_val: number }[] = []
171
- if (annotate_peaks > 0 && annotate_peaks < 1) {
164
+ if (annotate_peaks < 1) {
172
165
  const thresh = annotate_peaks * 100
173
- candidates = intens
166
+ candidates = ys
174
167
  .map((y_val, idx) => ({ y_val, idx }))
175
168
  .filter(({ y_val }) => y_val > thresh)
176
169
  } else {
177
- const max_peaks = Math.min(intens.length, Math.floor(annotate_peaks))
178
- candidates = intens
170
+ const max_peaks = Math.min(ys.length, Math.floor(annotate_peaks))
171
+ candidates = ys
179
172
  .map((y_val, idx) => ({ y_val, idx }))
180
173
  .sort((a, b) => b.y_val - a.y_val)
181
174
  .slice(0, max_peaks)
@@ -209,10 +202,9 @@
209
202
 
210
203
  if (selected_indices.includes(idx)) {
211
204
  const angle_text = actual_show_angles ? `${format_value(xs[idx], `.2f`)}°` : ``
212
- const hkl_text =
213
- hkls && hkl_format
214
- ? hkls.map((hkl_val) => format_hkl(hkl_val, hkl_format)).join(`, `)
215
- : ``
205
+ const hkl_text = hkl_format
206
+ ? hkls.map((hkl_val) => format_hkl(hkl_val, hkl_format)).join(`, `)
207
+ : ``
216
208
  // Use @ separator between hkl and angle for better clarity
217
209
  const separator = hkl_text && angle_text ? ` @ ` : ``
218
210
  const text = [hkl_text, angle_text].filter(Boolean).join(separator)
@@ -239,49 +231,32 @@
239
231
  if (!broadening_enabled) return []
240
232
 
241
233
  const include_name = pattern_entries.length > 1
242
- // We rescale after broadening so that max peak is 100, matching stick view scale
243
- return pattern_entries
244
- .map((entry, entry_idx) => {
245
- const broadened = compute_broadened_pattern(
246
- entry.pattern,
247
- broadening_params,
248
- angle_range,
249
- )
250
-
251
- // Normalize broadened profile relative to GLOBAL max intensity of stick patterns?
252
- // Or normalize to 100 for *this* profile?
253
- // Usually we want relative intensities between patterns to be preserved if possible.
254
- // But broadening spreads intensity, so peak heights drop.
255
- // If we normalize each profile to 100 independently, we lose relative scaling between patterns.
256
- // If we normalize by global_max_intensity (from sticks), broadened peaks will be tiny.
257
- // Let's normalize such that the highest peak across ALL broadened patterns is 100.
258
-
259
- return {
260
- broadened,
261
- entry,
262
- entry_idx,
263
- }
264
- })
265
- .map(({ broadened, entry, entry_idx }, _, all_processed) => {
266
- // Find global max of all broadened patterns to normalize
267
- const all_ys = all_processed.flatMap((processed) => processed.broadened.y)
268
- const max_y = Math.max(...all_ys, 1) // Avoid div by zero
269
-
270
- const scale = (y_val: number) => (y_val / max_y) * 100
271
- const base_color = entry.color ?? PLOT_COLORS[entry_idx % PLOT_COLORS.length]
272
- // Add transparency when multiple series overlap
273
- const alpha = all_processed.length > 1 ? 0.6 : 1
274
-
275
- return {
276
- x: broadened.x,
277
- y: broadened.y.map(scale),
278
- label: include_name ? entry.label : ``,
279
- color: add_alpha(base_color, alpha),
280
- markers: `line`, // Only line for profile
281
- line_style: { stroke_width: 2 },
282
- visible: true,
283
- } as DataSeries
284
- })
234
+ // Normalize so the highest peak across ALL broadened profiles is 100: per-profile
235
+ // normalization would lose relative scaling between patterns, while the stick-view
236
+ // global max would make broadened peaks tiny (broadening spreads intensity)
237
+ const broadened = pattern_entries.map((entry) =>
238
+ compute_broadened_pattern(entry.pattern, broadening_params, angle_range),
239
+ )
240
+ let max_y = 1 // avoid div by zero
241
+ for (const profile of broadened) {
242
+ for (const y_val of profile.y) max_y = Math.max(max_y, y_val)
243
+ }
244
+ // Add transparency when multiple series overlap
245
+ const alpha = pattern_entries.length > 1 ? 0.6 : 1
246
+
247
+ return broadened.map((profile, entry_idx) => {
248
+ const entry = pattern_entries[entry_idx]
249
+ const base_color = entry.color ?? PLOT_COLORS[entry_idx % PLOT_COLORS.length]
250
+ return {
251
+ x: profile.x,
252
+ y: profile.y.map((y_val) => (y_val / max_y) * 100),
253
+ label: include_name ? entry.label : ``,
254
+ color: add_alpha(base_color, alpha),
255
+ markers: `line`, // Only line for profile
256
+ line_style: { stroke_width: 2 },
257
+ visible: true,
258
+ } as DataSeries
259
+ })
285
260
  })
286
261
 
287
262
  async function handle_file_drop(event: DragEvent) {
@@ -302,16 +277,16 @@
302
277
 
303
278
  try {
304
279
  // Handle URL-based drops
305
- const handled = await handle_url_drop(event, on_file_drop || compute_and_add).catch(
306
- () => false,
307
- )
280
+ const handled = await io
281
+ .handle_url_drop(event, on_file_drop || compute_and_add)
282
+ .catch(() => false)
308
283
  if (handled) return
309
284
 
310
285
  const file = event.dataTransfer?.files?.[0]
311
286
  if (file) {
312
287
  try {
313
288
  const lower_name = file.name.toLowerCase()
314
- const compression_format = detect_compression_format(lower_name)
289
+ const compression_format = io.detect_compression_format(lower_name)
315
290
  // Get base filename without compression extension
316
291
  const base_name = compression_format
317
292
  ? lower_name.replace(/\.(?:gz|gzip)$/i, ``)
@@ -323,7 +298,7 @@
323
298
  let buffer = await file.arrayBuffer()
324
299
  // Decompress if gzipped
325
300
  if (compression_format === `gzip`) {
326
- buffer = await decompress_data_binary(buffer, `gzip`)
301
+ buffer = await io.decompress_data_binary(buffer, `gzip`)
327
302
  }
328
303
  const output_name = base_name.endsWith(`.brml`)
329
304
  ? base_name
@@ -331,7 +306,7 @@
331
306
  await (on_file_drop || compute_and_add)(buffer, output_name)
332
307
  } else {
333
308
  // Text-based formats (.xy, .xye, .xrdml) - decompress_file handles .gz
334
- const { content, filename } = await decompress_file(file)
309
+ const { content, filename } = await io.decompress_file(file)
335
310
  if (content) await (on_file_drop || compute_and_add)(content, filename)
336
311
  }
337
312
  } catch (exc) {
@@ -456,7 +431,7 @@
456
431
  }}
457
432
  {tooltip}
458
433
  ondrop={handle_file_drop}
459
- {...drag_over_handlers({
434
+ {...io.drag_over_handlers({
460
435
  allow: () => allow_file_drop,
461
436
  set_dragover: (over) => (dragover = over),
462
437
  })}
@@ -509,7 +484,7 @@
509
484
  }}
510
485
  {tooltip}
511
486
  ondrop={handle_file_drop}
512
- {...drag_over_handlers({
487
+ {...io.drag_over_handlers({
513
488
  allow: () => allow_file_drop,
514
489
  set_dragover: (over) => (dragover = over),
515
490
  })}
@@ -128,11 +128,7 @@ export function compute_xrd_pattern(structure, options = {}) {
128
128
  const two_theta_range = options.two_theta_range === null ? null : (options.two_theta_range ?? [0, 180]);
129
129
  const [min_radius, max_radius] = two_theta_range === null
130
130
  ? [0, 2 / wavelength]
131
- : (([t_min, t_max]) => {
132
- const r_min = (2 * Math.sin((t_min / 2) * (Math.PI / 180))) / wavelength;
133
- const r_max = (2 * Math.sin((t_max / 2) * (Math.PI / 180))) / wavelength;
134
- return [r_min, r_max];
135
- })(two_theta_range);
131
+ : two_theta_range.map((angle) => (2 * Math.sin((angle / 2) * (Math.PI / 180))) / wavelength);
136
132
  const recip_points = enumerate_reciprocal_points(recip_rows, structure.lattice.matrix, max_radius, min_radius);
137
133
  const coeffs = [];
138
134
  const frac_coords = [];
@@ -149,16 +145,11 @@ export function compute_xrd_pattern(structure, options = {}) {
149
145
  if (!raw_coeff) {
150
146
  throw new Error(`No atomic scattering coefficients for ${element_symbol}. Extend ATOMIC_SCATTERING_PARAMS.`);
151
147
  }
152
- let coeff_entry;
153
- if (Array.isArray(raw_coeff)) {
154
- const a_arr = raw_coeff.map(([a]) => a);
155
- const b_arr = raw_coeff.map(([_, b]) => b);
156
- coeff_entry = { a: a_arr, b: b_arr, z: ELEMENT_Z[element_symbol] };
157
- }
158
- else {
159
- coeff_entry = { a: raw_coeff.a.slice(), b: raw_coeff.b.slice(), c: raw_coeff.c };
160
- }
161
- coeffs.push(coeff_entry);
148
+ coeffs.push({
149
+ a: raw_coeff.map((row) => row[0]),
150
+ b: raw_coeff.map((row) => row[1]),
151
+ z: ELEMENT_Z[element_symbol],
152
+ });
162
153
  frac_coords.push(site.abc);
163
154
  occus.push(species.occu);
164
155
  dw_factors.push(debye_waller_factors[element_symbol] ?? 0);
@@ -169,9 +160,7 @@ export function compute_xrd_pattern(structure, options = {}) {
169
160
  const two_thetas = [];
170
161
  const merge_tol = options.peak_merge_tol ?? TWO_THETA_TOL;
171
162
  const scaled_tol = options.scaled_intensity_tol ?? SCALED_INTENSITY_TOL;
172
- for (const entry of recip_points) {
173
- const hkl = entry.hkl;
174
- const g_norm = entry.g_norm;
163
+ for (const { hkl, g_norm } of recip_points) {
175
164
  if (g_norm === 0)
176
165
  continue;
177
166
  const asin_arg = (wavelength * g_norm) / 2;
@@ -182,18 +171,10 @@ export function compute_xrd_pattern(structure, options = {}) {
182
171
  const sin_theta_over_lambda_sq = sin_theta_over_lambda * sin_theta_over_lambda;
183
172
  // g.r for all fractional coords
184
173
  const g_dot_r_all = frac_coords.map((frac_coord) => math.dot(frac_coord, hkl));
185
- // Atomic scattering factors (vectorized style)
186
- const f_scattering = coeffs.map((coeff_entry) => {
187
- const { a: a_arr, b: b_arr, z: atomic_number } = coeff_entry;
188
- const num_terms = Math.min(a_arr.length, b_arr.length);
189
- const sum_terms = a_arr
190
- .slice(0, num_terms)
191
- .reduce((sum, a_i, term_idx) => sum + a_i * Math.exp(-b_arr[term_idx] * sin_theta_over_lambda_sq), 0);
192
- // pymatgen-style fitted params: f = Z − 41.78214·s²·Σ aᵢ·exp(−bᵢ·s²)
193
- if (atomic_number !== undefined) {
194
- return atomic_number - 41.78214 * sin_theta_over_lambda_sq * sum_terms;
195
- }
196
- return sum_terms + (coeff_entry.c ?? 0);
174
+ // Atomic scattering factors: f = Z − 41.78214·s²·Σ aᵢ·exp(−bᵢ·s²) (pymatgen fitted params)
175
+ const f_scattering = coeffs.map(({ a: a_arr, b: b_arr, z: atomic_number }) => {
176
+ const sum_terms = a_arr.reduce((sum, a_i, term_idx) => sum + a_i * Math.exp(-b_arr[term_idx] * sin_theta_over_lambda_sq), 0);
177
+ return atomic_number - 41.78214 * sin_theta_over_lambda_sq * sum_terms;
197
178
  });
198
179
  const dw_corr = dw_factors.map((dw_b) => Math.exp(-dw_b * sin_theta_over_lambda_sq));
199
180
  // Structure factor sum: sum(fs * occu * exp(2πi g·r) * DW)
@@ -212,28 +193,16 @@ export function compute_xrd_pattern(structure, options = {}) {
212
193
  const lorentz = (1 + Math.cos(2 * theta) ** 2) / denom;
213
194
  const intensity_hkl = (f_real * f_real + f_imag * f_imag) * lorentz;
214
195
  const two_theta = math.to_degrees(2 * theta);
215
- // Use (h, k, l) always. For hexagonal systems, pymatgen presents Miller–Bravais (h, k, i, l),
216
- // but downstream components expect 3-index HKL. Keep 3-index form to match types/consumers.
217
- const hkl_to_store = [hkl[0], hkl[1], hkl[2]];
218
- // Merge peaks within tolerance
219
- let found_index = null;
220
- for (let idx = 0; idx < two_thetas.length; idx++) {
221
- if (Math.abs(two_thetas[idx] - two_theta) < merge_tol) {
222
- found_index = idx;
223
- break;
224
- }
225
- }
226
- if (found_index !== null) {
227
- const key = two_thetas[found_index];
228
- const item = peaks.get(key);
229
- if (item) {
230
- item.intensity += intensity_hkl;
231
- item.hkls.push(hkl_to_store);
232
- }
196
+ // Merge peaks within tolerance. hkls stay 3-index (h, k, l) even for hexagonal
197
+ // systems where pymatgen presents Miller–Bravais (h, k, i, l), matching consumers.
198
+ const merge_key = two_thetas.find((angle) => Math.abs(angle - two_theta) < merge_tol);
199
+ const existing = merge_key === undefined ? undefined : peaks.get(merge_key);
200
+ if (existing) {
201
+ existing.intensity += intensity_hkl;
202
+ existing.hkls.push(hkl);
233
203
  }
234
204
  else {
235
- const d_hkl = 1 / g_norm;
236
- peaks.set(two_theta, { intensity: intensity_hkl, hkls: [hkl_to_store], d_hkl });
205
+ peaks.set(two_theta, { intensity: intensity_hkl, hkls: [hkl], d_hkl: 1 / g_norm });
237
206
  two_thetas.push(two_theta);
238
207
  }
239
208
  }
@@ -283,14 +252,9 @@ wavelength) {
283
252
  // Check if file is a direct XRD data file (.xy, .brml)
284
253
  if (is_xrd_data_file(filename)) {
285
254
  // Convert ArrayBufferLike to ArrayBuffer if needed (handles SharedArrayBuffer)
286
- let buffer_content;
287
- if (typeof content === `string`) {
288
- buffer_content = content;
289
- }
290
- else {
291
- buffer_content =
292
- content instanceof ArrayBuffer ? content : new Uint8Array(content).slice().buffer;
293
- }
255
+ const buffer_content = typeof content === `string` || content instanceof ArrayBuffer
256
+ ? content
257
+ : new Uint8Array(content).slice().buffer;
294
258
  const pattern = await parse_xrd_file(buffer_content, filename);
295
259
  if (pattern && pattern.x.length > 0) {
296
260
  return { pattern: { label: filename || `XRD data`, pattern } };
package/dist/xrd/parse.js CHANGED
@@ -2,17 +2,13 @@
2
2
  const MAX_POINTS = 1000;
3
3
  // Default step size in degrees for XRD scans when not specified in file
4
4
  const DEFAULT_STEP_SIZE = 0.02;
5
- // Generate x values from scan parameters (start angle, step size, point count).
6
- // Used by formats that store metadata + intensity-only data.
7
- const generate_x_from_scan = (start, step, count) => Array.from({ length: count }, (_, idx) => start + idx * step);
8
- // Create normalized XrdPattern from scan metadata and intensities.
5
+ // Create normalized XrdPattern from scan metadata (start angle, step size) and intensities.
9
6
  // Returns null if no intensity data. Used by all parsers as final step.
10
7
  function create_pattern(start, step, intensities) {
11
8
  if (intensities.length === 0)
12
9
  return null;
13
- const x_values = generate_x_from_scan(start, step, intensities.length);
14
- const normalized = normalize_and_subsample(x_values, intensities);
15
- return { x: normalized.x, y: normalized.y };
10
+ const x_values = intensities.map((_, idx) => start + idx * step);
11
+ return normalize_and_subsample(x_values, intensities);
16
12
  }
17
13
  // Parse whitespace-separated numbers from text. Used by multiple formats.
18
14
  const parse_number_list = (text) => text
@@ -130,8 +126,7 @@ export function parse_xy_file(content) {
130
126
  }
131
127
  if (x_values.length === 0)
132
128
  return null;
133
- const normalized = normalize_and_subsample(x_values, y_values);
134
- return { x: normalized.x, y: normalized.y };
129
+ return normalize_and_subsample(x_values, y_values);
135
130
  }
136
131
  // Parse a Rigaku .ras file (ASCII format with structured header).
137
132
  // Format: *RAS_HEADER_START ... *RAS_HEADER_END followed by *RAS_INT_START ... *RAS_INT_END
@@ -525,19 +520,15 @@ function extract_scan_parameters_xml(doc) {
525
520
  // Try to find intensity data - multiple possible tag names
526
521
  let intensities = null;
527
522
  let two_theta_values = null;
528
- // Method 1: <Intensities> tag with space-separated values
529
- const intensities_el = doc.querySelector(`Intensities`);
530
- if (intensities_el?.textContent) {
531
- intensities = parse_number_list(intensities_el.textContent);
532
- }
533
- // Method 2: <Counts> tag
534
- if (!intensities?.length) {
535
- const counts_el = doc.querySelector(`Counts`);
536
- if (counts_el?.textContent) {
537
- intensities = parse_number_list(counts_el.textContent);
538
- }
523
+ // Method 1: <Intensities> or <Counts> tag with space-separated values
524
+ for (const tag of [`Intensities`, `Counts`]) {
525
+ const text = doc.querySelector(tag)?.textContent;
526
+ if (text)
527
+ intensities = parse_number_list(text);
528
+ if (intensities?.length)
529
+ break;
539
530
  }
540
- // Method 3: Individual <I> or <Count> elements
531
+ // Method 2: Individual <I> or <Count> elements
541
532
  if (!intensities?.length) {
542
533
  const intensity_elements = doc.querySelectorAll(`I, Count`);
543
534
  if (intensity_elements.length > 0) {
@@ -546,7 +537,7 @@ function extract_scan_parameters_xml(doc) {
546
537
  .filter((val) => !isNaN(val));
547
538
  }
548
539
  }
549
- // Method 4: <Datum> elements with comma-separated values
540
+ // Method 3: <Datum> elements with comma-separated values
550
541
  // Bruker uses different formats depending on instrument/software version:
551
542
  // - 8-column HRXRD: "1,1,TwoTheta,Omega,...,Intensity" (indices 2 and 7)
552
543
  // - 5-column powder: "time,1,TwoTheta,Theta,Intensity" (indices 2 and 4)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterviz",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "Interactive visualizations for materials science: periodic tables, 3D structures, MD trajectories, heatmaps, scatter plots.",
5
5
  "keywords": [
6
6
  "chemistry",
@@ -20,7 +20,10 @@
20
20
  ],
21
21
  "type": "module",
22
22
  "sideEffects": [
23
- "**/*.css"
23
+ "**/*.css",
24
+ "**/file-viewer/main.*",
25
+ "**/theme/embedded.*",
26
+ "**/theme/themes.*"
24
27
  ],
25
28
  "exports": {
26
29
  ".": {
@@ -63,6 +66,30 @@
63
66
  "types": "./dist/feedback/index.d.ts",
64
67
  "default": "./dist/feedback/index.js"
65
68
  },
69
+ "./file-viewer": {
70
+ "types": "./dist/file-viewer/index.d.ts",
71
+ "default": "./dist/file-viewer/index.js"
72
+ },
73
+ "./file-viewer/parse": {
74
+ "types": "./dist/file-viewer/parse.d.ts",
75
+ "default": "./dist/file-viewer/parse.js"
76
+ },
77
+ "./file-viewer/eligibility": {
78
+ "types": "./dist/file-viewer/eligibility.d.ts",
79
+ "default": "./dist/file-viewer/eligibility.js"
80
+ },
81
+ "./file-viewer/host-protocol": {
82
+ "types": "./dist/file-viewer/host-protocol.d.ts",
83
+ "default": "./dist/file-viewer/host-protocol.js"
84
+ },
85
+ "./file-viewer/host-transfer": {
86
+ "types": "./dist/file-viewer/host-transfer.d.ts",
87
+ "default": "./dist/file-viewer/host-transfer.js"
88
+ },
89
+ "./file-viewer/webview": {
90
+ "types": "./dist/file-viewer/main.d.ts",
91
+ "default": "./dist/file-viewer/main.js"
92
+ },
66
93
  "./fermi-surface": {
67
94
  "types": "./dist/fermi-surface/index.d.ts",
68
95
  "default": "./dist/fermi-surface/index.js"
@@ -147,6 +174,10 @@
147
174
  "types": "./dist/theme/index.d.ts",
148
175
  "default": "./dist/theme/index.js"
149
176
  },
177
+ "./theme/embedded": {
178
+ "types": "./dist/theme/embedded.d.ts",
179
+ "default": "./dist/theme/embedded.js"
180
+ },
150
181
  "./theme/themes": {
151
182
  "default": "./dist/theme/themes.mjs"
152
183
  },
@@ -185,12 +216,13 @@
185
216
  "prepublishOnly": "pnpm run package:dist"
186
217
  },
187
218
  "dependencies": {
188
- "@spglib/moyo-wasm": "^0.14.0",
189
- "@sveltejs/kit": "2.69.2",
219
+ "@spglib/moyo-wasm": "^0.15.0",
220
+ "@sveltejs/kit": "2.69.3",
190
221
  "@threlte/core": "^8.5.16",
191
222
  "@threlte/extras": "^9.21.0",
192
223
  "d3-array": "^3.2.4",
193
224
  "d3-color": "^3.1.0",
225
+ "d3-contour": "^4.0.2",
194
226
  "d3-format": "^3.1.2",
195
227
  "d3-hierarchy": "^3.1.2",
196
228
  "d3-interpolate-path": "^2.3.0",
@@ -214,6 +246,7 @@
214
246
  "@sveltejs/vite-plugin-svelte": "^7.2.0",
215
247
  "@types/d3-array": "^3.2.2",
216
248
  "@types/d3-color": "^3.1.3",
249
+ "@types/d3-contour": "^3.0.6",
217
250
  "@types/d3-format": "^3.0.4",
218
251
  "@types/d3-hierarchy": "^3.1.7",
219
252
  "@types/d3-interpolate-path": "^2.0.3",
@@ -226,12 +259,12 @@
226
259
  "@vitest/coverage-v8": "4.1.10",
227
260
  "@wooorm/starry-night": "^3.10.0",
228
261
  "happy-dom": "^20.10.6",
229
- "knip": "^6.25.0",
262
+ "knip": "^6.26.0",
230
263
  "mdsvex": "^0.12.7",
231
264
  "publint": "^0.3.21",
232
265
  "rehype-katex": "^7.0.1",
233
266
  "remark-math": "3.0.1",
234
- "svelte": "^5.56.4",
267
+ "svelte": "^5.56.5",
235
268
  "svelte-check": "^4.7.2",
236
269
  "typescript": "^6.0.3",
237
270
  "vite": "^8.1.4",
@@ -276,8 +309,7 @@
276
309
  },
277
310
  "extensions/vscode": {
278
311
  "entry": [
279
- "src/extension.ts",
280
- "src/webview/main.ts"
312
+ "src/extension.ts"
281
313
  ],
282
314
  "paths": {
283
315
  "$lib": [