matterviz 0.1.0

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 (131) hide show
  1. package/dist/BohrAtom.svelte +105 -0
  2. package/dist/BohrAtom.svelte.d.ts +21 -0
  3. package/dist/ControlPanel.svelte +158 -0
  4. package/dist/ControlPanel.svelte.d.ts +18 -0
  5. package/dist/Icon.svelte +23 -0
  6. package/dist/Icon.svelte.d.ts +8 -0
  7. package/dist/InfoCard.svelte +79 -0
  8. package/dist/InfoCard.svelte.d.ts +23 -0
  9. package/dist/Nucleus.svelte +64 -0
  10. package/dist/Nucleus.svelte.d.ts +16 -0
  11. package/dist/Spinner.svelte +44 -0
  12. package/dist/Spinner.svelte.d.ts +7 -0
  13. package/dist/api.d.ts +6 -0
  14. package/dist/api.js +30 -0
  15. package/dist/colors/alloy-colors.json +111 -0
  16. package/dist/colors/dark-mode-colors.json +111 -0
  17. package/dist/colors/index.d.ts +26 -0
  18. package/dist/colors/index.js +72 -0
  19. package/dist/colors/jmol-colors.json +111 -0
  20. package/dist/colors/muted-colors.json +111 -0
  21. package/dist/colors/pastel-colors.json +111 -0
  22. package/dist/colors/vesta-colors.json +111 -0
  23. package/dist/composition/BarChart.svelte +260 -0
  24. package/dist/composition/BarChart.svelte.d.ts +33 -0
  25. package/dist/composition/BubbleChart.svelte +166 -0
  26. package/dist/composition/BubbleChart.svelte.d.ts +30 -0
  27. package/dist/composition/Composition.svelte +73 -0
  28. package/dist/composition/Composition.svelte.d.ts +27 -0
  29. package/dist/composition/PieChart.svelte +236 -0
  30. package/dist/composition/PieChart.svelte.d.ts +36 -0
  31. package/dist/composition/index.d.ts +5 -0
  32. package/dist/composition/index.js +5 -0
  33. package/dist/composition/parse.d.ts +14 -0
  34. package/dist/composition/parse.js +307 -0
  35. package/dist/element/ElementHeading.svelte +21 -0
  36. package/dist/element/ElementHeading.svelte.d.ts +8 -0
  37. package/dist/element/ElementPhoto.svelte +56 -0
  38. package/dist/element/ElementPhoto.svelte.d.ts +9 -0
  39. package/dist/element/ElementStats.svelte +73 -0
  40. package/dist/element/ElementStats.svelte.d.ts +8 -0
  41. package/dist/element/ElementTile.svelte +449 -0
  42. package/dist/element/ElementTile.svelte.d.ts +25 -0
  43. package/dist/element/data.d.ts +4958 -0
  44. package/dist/element/data.js +5628 -0
  45. package/dist/element/index.d.ts +4 -0
  46. package/dist/element/index.js +4 -0
  47. package/dist/icons.d.ts +435 -0
  48. package/dist/icons.js +435 -0
  49. package/dist/index.d.ts +82 -0
  50. package/dist/index.js +43 -0
  51. package/dist/io/decompress.d.ts +16 -0
  52. package/dist/io/decompress.js +78 -0
  53. package/dist/io/export.d.ts +9 -0
  54. package/dist/io/export.js +205 -0
  55. package/dist/io/parse.d.ts +53 -0
  56. package/dist/io/parse.js +747 -0
  57. package/dist/labels.d.ts +31 -0
  58. package/dist/labels.js +209 -0
  59. package/dist/material/MaterialCard.svelte +135 -0
  60. package/dist/material/MaterialCard.svelte.d.ts +10 -0
  61. package/dist/material/SymmetryCard.svelte +23 -0
  62. package/dist/material/SymmetryCard.svelte.d.ts +9 -0
  63. package/dist/material/index.d.ts +2 -0
  64. package/dist/material/index.js +2 -0
  65. package/dist/math.d.ts +24 -0
  66. package/dist/math.js +216 -0
  67. package/dist/periodic-table/PeriodicTable.svelte +284 -0
  68. package/dist/periodic-table/PeriodicTable.svelte.d.ts +50 -0
  69. package/dist/periodic-table/PropertySelect.svelte +20 -0
  70. package/dist/periodic-table/PropertySelect.svelte.d.ts +13 -0
  71. package/dist/periodic-table/TableInset.svelte +18 -0
  72. package/dist/periodic-table/TableInset.svelte.d.ts +9 -0
  73. package/dist/periodic-table/index.d.ts +9 -0
  74. package/dist/periodic-table/index.js +3 -0
  75. package/dist/plot/ColorBar.svelte +414 -0
  76. package/dist/plot/ColorBar.svelte.d.ts +22 -0
  77. package/dist/plot/ColorScaleSelect.svelte +31 -0
  78. package/dist/plot/ColorScaleSelect.svelte.d.ts +15 -0
  79. package/dist/plot/ElementScatter.svelte +38 -0
  80. package/dist/plot/ElementScatter.svelte.d.ts +14 -0
  81. package/dist/plot/Line.svelte +42 -0
  82. package/dist/plot/Line.svelte.d.ts +15 -0
  83. package/dist/plot/PlotLegend.svelte +206 -0
  84. package/dist/plot/PlotLegend.svelte.d.ts +18 -0
  85. package/dist/plot/ScatterPlot.svelte +1753 -0
  86. package/dist/plot/ScatterPlot.svelte.d.ts +114 -0
  87. package/dist/plot/ScatterPlotControls.svelte +505 -0
  88. package/dist/plot/ScatterPlotControls.svelte.d.ts +33 -0
  89. package/dist/plot/ScatterPoint.svelte +72 -0
  90. package/dist/plot/ScatterPoint.svelte.d.ts +17 -0
  91. package/dist/plot/index.d.ts +168 -0
  92. package/dist/plot/index.js +46 -0
  93. package/dist/state.svelte.d.ts +12 -0
  94. package/dist/state.svelte.js +11 -0
  95. package/dist/structure/Bond.svelte +68 -0
  96. package/dist/structure/Bond.svelte.d.ts +13 -0
  97. package/dist/structure/Lattice.svelte +115 -0
  98. package/dist/structure/Lattice.svelte.d.ts +15 -0
  99. package/dist/structure/Structure.svelte +298 -0
  100. package/dist/structure/Structure.svelte.d.ts +28 -0
  101. package/dist/structure/StructureCard.svelte +26 -0
  102. package/dist/structure/StructureCard.svelte.d.ts +9 -0
  103. package/dist/structure/StructureControls.svelte +383 -0
  104. package/dist/structure/StructureControls.svelte.d.ts +23 -0
  105. package/dist/structure/StructureLegend.svelte +130 -0
  106. package/dist/structure/StructureLegend.svelte.d.ts +17 -0
  107. package/dist/structure/StructureScene.svelte +331 -0
  108. package/dist/structure/StructureScene.svelte.d.ts +47 -0
  109. package/dist/structure/bonding.d.ts +16 -0
  110. package/dist/structure/bonding.js +150 -0
  111. package/dist/structure/index.d.ts +98 -0
  112. package/dist/structure/index.js +114 -0
  113. package/dist/structure/pbc.d.ts +6 -0
  114. package/dist/structure/pbc.js +72 -0
  115. package/dist/trajectory/Sidebar.svelte +412 -0
  116. package/dist/trajectory/Sidebar.svelte.d.ts +14 -0
  117. package/dist/trajectory/Trajectory.svelte +1084 -0
  118. package/dist/trajectory/Trajectory.svelte.d.ts +49 -0
  119. package/dist/trajectory/TrajectoryError.svelte +120 -0
  120. package/dist/trajectory/TrajectoryError.svelte.d.ts +12 -0
  121. package/dist/trajectory/extract.d.ts +5 -0
  122. package/dist/trajectory/extract.js +157 -0
  123. package/dist/trajectory/index.d.ts +16 -0
  124. package/dist/trajectory/index.js +49 -0
  125. package/dist/trajectory/parse.d.ts +13 -0
  126. package/dist/trajectory/parse.js +1093 -0
  127. package/dist/trajectory/plotting.d.ts +12 -0
  128. package/dist/trajectory/plotting.js +148 -0
  129. package/license +21 -0
  130. package/package.json +131 -0
  131. package/readme.md +95 -0
