matterviz 0.3.0 → 0.3.2

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 (286) hide show
  1. package/dist/FilePicker.svelte +37 -20
  2. package/dist/Icon.svelte +2 -2
  3. package/dist/MillerIndexInput.svelte +60 -0
  4. package/dist/MillerIndexInput.svelte.d.ts +7 -0
  5. package/dist/app.css +38 -2
  6. package/dist/brillouin/BrillouinZone.svelte +20 -62
  7. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  8. package/dist/brillouin/BrillouinZoneExportPane.svelte +12 -20
  9. package/dist/brillouin/BrillouinZoneScene.svelte +2 -2
  10. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  11. package/dist/chempot-diagram/ChemPotDiagram.svelte +192 -0
  12. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
  13. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +677 -0
  14. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
  15. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2688 -0
  16. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
  17. package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -0
  18. package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
  19. package/dist/chempot-diagram/color.d.ts +10 -0
  20. package/dist/chempot-diagram/color.js +33 -0
  21. package/dist/chempot-diagram/compute.d.ts +38 -0
  22. package/dist/chempot-diagram/compute.js +650 -0
  23. package/dist/chempot-diagram/index.d.ts +5 -0
  24. package/dist/chempot-diagram/index.js +5 -0
  25. package/dist/chempot-diagram/pointer.d.ts +16 -0
  26. package/dist/chempot-diagram/pointer.js +40 -0
  27. package/dist/chempot-diagram/temperature.d.ts +15 -0
  28. package/dist/chempot-diagram/temperature.js +37 -0
  29. package/dist/chempot-diagram/types.d.ts +83 -0
  30. package/dist/chempot-diagram/types.js +27 -0
  31. package/dist/colors/index.d.ts +3 -1
  32. package/dist/colors/index.js +4 -0
  33. package/dist/composition/BarChart.svelte +13 -22
  34. package/dist/composition/BubbleChart.svelte +5 -3
  35. package/dist/composition/FormulaFilter.svelte +770 -90
  36. package/dist/composition/FormulaFilter.svelte.d.ts +37 -1
  37. package/dist/composition/PieChart.svelte +43 -18
  38. package/dist/composition/PieChart.svelte.d.ts +1 -1
  39. package/dist/constants.d.ts +1 -0
  40. package/dist/constants.js +2 -0
  41. package/dist/convex-hull/ConvexHull.svelte +14 -1
  42. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  43. package/dist/convex-hull/ConvexHull2D.svelte +14 -45
  44. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  45. package/dist/convex-hull/ConvexHull3D.svelte +396 -134
  46. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  47. package/dist/convex-hull/ConvexHull4D.svelte +93 -42
  48. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  49. package/dist/convex-hull/ConvexHullControls.svelte +94 -31
  50. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +4 -2
  51. package/dist/convex-hull/ConvexHullStats.svelte +697 -128
  52. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
  53. package/dist/convex-hull/ConvexHullTooltip.svelte +1 -0
  54. package/dist/convex-hull/GasPressureControls.svelte +72 -38
  55. package/dist/convex-hull/GasPressureControls.svelte.d.ts +2 -1
  56. package/dist/convex-hull/TemperatureSlider.svelte +46 -19
  57. package/dist/convex-hull/TemperatureSlider.svelte.d.ts +2 -1
  58. package/dist/convex-hull/demo-temperature.d.ts +6 -0
  59. package/dist/convex-hull/demo-temperature.js +36 -0
  60. package/dist/convex-hull/gas-thermodynamics.js +16 -5
  61. package/dist/convex-hull/helpers.d.ts +7 -1
  62. package/dist/convex-hull/helpers.js +45 -15
  63. package/dist/convex-hull/index.d.ts +15 -1
  64. package/dist/convex-hull/index.js +1 -0
  65. package/dist/convex-hull/thermodynamics.d.ts +8 -21
  66. package/dist/convex-hull/thermodynamics.js +106 -17
  67. package/dist/convex-hull/types.d.ts +7 -0
  68. package/dist/convex-hull/types.js +11 -0
  69. package/dist/coordination/CoordinationBarPlot.svelte +29 -46
  70. package/dist/element/BohrAtom.svelte +1 -1
  71. package/dist/element/data.js +2 -14
  72. package/dist/element/data.json.gz +0 -0
  73. package/dist/element/index.d.ts +1 -1
  74. package/dist/element/index.js +1 -0
  75. package/dist/element/types.d.ts +1 -0
  76. package/dist/fermi-surface/FermiSurface.svelte +21 -65
  77. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  78. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  79. package/dist/fermi-surface/FermiSurfaceScene.svelte +1 -1
  80. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  81. package/dist/fermi-surface/compute.js +1 -21
  82. package/dist/fermi-surface/marching-cubes.d.ts +2 -13
  83. package/dist/fermi-surface/marching-cubes.js +2 -519
  84. package/dist/fermi-surface/parse.js +17 -23
  85. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1273 -0
  86. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
  87. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +171 -0
  88. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +31 -0
  89. package/dist/heatmap-matrix/index.d.ts +53 -0
  90. package/dist/heatmap-matrix/index.js +100 -0
  91. package/dist/heatmap-matrix/shared.d.ts +2 -0
  92. package/dist/heatmap-matrix/shared.js +4 -0
  93. package/dist/icons.d.ts +119 -0
  94. package/dist/icons.js +119 -0
  95. package/dist/index.d.ts +6 -1
  96. package/dist/index.js +6 -1
  97. package/dist/io/export.js +15 -3
  98. package/dist/io/file-drop.d.ts +7 -0
  99. package/dist/io/file-drop.js +43 -0
  100. package/dist/io/index.d.ts +2 -2
  101. package/dist/io/index.js +2 -112
  102. package/dist/io/types.d.ts +1 -0
  103. package/dist/io/url-drop.d.ts +2 -0
  104. package/dist/io/url-drop.js +118 -0
  105. package/dist/isosurface/Isosurface.svelte +231 -0
  106. package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
  107. package/dist/isosurface/IsosurfaceControls.svelte +273 -0
  108. package/dist/isosurface/IsosurfaceControls.svelte.d.ts +9 -0
  109. package/dist/isosurface/index.d.ts +5 -0
  110. package/dist/isosurface/index.js +6 -0
  111. package/dist/isosurface/parse.d.ts +6 -0
  112. package/dist/isosurface/parse.js +548 -0
  113. package/dist/isosurface/slice.d.ts +11 -0
  114. package/dist/isosurface/slice.js +145 -0
  115. package/dist/isosurface/types.d.ts +55 -0
  116. package/dist/isosurface/types.js +178 -0
  117. package/dist/labels.d.ts +2 -1
  118. package/dist/labels.js +1 -0
  119. package/dist/layout/InfoTag.svelte +62 -62
  120. package/dist/layout/SubpageGrid.svelte +74 -0
  121. package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
  122. package/dist/layout/index.d.ts +1 -0
  123. package/dist/layout/index.js +1 -0
  124. package/dist/layout/json-tree/JsonNode.svelte +226 -53
  125. package/dist/layout/json-tree/JsonTree.svelte +425 -51
  126. package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
  127. package/dist/layout/json-tree/JsonValue.svelte +218 -97
  128. package/dist/layout/json-tree/types.d.ts +27 -2
  129. package/dist/layout/json-tree/utils.d.ts +14 -1
  130. package/dist/layout/json-tree/utils.js +254 -0
  131. package/dist/marching-cubes.d.ts +14 -0
  132. package/dist/marching-cubes.js +519 -0
  133. package/dist/math.d.ts +8 -0
  134. package/dist/math.js +374 -7
  135. package/dist/overlays/ContextMenu.svelte +3 -2
  136. package/dist/overlays/DraggablePane.svelte +163 -58
  137. package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
  138. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +232 -77
  139. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
  140. package/dist/phase-diagram/PhaseDiagramControls.svelte +32 -11
  141. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
  142. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +103 -0
  143. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
  144. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +102 -95
  145. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +7 -0
  146. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +100 -26
  147. package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
  148. package/dist/phase-diagram/index.d.ts +2 -0
  149. package/dist/phase-diagram/index.js +2 -0
  150. package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
  151. package/dist/phase-diagram/svg-to-diagram.js +865 -0
  152. package/dist/phase-diagram/types.d.ts +10 -0
  153. package/dist/phase-diagram/utils.d.ts +7 -4
  154. package/dist/phase-diagram/utils.js +149 -59
  155. package/dist/plot/AxisLabel.svelte +26 -0
  156. package/dist/plot/AxisLabel.svelte.d.ts +16 -0
  157. package/dist/plot/BarPlot.svelte +473 -228
  158. package/dist/plot/BarPlot.svelte.d.ts +3 -3
  159. package/dist/plot/BarPlotControls.svelte +3 -2
  160. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  161. package/dist/plot/ColorBar.svelte +54 -54
  162. package/dist/plot/ColorBar.svelte.d.ts +1 -1
  163. package/dist/plot/ElementScatter.svelte +4 -3
  164. package/dist/plot/FillArea.svelte +4 -1
  165. package/dist/plot/Histogram.svelte +320 -230
  166. package/dist/plot/Histogram.svelte.d.ts +2 -2
  167. package/dist/plot/HistogramControls.svelte +29 -10
  168. package/dist/plot/HistogramControls.svelte.d.ts +6 -2
  169. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +2 -2
  170. package/dist/plot/PlotControls.svelte +109 -27
  171. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  172. package/dist/plot/PlotLegend.svelte +1 -1
  173. package/dist/plot/PortalSelect.svelte +2 -1
  174. package/dist/plot/ReferenceLine.svelte +2 -1
  175. package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
  176. package/dist/plot/ReferencePlane.svelte +1 -3
  177. package/dist/plot/ScatterPlot.svelte +343 -209
  178. package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
  179. package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
  180. package/dist/plot/ScatterPlot3DControls.svelte +203 -250
  181. package/dist/plot/ScatterPlot3DScene.svelte +4 -7
  182. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
  183. package/dist/plot/ScatterPlotControls.svelte +95 -55
  184. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  185. package/dist/plot/ZeroLines.svelte +44 -0
  186. package/dist/plot/ZeroLines.svelte.d.ts +32 -0
  187. package/dist/plot/ZoomRect.svelte +21 -0
  188. package/dist/plot/ZoomRect.svelte.d.ts +8 -0
  189. package/dist/plot/axis-utils.d.ts +1 -1
  190. package/dist/plot/data-cleaning.js +1 -5
  191. package/dist/plot/index.d.ts +6 -2
  192. package/dist/plot/index.js +6 -2
  193. package/dist/plot/interactions.d.ts +8 -10
  194. package/dist/plot/interactions.js +10 -19
  195. package/dist/plot/layout.d.ts +7 -1
  196. package/dist/plot/layout.js +12 -4
  197. package/dist/plot/reference-line.d.ts +4 -21
  198. package/dist/plot/reference-line.js +7 -81
  199. package/dist/plot/types.d.ts +42 -17
  200. package/dist/plot/types.js +10 -0
  201. package/dist/plot/utils/label-placement.js +14 -11
  202. package/dist/plot/utils.d.ts +1 -0
  203. package/dist/plot/utils.js +14 -0
  204. package/dist/rdf/RdfPlot.svelte +55 -66
  205. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  206. package/dist/rdf/index.d.ts +1 -1
  207. package/dist/rdf/index.js +1 -1
  208. package/dist/settings.d.ts +5 -0
  209. package/dist/settings.js +37 -3
  210. package/dist/spectral/Bands.svelte +515 -143
  211. package/dist/spectral/Bands.svelte.d.ts +22 -2
  212. package/dist/spectral/helpers.d.ts +23 -1
  213. package/dist/spectral/helpers.js +65 -9
  214. package/dist/spectral/types.d.ts +2 -0
  215. package/dist/structure/AtomLegend.svelte +31 -10
  216. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  217. package/dist/structure/CellSelect.svelte +92 -22
  218. package/dist/structure/Lattice.svelte +2 -0
  219. package/dist/structure/Structure.svelte +716 -173
  220. package/dist/structure/Structure.svelte.d.ts +7 -2
  221. package/dist/structure/StructureControls.svelte +26 -14
  222. package/dist/structure/StructureControls.svelte.d.ts +5 -1
  223. package/dist/structure/StructureInfoPane.svelte +7 -1
  224. package/dist/structure/StructureScene.svelte +386 -95
  225. package/dist/structure/StructureScene.svelte.d.ts +15 -4
  226. package/dist/structure/atom-properties.d.ts +6 -2
  227. package/dist/structure/atom-properties.js +38 -25
  228. package/dist/structure/export.js +10 -7
  229. package/dist/structure/ferrox-wasm-types.d.ts +3 -2
  230. package/dist/structure/ferrox-wasm-types.js +0 -3
  231. package/dist/structure/ferrox-wasm.d.ts +3 -2
  232. package/dist/structure/ferrox-wasm.js +1 -2
  233. package/dist/structure/index.d.ts +7 -0
  234. package/dist/structure/index.js +22 -0
  235. package/dist/structure/parse.js +19 -16
  236. package/dist/structure/partial-occupancy.d.ts +25 -0
  237. package/dist/structure/partial-occupancy.js +102 -0
  238. package/dist/structure/validation.js +6 -3
  239. package/dist/symmetry/SymmetryStats.svelte +18 -4
  240. package/dist/symmetry/WyckoffTable.svelte +18 -10
  241. package/dist/symmetry/index.d.ts +7 -4
  242. package/dist/symmetry/index.js +83 -18
  243. package/dist/table/HeatmapTable.svelte +468 -69
  244. package/dist/table/HeatmapTable.svelte.d.ts +13 -1
  245. package/dist/table/ToggleMenu.svelte +291 -44
  246. package/dist/table/ToggleMenu.svelte.d.ts +4 -1
  247. package/dist/table/index.d.ts +3 -0
  248. package/dist/tooltip/index.d.ts +1 -1
  249. package/dist/tooltip/index.js +1 -0
  250. package/dist/trajectory/Trajectory.svelte +147 -145
  251. package/dist/trajectory/TrajectoryExportPane.svelte +13 -9
  252. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
  253. package/dist/trajectory/constants.d.ts +6 -0
  254. package/dist/trajectory/constants.js +7 -0
  255. package/dist/trajectory/extract.js +3 -5
  256. package/dist/trajectory/format-detect.d.ts +9 -0
  257. package/dist/trajectory/format-detect.js +76 -0
  258. package/dist/trajectory/frame-reader.d.ts +17 -0
  259. package/dist/trajectory/frame-reader.js +339 -0
  260. package/dist/trajectory/helpers.d.ts +15 -0
  261. package/dist/trajectory/helpers.js +187 -0
  262. package/dist/trajectory/index.d.ts +1 -0
  263. package/dist/trajectory/index.js +11 -4
  264. package/dist/trajectory/parse/ase.d.ts +2 -0
  265. package/dist/trajectory/parse/ase.js +76 -0
  266. package/dist/trajectory/parse/hdf5.d.ts +2 -0
  267. package/dist/trajectory/parse/hdf5.js +121 -0
  268. package/dist/trajectory/parse/index.d.ts +12 -0
  269. package/dist/trajectory/parse/index.js +304 -0
  270. package/dist/trajectory/parse/lammps.d.ts +5 -0
  271. package/dist/trajectory/parse/lammps.js +169 -0
  272. package/dist/trajectory/parse/vasp.d.ts +2 -0
  273. package/dist/trajectory/parse/vasp.js +65 -0
  274. package/dist/trajectory/parse/xyz.d.ts +2 -0
  275. package/dist/trajectory/parse/xyz.js +109 -0
  276. package/dist/trajectory/types.d.ts +11 -0
  277. package/dist/trajectory/types.js +1 -0
  278. package/dist/utils.d.ts +2 -0
  279. package/dist/utils.js +4 -0
  280. package/dist/xrd/XrdPlot.svelte +6 -4
  281. package/dist/xrd/calc-xrd.js +0 -1
  282. package/package.json +33 -23
  283. package/readme.md +4 -4
  284. package/dist/trajectory/parse.d.ts +0 -42
  285. package/dist/trajectory/parse.js +0 -1267
  286. /package/dist/element/{data.json.d.ts → data.json.gz.d.ts} +0 -0
