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,17 +1,41 @@
1
- <script lang="ts" generics="EntryT extends PhaseData = PhaseData">// Unified tooltip component for convex hull diagrams
2
- import { ELEM_SYMBOL_TO_NAME, get_electro_neg_formula } from '../composition';
3
- import { format_num } from '../labels';
4
- import { TooltipContent } from '../tooltip';
5
- import { is_unary_entry } from './types';
6
- let { entry, polymorph_stats_map, highlight_style, tooltip, show_fractional = true, } = $props();
7
- const is_element = $derived(is_unary_entry(entry));
8
- const elem_symbol = $derived(is_element
9
- ? (Object.entries(entry.composition).find(([, n]) => n > 0)?.[0] ?? ``)
10
- : ``);
11
- const elem_name = $derived(elem_symbol && ELEM_SYMBOL_TO_NAME[elem_symbol]);
12
- const polymorph_stats = $derived(entry.entry_id && polymorph_stats_map
13
- ? polymorph_stats_map.get(entry.entry_id)
14
- : null);
1
+ <script lang="ts" generics="EntryT extends PhaseData = PhaseData">
2
+ // Unified tooltip component for convex hull diagrams
3
+ import { ELEM_SYMBOL_TO_NAME, get_electro_neg_formula } from '../composition'
4
+ import type { ElementSymbol } from '../element'
5
+ import { format_num } from '../labels'
6
+ import { sanitize_html } from '../sanitize'
7
+ import { TooltipContent } from '../tooltip'
8
+ import type { PolymorphStats } from './helpers'
9
+ import type { ConvexHullTooltipProp, TooltipSnippetProps } from './index'
10
+ import type { HighlightStyle, PhaseData } from './types'
11
+ import { is_unary_entry } from './helpers'
12
+
13
+ let {
14
+ entry,
15
+ polymorph_stats_map,
16
+ highlight_style,
17
+ tooltip,
18
+ show_fractional = true,
19
+ }: {
20
+ entry: EntryT
21
+ polymorph_stats_map?: Map<string, PolymorphStats>
22
+ highlight_style?: HighlightStyle
23
+ tooltip?: ConvexHullTooltipProp<EntryT>
24
+ show_fractional?: boolean
25
+ } = $props()
26
+
27
+ const is_element = $derived(is_unary_entry(entry))
28
+ const elem_symbol = $derived(
29
+ is_element
30
+ ? (Object.entries(entry.composition).find(([, n]) => n > 0)?.[0] ?? ``)
31
+ : ``,
32
+ ) as ElementSymbol | ``
33
+ const elem_name = $derived(elem_symbol && ELEM_SYMBOL_TO_NAME[elem_symbol])
34
+ const polymorph_stats = $derived(
35
+ entry.entry_id && polymorph_stats_map
36
+ ? polymorph_stats_map.get(entry.entry_id)
37
+ : null,
38
+ )
15
39
  </script>
16
40
 
17
41
  <TooltipContent
