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,224 +1,364 @@
1
- <script lang="ts">import { compute_brillouin_zone, reciprocal_lattice } from '../brillouin';
2
- import { normalize_show_controls } from '../controls';
3
- import EmptyState from '../EmptyState.svelte';
4
- import { StatusMessage } from '../feedback';
5
- import Spinner from '../feedback/Spinner.svelte';
6
- import Icon from '../Icon.svelte';
7
- import { create_file_drop_handler, load_from_url } from '../io';
8
- import { set_fullscreen_bg, toggle_fullscreen } from '../layout';
9
- import { PlotTooltip } from '../plot';
10
- import { DEFAULTS } from '../settings';
11
- import { Canvas } from '@threlte/core';
12
- import { untrack } from 'svelte';
13
- import { tooltip } from 'svelte-multiselect/attachments';
14
- import { detect_irreducible_bz, extract_fermi_surface } from './compute';
15
- import FermiSurfaceControls from './FermiSurfaceControls.svelte';
16
- import FermiSurfaceScene from './FermiSurfaceScene.svelte';
17
- import FermiSurfaceTooltip from './FermiSurfaceTooltip.svelte';
18
- import { parse_fermi_file } from './parse';
19
- let { fermi_data = $bindable(), band_data = $bindable(), structure, bz_data = $bindable(), mu = $bindable(0), controls_open = $bindable(false), color_property = $bindable(`band`), color_scale = $bindable(`interpolateViridis`), custom_property_label, representation = $bindable(`solid`), surface_opacity = $bindable(0.8), selected_bands = $bindable(), show_bz = $bindable(true), bz_opacity = $bindable(0.1), show_vectors = $bindable(true), tile_bz = $bindable(false),
20
- // Clipping plane
21
- clip_enabled = $bindable(false), clip_axis = $bindable(`z`), clip_position = $bindable(0), clip_flip = $bindable(false),
22
- // Interpolation
23
- interpolation_factor = $bindable(1), camera_projection = $bindable(`perspective`), show_controls, fullscreen = $bindable(false), wrapper = $bindable(), width = $bindable(0), height = $bindable(0), hovered = $bindable(false), dragover = $bindable(false), allow_file_drop = true, fullscreen_toggle = DEFAULTS.structure.fullscreen_toggle, data_url, spinner_props = {}, loading = $bindable(false), error_msg = $bindable(), children, tooltip_config, on_file_drop, on_file_load, on_error, on_fullscreen_change, on_mu_change, on_hover, ...rest } = $props();
24
- let scene = $state(undefined);
25
- let camera = $state(undefined);
26
- let current_filename = $state(undefined);
27
- let recompute_job_id = 0; // monotonic counter to track latest recompute call
28
- let hover_data = $state(null);
29
- // Call on_hover callback when hover_data changes
30
- $effect(() => {
31
- on_hover?.(hover_data);
32
- });
33
- let controls_config = $derived(normalize_show_controls(show_controls));
34
- // Yield to browser so spinner can render before heavy computation
35
- const tick = () => new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(() => r())));
36
- // Parse and load Fermi surface from content (async for UI responsiveness)
37
- async function parse_fermi_content(content, filename) {
1
+ <script lang="ts">
2
+ import type { BrillouinZoneData } from '../brillouin'
3
+ import { compute_brillouin_zone, reciprocal_lattice } from '../brillouin'
4
+ import type { ShowControlsProp } from '../controls'
5
+ import { normalize_show_controls } from '../controls'
6
+ import EmptyState from '../EmptyState.svelte'
7
+ import { StatusMessage } from '../feedback'
8
+ import Spinner from '../feedback/Spinner.svelte'
9
+ import Icon from '../Icon.svelte'
10
+ import { create_file_drop_handler, load_from_url } from '../io'
11
+ import { set_fullscreen_bg, toggle_fullscreen } from '../layout'
12
+ import { PlotTooltip } from '../plot'
13
+ import type { CameraProjection } from '../settings'
14
+ import { DEFAULTS } from '../settings'
15
+ import type { Crystal } from '../structure'
16
+ import { Canvas } from '@threlte/core'
17
+ import type { ComponentProps, Snippet } from 'svelte'
18
+ import { untrack } from 'svelte'
19
+ import { tooltip } from 'svelte-multiselect/attachments'
20
+ import type { HTMLAttributes } from 'svelte/elements'
21
+ import type { Camera, Scene } from 'three'
22
+ import { detect_irreducible_bz, extract_fermi_surface } from './compute'
23
+ import FermiSurfaceControls from './FermiSurfaceControls.svelte'
24
+ import FermiSurfaceScene from './FermiSurfaceScene.svelte'
25
+ import FermiSurfaceTooltip from './FermiSurfaceTooltip.svelte'
26
+ import { parse_fermi_file } from './parse'
27
+ import type {
28
+ BandGridData,
29
+ ColorProperty,
30
+ FermiErrorData,
31
+ FermiFileLoadData,
32
+ FermiHoverData,
33
+ FermiSurfaceData,
34
+ FermiTooltipConfig,
35
+ RepresentationMode,
36
+ } from './types'
37
+
38
+ type FermiHandlerData = {
39
+ fermi_data?: FermiSurfaceData
40
+ band_data?: BandGridData
41
+ bz_data?: BrillouinZoneData
42
+ filename?: string
43
+ file_size?: number
44
+ error_msg?: string
45
+ fullscreen?: boolean
46
+ }
47
+
48
+ let {
49
+ fermi_data = $bindable(),
50
+ band_data = $bindable(),
51
+ structure,
52
+ bz_data = $bindable(),
53
+ mu = $bindable(0),
54
+ controls_open = $bindable(false),
55
+ color_property = $bindable(`band`),
56
+ color_scale = $bindable(`interpolateViridis`),
57
+ custom_property_label,
58
+ representation = $bindable(`solid`),
59
+ surface_opacity = $bindable(0.8),
60
+ selected_bands = $bindable(),
61
+ show_bz = $bindable(true),
62
+ bz_opacity = $bindable(0.1),
63
+ show_vectors = $bindable(true),
64
+ tile_bz = $bindable(false),
65
+ // Clipping plane
66
+ clip_enabled = $bindable(false),
67
+ clip_axis = $bindable(`z`),
68
+ clip_position = $bindable(0),
69
+ clip_flip = $bindable(false),
70
+ // Interpolation
71
+ interpolation_factor = $bindable(1),
72
+ camera_projection = $bindable(`perspective`),
73
+ show_controls,
74
+ fullscreen = $bindable(false),
75
+ wrapper = $bindable(),
76
+ width = $bindable(0),
77
+ height = $bindable(0),
78
+ hovered = $bindable(false),
79
+ dragover = $bindable(false),
80
+ allow_file_drop = true,
81
+ fullscreen_toggle = DEFAULTS.structure.fullscreen_toggle,
82
+ data_url,
83
+ spinner_props = {},
84
+ loading = $bindable(false),
85
+ error_msg = $bindable(),
86
+ children,
87
+ tooltip_config,
88
+ on_file_drop,
89
+ on_file_load,
90
+ on_error,
91
+ on_fullscreen_change,
92
+ on_mu_change,
93
+ on_hover,
94
+ ...rest
95
+ }: {
96
+ fermi_data?: FermiSurfaceData
97
+ band_data?: BandGridData
98
+ structure?: Crystal
99
+ bz_data?: BrillouinZoneData
100
+ mu?: number
101
+ controls_open?: boolean
102
+ color_property?: ColorProperty
103
+ color_scale?: string
104
+ // Label for custom property coloring (e.g. "λ(k)", "DOS", etc.)
105
+ custom_property_label?: string
106
+ representation?: RepresentationMode
107
+ surface_opacity?: number
108
+ selected_bands?: number[]
109
+ show_bz?: boolean
110
+ bz_opacity?: number
111
+ show_vectors?: boolean
112
+ tile_bz?: boolean
113
+ clip_enabled?: boolean
114
+ clip_axis?: `x` | `y` | `z`
115
+ clip_position?: number
116
+ clip_flip?: boolean
117
+ interpolation_factor?: number
118
+ camera_projection?: CameraProjection
119
+ /**
120
+ * Controls visibility configuration.
121
+ * - 'always': controls always visible
122
+ * - 'hover': controls visible on component hover (default)
123
+ * - 'never': controls never visible
124
+ * - object: { mode, hidden, style } for fine-grained control
125
+ *
126
+ * Control names: 'filename', 'fullscreen', 'controls'
127
+ */
128
+ show_controls?: ShowControlsProp
129
+ fullscreen?: boolean
130
+ width?: number
131
+ height?: number
132
+ wrapper?: HTMLDivElement
133
+ hovered?: boolean
134
+ dragover?: boolean
135
+ allow_file_drop?: boolean
136
+ fullscreen_toggle?: Snippet<[{ fullscreen: boolean }]> | boolean
137
+ data_url?: string
138
+ spinner_props?: ComponentProps<typeof Spinner>
139
+ loading?: boolean
140
+ error_msg?: string
141
+ children?: Snippet<
142
+ [{ fermi_data?: FermiSurfaceData; bz_data?: BrillouinZoneData }]
143
+ >
144
+ on_file_drop?: (filename: string) => void
145
+ on_file_load?: (data: FermiFileLoadData) => void
146
+ on_error?: (data: FermiErrorData) => void
147
+ on_fullscreen_change?: (data: FermiHandlerData) => void
148
+ on_mu_change?: (mu: number) => void
149
+ tooltip_config?: Snippet<[{ hover_data: FermiHoverData }]> | FermiTooltipConfig
150
+ on_hover?: (data: FermiHoverData | null) => void
151
+ } & HTMLAttributes<HTMLDivElement> = $props()
152
+
153
+ let scene = $state<Scene | undefined>(undefined)
154
+ let camera = $state<Camera | undefined>(undefined)
155
+ let current_filename = $state<string | undefined>(undefined)
156
+ let recompute_job_id = 0 // monotonic counter to track latest recompute call
157
+ let hover_data = $state<FermiHoverData | null>(null)
158
+
159
+ // Call on_hover callback when hover_data changes
160
+ $effect(() => {
161
+ on_hover?.(hover_data)
162
+ })
163
+
164
+ let controls_config = $derived(normalize_show_controls(show_controls))
165
+
166
+ // Yield to browser so spinner can render before heavy computation
167
+ const tick = () =>
168
+ new Promise<void>((r) =>
169
+ requestAnimationFrame(() => requestAnimationFrame(() => r()))
170
+ )
171
+
172
+ // Parse and load Fermi surface from content (async for UI responsiveness)
173
+ async function parse_fermi_content(
174
+ content: string | ArrayBuffer,
175
+ filename: string,
176
+ ) {
38
177
  const text = content instanceof ArrayBuffer
39
- ? new TextDecoder().decode(content)
40
- : content;
41
- const parsed = parse_fermi_file(text, filename);
42
- if (!parsed)
43
- throw new Error(`Failed to parse Fermi surface from ${filename}`);
44
- const file_size = new Blob([content]).size;
45
- current_filename = filename;
178
+ ? new TextDecoder().decode(content)
179
+ : content
180
+
181
+ const parsed = parse_fermi_file(text, filename)
182
+ if (!parsed) throw new Error(`Failed to parse Fermi surface from ${filename}`)
183
+
184
+ const file_size = new Blob([content]).size
185
+ current_filename = filename
186
+
46
187
  // Check if it's already FermiSurfaceData or BandGridData
47
188
  if (`isosurfaces` in parsed) {
48
- fermi_data = parsed;
49
- band_data = undefined;
50
- }
51
- else {
52
- band_data = parsed;
53
- fermi_data = extract_fermi_surface(band_data, { mu, wigner_seitz: true });
189
+ fermi_data = parsed as FermiSurfaceData
190
+ band_data = undefined
191
+ } else {
192
+ band_data = parsed as BandGridData
193
+ fermi_data = extract_fermi_surface(band_data, { mu, wigner_seitz: true })
54
194
  }
55
- on_file_load?.({ fermi_data, band_data, filename, file_size });
56
- }
57
- // Load with error handling
58
- async function safe_parse(content, filename) {
195
+
196
+ on_file_load?.({ fermi_data, band_data, filename, file_size })
197
+ }
198
+
199
+ // Load with error handling
200
+ async function safe_parse(content: string | ArrayBuffer, filename: string) {
59
201
  try {
60
- await parse_fermi_content(content, filename);
61
- }
62
- catch (err) {
63
- error_msg = `Failed to parse ${filename}: ${err instanceof Error ? err.message : err}`;
64
- on_error?.({ error_msg, filename });
202
+ await parse_fermi_content(content, filename)
203
+ } catch (err) {
204
+ error_msg = `Failed to parse ${filename}: ${
205
+ err instanceof Error ? err.message : err
206
+ }`
207
+ on_error?.({ error_msg, filename })
65
208
  }
66
- }
67
- // Re-extract Fermi surface from band data with current settings
68
- async function recompute_fermi_surface() {
69
- if (!band_data)
70
- return;
71
- const job_id = ++recompute_job_id; // capture this job's ID
72
- await tick(); // yield to check for newer jobs before committing to work
209
+ }
210
+
211
+ // Re-extract Fermi surface from band data with current settings
212
+ async function recompute_fermi_surface() {
213
+ if (!band_data) return
214
+ const job_id = ++recompute_job_id // capture this job's ID
215
+ await tick() // yield to check for newer jobs before committing to work
73
216
  // Check if this job is still the latest before proceeding
74
217
  // If stale, return without setting loading - the superseding job handles it
75
- if (job_id !== recompute_job_id)
76
- return;
218
+ if (job_id !== recompute_job_id) return
77
219
  // Only set loading after stale check to avoid orphaned loading states
78
- loading = true;
220
+ loading = true
79
221
  try {
80
- const result = extract_fermi_surface(band_data, {
81
- mu,
82
- wigner_seitz: true,
83
- interpolation_factor,
84
- });
85
- // Only update state if this is still the latest job
86
- if (job_id === recompute_job_id) {
87
- fermi_data = result;
88
- }
89
- }
90
- catch (err) {
91
- console.error(`Failed to re-extract Fermi surface:`, err);
222
+ const result = extract_fermi_surface(band_data, {
223
+ mu,
224
+ wigner_seitz: true,
225
+ interpolation_factor,
226
+ })
227
+ // Only update state if this is still the latest job
228
+ if (job_id === recompute_job_id) {
229
+ fermi_data = result
230
+ }
231
+ } catch (err) {
232
+ console.error(`Failed to re-extract Fermi surface:`, err)
233
+ } finally {
234
+ // Only clear loading if this is still the latest job
235
+ if (job_id === recompute_job_id) loading = false
92
236
  }
93
- finally {
94
- // Only clear loading if this is still the latest job
95
- if (job_id === recompute_job_id)
96
- loading = false;
97
- }
98
- }
99
- // Debounce recompute to avoid excessive re-computation during rapid slider drags
100
- let recompute_timeout;
101
- function handle_mu_change(new_mu) {
102
- mu = new_mu;
103
- clearTimeout(recompute_timeout);
104
- recompute_timeout = setTimeout(() => void recompute_fermi_surface(), 150);
105
- on_mu_change?.(new_mu);
106
- }
107
- function handle_interpolation_change(new_factor) {
108
- interpolation_factor = new_factor;
109
- clearTimeout(recompute_timeout);
110
- recompute_timeout = setTimeout(() => void recompute_fermi_surface(), 150);
111
- }
112
- // Export Fermi surface to various formats
113
- async function handle_export(format) {
237
+ }
238
+
239
+ // Debounce recompute to avoid excessive re-computation during rapid slider drags
240
+ let recompute_timeout: ReturnType<typeof setTimeout>
241
+
242
+ function handle_mu_change(new_mu: number) {
243
+ mu = new_mu
244
+ clearTimeout(recompute_timeout)
245
+ recompute_timeout = setTimeout(() => void recompute_fermi_surface(), 150)
246
+ on_mu_change?.(new_mu)
247
+ }
248
+
249
+ function handle_interpolation_change(new_factor: number) {
250
+ interpolation_factor = new_factor
251
+ clearTimeout(recompute_timeout)
252
+ recompute_timeout = setTimeout(() => void recompute_fermi_surface(), 150)
253
+ }
254
+
255
+ // Export Fermi surface to various formats
256
+ async function handle_export(format: `stl` | `obj` | `gltf`) {
114
257
  if (!scene) {
115
- console.error(`No scene available for export`);
116
- return;
258
+ console.error(`No scene available for export`)
259
+ return
117
260
  }
118
261
  try {
119
- const { export_scene } = await import(`./export`);
120
- await export_scene(scene, format, current_filename || `fermi-surface`);
262
+ const { export_scene } = await import(`./export`)
263
+ await export_scene(scene, format, current_filename || `fermi-surface`)
264
+ } catch (err) {
265
+ console.error(`Export failed:`, err)
266
+ error_msg = `Export failed: ${err instanceof Error ? err.message : err}`
121
267
  }
122
- catch (err) {
123
- console.error(`Export failed:`, err);
124
- error_msg = `Export failed: ${err instanceof Error ? err.message : err}`;
125
- }
126
- }
127
- // Compute BZ when structure or fermi_data changes
128
- $effect(() => {
268
+ }
269
+
270
+ // Compute BZ when structure or fermi_data changes
271
+ $effect(() => {
129
272
  // Get k_lattice from available sources (priority order)
130
273
  const k_lattice = fermi_data?.k_lattice ??
131
- band_data?.k_lattice ??
132
- (structure?.lattice?.matrix
133
- ? reciprocal_lattice(structure.lattice.matrix)
134
- : null);
274
+ band_data?.k_lattice ??
275
+ (structure?.lattice?.matrix
276
+ ? reciprocal_lattice(structure.lattice.matrix)
277
+ : null)
278
+
135
279
  if (!k_lattice) {
136
- bz_data = undefined;
137
- return;
280
+ bz_data = undefined
281
+ return
138
282
  }
283
+
139
284
  try {
140
- bz_data = compute_brillouin_zone(k_lattice, 1);
285
+ bz_data = compute_brillouin_zone(k_lattice, 1)
286
+ } catch (err) {
287
+ const msg = err instanceof Error ? err.message : String(err)
288
+ console.warn(`BZ computation failed:`, msg)
289
+ bz_data = undefined
290
+ // Only report error for structure-derived lattice (user-provided data)
291
+ if (structure?.lattice?.matrix) {
292
+ const err_msg = `BZ computation failed: ${msg}`
293
+ error_msg = err_msg
294
+ untrack(() => on_error?.({ error_msg: err_msg }))
295
+ }
141
296
  }
142
- catch (err) {
143
- const msg = err instanceof Error ? err.message : String(err);
144
- console.warn(`BZ computation failed:`, msg);
145
- bz_data = undefined;
146
- // Only report error for structure-derived lattice (user-provided data)
147
- if (structure?.lattice?.matrix) {
148
- const err_msg = `BZ computation failed: ${msg}`;
149
- error_msg = err_msg;
150
- untrack(() => on_error?.({ error_msg: err_msg }));
151
- }
152
- }
153
- });
154
- // Auto-enable BZ tiling when irreducible data is detected
155
- $effect(() => {
297
+ })
298
+
299
+ // Auto-enable BZ tiling when irreducible data is detected
300
+ $effect(() => {
156
301
  if (fermi_data && detect_irreducible_bz(fermi_data)) {
157
- tile_bz = true;
302
+ tile_bz = true
158
303
  }
159
- });
160
- // Load from URL (with race condition protection for rapid URL changes)
161
- let load_id = 0;
162
- $effect(() => {
304
+ })
305
+
306
+ // Load from URL (with race condition protection for rapid URL changes)
307
+ let load_id = 0
308
+ $effect(() => {
163
309
  if (data_url && !fermi_data && !band_data) {
164
- const current_load_id = ++load_id;
165
- loading = true;
166
- error_msg = undefined;
167
- load_from_url(data_url, safe_parse)
168
- .catch((err) => {
169
- if (current_load_id !== load_id)
170
- return; // stale request
171
- error_msg = err instanceof Error ? err.message : String(err);
172
- on_error?.({ error_msg, filename: data_url });
310
+ const current_load_id = ++load_id
311
+ loading = true
312
+ error_msg = undefined
313
+ load_from_url(data_url, safe_parse)
314
+ .catch((err) => {
315
+ if (current_load_id !== load_id) return // stale request
316
+ error_msg = err instanceof Error ? err.message : String(err)
317
+ on_error?.({ error_msg, filename: data_url })
318
+ })
319
+ .finally(() => {
320
+ if (current_load_id === load_id) loading = false
173
321
  })
174
- .finally(() => {
175
- if (current_load_id === load_id)
176
- loading = false;
177
- });
178
322
  }
179
- });
180
- const handle_file_drop = create_file_drop_handler({
323
+ })
324
+
325
+ const handle_file_drop = create_file_drop_handler({
181
326
  allow: () => allow_file_drop,
182
327
  on_drop: async (content, filename) => {
183
- on_file_drop?.(filename);
184
- await safe_parse(content, filename);
328
+ on_file_drop?.(filename)
329
+ await safe_parse(content, filename)
185
330
  },
186
331
  on_error: (msg) => {
187
- error_msg = msg;
188
- on_error?.({ error_msg: msg });
332
+ error_msg = msg
333
+ on_error?.({ error_msg: msg })
189
334
  },
190
335
  set_loading: (val) => {
191
- loading = val;
192
- if (val)
193
- [error_msg, dragover] = [undefined, false];
336
+ loading = val
337
+ if (val) [error_msg, dragover] = [undefined, false]
194
338
  },
195
- });
196
- function handle_keydown(event) {
197
- const target = event.target;
198
- if ([`INPUT`, `TEXTAREA`].includes(target.tagName))
199
- return;
339
+ })
340
+
341
+ function handle_keydown(event: KeyboardEvent) {
342
+ const target = event.target as HTMLElement
343
+ if ([`INPUT`, `TEXTAREA`].includes(target.tagName)) return
200
344
  // Only handle shortcuts when component is focused/hovered or contains focus
201
- if (!wrapper?.contains(document.activeElement) && !hovered)
202
- return;
203
- if (event.key === `f` && fullscreen_toggle)
204
- toggle_fullscreen(wrapper);
205
- else if (event.key === `Escape`)
206
- controls_open = false;
207
- }
208
- $effect(() => {
209
- if (typeof window === `undefined`)
210
- return;
211
- const fs_el = document.fullscreenElement;
345
+ if (!wrapper?.contains(document.activeElement) && !hovered) return
346
+
347
+ if (event.key === `f` && fullscreen_toggle) toggle_fullscreen(wrapper)
348
+ else if (event.key === `Escape`) controls_open = false
349
+ }
350
+
351
+ $effect(() => {
352
+ if (typeof window === `undefined`) return
353
+ const fs_el = document.fullscreenElement
212
354
  if (fullscreen && fs_el !== wrapper && wrapper) {
213
- wrapper.requestFullscreen().catch((err) => {
214
- console.error(err);
215
- fullscreen = false;
216
- });
217
- }
218
- else if (!fullscreen && fs_el === wrapper)
219
- document.exitFullscreen();
220
- set_fullscreen_bg(wrapper, fullscreen, `--fermi-bg-fullscreen`);
221
- });
355
+ wrapper.requestFullscreen().catch((err) => {
356
+ console.error(err)
357
+ fullscreen = false
358
+ })
359
+ } else if (!fullscreen && fs_el === wrapper) document.exitFullscreen()
360
+ set_fullscreen_bg(wrapper, fullscreen, `--fermi-bg-fullscreen`)
361
+ })
222
362
  </script>
223
363
 
224
364
  <svelte:window onkeydown={handle_keydown} />
@@ -427,7 +567,8 @@ $effect(() => {
427
567
  pointer-events: auto;
428
568
  }
429
569
  /* Mode: hover - controls visible on component hover */
430
- .fermi-surface:hover section.control-buttons.hover-visible {
570
+ .fermi-surface:hover section.control-buttons.hover-visible,
571
+ .fermi-surface:focus-within section.control-buttons.hover-visible {
431
572
  opacity: 1;
432
573
  pointer-events: auto;
433
574
  }
@@ -78,6 +78,6 @@ type $$ComponentProps = {
78
78
  }]> | FermiTooltipConfig;
79
79
  on_hover?: (data: FermiHoverData | null) => void;
80
80
  } & HTMLAttributes<HTMLDivElement>;
81
- declare const FermiSurface: import("svelte").Component<$$ComponentProps, {}, "height" | "width" | "dragover" | "color_scale" | "controls_open" | "loading" | "fullscreen" | "hovered" | "camera_projection" | "wrapper" | "error_msg" | "surface_opacity" | "show_vectors" | "bz_data" | "mu" | "selected_bands" | "interpolation_factor" | "fermi_data" | "band_data" | "color_property" | "representation" | "show_bz" | "bz_opacity" | "tile_bz" | "clip_enabled" | "clip_axis" | "clip_position" | "clip_flip">;
81
+ declare const FermiSurface: import("svelte").Component<$$ComponentProps, {}, "height" | "width" | "dragover" | "fullscreen" | "hovered" | "controls_open" | "loading" | "camera_projection" | "color_scale" | "wrapper" | "error_msg" | "surface_opacity" | "show_vectors" | "bz_data" | "mu" | "selected_bands" | "interpolation_factor" | "fermi_data" | "band_data" | "color_property" | "representation" | "show_bz" | "bz_opacity" | "tile_bz" | "clip_enabled" | "clip_axis" | "clip_position" | "clip_flip">;
82
82
  type FermiSurface = ReturnType<typeof FermiSurface>;
83
83
  export default FermiSurface;