matterviz 0.1.12 → 0.1.13

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 (195) hide show
  1. package/dist/ContextMenu.svelte +1 -1
  2. package/dist/ContextMenu.svelte.d.ts +3 -3
  3. package/dist/DraggablePane.svelte +10 -5
  4. package/dist/DraggablePane.svelte.d.ts +3 -3
  5. package/dist/FilePicker.svelte.d.ts +3 -3
  6. package/dist/Icon.svelte.d.ts +3 -3
  7. package/dist/Nav.svelte +76 -31
  8. package/dist/SettingsSection.svelte.d.ts +3 -3
  9. package/dist/Spinner.svelte +18 -29
  10. package/dist/Spinner.svelte.d.ts +3 -3
  11. package/dist/app.css +4 -0
  12. package/dist/bands/Bands.svelte +216 -0
  13. package/dist/bands/Bands.svelte.d.ts +16 -0
  14. package/dist/bands/BandsAndDos.svelte +26 -0
  15. package/dist/bands/BandsAndDos.svelte.d.ts +16 -0
  16. package/dist/bands/Dos.svelte +124 -0
  17. package/dist/bands/Dos.svelte.d.ts +18 -0
  18. package/dist/bands/helpers.d.ts +11 -0
  19. package/dist/bands/helpers.js +195 -0
  20. package/dist/bands/index.d.ts +5 -0
  21. package/dist/bands/index.js +6 -0
  22. package/dist/bands/types.d.ts +54 -0
  23. package/dist/bands/types.js +2 -0
  24. package/dist/brillouin/BrillouinZone.svelte +373 -0
  25. package/dist/brillouin/BrillouinZone.svelte.d.ts +57 -0
  26. package/dist/brillouin/BrillouinZoneControls.svelte +88 -0
  27. package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +14 -0
  28. package/dist/brillouin/BrillouinZoneExportPane.svelte +129 -0
  29. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +15 -0
  30. package/dist/brillouin/BrillouinZoneInfoPane.svelte +115 -0
  31. package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +13 -0
  32. package/dist/brillouin/BrillouinZoneScene.svelte +180 -0
  33. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +34 -0
  34. package/dist/brillouin/compute.d.ts +7 -0
  35. package/dist/brillouin/compute.js +215 -0
  36. package/dist/brillouin/index.d.ts +7 -0
  37. package/dist/brillouin/index.js +7 -0
  38. package/dist/brillouin/types.d.ts +23 -0
  39. package/dist/brillouin/types.js +1 -0
  40. package/dist/composition/BarChart.svelte.d.ts +3 -3
  41. package/dist/composition/BubbleChart.svelte +7 -6
  42. package/dist/composition/BubbleChart.svelte.d.ts +3 -3
  43. package/dist/composition/Composition.svelte.d.ts +3 -3
  44. package/dist/composition/PieChart.svelte +1 -1
  45. package/dist/composition/PieChart.svelte.d.ts +3 -3
  46. package/dist/composition/parse.d.ts +3 -3
  47. package/dist/coordination/CoordinationBarPlot.svelte +241 -0
  48. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +29 -0
  49. package/dist/coordination/calc-coordination.d.ts +15 -0
  50. package/dist/coordination/calc-coordination.js +66 -0
  51. package/dist/coordination/index.d.ts +8 -0
  52. package/dist/coordination/index.js +7 -0
  53. package/dist/element/BohrAtom.svelte.d.ts +3 -3
  54. package/dist/element/ElementHeading.svelte.d.ts +3 -3
  55. package/dist/element/ElementPhoto.svelte.d.ts +3 -3
  56. package/dist/element/ElementStats.svelte.d.ts +3 -3
  57. package/dist/element/ElementTile.svelte +1 -1
  58. package/dist/element/ElementTile.svelte.d.ts +4 -4
  59. package/dist/element/Nucleus.svelte.d.ts +3 -3
  60. package/dist/icons.d.ts +4 -0
  61. package/dist/icons.js +4 -0
  62. package/dist/index.d.ts +5 -1
  63. package/dist/index.js +5 -1
  64. package/dist/io/export.d.ts +1 -6
  65. package/dist/io/export.js +12 -12
  66. package/dist/labels.d.ts +19 -0
  67. package/dist/labels.js +59 -0
  68. package/dist/math.d.ts +7 -2
  69. package/dist/math.js +24 -12
  70. package/dist/periodic-table/PeriodicTable.svelte.d.ts +3 -3
  71. package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +3 -3
  72. package/dist/periodic-table/PropertySelect.svelte +1 -1
  73. package/dist/periodic-table/PropertySelect.svelte.d.ts +5 -4
  74. package/dist/periodic-table/TableInset.svelte.d.ts +3 -3
  75. package/dist/phase-diagram/PhaseDiagram2D.svelte +44 -107
  76. package/dist/phase-diagram/PhaseDiagram2D.svelte.d.ts +7 -27
  77. package/dist/phase-diagram/PhaseDiagram3D.svelte +67 -170
  78. package/dist/phase-diagram/PhaseDiagram3D.svelte.d.ts +7 -31
  79. package/dist/phase-diagram/PhaseDiagram4D.svelte +87 -145
  80. package/dist/phase-diagram/PhaseDiagram4D.svelte.d.ts +5 -28
  81. package/dist/phase-diagram/PhaseDiagramControls.svelte +9 -9
  82. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +6 -6
  83. package/dist/phase-diagram/PhaseDiagramInfoPane.svelte +4 -4
  84. package/dist/phase-diagram/PhaseDiagramInfoPane.svelte.d.ts +5 -5
  85. package/dist/phase-diagram/PhaseDiagramStats.svelte +9 -16
  86. package/dist/phase-diagram/PhaseDiagramStats.svelte.d.ts +3 -3
  87. package/dist/phase-diagram/StructurePopup.svelte.d.ts +3 -3
  88. package/dist/phase-diagram/barycentric-coords.js +13 -24
  89. package/dist/phase-diagram/helpers.d.ts +12 -14
  90. package/dist/phase-diagram/helpers.js +70 -23
  91. package/dist/phase-diagram/index.d.ts +58 -0
  92. package/dist/phase-diagram/index.js +44 -0
  93. package/dist/phase-diagram/thermodynamics.js +2 -3
  94. package/dist/phase-diagram/types.d.ts +3 -8
  95. package/dist/plot/BarPlot.svelte +474 -240
  96. package/dist/plot/BarPlot.svelte.d.ts +16 -37
  97. package/dist/plot/BarPlotControls.svelte +33 -201
  98. package/dist/plot/BarPlotControls.svelte.d.ts +11 -22
  99. package/dist/plot/ColorBar.svelte.d.ts +3 -3
  100. package/dist/plot/ColorScaleSelect.svelte +1 -1
  101. package/dist/plot/ColorScaleSelect.svelte.d.ts +3 -3
  102. package/dist/plot/ElementScatter.svelte +5 -5
  103. package/dist/plot/ElementScatter.svelte.d.ts +8 -8
  104. package/dist/plot/Histogram.svelte +318 -170
  105. package/dist/plot/Histogram.svelte.d.ts +21 -41
  106. package/dist/plot/HistogramControls.svelte +115 -347
  107. package/dist/plot/HistogramControls.svelte.d.ts +13 -28
  108. package/dist/plot/Line.svelte +1 -1
  109. package/dist/plot/Line.svelte.d.ts +4 -4
  110. package/dist/plot/PlotControls.svelte +280 -0
  111. package/dist/plot/PlotControls.svelte.d.ts +4 -0
  112. package/dist/plot/PlotLegend.svelte +9 -24
  113. package/dist/plot/PlotLegend.svelte.d.ts +3 -3
  114. package/dist/plot/ScatterPlot.svelte +536 -571
  115. package/dist/plot/ScatterPlot.svelte.d.ts +18 -90
  116. package/dist/plot/ScatterPlotControls.svelte +108 -316
  117. package/dist/plot/ScatterPlotControls.svelte.d.ts +11 -38
  118. package/dist/plot/ScatterPoint.svelte +1 -1
  119. package/dist/plot/ScatterPoint.svelte.d.ts +5 -5
  120. package/dist/plot/SpacegroupBarPlot.svelte +235 -0
  121. package/dist/plot/SpacegroupBarPlot.svelte.d.ts +9 -0
  122. package/dist/plot/data-transform.d.ts +2 -2
  123. package/dist/plot/data-transform.js +1 -5
  124. package/dist/plot/index.d.ts +12 -200
  125. package/dist/plot/index.js +14 -6
  126. package/dist/plot/layout.d.ts +10 -16
  127. package/dist/plot/layout.js +40 -25
  128. package/dist/plot/scales.d.ts +7 -8
  129. package/dist/plot/scales.js +22 -7
  130. package/dist/plot/types.d.ts +303 -0
  131. package/dist/plot/types.js +1 -0
  132. package/dist/rdf/RdfPlot.svelte +156 -0
  133. package/dist/rdf/RdfPlot.svelte.d.ts +20 -0
  134. package/dist/rdf/calc-rdf.d.ts +4 -0
  135. package/dist/rdf/calc-rdf.js +107 -0
  136. package/dist/rdf/index.d.ts +22 -0
  137. package/dist/rdf/index.js +2 -0
  138. package/dist/settings.d.ts +86 -75
  139. package/dist/settings.js +257 -155
  140. package/dist/structure/Bond.svelte +126 -110
  141. package/dist/structure/Bond.svelte.d.ts +7 -20
  142. package/dist/structure/CanvasTooltip.svelte.d.ts +4 -4
  143. package/dist/structure/Cylinder.svelte +29 -0
  144. package/dist/structure/Cylinder.svelte.d.ts +10 -0
  145. package/dist/structure/Lattice.svelte +1 -2
  146. package/dist/structure/Lattice.svelte.d.ts +3 -3
  147. package/dist/structure/Structure.svelte +23 -8
  148. package/dist/structure/Structure.svelte.d.ts +10 -7
  149. package/dist/structure/StructureControls.svelte +25 -134
  150. package/dist/structure/StructureControls.svelte.d.ts +4 -9
  151. package/dist/structure/StructureExportPane.svelte +188 -0
  152. package/dist/structure/StructureExportPane.svelte.d.ts +17 -0
  153. package/dist/structure/StructureInfoPane.svelte.d.ts +3 -3
  154. package/dist/structure/StructureLegend.svelte +91 -27
  155. package/dist/structure/StructureLegend.svelte.d.ts +5 -4
  156. package/dist/structure/StructureScene.svelte +93 -100
  157. package/dist/structure/StructureScene.svelte.d.ts +15 -12
  158. package/dist/structure/Vector.svelte +19 -25
  159. package/dist/structure/Vector.svelte.d.ts +3 -3
  160. package/dist/structure/bonding.d.ts +16 -14
  161. package/dist/structure/bonding.js +207 -216
  162. package/dist/structure/export.d.ts +3 -0
  163. package/dist/structure/export.js +120 -0
  164. package/dist/structure/index.d.ts +15 -1
  165. package/dist/structure/index.js +2 -0
  166. package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -3
  167. package/dist/symmetry/index.d.ts +1 -0
  168. package/dist/symmetry/index.js +1 -0
  169. package/dist/symmetry/spacegroups.d.ts +9 -0
  170. package/dist/symmetry/spacegroups.js +397 -0
  171. package/dist/theme/ThemeControl.svelte.d.ts +3 -3
  172. package/dist/theme/themes.js +2 -16
  173. package/dist/trajectory/Trajectory.svelte +52 -78
  174. package/dist/trajectory/Trajectory.svelte.d.ts +5 -5
  175. package/dist/trajectory/TrajectoryError.svelte.d.ts +3 -3
  176. package/dist/trajectory/TrajectoryExportPane.svelte +1 -1
  177. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +5 -5
  178. package/dist/trajectory/TrajectoryInfoPane.svelte +1 -1
  179. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -3
  180. package/dist/trajectory/extract.js +2 -1
  181. package/dist/trajectory/index.d.ts +1 -1
  182. package/dist/trajectory/index.js +1 -1
  183. package/dist/trajectory/parse.js +21 -14
  184. package/dist/utils.d.ts +1 -0
  185. package/dist/utils.js +17 -0
  186. package/dist/xrd/XrdPlot.svelte +14 -11
  187. package/dist/xrd/XrdPlot.svelte.d.ts +6 -5
  188. package/package.json +20 -12
  189. package/readme.md +1 -1
  190. package/dist/material/MaterialCard.svelte +0 -123
  191. package/dist/material/MaterialCard.svelte.d.ts +0 -9
  192. package/dist/material/index.d.ts +0 -1
  193. package/dist/material/index.js +0 -1
  194. package/dist/plot/formatting.d.ts +0 -7
  195. package/dist/plot/formatting.js +0 -53