@@ -3,6 +3,6 @@ import type { ConvexHullEntry, HighlightStyle } from './types';
3
3
  type $$ComponentProps = BaseConvexHullProps<ConvexHullEntry> & Hull3DProps & {
4
4
  highlight_style?: HighlightStyle;
5
5
  };
6
- declare const ConvexHull3D: import("svelte").Component<$$ComponentProps, {}, "temperature" | "fullscreen" | "show_hull_faces" | "hull_face_opacity" | "color_mode" | "color_scale" | "show_stable" | "show_unstable" | "show_stable_labels" | "show_unstable_labels" | "max_hull_dist_show_phases" | "max_hull_dist_show_labels" | "info_pane_open" | "legend_pane_open" | "wrapper" | "energy_source_mode" | "stable_entries" | "unstable_entries" | "phase_stats" | "highlighted_entries" | "selected_entry" | "gas_pressures">;
6
+ declare const ConvexHull3D: import("svelte").Component<$$ComponentProps, {}, "temperature" | "color_scale" | "fullscreen" | "show_hull_faces" | "hull_face_opacity" | "hull_face_color_mode" | "color_mode" | "show_stable" | "show_unstable" | "show_stable_labels" | "show_unstable_labels" | "max_hull_dist_show_phases" | "max_hull_dist_show_labels" | "info_pane_open" | "legend_pane_open" | "wrapper" | "energy_source_mode" | "stable_entries" | "unstable_entries" | "phase_stats" | "highlighted_entries" | "selected_entry" | "gas_pressures">;
7
7
  type ConvexHull3D = ReturnType<typeof ConvexHull3D>;