@@ -0,0 +1,72 @@
1
+ <script lang="ts">import { symbol_map } from './';
2
+ import * as d3_symbols from 'd3-shape';
3
+ import { symbol } from 'd3-shape';
4
+ import { cubicOut } from 'svelte/easing';
5
+ import { Tween } from 'svelte/motion';
6
+ let { x, y, style = {}, hover = {}, label = {}, offset = { x: 0, y: 0 }, point_tween, origin = { x: 0, y: 0 }, is_hovered = false, ...rest } = $props();
7
+ // get the SVG path data as 'd' attribute
8
+ function get_symbol_path() {
9
+ const symbol_type = symbol_map[style.symbol_type ?? `Circle`] ??
10
+ d3_symbols.symbolCircle;
11
+ const size = style.symbol_size ?? Math.PI * Math.pow(style.radius ?? 2, 2);
12
+ return symbol().type(symbol_type).size(size)() || ``;
13
+ }
14
+ let marker_path = $derived.by(get_symbol_path);
15
+ const default_tween_props = {
16
+ duration: 600,
17
+ easing: cubicOut,
18
+ };
19
+ // Single tween for {x, y} coordinates
20
+ const tweened_coords = new Tween(origin, { ...default_tween_props, ...point_tween });
21
+ $effect.pre(() => {
22
+ tweened_coords.target = { x: x + offset.x, y: y + offset.y };
23
+ });
24
+ </script>
25
+
26
+ <g
27
+ transform="translate({tweened_coords.current.x} {tweened_coords.current.y})"
28
+ style:--hover-scale={hover.scale ?? 1.5}
29
+ style:--hover-stroke={hover.stroke ?? `white`}
30
+ style:--hover-stroke-width="{hover.stroke_width ?? 0}px"
31
+ style:--hover-brightness={hover.brightness ?? 1.2}
32
+ {...rest}
33
+ >
34
+ <path
35
+ d={marker_path}
36
+ stroke={style.stroke ?? `transparent`}
37
+ stroke-width={style.stroke_width ?? 1}
38
+ style:fill-opacity={style.fill_opacity}
39
+ style:stroke-opacity={style.stroke_opacity}
40
+ style:fill="var(--point-fill-color, {style.fill ?? `black`})"
41
+ class="marker"
42
+ class:is-hovered={is_hovered && (hover.enabled ?? true)}
43
+ />
44
+ {#if label.text}
45
+ <text
46
+ x={label?.offset?.x ?? 10}
47
+ y={label?.offset?.y ?? 0}
48
+ style:font-size={label?.font_size ?? `10px`}
49
+ style:font-family={label?.font_family ?? `sans-serif`}
50
+ style:fill="var(--scatter-point-label-fill, currentColor)"
51
+ dominant-baseline="middle"
52
+ class="label-text"
53
+ >
54
+ {label.text}
55
+ </text>
56
+ {/if}
57
+ </g>
58
+
59
+ <style>
60
+ .marker {
61
+ transition: var(--scatter-point-transition, all 0.2s);
62
+ }
63
+ .marker.is-hovered {
64
+ transform: scale(var(--hover-scale));
65
+ stroke: var(--hover-stroke);
66
+ stroke-width: var(--hover-stroke-width);
67
+ filter: brightness(var(--hover-brightness));
68
+ }
69
+ .label-text {
70
+ pointer-events: var(--scatter-point-label-pointer-events, none);
71
+ }
72
+ </style>
@@ -0,0 +1,17 @@
1
+ import type { HoverStyle, LabelStyle, Point, PointStyle, XyObj } from './';
2
+ import { type TweenedOptions } from 'svelte/motion';
3
+ interface Props {
4
+ x: number;
5
+ y: number;
6
+ style?: PointStyle;
7
+ hover?: HoverStyle;
8
+ label?: LabelStyle;
9
+ offset?: Point[`offset`];
10
+ point_tween?: TweenedOptions<XyObj>;
11
+ origin?: XyObj;
12
+ is_hovered?: boolean;
13
+ [key: string]: unknown;
14
+ }
15
+ declare const ScatterPoint: import("svelte").Component<Props, {}, "">;
16
+ type ScatterPoint = ReturnType<typeof ScatterPoint>;
17
+ export default ScatterPoint;
@@ -0,0 +1,168 @@
1
+ import type { SimulationNodeDatum } from 'd3-force';
2
+ import type { SymbolType } from 'd3-shape';
3
+ import * as d3_symbols from 'd3-shape';
4
+ import type { ComponentProps } from 'svelte';
5
+ import { type TweenedOptions } from 'svelte/motion';
6
+ import type ColorBar from './ColorBar.svelte';
7
+ import PlotLegend from './PlotLegend.svelte';
8
+ export { default as ColorBar } from './ColorBar.svelte';
9
+ export { default as ColorScaleSelect } from './ColorScaleSelect.svelte';
10
+ export { default as ElementScatter } from './ElementScatter.svelte';
11
+ export { default as Line } from './Line.svelte';
12
+ export { default as PlotLegend } from './PlotLegend.svelte';
13
+ export { default as ScatterPlot } from './ScatterPlot.svelte';
14
+ export { default as ScatterPlotControls } from './ScatterPlotControls.svelte';
15
+ export { default as ScatterPoint } from './ScatterPoint.svelte';
16
+ export type XyObj = {
17
+ x: number;
18
+ y: number;
19
+ };
20
+ export type Sides = {
21
+ t?: number;
22
+ b?: number;
23
+ l?: number;
24
+ r?: number;
25
+ };
26
+ export type D3Symbol = keyof typeof d3_symbols & `symbol${Capitalize<string>}`;
27
+ export type D3SymbolName = Exclude<D3Symbol extends `symbol${infer Name}` ? Name : never, ``>;
28
+ export declare const symbol_names: D3SymbolName[];
29
+ export declare const symbol_map: Record<D3SymbolName, SymbolType>;
30
+ export declare const line_types: readonly ["solid", "dashed", "dotted"];
31
+ export type LineType = (typeof line_types)[number];
32
+ export type Point = {
33
+ x: number;
34
+ y: number;
35
+ metadata?: {
36
+ [key: string]: unknown;
37
+ };
38
+ offset?: XyObj;
39
+ };
40
+ export interface PointStyle {
41
+ fill?: string;
42
+ radius?: number;
43
+ stroke?: string;
44
+ stroke_width?: number;
45
+ stroke_opacity?: number;
46
+ fill_opacity?: number;
47
+ symbol_type?: D3SymbolName;
48
+ symbol_size?: number | null;
49
+ shape?: string;
50
+ }
51
+ export interface HoverStyle {
52
+ enabled?: boolean;
53
+ scale?: number;
54
+ stroke?: string;
55
+ stroke_width?: number;
56
+ brightness?: number;
57
+ }
58
+ export interface LabelStyle {
59
+ text?: string;
60
+ offset?: XyObj;
61
+ font_size?: string;
62
+ font_family?: string;
63
+ auto_placement?: boolean;
64
+ }
65
+ export interface PlotPoint extends Point {
66
+ color_value?: number | null;
67
+ metadata?: Record<string, unknown>;
68
+ point_style?: PointStyle;
69
+ point_hover?: HoverStyle;
70
+ point_label?: LabelStyle;
71
+ point_offset?: XyObj;
72
+ point_tween?: TweenedOptions<XyObj>;
73
+ }
74
+ export interface DataSeries {
75
+ x: readonly number[];
76
+ y: readonly number[];
77
+ markers?: `line` | `points` | `line+points`;
78
+ y_axis?: `y1` | `y2`;
79
+ color_values?: (number | null)[] | null;
80
+ size_values?: readonly (number | null)[] | null;
81
+ metadata?: Record<string, unknown>[] | Record<string, unknown>;
82
+ point_style?: PointStyle[] | PointStyle;
83
+ point_hover?: HoverStyle[] | HoverStyle;
84
+ point_label?: LabelStyle[] | LabelStyle;
85
+ point_offset?: XyObj[] | XyObj;
86
+ point_tween?: TweenedOptions<XyObj>;
87
+ visible?: boolean;
88
+ label?: string;
89
+ unit?: string;
90
+ line_style?: {
91
+ stroke?: string;
92
+ stroke_width?: number;
93
+ line_dash?: string;
94
+ };
95
+ }
96
+ export interface InternalPoint extends PlotPoint {
97
+ series_idx: number;
98
+ point_idx: number;
99
+ size_value?: number | null;
100
+ }
101
+ export type TooltipProps = {
102
+ x: number;
103
+ y: number;
104
+ cx: number;
105
+ cy: number;
106
+ x_formatted: string;
107
+ y_formatted: string;
108
+ metadata?: Record<string, unknown>;
109
+ color_value?: number | null;
110
+ label?: string | null;
111
+ };
112
+ export type TimeInterval = `day` | `month` | `year`;
113
+ export type ScaleType = `linear` | `log`;
114
+ export type QuadrantCounts = {
115
+ top_left: number;
116
+ top_right: number;
117
+ bottom_left: number;
118
+ bottom_right: number;
119
+ };
120
+ export interface LabelNode extends SimulationNodeDatum {
121
+ id: string;
122
+ anchor_x: number;
123
+ anchor_y: number;
124
+ point_node: InternalPoint;
125
+ label_width: number;
126
+ label_height: number;
127
+ }
128
+ export interface LabelPlacementConfig {
129
+ collision_strength: number;
130
+ link_strength: number;
131
+ link_distance: number;
132
+ placement_ticks: number;
133
+ link_distance_range?: [number | null, number | null];
134
+ }
135
+ export type HoverConfig = {
136
+ threshold_px: number;
137
+ };
138
+ export interface AnchorNode extends SimulationNodeDatum {
139
+ id: string;
140
+ fx: number;
141
+ fy: number;
142
+ point_radius: number;
143
+ show_color_bar?: boolean;
144
+ color_bar?: ComponentProps<typeof ColorBar> | null;
145
+ label_placement_config?: Partial<LabelPlacementConfig>;
146
+ }
147
+ export type LegendConfig = Omit<ComponentProps<typeof PlotLegend>, `series_data` | `on_toggle` | `on_drag_start` | `on_drag` | `on_drag_end`> & {
148
+ margin?: number | Sides;
149
+ tween?: TweenedOptions<XyObj>;
150
+ responsive?: boolean;
151
+ draggable?: boolean;
152
+ };
153
+ export declare const cells_3x3: readonly ["top-left", "top-center", "top-right", "middle-left", "middle-center", "middle-right", "bottom-left", "bottom-center", "bottom-right"];
154
+ export declare const corner_cells: readonly ["top-left", "top-right", "bottom-left", "bottom-right"];
155
+ export type Cell3x3 = (typeof cells_3x3)[number];
156
+ export type Corner = (typeof corner_cells)[number];
157
+ export interface LegendItem {
158
+ label: string;
159
+ visible: boolean;
160
+ series_idx: number;
161
+ display_style: {
162
+ symbol_type?: D3SymbolName;
163
+ symbol_color?: string;
164
+ line_color?: string;
165
+ line_dash?: string;
166
+ };
167
+ }
168
+ export declare const LOG_MIN_EPS = 1e-9;
@@ -0,0 +1,46 @@
1
+ import * as d3_symbols from 'd3-shape';
2
+ import {} from 'svelte/motion';
3
+ import PlotLegend from './PlotLegend.svelte';
4
+ export { default as ColorBar } from './ColorBar.svelte';
5
+ export { default as ColorScaleSelect } from './ColorScaleSelect.svelte';
6
+ export { default as ElementScatter } from './ElementScatter.svelte';
7
+ export { default as Line } from './Line.svelte';
8
+ export { default as PlotLegend } from './PlotLegend.svelte';
9
+ export { default as ScatterPlot } from './ScatterPlot.svelte';
10
+ export { default as ScatterPlotControls } from './ScatterPlotControls.svelte';
11
+ export { default as ScatterPoint } from './ScatterPoint.svelte';
12
+ export const symbol_names = [
13
+ ...d3_symbols.symbolsFill,
14
+ ...d3_symbols.symbolsStroke,
15
+ ].map((sym) => {
16
+ // Attempt to find the key associated with this symbol function object
17
+ for (const key in d3_symbols) {
18
+ if (Object.prototype.hasOwnProperty.call(d3_symbols, key) &&
19
+ d3_symbols[key] === sym) {
20
+ if (key.match(/symbol[A-Z]/))
21
+ return key.substring(6);
22
+ }
23
+ }
24
+ });
25
+ export const symbol_map = Object.fromEntries(symbol_names.map((name) => [name, d3_symbols[`symbol${name}`]]));
26
+ export const line_types = [`solid`, `dashed`, `dotted`];
27
+ // Define grid cell identifiers
28
+ export const cells_3x3 = [
29
+ `top-left`,
30
+ `top-center`,
31
+ `top-right`,
32
+ `middle-left`,
33
+ `middle-center`,
34
+ `middle-right`,
35
+ `bottom-left`,
36
+ `bottom-center`,
37
+ `bottom-right`,
38
+ ];
39
+ export const corner_cells = [
40
+ `top-left`,
41
+ `top-right`,
42
+ `bottom-left`,
43
+ `bottom-right`,
44
+ ];
45
+ // Small value to substitute for non-positive minimum in log scales
46
+ export const LOG_MIN_EPS = 1e-9;
@@ -0,0 +1,12 @@
1
+ import type { Category, ChemicalElement } from './';
2
+ import { default_category_colors, default_element_colors } from './colors';
3
+ export declare const selected: {
4
+ category: Category | null;
5
+ element: ChemicalElement | null;
6
+ last_element: ChemicalElement | null;
7
+ heatmap_key: keyof ChemicalElement | null;
8
+ };
9
+ export declare const colors: {
10
+ category: typeof default_category_colors;
11
+ element: typeof default_element_colors;
12
+ };
@@ -0,0 +1,11 @@
1
+ import { default_category_colors, default_element_colors } from './colors';
2
+ export const selected = $state({
3
+ category: null,
4
+ element: null,
5
+ last_element: null,
6
+ heatmap_key: null,
7
+ });
8
+ export const colors = $state({
9
+ category: { ...default_category_colors },
10
+ element: { ...default_element_colors },
11
+ });
@@ -0,0 +1,68 @@
1
+ <script lang="ts">import { T } from '@threlte/core';
2
+ import { CanvasTexture, Euler, Quaternion } from 'three';
3
+ let { from = [0, 0, 0], to, offset = 0, thickness = 0.5, color = `white`, from_color, to_color, } = $props();
4
+ const from_vec = new Vector3(...from);
5
+ const to_vec = new Vector3(...to);
6
+ const { position, rotation, height } = calc_bond(from_vec, to_vec, offset, thickness);
7
+ // Create gradient texture when both colors are provided
8
+ let gradient_texture = $derived.by(() => {
9
+ if (!from_color || !to_color)
10
+ return null;
11
+ // Create a canvas for the gradient
12
+ const canvas = document.createElement(`canvas`);
13
+ canvas.width = 1;
14
+ canvas.height = 256;
15
+ const ctx = canvas.getContext(`2d`);
16
+ // Create linear gradient along Y axis (cylinder height)
17
+ const gradient = ctx.createLinearGradient(0, 0, 0, 256);
18
+ gradient.addColorStop(0, to_color);
19
+ gradient.addColorStop(1, from_color);
20
+ // Fill the canvas with the gradient
21
+ ctx.fillStyle = gradient;
22
+ ctx.fillRect(0, 0, 1, 256);
23
+ // Create texture from canvas
24
+ const texture = new CanvasTexture(canvas);
25
+ texture.needsUpdate = true;
26
+ return texture;
27
+ });
28
+ function calc_bond(from_vec, to_vec, offset, thickness) {
29
+ // find the axis of the the box
30
+ const delta_vec = to_vec.clone().sub(from_vec);
31
+ // length of the bond
32
+ const height = delta_vec.length();
33
+ // calculate position
34
+ let position;
35
+ if (offset === 0) {
36
+ position = from_vec.clone().add(delta_vec.multiplyScalar(0.5)).toArray();
37
+ }
38
+ else {
39
+ const offset_vec = new Vector3()
40
+ .crossVectors(delta_vec, new Vector3(1, 0, 0))
41
+ .normalize();
42
+ position = from_vec
43
+ .clone()
44
+ .add(delta_vec.multiplyScalar(0.5))
45
+ .add(offset_vec.multiplyScalar(offset * thickness * 2))
46
+ .toArray();
47
+ }
48
+ // calculate rotation
49
+ const quaternion = new Quaternion().setFromUnitVectors(new Vector3(0, 1, 0), delta_vec.normalize());
50
+ const rotation = new Euler().setFromQuaternion(quaternion).toArray();
51
+ // return results
52
+ return { height, position, rotation };
53
+ }
54
+ </script>
55
+
56
+ {#if gradient_texture}
57
+ <!-- Use gradient material for bonds with two colors -->
58
+ <T.Mesh {position} {rotation} scale={[thickness, height, thickness]}>
59
+ <T.CylinderGeometry args={[thickness, thickness, 1, 16]} />
60
+ <T.MeshStandardMaterial map={gradient_texture} />
61
+ </T.Mesh>
62
+ {:else}
63
+ <!-- Fallback to solid color -->
64
+ <T.Mesh {position} {rotation} scale={[thickness, height, thickness]}>
65
+ <T.CylinderGeometry args={[thickness, thickness, 1, 16]} />
66
+ <T.MeshStandardMaterial {color} />
67
+ </T.Mesh>
68
+ {/if}
@@ -0,0 +1,13 @@
1
+ import type { Vector3 } from '..';
2
+ interface Props {
3
+ from?: Vector3;
4
+ to: Vector3;
5
+ offset?: number;
6
+ thickness?: number;
7
+ color?: string;
8
+ from_color?: string;
9
+ to_color?: string;
10
+ }
11
+ declare const Bond: import("svelte").Component<Props, {}, "">;
12
+ type Bond = ReturnType<typeof Bond>;
13
+ export default Bond;
@@ -0,0 +1,115 @@
1
+ <!-- Export default values for use in other components -->
2
+ <script lang="ts">import { add, scale } from '..';
3
+ import { T } from '@threlte/core';
4
+ import { BoxGeometry, EdgesGeometry, Euler, Matrix4, Quaternion, Vector3, } from 'three';
5
+ import { CELL_DEFAULTS } from './index';
6
+ let { matrix = undefined, cell_edge_color = CELL_DEFAULTS.color, cell_surface_color = CELL_DEFAULTS.color, cell_line_width = CELL_DEFAULTS.line_width, cell_edge_opacity = CELL_DEFAULTS.edge_opacity, cell_surface_opacity = CELL_DEFAULTS.surface_opacity, show_vectors = true, vector_colors = [`red`, `green`, `blue`], vector_origin = [-1, -1, -1], } = $props();
7
+ let lattice_center = $derived(matrix ? scale(add(...matrix), 0.5) : [0, 0, 0]);
8
+ // Extract line segments from EdgesGeometry for cylinder-based thick lines
9
+ function get_edge_segments(edges_geometry) {
10
+ const positions = edges_geometry.getAttribute(`position`).array;
11
+ const segments = [];
12
+ for (let idx = 0; idx < positions.length; idx += 6) {
13
+ const start = new Vector3(positions[idx], positions[idx + 1], positions[idx + 2]);
14
+ const end = new Vector3(positions[idx + 3], positions[idx + 4], positions[idx + 5]);
15
+ segments.push([start, end]);
16
+ }
17
+ return segments;
18
+ }
19
+ // Calculate cylinder transform for a line segment
20
+ function get_cylinder_transform(start, end) {
21
+ const direction = end.clone().sub(start);
22
+ const length = direction.length();
23
+ const center = start.clone().add(end).multiplyScalar(0.5);
24
+ // Calculate rotation to align cylinder with the line
25
+ const quaternion = new Quaternion().setFromUnitVectors(new Vector3(0, 1, 0), // cylinder default orientation
26
+ direction.normalize());
27
+ const euler = new Euler().setFromQuaternion(quaternion);
28
+ return {
29
+ position: center.toArray(),
30
+ rotation: euler.toArray().slice(0, 3),
31
+ length,
32
+ };
33
+ }
34
+ </script>
35
+
36
+ {#if matrix}
37
+ {#key matrix}
38
+ {@const shear_matrix = new Matrix4().makeBasis(
39
+ new Vector3(...matrix[0]),
40
+ new Vector3(...matrix[1]),
41
+ new Vector3(...matrix[2]),
42
+ )}
43
+ {@const box_geometry = new BoxGeometry(1, 1, 1).applyMatrix4(shear_matrix)}
44
+
45
+ <!-- Render wireframe edges if edge opacity > 0 -->
46
+ {#if cell_edge_opacity > 0}
47
+ {@const edges_geometry = new EdgesGeometry(box_geometry)}
48
+ {@const edge_segments = get_edge_segments(edges_geometry)}
49
+
50
+ <!-- Use cylinders for thick wireframe lines -->
51
+ <T.Group position={lattice_center}>
52
+ {#each edge_segments as [start, end], idx (idx)}
53
+ {@const { position, rotation, length } = get_cylinder_transform(start, end)}
54
+ <T.Mesh {position} {rotation}>
55
+ <T.CylinderGeometry
56
+ args={[cell_line_width * 0.01, cell_line_width * 0.01, length, 8]}
57
+ />
58
+ <T.MeshStandardMaterial
59
+ color={cell_edge_color}
60
+ opacity={cell_edge_opacity}
61
+ transparent
62
+ />
63
+ </T.Mesh>
64
+ {/each}
65
+ </T.Group>
66
+ {/if}
67
+
68
+ <!-- Render transparent surfaces if surface opacity > 0 -->
69
+ {#if cell_surface_opacity > 0}
70
+ <T.Mesh geometry={box_geometry} position={lattice_center}>
71
+ <T.MeshStandardMaterial
72
+ color={cell_surface_color}
73
+ opacity={cell_surface_opacity}
74
+ transparent
75
+ />
76
+ </T.Mesh>
77
+ {/if}
78
+
79
+ <!-- NOTE below is an untested fix for the lattice vectors being much too small when deployed even though they look correct in local dev -->
80
+
81
+ {#if show_vectors}
82
+ <T.Group position={vector_origin}>
83
+ {#each matrix as vec, idx (vec)}
84
+ {@const vector_length = Math.sqrt(vec[0] ** 2 + vec[1] ** 2 + vec[2] ** 2)}
85
+ {@const shaft_length = vector_length * 0.85}
86
+ <!-- Shaft goes to 85% of vector length -->
87
+ {@const tip_start_position = scale(vec, 0.85) as Vec3}
88
+ <!-- Calculate rotation to align with vector direction -->
89
+ {@const quaternion = new Quaternion().setFromUnitVectors(
90
+ new Vector3(0, 1, 0), // Default up direction for cylinder/cone
91
+ new Vector3(...vec).normalize(),
92
+ )}
93
+ {@const rotation = new Euler()
94
+ .setFromQuaternion(quaternion)
95
+ .toArray()
96
+ .slice(0, 3) as Vec3}
97
+
98
+ <!-- Arrow shaft - position at center of shaft length -->
99
+ {@const shaft_center = scale(vec, 0.425) as Vec3}
100
+ <!-- Center at 42.5% = half of 85% -->
101
+ <T.Mesh position={shaft_center} {rotation}>
102
+ <T.CylinderGeometry args={[0.05, 0.05, shaft_length, 16]} />
103
+ <T.MeshStandardMaterial color={vector_colors[idx]} />
104
+ </T.Mesh>
105
+
106
+ <!-- Arrow tip -->
107
+ <T.Mesh position={tip_start_position} {rotation}>
108
+ <T.ConeGeometry args={[0.15, vector_length * 0.15, 16]} />
109
+ <T.MeshStandardMaterial color={vector_colors[idx]} />
110
+ </T.Mesh>
111
+ {/each}
112
+ </T.Group>
113
+ {/if}
114
+ {/key}
115
+ {/if}
@@ -0,0 +1,15 @@
1
+ import type { Matrix3x3, Vec3 } from '../math';
2
+ interface Props {
3
+ matrix?: Matrix3x3 | undefined;
4
+ cell_edge_color?: string;
5
+ cell_surface_color?: string;
6
+ cell_line_width?: number;
7
+ cell_edge_opacity?: number;
8
+ cell_surface_opacity?: number;
9
+ show_vectors?: boolean;
10
+ vector_colors?: [string, string, string];
11
+ vector_origin?: Vec3;
12
+ }
13
+ declare const Lattice: import("svelte").Component<Props, {}, "">;
14
+ type Lattice = ReturnType<typeof Lattice>;
15
+ export default Lattice;