@@ -1,114 +1,130 @@
1
- <script lang="ts">import { format_num } from '../labels';
2
- import { DEFAULTS } from '../settings';
3
- import { CanvasTooltip } from './';
4
- import { T } from '@threlte/core';
5
- import { interactivity } from '@threlte/extras';
6
- import { CanvasTexture, Euler, Quaternion, Vector3 } from 'three';
7
- let { from, to, color = DEFAULTS.structure.bond_color, thickness = DEFAULTS.structure.bond_thickness, offset = 0, from_color, to_color, bond_data, bonding_strategy, active_tooltip, hovered_bond_data, onbondhover, ontooltipchange, onpointerenter, onpointerleave, ...rest } = $props();
8
- interactivity();
9
- const from_vec = new Vector3(...from);
10
- const to_vec = new Vector3(...to);
11
- const { position, rotation, height } = calc_bond(from_vec, to_vec, offset, thickness);
12
- // Create gradient texture when both colors are provided
13
- let gradient_texture = $derived.by(() => {
14
- if (!from_color || !to_color)
15
- return null;
16
- // Create a canvas for the gradient
17
- const canvas = document.createElement(`canvas`);
18
- canvas.width = 1;
19
- canvas.height = 256;
20
- const ctx = canvas.getContext(`2d`);
21
- // Create linear gradient along Y axis (cylinder height)
22
- const gradient = ctx.createLinearGradient(0, 0, 0, 256);
23
- gradient.addColorStop(0, to_color);
24
- gradient.addColorStop(1, from_color);
25
- // Fill the canvas with the gradient
26
- ctx.fillStyle = gradient;
27
- ctx.fillRect(0, 0, 1, 256);
28
- // Create texture from canvas
29
- const texture = new CanvasTexture(canvas);
30
- texture.needsUpdate = true;
31
- return texture;
32
- });
33
- const pointer_handlers = {
34
- onpointerenter: (event) => {
35
- if (bond_data) {
36
- onbondhover?.(bond_data);
37
- ontooltipchange?.(`bond`);
38
- }
39
- onpointerenter?.(event);
40
- },
41
- onpointerleave: (event) => {
42
- onbondhover?.(null);
43
- ontooltipchange?.(null);
44
- onpointerleave?.(event);
45
- },
46
- };
47
- function calc_bond(from_vec, to_vec, offset, thickness) {
48
- // find the axis of the the box
49
- const delta_vec = to_vec.clone().sub(from_vec);
50
- // length of the bond
51
- const height = delta_vec.length();
52
- // calculate position
53
- let position;
54
- if (offset === 0) {
55
- position = from_vec.clone().add(delta_vec.multiplyScalar(0.5)).toArray();
1
+ <script lang="ts">import { T } from '@threlte/core';
2
+ import { Color, InstancedBufferAttribute, Matrix4, ShaderMaterial } from 'three';
3
+ let { group, saturation = 0.5, brightness = 0.6 } = $props();
4
+ let mesh = $state();
5
+ // Reusable buffers to avoid reallocation on every update
6
+ let colors_start = new Float32Array(0);
7
+ let colors_end = new Float32Array(0);
8
+ const vertex_shader = `
9
+ attribute vec3 instanceColorStart;
10
+ attribute vec3 instanceColorEnd;
11
+ varying vec3 vColorStart;
12
+ varying vec3 vColorEnd;
13
+ varying float vYPosition;
14
+ varying vec3 vNormal;
15
+
16
+ void main() {
17
+ // Colors from Three.js Color class are in linear RGB, pass them through
18
+ vColorStart = instanceColorStart;
19
+ vColorEnd = instanceColorEnd;
20
+ vYPosition = position.y;
21
+ mat3 normalMat = normalMatrix;
22
+ vNormal = normalize(normalMat * normal);
23
+ gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(position, 1.0);
24
+ }
25
+ `;
26
+ const fragment_shader = `
27
+ uniform float ambientIntensity;
28
+ uniform float directionalIntensity;
29
+ uniform float saturation;
30
+ uniform float brightness;
31
+ varying vec3 vColorStart;
32
+ varying vec3 vColorEnd;
33
+ varying float vYPosition;
34
+ varying vec3 vNormal;
35
+
36
+ // Linear to sRGB conversion (gamma correction)
37
+ vec3 linearTosRGB(vec3 linear) {
38
+ return vec3(
39
+ linear.r <= 0.0031308 ? linear.r * 12.92 : 1.055 * pow(linear.r, 1.0/2.4) - 0.055,
40
+ linear.g <= 0.0031308 ? linear.g * 12.92 : 1.055 * pow(linear.g, 1.0/2.4) - 0.055,
41
+ linear.b <= 0.0031308 ? linear.b * 12.92 : 1.055 * pow(linear.b, 1.0/2.4) - 0.055
42
+ );
56
43
  }
57
- else {
58
- const offset_vec = new Vector3()
59
- .crossVectors(delta_vec, new Vector3(1, 0, 0))
60
- .normalize();
61
- position = from_vec.clone().add(delta_vec.multiplyScalar(0.5)).add(offset_vec.multiplyScalar(offset * thickness * 2)).toArray();
44
+
45
+ // Desaturate and darken colors for bonds
46
+ vec3 desaturateBondColor(vec3 color) {
47
+ // Convert to grayscale
48
+ float gray = dot(color, vec3(0.299, 0.587, 0.114));
49
+ // Mix with gray (controlled by saturation) and darken (controlled by brightness)
50
+ return mix(vec3(gray), color, saturation) * brightness;
62
51
  }
63
- // calculate rotation
64
- const quaternion = new Quaternion().setFromUnitVectors(new Vector3(0, 1, 0), delta_vec.normalize());
65
- const rotation = new Euler().setFromQuaternion(quaternion).toArray();
66
- // return results
67
- return { height, position, rotation };
68
- }
69
- </script>
70
52
 
71
- {#if gradient_texture}
72
- <!-- Use gradient material for bonds with two colors -->
73
- <T.Mesh
74
- {...rest}
75
- {position}
76
- {rotation}
77
- scale={[thickness, height, thickness]}
78
- {...pointer_handlers}
79
- >
80
- <T.CylinderGeometry args={[thickness, thickness, 1, 16]} />
81
- <T.MeshStandardMaterial map={gradient_texture} />
82
- </T.Mesh>
83
- {:else}
84
- <!-- Fallback to solid color -->
85
- <T.Mesh
86
- {...rest}
87
- {position}
88
- {rotation}
89
- scale={[thickness, height, thickness]}
90
- {...pointer_handlers}
91
- >
92
- <T.CylinderGeometry args={[thickness, thickness, 1, 16]} />
93
- <T.MeshStandardMaterial {color} />
94
- </T.Mesh>
95
- {/if}
53
+ void main() {
54
+ // Mix colors first: bottom (-0.5) = start color, top (+0.5) = end color
55
+ vec3 baseColor = mix(vColorStart, vColorEnd, vYPosition + 0.5);
56
+
57
+ // Desaturate and darken bond colors
58
+ baseColor = desaturateBondColor(baseColor);
59
+
60
+ // Apply lighting to the mixed color
61
+ vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0));
62
+ float diffuse = max(dot(vNormal, lightDir), 0.0);
63
+
64
+ vec3 finalColor = baseColor * (ambientIntensity + directionalIntensity * diffuse);
65
+
66
+ // Convert to sRGB for display
67
+ gl_FragColor = vec4(linearTosRGB(finalColor), 1.0);
68
+ }
69
+ `;
70
+ $effect(() => {
71
+ if (!mesh)
72
+ return;
73
+ const count = group.instances.length;
74
+ const matrix = new Matrix4();
75
+ const temp_color = new Color();
76
+ // Reallocate color buffers if needed
77
+ if (colors_start.length !== count * 3) {
78
+ colors_start = new Float32Array(count * 3);
79
+ colors_end = new Float32Array(count * 3);
80
+ }
81
+ // Set matrices and colors in single loop
82
+ for (let idx = 0; idx < count; idx++) {
83
+ const instance = group.instances[idx];
84
+ // Set matrix
85
+ matrix.fromArray(instance.matrix);
86
+ mesh.setMatrixAt(idx, matrix);
87
+ // Set start color
88
+ temp_color.set(instance.color_start);
89
+ colors_start[idx * 3] = temp_color.r;
90
+ colors_start[idx * 3 + 1] = temp_color.g;
91
+ colors_start[idx * 3 + 2] = temp_color.b;
92
+ // Set end color
93
+ temp_color.set(instance.color_end);
94
+ colors_end[idx * 3] = temp_color.r;
95
+ colors_end[idx * 3 + 1] = temp_color.g;
96
+ colors_end[idx * 3 + 2] = temp_color.b;
97
+ }
98
+ mesh.instanceMatrix.needsUpdate = true;
99
+ // Update or create color attributes
100
+ const { geometry } = mesh;
101
+ for (const [name, buffer] of [
102
+ [`instanceColorStart`, colors_start],
103
+ [`instanceColorEnd`, colors_end],
104
+ ]) {
105
+ const existing = geometry.getAttribute(name);
106
+ if (existing?.array === buffer)
107
+ existing.needsUpdate = true;
108
+ else
109
+ geometry.setAttribute(name, new InstancedBufferAttribute(buffer, 3));
110
+ }
111
+ mesh.count = count;
112
+ });
113
+ let shader_material = $derived(new ShaderMaterial({
114
+ vertexShader: vertex_shader,
115
+ fragmentShader: fragment_shader,
116
+ uniforms: {
117
+ ambientIntensity: { value: group.ambient_light ?? 0.7 },
118
+ directionalIntensity: { value: group.directional_light ?? 0.3 },
119
+ saturation: { value: saturation },
120
+ brightness: { value: brightness },
121
+ },
122
+ }));
123
+ </script>
96
124
 
97
- <!-- Bond tooltip on hover -->
98
- {#if active_tooltip === `bond` && hovered_bond_data && bond_data &&
99
- hovered_bond_data === bond_data}
100
- {@const midpoint = [
101
- (from[0] + to[0]) / 2,
102
- (from[1] + to[1]) / 2,
103
- (from[2] + to[2]) / 2,
104
- ] as Vec3}
105
- <CanvasTooltip position={midpoint}>
106
- <strong>Distance:</strong> {format_num(bond_data.bond_length, `.3f`)} Å (sites {
107
- bond_data.site_idx_1
108
- } ↔ {bond_data.site_idx_2})<br>
109
- {#if bond_data.strength}
110
- <strong>Strength:</strong> {format_num(bond_data.strength, `.3f`)}
111
- {#if bonding_strategy}({bonding_strategy.replace(/_/g, ` `)}){/if}
112
- {/if}
113
- </CanvasTooltip>
114
- {/if}
125
+ <T.InstancedMesh
126
+ args={[undefined, shader_material, group.instances.length]}
127
+ bind:ref={mesh}
128
+ >
129
+ <T.CylinderGeometry args={[group.thickness, group.thickness, 1, 8]} />
130
+ </T.InstancedMesh>
@@ -1,22 +1,9 @@
1
- import type { BondPair, Vec3 } from '..';
2
- import type { BondingStrategy } from './bonding';
3
- import { T } from '@threlte/core';
4
- import type { ComponentProps } from 'svelte';
5
- interface Props extends ComponentProps<typeof T.Mesh> {
6
- from: Vec3;
7
- to: Vec3;
8
- color?: string;
9
- thickness?: number;
10
- offset?: number;
11
- from_color?: string;
12
- to_color?: string;
13
- bond_data?: BondPair;
14
- bonding_strategy?: BondingStrategy;
15
- active_tooltip?: `atom` | `bond` | null;
16
- hovered_bond_data?: BondPair | null;
17
- onbondhover?: (bond_data: BondPair | null) => void;
18
- ontooltipchange?: (type: `atom` | `bond` | null) => void;
19
- }
20
- declare const Bond: import("svelte").Component<Props, {}, "">;
1
+ import type { BondGroupWithGradients } from './';
2
+ type $$ComponentProps = {
3
+ group: BondGroupWithGradients;
4
+ saturation?: number;
5
+ brightness?: number;
6
+ };
7
+ declare const Bond: import("svelte").Component<$$ComponentProps, {}, "">;
21
8
  type Bond = ReturnType<typeof Bond>;
22
9
  export default Bond;
@@ -1,10 +1,10 @@
1
1
  import type { Vec3 } from '../math';
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
- interface Props extends HTMLAttributes<HTMLDivElement> {
4
+ type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
5
5
  position: Vec3;
6
- children: Snippet;
7
- }
8
- declare const CanvasTooltip: import("svelte").Component<Props, {}, "">;
6
+ children: Snippet<[]>;
7
+ };
8
+ declare const CanvasTooltip: import("svelte").Component<$$ComponentProps, {}, "">;
9
9
  type CanvasTooltip = ReturnType<typeof CanvasTooltip>;
10
10
  export default CanvasTooltip;
@@ -0,0 +1,29 @@
1
+ <script lang="ts">import { T } from '@threlte/core';
2
+ import { Euler, Quaternion, Vector3 } from 'three';
3
+ let { from, to, color = `#808080`, thickness = 0.1, } = $props();
4
+ let from_vec = $derived(new Vector3(...from));
5
+ let to_vec = $derived(new Vector3(...to));
6
+ let { position, rotation, height } = $derived(calc_bond(from_vec, to_vec));
7
+ function calc_bond(from_vec, to_vec) {
8
+ // find the axis of the cylinder
9
+ const delta_vec = to_vec.clone().sub(from_vec);
10
+ // length of the cylinder
11
+ const height = delta_vec.length();
12
+ // calculate position (midpoint between from and to)
13
+ const position = from_vec
14
+ .clone()
15
+ .add(delta_vec.multiplyScalar(0.5))
16
+ .toArray();
17
+ // calculate rotation
18
+ const quaternion = new Quaternion().setFromUnitVectors(new Vector3(0, 1, 0), delta_vec.normalize());
19
+ const euler = new Euler().setFromQuaternion(quaternion);
20
+ const rotation = [euler.x, euler.y, euler.z];
21
+ // return results
22
+ return { height, position, rotation };
23
+ }
24
+ </script>
25
+
26
+ <T.Mesh {position} {rotation} scale={[thickness, height, thickness]}>
27
+ <T.CylinderGeometry args={[thickness, thickness, 1, 8]} />
28
+ <T.MeshStandardMaterial {color} />
29
+ </T.Mesh>
@@ -0,0 +1,10 @@
1
+ import type { Vec3 } from '..';
2
+ type $$ComponentProps = {
3
+ from: Vec3;
4
+ to: Vec3;
5
+ color?: string;
6
+ thickness?: number;
7
+ };
8
+ declare const Cylinder: import("svelte").Component<$$ComponentProps, {}, "">;
9
+ type Cylinder = ReturnType<typeof Cylinder>;
10
+ export default Cylinder;
@@ -88,8 +88,7 @@ function get_cylinder_transform(start, end) {
88
88
  {#if show_cell_vectors}
89
89
  <T.Group position={vector_origin}>
90
90
  {#each matrix as vec, idx (vec)}
91
- {@const vector_length = Math.sqrt(vec[0] ** 2 + vec[1] ** 2 + vec[2] ** 2)}
92
- {@const shaft_length = vector_length * 0.85}
91
+ {@const shaft_length = Math.hypot(...vec) * 0.85}
93
92
  <!-- Shaft goes to 85% of vector length -->
94
93
  {@const tip_start_position = math.scale(vec, 0.85) as Vec3}
95
94
  <!-- Calculate rotation to align with vector direction -->
@@ -1,6 +1,6 @@
1
1
  import type { Vec3 } from '../math';
2
2
  import * as math from '../math';
3
- interface Props {
3
+ type $$ComponentProps = {
4
4
  matrix?: math.Matrix3x3;
5
5
  cell_edge_color?: string;
6
6
  cell_surface_color?: string;
@@ -11,7 +11,7 @@ interface Props {
11
11
  vector_colors?: readonly [string, string, string];
12
12
  vector_origin?: Vec3;
13
13
  float_fmt?: string;
14
- }
15
- declare const Lattice: import("svelte").Component<Props, {}, "">;
14
+ };
15
+ declare const Lattice: import("svelte").Component<$$ComponentProps, {}, "">;
16
16
  type Lattice = ReturnType<typeof Lattice>;
17
17
  export default Lattice;
@@ -8,7 +8,7 @@ import { is_valid_supercell_input, make_supercell } from './supercell';
8
8
  import { Canvas } from '@threlte/core';
9
9
  import { untrack } from 'svelte';
10
10
  import { click_outside, tooltip } from 'svelte-multiselect';
11
- import { StructureControls, StructureInfoPane, StructureLegend, StructureScene, } from './index';
11
+ import { StructureControls, StructureExportPane, StructureInfoPane, StructureLegend, StructureScene, } from './index';
12
12
  import { MAX_SELECTED_SITES } from './measure';
13
13
  import { parse_any_structure } from './parse';
14
14
  // Local reactive state for scene and lattice props. Deeply reactive so nested mutations propagate.
@@ -28,7 +28,9 @@ selected_sites = $bindable([]),
28
28
  // expose measured site indices for overlays/labels
29
29
  measured_sites = $bindable([]),
30
30
  // expose the displayed structure (with image atoms and supercell) for external use
31
- displayed_structure = $bindable(undefined), children, on_file_load, on_error, on_fullscreen_change, on_camera_move, on_camera_reset, ...rest } = $props();
31
+ displayed_structure = $bindable(undefined),
32
+ // Track hidden elements across component lifecycle
33
+ hidden_elements = $bindable(new Set()), children, on_file_load, on_error, on_fullscreen_change, on_camera_move, on_camera_reset, ...rest } = $props();
32
34
  // Initialize models from incoming props; mutations come from UI controls; we mirror into local dicts (NOTE only doing shallow merge)
33
35
  $effect.pre(() => {
34
36
  if (scene_props_in && typeof scene_props_in === `object`) {
@@ -138,6 +140,7 @@ $effect(() => {
138
140
  // Measurement mode and selection state
139
141
  let measure_mode = $state(`distance`);
140
142
  let measure_menu_open = $state(false);
143
+ let export_pane_open = $state(false);
141
144
  let visible_buttons = $derived(show_controls === true ||
142
145
  (typeof show_controls === `number` && width > show_controls));
143
146
  // Create supercell if needed
@@ -344,7 +347,7 @@ $effect(() => {
344
347
 
345
348
  <div
346
349
  class:dragover
347
- class:active={info_pane_open || controls_open}
350
+ class:active={info_pane_open || controls_open || export_pane_open}
348
351
  role="region"
349
352
  aria-label="Structure viewer"
350
353
  bind:this={wrapper}
@@ -474,6 +477,16 @@ $effect(() => {
474
477
  />
475
478
  {/if}
476
479
 
480
+ <StructureExportPane
481
+ bind:export_pane_open
482
+ {structure}
483
+ {wrapper}
484
+ {scene}
485
+ {camera}
486
+ bind:png_dpi
487
+ pane_props={{ style: `max-height: calc(${height}px - 50px)` }}
488
+ />
489
+
477
490
  <StructureControls
478
491
  bind:controls_open
479
492
  bind:scene_props
@@ -483,16 +496,15 @@ $effect(() => {
483
496
  bind:background_color
484
497
  bind:background_opacity
485
498
  bind:color_scheme
486
- bind:png_dpi
487
499
  {structure}
488
- {wrapper}
489
- {scene}
490
- {camera}
491
500
  />
492
501
  {/if}
493
502
  </section>
494
503
 
495
- <StructureLegend elements={get_elem_amounts(supercell_structure ?? structure!)} />
504
+ <StructureLegend
505
+ elements={get_elem_amounts(supercell_structure ?? structure!)}
506
+ bind:hidden_elements
507
+ />
496
508
 
497
509
  <!-- prevent from rendering in vitest runner since WebGLRenderingContext not available -->
498
510
  {#if typeof WebGLRenderingContext !== `undefined`}
@@ -506,6 +518,9 @@ $effect(() => {
506
518
  bind:camera_is_moving
507
519
  bind:selected_sites
508
520
  bind:measured_sites
521
+ bind:scene
522
+ bind:camera
523
+ bind:hidden_elements
509
524
  {measure_mode}
510
525
  {width}
511
526
  {height}
@@ -1,17 +1,19 @@
1
- import type { AnyStructure } from '..';
1
+ import type { AnyStructure, ElementSymbol } from '..';
2
2
  import { Spinner } from '..';
3
3
  import type { ComponentProps, Snippet } from 'svelte';
4
4
  import type { HTMLAttributes } from 'svelte/elements';
5
5
  import type { StructureHandlerData } from './index';
6
- import { StructureScene } from './index';
7
- import type { Props as ControlProps } from './StructureControls.svelte';
6
+ import { StructureControls, StructureScene } from './index';
8
7
  type EventHandler = (data: StructureHandlerData) => void;
9
- interface Props extends Omit<ControlProps, `children` | `onclose`>, Omit<HTMLAttributes<HTMLDivElement>, `children`> {
8
+ type $$ComponentProps = {
9
+ structure?: AnyStructure;
10
10
  scene_props?: ComponentProps<typeof StructureScene>;
11
11
  show_controls?: boolean | number;
12
12
  fullscreen?: boolean;
13
13
  width?: number;
14
14
  height?: number;
15
+ wrapper?: HTMLDivElement;
16
+ png_dpi?: number;
15
17
  reset_text?: string;
16
18
  hovered?: boolean;
17
19
  dragover?: boolean;
@@ -31,7 +33,8 @@ interface Props extends Omit<ControlProps, `children` | `onclose`>, Omit<HTMLAtt
31
33
  performance_mode?: `quality` | `speed`;
32
34
  selected_sites?: number[];
33
35
  measured_sites?: number[];
34
- displayed_structure?: AnyStructure | undefined;
36
+ displayed_structure?: AnyStructure;
37
+ hidden_elements?: Set<ElementSymbol>;
35
38
  structure_string?: string;
36
39
  children?: Snippet<[{
37
40
  structure?: AnyStructure;
@@ -41,7 +44,7 @@ interface Props extends Omit<ControlProps, `children` | `onclose`>, Omit<HTMLAtt
41
44
  on_fullscreen_change?: EventHandler;
42
45
  on_camera_move?: EventHandler;
43
46
  on_camera_reset?: EventHandler;
44
- }
45
- declare const Structure: import("svelte").Component<Props, {}, "height" | "width" | "loading" | "dragover" | "structure" | "color_scheme" | "background_color" | "background_opacity" | "show_image_atoms" | "info_pane_open" | "scene_props" | "lattice_props" | "controls_open" | "enable_measure_mode" | "wrapper" | "hovered" | "png_dpi" | "supercell_scaling" | "error_msg" | "performance_mode" | "selected_sites" | "measured_sites" | "displayed_structure">;
47
+ } & Omit<ComponentProps<typeof StructureControls>, `children` | `onclose`> & Omit<HTMLAttributes<HTMLDivElement>, `children`>;
48
+ declare const Structure: import("svelte").Component<$$ComponentProps, {}, "height" | "width" | "loading" | "dragover" | "structure" | "color_scheme" | "background_color" | "background_opacity" | "show_image_atoms" | "info_pane_open" | "hovered" | "controls_open" | "scene_props" | "lattice_props" | "supercell_scaling" | "enable_measure_mode" | "wrapper" | "png_dpi" | "error_msg" | "performance_mode" | "selected_sites" | "measured_sites" | "displayed_structure" | "hidden_elements">;
46
49
  type Structure = ReturnType<typeof Structure>;
47
50
  export default Structure;