8
8
  export default ConvexHull3D;
@@ -1,6 +1,6 @@
1
- <script lang="ts">import { is_dark_mode, watch_dark_mode } from '../colors';
1
+ <script lang="ts">import { add_alpha, is_dark_mode, PLOT_COLORS, vesta_hex, watch_dark_mode, } from '../colors';
2
2
  import { normalize_show_controls } from '../controls';
3
- import { ClickFeedback, DragOverlay } from '../feedback';
3
+ import { ClickFeedback, DragOverlay, Spinner } from '../feedback';
4
4
  import Icon from '../Icon.svelte';
5
5
  import { set_fullscreen_bg, setup_fullscreen_effect, toggle_fullscreen, } from '../layout';
6
6
  import { ColorBar, PlotTooltip } from '../plot';
@@ -15,7 +15,7 @@ import { CONVEX_HULL_STYLE, default_controls, default_hull_config } from './inde
15
15
  import StructurePopup from './StructurePopup.svelte';
16
16
  import TemperatureSlider from './TemperatureSlider.svelte';
17
17
  import * as thermo from './thermodynamics';
18
- let { entries = [], controls = {}, config = {}, on_point_click, on_point_hover, fullscreen = $bindable(DEFAULTS.convex_hull.quaternary.fullscreen), enable_fullscreen = true, enable_info_pane = true, wrapper = $bindable(), label_threshold = 50, show_stable = $bindable(DEFAULTS.convex_hull.quaternary.show_stable), show_unstable = $bindable(DEFAULTS.convex_hull.quaternary.show_unstable), show_hull_faces = $bindable(DEFAULTS.convex_hull.quaternary.show_hull_faces), hull_face_opacity = $bindable(DEFAULTS.convex_hull.quaternary.hull_face_opacity), color_mode = $bindable(DEFAULTS.convex_hull.quaternary.color_mode), color_scale = $bindable(DEFAULTS.convex_hull.quaternary.color_scale), info_pane_open = $bindable(DEFAULTS.convex_hull.quaternary.info_pane_open), legend_pane_open = $bindable(DEFAULTS.convex_hull.quaternary.legend_pane_open), max_hull_dist_show_phases = $bindable(DEFAULTS.convex_hull.quaternary.max_hull_dist_show_phases), max_hull_dist_show_labels = $bindable(DEFAULTS.convex_hull.quaternary.max_hull_dist_show_labels), show_stable_labels = $bindable(DEFAULTS.convex_hull.quaternary.show_stable_labels), show_unstable_labels = $bindable(DEFAULTS.convex_hull.quaternary.show_unstable_labels), on_file_drop, enable_click_selection = true, enable_structure_preview = true, energy_source_mode = $bindable(`precomputed`), phase_stats = $bindable(null), stable_entries = $bindable([]), unstable_entries = $bindable([]), highlighted_entries = $bindable([]), highlight_style = {}, selected_entry = $bindable(null), temperature = $bindable(), interpolate_temperature = true, max_interpolation_gap = 500, gas_config, gas_pressures = $bindable({}), children, tooltip, ...rest } = $props();
18
+ let { entries = [], controls = {}, config = {}, on_point_click, on_point_hover, fullscreen = $bindable(DEFAULTS.convex_hull.quaternary.fullscreen), enable_fullscreen = true, enable_info_pane = true, wrapper = $bindable(), label_threshold = 50, show_stable = $bindable(DEFAULTS.convex_hull.quaternary.show_stable), show_unstable = $bindable(DEFAULTS.convex_hull.quaternary.show_unstable), show_hull_faces = $bindable(DEFAULTS.convex_hull.quaternary.show_hull_faces), hull_face_opacity = $bindable(DEFAULTS.convex_hull.quaternary.hull_face_opacity), hull_face_color_mode = $bindable(DEFAULTS.convex_hull.quaternary.hull_face_color_mode), element_colors = vesta_hex, color_mode = $bindable(DEFAULTS.convex_hull.quaternary.color_mode), color_scale = $bindable(DEFAULTS.convex_hull.quaternary.color_scale), info_pane_open = $bindable(DEFAULTS.convex_hull.quaternary.info_pane_open), legend_pane_open = $bindable(DEFAULTS.convex_hull.quaternary.legend_pane_open), max_hull_dist_show_phases = $bindable(DEFAULTS.convex_hull.quaternary.max_hull_dist_show_phases), max_hull_dist_show_labels = $bindable(DEFAULTS.convex_hull.quaternary.max_hull_dist_show_labels), show_stable_labels = $bindable(DEFAULTS.convex_hull.quaternary.show_stable_labels), show_unstable_labels = $bindable(DEFAULTS.convex_hull.quaternary.show_unstable_labels), on_file_drop, enable_click_selection = true, enable_structure_preview = true, energy_source_mode = $bindable(`precomputed`), phase_stats = $bindable(null), stable_entries = $bindable([]), unstable_entries = $bindable([]), highlighted_entries = $bindable([]), highlight_style = {}, selected_entry = $bindable(null), temperature = $bindable(), interpolate_temperature = true, max_interpolation_gap = 500, gas_config, gas_pressures = $bindable({}), children, tooltip, ...rest } = $props();
19
19
  const merged_controls = $derived({ ...default_controls, ...controls });