@@ -32,7 +56,7 @@ const polymorph_stats = $derived(entry.entry_id && polymorph_stats_map
32
56
  {/if}
33
57
  {#if !is_element || !entry.entry_id}
34
58
  <strong style="display: block">
35
- {@html get_electro_neg_formula(entry.composition)}
59
+ {@html sanitize_html(get_electro_neg_formula(entry.composition))}
36
60
  </strong>
37
61
  {/if}
38
62
  </div>
@@ -56,7 +80,7 @@ const polymorph_stats = $derived(entry.entry_id && polymorph_stats_map
56
80
  .filter(([, amt]) => amt > 0)
57
81
  .map(([el, amt]) => `${el}<sub>${format_num(amt / total, `.2~`)}</sub>`)}
58
82
  {#if fractions.length > 1}
59
- <div>Fractional: {@html fractions.join(` `)}</div>
83
+ <div>Fractional: {@html sanitize_html(fractions.join(` `))}</div>
60
84
  {/if}
61
85
  {/if}
62
86
  {/if}
@@ -1,66 +1,110 @@
1
- <script lang="ts">import { tooltip } from 'svelte-multiselect';
2
- import { compute_gas_chemical_potential, format_chemical_potential, get_default_gas_provider, get_effective_pressures, } from './gas-thermodynamics';
3
- let { config, pressures = $bindable({}), temperature, position = `top-right`, ...rest } = $props();
4
- // Log scale range for pressure slider: 10^-10 to 10^2 bar
5
- const LOG_P_MIN = -10;
6
- const LOG_P_MAX = 2;
7
- const LOG_P_RANGE = LOG_P_MAX - LOG_P_MIN;
8
- const MIN_PRESSURE = 1e-15; // Safe minimum to avoid log(0) or NaN
9
- const THROTTLE_MS = 100;
10
- // Local preview state for smooth slider interaction without causing full hull re-renders
11
- let preview_pressures = $state({});
12
- let last_update_time = 0;
13
- // Get provider for chemical potential calculations
14
- const provider = $derived(config.provider ?? get_default_gas_provider());
15
- // Get enabled gases from config
16
- const enabled_gases = $derived(config.enabled_gases ?? []);
17
- // Effective pressures including defaults
18
- const effective_pressures = $derived(get_effective_pressures(config));
19
- // Get current pressure for a gas (preview during drag, committed, or default)
20
- function get_pressure(gas) {
21
- const P = preview_pressures[gas] ?? pressures[gas] ?? effective_pressures[gas];
22
- return Number.isFinite(P) && P > 0 ? P : MIN_PRESSURE;
23
- }
24
- // Compute chemical potential μ(T,P) for a gas at current temperature and pressure
25
- const get_mu = (gas) => compute_gas_chemical_potential(provider, gas, temperature, get_pressure(gas));
26
- // Convert pressure to log scale slider position (0-100)
27
- const pressure_to_slider = (P) => ((Math.max(LOG_P_MIN, Math.min(LOG_P_MAX, Math.log10(P))) - LOG_P_MIN) /
28
- LOG_P_RANGE) * 100;
29
- // Convert slider position (0-100) to pressure
30
- const slider_to_pressure = (value) => Math.pow(10, LOG_P_MIN + (value / 100) * LOG_P_RANGE);
31
- // Format gas name for display (subscript numbers)
32
- const format_gas_name = (gas) => gas.replace(/(\d+)/g, `<sub>$1</sub>`);
33
- // Format pressure as plain text (no HTML) for the number input
34
- function format_pressure(P) {
35
- const log_P = Math.log10(P);
36
- const exp = Math.round(log_P);
37
- if (Math.abs(log_P - exp) < 0.1)
38
- return `1e${exp}`;
39
- if (P >= 0.01 && P < 100)
40
- return P.toPrecision(2);
41
- return P.toExponential(1);
42
- }
43
- function set_pressure(gas, value) {
44
- const P = slider_to_pressure(value);
45
- preview_pressures = { ...preview_pressures, [gas]: P };
1
+ <script lang="ts">
2
+ import type {
3
+ GasControlPosition,
4
+ GasSpecies,
5
+ GasThermodynamicsConfig,
6
+ } from './types'
7
+ import { sanitize_html } from '../sanitize'
8
+ import { tooltip } from 'svelte-multiselect'
9
+ import type { HTMLAttributes } from 'svelte/elements'
10
+ import {
11
+ compute_gas_chemical_potential,
12
+ format_chemical_potential,
13
+ get_default_gas_provider,
14
+ get_effective_pressures,
15
+ } from './gas-thermodynamics'
16
+
17
+ let {
18
+ config,
19
+ pressures = $bindable({}),
20
+ temperature,
21
+ position = `top-right`,
22
+ ...rest
23
+ }: HTMLAttributes<HTMLDivElement> & {
24
+ config: GasThermodynamicsConfig
25
+ pressures: Partial<Record<GasSpecies, number>>
26
+ temperature: number
27
+ position?: GasControlPosition
28
+ } = $props()
29
+
30
+ // Log scale range for pressure slider: 10^-10 to 10^2 bar
31
+ const LOG_P_MIN = -10
32
+ const LOG_P_MAX = 2
33
+ const LOG_P_RANGE = LOG_P_MAX - LOG_P_MIN
34
+ const MIN_PRESSURE = 1e-15 // Safe minimum to avoid log(0) or NaN
35
+ const THROTTLE_MS = 100
36
+
37
+ // Local preview state for smooth slider interaction without causing full hull re-renders
38
+ let preview_pressures = $state<Partial<Record<GasSpecies, number>>>({})
39
+ let last_update_time = 0
40
+
41
+ // Get provider for chemical potential calculations
42
+ const provider = $derived(config.provider ?? get_default_gas_provider())
43
+
44
+ // Get enabled gases from config
45
+ const enabled_gases = $derived(config.enabled_gases ?? [])
46
+
47
+ // Effective pressures including defaults
48
+ const effective_pressures = $derived(get_effective_pressures(config))
49
+
50
+ // Get current pressure for a gas (preview during drag, committed, or default)
51
+ function get_pressure(gas: GasSpecies): number {
52
+ const P = preview_pressures[gas] ?? pressures[gas] ?? effective_pressures[gas]
53
+ return Number.isFinite(P) && P > 0 ? P : MIN_PRESSURE
54
+ }
55
+
56
+ // Compute chemical potential μ(T,P) for a gas at current temperature and pressure
57
+ const get_mu = (gas: GasSpecies): number =>
58
+ compute_gas_chemical_potential(provider, gas, temperature, get_pressure(gas))
59
+
60
+ // Convert pressure to log scale slider position (0-100)
61
+ const pressure_to_slider = (P: number): number =>
62
+ ((Math.max(LOG_P_MIN, Math.min(LOG_P_MAX, Math.log10(P))) - LOG_P_MIN) /
63
+ LOG_P_RANGE) * 100
64
+
65
+ // Convert slider position (0-100) to pressure
66
+ const slider_to_pressure = (value: number): number =>
67
+ Math.pow(10, LOG_P_MIN + (value / 100) * LOG_P_RANGE)
68
+
69
+ // Format gas name for display (subscript numbers)
70
+ const format_gas_name = (gas: GasSpecies): string =>
71
+ gas.replaceAll(/(\d+)/g, `<sub>$1</sub>`)
72
+
73
+ // Format pressure as plain text (no HTML) for the number input
74
+ function format_pressure(P: number): string {
75
+ const log_P = Math.log10(P)
76
+ const exp = Math.round(log_P)
77
+ if (Math.abs(log_P - exp) < 0.1) return `1e${exp}`
78
+ if (P >= 0.01 && P < 100) return P.toPrecision(2)
79
+ return P.toExponential(1)
80
+ }
81
+
82
+ function set_pressure(gas: GasSpecies, value: number): void {
83
+ const P = slider_to_pressure(value)
84
+ preview_pressures = { ...preview_pressures, [gas]: P }
46
85
  // Throttle parent updates during drag to prevent hull recomputation on every pixel
47
- const now = Date.now();
86
+ const now = Date.now()
48
87
  if (now - last_update_time >= THROTTLE_MS) {
49
- last_update_time = now;
50
- pressures = { ...pressures, [gas]: P };
88
+ last_update_time = now
89
+ pressures = { ...pressures, [gas]: P }
51
90
  }
52
- }
53
- function handle_slider_end(gas, event) {
54
- const P = slider_to_pressure(+event.currentTarget.value);
55
- pressures = { ...pressures, [gas]: P };
91
+ }
92
+
93
+ function handle_slider_end(gas: GasSpecies, event: Event): void {
94
+ const P = slider_to_pressure(+(event.currentTarget as HTMLInputElement).value)
95
+ pressures = { ...pressures, [gas]: P }
56
96
  // Clear only this gas's preview (don't reset other sliders being dragged simultaneously)
57
- const { [gas]: _, ...rest } = preview_pressures;
58
- preview_pressures = rest;
59
- }
60
- function set_pressure_direct(gas, value) {
61
- const clamped = Math.max(Math.pow(10, LOG_P_MIN), Math.min(Math.pow(10, LOG_P_MAX), value));
62
- pressures = { ...pressures, [gas]: clamped };
63
- }
97
+ const { [gas]: _, ...rest } = preview_pressures
98
+ preview_pressures = rest
99
+ }
100
+
101
+ function set_pressure_direct(gas: GasSpecies, value: number): void {
102
+ const clamped = Math.max(
103
+ Math.pow(10, LOG_P_MIN),
104
+ Math.min(Math.pow(10, LOG_P_MAX), value),
105
+ )
106
+ pressures = { ...pressures, [gas]: clamped }
107
+ }
64
108
  </script>
65
109
 
66
110
  {#if enabled_gases.length > 0}
@@ -88,8 +132,7 @@ function set_pressure_direct(gas, value) {
88
132
  }}
89
133
  aria-label="{gas} pressure (bar)"
90
134
  />
91
- <!-- eslint-disable-next-line svelte/no-at-html-tags -->
92
- <span class="gas-name">{@html format_gas_name(gas)}</span>
135
+ <span class="gas-name">{@html sanitize_html(format_gas_name(gas))}</span>
93
136
  </label>
94
137
  <div class="slider-wrapper">
95
138
  <span class="pressure-range">
@@ -1,7 +1,28 @@
1
- <script lang="ts">import Icon from '../Icon.svelte';
2
- import { format_num } from '../labels';
3
- import { Structure } from '../structure';
4
- let { structure, place_right = true, width = 500, height = 400, onclose, stats, popup_div = $bindable(), ...rest } = $props();
1
+ <script lang="ts">
2
+ import type { AnyStructure } from '../structure'
3
+ import Icon from '../Icon.svelte'
4
+ import { format_num } from '../labels'
5
+ import { Structure } from '../structure'
6
+ import type { HTMLAttributes } from 'svelte/elements'
7
+
8
+ let {
9
+ structure,
10
+ place_right = true,
11
+ width = 500,
12
+ height = 400,
13
+ onclose,
14
+ stats,
15
+ popup_div = $bindable(),
16
+ ...rest
17
+ }: HTMLAttributes<HTMLDivElement> & {
18
+ structure: AnyStructure
19
+ place_right?: boolean
20
+ width?: number
21
+ height?: number
22
+ onclose?: () => void
23
+ stats?: { id?: string; e_above_hull?: number; e_form?: number }
24
+ popup_div?: HTMLDivElement
25
+ } = $props()
5
26
  </script>
6
27
 
7
28
  {#snippet close_button()}
@@ -1,31 +1,51 @@
1
- <script lang="ts">import { tooltip } from 'svelte-multiselect';
2
- let { available_temperatures, temperature = $bindable(), ...rest } = $props();
3
- // Local preview state for smooth slider interaction without causing full re-renders
4
- let preview_index = $state(null);
5
- let last_update_time = 0;
6
- const THROTTLE_MS = 100;
7
- const temp_index = $derived(Math.max(0, available_temperatures.indexOf(temperature)));
8
- const display_index = $derived(preview_index ?? temp_index);
9
- const display_temp = $derived(available_temperatures[display_index] ?? temperature);
10
- function handle_slider_input(event) {
11
- const new_index = +event.currentTarget.value;
12
- preview_index = new_index;
1
+ <script lang="ts">
2
+ import { tooltip } from 'svelte-multiselect'
3
+ import type { HTMLAttributes } from 'svelte/elements'
4
+
5
+ let {
6
+ available_temperatures,
7
+ temperature = $bindable(),
8
+ ...rest
9
+ }: HTMLAttributes<HTMLDivElement> & {
10
+ available_temperatures: number[]
11
+ temperature: number
12
+ } = $props()
13
+
14
+ // Local preview state for smooth slider interaction without causing full re-renders
15
+ let preview_index = $state<number | null>(null)
16
+ let last_update_time = 0
17
+ const THROTTLE_MS = 100
18
+
19
+ const temp_index = $derived(
20
+ Math.max(0, available_temperatures.indexOf(temperature)),
21
+ )
22
+ const display_index = $derived(preview_index ?? temp_index)
23
+ const display_temp = $derived(available_temperatures[display_index] ?? temperature)
24
+
25
+ function handle_slider_input(event: Event): void {
26
+ const new_index = +(event.currentTarget as HTMLInputElement).value
27
+ preview_index = new_index
13
28
  // Throttle parent updates during drag to prevent scene flashing
14
- const now = Date.now();
29
+ const now = Date.now()
15
30
  if (now - last_update_time >= THROTTLE_MS) {
16
- last_update_time = now;
17
- temperature = available_temperatures[new_index] ?? temperature;
31
+ last_update_time = now
32
+ temperature = available_temperatures[new_index] ?? temperature
18
33
  }
19
- }
20
- function handle_slider_end(event) {
21
- const new_temp = available_temperatures[+event.currentTarget.value];
22
- if (new_temp !== undefined)
23
- temperature = new_temp;
24
- preview_index = null;
25
- }
26
- function set_closest_temp(value) {
27
- temperature = available_temperatures.reduce((prev, curr) => (Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev), temperature);
28
- }
34
+ }
35
+
36
+ function handle_slider_end(event: Event): void {
37
+ const new_temp =
38
+ available_temperatures[+(event.currentTarget as HTMLInputElement).value]
39
+ if (new_temp !== undefined) temperature = new_temp
40
+ preview_index = null
41
+ }
42
+
43
+ function set_closest_temp(value: number): void {
44
+ temperature = available_temperatures.reduce(
45
+ (prev, curr) => (Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev),
46
+ temperature,
47
+ )
48
+ }
29
49
  </script>
30
50
 
31
51
  <div
@@ -1,5 +1,5 @@
1
1
  import { compute_e_form_per_atom, find_lowest_energy_unary_refs } from './thermodynamics';
2
- import { is_unary_entry } from './types';
2
+ import { is_unary_entry } from './helpers';
3
3
  // --- Ternary coordinates ---
4
4
  export const TRIANGLE_VERTICES = [
5
5
  [1, 0],
@@ -81,10 +81,9 @@ export function get_ternary_3d_coordinates(entries, elements, el_refs) {
81
81
  // Map entries to ternary plot coordinates
82
82
  const result = within_system.map((entry) => {
83
83
  const barycentric = composition_to_barycentric_3d(entry.composition, elements);
84
- const e_form_per_atom = typeof entry.e_form_per_atom === `number` &&
85
- Number.isFinite(entry.e_form_per_atom)
84
+ const e_form_per_atom = typeof entry.e_form_per_atom === `number` && Number.isFinite(entry.e_form_per_atom)
86
85
  ? entry.e_form_per_atom
87
- : compute_e_form_per_atom(entry, refs) ?? NaN;
86
+ : (compute_e_form_per_atom(entry, refs) ?? NaN);
88
87
  const xyz = barycentric_to_ternary_xyz(barycentric, e_form_per_atom);
89
88
  const is_element = is_unary_entry(entry);
90
89
  return { ...entry, ...xyz, is_element, visible: true };
@@ -93,11 +92,18 @@ export function get_ternary_3d_coordinates(entries, elements, el_refs) {
93
92
  }
94
93
  export function get_triangle_edges() {
95
94
  const [v0, v1, v2] = TRIANGLE_VERTICES.map(([x, y]) => ({ x, y, z: 0 }));
96
- return [[v0, v1], [v1, v2], [v2, v0]];
95
+ return [
96
+ [v0, v1],
97
+ [v1, v2],
98
+ [v2, v0],
99
+ ];
97
100
  }
98
101
  export function get_triangle_vertical_edges(min_z, max_z) {
99
102
  const vertices = TRIANGLE_VERTICES.map(([x, y]) => ({ x, y, z: 0 }));
100
- return vertices.map((vertex) => [{ ...vertex, z: min_z }, { ...vertex, z: max_z }]);
103
+ return vertices.map((vertex) => [
104
+ { ...vertex, z: min_z },
105
+ { ...vertex, z: max_z },
106
+ ]);
101
107
  }
102
108
  // --- N-dimensional barycentric coordinates (for 5+ element systems) ---
103
109
  // Convert composition to N-dimensional barycentric coordinates
@@ -111,7 +117,7 @@ export function composition_to_barycentric_nd(composition, elements) {
111
117
  // NaN and undefined/missing elements are treated as 0
112
118
  const amounts = elements.map((el) => {
113
119
  const val = composition[el];
114
- return (val === null || val === undefined || Number.isNaN(val)) ? 0 : val;
120
+ return val == null || Number.isNaN(val) ? 0 : val;
115
121
  });
116
122
  let total = 0;
117
123
  const negative = [];
@@ -6,20 +6,24 @@ function seeded_random(seed) {
6
6
  export function make_demo_phase(composition, seed, entropy_boost = 0) {
7
7
  const n_elements = Object.keys(composition).length;
8
8
  const energy = -0.3 * n_elements - seeded_random(seed) * 0.5;
9
- const entropy_coef = 0.5 + n_elements * 0.3 + seeded_random(seed + 1) * 2 +
10
- entropy_boost;
9
+ const entropy_coef = 0.5 + n_elements * 0.3 + seeded_random(seed + 1) * 2 + entropy_boost;
11
10
  return {
12
11
  composition,
13
12
  energy,
14
13
  temperatures: demo_temperatures,
15
- free_energies: demo_temperatures.map((temp_kelvin) => energy + entropy_coef * temp_kelvin * 0.0001 -
14
+ free_energies: demo_temperatures.map((temp_kelvin) => energy +
15
+ entropy_coef * temp_kelvin * 0.0001 -
16
16
  0.00005 * temp_kelvin * Math.log(temp_kelvin)),
17
17
  };
18
18
  }
19
19
  export function create_temp_ternary_entries_li_fe_o() {
20
20
  return [
21
21
  ...[`Li`, `Fe`, `O`].map((element, idx) => make_demo_phase({ [element]: 1 }, idx)),
22
- ...[[`Li`, `Fe`], [`Li`, `O`], [`Fe`, `O`]].flatMap(([element_a, element_b], idx) => [0.33, 0.5, 0.67].flatMap((fraction, jdx) => [
22
+ ...[
23
+ [`Li`, `Fe`],
24
+ [`Li`, `O`],
25
+ [`Fe`, `O`],
26
+ ].flatMap(([element_a, element_b], idx) => [0.33, 0.5, 0.67].flatMap((fraction, jdx) => [
23
27
  make_demo_phase({ [element_a]: fraction, [element_b]: 1 - fraction }, 100 + idx * 10 + jdx),
24
28
  make_demo_phase({ [element_a]: fraction, [element_b]: 1 - fraction }, 200 + idx * 10 + jdx, 3),
25
29
  ])),
@@ -28,7 +28,7 @@ export const GAS_STOICHIOMETRY = {
28
28
  // Source: Barin Thermochemical Tables and NBS Thermochemical Tables
29
29
  // Data compiled to match PIRO (https://github.com/GENESIS-EFRC/piro)
30
30
  // Note: These values are T*S in eV/molecule
31
- // deno-fmt-ignore
31
+ // oxfmt-ignore
32
32
  const DEFAULT_TS_DATA = {
33
33
  O2: {
34
34
  temperatures: [0, 298, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000],
@@ -56,8 +56,14 @@ const DEFAULT_TS_DATA = {
56
56
  },
57
57
  F2: {
58
58
  // F2 not in Barin/NBS tables used by PIRO - approximated from similar homonuclear diatomics (O2, N2)
59
- temperatures: [0, 298, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000],
60
- values: [0, 0.31, 0.312, 0.435, 0.56, 0.69, 0.82, 0.96, 1.1, 1.24, 1.38, 1.53, 1.68, 1.83, 1.98, 2.13, 2.29, 2.45, 2.61, 2.77],
59
+ temperatures: [
60
+ 0, 298, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600,
61
+ 1700, 1800, 1900, 2000,
62
+ ],
63
+ values: [
64
+ 0, 0.31, 0.312, 0.435, 0.56, 0.69, 0.82, 0.96, 1.1, 1.24, 1.38, 1.53, 1.68, 1.83,
65
+ 1.98, 2.13, 2.29, 2.45, 2.61, 2.77,
66
+ ],
61
67
  },
62
68
  };
63
69
  // Formation enthalpies H_f at 0K in eV/molecule
@@ -81,13 +87,13 @@ function interpolate_ts(data, T) {
81
87
  return values[values.length - 1];
82
88
  }
83
89
  // Find bracketing indices
84
- let i = 0;
85
- while (i < temperatures.length - 1 && temperatures[i + 1] < T)
86
- i++;
87
- const T_low = temperatures[i];
88
- const T_high = temperatures[i + 1];
89
- const v_low = values[i];
90
- const v_high = values[i + 1];
90
+ let idx = 0;
91
+ while (idx < temperatures.length - 1 && temperatures[idx + 1] < T)
92
+ idx++;
93
+ const T_low = temperatures[idx];
94
+ const T_high = temperatures[idx + 1];
95
+ const v_low = values[idx];
96
+ const v_high = values[idx + 1];
91
97
  // Linear interpolation
92
98
  const fraction = (T - T_low) / (T_high - T_low);
93
99
  return v_low + fraction * (v_high - v_low);
@@ -146,8 +152,7 @@ export function compute_gas_chemical_potential(provider, gas, T, P) {
146
152
  // μ_per_atom(T, P) = μ°_per_atom(T) + k_B·T·ln(P/P₀) / num_atoms
147
153
  // The RT·ln(P) term must be divided by num_atoms to match PIRO's per-atom convention
148
154
  const num_atoms = GAS_NUM_ATOMS[gas];
149
- return mu_standard +
150
- (R_EV_PER_K * T * Math.log(effective_P / P_REF)) / num_atoms;
155
+ return mu_standard + (R_EV_PER_K * T * Math.log(effective_P / P_REF)) / num_atoms;
151
156
  }
152
157
  // Compute chemical potential per atom of a specific element from a gas
153
158
  // Since compute_gas_chemical_potential returns per-atom of gas molecule,
@@ -4,6 +4,14 @@ import type { ElementSymbol } from '../element';
4
4
  import type { ConvexHullConfig, GasAnalysis, GasThermodynamicsConfig, HighlightStyle, MarkerSymbol, PhaseData } from './types';
5
5
  import { DEFAULT_GAS_TEMP } from './types';
6
6
  export { DEFAULT_GAS_TEMP };
7
+ export declare const HULL_STABILITY_TOL = 0.000001;
8
+ export declare function compute_hull_stability(raw_distance: number, exclude_from_hull?: boolean, tol?: number): {
9
+ e_above_hull: number;
10
+ is_stable: boolean;
11
+ };
12
+ export declare const is_on_hull: (entry: PhaseData, tol?: number) => boolean;
13
+ export declare const get_arity: (entry: PhaseData) => number;
14
+ export declare const is_unary_entry: (entry: PhaseData) => boolean;
7
15
  export declare function get_energy_color_scale(color_mode: `stability` | `energy`, color_scale: D3InterpolateName, plot_entries: {
8
16
  e_above_hull?: number;
9
17
  }[]): ((value: number) => string) | null;
@@ -55,6 +63,7 @@ export interface PolymorphStats {
55
63
  lower: number;
56
64
  equal: number;
57
65
  }
66
+ export declare function get_composition_label_entries<T extends PhaseData>(entries: Iterable<T>): T[];
58
67
  export declare function compute_all_polymorph_stats(all_entries: PhaseData[]): Map<string, PolymorphStats>;
59
68
  export declare function draw_highlight_effect(ctx: CanvasRenderingContext2D, projected: {
60
69
  x: number;