@slithy/math-particles 0.1.0 → 0.2.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.
- package/README.md +17 -1
- package/dist/chunk-7SB7KDRV.js +206 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +107 -307
- package/dist/worker-entry.d.ts +2 -0
- package/dist/worker-entry.js +140 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @slithy/math-particles
|
|
2
2
|
|
|
3
|
-
Animated math equations particle overlay for React. Equations drift outward from the center of the container, scaling and fading over time. No animation library —
|
|
3
|
+
Animated math equations particle overlay for React. Equations drift outward from the center of the container, scaling and fading over time. No animation library — the loop runs in a Web Worker via `OffscreenCanvas`, keeping the main thread free.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -29,9 +29,13 @@ import { MathParticlesOverlay } from '@slithy/math-particles'
|
|
|
29
29
|
| Prop | Type | Default | Description |
|
|
30
30
|
|---|---|---|---|
|
|
31
31
|
| `backgroundColor` | `string` | `"#07070f"` | Background fill color of the container |
|
|
32
|
+
| `blur` | `boolean` | `true` | Applies a soft blur at the start and end of each particle's lifecycle |
|
|
32
33
|
| `colors` | `string[]` | ColorBrewer RdYlBu | Array of colors to pick from randomly per particle |
|
|
33
34
|
| `density` | `number` | `1` | Multiplier on the auto-calculated particle count. `0.5` = half, `2` = double. Fixed at mount — use a `key` prop to reinitialize. |
|
|
35
|
+
| `fadeIn` | `boolean` | `true` | Fades the canvas in on mount |
|
|
36
|
+
| `fadeInDuration` | `number` | `800` | Duration of the mount fade-in in milliseconds |
|
|
34
37
|
| `reverse` | `boolean` | `false` | Reverses the animation: equations start large and drift inward rather than starting small and drifting outward |
|
|
38
|
+
| `speed` | `number` | `1` | Multiplier on particle animation speed. `0.5` = half speed, `2` = double. |
|
|
35
39
|
|
|
36
40
|
---
|
|
37
41
|
|
|
@@ -55,6 +59,18 @@ import { MathParticlesOverlay } from '@slithy/math-particles'
|
|
|
55
59
|
<MathParticlesOverlay reverse />
|
|
56
60
|
```
|
|
57
61
|
|
|
62
|
+
### No blur
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
<MathParticlesOverlay blur={false} />
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### No fade-in
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<MathParticlesOverlay fadeIn={false} />
|
|
72
|
+
```
|
|
73
|
+
|
|
58
74
|
### Transparent background
|
|
59
75
|
|
|
60
76
|
```tsx
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// src/equations.ts
|
|
2
|
+
var EQUATIONS = [
|
|
3
|
+
{
|
|
4
|
+
label: "euler",
|
|
5
|
+
w: 220,
|
|
6
|
+
h: 60,
|
|
7
|
+
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 60" width="220" height="60">
|
|
8
|
+
<text x="10" y="44" font-family="Georgia,serif" font-size="38" fill="currentColor">
|
|
9
|
+
<tspan font-style="italic">e</tspan>
|
|
10
|
+
<tspan font-size="22" baseline-shift="super">iπ</tspan>
|
|
11
|
+
<tspan> + 1 = 0</tspan>
|
|
12
|
+
</text>
|
|
13
|
+
</svg>`
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
label: "pythagoras",
|
|
17
|
+
w: 230,
|
|
18
|
+
h: 60,
|
|
19
|
+
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 230 60" width="230" height="60">
|
|
20
|
+
<text x="10" y="44" font-family="Georgia,serif" font-size="38" fill="currentColor">
|
|
21
|
+
<tspan font-style="italic">a</tspan><tspan font-size="22" baseline-shift="super">2</tspan>
|
|
22
|
+
<tspan> + </tspan>
|
|
23
|
+
<tspan font-style="italic">b</tspan><tspan font-size="22" baseline-shift="super">2</tspan>
|
|
24
|
+
<tspan> = </tspan>
|
|
25
|
+
<tspan font-style="italic">c</tspan><tspan font-size="22" baseline-shift="super">2</tspan>
|
|
26
|
+
</text>
|
|
27
|
+
</svg>`
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
label: "quadratic",
|
|
31
|
+
w: 310,
|
|
32
|
+
h: 80,
|
|
33
|
+
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 310 80" width="310" height="80">
|
|
34
|
+
<text x="10" y="32" font-family="Georgia,serif" font-size="22" fill="currentColor">
|
|
35
|
+
<tspan font-style="italic">x</tspan><tspan> = </tspan>
|
|
36
|
+
<tspan>−</tspan><tspan font-style="italic">b</tspan>
|
|
37
|
+
<tspan> ± </tspan>
|
|
38
|
+
<tspan>√(</tspan><tspan font-style="italic">b</tspan>
|
|
39
|
+
<tspan font-size="14" baseline-shift="super">2</tspan>
|
|
40
|
+
<tspan> − 4</tspan><tspan font-style="italic">ac</tspan><tspan>)</tspan>
|
|
41
|
+
</text>
|
|
42
|
+
<line x1="127" y1="40" x2="295" y2="40" stroke="currentColor" stroke-width="1.5"/>
|
|
43
|
+
<text x="195" y="65" font-family="Georgia,serif" font-size="22" fill="currentColor">2<tspan font-style="italic">a</tspan></text>
|
|
44
|
+
</svg>`
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
label: "einstein",
|
|
48
|
+
w: 180,
|
|
49
|
+
h: 60,
|
|
50
|
+
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 60" width="180" height="60">
|
|
51
|
+
<text x="10" y="44" font-family="Georgia,serif" font-size="38" fill="currentColor">
|
|
52
|
+
<tspan font-style="italic">E</tspan>
|
|
53
|
+
<tspan> = </tspan>
|
|
54
|
+
<tspan font-style="italic">mc</tspan>
|
|
55
|
+
<tspan font-size="22" baseline-shift="super">2</tspan>
|
|
56
|
+
</text>
|
|
57
|
+
</svg>`
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
label: "fourier",
|
|
61
|
+
w: 330,
|
|
62
|
+
h: 80,
|
|
63
|
+
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 330 80" width="330" height="80">
|
|
64
|
+
<text x="10" y="32" font-family="Georgia,serif" font-size="20" fill="currentColor">
|
|
65
|
+
<tspan font-style="italic">F</tspan><tspan>(ξ) = </tspan>
|
|
66
|
+
</text>
|
|
67
|
+
<text x="90" y="22" font-family="Georgia,serif" font-size="30" fill="currentColor">∫</text>
|
|
68
|
+
<text x="67" y="22" font-family="Georgia,serif" font-size="13" fill="currentColor">+∞</text>
|
|
69
|
+
<text x="67" y="38" font-family="Georgia,serif" font-size="13" fill="currentColor">−∞</text>
|
|
70
|
+
<text x="115" y="32" font-family="Georgia,serif" font-size="20" fill="currentColor">
|
|
71
|
+
<tspan font-style="italic">f</tspan><tspan>(</tspan><tspan font-style="italic">x</tspan><tspan>)</tspan>
|
|
72
|
+
<tspan font-style="italic"> e</tspan>
|
|
73
|
+
<tspan font-size="13" baseline-shift="super">−2πiξ</tspan>
|
|
74
|
+
<tspan font-style="italic" font-size="13" baseline-shift="super">x</tspan>
|
|
75
|
+
<tspan> d</tspan><tspan font-style="italic">x</tspan>
|
|
76
|
+
</text>
|
|
77
|
+
</svg>`
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
label: "schrodinger",
|
|
81
|
+
w: 220,
|
|
82
|
+
h: 80,
|
|
83
|
+
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 80" width="220" height="80">
|
|
84
|
+
<text x="10" y="38" font-family="Georgia,serif" font-size="24" fill="currentColor">
|
|
85
|
+
<tspan font-style="italic">i</tspan><tspan>ℏ</tspan>
|
|
86
|
+
</text>
|
|
87
|
+
<text x="44" y="26" font-family="Georgia,serif" font-size="20" fill="currentColor">∂Ψ</text>
|
|
88
|
+
<line x1="42" y1="32" x2="80" y2="32" stroke="currentColor" stroke-width="1.4"/>
|
|
89
|
+
<text x="46" y="52" font-family="Georgia,serif" font-size="20" fill="currentColor">∂<tspan font-style="italic">t</tspan></text>
|
|
90
|
+
<text x="86" y="38" font-family="Georgia,serif" font-size="24" fill="currentColor"> = ĤΨ</text>
|
|
91
|
+
</svg>`
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
label: "gaussian",
|
|
95
|
+
w: 240,
|
|
96
|
+
h: 80,
|
|
97
|
+
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 80" width="240" height="80">
|
|
98
|
+
<text x="22" y="22" font-family="Georgia,serif" font-size="30" fill="currentColor">∫</text>
|
|
99
|
+
<text x="10" y="20" font-family="Georgia,serif" font-size="13" fill="currentColor">+∞</text>
|
|
100
|
+
<text x="10" y="48" font-family="Georgia,serif" font-size="13" fill="currentColor">−∞</text>
|
|
101
|
+
<text x="50" y="38" font-family="Georgia,serif" font-size="24" fill="currentColor">
|
|
102
|
+
<tspan font-style="italic">e</tspan>
|
|
103
|
+
<tspan font-size="15" baseline-shift="super">−<tspan font-style="italic">x</tspan><tspan font-size="10">2</tspan></tspan>
|
|
104
|
+
<tspan> d</tspan><tspan font-style="italic">x</tspan><tspan> = √π</tspan>
|
|
105
|
+
</text>
|
|
106
|
+
</svg>`
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
label: "taylor",
|
|
110
|
+
w: 320,
|
|
111
|
+
h: 80,
|
|
112
|
+
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 80" width="320" height="80">
|
|
113
|
+
<text x="10" y="38" font-family="Georgia,serif" font-size="22" fill="currentColor">
|
|
114
|
+
<tspan font-style="italic">f</tspan><tspan>(</tspan><tspan font-style="italic">x</tspan><tspan>) = </tspan>
|
|
115
|
+
</text>
|
|
116
|
+
<text x="90" y="18" font-family="Georgia,serif" font-size="15" fill="currentColor">∞</text>
|
|
117
|
+
<text x="88" y="36" font-family="Georgia,serif" font-size="28" fill="currentColor">∑</text>
|
|
118
|
+
<text x="83" y="56" font-family="Georgia,serif" font-size="14" fill="currentColor"><tspan font-style="italic">n</tspan>=0</text>
|
|
119
|
+
<text x="126" y="26" font-family="Georgia,serif" font-size="17" fill="currentColor">
|
|
120
|
+
<tspan font-style="italic">f</tspan><tspan font-size="12" baseline-shift="super">(<tspan font-style="italic">n</tspan>)</tspan>(<tspan font-style="italic">a</tspan>)
|
|
121
|
+
</text>
|
|
122
|
+
<line x1="124" y1="32" x2="178" y2="32" stroke="currentColor" stroke-width="1.2"/>
|
|
123
|
+
<text x="138" y="52" font-family="Georgia,serif" font-size="17" fill="currentColor">
|
|
124
|
+
<tspan font-style="italic">n</tspan><tspan>!</tspan>
|
|
125
|
+
</text>
|
|
126
|
+
<text x="184" y="38" font-family="Georgia,serif" font-size="22" fill="currentColor">
|
|
127
|
+
(<tspan font-style="italic">x−a</tspan>)<tspan font-size="14" baseline-shift="super"><tspan font-style="italic">n</tspan></tspan>
|
|
128
|
+
</text>
|
|
129
|
+
</svg>`
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
label: "navier-stokes",
|
|
133
|
+
w: 370,
|
|
134
|
+
h: 60,
|
|
135
|
+
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 370 60" width="370" height="60">
|
|
136
|
+
<text x="10" y="40" font-family="Georgia,serif" font-size="22" fill="currentColor">
|
|
137
|
+
ρ(∂<tspan font-style="italic">t</tspan><tspan font-weight="bold" font-style="italic">u</tspan> + <tspan font-style="italic">u</tspan>⋅∇<tspan font-style="italic">u</tspan>) = −∇<tspan font-style="italic">p</tspan> + μ∇<tspan font-size="16" baseline-shift="super">2</tspan><tspan font-weight="bold" font-style="italic">u</tspan>
|
|
138
|
+
</text>
|
|
139
|
+
</svg>`
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
label: "maxwell",
|
|
143
|
+
w: 210,
|
|
144
|
+
h: 70,
|
|
145
|
+
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 210 70" width="210" height="70">
|
|
146
|
+
<text x="10" y="44" font-family="Georgia,serif" font-size="30" fill="currentColor">
|
|
147
|
+
∇ ⋅ <tspan font-weight="bold" font-style="italic">E</tspan> =
|
|
148
|
+
</text>
|
|
149
|
+
<text x="136" y="32" font-family="Georgia,serif" font-size="22" fill="currentColor">ρ</text>
|
|
150
|
+
<line x1="134" y1="38" x2="165" y2="38" stroke="currentColor" stroke-width="1.4"/>
|
|
151
|
+
<text x="136" y="58" font-family="Georgia,serif" font-size="22" fill="currentColor">ε<tspan font-size="14" baseline-shift="sub">0</tspan></text>
|
|
152
|
+
</svg>`
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
label: "riemann",
|
|
156
|
+
w: 200,
|
|
157
|
+
h: 80,
|
|
158
|
+
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 80" width="200" height="80">
|
|
159
|
+
<text x="10" y="38" font-family="Georgia,serif" font-size="22" fill="currentColor">
|
|
160
|
+
ζ(<tspan font-style="italic">s</tspan>) =
|
|
161
|
+
</text>
|
|
162
|
+
<text x="85" y="18" font-family="Georgia,serif" font-size="15" fill="currentColor">∞</text>
|
|
163
|
+
<text x="82" y="36" font-family="Georgia,serif" font-size="28" fill="currentColor">∑</text>
|
|
164
|
+
<text x="78" y="56" font-family="Georgia,serif" font-size="14" fill="currentColor"><tspan font-style="italic">n</tspan>=1</text>
|
|
165
|
+
<text x="120" y="26" font-family="Georgia,serif" font-size="18" fill="currentColor">1</text>
|
|
166
|
+
<line x1="118" y1="32" x2="152" y2="32" stroke="currentColor" stroke-width="1.2"/>
|
|
167
|
+
<text x="120" y="52" font-family="Georgia,serif" font-size="18" fill="currentColor">
|
|
168
|
+
<tspan font-style="italic">n</tspan><tspan font-size="12" baseline-shift="super"><tspan font-style="italic">s</tspan></tspan>
|
|
169
|
+
</text>
|
|
170
|
+
</svg>`
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
label: "bayes",
|
|
174
|
+
w: 300,
|
|
175
|
+
h: 80,
|
|
176
|
+
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 80" width="300" height="80">
|
|
177
|
+
<text x="10" y="36" font-family="Georgia,serif" font-size="22" fill="currentColor">
|
|
178
|
+
<tspan font-style="italic">P</tspan>(<tspan font-style="italic">A</tspan>|<tspan font-style="italic">B</tspan>) =
|
|
179
|
+
</text>
|
|
180
|
+
<text x="118" y="24" font-family="Georgia,serif" font-size="20" fill="currentColor">
|
|
181
|
+
<tspan font-style="italic">P</tspan>(<tspan font-style="italic">B</tspan>|<tspan font-style="italic">A</tspan>)<tspan font-style="italic">P</tspan>(<tspan font-style="italic">A</tspan>)
|
|
182
|
+
</text>
|
|
183
|
+
<line x1="116" y1="32" x2="258" y2="32" stroke="currentColor" stroke-width="1.3"/>
|
|
184
|
+
<text x="162" y="56" font-family="Georgia,serif" font-size="20" fill="currentColor">
|
|
185
|
+
<tspan font-style="italic">P</tspan>(<tspan font-style="italic">B</tspan>)
|
|
186
|
+
</text>
|
|
187
|
+
</svg>`
|
|
188
|
+
}
|
|
189
|
+
];
|
|
190
|
+
var DEFAULT_COLORS = [
|
|
191
|
+
"#313695",
|
|
192
|
+
"#4575b4",
|
|
193
|
+
"#74add1",
|
|
194
|
+
"#abd9e9",
|
|
195
|
+
"#fee090",
|
|
196
|
+
"#fdae61",
|
|
197
|
+
"#f46d43",
|
|
198
|
+
"#d73027",
|
|
199
|
+
"#a50026",
|
|
200
|
+
"#ffffff"
|
|
201
|
+
];
|
|
202
|
+
|
|
203
|
+
export {
|
|
204
|
+
EQUATIONS,
|
|
205
|
+
DEFAULT_COLORS
|
|
206
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -2,10 +2,14 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
|
|
3
3
|
type Props = {
|
|
4
4
|
backgroundColor?: string;
|
|
5
|
+
blur?: boolean;
|
|
5
6
|
colors?: string[];
|
|
6
7
|
density?: number;
|
|
7
8
|
reverse?: boolean;
|
|
9
|
+
speed?: number;
|
|
10
|
+
fadeIn?: boolean;
|
|
11
|
+
fadeInDuration?: number;
|
|
8
12
|
};
|
|
9
|
-
declare const MathParticlesOverlay: ({ backgroundColor, colors, density, reverse, }: Props) => react_jsx_runtime.JSX.Element;
|
|
13
|
+
declare const MathParticlesOverlay: ({ backgroundColor, blur, colors, density, reverse, speed, fadeIn, fadeInDuration, }: Props) => react_jsx_runtime.JSX.Element;
|
|
10
14
|
|
|
11
15
|
export { MathParticlesOverlay };
|
package/dist/index.js
CHANGED
|
@@ -1,338 +1,138 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_COLORS,
|
|
3
|
+
EQUATIONS
|
|
4
|
+
} from "./chunk-7SB7KDRV.js";
|
|
5
|
+
|
|
1
6
|
// src/MathParticlesOverlay.tsx
|
|
2
7
|
import { useEffect, useRef } from "react";
|
|
3
8
|
import { jsx } from "react/jsx-runtime";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
<tspan> + </tspan>
|
|
25
|
-
<tspan font-style="italic">b</tspan><tspan font-size="22" baseline-shift="super">2</tspan>
|
|
26
|
-
<tspan> = </tspan>
|
|
27
|
-
<tspan font-style="italic">c</tspan><tspan font-size="22" baseline-shift="super">2</tspan>
|
|
28
|
-
</text>
|
|
29
|
-
</svg>`
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
label: "quadratic",
|
|
33
|
-
w: 310,
|
|
34
|
-
h: 80,
|
|
35
|
-
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 310 80" width="310" height="80">
|
|
36
|
-
<text x="10" y="32" font-family="Georgia,serif" font-size="22" fill="currentColor">
|
|
37
|
-
<tspan font-style="italic">x</tspan><tspan> = </tspan>
|
|
38
|
-
<tspan>−</tspan><tspan font-style="italic">b</tspan>
|
|
39
|
-
<tspan> ± </tspan>
|
|
40
|
-
<tspan>√(</tspan><tspan font-style="italic">b</tspan>
|
|
41
|
-
<tspan font-size="14" baseline-shift="super">2</tspan>
|
|
42
|
-
<tspan> − 4</tspan><tspan font-style="italic">ac</tspan><tspan>)</tspan>
|
|
43
|
-
</text>
|
|
44
|
-
<line x1="127" y1="40" x2="295" y2="40" stroke="currentColor" stroke-width="1.5"/>
|
|
45
|
-
<text x="195" y="65" font-family="Georgia,serif" font-size="22" fill="currentColor">2<tspan font-style="italic">a</tspan></text>
|
|
46
|
-
</svg>`
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
label: "einstein",
|
|
50
|
-
w: 180,
|
|
51
|
-
h: 60,
|
|
52
|
-
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 60" width="180" height="60">
|
|
53
|
-
<text x="10" y="44" font-family="Georgia,serif" font-size="38" fill="currentColor">
|
|
54
|
-
<tspan font-style="italic">E</tspan>
|
|
55
|
-
<tspan> = </tspan>
|
|
56
|
-
<tspan font-style="italic">mc</tspan>
|
|
57
|
-
<tspan font-size="22" baseline-shift="super">2</tspan>
|
|
58
|
-
</text>
|
|
59
|
-
</svg>`
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
label: "fourier",
|
|
63
|
-
w: 330,
|
|
64
|
-
h: 80,
|
|
65
|
-
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 330 80" width="330" height="80">
|
|
66
|
-
<text x="10" y="32" font-family="Georgia,serif" font-size="20" fill="currentColor">
|
|
67
|
-
<tspan font-style="italic">F</tspan><tspan>(ξ) = </tspan>
|
|
68
|
-
</text>
|
|
69
|
-
<text x="90" y="22" font-family="Georgia,serif" font-size="30" fill="currentColor">∫</text>
|
|
70
|
-
<text x="67" y="22" font-family="Georgia,serif" font-size="13" fill="currentColor">+∞</text>
|
|
71
|
-
<text x="67" y="38" font-family="Georgia,serif" font-size="13" fill="currentColor">−∞</text>
|
|
72
|
-
<text x="115" y="32" font-family="Georgia,serif" font-size="20" fill="currentColor">
|
|
73
|
-
<tspan font-style="italic">f</tspan><tspan>(</tspan><tspan font-style="italic">x</tspan><tspan>)</tspan>
|
|
74
|
-
<tspan font-style="italic"> e</tspan>
|
|
75
|
-
<tspan font-size="13" baseline-shift="super">−2πiξ</tspan>
|
|
76
|
-
<tspan font-style="italic" font-size="13" baseline-shift="super">x</tspan>
|
|
77
|
-
<tspan> d</tspan><tspan font-style="italic">x</tspan>
|
|
78
|
-
</text>
|
|
79
|
-
</svg>`
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
label: "schrodinger",
|
|
83
|
-
w: 220,
|
|
84
|
-
h: 80,
|
|
85
|
-
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 80" width="220" height="80">
|
|
86
|
-
<text x="10" y="38" font-family="Georgia,serif" font-size="24" fill="currentColor">
|
|
87
|
-
<tspan font-style="italic">i</tspan><tspan>ℏ</tspan>
|
|
88
|
-
</text>
|
|
89
|
-
<text x="44" y="26" font-family="Georgia,serif" font-size="20" fill="currentColor">∂Ψ</text>
|
|
90
|
-
<line x1="42" y1="32" x2="80" y2="32" stroke="currentColor" stroke-width="1.4"/>
|
|
91
|
-
<text x="46" y="52" font-family="Georgia,serif" font-size="20" fill="currentColor">∂<tspan font-style="italic">t</tspan></text>
|
|
92
|
-
<text x="86" y="38" font-family="Georgia,serif" font-size="24" fill="currentColor"> = ĤΨ</text>
|
|
93
|
-
</svg>`
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
label: "gaussian",
|
|
97
|
-
w: 240,
|
|
98
|
-
h: 80,
|
|
99
|
-
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 80" width="240" height="80">
|
|
100
|
-
<text x="22" y="22" font-family="Georgia,serif" font-size="30" fill="currentColor">∫</text>
|
|
101
|
-
<text x="10" y="20" font-family="Georgia,serif" font-size="13" fill="currentColor">+∞</text>
|
|
102
|
-
<text x="10" y="48" font-family="Georgia,serif" font-size="13" fill="currentColor">−∞</text>
|
|
103
|
-
<text x="50" y="38" font-family="Georgia,serif" font-size="24" fill="currentColor">
|
|
104
|
-
<tspan font-style="italic">e</tspan>
|
|
105
|
-
<tspan font-size="15" baseline-shift="super">−<tspan font-style="italic">x</tspan><tspan font-size="10">2</tspan></tspan>
|
|
106
|
-
<tspan> d</tspan><tspan font-style="italic">x</tspan><tspan> = √π</tspan>
|
|
107
|
-
</text>
|
|
108
|
-
</svg>`
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
label: "taylor",
|
|
112
|
-
w: 320,
|
|
113
|
-
h: 80,
|
|
114
|
-
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 80" width="320" height="80">
|
|
115
|
-
<text x="10" y="38" font-family="Georgia,serif" font-size="22" fill="currentColor">
|
|
116
|
-
<tspan font-style="italic">f</tspan><tspan>(</tspan><tspan font-style="italic">x</tspan><tspan>) = </tspan>
|
|
117
|
-
</text>
|
|
118
|
-
<text x="90" y="18" font-family="Georgia,serif" font-size="15" fill="currentColor">∞</text>
|
|
119
|
-
<text x="88" y="36" font-family="Georgia,serif" font-size="28" fill="currentColor">∑</text>
|
|
120
|
-
<text x="83" y="56" font-family="Georgia,serif" font-size="14" fill="currentColor"><tspan font-style="italic">n</tspan>=0</text>
|
|
121
|
-
<text x="126" y="26" font-family="Georgia,serif" font-size="17" fill="currentColor">
|
|
122
|
-
<tspan font-style="italic">f</tspan><tspan font-size="12" baseline-shift="super">(<tspan font-style="italic">n</tspan>)</tspan>(<tspan font-style="italic">a</tspan>)
|
|
123
|
-
</text>
|
|
124
|
-
<line x1="124" y1="32" x2="178" y2="32" stroke="currentColor" stroke-width="1.2"/>
|
|
125
|
-
<text x="138" y="52" font-family="Georgia,serif" font-size="17" fill="currentColor">
|
|
126
|
-
<tspan font-style="italic">n</tspan><tspan>!</tspan>
|
|
127
|
-
</text>
|
|
128
|
-
<text x="184" y="38" font-family="Georgia,serif" font-size="22" fill="currentColor">
|
|
129
|
-
(<tspan font-style="italic">x−a</tspan>)<tspan font-size="14" baseline-shift="super"><tspan font-style="italic">n</tspan></tspan>
|
|
130
|
-
</text>
|
|
131
|
-
</svg>`
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
label: "navier-stokes",
|
|
135
|
-
w: 370,
|
|
136
|
-
h: 60,
|
|
137
|
-
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 370 60" width="370" height="60">
|
|
138
|
-
<text x="10" y="40" font-family="Georgia,serif" font-size="22" fill="currentColor">
|
|
139
|
-
ρ(∂<tspan font-style="italic">t</tspan><tspan font-weight="bold" font-style="italic">u</tspan> + <tspan font-style="italic">u</tspan>⋅∇<tspan font-style="italic">u</tspan>) = −∇<tspan font-style="italic">p</tspan> + μ∇<tspan font-size="16" baseline-shift="super">2</tspan><tspan font-weight="bold" font-style="italic">u</tspan>
|
|
140
|
-
</text>
|
|
141
|
-
</svg>`
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
label: "maxwell",
|
|
145
|
-
w: 210,
|
|
146
|
-
h: 70,
|
|
147
|
-
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 210 70" width="210" height="70">
|
|
148
|
-
<text x="10" y="44" font-family="Georgia,serif" font-size="30" fill="currentColor">
|
|
149
|
-
∇ ⋅ <tspan font-weight="bold" font-style="italic">E</tspan> =
|
|
150
|
-
</text>
|
|
151
|
-
<text x="136" y="32" font-family="Georgia,serif" font-size="22" fill="currentColor">ρ</text>
|
|
152
|
-
<line x1="134" y1="38" x2="165" y2="38" stroke="currentColor" stroke-width="1.4"/>
|
|
153
|
-
<text x="136" y="58" font-family="Georgia,serif" font-size="22" fill="currentColor">ε<tspan font-size="14" baseline-shift="sub">0</tspan></text>
|
|
154
|
-
</svg>`
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
label: "riemann",
|
|
158
|
-
w: 200,
|
|
159
|
-
h: 80,
|
|
160
|
-
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 80" width="200" height="80">
|
|
161
|
-
<text x="10" y="38" font-family="Georgia,serif" font-size="22" fill="currentColor">
|
|
162
|
-
ζ(<tspan font-style="italic">s</tspan>) =
|
|
163
|
-
</text>
|
|
164
|
-
<text x="85" y="18" font-family="Georgia,serif" font-size="15" fill="currentColor">∞</text>
|
|
165
|
-
<text x="82" y="36" font-family="Georgia,serif" font-size="28" fill="currentColor">∑</text>
|
|
166
|
-
<text x="78" y="56" font-family="Georgia,serif" font-size="14" fill="currentColor"><tspan font-style="italic">n</tspan>=1</text>
|
|
167
|
-
<text x="120" y="26" font-family="Georgia,serif" font-size="18" fill="currentColor">1</text>
|
|
168
|
-
<line x1="118" y1="32" x2="152" y2="32" stroke="currentColor" stroke-width="1.2"/>
|
|
169
|
-
<text x="120" y="52" font-family="Georgia,serif" font-size="18" fill="currentColor">
|
|
170
|
-
<tspan font-style="italic">n</tspan><tspan font-size="12" baseline-shift="super"><tspan font-style="italic">s</tspan></tspan>
|
|
171
|
-
</text>
|
|
172
|
-
</svg>`
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
label: "bayes",
|
|
176
|
-
w: 300,
|
|
177
|
-
h: 80,
|
|
178
|
-
svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 80" width="300" height="80">
|
|
179
|
-
<text x="10" y="36" font-family="Georgia,serif" font-size="22" fill="currentColor">
|
|
180
|
-
<tspan font-style="italic">P</tspan>(<tspan font-style="italic">A</tspan>|<tspan font-style="italic">B</tspan>) =
|
|
181
|
-
</text>
|
|
182
|
-
<text x="118" y="24" font-family="Georgia,serif" font-size="20" fill="currentColor">
|
|
183
|
-
<tspan font-style="italic">P</tspan>(<tspan font-style="italic">B</tspan>|<tspan font-style="italic">A</tspan>)<tspan font-style="italic">P</tspan>(<tspan font-style="italic">A</tspan>)
|
|
184
|
-
</text>
|
|
185
|
-
<line x1="116" y1="32" x2="258" y2="32" stroke="currentColor" stroke-width="1.3"/>
|
|
186
|
-
<text x="162" y="56" font-family="Georgia,serif" font-size="20" fill="currentColor">
|
|
187
|
-
<tspan font-style="italic">P</tspan>(<tspan font-style="italic">B</tspan>)
|
|
188
|
-
</text>
|
|
189
|
-
</svg>`
|
|
190
|
-
}
|
|
191
|
-
];
|
|
192
|
-
var DEFAULT_COLORS = [
|
|
193
|
-
"#313695",
|
|
194
|
-
"#4575b4",
|
|
195
|
-
"#74add1",
|
|
196
|
-
"#abd9e9",
|
|
197
|
-
"#fee090",
|
|
198
|
-
"#fdae61",
|
|
199
|
-
"#f46d43",
|
|
200
|
-
"#d73027",
|
|
201
|
-
"#a50026",
|
|
202
|
-
"#ffffff"
|
|
203
|
-
];
|
|
204
|
-
function rand(a, b) {
|
|
205
|
-
return a + Math.random() * (b - a);
|
|
206
|
-
}
|
|
207
|
-
function easeIn(t) {
|
|
208
|
-
return t * t * t;
|
|
209
|
-
}
|
|
210
|
-
function fadeEnvelope(t, fi = 0.18, fo = 0.78) {
|
|
211
|
-
if (t < fi) return t / fi;
|
|
212
|
-
if (t < fo) return 1;
|
|
213
|
-
return 1 - (t - fo) / (1 - fo);
|
|
214
|
-
}
|
|
215
|
-
function applyEquation(el, eq, color) {
|
|
216
|
-
el.innerHTML = eq.svg;
|
|
217
|
-
const svg = el.querySelector("svg");
|
|
218
|
-
if (svg) svg.style.color = color;
|
|
219
|
-
el.style.width = `${eq.w}px`;
|
|
220
|
-
el.style.height = `${eq.h}px`;
|
|
221
|
-
el.style.filter = `drop-shadow(0 0 7px ${color}aa)`;
|
|
222
|
-
}
|
|
223
|
-
function createParticle(el, w, h, staggerT, colors) {
|
|
224
|
-
const eq = EQUATIONS[Math.floor(Math.random() * EQUATIONS.length)];
|
|
225
|
-
const color = colors[Math.floor(Math.random() * colors.length)];
|
|
226
|
-
applyEquation(el, eq, color);
|
|
227
|
-
return {
|
|
228
|
-
el,
|
|
229
|
-
eq,
|
|
230
|
-
color,
|
|
231
|
-
vx: w * rand(0.35, 0.65),
|
|
232
|
-
vy: h * rand(0.35, 0.65),
|
|
233
|
-
angle: rand(0, Math.PI * 2),
|
|
234
|
-
maxDist: rand(Math.min(w, h) * 0.25, Math.min(w, h) * 0.7),
|
|
235
|
-
scaleStart: rand(0.04, 0.1),
|
|
236
|
-
scaleEnd: rand(1.4, 2.8),
|
|
237
|
-
peakOpacity: rand(0.5, 0.85),
|
|
238
|
-
duration: rand(5e3, 11e3),
|
|
239
|
-
startTime: null,
|
|
240
|
-
t: staggerT
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
function resetParticle(p, w, h, colors) {
|
|
244
|
-
const eq = EQUATIONS[Math.floor(Math.random() * EQUATIONS.length)];
|
|
245
|
-
const color = colors[Math.floor(Math.random() * colors.length)];
|
|
246
|
-
p.eq = eq;
|
|
247
|
-
p.color = color;
|
|
248
|
-
p.vx = w * rand(0.35, 0.65);
|
|
249
|
-
p.vy = h * rand(0.35, 0.65);
|
|
250
|
-
p.angle = rand(0, Math.PI * 2);
|
|
251
|
-
p.maxDist = rand(Math.min(w, h) * 0.25, Math.min(w, h) * 0.7);
|
|
252
|
-
p.scaleStart = rand(0.04, 0.1);
|
|
253
|
-
p.scaleEnd = rand(1.4, 2.8);
|
|
254
|
-
p.peakOpacity = rand(0.5, 0.85);
|
|
255
|
-
p.duration = rand(5e3, 11e3);
|
|
256
|
-
p.startTime = null;
|
|
257
|
-
p.t = 0;
|
|
258
|
-
applyEquation(p.el, eq, color);
|
|
259
|
-
}
|
|
260
|
-
function updateParticle(p, now, w, h, reverse, colors) {
|
|
261
|
-
if (p.startTime === null) {
|
|
262
|
-
p.startTime = now - p.t * p.duration;
|
|
263
|
-
}
|
|
264
|
-
let t = (now - p.startTime) / p.duration;
|
|
265
|
-
if (t >= 1) {
|
|
266
|
-
resetParticle(p, w, h, colors);
|
|
267
|
-
p.startTime = now;
|
|
268
|
-
t = 0;
|
|
269
|
-
}
|
|
270
|
-
const tz = easeIn(reverse ? 1 - t : t);
|
|
271
|
-
const scale = p.scaleStart + (p.scaleEnd - p.scaleStart) * tz;
|
|
272
|
-
const dist = p.maxDist * tz;
|
|
273
|
-
const cx = p.vx + Math.cos(p.angle) * dist;
|
|
274
|
-
const cy = p.vy + Math.sin(p.angle) * dist;
|
|
275
|
-
p.el.style.left = `${cx - p.eq.w / 2}px`;
|
|
276
|
-
p.el.style.top = `${cy - p.eq.h / 2}px`;
|
|
277
|
-
p.el.style.opacity = String(p.peakOpacity * fadeEnvelope(t, 0.12, 0.75));
|
|
278
|
-
p.el.style.transform = `scale(${scale})`;
|
|
279
|
-
const blur = t < 0.15 ? (0.15 - t) / 0.15 * 5 : t > 0.8 ? (t - 0.8) / 0.2 * 3 : 0;
|
|
280
|
-
p.el.style.filter = `drop-shadow(0 0 ${(6 * scale).toFixed(1)}px ${p.color}99) blur(${blur.toFixed(2)}px)`;
|
|
9
|
+
async function renderWhiteBitmaps() {
|
|
10
|
+
return Promise.all(
|
|
11
|
+
EQUATIONS.map(({ w, h, svg }) => {
|
|
12
|
+
const whiteSvg = svg.replace(/currentColor/g, "white");
|
|
13
|
+
const blob = new Blob([whiteSvg], { type: "image/svg+xml" });
|
|
14
|
+
const url = URL.createObjectURL(blob);
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
const img = new Image(w, h);
|
|
17
|
+
img.onload = () => {
|
|
18
|
+
const offscreen = new OffscreenCanvas(w, h);
|
|
19
|
+
const offCtx = offscreen.getContext("2d");
|
|
20
|
+
offCtx.drawImage(img, 0, 0, w, h);
|
|
21
|
+
resolve(offscreen.transferToImageBitmap());
|
|
22
|
+
URL.revokeObjectURL(url);
|
|
23
|
+
};
|
|
24
|
+
img.onerror = reject;
|
|
25
|
+
img.src = url;
|
|
26
|
+
});
|
|
27
|
+
})
|
|
28
|
+
);
|
|
281
29
|
}
|
|
282
30
|
var MathParticlesOverlay = ({
|
|
283
31
|
backgroundColor = "#07070f",
|
|
32
|
+
blur = true,
|
|
284
33
|
colors = DEFAULT_COLORS,
|
|
285
34
|
density = 1,
|
|
286
|
-
reverse = false
|
|
35
|
+
reverse = false,
|
|
36
|
+
speed = 1,
|
|
37
|
+
fadeIn = true,
|
|
38
|
+
fadeInDuration = 800
|
|
287
39
|
}) => {
|
|
288
|
-
const
|
|
40
|
+
const canvasRef = useRef(null);
|
|
41
|
+
const workerRef = useRef(null);
|
|
42
|
+
const blurRef = useRef(blur);
|
|
43
|
+
blurRef.current = blur;
|
|
289
44
|
const colorsRef = useRef(colors);
|
|
290
45
|
colorsRef.current = colors;
|
|
291
46
|
const reverseRef = useRef(reverse);
|
|
292
47
|
reverseRef.current = reverse;
|
|
48
|
+
const speedRef = useRef(speed);
|
|
49
|
+
speedRef.current = speed;
|
|
293
50
|
useEffect(() => {
|
|
294
|
-
const
|
|
295
|
-
if (!
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
51
|
+
const canvas = canvasRef.current;
|
|
52
|
+
if (!canvas) return;
|
|
53
|
+
const w = canvas.clientWidth;
|
|
54
|
+
const h = canvas.clientHeight;
|
|
55
|
+
canvas.width = w;
|
|
56
|
+
canvas.height = h;
|
|
57
|
+
let stopped = false;
|
|
58
|
+
renderWhiteBitmaps().then((bitmaps) => {
|
|
59
|
+
if (stopped) {
|
|
60
|
+
for (const b of bitmaps) b.close();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const offscreen = canvas.transferControlToOffscreen();
|
|
64
|
+
const worker = new Worker(new URL("./worker-entry.js", import.meta.url), {
|
|
65
|
+
type: "module"
|
|
66
|
+
});
|
|
67
|
+
workerRef.current = worker;
|
|
68
|
+
worker.postMessage(
|
|
69
|
+
{
|
|
70
|
+
type: "init",
|
|
71
|
+
canvas: offscreen,
|
|
72
|
+
bitmaps,
|
|
73
|
+
config: {
|
|
74
|
+
width: w,
|
|
75
|
+
height: h,
|
|
76
|
+
density,
|
|
77
|
+
blur: blurRef.current,
|
|
78
|
+
colors: colorsRef.current,
|
|
79
|
+
reverse: reverseRef.current,
|
|
80
|
+
speed: speedRef.current
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
[offscreen, ...bitmaps]
|
|
306
84
|
);
|
|
85
|
+
});
|
|
86
|
+
if (fadeIn) {
|
|
87
|
+
canvas.style.transition = `opacity ${fadeInDuration}ms ease`;
|
|
88
|
+
canvas.style.opacity = "0";
|
|
89
|
+
void canvas.offsetHeight;
|
|
90
|
+
canvas.style.opacity = "1";
|
|
307
91
|
}
|
|
308
|
-
let rafId;
|
|
309
|
-
const loop = (now) => {
|
|
310
|
-
for (const p of particles)
|
|
311
|
-
updateParticle(p, now, w, h, reverseRef.current, colorsRef.current);
|
|
312
|
-
rafId = requestAnimationFrame(loop);
|
|
313
|
-
};
|
|
314
|
-
rafId = requestAnimationFrame(loop);
|
|
315
92
|
const onResize = () => {
|
|
316
|
-
|
|
317
|
-
|
|
93
|
+
workerRef.current?.postMessage({
|
|
94
|
+
type: "resize",
|
|
95
|
+
width: canvas.clientWidth,
|
|
96
|
+
height: canvas.clientHeight
|
|
97
|
+
});
|
|
318
98
|
};
|
|
319
99
|
window.addEventListener("resize", onResize);
|
|
320
100
|
return () => {
|
|
321
|
-
|
|
101
|
+
stopped = true;
|
|
102
|
+
workerRef.current?.postMessage({ type: "stop" });
|
|
103
|
+
workerRef.current?.terminate();
|
|
104
|
+
workerRef.current = null;
|
|
322
105
|
window.removeEventListener("resize", onResize);
|
|
323
|
-
container.innerHTML = "";
|
|
324
106
|
};
|
|
325
107
|
}, []);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
workerRef.current?.postMessage({
|
|
110
|
+
type: "config",
|
|
111
|
+
config: { blur, colors, reverse, speed }
|
|
112
|
+
});
|
|
113
|
+
}, [blur, colors, reverse, speed]);
|
|
326
114
|
return /* @__PURE__ */ jsx(
|
|
327
115
|
"div",
|
|
328
116
|
{
|
|
329
|
-
|
|
117
|
+
inert: true,
|
|
330
118
|
style: {
|
|
331
|
-
|
|
332
|
-
inset: 0,
|
|
119
|
+
backgroundColor,
|
|
333
120
|
overflow: "hidden",
|
|
334
|
-
|
|
335
|
-
|
|
121
|
+
position: "absolute",
|
|
122
|
+
inset: 0
|
|
123
|
+
},
|
|
124
|
+
children: /* @__PURE__ */ jsx(
|
|
125
|
+
"canvas",
|
|
126
|
+
{
|
|
127
|
+
ref: canvasRef,
|
|
128
|
+
style: {
|
|
129
|
+
position: "absolute",
|
|
130
|
+
inset: 0,
|
|
131
|
+
height: "100%",
|
|
132
|
+
width: "100%"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
)
|
|
336
136
|
}
|
|
337
137
|
);
|
|
338
138
|
};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EQUATIONS
|
|
3
|
+
} from "./chunk-7SB7KDRV.js";
|
|
4
|
+
|
|
5
|
+
// src/worker-entry.ts
|
|
6
|
+
var canvas;
|
|
7
|
+
var ctx;
|
|
8
|
+
var whiteBitmaps;
|
|
9
|
+
var particles = [];
|
|
10
|
+
var config;
|
|
11
|
+
var loopId;
|
|
12
|
+
function rand(a, b) {
|
|
13
|
+
return a + Math.random() * (b - a);
|
|
14
|
+
}
|
|
15
|
+
function easeIn(t) {
|
|
16
|
+
return t * t * t;
|
|
17
|
+
}
|
|
18
|
+
function fadeEnvelope(t, fi = 0.18, fo = 0.78) {
|
|
19
|
+
if (t < fi) return t / fi;
|
|
20
|
+
if (t < fo) return 1;
|
|
21
|
+
return 1 - (t - fo) / (1 - fo);
|
|
22
|
+
}
|
|
23
|
+
function tintBitmap(white, color, w, h) {
|
|
24
|
+
const temp = new OffscreenCanvas(w, h);
|
|
25
|
+
const tempCtx = temp.getContext("2d");
|
|
26
|
+
tempCtx.drawImage(white, 0, 0, w, h);
|
|
27
|
+
tempCtx.globalCompositeOperation = "source-atop";
|
|
28
|
+
tempCtx.fillStyle = color;
|
|
29
|
+
tempCtx.fillRect(0, 0, w, h);
|
|
30
|
+
return temp.transferToImageBitmap();
|
|
31
|
+
}
|
|
32
|
+
function createParticle(w, h, staggerT, colors, speed) {
|
|
33
|
+
const eqIndex = Math.floor(Math.random() * EQUATIONS.length);
|
|
34
|
+
const eq = EQUATIONS[eqIndex];
|
|
35
|
+
const color = colors[Math.floor(Math.random() * colors.length)];
|
|
36
|
+
return {
|
|
37
|
+
bitmap: tintBitmap(whiteBitmaps[eqIndex], color, eq.w, eq.h),
|
|
38
|
+
eqIndex,
|
|
39
|
+
color,
|
|
40
|
+
vx: w * rand(0.35, 0.65),
|
|
41
|
+
vy: h * rand(0.35, 0.65),
|
|
42
|
+
angle: rand(0, Math.PI * 2),
|
|
43
|
+
maxDist: rand(Math.min(w, h) * 0.25, Math.min(w, h) * 0.7),
|
|
44
|
+
scaleStart: rand(0.04, 0.1),
|
|
45
|
+
scaleEnd: rand(1.4, 2.8),
|
|
46
|
+
peakOpacity: rand(0.5, 0.85),
|
|
47
|
+
duration: rand(5e3, 11e3) / speed,
|
|
48
|
+
startTime: null,
|
|
49
|
+
t: staggerT
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function resetParticle(p, w, h, colors, speed) {
|
|
53
|
+
p.bitmap.close();
|
|
54
|
+
p.eqIndex = Math.floor(Math.random() * EQUATIONS.length);
|
|
55
|
+
const eq = EQUATIONS[p.eqIndex];
|
|
56
|
+
p.color = colors[Math.floor(Math.random() * colors.length)];
|
|
57
|
+
p.bitmap = tintBitmap(whiteBitmaps[p.eqIndex], p.color, eq.w, eq.h);
|
|
58
|
+
p.vx = w * rand(0.35, 0.65);
|
|
59
|
+
p.vy = h * rand(0.35, 0.65);
|
|
60
|
+
p.angle = rand(0, Math.PI * 2);
|
|
61
|
+
p.maxDist = rand(Math.min(w, h) * 0.25, Math.min(w, h) * 0.7);
|
|
62
|
+
p.scaleStart = rand(0.04, 0.1);
|
|
63
|
+
p.scaleEnd = rand(1.4, 2.8);
|
|
64
|
+
p.peakOpacity = rand(0.5, 0.85);
|
|
65
|
+
p.duration = rand(5e3, 11e3) / speed;
|
|
66
|
+
p.startTime = null;
|
|
67
|
+
p.t = 0;
|
|
68
|
+
}
|
|
69
|
+
function drawParticle(p, now) {
|
|
70
|
+
const eq = EQUATIONS[p.eqIndex];
|
|
71
|
+
const w = canvas.width;
|
|
72
|
+
const h = canvas.height;
|
|
73
|
+
if (p.startTime === null) {
|
|
74
|
+
p.startTime = now - p.t * p.duration;
|
|
75
|
+
}
|
|
76
|
+
let t = (now - p.startTime) / p.duration;
|
|
77
|
+
if (t >= 1) {
|
|
78
|
+
resetParticle(p, w, h, config.colors, config.speed);
|
|
79
|
+
p.startTime = now;
|
|
80
|
+
t = 0;
|
|
81
|
+
}
|
|
82
|
+
const tz = easeIn(config.reverse ? 1 - t : t);
|
|
83
|
+
const scale = p.scaleStart + (p.scaleEnd - p.scaleStart) * tz;
|
|
84
|
+
const dist = p.maxDist * tz;
|
|
85
|
+
const cx = p.vx + Math.cos(p.angle) * dist;
|
|
86
|
+
const cy = p.vy + Math.sin(p.angle) * dist;
|
|
87
|
+
const opacity = p.peakOpacity * fadeEnvelope(t, 0.12, 0.75);
|
|
88
|
+
ctx.save();
|
|
89
|
+
ctx.globalAlpha = opacity;
|
|
90
|
+
ctx.shadowColor = p.color + "99";
|
|
91
|
+
ctx.shadowBlur = 6 * scale;
|
|
92
|
+
if (config.blur) {
|
|
93
|
+
const blurAmount = t < 0.15 ? (0.15 - t) / 0.15 * 5 : t > 0.8 ? (t - 0.8) / 0.2 * 3 : 0;
|
|
94
|
+
if (blurAmount > 0) ctx.filter = `blur(${blurAmount.toFixed(1)}px)`;
|
|
95
|
+
}
|
|
96
|
+
ctx.translate(cx, cy);
|
|
97
|
+
ctx.scale(scale, scale);
|
|
98
|
+
ctx.drawImage(p.bitmap, -eq.w / 2, -eq.h / 2, eq.w, eq.h);
|
|
99
|
+
ctx.restore();
|
|
100
|
+
}
|
|
101
|
+
function initParticles() {
|
|
102
|
+
for (const p of particles) p.bitmap.close();
|
|
103
|
+
particles = [];
|
|
104
|
+
const { width, height, density, colors, speed } = config;
|
|
105
|
+
const count = Math.max(1, Math.floor(width * height / 55e3 * density));
|
|
106
|
+
for (let i = 0; i < count; i++) {
|
|
107
|
+
particles.push(createParticle(width, height, Math.random(), colors, speed));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function loop() {
|
|
111
|
+
const now = performance.now();
|
|
112
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
113
|
+
for (const p of particles) drawParticle(p, now);
|
|
114
|
+
loopId = setTimeout(loop, 0);
|
|
115
|
+
}
|
|
116
|
+
self.onmessage = (e) => {
|
|
117
|
+
const { type } = e.data;
|
|
118
|
+
if (type === "init") {
|
|
119
|
+
canvas = e.data.canvas;
|
|
120
|
+
ctx = canvas.getContext("2d");
|
|
121
|
+
whiteBitmaps = e.data.bitmaps;
|
|
122
|
+
config = e.data.config;
|
|
123
|
+
canvas.width = config.width;
|
|
124
|
+
canvas.height = config.height;
|
|
125
|
+
initParticles();
|
|
126
|
+
loop();
|
|
127
|
+
} else if (type === "config") {
|
|
128
|
+
config = { ...config, ...e.data.config };
|
|
129
|
+
} else if (type === "resize") {
|
|
130
|
+
canvas.width = e.data.width;
|
|
131
|
+
canvas.height = e.data.height;
|
|
132
|
+
config.width = canvas.width;
|
|
133
|
+
config.height = canvas.height;
|
|
134
|
+
initParticles();
|
|
135
|
+
} else if (type === "stop") {
|
|
136
|
+
clearTimeout(loopId);
|
|
137
|
+
for (const p of particles) p.bitmap.close();
|
|
138
|
+
particles = [];
|
|
139
|
+
}
|
|
140
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slithy/math-particles",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Animated math equations particle overlay for React.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"clean": "rm -rf dist",
|
|
59
|
-
"build": "rm -rf dist && tsup src/index.ts --format esm --dts",
|
|
60
|
-
"dev": "tsup src/index.ts --format esm --watch",
|
|
59
|
+
"build": "rm -rf dist && tsup src/index.ts src/worker-entry.ts --format esm --dts",
|
|
60
|
+
"dev": "tsup src/index.ts src/worker-entry.ts --format esm --watch",
|
|
61
61
|
"typecheck": "tsc --noEmit",
|
|
62
62
|
"lint": "eslint .",
|
|
63
63
|
"test": "vitest run",
|