20
20
  const controls_config = $derived(normalize_show_controls(merged_controls.show));
21
21
  const merged_config = $derived({
@@ -80,10 +80,9 @@ const hull_4d = $derived.by(() => {
80
80
  return { x, y, z, w: ent.e_form_per_atom };
81
81
  })
82
82
  .filter((p) => [p.x, p.y, p.z, p.w].every(Number.isFinite));
83
- const valid_points = points_4d;
84
- if (valid_points.length < 5)
83
+ if (points_4d.length < 5)
85
84
  return []; // Need at least 5 points for 4D hull
86
- return thermo.compute_lower_hull_4d(valid_points);
85
+ return thermo.compute_lower_hull_4d(points_4d);
87
86
  }
88
87
  catch (error) {
89
88
  console.error(`Error computing 4D hull:`, error);
@@ -208,7 +207,7 @@ $effect(() => {
208
207
  $effect(() => {
209
208
  // deno-fmt-ignore
210
209
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions
211
- [show_hull_faces, color_mode, color_scale, camera.rotation_x, camera.rotation_y, camera.zoom, camera.center_x, camera.center_y, plot_entries, hull_face_color, hull_face_opacity, text_color, elements];
210
+ [show_hull_faces, color_mode, color_scale, camera.rotation_x, camera.rotation_y, camera.zoom, camera.center_x, camera.center_y, plot_entries, hull_face_color, hull_face_opacity, hull_face_color_mode, element_colors, text_color, elements];
212
211
  render_once();
213
212
  });
214
213
  // Visibility toggles are now bindable props
@@ -255,6 +254,8 @@ function reset_all() {
255
254
  show_hull_faces = DEFAULTS.convex_hull.quaternary.show_hull_faces;
256
255
  hull_face_color = DEFAULTS.convex_hull.quaternary.hull_face_color;
257
256
  hull_face_opacity = DEFAULTS.convex_hull.quaternary.hull_face_opacity;
257
+ hull_face_color_mode = DEFAULTS.convex_hull.quaternary
258
+ .hull_face_color_mode;
258
259
  }
259
260
  const handle_keydown = (event) => {
260
261
  const target = event.target;
@@ -316,17 +317,6 @@ const energy_color_scale = $derived.by(() => helpers.get_energy_color_scale(colo
316
317
  $effect(() => {
317
318
  phase_stats = thermo.get_convex_hull_stats(plot_entries, elements, 4);
318
319
  });
319
- // Utility: convert hex color to rgba string with alpha
320
- function hex_to_rgba(hex, alpha) {
321
- const normalized = hex.trim();
322
- const match = normalized.match(/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i);
323
- if (!match)
324
- return `rgba(0,0,0,${alpha})`;
325
- const r = parseInt(match[1], 16);
326
- const g = parseInt(match[2], 16);
327
- const b = parseInt(match[3], 16);
328
- return `rgba(${r}, ${g}, ${b}, ${Math.max(0, Math.min(1, alpha))})`;
329
- }
330
320
  // 3D to 2D projection following Materials Project approach
331
321
  function project_3d_point(x, y, z) {
332
322
  if (!canvas)
@@ -476,6 +466,15 @@ function draw_convex_hull_faces() {
476
466
  const proj1 = project_3d_point(tet1.x, tet1.y, tet1.z);
477
467
  const proj2 = project_3d_point(tet2.x, tet2.y, tet2.z);
478
468
  const proj3 = project_3d_point(tet3.x, tet3.y, tet3.z);
469
+ // Compute tetrahedron centroid in barycentric coords (for dominant_element mode)
470
+ // All 4 faces share the same tetrahedron, so they get the same color for facet_index
471
+ const tet_centroid_bary = [
472
+ (p0.x + p1.x + p2.x + p3.x) / 4,
473
+ (p0.y + p1.y + p2.y + p3.y) / 4,
474
+ (p0.z + p1.z + p2.z + p3.z) / 4,
475
+ ((1 - p0.x - p0.y - p0.z) + (1 - p1.x - p1.y - p1.z) +
476
+ (1 - p2.x - p2.y - p2.z) + (1 - p3.x - p3.y - p3.z)) / 4,
477
+ ];
479
478
  // Each tetrahedron has 4 triangular faces
480
479
  const faces = [
481
480
  [proj0, proj1, proj2, (p0.w + p1.w + p2.w) / 3],
@@ -488,34 +487,68 @@ function draw_convex_hull_faces() {
488
487
  vertices: [v0, v1, v2],
489
488
  avg_depth: (v0.depth + v1.depth + v2.depth) / 3,
490
489
  avg_w,
490
+ tet_idx,
491
+ centroid_bary: tet_centroid_bary,
491
492
  });
492
493
  }
493
494
  }
494
495
  // Sort by depth (back to front)
495
496
  triangles.sort((a, b) => a.avg_depth - b.avg_depth);
496
- // Determine alpha based on formation energy (more negative = more opaque)
497
- // Scale by user-controlled opacity
498
- const formation_energies = plot_entries.map((e) => e.e_form_per_atom ?? 0);
499
- const min_fe = Math.min(0, ...formation_energies);
500
- const norm_alpha = (w) => {
501
- const t = Math.max(0, Math.min(1, (0 - w) / Math.max(1e-6, 0 - min_fe)));
502
- // Use user-controlled opacity as the maximum
503
- return t * hull_face_opacity;
497
+ // Lazy computation for uniform mode: normalize alpha by formation energy
498
+ let norm_alpha = null;
499
+ if (hull_face_color_mode === `uniform`) {
500
+ const formation_energies = plot_entries.map((e) => e.e_form_per_atom ?? 0);
501
+ const min_fe = Math.min(0, ...formation_energies);
502
+ norm_alpha = (w) => {
503
+ const t = Math.max(0, Math.min(1, (0 - w) / Math.max(1e-6, 0 - min_fe)));
504
+ return t * hull_face_opacity;
505
+ };
506
+ }
507
+ // Lazy computation for formation_energy mode
508
+ let energy_face_scale = null;
509
+ let min_w = 0;
510
+ if (hull_face_color_mode === `formation_energy`) {
511
+ const all_avg_w = triangles.map((tri) => tri.avg_w);
512
+ min_w = Math.min(...all_avg_w);
513
+ energy_face_scale = helpers.get_energy_color_scale(`energy`, color_scale, all_avg_w.map((w) => ({ e_above_hull: w - min_w })));
514
+ }
515
+ // Helper to get face color based on mode
516
+ const get_face_color = (tri) => {
517
+ if (hull_face_color_mode === `uniform`) {
518
+ return hull_face_color;
519
+ }
520
+ if (hull_face_color_mode === `formation_energy`) {
521
+ return energy_face_scale(tri.avg_w - min_w);
522
+ }
523
+ if (hull_face_color_mode === `dominant_element`) {
524
+ // Find element with highest fraction
525
+ const max_idx = tri.centroid_bary.indexOf(Math.max(...tri.centroid_bary));
526
+ const el = elements[max_idx];
527
+ return element_colors[el] ?? `#888888`;
528
+ }
529
+ if (hull_face_color_mode === `facet_index`) {
530
+ return PLOT_COLORS[tri.tet_idx % PLOT_COLORS.length];
531
+ }
532
+ return hull_face_color;
504
533
  };
505
534
  // Draw each triangle
506
535
  for (const tri of triangles) {
507
536
  const [v0, v1, v2] = tri.vertices;
508
- const alpha = norm_alpha(tri.avg_w);
537
+ // Uniform mode uses variable opacity; other modes use fixed opacity
538
+ const alpha = hull_face_color_mode === `uniform`
539
+ ? norm_alpha(tri.avg_w)
540
+ : hull_face_opacity;
541
+ const face_color = get_face_color(tri);
509
542
  ctx.save();
510
543
  ctx.beginPath();
511
544
  ctx.moveTo(v0.x, v0.y);
512
545
  ctx.lineTo(v1.x, v1.y);
513
546
  ctx.lineTo(v2.x, v2.y);
514
547
  ctx.closePath();
515
- ctx.fillStyle = hex_to_rgba(hull_face_color, alpha);
548
+ ctx.fillStyle = add_alpha(face_color, alpha);
516
549
  ctx.fill();
517
- // Edge lines more pronounced with higher opacity and thicker width
518
- ctx.strokeStyle = hex_to_rgba(hull_face_color, Math.min(0.4, hull_face_opacity * 4));
550
+ // Edge lines more pronounced with higher opacity
551
+ ctx.strokeStyle = add_alpha(face_color, Math.min(0.4, alpha * 4));
519
552
  ctx.lineWidth = 1;
520
553
  ctx.stroke();
521
554
  ctx.restore();
@@ -564,8 +597,7 @@ function draw_data_points() {
564
597
  (entry.e_above_hull ?? 0) <= max_hull_dist_show_labels));
565
598
  if (should_label) {
566
599
  ctx.fillStyle = text_color;
567
- const label = entry.name || entry.reduced_formula || entry.entry_id ||
568
- `Unknown`;
600
+ const label = helpers.get_entry_label(entry, elements);
569
601
  const font_size = Math.round(12 * canvas_dims.scale);
570
602
  ctx.font = `${font_size}px Arial`;
571
603
  ctx.textAlign = `center`;
@@ -584,11 +616,13 @@ function render_frame() {
584
616
  ctx.fillStyle = `transparent`; // Set background - use transparent to inherit from container
585
617
  ctx.fillRect(0, 0, display_width, display_height);
586
618
  if (elements.length !== 4) {
587
- ctx.fillStyle = text_color;
588
- ctx.font = `16px Arial`;
589
- ctx.textAlign = `center`;
590
- ctx.textBaseline = `middle`;
591
- ctx.fillText(`Quaternary convex hull requires exactly 4 elements (got ${pd_data.elements.length})`, display_width / 2, display_height / 2);
619
+ if (elements.length > 0) {
620
+ ctx.fillStyle = text_color;
621
+ ctx.font = `16px Arial`;
622
+ ctx.textAlign = `center`;
623
+ ctx.textBaseline = `middle`;
624
+ ctx.fillText(`Quaternary convex hull requires exactly 4 elements (got ${elements.length})`, display_width / 2, display_height / 2);
625
+ }
592
626
  return;
593
627
  }
594
628
  draw_structure_outline(); // Draw tetrahedron outline
@@ -598,6 +632,8 @@ function render_frame() {
598
632
  function handle_mouse_down(event) {
599
633
  is_dragging = true;
600
634
  drag_started = false;
635
+ hover_data = null;
636
+ on_point_hover?.(null);
601
637
  last_mouse = { x: event.clientX, y: event.clientY };
602
638
  }
603
639
  const handle_mouse_move = (event) => {
@@ -613,8 +649,8 @@ const handle_mouse_move = (event) => {
613
649
  camera.center_y += dy;
614
650
  }
615
651
  else {
616
- camera.rotation_y -= dx * 0.005;
617
- camera.rotation_x = Math.max(-Math.PI / 3, Math.min(Math.PI / 3, camera.rotation_x + dy * 0.005));
652
+ camera.rotation_y += dx * 0.005;
653
+ camera.rotation_x = Math.max(-Math.PI / 3, Math.min(Math.PI / 3, camera.rotation_x - dy * 0.005));
618
654
  }
619
655
  last_mouse = { x: event.clientX, y: event.clientY };
620
656
  };
@@ -623,6 +659,8 @@ const handle_wheel = (event) => {
623
659
  camera.zoom = Math.max(1.0, Math.min(15, camera.zoom * (event.deltaY > 0 ? 0.98 : 1.02)));
624
660
  };
625
661
  const handle_hover = (event) => {
662
+ if (is_dragging)
663
+ return;
626
664
  const entry = find_entry_at_mouse(event);
627
665
  hover_data = entry
628
666
  ? { entry, position: { x: event.clientX, y: event.clientY } }
@@ -759,6 +797,10 @@ let style = $derived(`--hull-stable-color:${merged_config.colors?.stable || `#00
759
797
  class:dragover={drag_over}
760
798
  style={`${style}; ${rest.style ?? ``}`}
761
799
  data-has-selection={selected_entry !== null}
800
+ data-has-hover={hover_data !== null}
801
+ data-is-dragging={is_dragging}
802
+ data-rotation-x={camera.rotation_x.toFixed(4)}
803
+ data-rotation-y={camera.rotation_y.toFixed(4)}
762
804
  bind:this={wrapper}
763
805
  role="application"
764
806
  tabindex="-1"
@@ -796,6 +838,13 @@ let style = $derived(`--hull-stable-color:${merged_config.colors?.stable || `#00
796
838
  onwheel={handle_wheel}
797
839
  ></canvas>
798
840
 
841
+ {#if entries.length === 0}
842
+ <Spinner
843
+ text="Loading data..."
844
+ style="position: absolute; inset: 0; display: flex; align-items: center; justify-content: center"
845
+ />
846
+ {/if}
847
+
799
848
  <!-- Energy above hull Color Bar -->
800
849
  {#if color_mode === `energy` && plot_entries.length > 0}
801
850
  {@const hull_distances = plot_entries
@@ -875,6 +924,8 @@ let style = $derived(`--hull-stable-color:${merged_config.colors?.stable || `#00
875
924
  on_hull_face_color_change={(value) => hull_face_color = value}
876
925
  {hull_face_opacity}
877
926
  on_hull_face_opacity_change={(value) => hull_face_opacity = value}
927
+ {hull_face_color_mode}
928
+ on_hull_face_color_mode_change={(value) => hull_face_color_mode = value}
878
929
  bind:energy_source_mode
879
930
  {has_precomputed_e_form}
880
931
  {can_compute_e_form}
@@ -990,7 +1041,7 @@ let style = $derived(`--hull-stable-color:${merged_config.colors?.stable || `#00
990
1041
  .control-buttons :global(.draggable-pane) {
991
1042
  z-index: 1001 !important;
992
1043
  }
993
- .control-buttons button {
1044
+ .control-buttons :global(button) {
994
1045
  background: transparent;
995
1046
  border: none;
996
1047
  padding: 4px;
@@ -999,9 +1050,9 @@ let style = $derived(`--hull-stable-color:${merged_config.colors?.stable || `#00
999
1050
  color: var(--text-color, currentColor);
1000
1051
  transition: background-color 0.2s;
1001
1052
  display: flex;
1002
- font-size: clamp(0.85em, 2cqmin, 2.5em);
1053
+ font-size: clamp(0.85em, 2cqmin, 1.3em);
1003
1054
  }
1004
- .control-buttons button:hover {
1055
+ .control-buttons :global(button):hover {
1005
1056
  background-color: color-mix(in srgb, currentColor 8%, transparent);
1006
1057
  }
1007
1058
  </style>
@@ -3,6 +3,6 @@ import type { ConvexHullEntry, HighlightStyle } from './types';
3
3
  type $$ComponentProps = BaseConvexHullProps<ConvexHullEntry> & Hull3DProps & {
4
4
  highlight_style?: HighlightStyle;
5
5
  };
6
- declare const ConvexHull4D: import("svelte").Component<$$ComponentProps, {}, "temperature" | "fullscreen" | "show_hull_faces" | "hull_face_opacity" | "color_mode" | "color_scale" | "show_stable" | "show_unstable" | "show_stable_labels" | "show_unstable_labels" | "max_hull_dist_show_phases" | "max_hull_dist_show_labels" | "info_pane_open" | "legend_pane_open" | "wrapper" | "energy_source_mode" | "stable_entries" | "unstable_entries" | "phase_stats" | "highlighted_entries" | "selected_entry" | "gas_pressures">;
6
+ declare const ConvexHull4D: import("svelte").Component<$$ComponentProps, {}, "temperature" | "color_scale" | "fullscreen" | "show_hull_faces" | "hull_face_opacity" | "hull_face_color_mode" | "color_mode" | "show_stable" | "show_unstable" | "show_stable_labels" | "show_unstable_labels" | "max_hull_dist_show_phases" | "max_hull_dist_show_labels" | "info_pane_open" | "legend_pane_open" | "wrapper" | "energy_source_mode" | "stable_entries" | "unstable_entries" | "phase_stats" | "highlighted_entries" | "selected_entry" | "gas_pressures">;
7
7
  type ConvexHull4D = ReturnType<typeof ConvexHull4D>;
8
8
  export default ConvexHull4D;
@@ -2,7 +2,27 @@
2
2
  import DraggablePane from '../overlays/DraggablePane.svelte';
3
3
  import { ColorScaleSelect } from '../plot';
4
4
  import { tooltip } from 'svelte-multiselect';
5
- let { color_mode = $bindable(`stability`), color_scale = $bindable(`interpolateViridis`), show_stable = $bindable(true), show_unstable = $bindable(true), show_stable_labels = $bindable(true), show_unstable_labels = $bindable(false), show_hull_faces = undefined, on_hull_faces_change, hull_face_color = `#0072B2`, on_hull_face_color_change, hull_face_opacity = $bindable(0.03), on_hull_face_opacity_change, max_hull_dist_show_phases = $bindable(0), max_hull_dist_show_labels = $bindable(0.1), max_hull_dist_in_data = 0.5, energy_source_mode = $bindable(`precomputed`), has_precomputed_hull = false, can_compute_hull = false, has_precomputed_e_form = false, can_compute_e_form = false, stable_entries, unstable_entries, camera, merged_controls, controls_open = $bindable(false), toggle_props = {}, pane_props = {}, ...rest } = $props();
5
+ import { HULL_FACE_COLOR_MODES } from './types';
6
+ // Face color mode display labels and tooltips
7
+ const FACE_COLOR_MODES = {
8
+ uniform: { label: `Uniform`, tip: `Single uniform color for all faces` },
9
+ formation_energy: {
10
+ label: `Energy`,
11
+ tip: `Color by average formation energy of face vertices`,
12
+ },
13
+ dominant_element: {
14
+ label: `Element`,
15
+ tip: `Color by element with highest concentration at face centroid`,
16
+ },
17
+ facet_index: { label: `Index`, tip: `Distinct categorical color per facet` },
18
+ };
19
+ let { color_mode = $bindable(`stability`), color_scale = $bindable(`interpolateViridis`), show_stable = $bindable(true), show_unstable = $bindable(true), show_stable_labels = $bindable(true), show_unstable_labels = $bindable(false), show_hull_faces = undefined, on_hull_faces_change, hull_face_color = `#0072B2`, on_hull_face_color_change, hull_face_opacity = $bindable(0.03), on_hull_face_opacity_change, hull_face_color_mode = `uniform`, on_hull_face_color_mode_change, max_hull_dist_show_phases = $bindable(0), max_hull_dist_show_labels = $bindable(0.1), max_hull_dist_in_data = 0.5, energy_source_mode = $bindable(`precomputed`), has_precomputed_hull = false, can_compute_hull = false, has_precomputed_e_form = false, can_compute_e_form = false, stable_entries, unstable_entries, camera, merged_controls, controls_open = $bindable(false), toggle_props = {}, pane_props = {}, ...rest } = $props();
20
+ // Focus the multiselect input next to the "Color scale" label
21
+ function focus_multiselect(evt) {
22
+ ;
23
+ evt.currentTarget.nextElementSibling
24
+ ?.querySelector(`input`)?.focus();
25
+ }
6
26
  </script>
7
27
 
8
28
  <DraggablePane
@@ -10,10 +30,7 @@ let { color_mode = $bindable(`stability`), color_scale = $bindable(`interpolateV
10
30
  pane_props={{
11
31
  ...pane_props,
12
32
  class: `convex-hull-controls-pane ${pane_props?.class ?? ``}`,
13
- style:
14
- `--pane-min-height: 280px; --pane-max-height: max(350px, calc(100cqh - 40px)); ${
15
- pane_props?.style ?? ``
16
- }`,
33
+ style: `${pane_props?.style ?? ``}`,
17
34
  }}
18
35
  toggle_props={{
19
36
  title: controls_open ? `` : `Convex hull controls`,
@@ -24,7 +41,7 @@ let { color_mode = $bindable(`stability`), color_scale = $bindable(`interpolateV
24
41
  open_icon="Cross"
25
42
  {...rest}
26
43
  >
27
- <h4 style="margin: 0">
44
+ <h4>
28
45
  {@html merged_controls.title || `Convex Hull Controls`}
29
46
  </h4>
30
47
 
@@ -89,7 +106,7 @@ let { color_mode = $bindable(`stability`), color_scale = $bindable(`interpolateV
89
106
  bind:value={max_hull_dist_show_phases}
90
107
  class="threshold-input"
91
108
  />
92
- <span style="white-space: nowrap; font-size: 0.85em">eV/atom</span>
109
+ <span style="white-space: nowrap">eV/atom</span>
93
110
  <input
94
111
  type="range"
95
112
  min="0"
@@ -141,8 +158,17 @@ let { color_mode = $bindable(`stability`), color_scale = $bindable(`interpolateV
141
158
  </div>
142
159
  {:else}
143
160
  <!-- Color scale selector -->
144
- <div style="display: grid; gap: 8px; grid-template-columns: auto 1fr">
145
- <span {@attach tooltip({ content: `Choose energy colormap` })}>Color scale</span>
161
+ <div class="color-scale-row">
162
+ <span
163
+ {@attach tooltip({ content: `Choose energy colormap` })}
164
+ onclick={focus_multiselect}
165
+ onkeydown={(evt) => {
166
+ if (evt.key === `Enter` || evt.key === ` `) focus_multiselect(evt)
167
+ }}
168
+ role="button"
169
+ tabindex="0"
170
+ style="cursor: pointer"
171
+ >Color scale</span>
146
172
  <ColorScaleSelect
147
173
  bind:value={color_scale}
148
174
  selected={[color_scale]}
@@ -187,9 +213,8 @@ let { color_mode = $bindable(`stability`), color_scale = $bindable(`interpolateV
187
213
  >
188
214
  <span class="control-label">Label threshold</span>
189
215
  <label style="display: flex; align-items: center; gap: 4px; flex: 1">
190
- <span style="white-space: nowrap; font-size: 0.85em">{
191
- max_hull_dist_show_labels.toFixed(2)
192
- } eV/atom</span>
216
+ <span style="white-space: nowrap">{max_hull_dist_show_labels.toFixed(2)}
217
+ eV/atom</span>
193
218
  <input
194
219
  type="range"
195
220
  min="0"
@@ -216,13 +241,15 @@ let { color_mode = $bindable(`stability`), color_scale = $bindable(`interpolateV
216
241
  <span>Show</span>
217
242
  </label>
218
243
  <div style="display: flex; gap: 6px; align-items: center; flex: 1">
219
- <input
220
- type="color"
221
- value={hull_face_color}
222
- oninput={(e) => on_hull_face_color_change?.((e.target as HTMLInputElement).value)}
223
- {@attach tooltip({ content: `Set hull face color` })}
224
- style="width: 40px; height: 28px"
225
- />
244
+ {#if hull_face_color_mode === `uniform`}
245
+ <input
246
+ type="color"
247
+ value={hull_face_color}
248
+ oninput={(e) => on_hull_face_color_change?.((e.target as HTMLInputElement).value)}
249
+ {@attach tooltip({ content: `Set hull face color` })}
250
+ style="width: 40px; height: 28px"
251
+ />
252
+ {/if}
226
253
  <input
227
254
  type="range"
228
255
  min="0"
@@ -235,11 +262,27 @@ let { color_mode = $bindable(`stability`), color_scale = $bindable(`interpolateV
235
262
  class="threshold-slider"
236
263
  style="flex: 1; min-width: 80px"
237
264
  />
238
- <span style="font-size: 0.75em; min-width: 2em; text-align: right">{
265
+ <span style="font-size: 0.9em; min-width: 2em; text-align: right">{
239
266
  format_num(hull_face_opacity, `.1%`)
240
267
  }</span>
241
268
  </div>
242
269
  </div>
270
+
271
+ <!-- Face color mode selector -->
272
+ <div class="control-row">
273
+ <span class="control-label">Face color</span>
274
+ <div class="face-color-mode-buttons">
275
+ {#each HULL_FACE_COLOR_MODES as mode (mode)}
276
+ <button
277
+ class="toggle-btn face-mode-btn {hull_face_color_mode === mode ? `active` : ``}"
278
+ onclick={() => on_hull_face_color_mode_change?.(mode)}
279
+ {@attach tooltip({ content: FACE_COLOR_MODES[mode].tip })}
280
+ >
281
+ {FACE_COLOR_MODES[mode].label}
282
+ </button>
283
+ {/each}
284
+ </div>
285
+ </div>
243
286
  {/if}
244
287
 
245
288
  {#if camera}
@@ -326,27 +369,24 @@ let { color_mode = $bindable(`stability`), color_scale = $bindable(`interpolateV
326
369
  </DraggablePane>
327
370
 
328
371
  <style>
372
+ :global(.convex-hull-controls-pane) {
373
+ --pane-max-height: max(350px, calc(100cqh - 40px));
374
+ --pane-padding: 1ex;
375
+ --pane-gap: 0;
376
+ font-size: 0.85em;
377
+ pointer-events: auto;
378
+ }
329
379
  .control-row {
330
380
  display: flex;
331
381
  align-items: center;
332
382
  gap: 8px;
333
- margin-bottom: 12px;
334
- }
335
- /* Remove bottom margin from last element to prevent blank scrollable space */
336
- :global(.convex-hull-controls-pane > :last-child) {
337
- margin-bottom: 0;
383
+ margin-top: 12px;
338
384
  }
339
385
  .control-label {
340
386
  font-weight: 500;
341
387
  min-width: 80px;
342
388
  }
343
- .color-mode-toggle {
344
- display: flex;
345
- gap: 4px;
346
- flex: 1;
347
- }
348
389
  button {
349
- flex: 1;
350
390
  border: 1px solid var(--border-color, rgba(0, 0, 0, 0.2));
351
391
  }
352
392
  .toggle-btn.active, .toggle-btn:hover.active {
@@ -389,8 +429,31 @@ let { color_mode = $bindable(`stability`), color_scale = $bindable(`interpolateV
389
429
  display: flex;
390
430
  gap: 12px;
391
431
  flex: 1;
432
+ margin-top: 12px;
392
433
  }
393
434
  .threshold-input {
394
435
  border: 1px solid var(--border-color, rgba(0, 0, 0, 0.2));
395
436
  }
437
+ .face-color-mode-buttons {
438
+ display: flex;
439
+ gap: 4px;
440
+ flex: 1;
441
+ flex-wrap: wrap;
442
+ }
443
+ .face-mode-btn {
444
+ padding: 2px 6px;
445
+ min-width: auto;
446
+ flex: 0 1 auto;
447
+ }
448
+ .color-scale-row {
449
+ display: grid;
450
+ gap: 8px;
451
+ grid-template-columns: auto 1fr;
452
+ align-items: center;
453
+ margin-top: 12px;
454
+ }
455
+ .color-scale-row :global(.multiselect) {
456
+ font-size: 0.85em;
457
+ --sms-min-height: 24px;
458
+ }
396
459
  </style>
@@ -2,7 +2,7 @@ import type { D3InterpolateName } from '../colors';
2
2
  import DraggablePane from '../overlays/DraggablePane.svelte';
3
3
  import type { ComponentProps } from 'svelte';
4
4
  import type { HTMLAttributes } from 'svelte/elements';
5
- import type { ConvexHullControlsType, ConvexHullEntry } from './types';
5
+ import type { ConvexHullControlsType, ConvexHullEntry, HullFaceColorMode } from './types';
6
6
  interface CameraState {
7
7
  elevation?: number;
8
8
  azimuth?: number;
@@ -25,6 +25,8 @@ type $$ComponentProps = Omit<HTMLAttributes<HTMLDivElement>, `onclose`> & {
25
25
  on_hull_face_color_change?: (value: string) => void;
26
26
  hull_face_opacity?: number;
27
27
  on_hull_face_opacity_change?: (value: number) => void;
28
+ hull_face_color_mode?: HullFaceColorMode;
29
+ on_hull_face_color_mode_change?: (value: HullFaceColorMode) => void;
28
30
  energy_source_mode?: `precomputed` | `on-the-fly`;
29
31
  has_precomputed_hull?: boolean;
30
32
  can_compute_hull?: boolean;
@@ -41,6 +43,6 @@ type $$ComponentProps = Omit<HTMLAttributes<HTMLDivElement>, `onclose`> & {
41
43
  toggle_props?: ComponentProps<typeof DraggablePane>[`toggle_props`];
42
44
  pane_props?: ComponentProps<typeof DraggablePane>[`pane_props`];
43
45
  };
44
- declare const ConvexHullControls: import("svelte").Component<$$ComponentProps, {}, "controls_open" | "hull_face_opacity" | "color_mode" | "color_scale" | "show_stable" | "show_unstable" | "show_stable_labels" | "show_unstable_labels" | "max_hull_dist_show_phases" | "max_hull_dist_show_labels" | "energy_source_mode">;
46
+ declare const ConvexHullControls: import("svelte").Component<$$ComponentProps, {}, "color_scale" | "controls_open" | "hull_face_opacity" | "color_mode" | "show_stable" | "show_unstable" | "show_stable_labels" | "show_unstable_labels" | "max_hull_dist_show_phases" | "max_hull_dist_show_labels" | "energy_source_mode">;
45
47
  type ConvexHullControls = ReturnType<typeof ConvexHullControls>;
46
48
  export default ConvexHullControls;