@basmilius/sparkle 2.1.0 → 2.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/dist/index.d.mts +306 -459
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1106 -848
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -2
- package/src/aurora/index.ts +9 -3
- package/src/aurora/layer.ts +57 -29
- package/src/balloons/index.ts +9 -3
- package/src/balloons/layer.ts +50 -19
- package/src/bubbles/index.ts +9 -3
- package/src/bubbles/layer.ts +30 -17
- package/src/canvas.ts +12 -0
- package/src/color.ts +11 -2
- package/src/confetti/index.ts +15 -3
- package/src/confetti/layer.ts +8 -5
- package/src/confetti/particle.ts +12 -11
- package/src/donuts/consts.ts +2 -2
- package/src/donuts/index.ts +9 -3
- package/src/donuts/layer.ts +43 -12
- package/src/effect.ts +107 -0
- package/src/fade.ts +87 -0
- package/src/fireflies/index.ts +9 -3
- package/src/fireflies/layer.ts +26 -9
- package/src/fireflies/particle.ts +2 -2
- package/src/firepit/index.ts +9 -3
- package/src/firepit/layer.ts +26 -7
- package/src/fireworks/create-explosion.ts +237 -0
- package/src/fireworks/explosion.ts +1 -1
- package/src/fireworks/index.ts +15 -3
- package/src/fireworks/layer.ts +55 -304
- package/src/fireworks/spark.ts +2 -2
- package/src/fireworks/types.ts +2 -2
- package/src/glitter/index.ts +9 -4
- package/src/glitter/layer.ts +15 -7
- package/src/glitter/types.ts +10 -0
- package/src/index.ts +3 -4
- package/src/lanterns/index.ts +9 -4
- package/src/lanterns/layer.ts +22 -10
- package/src/lanterns/types.ts +8 -0
- package/src/layer.ts +13 -11
- package/src/leaves/index.ts +9 -4
- package/src/leaves/layer.ts +21 -14
- package/src/leaves/types.ts +9 -0
- package/src/lightning/index.ts +9 -4
- package/src/lightning/layer.ts +4 -4
- package/src/lightning/system.ts +3 -3
- package/src/lightning/types.ts +10 -2
- package/src/matrix/index.ts +9 -4
- package/src/matrix/layer.ts +15 -7
- package/src/matrix/types.ts +9 -0
- package/src/orbits/index.ts +9 -4
- package/src/orbits/layer.ts +51 -21
- package/src/orbits/types.ts +12 -1
- package/src/particles/index.ts +9 -3
- package/src/particles/layer.ts +55 -12
- package/src/petals/index.ts +9 -3
- package/src/petals/layer.ts +29 -13
- package/src/plasma/index.ts +9 -3
- package/src/plasma/layer.ts +21 -6
- package/src/rain/index.ts +9 -3
- package/src/rain/layer.ts +30 -8
- package/src/sandstorm/index.ts +9 -3
- package/src/sandstorm/layer.ts +26 -9
- package/src/scene.ts +201 -0
- package/src/shooting-stars/system.ts +26 -24
- package/src/shooting-stars/types.ts +2 -1
- package/src/simulation-canvas.ts +40 -4
- package/src/snow/index.ts +9 -3
- package/src/snow/layer.ts +24 -11
- package/src/sparklers/index.ts +13 -3
- package/src/sparklers/layer.ts +61 -15
- package/src/stars/index.ts +9 -3
- package/src/stars/layer.ts +28 -22
- package/src/streamers/index.ts +9 -3
- package/src/streamers/layer.ts +18 -6
- package/src/streamers/types.ts +1 -1
- package/src/waves/index.ts +9 -3
- package/src/waves/layer.ts +42 -45
- package/src/waves/types.ts +1 -0
- package/src/wormhole/index.ts +9 -3
- package/src/wormhole/layer.ts +22 -6
- package/src/aurora/simulation.ts +0 -19
- package/src/balloons/simulation.ts +0 -19
- package/src/bubbles/simulation.ts +0 -20
- package/src/confetti/simulation.ts +0 -27
- package/src/donuts/simulation.ts +0 -25
- package/src/fireflies/simulation.ts +0 -18
- package/src/firepit/simulation.ts +0 -17
- package/src/fireworks/simulation.ts +0 -18
- package/src/glitter/simulation.ts +0 -19
- package/src/lanterns/simulation.ts +0 -17
- package/src/layered.ts +0 -185
- package/src/leaves/simulation.ts +0 -18
- package/src/lightning/simulation.ts +0 -17
- package/src/matrix/simulation.ts +0 -18
- package/src/orbits/simulation.ts +0 -19
- package/src/particles/simulation.ts +0 -26
- package/src/petals/simulation.ts +0 -18
- package/src/plasma/simulation.ts +0 -17
- package/src/rain/simulation.ts +0 -21
- package/src/sandstorm/simulation.ts +0 -18
- package/src/snow/simulation.ts +0 -17
- package/src/sparklers/simulation.ts +0 -30
- package/src/stars/simulation.ts +0 -22
- package/src/streamers/simulation.ts +0 -16
- package/src/waves/simulation.ts +0 -18
- package/src/wormhole/simulation.ts +0 -17
package/dist/index.mjs
CHANGED
|
@@ -1,132 +1,4 @@
|
|
|
1
1
|
import { hexToRGB, mulberry32 } from "@basmilius/utils";
|
|
2
|
-
//#region src/layer.ts
|
|
3
|
-
var SimulationLayer = class {
|
|
4
|
-
fade = null;
|
|
5
|
-
onResize(_width, _height) {}
|
|
6
|
-
onMount(_canvas) {}
|
|
7
|
-
onUnmount(_canvas) {}
|
|
8
|
-
withFade(fade) {
|
|
9
|
-
this.fade = fade;
|
|
10
|
-
return this;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
//#endregion
|
|
14
|
-
//#region src/aurora/consts.ts
|
|
15
|
-
const MULBERRY$23 = mulberry32(13);
|
|
16
|
-
//#endregion
|
|
17
|
-
//#region src/aurora/layer.ts
|
|
18
|
-
const DEFAULT_COLORS$4 = [
|
|
19
|
-
"#9922ff",
|
|
20
|
-
"#4455ff",
|
|
21
|
-
"#0077ee",
|
|
22
|
-
"#00aabb",
|
|
23
|
-
"#22ddff"
|
|
24
|
-
];
|
|
25
|
-
const TOP_HUE = 265;
|
|
26
|
-
var AuroraLayer = class extends SimulationLayer {
|
|
27
|
-
#speed;
|
|
28
|
-
#intensity;
|
|
29
|
-
#waveAmplitude;
|
|
30
|
-
#verticalPosition;
|
|
31
|
-
#time = 0;
|
|
32
|
-
#bands = [];
|
|
33
|
-
constructor(config = {}) {
|
|
34
|
-
super();
|
|
35
|
-
const bandCount = config.bands ?? 5;
|
|
36
|
-
const colors = config.colors ?? DEFAULT_COLORS$4;
|
|
37
|
-
this.#speed = config.speed ?? 1;
|
|
38
|
-
this.#intensity = config.intensity ?? .8;
|
|
39
|
-
this.#waveAmplitude = config.waveAmplitude ?? 1;
|
|
40
|
-
this.#verticalPosition = config.verticalPosition ?? .68;
|
|
41
|
-
const clusterCenters = [.35, .65];
|
|
42
|
-
for (let i = 0; i < bandCount; i++) {
|
|
43
|
-
const color = colors[i % colors.length];
|
|
44
|
-
const [r, g, b] = hexToRGB(color);
|
|
45
|
-
const hue = this.#rgbToHue(r, g, b);
|
|
46
|
-
const cluster = clusterCenters[i % clusterCenters.length];
|
|
47
|
-
this.#bands.push({
|
|
48
|
-
x: cluster + (MULBERRY$23.next() - .5) * .22,
|
|
49
|
-
baseY: this.#verticalPosition + (MULBERRY$23.next() - .5) * .08,
|
|
50
|
-
height: .5 + MULBERRY$23.next() * .3,
|
|
51
|
-
sigma: 160 + MULBERRY$23.next() * 110,
|
|
52
|
-
phase1: MULBERRY$23.next() * Math.PI * 2,
|
|
53
|
-
phase2: MULBERRY$23.next() * Math.PI * 2,
|
|
54
|
-
amplitude1: .015 + MULBERRY$23.next() * .025,
|
|
55
|
-
frequency1: .003 + MULBERRY$23.next() * .004,
|
|
56
|
-
speed: (.4 + MULBERRY$23.next() * .6) * this.#speed,
|
|
57
|
-
hue,
|
|
58
|
-
opacity: (.5 + MULBERRY$23.next() * .3) * this.#intensity
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
tick(dt, width, height) {
|
|
63
|
-
this.#time += .016 * dt * this.#speed;
|
|
64
|
-
for (const band of this.#bands) {
|
|
65
|
-
band.phase1 += .005 * band.speed * dt;
|
|
66
|
-
band.phase2 += .008 * band.speed * dt;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
draw(ctx, width, height) {
|
|
70
|
-
const bg = ctx.createLinearGradient(0, 0, 0, height);
|
|
71
|
-
bg.addColorStop(0, "#000000");
|
|
72
|
-
bg.addColorStop(.5, "#050012");
|
|
73
|
-
bg.addColorStop(1, "#0a0025");
|
|
74
|
-
ctx.fillStyle = bg;
|
|
75
|
-
ctx.fillRect(0, 0, width, height);
|
|
76
|
-
ctx.globalCompositeOperation = "screen";
|
|
77
|
-
const step = 4;
|
|
78
|
-
const scale = width / 1920;
|
|
79
|
-
for (const band of this.#bands) {
|
|
80
|
-
const swayX = band.amplitude1 * width * Math.sin(band.phase1);
|
|
81
|
-
const cx = band.x * width + swayX;
|
|
82
|
-
const baseY = band.baseY * height;
|
|
83
|
-
const rayHeight = band.height * height * (height / 800);
|
|
84
|
-
const sigma = band.sigma * scale;
|
|
85
|
-
const cutoff = sigma * 3.5;
|
|
86
|
-
const sigmaSq2 = 2 * sigma * sigma;
|
|
87
|
-
const midHue = (band.hue + TOP_HUE) / 2;
|
|
88
|
-
const waveRange = height * .035 * this.#waveAmplitude;
|
|
89
|
-
const xStart = Math.max(0, Math.floor((cx - cutoff) / step) * step);
|
|
90
|
-
const xEnd = Math.min(width, Math.ceil((cx + cutoff) / step) * step);
|
|
91
|
-
for (let x = xStart; x < xEnd; x += step) {
|
|
92
|
-
const dx = x - cx;
|
|
93
|
-
const alpha = Math.exp(-dx * dx / sigmaSq2);
|
|
94
|
-
if (alpha < .015) continue;
|
|
95
|
-
const colBase = baseY + Math.sin(band.frequency1 * x + band.phase2) * waveRange;
|
|
96
|
-
const colTop = colBase - rayHeight;
|
|
97
|
-
const fadeBottom = colBase + rayHeight * .1;
|
|
98
|
-
const eff = alpha * band.opacity;
|
|
99
|
-
const gradient = ctx.createLinearGradient(0, fadeBottom, 0, colTop);
|
|
100
|
-
gradient.addColorStop(0, `hsla(${band.hue}, 100%, 90%, 0)`);
|
|
101
|
-
gradient.addColorStop(.04, `hsla(${band.hue}, 100%, 90%, ${eff * .55})`);
|
|
102
|
-
gradient.addColorStop(.1, `hsla(${band.hue}, 90%, 72%, ${eff})`);
|
|
103
|
-
gradient.addColorStop(.32, `hsla(${band.hue}, 85%, 62%, ${eff * .75})`);
|
|
104
|
-
gradient.addColorStop(.62, `hsla(${midHue}, 80%, 56%, ${eff * .35})`);
|
|
105
|
-
gradient.addColorStop(.86, `hsla(${TOP_HUE}, 75%, 50%, ${eff * .12})`);
|
|
106
|
-
gradient.addColorStop(1, `hsla(${TOP_HUE}, 70%, 45%, 0)`);
|
|
107
|
-
ctx.fillStyle = gradient;
|
|
108
|
-
ctx.fillRect(x, colTop, step, fadeBottom - colTop + 1);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
ctx.globalCompositeOperation = "source-over";
|
|
112
|
-
}
|
|
113
|
-
#rgbToHue(r, g, b) {
|
|
114
|
-
r /= 255;
|
|
115
|
-
g /= 255;
|
|
116
|
-
b /= 255;
|
|
117
|
-
const max = Math.max(r, g, b);
|
|
118
|
-
const delta = max - Math.min(r, g, b);
|
|
119
|
-
if (delta === 0) return 0;
|
|
120
|
-
let hue;
|
|
121
|
-
if (max === r) hue = (g - b) / delta % 6;
|
|
122
|
-
else if (max === g) hue = (b - r) / delta + 2;
|
|
123
|
-
else hue = (r - g) / delta + 4;
|
|
124
|
-
hue = Math.round(hue * 60);
|
|
125
|
-
if (hue < 0) hue += 360;
|
|
126
|
-
return hue;
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
//#endregion
|
|
130
2
|
//#region src/canvas.ts
|
|
131
3
|
var LimitedFrameRateCanvas = class LimitedFrameRateCanvas {
|
|
132
4
|
static #globalSpeed = 1;
|
|
@@ -217,6 +89,16 @@ var LimitedFrameRateCanvas = class LimitedFrameRateCanvas {
|
|
|
217
89
|
this.#isStopped = true;
|
|
218
90
|
cancelAnimationFrame(this.#frame);
|
|
219
91
|
}
|
|
92
|
+
pause() {
|
|
93
|
+
this.#isStopped = true;
|
|
94
|
+
cancelAnimationFrame(this.#frame);
|
|
95
|
+
}
|
|
96
|
+
resume() {
|
|
97
|
+
if (this.#isStopped) {
|
|
98
|
+
this.#isStopped = false;
|
|
99
|
+
this.#frame = requestAnimationFrame(this.loop.bind(this));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
220
102
|
draw() {
|
|
221
103
|
throw new Error("LimitedFrameRateCanvas::draw() should be overwritten.");
|
|
222
104
|
}
|
|
@@ -245,18 +127,99 @@ var LimitedFrameRateCanvas = class LimitedFrameRateCanvas {
|
|
|
245
127
|
}
|
|
246
128
|
};
|
|
247
129
|
//#endregion
|
|
130
|
+
//#region src/fade.ts
|
|
131
|
+
function parseSide(side) {
|
|
132
|
+
return typeof side === "number" ? [0, side] : side;
|
|
133
|
+
}
|
|
134
|
+
function applyEdgeFade(ctx, width, height, fade) {
|
|
135
|
+
ctx.globalCompositeOperation = "destination-out";
|
|
136
|
+
if (fade.top !== void 0) {
|
|
137
|
+
const [near, far] = parseSide(fade.top);
|
|
138
|
+
const nearPx = near * height;
|
|
139
|
+
const farPx = far * height;
|
|
140
|
+
if (nearPx > 0) {
|
|
141
|
+
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
142
|
+
ctx.fillRect(0, 0, width, nearPx);
|
|
143
|
+
}
|
|
144
|
+
if (farPx > nearPx) {
|
|
145
|
+
const gradient = ctx.createLinearGradient(0, nearPx, 0, farPx);
|
|
146
|
+
gradient.addColorStop(0, "rgba(0,0,0,1)");
|
|
147
|
+
gradient.addColorStop(1, "rgba(0,0,0,0)");
|
|
148
|
+
ctx.fillStyle = gradient;
|
|
149
|
+
ctx.fillRect(0, nearPx, width, farPx - nearPx);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (fade.bottom !== void 0) {
|
|
153
|
+
const [near, far] = parseSide(fade.bottom);
|
|
154
|
+
const nearPx = near * height;
|
|
155
|
+
const farPx = far * height;
|
|
156
|
+
if (nearPx > 0) {
|
|
157
|
+
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
158
|
+
ctx.fillRect(0, height - nearPx, width, nearPx);
|
|
159
|
+
}
|
|
160
|
+
if (farPx > nearPx) {
|
|
161
|
+
const gradient = ctx.createLinearGradient(0, height - farPx, 0, height - nearPx);
|
|
162
|
+
gradient.addColorStop(0, "rgba(0,0,0,0)");
|
|
163
|
+
gradient.addColorStop(1, "rgba(0,0,0,1)");
|
|
164
|
+
ctx.fillStyle = gradient;
|
|
165
|
+
ctx.fillRect(0, height - farPx, width, farPx - nearPx);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (fade.left !== void 0) {
|
|
169
|
+
const [near, far] = parseSide(fade.left);
|
|
170
|
+
const nearPx = near * width;
|
|
171
|
+
const farPx = far * width;
|
|
172
|
+
if (nearPx > 0) {
|
|
173
|
+
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
174
|
+
ctx.fillRect(0, 0, nearPx, height);
|
|
175
|
+
}
|
|
176
|
+
if (farPx > nearPx) {
|
|
177
|
+
const gradient = ctx.createLinearGradient(nearPx, 0, farPx, 0);
|
|
178
|
+
gradient.addColorStop(0, "rgba(0,0,0,1)");
|
|
179
|
+
gradient.addColorStop(1, "rgba(0,0,0,0)");
|
|
180
|
+
ctx.fillStyle = gradient;
|
|
181
|
+
ctx.fillRect(nearPx, 0, farPx - nearPx, height);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (fade.right !== void 0) {
|
|
185
|
+
const [near, far] = parseSide(fade.right);
|
|
186
|
+
const nearPx = near * width;
|
|
187
|
+
const farPx = far * width;
|
|
188
|
+
if (nearPx > 0) {
|
|
189
|
+
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
190
|
+
ctx.fillRect(width - nearPx, 0, nearPx, height);
|
|
191
|
+
}
|
|
192
|
+
if (farPx > nearPx) {
|
|
193
|
+
const gradient = ctx.createLinearGradient(width - farPx, 0, width - nearPx, 0);
|
|
194
|
+
gradient.addColorStop(0, "rgba(0,0,0,0)");
|
|
195
|
+
gradient.addColorStop(1, "rgba(0,0,0,1)");
|
|
196
|
+
ctx.fillStyle = gradient;
|
|
197
|
+
ctx.fillRect(width - farPx, 0, farPx - nearPx, height);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
ctx.globalCompositeOperation = "source-over";
|
|
201
|
+
}
|
|
202
|
+
//#endregion
|
|
248
203
|
//#region src/simulation-canvas.ts
|
|
249
204
|
var SimulationCanvas = class extends LimitedFrameRateCanvas {
|
|
250
205
|
#simulation;
|
|
206
|
+
#contextOptions;
|
|
207
|
+
#offscreen = null;
|
|
208
|
+
#offscreenCtx = null;
|
|
251
209
|
constructor(canvas, simulation, frameRate = 60, options = { colorSpace: "display-p3" }) {
|
|
252
210
|
super(canvas, frameRate, options);
|
|
253
211
|
this.#simulation = simulation;
|
|
212
|
+
this.#contextOptions = options;
|
|
254
213
|
canvas.style.position = "absolute";
|
|
255
214
|
canvas.style.top = "0";
|
|
256
215
|
canvas.style.left = "0";
|
|
257
216
|
canvas.style.height = "100%";
|
|
258
217
|
canvas.style.width = "100%";
|
|
259
218
|
}
|
|
219
|
+
withFade(fade) {
|
|
220
|
+
this.#simulation.fade = fade;
|
|
221
|
+
return this;
|
|
222
|
+
}
|
|
260
223
|
start() {
|
|
261
224
|
this.#simulation.onMount(this.canvas);
|
|
262
225
|
super.start();
|
|
@@ -269,9 +232,17 @@ var SimulationCanvas = class extends LimitedFrameRateCanvas {
|
|
|
269
232
|
this.canvas.height = this.height;
|
|
270
233
|
this.canvas.width = this.width;
|
|
271
234
|
const ctx = this.context;
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
235
|
+
if (this.#simulation.fade) {
|
|
236
|
+
const offCtx = this.#getOffscreenCtx(this.width, this.height);
|
|
237
|
+
offCtx.clearRect(0, 0, this.width, this.height);
|
|
238
|
+
this.#simulation.draw(offCtx, this.width, this.height);
|
|
239
|
+
applyEdgeFade(offCtx, this.width, this.height, this.#simulation.fade);
|
|
240
|
+
ctx.drawImage(this.#offscreen, 0, 0);
|
|
241
|
+
} else {
|
|
242
|
+
ctx.save();
|
|
243
|
+
this.#simulation.draw(ctx, this.width, this.height);
|
|
244
|
+
ctx.restore();
|
|
245
|
+
}
|
|
275
246
|
}
|
|
276
247
|
tick() {
|
|
277
248
|
const dt = (this.delta > 0 && this.delta < 200 ? this.delta / (1e3 / 60) : 1) * this.speed * LimitedFrameRateCanvas.globalSpeed;
|
|
@@ -279,32 +250,230 @@ var SimulationCanvas = class extends LimitedFrameRateCanvas {
|
|
|
279
250
|
}
|
|
280
251
|
onResize() {
|
|
281
252
|
super.onResize();
|
|
253
|
+
if (this.#offscreen) {
|
|
254
|
+
this.#offscreen.width = this.width;
|
|
255
|
+
this.#offscreen.height = this.height;
|
|
256
|
+
}
|
|
282
257
|
this.#simulation.onResize(this.width, this.height);
|
|
283
258
|
}
|
|
259
|
+
#getOffscreenCtx(width, height) {
|
|
260
|
+
if (!this.#offscreen) {
|
|
261
|
+
this.#offscreen = document.createElement("canvas");
|
|
262
|
+
this.#offscreen.width = width;
|
|
263
|
+
this.#offscreen.height = height;
|
|
264
|
+
this.#offscreenCtx = this.#offscreen.getContext("2d", this.#contextOptions);
|
|
265
|
+
}
|
|
266
|
+
return this.#offscreenCtx;
|
|
267
|
+
}
|
|
284
268
|
};
|
|
285
269
|
//#endregion
|
|
286
|
-
//#region src/
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
270
|
+
//#region src/effect.ts
|
|
271
|
+
/**
|
|
272
|
+
* Base class for all visual effects. Implements the internal SimulationLayer interface
|
|
273
|
+
* so that effects can be used both standalone (via mount()) and composed in a Scene.
|
|
274
|
+
*
|
|
275
|
+
* @example Standalone usage
|
|
276
|
+
* const snow = new Snow({ particles: 200 });
|
|
277
|
+
* snow.mount(canvas).start();
|
|
278
|
+
*
|
|
279
|
+
* @example Scene composition
|
|
280
|
+
* const scene = new Scene()
|
|
281
|
+
* .mount(canvas)
|
|
282
|
+
* .layer(new Aurora())
|
|
283
|
+
* .layer(new Snow())
|
|
284
|
+
* .start();
|
|
285
|
+
*/
|
|
286
|
+
var Effect = class {
|
|
287
|
+
#canvas = null;
|
|
288
|
+
fade = null;
|
|
289
|
+
configure(_config) {}
|
|
290
|
+
onResize(_width, _height) {}
|
|
291
|
+
onMount(_canvas) {}
|
|
292
|
+
onUnmount(_canvas) {}
|
|
293
|
+
/**
|
|
294
|
+
* Apply an edge fade mask when rendering this effect standalone or in a Scene.
|
|
295
|
+
*/
|
|
296
|
+
withFade(fade) {
|
|
297
|
+
this.fade = fade;
|
|
298
|
+
return this;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Mount this effect to a canvas element or CSS selector, creating the render loop.
|
|
302
|
+
* Must be called before start().
|
|
303
|
+
*/
|
|
304
|
+
mount(canvas, options = { colorSpace: "display-p3" }) {
|
|
305
|
+
if (typeof canvas === "string") {
|
|
306
|
+
const el = document.querySelector(canvas);
|
|
307
|
+
if (!el) throw new Error(`Effect.mount(): no element found for selector "${canvas}".`);
|
|
308
|
+
canvas = el;
|
|
309
|
+
}
|
|
310
|
+
this.#canvas = new SimulationCanvas(canvas, this, 60, options);
|
|
311
|
+
return this;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Remove this effect from its canvas and clean up the render loop.
|
|
315
|
+
*/
|
|
316
|
+
unmount() {
|
|
317
|
+
this.#canvas?.destroy();
|
|
318
|
+
this.#canvas = null;
|
|
319
|
+
return this;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Start the render loop. Call mount() first.
|
|
323
|
+
*/
|
|
324
|
+
start() {
|
|
325
|
+
this.#canvas?.start();
|
|
326
|
+
return this;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Pause rendering without destroying state. Use resume() to continue.
|
|
330
|
+
*/
|
|
331
|
+
pause() {
|
|
332
|
+
this.#canvas?.pause();
|
|
333
|
+
return this;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Resume rendering after a pause().
|
|
337
|
+
*/
|
|
338
|
+
resume() {
|
|
339
|
+
this.#canvas?.resume();
|
|
340
|
+
return this;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Stop rendering and call onUnmount(). Safe to call multiple times.
|
|
344
|
+
*/
|
|
345
|
+
destroy() {
|
|
346
|
+
this.unmount();
|
|
290
347
|
}
|
|
291
348
|
};
|
|
292
349
|
//#endregion
|
|
293
|
-
//#region src/
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
350
|
+
//#region src/aurora/consts.ts
|
|
351
|
+
const MULBERRY$23 = mulberry32(13);
|
|
352
|
+
//#endregion
|
|
353
|
+
//#region src/aurora/layer.ts
|
|
354
|
+
const DEFAULT_COLORS$4 = [
|
|
355
|
+
"#9922ff",
|
|
356
|
+
"#4455ff",
|
|
357
|
+
"#0077ee",
|
|
358
|
+
"#00aabb",
|
|
359
|
+
"#22ddff"
|
|
360
|
+
];
|
|
361
|
+
const TOP_HUE = 265;
|
|
362
|
+
var Aurora = class extends Effect {
|
|
363
|
+
#speed;
|
|
364
|
+
#intensity;
|
|
365
|
+
#waveAmplitude;
|
|
366
|
+
#verticalPosition;
|
|
367
|
+
#bands = [];
|
|
368
|
+
constructor(config = {}) {
|
|
369
|
+
super();
|
|
370
|
+
const bandCount = config.bands ?? 5;
|
|
371
|
+
const colors = config.colors ?? DEFAULT_COLORS$4;
|
|
372
|
+
this.#speed = config.speed ?? 1;
|
|
373
|
+
this.#intensity = config.intensity ?? .8;
|
|
374
|
+
this.#waveAmplitude = config.waveAmplitude ?? 1;
|
|
375
|
+
this.#verticalPosition = config.verticalPosition ?? .68;
|
|
376
|
+
const clusterCenters = [.35, .65];
|
|
377
|
+
for (let i = 0; i < bandCount; i++) {
|
|
378
|
+
const color = colors[i % colors.length];
|
|
379
|
+
const [r, g, b] = hexToRGB(color);
|
|
380
|
+
const hue = this.#rgbToHue(r, g, b);
|
|
381
|
+
const cluster = clusterCenters[i % clusterCenters.length];
|
|
382
|
+
this.#bands.push({
|
|
383
|
+
x: cluster + (MULBERRY$23.next() - .5) * .22,
|
|
384
|
+
baseY: (MULBERRY$23.next() - .5) * .08,
|
|
385
|
+
height: .5 + MULBERRY$23.next() * .3,
|
|
386
|
+
sigma: 160 + MULBERRY$23.next() * 110,
|
|
387
|
+
phase1: MULBERRY$23.next() * Math.PI * 2,
|
|
388
|
+
phase2: MULBERRY$23.next() * Math.PI * 2,
|
|
389
|
+
amplitude1: .015 + MULBERRY$23.next() * .025,
|
|
390
|
+
frequency1: .003 + MULBERRY$23.next() * .004,
|
|
391
|
+
speed: .4 + MULBERRY$23.next() * .6,
|
|
392
|
+
hue,
|
|
393
|
+
opacity: .5 + MULBERRY$23.next() * .3
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
configure(config) {
|
|
398
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
399
|
+
if (config.intensity !== void 0) this.#intensity = config.intensity;
|
|
400
|
+
if (config.waveAmplitude !== void 0) this.#waveAmplitude = config.waveAmplitude;
|
|
401
|
+
if (config.verticalPosition !== void 0) this.#verticalPosition = config.verticalPosition;
|
|
402
|
+
}
|
|
403
|
+
tick(dt, _width, _height) {
|
|
404
|
+
for (const band of this.#bands) {
|
|
405
|
+
band.phase1 += .005 * band.speed * this.#speed * dt;
|
|
406
|
+
band.phase2 += .008 * band.speed * this.#speed * dt;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
draw(ctx, width, height) {
|
|
410
|
+
const bg = ctx.createLinearGradient(0, 0, 0, height);
|
|
411
|
+
bg.addColorStop(0, "#000000");
|
|
412
|
+
bg.addColorStop(.5, "#050012");
|
|
413
|
+
bg.addColorStop(1, "#0a0025");
|
|
414
|
+
ctx.fillStyle = bg;
|
|
415
|
+
ctx.fillRect(0, 0, width, height);
|
|
416
|
+
ctx.globalCompositeOperation = "screen";
|
|
417
|
+
const step = 4;
|
|
418
|
+
const scale = width / 1920;
|
|
419
|
+
for (const band of this.#bands) {
|
|
420
|
+
const swayX = band.amplitude1 * width * Math.sin(band.phase1);
|
|
421
|
+
const cx = band.x * width + swayX;
|
|
422
|
+
const baseY = (this.#verticalPosition + band.baseY) * height;
|
|
423
|
+
const rayHeight = band.height * height * (height / 800);
|
|
424
|
+
const sigma = band.sigma * scale;
|
|
425
|
+
const cutoff = sigma * 3.5;
|
|
426
|
+
const sigmaSq2 = 2 * sigma * sigma;
|
|
427
|
+
const midHue = (band.hue + TOP_HUE) / 2;
|
|
428
|
+
const waveRange = height * .035 * this.#waveAmplitude;
|
|
429
|
+
const xStart = Math.max(0, Math.floor((cx - cutoff) / step) * step);
|
|
430
|
+
const xEnd = Math.min(width, Math.ceil((cx + cutoff) / step) * step);
|
|
431
|
+
const centreBase = baseY + Math.sin(band.frequency1 * cx + band.phase2) * waveRange;
|
|
432
|
+
const centreTop = centreBase - rayHeight;
|
|
433
|
+
const centreFadeBottom = centreBase + rayHeight * .1;
|
|
434
|
+
const gradient = ctx.createLinearGradient(0, centreFadeBottom, 0, centreTop);
|
|
435
|
+
gradient.addColorStop(0, `hsla(${band.hue}, 100%, 90%, 0)`);
|
|
436
|
+
gradient.addColorStop(.04, `hsla(${band.hue}, 100%, 90%, 0.55)`);
|
|
437
|
+
gradient.addColorStop(.1, `hsla(${band.hue}, 90%, 72%, 1)`);
|
|
438
|
+
gradient.addColorStop(.32, `hsla(${band.hue}, 85%, 62%, 0.75)`);
|
|
439
|
+
gradient.addColorStop(.62, `hsla(${midHue}, 80%, 56%, 0.35)`);
|
|
440
|
+
gradient.addColorStop(.86, `hsla(${TOP_HUE}, 75%, 50%, 0.12)`);
|
|
441
|
+
gradient.addColorStop(1, `hsla(${TOP_HUE}, 70%, 45%, 0)`);
|
|
442
|
+
ctx.fillStyle = gradient;
|
|
443
|
+
for (let x = xStart; x < xEnd; x += step) {
|
|
444
|
+
const dx = x - cx;
|
|
445
|
+
const alpha = Math.exp(-dx * dx / sigmaSq2);
|
|
446
|
+
if (alpha < .015) continue;
|
|
447
|
+
const colBase = baseY + Math.sin(band.frequency1 * x + band.phase2) * waveRange;
|
|
448
|
+
const colTop = colBase - rayHeight;
|
|
449
|
+
const fadeBottom = colBase + rayHeight * .1;
|
|
450
|
+
ctx.globalAlpha = alpha * band.opacity * this.#intensity;
|
|
451
|
+
ctx.fillRect(x, colTop, step, fadeBottom - colTop + 1);
|
|
452
|
+
}
|
|
453
|
+
ctx.globalAlpha = 1;
|
|
454
|
+
}
|
|
455
|
+
ctx.globalCompositeOperation = "source-over";
|
|
456
|
+
}
|
|
457
|
+
#rgbToHue(r, g, b) {
|
|
458
|
+
r /= 255;
|
|
459
|
+
g /= 255;
|
|
460
|
+
b /= 255;
|
|
461
|
+
const max = Math.max(r, g, b);
|
|
462
|
+
const delta = max - Math.min(r, g, b);
|
|
463
|
+
if (delta === 0) return 0;
|
|
464
|
+
let hue;
|
|
465
|
+
if (max === r) hue = (g - b) / delta % 6;
|
|
466
|
+
else if (max === g) hue = (b - r) / delta + 2;
|
|
467
|
+
else hue = (r - g) / delta + 4;
|
|
468
|
+
hue = Math.round(hue * 60);
|
|
469
|
+
if (hue < 0) hue += 360;
|
|
470
|
+
return hue;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
//#endregion
|
|
474
|
+
//#region src/aurora/index.ts
|
|
475
|
+
function createAurora(config) {
|
|
476
|
+
return new Aurora(config);
|
|
308
477
|
}
|
|
309
478
|
//#endregion
|
|
310
479
|
//#region src/balloons/consts.ts
|
|
@@ -319,7 +488,7 @@ const DEFAULT_COLORS$3 = [
|
|
|
319
488
|
"#ff88cc",
|
|
320
489
|
"#8844ff"
|
|
321
490
|
];
|
|
322
|
-
var
|
|
491
|
+
var Balloons = class extends Effect {
|
|
323
492
|
#scale;
|
|
324
493
|
#speed;
|
|
325
494
|
#driftAmount;
|
|
@@ -341,6 +510,11 @@ var BalloonLayer = class extends SimulationLayer {
|
|
|
341
510
|
if (innerWidth < 991) this.#maxCount = Math.floor(this.#maxCount / 2);
|
|
342
511
|
for (let i = 0; i < this.#maxCount; ++i) this.#balloons.push(this.#createBalloon(true));
|
|
343
512
|
}
|
|
513
|
+
configure(config) {
|
|
514
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
515
|
+
if (config.driftAmount !== void 0) this.#driftAmount = config.driftAmount;
|
|
516
|
+
if (config.stringLength !== void 0) this.#stringLengthMul = config.stringLength;
|
|
517
|
+
}
|
|
344
518
|
tick(dt, width, height) {
|
|
345
519
|
this.#time += .015 * dt * this.#speed;
|
|
346
520
|
for (let i = 0; i < this.#balloons.length; i++) {
|
|
@@ -359,9 +533,9 @@ var BalloonLayer = class extends SimulationLayer {
|
|
|
359
533
|
const rx = balloon.radiusX * this.#scale;
|
|
360
534
|
const ry = balloon.radiusY * this.#scale;
|
|
361
535
|
const [r, g, b] = balloon.color;
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
ctx.
|
|
536
|
+
const cos = Math.cos(balloon.rotation);
|
|
537
|
+
const sin = Math.sin(balloon.rotation);
|
|
538
|
+
ctx.setTransform(cos, sin, -sin, cos, px, py);
|
|
365
539
|
const gradient = ctx.createRadialGradient(-rx * .3, -ry * .3, rx * .1, 0, 0, Math.max(rx, ry));
|
|
366
540
|
gradient.addColorStop(0, `rgba(${Math.min(255, r + 80)}, ${Math.min(255, g + 80)}, ${Math.min(255, b + 80)}, 0.95)`);
|
|
367
541
|
gradient.addColorStop(.6, `rgba(${r}, ${g}, ${b}, 0.9)`);
|
|
@@ -383,15 +557,21 @@ var BalloonLayer = class extends SimulationLayer {
|
|
|
383
557
|
ctx.fillStyle = `rgba(${Math.max(0, r - 30)}, ${Math.max(0, g - 30)}, ${Math.max(0, b - 30)}, 0.9)`;
|
|
384
558
|
ctx.fill();
|
|
385
559
|
const stringLen = balloon.stringLength * this.#scale * this.#stringLengthMul;
|
|
386
|
-
const
|
|
560
|
+
const knotBaseY = knotY + 5 * this.#scale;
|
|
561
|
+
const ph = balloon.driftPhase;
|
|
562
|
+
const fr = balloon.driftFreq;
|
|
563
|
+
const swingAmt = 10 * this.#scale * this.#driftAmount;
|
|
564
|
+
const midSwing = Math.sin(this.#time * fr + ph - .3) * swingAmt * .55;
|
|
565
|
+
const tipSwing = Math.sin(this.#time * fr + ph - .8) * swingAmt;
|
|
566
|
+
const flutter = Math.sin(this.#time * fr * 2.5 + ph * 1.4 + 1.8) * 2.5 * this.#scale;
|
|
387
567
|
ctx.beginPath();
|
|
388
|
-
ctx.moveTo(0,
|
|
389
|
-
ctx.
|
|
568
|
+
ctx.moveTo(0, knotBaseY);
|
|
569
|
+
ctx.bezierCurveTo(midSwing * .35, knotBaseY + stringLen * .3, midSwing + flutter * .5, knotBaseY + stringLen * .65, tipSwing + flutter, knotBaseY + stringLen);
|
|
390
570
|
ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, 0.4)`;
|
|
391
571
|
ctx.lineWidth = 1;
|
|
392
572
|
ctx.stroke();
|
|
393
|
-
ctx.restore();
|
|
394
573
|
}
|
|
574
|
+
ctx.resetTransform();
|
|
395
575
|
}
|
|
396
576
|
#createBalloon(initialSpread) {
|
|
397
577
|
const colorIndex = Math.floor(MULBERRY$22.next() * this.#colorRGBs.length);
|
|
@@ -496,12 +676,32 @@ var BalloonParticle = class {
|
|
|
496
676
|
}
|
|
497
677
|
};
|
|
498
678
|
//#endregion
|
|
499
|
-
//#region src/balloons/
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
679
|
+
//#region src/balloons/index.ts
|
|
680
|
+
function createBalloons(config) {
|
|
681
|
+
return new Balloons(config);
|
|
682
|
+
}
|
|
683
|
+
//#endregion
|
|
684
|
+
//#region src/color.ts
|
|
685
|
+
const cache = /* @__PURE__ */ new Map();
|
|
686
|
+
function parseColor(fillStyle) {
|
|
687
|
+
const cached = cache.get(fillStyle);
|
|
688
|
+
if (cached) return cached;
|
|
689
|
+
const canvas = document.createElement("canvas");
|
|
690
|
+
canvas.width = 1;
|
|
691
|
+
canvas.height = 1;
|
|
692
|
+
const ctx = canvas.getContext("2d");
|
|
693
|
+
ctx.fillStyle = fillStyle;
|
|
694
|
+
ctx.fillRect(0, 0, 1, 1);
|
|
695
|
+
const data = ctx.getImageData(0, 0, 1, 1).data;
|
|
696
|
+
const result = {
|
|
697
|
+
r: data[0],
|
|
698
|
+
g: data[1],
|
|
699
|
+
b: data[2],
|
|
700
|
+
a: data[3] / 255
|
|
701
|
+
};
|
|
702
|
+
cache.set(fillStyle, result);
|
|
703
|
+
return result;
|
|
704
|
+
}
|
|
505
705
|
//#endregion
|
|
506
706
|
//#region src/bubbles/consts.ts
|
|
507
707
|
const MULBERRY$21 = mulberry32(13);
|
|
@@ -512,7 +712,7 @@ const DEFAULT_COLORS$2 = [
|
|
|
512
712
|
"#aaddff",
|
|
513
713
|
"#ccbbff"
|
|
514
714
|
];
|
|
515
|
-
var
|
|
715
|
+
var Bubbles = class extends Effect {
|
|
516
716
|
#scale;
|
|
517
717
|
#speed;
|
|
518
718
|
#sizeRange;
|
|
@@ -548,6 +748,10 @@ var BubbleLayer = class extends SimulationLayer {
|
|
|
548
748
|
canvas.removeEventListener("click", this.#onClickBound);
|
|
549
749
|
this.#canvas = null;
|
|
550
750
|
}
|
|
751
|
+
configure(config) {
|
|
752
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
753
|
+
if (config.wobbleAmount !== void 0) this.#wobbleAmount = config.wobbleAmount;
|
|
754
|
+
}
|
|
551
755
|
tick(dt, width, height) {
|
|
552
756
|
this.#time += .01 * dt;
|
|
553
757
|
for (let i = 0; i < this.#bubbles.length; i++) {
|
|
@@ -646,16 +850,10 @@ var BubbleLayer = class extends SimulationLayer {
|
|
|
646
850
|
}
|
|
647
851
|
}
|
|
648
852
|
#colorToHue(color) {
|
|
649
|
-
const
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
ctx.fillStyle = color;
|
|
654
|
-
ctx.fillRect(0, 0, 1, 1);
|
|
655
|
-
const data = ctx.getImageData(0, 0, 1, 1).data;
|
|
656
|
-
let r = data[0] / 255;
|
|
657
|
-
let g = data[1] / 255;
|
|
658
|
-
let b = data[2] / 255;
|
|
853
|
+
const { r: r255, g: g255, b: b255 } = parseColor(color);
|
|
854
|
+
let r = r255 / 255;
|
|
855
|
+
let g = g255 / 255;
|
|
856
|
+
let b = b255 / 255;
|
|
659
857
|
const max = Math.max(r, g, b);
|
|
660
858
|
const delta = max - Math.min(r, g, b);
|
|
661
859
|
if (delta === 0) return 0;
|
|
@@ -669,12 +867,10 @@ var BubbleLayer = class extends SimulationLayer {
|
|
|
669
867
|
}
|
|
670
868
|
};
|
|
671
869
|
//#endregion
|
|
672
|
-
//#region src/bubbles/
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
}
|
|
677
|
-
};
|
|
870
|
+
//#region src/bubbles/index.ts
|
|
871
|
+
function createBubbles(config) {
|
|
872
|
+
return new Bubbles(config);
|
|
873
|
+
}
|
|
678
874
|
//#endregion
|
|
679
875
|
//#region src/confetti/consts.ts
|
|
680
876
|
const PALETTES = {
|
|
@@ -838,7 +1034,7 @@ const SHAPE_PATHS = {
|
|
|
838
1034
|
//#endregion
|
|
839
1035
|
//#region src/confetti/layer.ts
|
|
840
1036
|
const TWO_PI = Math.PI * 2;
|
|
841
|
-
var
|
|
1037
|
+
var Confetti = class extends Effect {
|
|
842
1038
|
#scale;
|
|
843
1039
|
#particles = [];
|
|
844
1040
|
#width = 0;
|
|
@@ -852,7 +1048,7 @@ var ConfettiLayer = class extends SimulationLayer {
|
|
|
852
1048
|
this.#width = width;
|
|
853
1049
|
this.#height = height;
|
|
854
1050
|
}
|
|
855
|
-
|
|
1051
|
+
burst(config) {
|
|
856
1052
|
const width = this.#width;
|
|
857
1053
|
const height = this.#height;
|
|
858
1054
|
const resolved = {
|
|
@@ -987,28 +1183,28 @@ var ConfettiParticle = class {
|
|
|
987
1183
|
const scale = config.scale ?? 1;
|
|
988
1184
|
const spread = config.spread ?? 45;
|
|
989
1185
|
const startVelocity = (config.startVelocity ?? 45) * scale;
|
|
990
|
-
const launchAngle = -(direction * Math.PI / 180) + .5 * spread * Math.PI / 180 -
|
|
991
|
-
const speed = startVelocity * (.5 +
|
|
992
|
-
const rotAngle =
|
|
1186
|
+
const launchAngle = -(direction * Math.PI / 180) + .5 * spread * Math.PI / 180 - MULBERRY$20.next() * spread * Math.PI / 180;
|
|
1187
|
+
const speed = startVelocity * (.5 + MULBERRY$20.next());
|
|
1188
|
+
const rotAngle = MULBERRY$20.next() * Math.PI * 2;
|
|
993
1189
|
this.#colorStr = color;
|
|
994
1190
|
this.#gravity = (config.gravity ?? 1) * scale;
|
|
995
1191
|
this.#shape = shape;
|
|
996
|
-
this.#size = (5 +
|
|
1192
|
+
this.#size = (5 + MULBERRY$20.next() * 5) * scale;
|
|
997
1193
|
this.#totalTicks = config.ticks ?? 200;
|
|
998
1194
|
this.#x = position.x;
|
|
999
1195
|
this.#y = position.y;
|
|
1000
1196
|
this.#vx = Math.cos(launchAngle) * speed;
|
|
1001
1197
|
this.#vy = Math.sin(launchAngle) * speed;
|
|
1002
|
-
this.#decay = (config.decay ?? .9) - .05 +
|
|
1003
|
-
this.#flipAngle =
|
|
1004
|
-
this.#flipSpeed = .03 +
|
|
1198
|
+
this.#decay = (config.decay ?? .9) - .05 + MULBERRY$20.next() * .1;
|
|
1199
|
+
this.#flipAngle = MULBERRY$20.next() * Math.PI * 2;
|
|
1200
|
+
this.#flipSpeed = .03 + MULBERRY$20.next() * .05;
|
|
1005
1201
|
this.#rotAngle = rotAngle;
|
|
1006
1202
|
this.#rotCos = Math.cos(rotAngle);
|
|
1007
1203
|
this.#rotSin = Math.sin(rotAngle);
|
|
1008
|
-
this.#rotSpeed = (
|
|
1009
|
-
this.#swing =
|
|
1010
|
-
this.#swingAmp = .5 +
|
|
1011
|
-
this.#swingSpeed = .025 +
|
|
1204
|
+
this.#rotSpeed = (MULBERRY$20.next() - .5) * .06;
|
|
1205
|
+
this.#swing = MULBERRY$20.next() * Math.PI * 2;
|
|
1206
|
+
this.#swingAmp = .5 + MULBERRY$20.next() * 1.5;
|
|
1207
|
+
this.#swingSpeed = .025 + MULBERRY$20.next() * .035;
|
|
1012
1208
|
}
|
|
1013
1209
|
draw(ctx) {
|
|
1014
1210
|
ctx.save();
|
|
@@ -1034,20 +1230,10 @@ var ConfettiParticle = class {
|
|
|
1034
1230
|
}
|
|
1035
1231
|
};
|
|
1036
1232
|
//#endregion
|
|
1037
|
-
//#region src/confetti/
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
const layer = new ConfettiLayer(config);
|
|
1042
|
-
super(canvas, layer, 60, config.canvasOptions ?? { colorSpace: "display-p3" });
|
|
1043
|
-
this.#layer = layer;
|
|
1044
|
-
}
|
|
1045
|
-
fire(config) {
|
|
1046
|
-
this.onResize();
|
|
1047
|
-
this.#layer.fire(config);
|
|
1048
|
-
if (!this.isTicking) this.start();
|
|
1049
|
-
}
|
|
1050
|
-
};
|
|
1233
|
+
//#region src/confetti/index.ts
|
|
1234
|
+
function createConfetti(config) {
|
|
1235
|
+
return new Confetti(config);
|
|
1236
|
+
}
|
|
1051
1237
|
//#endregion
|
|
1052
1238
|
//#region src/donuts/consts.ts
|
|
1053
1239
|
const MULBERRY$19 = mulberry32(13);
|
|
@@ -1067,7 +1253,7 @@ const DEFAULT_CONFIG = {
|
|
|
1067
1253
|
};
|
|
1068
1254
|
//#endregion
|
|
1069
1255
|
//#region src/donuts/layer.ts
|
|
1070
|
-
var
|
|
1256
|
+
var Donuts = class extends Effect {
|
|
1071
1257
|
#background;
|
|
1072
1258
|
#collisionPadding;
|
|
1073
1259
|
#colors;
|
|
@@ -1128,6 +1314,12 @@ var DonutLayer = class extends SimulationLayer {
|
|
|
1128
1314
|
canvas.removeEventListener("mousemove", this.#onMouseMoveBound);
|
|
1129
1315
|
canvas.removeEventListener("mouseleave", this.#onMouseLeaveBound);
|
|
1130
1316
|
}
|
|
1317
|
+
configure(config) {
|
|
1318
|
+
if (config.mouseAvoidance !== void 0) this.#mouseAvoidance = config.mouseAvoidance;
|
|
1319
|
+
if (config.mouseAvoidanceRadius !== void 0) this.#mouseAvoidanceRadius = config.mouseAvoidanceRadius;
|
|
1320
|
+
if (config.mouseAvoidanceStrength !== void 0) this.#mouseAvoidanceStrength = config.mouseAvoidanceStrength;
|
|
1321
|
+
if (config.repulsionStrength !== void 0) this.#repulsionStrength = config.repulsionStrength;
|
|
1322
|
+
}
|
|
1131
1323
|
tick(dt, width, height) {
|
|
1132
1324
|
this.#width = width;
|
|
1133
1325
|
this.#height = height;
|
|
@@ -1140,17 +1332,17 @@ var DonutLayer = class extends SimulationLayer {
|
|
|
1140
1332
|
ctx.fillStyle = this.#background;
|
|
1141
1333
|
ctx.fillRect(0, 0, width, height);
|
|
1142
1334
|
for (const donut of this.#donuts) {
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
ctx.
|
|
1335
|
+
const cos = Math.cos(donut.angle);
|
|
1336
|
+
const sin = Math.sin(donut.angle);
|
|
1337
|
+
ctx.setTransform(cos, sin, -sin, cos, donut.x, donut.y);
|
|
1146
1338
|
ctx.beginPath();
|
|
1147
1339
|
ctx.arc(0, 0, donut.outerRadius, 0, Math.PI * 2);
|
|
1148
1340
|
ctx.arc(0, 0, donut.innerRadius, 0, Math.PI * 2, true);
|
|
1149
1341
|
ctx.closePath();
|
|
1150
1342
|
ctx.fillStyle = donut.color;
|
|
1151
1343
|
ctx.fill();
|
|
1152
|
-
ctx.restore();
|
|
1153
1344
|
}
|
|
1345
|
+
ctx.resetTransform();
|
|
1154
1346
|
}
|
|
1155
1347
|
#updateDonut(donut, dt) {
|
|
1156
1348
|
if (Math.sqrt(donut.vx * donut.vx + donut.vy * donut.vy) > donut.speed) {
|
|
@@ -1270,12 +1462,10 @@ var DonutLayer = class extends SimulationLayer {
|
|
|
1270
1462
|
}
|
|
1271
1463
|
};
|
|
1272
1464
|
//#endregion
|
|
1273
|
-
//#region src/donuts/
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
}
|
|
1278
|
-
};
|
|
1465
|
+
//#region src/donuts/index.ts
|
|
1466
|
+
function createDonuts(config) {
|
|
1467
|
+
return new Donuts(config);
|
|
1468
|
+
}
|
|
1279
1469
|
//#endregion
|
|
1280
1470
|
//#region src/fireflies/consts.ts
|
|
1281
1471
|
const MULBERRY$18 = mulberry32(13);
|
|
@@ -1284,7 +1474,7 @@ const MULBERRY$18 = mulberry32(13);
|
|
|
1284
1474
|
const SPRITE_SIZE$1 = 64;
|
|
1285
1475
|
const SPRITE_CENTER$1 = SPRITE_SIZE$1 / 2;
|
|
1286
1476
|
const SPRITE_RADIUS$1 = SPRITE_SIZE$1 / 2;
|
|
1287
|
-
var
|
|
1477
|
+
var Fireflies = class extends Effect {
|
|
1288
1478
|
#scale;
|
|
1289
1479
|
#size;
|
|
1290
1480
|
#speed;
|
|
@@ -1305,6 +1495,10 @@ var FireflyLayer = class extends SimulationLayer {
|
|
|
1305
1495
|
this.#sprite = this.#createSprite(r, g, b);
|
|
1306
1496
|
for (let i = 0; i < this.#maxCount; ++i) this.#fireflies.push(this.#createFirefly());
|
|
1307
1497
|
}
|
|
1498
|
+
configure(config) {
|
|
1499
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
1500
|
+
if (config.glowSpeed !== void 0) this.#glowSpeed = config.glowSpeed;
|
|
1501
|
+
}
|
|
1308
1502
|
tick(dt, _width, _height) {
|
|
1309
1503
|
this.#time += .02 * dt * this.#speed;
|
|
1310
1504
|
for (const firefly of this.#fireflies) {
|
|
@@ -1478,18 +1672,16 @@ var FireflyParticle = class {
|
|
|
1478
1672
|
}
|
|
1479
1673
|
};
|
|
1480
1674
|
//#endregion
|
|
1481
|
-
//#region src/fireflies/
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
}
|
|
1486
|
-
};
|
|
1675
|
+
//#region src/fireflies/index.ts
|
|
1676
|
+
function createFireflies(config) {
|
|
1677
|
+
return new Fireflies(config);
|
|
1678
|
+
}
|
|
1487
1679
|
//#endregion
|
|
1488
1680
|
//#region src/firepit/consts.ts
|
|
1489
1681
|
const MULBERRY$17 = mulberry32(13);
|
|
1490
1682
|
//#endregion
|
|
1491
1683
|
//#region src/firepit/layer.ts
|
|
1492
|
-
var
|
|
1684
|
+
var Firepit = class extends Effect {
|
|
1493
1685
|
#scale;
|
|
1494
1686
|
#flameWidth;
|
|
1495
1687
|
#flameHeight;
|
|
@@ -1515,6 +1707,11 @@ var FirepitLayer = class extends SimulationLayer {
|
|
|
1515
1707
|
height: this.#flameHeight * (.7 + MULBERRY$17.next() * .3)
|
|
1516
1708
|
});
|
|
1517
1709
|
}
|
|
1710
|
+
configure(config) {
|
|
1711
|
+
if (config.intensity !== void 0) this.#intensity = config.intensity;
|
|
1712
|
+
if (config.flameWidth !== void 0) this.#flameWidth = config.flameWidth;
|
|
1713
|
+
if (config.flameHeight !== void 0) this.#flameHeight = config.flameHeight;
|
|
1714
|
+
}
|
|
1518
1715
|
tick(dt, _width, _height) {
|
|
1519
1716
|
this.#time += .03 * dt * this.#intensity;
|
|
1520
1717
|
if (this.#embers.length < this.#maxEmbers && MULBERRY$17.next() < .3 * this.#intensity * dt) this.#embers.push(this.#createEmber());
|
|
@@ -1611,12 +1808,10 @@ var FirepitLayer = class extends SimulationLayer {
|
|
|
1611
1808
|
}
|
|
1612
1809
|
};
|
|
1613
1810
|
//#endregion
|
|
1614
|
-
//#region src/firepit/
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
}
|
|
1619
|
-
};
|
|
1811
|
+
//#region src/firepit/index.ts
|
|
1812
|
+
function createFirepit(config) {
|
|
1813
|
+
return new Firepit(config);
|
|
1814
|
+
}
|
|
1620
1815
|
//#endregion
|
|
1621
1816
|
//#region src/fireworks/consts.ts
|
|
1622
1817
|
const MULBERRY$16 = mulberry32(13);
|
|
@@ -1923,7 +2118,7 @@ var Explosion = class {
|
|
|
1923
2118
|
}
|
|
1924
2119
|
checkCrackle() {
|
|
1925
2120
|
if (this.#type !== "crackle" || this.#hasCrackled) return false;
|
|
1926
|
-
if (this.#alpha <=
|
|
2121
|
+
if (this.#alpha <= .4) {
|
|
1927
2122
|
this.#hasCrackled = true;
|
|
1928
2123
|
return true;
|
|
1929
2124
|
}
|
|
@@ -2032,6 +2227,158 @@ var Explosion = class {
|
|
|
2032
2227
|
}
|
|
2033
2228
|
};
|
|
2034
2229
|
//#endregion
|
|
2230
|
+
//#region src/fireworks/create-explosion.ts
|
|
2231
|
+
function between(rng, min, max) {
|
|
2232
|
+
return min + rng() * (max - min);
|
|
2233
|
+
}
|
|
2234
|
+
/**
|
|
2235
|
+
* Creates an array of {@link Explosion} particles for the given firework variant.
|
|
2236
|
+
* Use this to fire a fully formed explosion burst in your own render loop without
|
|
2237
|
+
* needing a {@link Fireworks} instance.
|
|
2238
|
+
*
|
|
2239
|
+
* @param variant - The firework variant to create.
|
|
2240
|
+
* @param position - The center position of the explosion in canvas pixels.
|
|
2241
|
+
* @param hue - Base hue in degrees (0–360).
|
|
2242
|
+
* @param options - Optional overrides for `lineWidth` (default `5`) and `scale` (default `1`).
|
|
2243
|
+
* @param rng - RNG function returning values in [0, 1). Defaults to `Math.random`.
|
|
2244
|
+
*/
|
|
2245
|
+
function createExplosion(variant, position, hue, options = {}, rng = Math.random) {
|
|
2246
|
+
const lineWidth = options.lineWidth ?? 5;
|
|
2247
|
+
const scale = options.scale ?? 1;
|
|
2248
|
+
const explosions = [];
|
|
2249
|
+
switch (variant) {
|
|
2250
|
+
case "saturn":
|
|
2251
|
+
createSaturn(explosions, position, hue, lineWidth, scale, rng);
|
|
2252
|
+
break;
|
|
2253
|
+
case "dahlia":
|
|
2254
|
+
createDahlia(explosions, position, hue, lineWidth, scale, rng);
|
|
2255
|
+
break;
|
|
2256
|
+
case "heart":
|
|
2257
|
+
createHeart(explosions, position, hue, lineWidth, scale, rng);
|
|
2258
|
+
break;
|
|
2259
|
+
case "spiral":
|
|
2260
|
+
createSpiral(explosions, position, hue, lineWidth, scale, rng);
|
|
2261
|
+
break;
|
|
2262
|
+
case "flower":
|
|
2263
|
+
createFlower(explosions, position, hue, lineWidth, scale, rng);
|
|
2264
|
+
break;
|
|
2265
|
+
case "concentric":
|
|
2266
|
+
createConcentric(explosions, position, hue, lineWidth, scale, rng);
|
|
2267
|
+
break;
|
|
2268
|
+
default: {
|
|
2269
|
+
const type = variant;
|
|
2270
|
+
const config = EXPLOSION_CONFIGS[type];
|
|
2271
|
+
const count = Math.floor(between(rng, config.particleCount[0], config.particleCount[1]));
|
|
2272
|
+
const effectiveHue = type === "brocade" ? between(rng, 35, 50) : hue;
|
|
2273
|
+
for (let i = 0; i < count; i++) {
|
|
2274
|
+
let angle;
|
|
2275
|
+
let speed;
|
|
2276
|
+
if (type === "ring") {
|
|
2277
|
+
angle = i / count * Math.PI * 2;
|
|
2278
|
+
speed = between(rng, config.speed[0], config.speed[1]) * .5 + config.speed[0] * .5;
|
|
2279
|
+
} else if (type === "palm" || type === "horsetail") {
|
|
2280
|
+
const spread = type === "horsetail" ? Math.PI / 8 : Math.PI / 5;
|
|
2281
|
+
angle = -Math.PI / 2 + between(rng, -spread, spread);
|
|
2282
|
+
}
|
|
2283
|
+
explosions.push(new Explosion(position, effectiveHue, lineWidth, type, scale, angle, speed));
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
return explosions;
|
|
2288
|
+
}
|
|
2289
|
+
function createSaturn(explosions, position, hue, lineWidth, scale, rng) {
|
|
2290
|
+
const velocity = between(rng, 4, 6);
|
|
2291
|
+
const shellCount = Math.floor(between(rng, 25, 35));
|
|
2292
|
+
for (let i = 0; i < shellCount; i++) {
|
|
2293
|
+
const rad = i / shellCount * Math.PI * 2;
|
|
2294
|
+
explosions.push(new Explosion(position, hue, lineWidth, "peony", scale, rad + between(rng, -.05, .05), velocity + between(rng, -.25, .25)));
|
|
2295
|
+
}
|
|
2296
|
+
const fillCount = Math.floor(between(rng, 40, 60));
|
|
2297
|
+
for (let i = 0; i < fillCount; i++) explosions.push(new Explosion(position, hue, lineWidth, "peony", scale, between(rng, 0, Math.PI * 2), velocity * between(rng, 0, 1)));
|
|
2298
|
+
const ringRotation = between(rng, 0, Math.PI * 2);
|
|
2299
|
+
const ringCount = Math.floor(between(rng, 40, 55));
|
|
2300
|
+
const ringVx = velocity * between(rng, 2, 3);
|
|
2301
|
+
const ringVy = velocity * .6;
|
|
2302
|
+
for (let i = 0; i < ringCount; i++) {
|
|
2303
|
+
const rad = i / ringCount * Math.PI * 2;
|
|
2304
|
+
const cx = Math.cos(rad) * ringVx + between(rng, -.25, .25);
|
|
2305
|
+
const cy = Math.sin(rad) * ringVy + between(rng, -.25, .25);
|
|
2306
|
+
const cosR = Math.cos(ringRotation);
|
|
2307
|
+
const sinR = Math.sin(ringRotation);
|
|
2308
|
+
const vx = cx * cosR - cy * sinR;
|
|
2309
|
+
const vy = cx * sinR + cy * cosR;
|
|
2310
|
+
const vz = Math.sin(rad) * velocity * .8;
|
|
2311
|
+
explosions.push(new Explosion(position, hue + 60, lineWidth, "ring", scale, Math.atan2(vy, vx), Math.sqrt(vx * vx + vy * vy), vz));
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
function createDahlia(explosions, position, hue, lineWidth, scale, rng) {
|
|
2315
|
+
const petalCount = Math.floor(between(rng, 6, 9));
|
|
2316
|
+
const particlesPerPetal = Math.floor(between(rng, 8, 12));
|
|
2317
|
+
for (let petal = 0; petal < petalCount; petal++) {
|
|
2318
|
+
const baseAngle = petal / petalCount * Math.PI * 2;
|
|
2319
|
+
const petalHue = hue + (petal % 2 === 0 ? 25 : -25);
|
|
2320
|
+
for (let i = 0; i < particlesPerPetal; i++) explosions.push(new Explosion(position, petalHue, lineWidth, "dahlia", scale, baseAngle + between(rng, -.3, .3)));
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
function createHeart(explosions, position, hue, lineWidth, scale, rng) {
|
|
2324
|
+
const velocity = between(rng, 3, 5);
|
|
2325
|
+
const count = Math.floor(between(rng, 60, 80));
|
|
2326
|
+
const rotation = between(rng, -.3, .3);
|
|
2327
|
+
const cosR = Math.cos(rotation);
|
|
2328
|
+
const sinR = Math.sin(rotation);
|
|
2329
|
+
for (let i = 0; i < count; i++) {
|
|
2330
|
+
const t = i / count * Math.PI * 2;
|
|
2331
|
+
const hx = 16 * Math.pow(Math.sin(t), 3);
|
|
2332
|
+
const hy = -(13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t));
|
|
2333
|
+
const s = velocity / 16;
|
|
2334
|
+
const vx = hx * s;
|
|
2335
|
+
const vy = hy * s;
|
|
2336
|
+
const rvx = vx * cosR - vy * sinR;
|
|
2337
|
+
const rvy = vx * sinR + vy * cosR;
|
|
2338
|
+
explosions.push(new Explosion(position, hue, lineWidth, "heart", scale, Math.atan2(rvy, rvx), Math.max(.1, Math.sqrt(rvx * rvx + rvy * rvy) + between(rng, -.15, .15))));
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
function createSpiral(explosions, position, hue, lineWidth, scale, rng) {
|
|
2342
|
+
const arms = Math.floor(between(rng, 3, 5));
|
|
2343
|
+
const particlesPerArm = Math.floor(between(rng, 15, 20));
|
|
2344
|
+
const twist = between(rng, 2, 3.5);
|
|
2345
|
+
const baseRotation = between(rng, 0, Math.PI * 2);
|
|
2346
|
+
for (let arm = 0; arm < arms; arm++) {
|
|
2347
|
+
const baseAngle = baseRotation + arm / arms * Math.PI * 2;
|
|
2348
|
+
const armHue = hue + arm * (360 / arms / 3);
|
|
2349
|
+
for (let i = 0; i < particlesPerArm; i++) {
|
|
2350
|
+
const progress = i / particlesPerArm;
|
|
2351
|
+
explosions.push(new Explosion(position, armHue, lineWidth, "spiral", scale, baseAngle + progress * twist, 2 + progress * 8 + between(rng, -.3, .3)));
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
function createFlower(explosions, position, hue, lineWidth, scale, rng) {
|
|
2356
|
+
const velocity = between(rng, 4, 7);
|
|
2357
|
+
const count = Math.floor(between(rng, 70, 90));
|
|
2358
|
+
const petals = Math.floor(between(rng, 2, 4));
|
|
2359
|
+
const rotation = between(rng, 0, Math.PI * 2);
|
|
2360
|
+
for (let i = 0; i < count; i++) {
|
|
2361
|
+
const t = i / count * Math.PI * 2;
|
|
2362
|
+
const speed = velocity * Math.abs(Math.cos(petals * t));
|
|
2363
|
+
if (speed < .3) continue;
|
|
2364
|
+
explosions.push(new Explosion(position, hue + between(rng, -15, 15), lineWidth, "flower", scale, t + rotation, speed + between(rng, -.2, .2)));
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
function createConcentric(explosions, position, hue, lineWidth, scale, rng) {
|
|
2368
|
+
const outerCount = Math.floor(between(rng, 35, 50));
|
|
2369
|
+
const outerSpeed = between(rng, 7, 10);
|
|
2370
|
+
for (let i = 0; i < outerCount; i++) {
|
|
2371
|
+
const angle = i / outerCount * Math.PI * 2;
|
|
2372
|
+
explosions.push(new Explosion(position, hue, lineWidth, "ring", scale, angle + between(rng, -.05, .05), outerSpeed + between(rng, -.25, .25)));
|
|
2373
|
+
}
|
|
2374
|
+
const innerCount = Math.floor(between(rng, 25, 35));
|
|
2375
|
+
const innerSpeed = between(rng, 3, 5);
|
|
2376
|
+
for (let i = 0; i < innerCount; i++) {
|
|
2377
|
+
const angle = i / innerCount * Math.PI * 2;
|
|
2378
|
+
explosions.push(new Explosion(position, hue + 120, lineWidth, "ring", scale, angle + between(rng, -.05, .05), innerSpeed + between(rng, -.25, .25)));
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
//#endregion
|
|
2035
2382
|
//#region src/distance.ts
|
|
2036
2383
|
function distance(a, b) {
|
|
2037
2384
|
let x = a.x - b.x;
|
|
@@ -2047,7 +2394,7 @@ var Spark = class {
|
|
|
2047
2394
|
#size;
|
|
2048
2395
|
#decay;
|
|
2049
2396
|
#friction = .94;
|
|
2050
|
-
#gravity = .
|
|
2397
|
+
#gravity = .3;
|
|
2051
2398
|
#alpha = 1;
|
|
2052
2399
|
get isDead() {
|
|
2053
2400
|
return this.#alpha <= 0;
|
|
@@ -2062,7 +2409,7 @@ var Spark = class {
|
|
|
2062
2409
|
this.#decay = MULBERRY$16.nextBetween(.03, .08);
|
|
2063
2410
|
this.#velocity = {
|
|
2064
2411
|
x: velocityX + MULBERRY$16.nextBetween(-1.5, 1.5),
|
|
2065
|
-
y: velocityY + MULBERRY$16.nextBetween(-2,
|
|
2412
|
+
y: velocityY + MULBERRY$16.nextBetween(-2, 2)
|
|
2066
2413
|
};
|
|
2067
2414
|
}
|
|
2068
2415
|
draw(ctx) {
|
|
@@ -2175,7 +2522,7 @@ var Firework = class extends EventTarget {
|
|
|
2175
2522
|
};
|
|
2176
2523
|
//#endregion
|
|
2177
2524
|
//#region src/fireworks/layer.ts
|
|
2178
|
-
var
|
|
2525
|
+
var Fireworks = class extends Effect {
|
|
2179
2526
|
#explosions = [];
|
|
2180
2527
|
#fireworks = [];
|
|
2181
2528
|
#sparks = [];
|
|
@@ -2183,6 +2530,7 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2183
2530
|
#spawnTimer = 0;
|
|
2184
2531
|
#positionRandom = MULBERRY$16.fork();
|
|
2185
2532
|
#autoSpawn;
|
|
2533
|
+
#variants;
|
|
2186
2534
|
#baseSize;
|
|
2187
2535
|
#scale;
|
|
2188
2536
|
#tailWidth;
|
|
@@ -2192,6 +2540,7 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2192
2540
|
super();
|
|
2193
2541
|
const scale = config.scale ?? 1;
|
|
2194
2542
|
this.#autoSpawn = config.autoSpawn ?? true;
|
|
2543
|
+
this.#variants = config.variants?.length ? [...config.variants] : [...FIREWORK_VARIANTS];
|
|
2195
2544
|
this.#baseSize = 5 * scale;
|
|
2196
2545
|
this.#scale = scale;
|
|
2197
2546
|
this.#tailWidth = 2 * scale;
|
|
@@ -2200,13 +2549,18 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2200
2549
|
this.#width = width;
|
|
2201
2550
|
this.#height = height;
|
|
2202
2551
|
}
|
|
2203
|
-
|
|
2552
|
+
launch(variant, position) {
|
|
2204
2553
|
const pos = position ?? {
|
|
2205
2554
|
x: this.#width / 2,
|
|
2206
2555
|
y: this.#height * .4
|
|
2207
2556
|
};
|
|
2208
2557
|
this.#hue = MULBERRY$16.nextBetween(0, 360);
|
|
2209
|
-
this.#
|
|
2558
|
+
this.#spawnExplosion(pos, this.#hue, variant);
|
|
2559
|
+
}
|
|
2560
|
+
configure(config) {
|
|
2561
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
2562
|
+
if (config.autoSpawn !== void 0) this.#autoSpawn = config.autoSpawn;
|
|
2563
|
+
if (Array.isArray(config.variants) && config.variants.length > 0) this.#variants = [...config.variants];
|
|
2210
2564
|
}
|
|
2211
2565
|
tick(dt, width, height) {
|
|
2212
2566
|
this.#width = width;
|
|
@@ -2223,7 +2577,8 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2223
2577
|
}
|
|
2224
2578
|
for (const firework of this.#fireworks) {
|
|
2225
2579
|
firework.tick(dt);
|
|
2226
|
-
|
|
2580
|
+
const collected = firework.collectSparks();
|
|
2581
|
+
for (let i = 0; i < collected.length; i++) this.#sparks.push(collected[i]);
|
|
2227
2582
|
}
|
|
2228
2583
|
for (const explosion of this.#explosions) explosion.tick(dt);
|
|
2229
2584
|
for (const spark of this.#sparks) spark.tick(dt);
|
|
@@ -2234,12 +2589,20 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2234
2589
|
const angle = explosion.angle + Math.PI / 2 * i + Math.PI / 4;
|
|
2235
2590
|
newExplosions.push(new Explosion(explosion.position, explosion.hue, this.#baseSize * .6, "peony", this.#scale, angle, MULBERRY$16.nextBetween(3, 6)));
|
|
2236
2591
|
}
|
|
2237
|
-
if (explosion.checkCrackle()) for (let j = 0; j <
|
|
2592
|
+
if (explosion.checkCrackle()) for (let j = 0; j < 14; j++) {
|
|
2593
|
+
const angle = MULBERRY$16.nextBetween(0, Math.PI * 2);
|
|
2594
|
+
const speed = MULBERRY$16.nextBetween(3, 8);
|
|
2595
|
+
newSparks.push(new Spark(explosion.position, explosion.hue + MULBERRY$16.nextBetween(-30, 30), Math.cos(angle) * speed, Math.sin(angle) * speed));
|
|
2596
|
+
}
|
|
2238
2597
|
}
|
|
2239
2598
|
this.#explosions.push(...newExplosions);
|
|
2240
2599
|
this.#sparks.push(...newSparks);
|
|
2241
|
-
|
|
2242
|
-
|
|
2600
|
+
let aliveExplosions = 0;
|
|
2601
|
+
for (let i = 0; i < this.#explosions.length; i++) if (!this.#explosions[i].isDead) this.#explosions[aliveExplosions++] = this.#explosions[i];
|
|
2602
|
+
this.#explosions.length = aliveExplosions;
|
|
2603
|
+
let aliveSparks = 0;
|
|
2604
|
+
for (let i = 0; i < this.#sparks.length; i++) if (!this.#sparks[i].isDead) this.#sparks[aliveSparks++] = this.#sparks[i];
|
|
2605
|
+
this.#sparks.length = aliveSparks;
|
|
2243
2606
|
}
|
|
2244
2607
|
draw(ctx, width, height) {
|
|
2245
2608
|
if (ctx.canvas.width !== width || ctx.canvas.height !== height) {
|
|
@@ -2252,153 +2615,13 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2252
2615
|
for (const firework of this.#fireworks) firework.draw(ctx);
|
|
2253
2616
|
ctx.globalCompositeOperation = "source-over";
|
|
2254
2617
|
}
|
|
2255
|
-
#
|
|
2618
|
+
#spawnExplosion(position, hue, variant) {
|
|
2256
2619
|
const selected = variant ?? this.#pickVariant();
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
this.#createDahliaExplosion(position, hue);
|
|
2263
|
-
return;
|
|
2264
|
-
}
|
|
2265
|
-
if (selected === "heart") {
|
|
2266
|
-
this.#createHeartExplosion(position, hue);
|
|
2267
|
-
return;
|
|
2268
|
-
}
|
|
2269
|
-
if (selected === "spiral") {
|
|
2270
|
-
this.#createSpiralExplosion(position, hue);
|
|
2271
|
-
return;
|
|
2272
|
-
}
|
|
2273
|
-
if (selected === "flower") {
|
|
2274
|
-
this.#createFlowerExplosion(position, hue);
|
|
2275
|
-
return;
|
|
2276
|
-
}
|
|
2277
|
-
if (selected === "concentric") {
|
|
2278
|
-
this.#createConcentricExplosion(position, hue);
|
|
2279
|
-
return;
|
|
2280
|
-
}
|
|
2281
|
-
const type = selected;
|
|
2282
|
-
const config = EXPLOSION_CONFIGS[type];
|
|
2283
|
-
const particleCount = Math.floor(MULBERRY$16.nextBetween(config.particleCount[0], config.particleCount[1]));
|
|
2284
|
-
const effectiveHue = type === "brocade" ? MULBERRY$16.nextBetween(35, 50) : hue;
|
|
2285
|
-
for (let i = 0; i < particleCount; i++) {
|
|
2286
|
-
let angle;
|
|
2287
|
-
let speed;
|
|
2288
|
-
if (type === "ring") {
|
|
2289
|
-
angle = i / particleCount * Math.PI * 2;
|
|
2290
|
-
speed = MULBERRY$16.nextBetween(config.speed[0], config.speed[1]) * .5 + config.speed[0] * .5;
|
|
2291
|
-
} else if (type === "palm" || type === "horsetail") {
|
|
2292
|
-
const spread = type === "horsetail" ? Math.PI / 8 : Math.PI / 5;
|
|
2293
|
-
angle = -Math.PI / 2 + MULBERRY$16.nextBetween(-spread, spread);
|
|
2294
|
-
}
|
|
2295
|
-
this.#explosions.push(new Explosion(position, effectiveHue, this.#baseSize, type, this.#scale, angle, speed));
|
|
2296
|
-
}
|
|
2297
|
-
}
|
|
2298
|
-
#createSaturnExplosion(position, hue) {
|
|
2299
|
-
const velocity = MULBERRY$16.nextBetween(4, 6);
|
|
2300
|
-
const shellCount = Math.floor(MULBERRY$16.nextBetween(25, 35));
|
|
2301
|
-
for (let i = 0; i < shellCount; i++) {
|
|
2302
|
-
const rad = i / shellCount * Math.PI * 2;
|
|
2303
|
-
this.#explosions.push(new Explosion(position, hue, this.#baseSize, "peony", this.#scale, rad + MULBERRY$16.nextBetween(-.05, .05), velocity + MULBERRY$16.nextBetween(-.25, .25)));
|
|
2304
|
-
}
|
|
2305
|
-
const fillCount = Math.floor(MULBERRY$16.nextBetween(40, 60));
|
|
2306
|
-
for (let i = 0; i < fillCount; i++) {
|
|
2307
|
-
const rad = MULBERRY$16.nextBetween(0, Math.PI * 2);
|
|
2308
|
-
const speed = velocity * MULBERRY$16.nextBetween(0, 1);
|
|
2309
|
-
this.#explosions.push(new Explosion(position, hue, this.#baseSize, "peony", this.#scale, rad, speed));
|
|
2310
|
-
}
|
|
2311
|
-
const ringRotation = MULBERRY$16.nextBetween(0, Math.PI * 2);
|
|
2312
|
-
const ringCount = Math.floor(MULBERRY$16.nextBetween(40, 55));
|
|
2313
|
-
const ringVx = velocity * MULBERRY$16.nextBetween(2, 3);
|
|
2314
|
-
const ringVy = velocity * .6;
|
|
2315
|
-
for (let i = 0; i < ringCount; i++) {
|
|
2316
|
-
const rad = i / ringCount * Math.PI * 2;
|
|
2317
|
-
const cx = Math.cos(rad) * ringVx + MULBERRY$16.nextBetween(-.25, .25);
|
|
2318
|
-
const cy = Math.sin(rad) * ringVy + MULBERRY$16.nextBetween(-.25, .25);
|
|
2319
|
-
const cosR = Math.cos(ringRotation);
|
|
2320
|
-
const sinR = Math.sin(ringRotation);
|
|
2321
|
-
const vx = cx * cosR - cy * sinR;
|
|
2322
|
-
const vy = cx * sinR + cy * cosR;
|
|
2323
|
-
const screenAngle = Math.atan2(vy, vx);
|
|
2324
|
-
const screenSpeed = Math.sqrt(vx * vx + vy * vy);
|
|
2325
|
-
const vz = Math.sin(rad) * velocity * .8;
|
|
2326
|
-
this.#explosions.push(new Explosion(position, hue + 60, this.#baseSize, "ring", this.#scale, screenAngle, screenSpeed, vz));
|
|
2327
|
-
}
|
|
2328
|
-
}
|
|
2329
|
-
#createDahliaExplosion(position, hue) {
|
|
2330
|
-
const petalCount = Math.floor(MULBERRY$16.nextBetween(6, 9));
|
|
2331
|
-
const particlesPerPetal = Math.floor(MULBERRY$16.nextBetween(8, 12));
|
|
2332
|
-
for (let petal = 0; petal < petalCount; petal++) {
|
|
2333
|
-
const baseAngle = petal / petalCount * Math.PI * 2;
|
|
2334
|
-
const petalHue = hue + (petal % 2 === 0 ? 25 : -25);
|
|
2335
|
-
for (let i = 0; i < particlesPerPetal; i++) {
|
|
2336
|
-
const angle = baseAngle + MULBERRY$16.nextBetween(-.3, .3);
|
|
2337
|
-
this.#explosions.push(new Explosion(position, petalHue, this.#baseSize, "dahlia", this.#scale, angle));
|
|
2338
|
-
}
|
|
2339
|
-
}
|
|
2340
|
-
}
|
|
2341
|
-
#createHeartExplosion(position, hue) {
|
|
2342
|
-
const velocity = MULBERRY$16.nextBetween(3, 5);
|
|
2343
|
-
const count = Math.floor(MULBERRY$16.nextBetween(60, 80));
|
|
2344
|
-
const rotation = MULBERRY$16.nextBetween(-.3, .3);
|
|
2345
|
-
for (let i = 0; i < count; i++) {
|
|
2346
|
-
const t = i / count * Math.PI * 2;
|
|
2347
|
-
const hx = 16 * Math.pow(Math.sin(t), 3);
|
|
2348
|
-
const hy = -(13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t));
|
|
2349
|
-
const scale = velocity / 16;
|
|
2350
|
-
const vx = hx * scale;
|
|
2351
|
-
const vy = hy * scale;
|
|
2352
|
-
const cosR = Math.cos(rotation);
|
|
2353
|
-
const sinR = Math.sin(rotation);
|
|
2354
|
-
const rvx = vx * cosR - vy * sinR;
|
|
2355
|
-
const rvy = vx * sinR + vy * cosR;
|
|
2356
|
-
const angle = Math.atan2(rvy, rvx);
|
|
2357
|
-
const speed = Math.sqrt(rvx * rvx + rvy * rvy);
|
|
2358
|
-
this.#explosions.push(new Explosion(position, hue, this.#baseSize, "heart", this.#scale, angle, Math.max(.1, speed + MULBERRY$16.nextBetween(-.15, .15))));
|
|
2359
|
-
}
|
|
2360
|
-
}
|
|
2361
|
-
#createSpiralExplosion(position, hue) {
|
|
2362
|
-
const arms = Math.floor(MULBERRY$16.nextBetween(3, 5));
|
|
2363
|
-
const particlesPerArm = Math.floor(MULBERRY$16.nextBetween(15, 20));
|
|
2364
|
-
const twist = MULBERRY$16.nextBetween(2, 3.5);
|
|
2365
|
-
const baseRotation = MULBERRY$16.nextBetween(0, Math.PI * 2);
|
|
2366
|
-
for (let arm = 0; arm < arms; arm++) {
|
|
2367
|
-
const baseAngle = baseRotation + arm / arms * Math.PI * 2;
|
|
2368
|
-
const armHue = hue + arm * (360 / arms / 3);
|
|
2369
|
-
for (let i = 0; i < particlesPerArm; i++) {
|
|
2370
|
-
const progress = i / particlesPerArm;
|
|
2371
|
-
const angle = baseAngle + progress * twist;
|
|
2372
|
-
const speed = 2 + progress * 8;
|
|
2373
|
-
this.#explosions.push(new Explosion(position, armHue, this.#baseSize, "spiral", this.#scale, angle, speed + MULBERRY$16.nextBetween(-.3, .3)));
|
|
2374
|
-
}
|
|
2375
|
-
}
|
|
2376
|
-
}
|
|
2377
|
-
#createFlowerExplosion(position, hue) {
|
|
2378
|
-
const velocity = MULBERRY$16.nextBetween(4, 7);
|
|
2379
|
-
const count = Math.floor(MULBERRY$16.nextBetween(70, 90));
|
|
2380
|
-
const petals = Math.floor(MULBERRY$16.nextBetween(2, 4));
|
|
2381
|
-
const rotation = MULBERRY$16.nextBetween(0, Math.PI * 2);
|
|
2382
|
-
for (let i = 0; i < count; i++) {
|
|
2383
|
-
const t = i / count * Math.PI * 2;
|
|
2384
|
-
const speed = velocity * Math.abs(Math.cos(petals * t));
|
|
2385
|
-
if (speed < .3) continue;
|
|
2386
|
-
this.#explosions.push(new Explosion(position, hue + MULBERRY$16.nextBetween(-15, 15), this.#baseSize, "flower", this.#scale, t + rotation, speed + MULBERRY$16.nextBetween(-.2, .2)));
|
|
2387
|
-
}
|
|
2388
|
-
}
|
|
2389
|
-
#createConcentricExplosion(position, hue) {
|
|
2390
|
-
const outerCount = Math.floor(MULBERRY$16.nextBetween(35, 50));
|
|
2391
|
-
const outerSpeed = MULBERRY$16.nextBetween(7, 10);
|
|
2392
|
-
for (let i = 0; i < outerCount; i++) {
|
|
2393
|
-
const angle = i / outerCount * Math.PI * 2;
|
|
2394
|
-
this.#explosions.push(new Explosion(position, hue, this.#baseSize, "ring", this.#scale, angle + MULBERRY$16.nextBetween(-.05, .05), outerSpeed + MULBERRY$16.nextBetween(-.25, .25)));
|
|
2395
|
-
}
|
|
2396
|
-
const innerCount = Math.floor(MULBERRY$16.nextBetween(25, 35));
|
|
2397
|
-
const innerSpeed = MULBERRY$16.nextBetween(3, 5);
|
|
2398
|
-
for (let i = 0; i < innerCount; i++) {
|
|
2399
|
-
const angle = i / innerCount * Math.PI * 2;
|
|
2400
|
-
this.#explosions.push(new Explosion(position, hue + 120, this.#baseSize, "ring", this.#scale, angle + MULBERRY$16.nextBetween(-.05, .05), innerSpeed + MULBERRY$16.nextBetween(-.25, .25)));
|
|
2401
|
-
}
|
|
2620
|
+
const rng = () => MULBERRY$16.nextBetween(0, 1);
|
|
2621
|
+
this.#explosions.push(...createExplosion(selected, position, hue, {
|
|
2622
|
+
lineWidth: this.#baseSize,
|
|
2623
|
+
scale: this.#scale
|
|
2624
|
+
}, rng));
|
|
2402
2625
|
}
|
|
2403
2626
|
#createFirework(position) {
|
|
2404
2627
|
const hue = this.#hue;
|
|
@@ -2413,43 +2636,20 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2413
2636
|
}, hue, this.#tailWidth, this.#baseSize);
|
|
2414
2637
|
firework.addEventListener("remove", () => {
|
|
2415
2638
|
this.#fireworks.splice(this.#fireworks.indexOf(firework), 1);
|
|
2416
|
-
this.#
|
|
2639
|
+
this.#spawnExplosion(firework.position, hue);
|
|
2417
2640
|
}, { once: true });
|
|
2418
2641
|
this.#fireworks.push(firework);
|
|
2419
2642
|
}
|
|
2420
2643
|
#pickVariant() {
|
|
2421
|
-
const
|
|
2422
|
-
|
|
2423
|
-
if (roll < 22) return "chrysanthemum";
|
|
2424
|
-
if (roll < 29) return "willow";
|
|
2425
|
-
if (roll < 34) return "ring";
|
|
2426
|
-
if (roll < 39) return "palm";
|
|
2427
|
-
if (roll < 44) return "crackle";
|
|
2428
|
-
if (roll < 48) return "crossette";
|
|
2429
|
-
if (roll < 55) return "saturn";
|
|
2430
|
-
if (roll < 62) return "dahlia";
|
|
2431
|
-
if (roll < 67) return "brocade";
|
|
2432
|
-
if (roll < 71) return "horsetail";
|
|
2433
|
-
if (roll < 75) return "strobe";
|
|
2434
|
-
if (roll < 82) return "heart";
|
|
2435
|
-
if (roll < 89) return "spiral";
|
|
2436
|
-
if (roll < 94) return "flower";
|
|
2437
|
-
return "concentric";
|
|
2644
|
+
const index = Math.floor(MULBERRY$16.nextBetween(0, this.#variants.length));
|
|
2645
|
+
return this.#variants[index];
|
|
2438
2646
|
}
|
|
2439
2647
|
};
|
|
2440
2648
|
//#endregion
|
|
2441
|
-
//#region src/fireworks/
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
const layer = new FireworkLayer(config);
|
|
2446
|
-
super(canvas, layer, 60, config.canvasOptions ?? { colorSpace: "display-p3" });
|
|
2447
|
-
this.#layer = layer;
|
|
2448
|
-
}
|
|
2449
|
-
fireExplosion(variant, position) {
|
|
2450
|
-
this.#layer.fireExplosion(variant, position);
|
|
2451
|
-
}
|
|
2452
|
-
};
|
|
2649
|
+
//#region src/fireworks/index.ts
|
|
2650
|
+
function createFireworks(config) {
|
|
2651
|
+
return new Fireworks(config);
|
|
2652
|
+
}
|
|
2453
2653
|
//#endregion
|
|
2454
2654
|
//#region src/glitter/consts.ts
|
|
2455
2655
|
const MULBERRY$15 = mulberry32(13);
|
|
@@ -2464,7 +2664,7 @@ const GLITTER_COLORS = [
|
|
|
2464
2664
|
];
|
|
2465
2665
|
//#endregion
|
|
2466
2666
|
//#region src/glitter/layer.ts
|
|
2467
|
-
var
|
|
2667
|
+
var Glitter = class extends Effect {
|
|
2468
2668
|
#scale;
|
|
2469
2669
|
#size;
|
|
2470
2670
|
#speed;
|
|
@@ -2487,6 +2687,10 @@ var GlitterLayer = class extends SimulationLayer {
|
|
|
2487
2687
|
if (innerWidth < 991) this.#maxCount = Math.floor(this.#maxCount / 2);
|
|
2488
2688
|
for (let i = 0; i < this.#maxCount; ++i) this.#falling.push(this.#createFallingPiece(true));
|
|
2489
2689
|
}
|
|
2690
|
+
configure(config) {
|
|
2691
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
2692
|
+
if (config.groundLevel !== void 0) this.#groundLevel = config.groundLevel;
|
|
2693
|
+
}
|
|
2490
2694
|
tick(dt, _width, _height) {
|
|
2491
2695
|
this.#time += .03 * dt;
|
|
2492
2696
|
let alive = 0;
|
|
@@ -2586,12 +2790,10 @@ var GlitterLayer = class extends SimulationLayer {
|
|
|
2586
2790
|
}
|
|
2587
2791
|
};
|
|
2588
2792
|
//#endregion
|
|
2589
|
-
//#region src/glitter/
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
}
|
|
2594
|
-
};
|
|
2793
|
+
//#region src/glitter/index.ts
|
|
2794
|
+
function createGlitter(config) {
|
|
2795
|
+
return new Glitter(config);
|
|
2796
|
+
}
|
|
2595
2797
|
//#endregion
|
|
2596
2798
|
//#region src/lanterns/consts.ts
|
|
2597
2799
|
const MULBERRY$14 = mulberry32(13);
|
|
@@ -2606,7 +2808,7 @@ const LANTERN_COLORS = [
|
|
|
2606
2808
|
];
|
|
2607
2809
|
//#endregion
|
|
2608
2810
|
//#region src/lanterns/layer.ts
|
|
2609
|
-
var
|
|
2811
|
+
var Lanterns = class extends Effect {
|
|
2610
2812
|
#scale;
|
|
2611
2813
|
#speed;
|
|
2612
2814
|
#size;
|
|
@@ -2614,6 +2816,8 @@ var LanternLayer = class extends SimulationLayer {
|
|
|
2614
2816
|
#maxCount;
|
|
2615
2817
|
#time = 0;
|
|
2616
2818
|
#lanterns = [];
|
|
2819
|
+
#sortedLanterns = [];
|
|
2820
|
+
#sortDirty = true;
|
|
2617
2821
|
constructor(config = {}) {
|
|
2618
2822
|
super();
|
|
2619
2823
|
this.#scale = config.scale ?? 1;
|
|
@@ -2624,6 +2828,9 @@ var LanternLayer = class extends SimulationLayer {
|
|
|
2624
2828
|
if (innerWidth < 991) this.#maxCount = Math.floor(this.#maxCount / 2);
|
|
2625
2829
|
for (let i = 0; i < this.#maxCount; ++i) this.#lanterns.push(this.#createLantern(true));
|
|
2626
2830
|
}
|
|
2831
|
+
configure(config) {
|
|
2832
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
2833
|
+
}
|
|
2627
2834
|
tick(dt, width, height) {
|
|
2628
2835
|
this.#time += .02 * dt * this.#speed;
|
|
2629
2836
|
for (let i = 0; i < this.#lanterns.length; i++) {
|
|
@@ -2631,11 +2838,18 @@ var LanternLayer = class extends SimulationLayer {
|
|
|
2631
2838
|
lantern.y -= lantern.vy * this.#speed * dt / (height * 1.5);
|
|
2632
2839
|
const sway = Math.sin(this.#time * lantern.swaySpeed + lantern.swayPhase) * lantern.swayAmplitude;
|
|
2633
2840
|
lantern.x += sway * dt / (width * 8);
|
|
2634
|
-
if (lantern.y < -.15)
|
|
2841
|
+
if (lantern.y < -.15) {
|
|
2842
|
+
this.#lanterns[i] = this.#createLantern(false);
|
|
2843
|
+
this.#sortDirty = true;
|
|
2844
|
+
}
|
|
2635
2845
|
}
|
|
2636
2846
|
}
|
|
2637
2847
|
draw(ctx, width, height) {
|
|
2638
|
-
|
|
2848
|
+
if (this.#sortDirty) {
|
|
2849
|
+
this.#sortedLanterns = [...this.#lanterns].sort((a, b) => a.size - b.size);
|
|
2850
|
+
this.#sortDirty = false;
|
|
2851
|
+
}
|
|
2852
|
+
const sorted = this.#sortedLanterns;
|
|
2639
2853
|
for (const lantern of sorted) {
|
|
2640
2854
|
const px = lantern.x * width;
|
|
2641
2855
|
const py = lantern.y * height;
|
|
@@ -2653,8 +2867,7 @@ var LanternLayer = class extends SimulationLayer {
|
|
|
2653
2867
|
ctx.beginPath();
|
|
2654
2868
|
ctx.arc(px, py, glowRadius, 0, Math.PI * 2);
|
|
2655
2869
|
ctx.fill();
|
|
2656
|
-
ctx.
|
|
2657
|
-
ctx.translate(px, py);
|
|
2870
|
+
ctx.setTransform(1, 0, 0, 1, px, py);
|
|
2658
2871
|
const bodyW = size * .8;
|
|
2659
2872
|
const bodyH = size;
|
|
2660
2873
|
const topW = bodyW * .6;
|
|
@@ -2664,210 +2877,69 @@ var LanternLayer = class extends SimulationLayer {
|
|
|
2664
2877
|
ctx.lineTo(bodyW * .7, bodyH * .5);
|
|
2665
2878
|
ctx.quadraticCurveTo(bodyW, 0, topW, -bodyH * .5);
|
|
2666
2879
|
ctx.closePath();
|
|
2667
|
-
const bodyGradient = ctx.createLinearGradient(0, -bodyH * .5, 0, bodyH * .5);
|
|
2668
|
-
bodyGradient.addColorStop(0, `rgba(${Math.min(255, r + 60)}, ${Math.min(255, g + 60)}, ${Math.min(255, b + 30)}, ${alpha * .9})`);
|
|
2669
|
-
bodyGradient.addColorStop(.5, `rgba(${r}, ${g}, ${b}, ${alpha * .85})`);
|
|
2670
|
-
bodyGradient.addColorStop(1, `rgba(${Math.max(0, r - 30)}, ${Math.max(0, g - 30)}, ${Math.max(0, b - 20)}, ${alpha * .8})`);
|
|
2671
|
-
ctx.fillStyle = bodyGradient;
|
|
2672
|
-
ctx.fill();
|
|
2673
|
-
ctx.beginPath();
|
|
2674
|
-
ctx.moveTo(-topW * .7, -bodyH * .55);
|
|
2675
|
-
ctx.lineTo(topW * .7, -bodyH * .55);
|
|
2676
|
-
ctx.lineWidth = size * .06;
|
|
2677
|
-
ctx.strokeStyle = `rgba(${Math.max(0, r - 40)}, ${Math.max(0, g - 40)}, ${Math.max(0, b - 40)}, ${alpha * .7})`;
|
|
2678
|
-
ctx.stroke();
|
|
2679
|
-
const flameH = bodyH * .3;
|
|
2680
|
-
const flameW = bodyW * .15;
|
|
2681
|
-
const flameFlicker = Math.sin(this.#time * 8 + lantern.glowPhase) * flameW * .3;
|
|
2682
|
-
const flameGradient = ctx.createRadialGradient(flameFlicker, -flameH * .1, 0, flameFlicker, -flameH * .1, flameH);
|
|
2683
|
-
flameGradient.addColorStop(0, `rgba(255, 255, 200, ${alpha * .95})`);
|
|
2684
|
-
flameGradient.addColorStop(.3, `rgba(255, 200, 80, ${alpha * .7})`);
|
|
2685
|
-
flameGradient.addColorStop(.7, `rgba(255, 140, 40, ${alpha * .3})`);
|
|
2686
|
-
flameGradient.addColorStop(1, `rgba(255, 100, 20, 0)`);
|
|
2687
|
-
ctx.beginPath();
|
|
2688
|
-
ctx.moveTo(-flameW + flameFlicker, flameH * .2);
|
|
2689
|
-
ctx.quadraticCurveTo(-flameW * .5 + flameFlicker, -flameH * .3, flameFlicker, -flameH);
|
|
2690
|
-
ctx.quadraticCurveTo(flameW * .5 + flameFlicker, -flameH * .3, flameW + flameFlicker, flameH * .2);
|
|
2691
|
-
ctx.closePath();
|
|
2692
|
-
ctx.fillStyle = flameGradient;
|
|
2693
|
-
ctx.fill();
|
|
2694
|
-
const stringLen = size * .6;
|
|
2695
|
-
const stringDrift = Math.sin(this.#time * 1.5 + lantern.swayPhase) * size * .1;
|
|
2696
|
-
ctx.beginPath();
|
|
2697
|
-
ctx.moveTo(0, bodyH * .5);
|
|
2698
|
-
ctx.quadraticCurveTo(stringDrift, bodyH * .5 + stringLen * .5, -stringDrift * .5, bodyH * .5 + stringLen);
|
|
2699
|
-
ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${alpha * .4})`;
|
|
2700
|
-
ctx.lineWidth = size * .04;
|
|
2701
|
-
ctx.stroke();
|
|
2702
|
-
ctx.
|
|
2703
|
-
}
|
|
2704
|
-
}
|
|
2705
|
-
#createLantern(initialSpread) {
|
|
2706
|
-
const colorIndex = Math.floor(MULBERRY$14.next() * this.#colorRGBs.length);
|
|
2707
|
-
const sizeVariation = .6 + MULBERRY$14.next() * .8;
|
|
2708
|
-
return {
|
|
2709
|
-
x: .05 + MULBERRY$14.next() * .9,
|
|
2710
|
-
y: initialSpread ? MULBERRY$14.next() * 1.3 : 1.15 + MULBERRY$14.next() * .2,
|
|
2711
|
-
vx: 0,
|
|
2712
|
-
vy: .2 + MULBERRY$14.next() * .6,
|
|
2713
|
-
size: this.#size * sizeVariation,
|
|
2714
|
-
glowPhase: MULBERRY$14.next() * Math.PI * 2,
|
|
2715
|
-
glowSpeed: .8 + MULBERRY$14.next() * 1.2,
|
|
2716
|
-
swayPhase: MULBERRY$14.next() * Math.PI * 2,
|
|
2717
|
-
swaySpeed: .4 + MULBERRY$14.next() * .8,
|
|
2718
|
-
swayAmplitude: .3 + MULBERRY$14.next() * .7,
|
|
2719
|
-
colorIndex,
|
|
2720
|
-
opacity: .7 + MULBERRY$14.next() * .3
|
|
2721
|
-
};
|
|
2722
|
-
}
|
|
2723
|
-
};
|
|
2724
|
-
//#endregion
|
|
2725
|
-
//#region src/lanterns/simulation.ts
|
|
2726
|
-
var LanternSimulation = class extends SimulationCanvas {
|
|
2727
|
-
constructor(canvas, config = {}) {
|
|
2728
|
-
super(canvas, new LanternLayer(config), 60, config.canvasOptions ?? { colorSpace: "display-p3" });
|
|
2729
|
-
}
|
|
2730
|
-
};
|
|
2731
|
-
//#endregion
|
|
2732
|
-
//#region src/layered.ts
|
|
2733
|
-
function parseSide(side) {
|
|
2734
|
-
return typeof side === "number" ? [0, side] : side;
|
|
2735
|
-
}
|
|
2736
|
-
function applyEdgeFade(ctx, width, height, fade) {
|
|
2737
|
-
ctx.globalCompositeOperation = "destination-out";
|
|
2738
|
-
if (fade.top !== void 0) {
|
|
2739
|
-
const [near, far] = parseSide(fade.top);
|
|
2740
|
-
const nearPx = near * height;
|
|
2741
|
-
const farPx = far * height;
|
|
2742
|
-
if (nearPx > 0) {
|
|
2743
|
-
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
2744
|
-
ctx.fillRect(0, 0, width, nearPx);
|
|
2745
|
-
}
|
|
2746
|
-
if (farPx > nearPx) {
|
|
2747
|
-
const gradient = ctx.createLinearGradient(0, nearPx, 0, farPx);
|
|
2748
|
-
gradient.addColorStop(0, "rgba(0,0,0,1)");
|
|
2749
|
-
gradient.addColorStop(1, "rgba(0,0,0,0)");
|
|
2750
|
-
ctx.fillStyle = gradient;
|
|
2751
|
-
ctx.fillRect(0, nearPx, width, farPx - nearPx);
|
|
2752
|
-
}
|
|
2753
|
-
}
|
|
2754
|
-
if (fade.bottom !== void 0) {
|
|
2755
|
-
const [near, far] = parseSide(fade.bottom);
|
|
2756
|
-
const nearPx = near * height;
|
|
2757
|
-
const farPx = far * height;
|
|
2758
|
-
if (nearPx > 0) {
|
|
2759
|
-
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
2760
|
-
ctx.fillRect(0, height - nearPx, width, nearPx);
|
|
2761
|
-
}
|
|
2762
|
-
if (farPx > nearPx) {
|
|
2763
|
-
const gradient = ctx.createLinearGradient(0, height - farPx, 0, height - nearPx);
|
|
2764
|
-
gradient.addColorStop(0, "rgba(0,0,0,0)");
|
|
2765
|
-
gradient.addColorStop(1, "rgba(0,0,0,1)");
|
|
2766
|
-
ctx.fillStyle = gradient;
|
|
2767
|
-
ctx.fillRect(0, height - farPx, width, farPx - nearPx);
|
|
2768
|
-
}
|
|
2769
|
-
}
|
|
2770
|
-
if (fade.left !== void 0) {
|
|
2771
|
-
const [near, far] = parseSide(fade.left);
|
|
2772
|
-
const nearPx = near * width;
|
|
2773
|
-
const farPx = far * width;
|
|
2774
|
-
if (nearPx > 0) {
|
|
2775
|
-
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
2776
|
-
ctx.fillRect(0, 0, nearPx, height);
|
|
2777
|
-
}
|
|
2778
|
-
if (farPx > nearPx) {
|
|
2779
|
-
const gradient = ctx.createLinearGradient(nearPx, 0, farPx, 0);
|
|
2780
|
-
gradient.addColorStop(0, "rgba(0,0,0,1)");
|
|
2781
|
-
gradient.addColorStop(1, "rgba(0,0,0,0)");
|
|
2782
|
-
ctx.fillStyle = gradient;
|
|
2783
|
-
ctx.fillRect(nearPx, 0, farPx - nearPx, height);
|
|
2784
|
-
}
|
|
2785
|
-
}
|
|
2786
|
-
if (fade.right !== void 0) {
|
|
2787
|
-
const [near, far] = parseSide(fade.right);
|
|
2788
|
-
const nearPx = near * width;
|
|
2789
|
-
const farPx = far * width;
|
|
2790
|
-
if (nearPx > 0) {
|
|
2791
|
-
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
2792
|
-
ctx.fillRect(width - nearPx, 0, nearPx, height);
|
|
2793
|
-
}
|
|
2794
|
-
if (farPx > nearPx) {
|
|
2795
|
-
const gradient = ctx.createLinearGradient(width - farPx, 0, width - nearPx, 0);
|
|
2796
|
-
gradient.addColorStop(0, "rgba(0,0,0,0)");
|
|
2797
|
-
gradient.addColorStop(1, "rgba(0,0,0,1)");
|
|
2798
|
-
ctx.fillStyle = gradient;
|
|
2799
|
-
ctx.fillRect(width - farPx, 0, farPx - nearPx, height);
|
|
2800
|
-
}
|
|
2801
|
-
}
|
|
2802
|
-
ctx.globalCompositeOperation = "source-over";
|
|
2803
|
-
}
|
|
2804
|
-
var LayeredSimulation = class extends LimitedFrameRateCanvas {
|
|
2805
|
-
#layers = [];
|
|
2806
|
-
#contextOptions;
|
|
2807
|
-
#offscreen = null;
|
|
2808
|
-
#offscreenCtx = null;
|
|
2809
|
-
constructor(canvas, frameRate = 60, options = { colorSpace: "display-p3" }) {
|
|
2810
|
-
super(canvas, frameRate, options);
|
|
2811
|
-
this.#contextOptions = options;
|
|
2812
|
-
canvas.style.position = "absolute";
|
|
2813
|
-
canvas.style.top = "0";
|
|
2814
|
-
canvas.style.left = "0";
|
|
2815
|
-
canvas.style.height = "100%";
|
|
2816
|
-
canvas.style.width = "100%";
|
|
2817
|
-
}
|
|
2818
|
-
add(layer) {
|
|
2819
|
-
this.#layers.push(layer);
|
|
2820
|
-
if (this.isTicking) layer.onMount(this.canvas);
|
|
2821
|
-
return this;
|
|
2822
|
-
}
|
|
2823
|
-
start() {
|
|
2824
|
-
for (const layer of this.#layers) layer.onMount(this.canvas);
|
|
2825
|
-
super.start();
|
|
2826
|
-
}
|
|
2827
|
-
destroy() {
|
|
2828
|
-
for (const layer of this.#layers) layer.onUnmount(this.canvas);
|
|
2829
|
-
super.destroy();
|
|
2830
|
-
}
|
|
2831
|
-
draw() {
|
|
2832
|
-
this.canvas.height = this.height;
|
|
2833
|
-
this.canvas.width = this.width;
|
|
2834
|
-
const ctx = this.context;
|
|
2835
|
-
ctx.clearRect(0, 0, this.width, this.height);
|
|
2836
|
-
for (const layer of this.#layers) if (layer.fade) {
|
|
2837
|
-
const offCtx = this.#getOffscreenCtx(this.width, this.height);
|
|
2838
|
-
offCtx.clearRect(0, 0, this.width, this.height);
|
|
2839
|
-
layer.draw(offCtx, this.width, this.height);
|
|
2840
|
-
applyEdgeFade(offCtx, this.width, this.height, layer.fade);
|
|
2841
|
-
ctx.drawImage(this.#offscreen, 0, 0);
|
|
2842
|
-
} else {
|
|
2843
|
-
ctx.save();
|
|
2844
|
-
layer.draw(ctx, this.width, this.height);
|
|
2845
|
-
ctx.restore();
|
|
2846
|
-
}
|
|
2847
|
-
}
|
|
2848
|
-
tick() {
|
|
2849
|
-
const dt = (this.delta > 0 && this.delta < 200 ? this.delta / (1e3 / 60) : 1) * this.speed * LimitedFrameRateCanvas.globalSpeed;
|
|
2850
|
-
for (const layer of this.#layers) layer.tick(dt, this.width, this.height);
|
|
2851
|
-
}
|
|
2852
|
-
onResize() {
|
|
2853
|
-
super.onResize();
|
|
2854
|
-
if (this.#offscreen) {
|
|
2855
|
-
this.#offscreen.width = this.width;
|
|
2856
|
-
this.#offscreen.height = this.height;
|
|
2880
|
+
const bodyGradient = ctx.createLinearGradient(0, -bodyH * .5, 0, bodyH * .5);
|
|
2881
|
+
bodyGradient.addColorStop(0, `rgba(${Math.min(255, r + 60)}, ${Math.min(255, g + 60)}, ${Math.min(255, b + 30)}, ${alpha * .9})`);
|
|
2882
|
+
bodyGradient.addColorStop(.5, `rgba(${r}, ${g}, ${b}, ${alpha * .85})`);
|
|
2883
|
+
bodyGradient.addColorStop(1, `rgba(${Math.max(0, r - 30)}, ${Math.max(0, g - 30)}, ${Math.max(0, b - 20)}, ${alpha * .8})`);
|
|
2884
|
+
ctx.fillStyle = bodyGradient;
|
|
2885
|
+
ctx.fill();
|
|
2886
|
+
ctx.beginPath();
|
|
2887
|
+
ctx.moveTo(-topW * .7, -bodyH * .55);
|
|
2888
|
+
ctx.lineTo(topW * .7, -bodyH * .55);
|
|
2889
|
+
ctx.lineWidth = size * .06;
|
|
2890
|
+
ctx.strokeStyle = `rgba(${Math.max(0, r - 40)}, ${Math.max(0, g - 40)}, ${Math.max(0, b - 40)}, ${alpha * .7})`;
|
|
2891
|
+
ctx.stroke();
|
|
2892
|
+
const flameH = bodyH * .3;
|
|
2893
|
+
const flameW = bodyW * .15;
|
|
2894
|
+
const flameFlicker = Math.sin(this.#time * 8 + lantern.glowPhase) * flameW * .3;
|
|
2895
|
+
const flameGradient = ctx.createRadialGradient(flameFlicker, -flameH * .1, 0, flameFlicker, -flameH * .1, flameH);
|
|
2896
|
+
flameGradient.addColorStop(0, `rgba(255, 255, 200, ${alpha * .95})`);
|
|
2897
|
+
flameGradient.addColorStop(.3, `rgba(255, 200, 80, ${alpha * .7})`);
|
|
2898
|
+
flameGradient.addColorStop(.7, `rgba(255, 140, 40, ${alpha * .3})`);
|
|
2899
|
+
flameGradient.addColorStop(1, `rgba(255, 100, 20, 0)`);
|
|
2900
|
+
ctx.beginPath();
|
|
2901
|
+
ctx.moveTo(-flameW + flameFlicker, flameH * .2);
|
|
2902
|
+
ctx.quadraticCurveTo(-flameW * .5 + flameFlicker, -flameH * .3, flameFlicker, -flameH);
|
|
2903
|
+
ctx.quadraticCurveTo(flameW * .5 + flameFlicker, -flameH * .3, flameW + flameFlicker, flameH * .2);
|
|
2904
|
+
ctx.closePath();
|
|
2905
|
+
ctx.fillStyle = flameGradient;
|
|
2906
|
+
ctx.fill();
|
|
2907
|
+
const stringLen = size * .6;
|
|
2908
|
+
const stringDrift = Math.sin(this.#time * 1.5 + lantern.swayPhase) * size * .1;
|
|
2909
|
+
ctx.beginPath();
|
|
2910
|
+
ctx.moveTo(0, bodyH * .5);
|
|
2911
|
+
ctx.quadraticCurveTo(stringDrift, bodyH * .5 + stringLen * .5, -stringDrift * .5, bodyH * .5 + stringLen);
|
|
2912
|
+
ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${alpha * .4})`;
|
|
2913
|
+
ctx.lineWidth = size * .04;
|
|
2914
|
+
ctx.stroke();
|
|
2915
|
+
ctx.resetTransform();
|
|
2857
2916
|
}
|
|
2858
|
-
for (const layer of this.#layers) layer.onResize(this.width, this.height);
|
|
2859
2917
|
}
|
|
2860
|
-
#
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2918
|
+
#createLantern(initialSpread) {
|
|
2919
|
+
const colorIndex = Math.floor(MULBERRY$14.next() * this.#colorRGBs.length);
|
|
2920
|
+
const sizeVariation = .6 + MULBERRY$14.next() * .8;
|
|
2921
|
+
return {
|
|
2922
|
+
x: .05 + MULBERRY$14.next() * .9,
|
|
2923
|
+
y: initialSpread ? MULBERRY$14.next() * 1.3 : 1.15 + MULBERRY$14.next() * .2,
|
|
2924
|
+
vx: 0,
|
|
2925
|
+
vy: .2 + MULBERRY$14.next() * .6,
|
|
2926
|
+
size: this.#size * sizeVariation,
|
|
2927
|
+
glowPhase: MULBERRY$14.next() * Math.PI * 2,
|
|
2928
|
+
glowSpeed: .8 + MULBERRY$14.next() * 1.2,
|
|
2929
|
+
swayPhase: MULBERRY$14.next() * Math.PI * 2,
|
|
2930
|
+
swaySpeed: .4 + MULBERRY$14.next() * .8,
|
|
2931
|
+
swayAmplitude: .3 + MULBERRY$14.next() * .7,
|
|
2932
|
+
colorIndex,
|
|
2933
|
+
opacity: .7 + MULBERRY$14.next() * .3
|
|
2934
|
+
};
|
|
2868
2935
|
}
|
|
2869
2936
|
};
|
|
2870
2937
|
//#endregion
|
|
2938
|
+
//#region src/lanterns/index.ts
|
|
2939
|
+
function createLanterns(config) {
|
|
2940
|
+
return new Lanterns(config);
|
|
2941
|
+
}
|
|
2942
|
+
//#endregion
|
|
2871
2943
|
//#region src/leaves/consts.ts
|
|
2872
2944
|
const MULBERRY$13 = mulberry32(13);
|
|
2873
2945
|
const LEAF_COLORS = [
|
|
@@ -2884,7 +2956,7 @@ const LEAF_COLORS = [
|
|
|
2884
2956
|
];
|
|
2885
2957
|
//#endregion
|
|
2886
2958
|
//#region src/leaves/layer.ts
|
|
2887
|
-
var
|
|
2959
|
+
var Leaves = class extends Effect {
|
|
2888
2960
|
#scale;
|
|
2889
2961
|
#size;
|
|
2890
2962
|
#speed;
|
|
@@ -2910,6 +2982,10 @@ var LeafLayer = class extends SimulationLayer {
|
|
|
2910
2982
|
onResize(_width, height) {
|
|
2911
2983
|
this.#height = height;
|
|
2912
2984
|
}
|
|
2985
|
+
configure(config) {
|
|
2986
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
2987
|
+
if (config.wind !== void 0) this.#wind = config.wind;
|
|
2988
|
+
}
|
|
2913
2989
|
tick(dt, _width, height) {
|
|
2914
2990
|
this.#height = height;
|
|
2915
2991
|
const speedFactor = height / 540 / this.#speed;
|
|
@@ -2944,14 +3020,13 @@ var LeafLayer = class extends SimulationLayer {
|
|
|
2944
3020
|
const py = leaf.y * height;
|
|
2945
3021
|
const displaySize = leaf.size * leaf.depth;
|
|
2946
3022
|
const scaleX = Math.cos(leaf.flipAngle);
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
ctx.
|
|
2950
|
-
ctx.scale(scaleX, 1);
|
|
3023
|
+
const cos = Math.cos(leaf.rotation);
|
|
3024
|
+
const sin = Math.sin(leaf.rotation);
|
|
3025
|
+
ctx.setTransform(cos * scaleX, sin * scaleX, -sin, cos, px, py);
|
|
2951
3026
|
ctx.globalAlpha = .3 + leaf.depth * .7;
|
|
2952
3027
|
ctx.drawImage(this.#sprites[leaf.colorIndex % this.#sprites.length], -displaySize / 2, -displaySize / 2, displaySize, displaySize);
|
|
2953
|
-
ctx.restore();
|
|
2954
3028
|
}
|
|
3029
|
+
ctx.resetTransform();
|
|
2955
3030
|
ctx.globalAlpha = 1;
|
|
2956
3031
|
}
|
|
2957
3032
|
#createSprites() {
|
|
@@ -3080,12 +3155,10 @@ var LeafLayer = class extends SimulationLayer {
|
|
|
3080
3155
|
}
|
|
3081
3156
|
};
|
|
3082
3157
|
//#endregion
|
|
3083
|
-
//#region src/leaves/
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
}
|
|
3088
|
-
};
|
|
3158
|
+
//#region src/leaves/index.ts
|
|
3159
|
+
function createLeaves(config) {
|
|
3160
|
+
return new Leaves(config);
|
|
3161
|
+
}
|
|
3089
3162
|
//#endregion
|
|
3090
3163
|
//#region src/lightning/consts.ts
|
|
3091
3164
|
const MULBERRY$12 = mulberry32(13);
|
|
@@ -3233,7 +3306,7 @@ var LightningSystem = class {
|
|
|
3233
3306
|
};
|
|
3234
3307
|
//#endregion
|
|
3235
3308
|
//#region src/lightning/layer.ts
|
|
3236
|
-
var
|
|
3309
|
+
var Lightning = class extends Effect {
|
|
3237
3310
|
#system;
|
|
3238
3311
|
#enableFlash;
|
|
3239
3312
|
constructor(config = {}) {
|
|
@@ -3264,19 +3337,17 @@ var LightningLayer = class extends SimulationLayer {
|
|
|
3264
3337
|
}
|
|
3265
3338
|
};
|
|
3266
3339
|
//#endregion
|
|
3267
|
-
//#region src/lightning/
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
}
|
|
3272
|
-
};
|
|
3340
|
+
//#region src/lightning/index.ts
|
|
3341
|
+
function createLightning(config) {
|
|
3342
|
+
return new Lightning(config);
|
|
3343
|
+
}
|
|
3273
3344
|
//#endregion
|
|
3274
3345
|
//#region src/matrix/consts.ts
|
|
3275
3346
|
const MULBERRY$11 = mulberry32(13);
|
|
3276
3347
|
const MATRIX_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
3277
3348
|
//#endregion
|
|
3278
3349
|
//#region src/matrix/layer.ts
|
|
3279
|
-
var
|
|
3350
|
+
var Matrix = class extends Effect {
|
|
3280
3351
|
#scale;
|
|
3281
3352
|
#speed;
|
|
3282
3353
|
#fontSize;
|
|
@@ -3315,6 +3386,10 @@ var MatrixLayer = class extends SimulationLayer {
|
|
|
3315
3386
|
}
|
|
3316
3387
|
}
|
|
3317
3388
|
}
|
|
3389
|
+
configure(config) {
|
|
3390
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
3391
|
+
if (config.trailLength !== void 0) this.#trailLength = config.trailLength;
|
|
3392
|
+
}
|
|
3318
3393
|
tick(dt, width, height) {
|
|
3319
3394
|
this.#width = width;
|
|
3320
3395
|
this.#height = height;
|
|
@@ -3366,12 +3441,10 @@ var MatrixLayer = class extends SimulationLayer {
|
|
|
3366
3441
|
}
|
|
3367
3442
|
};
|
|
3368
3443
|
//#endregion
|
|
3369
|
-
//#region src/matrix/
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
}
|
|
3374
|
-
};
|
|
3444
|
+
//#region src/matrix/index.ts
|
|
3445
|
+
function createMatrix(config) {
|
|
3446
|
+
return new Matrix(config);
|
|
3447
|
+
}
|
|
3375
3448
|
//#endregion
|
|
3376
3449
|
//#region src/orbits/consts.ts
|
|
3377
3450
|
const MULBERRY$10 = mulberry32(13);
|
|
@@ -3386,7 +3459,7 @@ const ORBIT_COLORS = [
|
|
|
3386
3459
|
];
|
|
3387
3460
|
//#endregion
|
|
3388
3461
|
//#region src/orbits/layer.ts
|
|
3389
|
-
var
|
|
3462
|
+
var Orbits = class extends Effect {
|
|
3390
3463
|
#centerCount;
|
|
3391
3464
|
#orbitersPerCenter;
|
|
3392
3465
|
#speed;
|
|
@@ -3421,6 +3494,12 @@ var OrbitLayer = class extends SimulationLayer {
|
|
|
3421
3494
|
for (let ci = 0; ci < this.#centers.length; ci++) for (let oi = 0; oi < count; oi++) this.#orbiters.push(this.#createOrbiter(ci));
|
|
3422
3495
|
}
|
|
3423
3496
|
}
|
|
3497
|
+
configure(config) {
|
|
3498
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
3499
|
+
if (config.trailLength !== void 0) this.#trailLength = config.trailLength;
|
|
3500
|
+
if (config.showCenters !== void 0) this.#showCenters = config.showCenters;
|
|
3501
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
3502
|
+
}
|
|
3424
3503
|
tick(dt, width, height) {
|
|
3425
3504
|
this.#time += .01 * dt * this.#speed;
|
|
3426
3505
|
for (const orbiter of this.#orbiters) {
|
|
@@ -3437,11 +3516,20 @@ var OrbitLayer = class extends SimulationLayer {
|
|
|
3437
3516
|
const rotatedY = localX * Math.sin(orbiter.tilt * .3) + localY * Math.cos(orbiter.tilt * .3);
|
|
3438
3517
|
const px = cx + rotatedX;
|
|
3439
3518
|
const py = cy + rotatedY;
|
|
3440
|
-
orbiter.trail
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3519
|
+
const trail = orbiter.trail;
|
|
3520
|
+
const maxLen = this.#trailLength;
|
|
3521
|
+
if (trail.length < maxLen) {
|
|
3522
|
+
trail.push({
|
|
3523
|
+
x: px,
|
|
3524
|
+
y: py
|
|
3525
|
+
});
|
|
3526
|
+
orbiter.trailHead = trail.length - 1;
|
|
3527
|
+
} else {
|
|
3528
|
+
const next = (orbiter.trailHead + 1) % maxLen;
|
|
3529
|
+
trail[next].x = px;
|
|
3530
|
+
trail[next].y = py;
|
|
3531
|
+
orbiter.trailHead = next;
|
|
3532
|
+
}
|
|
3445
3533
|
}
|
|
3446
3534
|
}
|
|
3447
3535
|
draw(ctx, width, height) {
|
|
@@ -3466,21 +3554,28 @@ var OrbitLayer = class extends SimulationLayer {
|
|
|
3466
3554
|
ctx.globalCompositeOperation = "lighter";
|
|
3467
3555
|
for (const orbiter of this.#orbiters) {
|
|
3468
3556
|
const [cr, cg, cb] = hexToRGB(orbiter.color);
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
const
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3557
|
+
const trail = orbiter.trail;
|
|
3558
|
+
const trailLen = trail.length;
|
|
3559
|
+
if (trailLen > 1) {
|
|
3560
|
+
const oldest = trailLen === this.#trailLength ? (orbiter.trailHead + 1) % trailLen : 0;
|
|
3561
|
+
for (let ti = 0; ti < trailLen - 1; ti++) {
|
|
3562
|
+
const progress = (ti + 1) / trailLen;
|
|
3563
|
+
const trailAlpha = progress * .5;
|
|
3564
|
+
const trailWidth = orbiter.size * progress * this.#scale;
|
|
3565
|
+
if (trailAlpha < .01) continue;
|
|
3566
|
+
const idx0 = (oldest + ti) % trailLen;
|
|
3567
|
+
const idx1 = (oldest + ti + 1) % trailLen;
|
|
3568
|
+
ctx.globalAlpha = trailAlpha;
|
|
3569
|
+
ctx.strokeStyle = `rgb(${cr}, ${cg}, ${cb})`;
|
|
3570
|
+
ctx.lineWidth = trailWidth;
|
|
3571
|
+
ctx.beginPath();
|
|
3572
|
+
ctx.moveTo(trail[idx0].x, trail[idx0].y);
|
|
3573
|
+
ctx.lineTo(trail[idx1].x, trail[idx1].y);
|
|
3574
|
+
ctx.stroke();
|
|
3575
|
+
}
|
|
3481
3576
|
}
|
|
3482
|
-
if (
|
|
3483
|
-
const head =
|
|
3577
|
+
if (trailLen > 0) {
|
|
3578
|
+
const head = trail[orbiter.trailHead];
|
|
3484
3579
|
const headSize = orbiter.size * this.#scale;
|
|
3485
3580
|
const glow = ctx.createRadialGradient(head.x, head.y, 0, head.x, head.y, headSize * 3);
|
|
3486
3581
|
glow.addColorStop(0, `rgba(${cr}, ${cg}, ${cb}, 0.9)`);
|
|
@@ -3512,23 +3607,22 @@ var OrbitLayer = class extends SimulationLayer {
|
|
|
3512
3607
|
tilt: MULBERRY$10.next() * Math.PI,
|
|
3513
3608
|
size: 1.5 + MULBERRY$10.next() * 2.5,
|
|
3514
3609
|
color: this.#colors[Math.floor(MULBERRY$10.next() * this.#colors.length)],
|
|
3515
|
-
trail: []
|
|
3610
|
+
trail: [],
|
|
3611
|
+
trailHead: 0
|
|
3516
3612
|
};
|
|
3517
3613
|
}
|
|
3518
3614
|
};
|
|
3519
3615
|
//#endregion
|
|
3520
|
-
//#region src/orbits/
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
}
|
|
3525
|
-
};
|
|
3616
|
+
//#region src/orbits/index.ts
|
|
3617
|
+
function createOrbits(config) {
|
|
3618
|
+
return new Orbits(config);
|
|
3619
|
+
}
|
|
3526
3620
|
//#endregion
|
|
3527
3621
|
//#region src/particles/consts.ts
|
|
3528
3622
|
const MULBERRY$9 = mulberry32(13);
|
|
3529
3623
|
//#endregion
|
|
3530
3624
|
//#region src/particles/layer.ts
|
|
3531
|
-
var
|
|
3625
|
+
var Particles = class extends Effect {
|
|
3532
3626
|
#scale;
|
|
3533
3627
|
#connectionDistance;
|
|
3534
3628
|
#lineWidth;
|
|
@@ -3575,6 +3669,16 @@ var ParticleLayer = class extends SimulationLayer {
|
|
|
3575
3669
|
this.#onMouseMoveBound = this.#onMouseMove.bind(this);
|
|
3576
3670
|
this.#onMouseLeaveBound = this.#onMouseLeave.bind(this);
|
|
3577
3671
|
}
|
|
3672
|
+
configure(config) {
|
|
3673
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
3674
|
+
if (config.connectionDistance !== void 0) this.#connectionDistance = config.connectionDistance * this.#scale;
|
|
3675
|
+
if (config.lineWidth !== void 0) this.#lineWidth = config.lineWidth;
|
|
3676
|
+
if (config.mouseMode !== void 0) this.#mouseMode = config.mouseMode;
|
|
3677
|
+
if (config.mouseRadius !== void 0) this.#mouseRadius = config.mouseRadius * this.#scale;
|
|
3678
|
+
if (config.mouseStrength !== void 0) this.#mouseStrength = config.mouseStrength;
|
|
3679
|
+
if (config.particleForces !== void 0) this.#particleForces = config.particleForces;
|
|
3680
|
+
if (config.glow !== void 0) this.#glow = config.glow;
|
|
3681
|
+
}
|
|
3578
3682
|
onResize(width, height) {
|
|
3579
3683
|
this.#width = width;
|
|
3580
3684
|
this.#height = height;
|
|
@@ -3757,12 +3861,10 @@ var ParticleLayer = class extends SimulationLayer {
|
|
|
3757
3861
|
}
|
|
3758
3862
|
};
|
|
3759
3863
|
//#endregion
|
|
3760
|
-
//#region src/particles/
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
}
|
|
3765
|
-
};
|
|
3864
|
+
//#region src/particles/index.ts
|
|
3865
|
+
function createParticles(config) {
|
|
3866
|
+
return new Particles(config);
|
|
3867
|
+
}
|
|
3766
3868
|
//#endregion
|
|
3767
3869
|
//#region src/petals/consts.ts
|
|
3768
3870
|
const MULBERRY$8 = mulberry32(13);
|
|
@@ -3777,7 +3879,7 @@ const PETAL_COLORS = [
|
|
|
3777
3879
|
];
|
|
3778
3880
|
//#endregion
|
|
3779
3881
|
//#region src/petals/layer.ts
|
|
3780
|
-
var
|
|
3882
|
+
var Petals = class extends Effect {
|
|
3781
3883
|
#scale;
|
|
3782
3884
|
#size;
|
|
3783
3885
|
#speed;
|
|
@@ -3799,6 +3901,10 @@ var PetalLayer = class extends SimulationLayer {
|
|
|
3799
3901
|
this.#sprites = this.#createSprites();
|
|
3800
3902
|
for (let i = 0; i < this.#maxCount; ++i) this.#petals.push(this.#createPetal(true));
|
|
3801
3903
|
}
|
|
3904
|
+
configure(config) {
|
|
3905
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
3906
|
+
if (config.wind !== void 0) this.#wind = config.wind;
|
|
3907
|
+
}
|
|
3802
3908
|
tick(dt, _width, height) {
|
|
3803
3909
|
const speedFactor = height / 540 / this.#speed;
|
|
3804
3910
|
this.#time += .012 * dt;
|
|
@@ -3829,14 +3935,13 @@ var PetalLayer = class extends SimulationLayer {
|
|
|
3829
3935
|
const py = petal.y * height;
|
|
3830
3936
|
const displaySize = petal.size * petal.depth;
|
|
3831
3937
|
const scaleX = Math.cos(petal.flipAngle);
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
ctx.
|
|
3835
|
-
ctx.scale(scaleX, 1);
|
|
3938
|
+
const cos = Math.cos(petal.rotation);
|
|
3939
|
+
const sin = Math.sin(petal.rotation);
|
|
3940
|
+
ctx.setTransform(cos * scaleX, sin * scaleX, -sin, cos, px, py);
|
|
3836
3941
|
ctx.globalAlpha = .4 + petal.depth * .6;
|
|
3837
3942
|
ctx.drawImage(this.#sprites[petal.colorIndex % this.#sprites.length], -displaySize / 2, -displaySize / 2, displaySize, displaySize);
|
|
3838
|
-
ctx.restore();
|
|
3839
3943
|
}
|
|
3944
|
+
ctx.resetTransform();
|
|
3840
3945
|
ctx.globalAlpha = 1;
|
|
3841
3946
|
}
|
|
3842
3947
|
#createSprites() {
|
|
@@ -3888,12 +3993,10 @@ var PetalLayer = class extends SimulationLayer {
|
|
|
3888
3993
|
}
|
|
3889
3994
|
};
|
|
3890
3995
|
//#endregion
|
|
3891
|
-
//#region src/petals/
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
}
|
|
3896
|
-
};
|
|
3996
|
+
//#region src/petals/index.ts
|
|
3997
|
+
function createPetals(config) {
|
|
3998
|
+
return new Petals(config);
|
|
3999
|
+
}
|
|
3897
4000
|
//#endregion
|
|
3898
4001
|
//#region src/plasma/layer.ts
|
|
3899
4002
|
const DEFAULT_PALETTE = [
|
|
@@ -3923,7 +4026,7 @@ const DEFAULT_PALETTE = [
|
|
|
3923
4026
|
b: 100
|
|
3924
4027
|
}
|
|
3925
4028
|
];
|
|
3926
|
-
var
|
|
4029
|
+
var Plasma = class extends Effect {
|
|
3927
4030
|
#speed;
|
|
3928
4031
|
#scale;
|
|
3929
4032
|
#resolution;
|
|
@@ -3939,6 +4042,10 @@ var PlasmaLayer = class extends SimulationLayer {
|
|
|
3939
4042
|
this.#resolution = config.resolution ?? 4;
|
|
3940
4043
|
this.#palette = config.palette ?? DEFAULT_PALETTE;
|
|
3941
4044
|
}
|
|
4045
|
+
configure(config) {
|
|
4046
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
4047
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
4048
|
+
}
|
|
3942
4049
|
tick(dt, _width, _height) {
|
|
3943
4050
|
this.#time += .02 * dt * this.#speed;
|
|
3944
4051
|
}
|
|
@@ -3983,12 +4090,10 @@ var PlasmaLayer = class extends SimulationLayer {
|
|
|
3983
4090
|
}
|
|
3984
4091
|
};
|
|
3985
4092
|
//#endregion
|
|
3986
|
-
//#region src/plasma/
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
}
|
|
3991
|
-
};
|
|
4093
|
+
//#region src/plasma/index.ts
|
|
4094
|
+
function createPlasma(config) {
|
|
4095
|
+
return new Plasma(config);
|
|
4096
|
+
}
|
|
3992
4097
|
//#endregion
|
|
3993
4098
|
//#region src/rain/consts.ts
|
|
3994
4099
|
const MULBERRY$7 = mulberry32(13);
|
|
@@ -4014,7 +4119,7 @@ const VARIANT_PRESETS = {
|
|
|
4014
4119
|
splashes: true
|
|
4015
4120
|
}
|
|
4016
4121
|
};
|
|
4017
|
-
var
|
|
4122
|
+
var Rain = class extends Effect {
|
|
4018
4123
|
#scale;
|
|
4019
4124
|
#speed;
|
|
4020
4125
|
#wind;
|
|
@@ -4042,6 +4147,11 @@ var RainLayer = class extends SimulationLayer {
|
|
|
4042
4147
|
if (innerWidth < 991) this.#maxDrops = Math.floor(this.#maxDrops / 2);
|
|
4043
4148
|
for (let i = 0; i < this.#maxDrops; ++i) this.#drops.push(this.#createDrop(true));
|
|
4044
4149
|
}
|
|
4150
|
+
configure(config) {
|
|
4151
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
4152
|
+
if (config.wind !== void 0) this.#wind = config.wind;
|
|
4153
|
+
if (config.splashes !== void 0) this.#enableSplashes = config.splashes;
|
|
4154
|
+
}
|
|
4045
4155
|
tick(dt, width, height) {
|
|
4046
4156
|
let aliveDrops = 0;
|
|
4047
4157
|
for (let i = 0; i < this.#drops.length; i++) {
|
|
@@ -4228,18 +4338,16 @@ var SplashParticle = class SplashParticle {
|
|
|
4228
4338
|
}
|
|
4229
4339
|
};
|
|
4230
4340
|
//#endregion
|
|
4231
|
-
//#region src/rain/
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
}
|
|
4236
|
-
};
|
|
4341
|
+
//#region src/rain/index.ts
|
|
4342
|
+
function createRain(config) {
|
|
4343
|
+
return new Rain(config);
|
|
4344
|
+
}
|
|
4237
4345
|
//#endregion
|
|
4238
4346
|
//#region src/sandstorm/consts.ts
|
|
4239
4347
|
const MULBERRY$6 = mulberry32(13);
|
|
4240
4348
|
//#endregion
|
|
4241
4349
|
//#region src/sandstorm/layer.ts
|
|
4242
|
-
var
|
|
4350
|
+
var Sandstorm = class extends Effect {
|
|
4243
4351
|
#scale;
|
|
4244
4352
|
#wind;
|
|
4245
4353
|
#turbulence;
|
|
@@ -4264,6 +4372,10 @@ var SandstormLayer = class extends SimulationLayer {
|
|
|
4264
4372
|
if (innerWidth < 991) this.#maxCount = Math.floor(this.#maxCount / 2);
|
|
4265
4373
|
for (let i = 0; i < this.#maxCount; ++i) this.#grains.push(this.#createGrain(true));
|
|
4266
4374
|
}
|
|
4375
|
+
configure(config) {
|
|
4376
|
+
if (config.wind !== void 0) this.#wind = config.wind;
|
|
4377
|
+
if (config.turbulence !== void 0) this.#turbulence = config.turbulence;
|
|
4378
|
+
}
|
|
4267
4379
|
tick(dt, width, height) {
|
|
4268
4380
|
this.#time += .02 * dt;
|
|
4269
4381
|
const gustX = Math.sin(this.#time * .3) * .5 + Math.sin(this.#time * .8 + 1) * .3 + Math.sin(this.#time * 2.1) * .2;
|
|
@@ -4338,12 +4450,162 @@ var SandstormLayer = class extends SimulationLayer {
|
|
|
4338
4450
|
}
|
|
4339
4451
|
};
|
|
4340
4452
|
//#endregion
|
|
4341
|
-
//#region src/sandstorm/
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4453
|
+
//#region src/sandstorm/index.ts
|
|
4454
|
+
function createSandstorm(config) {
|
|
4455
|
+
return new Sandstorm(config);
|
|
4456
|
+
}
|
|
4457
|
+
//#endregion
|
|
4458
|
+
//#region src/scene.ts
|
|
4459
|
+
/**
|
|
4460
|
+
* Internal canvas runner that drives all layers in a Scene.
|
|
4461
|
+
*/
|
|
4462
|
+
var SceneCanvas = class extends LimitedFrameRateCanvas {
|
|
4463
|
+
#layers;
|
|
4464
|
+
#contextOptions;
|
|
4465
|
+
#offscreen = null;
|
|
4466
|
+
#offscreenCtx = null;
|
|
4467
|
+
constructor(canvas, layers, frameRate, options) {
|
|
4468
|
+
super(canvas, frameRate, options);
|
|
4469
|
+
this.#layers = layers;
|
|
4470
|
+
this.#contextOptions = options;
|
|
4471
|
+
canvas.style.position = "absolute";
|
|
4472
|
+
canvas.style.top = "0";
|
|
4473
|
+
canvas.style.left = "0";
|
|
4474
|
+
canvas.style.height = "100%";
|
|
4475
|
+
canvas.style.width = "100%";
|
|
4476
|
+
}
|
|
4477
|
+
start() {
|
|
4478
|
+
for (const layer of this.#layers) layer.onMount(this.canvas);
|
|
4479
|
+
super.start();
|
|
4480
|
+
}
|
|
4481
|
+
destroy() {
|
|
4482
|
+
for (const layer of this.#layers) layer.onUnmount(this.canvas);
|
|
4483
|
+
super.destroy();
|
|
4484
|
+
}
|
|
4485
|
+
draw() {
|
|
4486
|
+
this.canvas.height = this.height;
|
|
4487
|
+
this.canvas.width = this.width;
|
|
4488
|
+
const ctx = this.context;
|
|
4489
|
+
ctx.clearRect(0, 0, this.width, this.height);
|
|
4490
|
+
for (const layer of this.#layers) if (layer.fade) {
|
|
4491
|
+
const offCtx = this.#getOffscreenCtx(this.width, this.height);
|
|
4492
|
+
offCtx.clearRect(0, 0, this.width, this.height);
|
|
4493
|
+
layer.draw(offCtx, this.width, this.height);
|
|
4494
|
+
applyEdgeFade(offCtx, this.width, this.height, layer.fade);
|
|
4495
|
+
ctx.drawImage(this.#offscreen, 0, 0);
|
|
4496
|
+
} else {
|
|
4497
|
+
ctx.save();
|
|
4498
|
+
layer.draw(ctx, this.width, this.height);
|
|
4499
|
+
ctx.restore();
|
|
4500
|
+
}
|
|
4501
|
+
}
|
|
4502
|
+
tick() {
|
|
4503
|
+
const dt = (this.delta > 0 && this.delta < 200 ? this.delta / (1e3 / 60) : 1) * this.speed * LimitedFrameRateCanvas.globalSpeed;
|
|
4504
|
+
for (const layer of this.#layers) layer.tick(dt, this.width, this.height);
|
|
4505
|
+
}
|
|
4506
|
+
onResize() {
|
|
4507
|
+
super.onResize();
|
|
4508
|
+
if (this.#offscreen) {
|
|
4509
|
+
this.#offscreen.width = this.width;
|
|
4510
|
+
this.#offscreen.height = this.height;
|
|
4511
|
+
}
|
|
4512
|
+
for (const layer of this.#layers) layer.onResize(this.width, this.height);
|
|
4513
|
+
}
|
|
4514
|
+
#getOffscreenCtx(width, height) {
|
|
4515
|
+
if (!this.#offscreen) {
|
|
4516
|
+
this.#offscreen = document.createElement("canvas");
|
|
4517
|
+
this.#offscreen.width = width;
|
|
4518
|
+
this.#offscreen.height = height;
|
|
4519
|
+
this.#offscreenCtx = this.#offscreen.getContext("2d", this.#contextOptions);
|
|
4520
|
+
}
|
|
4521
|
+
return this.#offscreenCtx;
|
|
4522
|
+
}
|
|
4523
|
+
};
|
|
4524
|
+
/**
|
|
4525
|
+
* Composable canvas that renders multiple Effect layers in order (first = bottom, last = top).
|
|
4526
|
+
*
|
|
4527
|
+
* @example
|
|
4528
|
+
* const scene = new Scene()
|
|
4529
|
+
* .mount(canvas)
|
|
4530
|
+
* .layer(new Aurora({ bands: 5 }))
|
|
4531
|
+
* .layer(new Stars().withFade({ bottom: 0.4 }))
|
|
4532
|
+
* .start();
|
|
4533
|
+
*/
|
|
4534
|
+
var Scene = class {
|
|
4535
|
+
#layers = [];
|
|
4536
|
+
#frameRate;
|
|
4537
|
+
#defaultOptions;
|
|
4538
|
+
#runner = null;
|
|
4539
|
+
constructor(frameRate = 60, options = { colorSpace: "display-p3" }) {
|
|
4540
|
+
this.#frameRate = frameRate;
|
|
4541
|
+
this.#defaultOptions = options;
|
|
4542
|
+
}
|
|
4543
|
+
/**
|
|
4544
|
+
* Mount the scene to a canvas element or CSS selector.
|
|
4545
|
+
*/
|
|
4546
|
+
mount(canvas, options) {
|
|
4547
|
+
if (typeof canvas === "string") {
|
|
4548
|
+
const el = document.querySelector(canvas);
|
|
4549
|
+
if (!el) throw new Error(`Scene.mount(): no element found for selector "${canvas}".`);
|
|
4550
|
+
canvas = el;
|
|
4551
|
+
}
|
|
4552
|
+
this.#runner?.destroy();
|
|
4553
|
+
this.#runner = new SceneCanvas(canvas, this.#layers, this.#frameRate, options ?? this.#defaultOptions);
|
|
4554
|
+
return this;
|
|
4555
|
+
}
|
|
4556
|
+
/**
|
|
4557
|
+
* Add an effect layer. Layers are rendered in the order they are added.
|
|
4558
|
+
* If the scene is already running, the layer is mounted immediately.
|
|
4559
|
+
*/
|
|
4560
|
+
layer(effect) {
|
|
4561
|
+
this.#layers.push(effect);
|
|
4562
|
+
if (this.#runner?.isTicking) effect.onMount(this.#runner.canvas);
|
|
4563
|
+
return this;
|
|
4564
|
+
}
|
|
4565
|
+
/**
|
|
4566
|
+
* Start the render loop.
|
|
4567
|
+
*/
|
|
4568
|
+
start() {
|
|
4569
|
+
this.#runner?.start();
|
|
4570
|
+
return this;
|
|
4571
|
+
}
|
|
4572
|
+
/**
|
|
4573
|
+
* Pause rendering without destroying state. Use resume() to continue.
|
|
4574
|
+
*/
|
|
4575
|
+
pause() {
|
|
4576
|
+
this.#runner?.pause();
|
|
4577
|
+
return this;
|
|
4578
|
+
}
|
|
4579
|
+
/**
|
|
4580
|
+
* Resume rendering after pause().
|
|
4581
|
+
*/
|
|
4582
|
+
resume() {
|
|
4583
|
+
this.#runner?.resume();
|
|
4584
|
+
return this;
|
|
4585
|
+
}
|
|
4586
|
+
/**
|
|
4587
|
+
* Stop and destroy all layers.
|
|
4588
|
+
*/
|
|
4589
|
+
destroy() {
|
|
4590
|
+
this.#runner?.destroy();
|
|
4591
|
+
this.#runner = null;
|
|
4592
|
+
}
|
|
4593
|
+
get speed() {
|
|
4594
|
+
return this.#runner?.speed ?? 1;
|
|
4595
|
+
}
|
|
4596
|
+
set speed(value) {
|
|
4597
|
+
if (this.#runner) this.#runner.speed = value;
|
|
4598
|
+
}
|
|
4599
|
+
get isTicking() {
|
|
4600
|
+
return this.#runner?.isTicking ?? false;
|
|
4345
4601
|
}
|
|
4346
4602
|
};
|
|
4603
|
+
/**
|
|
4604
|
+
* Factory alternative to `new Scene()`. Call .mount() and .layer() on the returned instance.
|
|
4605
|
+
*/
|
|
4606
|
+
function createScene(frameRate, options) {
|
|
4607
|
+
return new Scene(frameRate, options);
|
|
4608
|
+
}
|
|
4347
4609
|
//#endregion
|
|
4348
4610
|
//#region src/shooting-stars/system.ts
|
|
4349
4611
|
var ShootingStarSystem = class {
|
|
@@ -4357,10 +4619,8 @@ var ShootingStarSystem = class {
|
|
|
4357
4619
|
#alphaRange;
|
|
4358
4620
|
#decayMin;
|
|
4359
4621
|
#decayRange;
|
|
4360
|
-
#verticalFade;
|
|
4361
4622
|
#rng;
|
|
4362
4623
|
#cooldown;
|
|
4363
|
-
#height = 0;
|
|
4364
4624
|
#stars = [];
|
|
4365
4625
|
constructor(config, rng) {
|
|
4366
4626
|
this.#interval = config.interval;
|
|
@@ -4377,12 +4637,10 @@ var ShootingStarSystem = class {
|
|
|
4377
4637
|
this.#alphaRange = config.alphaRange ?? .3;
|
|
4378
4638
|
this.#decayMin = config.decayMin ?? .008;
|
|
4379
4639
|
this.#decayRange = config.decayRange ?? .01;
|
|
4380
|
-
this.#verticalFade = config.verticalFade ?? null;
|
|
4381
4640
|
this.#rng = rng;
|
|
4382
4641
|
this.#cooldown = this.#interval[0] + this.#rng() * (this.#interval[1] - this.#interval[0]);
|
|
4383
4642
|
}
|
|
4384
4643
|
tick(dt, width, height) {
|
|
4385
|
-
this.#height = height;
|
|
4386
4644
|
this.#cooldown -= dt;
|
|
4387
4645
|
if (this.#cooldown <= 0) {
|
|
4388
4646
|
this.#stars.push(this.#create(width, height));
|
|
@@ -4391,17 +4649,24 @@ var ShootingStarSystem = class {
|
|
|
4391
4649
|
let alive = 0;
|
|
4392
4650
|
for (let i = 0; i < this.#stars.length; i++) {
|
|
4393
4651
|
const star = this.#stars[i];
|
|
4394
|
-
star.trail
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4652
|
+
const trail = star.trail;
|
|
4653
|
+
const maxLen = this.#trailLength;
|
|
4654
|
+
if (trail.length < maxLen) {
|
|
4655
|
+
trail.push({
|
|
4656
|
+
x: star.x,
|
|
4657
|
+
y: star.y
|
|
4658
|
+
});
|
|
4659
|
+
star.trailHead = trail.length - 1;
|
|
4660
|
+
} else {
|
|
4661
|
+
const next = (star.trailHead + 1) % maxLen;
|
|
4662
|
+
trail[next].x = star.x;
|
|
4663
|
+
trail[next].y = star.y;
|
|
4664
|
+
star.trailHead = next;
|
|
4665
|
+
}
|
|
4399
4666
|
star.x += star.vx * this.#speed * dt;
|
|
4400
4667
|
star.y += star.vy * this.#speed * dt;
|
|
4401
4668
|
star.alpha -= star.decay * dt;
|
|
4402
|
-
|
|
4403
|
-
const fullyFaded = this.#verticalFade !== null && star.y / height >= this.#verticalFade[1];
|
|
4404
|
-
if (inBounds && !fullyFaded) this.#stars[alive++] = star;
|
|
4669
|
+
if (star.alpha > 0 && star.x > -50 && star.x < width + 50 && star.y < height + 50) this.#stars[alive++] = star;
|
|
4405
4670
|
}
|
|
4406
4671
|
this.#stars.length = alive;
|
|
4407
4672
|
}
|
|
@@ -4409,23 +4674,22 @@ var ShootingStarSystem = class {
|
|
|
4409
4674
|
const [cr, cg, cb] = this.#color;
|
|
4410
4675
|
ctx.globalCompositeOperation = "lighter";
|
|
4411
4676
|
for (const star of this.#stars) {
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
const progress = t / star.trail.length;
|
|
4419
|
-
const trailAlpha = star.alpha * progress * this.#trailAlphaFactor * fadeFactor;
|
|
4677
|
+
const trail = star.trail;
|
|
4678
|
+
const trailLen = trail.length;
|
|
4679
|
+
const oldest = trailLen === this.#trailLength ? (star.trailHead + 1) % trailLen : 0;
|
|
4680
|
+
for (let t = 0; t < trailLen; t++) {
|
|
4681
|
+
const progress = t / trailLen;
|
|
4682
|
+
const trailAlpha = star.alpha * progress * this.#trailAlphaFactor;
|
|
4420
4683
|
const trailSize = star.size * progress * this.#scale;
|
|
4421
4684
|
if (trailAlpha < .01) continue;
|
|
4685
|
+
const idx = (oldest + t) % trailLen;
|
|
4422
4686
|
ctx.globalAlpha = trailAlpha;
|
|
4423
4687
|
ctx.beginPath();
|
|
4424
|
-
ctx.arc(
|
|
4688
|
+
ctx.arc(trail[idx].x, trail[idx].y, trailSize, 0, Math.PI * 2);
|
|
4425
4689
|
ctx.fillStyle = `rgb(${cr}, ${cg}, ${cb})`;
|
|
4426
4690
|
ctx.fill();
|
|
4427
4691
|
}
|
|
4428
|
-
const alpha = star.alpha
|
|
4692
|
+
const alpha = star.alpha;
|
|
4429
4693
|
const headSize = star.size * 2 * this.#scale;
|
|
4430
4694
|
const glow = ctx.createRadialGradient(star.x, star.y, 0, star.x, star.y, headSize);
|
|
4431
4695
|
glow.addColorStop(0, `rgba(${cr}, ${cg}, ${cb}, ${alpha})`);
|
|
@@ -4453,7 +4717,8 @@ var ShootingStarSystem = class {
|
|
|
4453
4717
|
alpha: this.#alphaMin + this.#rng() * this.#alphaRange,
|
|
4454
4718
|
size: 1.5 + this.#rng() * 2,
|
|
4455
4719
|
decay: this.#decayMin + this.#rng() * this.#decayRange,
|
|
4456
|
-
trail: []
|
|
4720
|
+
trail: [],
|
|
4721
|
+
trailHead: 0
|
|
4457
4722
|
};
|
|
4458
4723
|
}
|
|
4459
4724
|
};
|
|
@@ -4465,7 +4730,7 @@ const MULBERRY$5 = mulberry32(13);
|
|
|
4465
4730
|
const SPRITE_SIZE = 64;
|
|
4466
4731
|
const SPRITE_CENTER = SPRITE_SIZE / 2;
|
|
4467
4732
|
const SPRITE_RADIUS = SPRITE_SIZE / 2;
|
|
4468
|
-
var
|
|
4733
|
+
var Snow = class extends Effect {
|
|
4469
4734
|
#scale;
|
|
4470
4735
|
#size;
|
|
4471
4736
|
#speed;
|
|
@@ -4488,6 +4753,9 @@ var SnowLayer = class extends SimulationLayer {
|
|
|
4488
4753
|
this.#sprites = this.#createSprites(r, g, b);
|
|
4489
4754
|
for (let i = 0; i < this.#maxParticles; ++i) this.#snowflakes.push(this.#createSnowflake(true));
|
|
4490
4755
|
}
|
|
4756
|
+
configure(config) {
|
|
4757
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
4758
|
+
}
|
|
4491
4759
|
onResize(_width, height) {
|
|
4492
4760
|
this.#height = height;
|
|
4493
4761
|
}
|
|
@@ -4530,11 +4798,11 @@ var SnowLayer = class extends SimulationLayer {
|
|
|
4530
4798
|
if (displaySize < .5) continue;
|
|
4531
4799
|
ctx.globalAlpha = this.#baseOpacity * (.15 + snowflake.depth * .85);
|
|
4532
4800
|
if (snowflake.spriteIndex === 3) {
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
ctx.
|
|
4801
|
+
const cos = Math.cos(snowflake.rotation);
|
|
4802
|
+
const sin = Math.sin(snowflake.rotation);
|
|
4803
|
+
ctx.setTransform(cos, sin, -sin, cos, px, py);
|
|
4536
4804
|
ctx.drawImage(this.#sprites[snowflake.spriteIndex], -displayRadius, -displayRadius, displaySize, displaySize);
|
|
4537
|
-
ctx.
|
|
4805
|
+
ctx.resetTransform();
|
|
4538
4806
|
} else ctx.drawImage(this.#sprites[snowflake.spriteIndex], px - displayRadius, py - displayRadius, displaySize, displaySize);
|
|
4539
4807
|
}
|
|
4540
4808
|
ctx.globalAlpha = 1;
|
|
@@ -4647,12 +4915,10 @@ var SnowLayer = class extends SimulationLayer {
|
|
|
4647
4915
|
}
|
|
4648
4916
|
};
|
|
4649
4917
|
//#endregion
|
|
4650
|
-
//#region src/snow/
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
}
|
|
4655
|
-
};
|
|
4918
|
+
//#region src/snow/index.ts
|
|
4919
|
+
function createSnow(config) {
|
|
4920
|
+
return new Snow(config);
|
|
4921
|
+
}
|
|
4656
4922
|
//#endregion
|
|
4657
4923
|
//#region src/sparklers/consts.ts
|
|
4658
4924
|
const MULBERRY$4 = mulberry32(13);
|
|
@@ -4664,7 +4930,7 @@ const DEFAULT_COLORS$1 = [
|
|
|
4664
4930
|
"#ffffff",
|
|
4665
4931
|
"#ffee88"
|
|
4666
4932
|
];
|
|
4667
|
-
var
|
|
4933
|
+
var Sparklers = class extends Effect {
|
|
4668
4934
|
#scale;
|
|
4669
4935
|
#emitRate;
|
|
4670
4936
|
#maxSparks;
|
|
@@ -4681,6 +4947,8 @@ var SparklerLayer = class extends SimulationLayer {
|
|
|
4681
4947
|
#emitY = .5;
|
|
4682
4948
|
#mouseOnCanvas = false;
|
|
4683
4949
|
#sparks = [];
|
|
4950
|
+
#mountedCanvas = null;
|
|
4951
|
+
#cachedRect = null;
|
|
4684
4952
|
constructor(config = {}) {
|
|
4685
4953
|
super();
|
|
4686
4954
|
this.#scale = config.scale ?? 1;
|
|
@@ -4696,11 +4964,13 @@ var SparklerLayer = class extends SimulationLayer {
|
|
|
4696
4964
|
this.#onMouseMoveBound = this.#onMouseMove.bind(this);
|
|
4697
4965
|
this.#onMouseLeaveBound = this.#onMouseLeave.bind(this);
|
|
4698
4966
|
}
|
|
4699
|
-
|
|
4967
|
+
moveTo(x, y) {
|
|
4700
4968
|
this.#emitX = x;
|
|
4701
4969
|
this.#emitY = y;
|
|
4702
4970
|
}
|
|
4703
4971
|
onMount(canvas) {
|
|
4972
|
+
this.#mountedCanvas = canvas;
|
|
4973
|
+
this.#cachedRect = canvas.getBoundingClientRect();
|
|
4704
4974
|
if (this.#hoverMode) {
|
|
4705
4975
|
canvas.addEventListener("mousemove", this.#onMouseMoveBound, { passive: true });
|
|
4706
4976
|
canvas.addEventListener("mouseleave", this.#onMouseLeaveBound, { passive: true });
|
|
@@ -4709,12 +4979,26 @@ var SparklerLayer = class extends SimulationLayer {
|
|
|
4709
4979
|
onUnmount(canvas) {
|
|
4710
4980
|
canvas.removeEventListener("mousemove", this.#onMouseMoveBound);
|
|
4711
4981
|
canvas.removeEventListener("mouseleave", this.#onMouseLeaveBound);
|
|
4982
|
+
this.#mountedCanvas = null;
|
|
4983
|
+
this.#cachedRect = null;
|
|
4984
|
+
}
|
|
4985
|
+
onResize() {
|
|
4986
|
+
if (this.#mountedCanvas) this.#cachedRect = this.#mountedCanvas.getBoundingClientRect();
|
|
4987
|
+
}
|
|
4988
|
+
configure(config) {
|
|
4989
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
4990
|
+
if (config.emitRate !== void 0) this.#emitRate = config.emitRate;
|
|
4991
|
+
if (config.friction !== void 0) this.#friction = config.friction;
|
|
4992
|
+
if (config.gravity !== void 0) this.#gravity = config.gravity;
|
|
4993
|
+
if (config.trailLength !== void 0) this.#trailLength = config.trailLength;
|
|
4994
|
+
if (config.hoverMode !== void 0) this.#hoverMode = config.hoverMode;
|
|
4712
4995
|
}
|
|
4713
4996
|
tick(dt, width, height) {
|
|
4714
4997
|
if (!this.#hoverMode || this.#mouseOnCanvas) {
|
|
4715
4998
|
const emitCount = Math.min(this.#emitRate, this.#maxSparks - this.#sparks.length);
|
|
4716
4999
|
for (let i = 0; i < emitCount; i++) this.#sparks.push(this.#createSpark(width, height));
|
|
4717
5000
|
}
|
|
5001
|
+
const frictionFactor = Math.pow(this.#friction, dt);
|
|
4718
5002
|
let alive = 0;
|
|
4719
5003
|
for (let i = 0; i < this.#sparks.length; i++) {
|
|
4720
5004
|
const spark = this.#sparks[i];
|
|
@@ -4723,8 +5007,8 @@ var SparklerLayer = class extends SimulationLayer {
|
|
|
4723
5007
|
y: spark.y
|
|
4724
5008
|
});
|
|
4725
5009
|
if (spark.trail.length > this.#trailLength) spark.trail.shift();
|
|
4726
|
-
spark.vx *=
|
|
4727
|
-
spark.vy *=
|
|
5010
|
+
spark.vx *= frictionFactor;
|
|
5011
|
+
spark.vy *= frictionFactor;
|
|
4728
5012
|
spark.vy += this.#gravity * this.#scale * dt;
|
|
4729
5013
|
spark.x += spark.vx * dt;
|
|
4730
5014
|
spark.y += spark.vy * dt;
|
|
@@ -4767,7 +5051,7 @@ var SparklerLayer = class extends SimulationLayer {
|
|
|
4767
5051
|
ctx.globalCompositeOperation = "source-over";
|
|
4768
5052
|
}
|
|
4769
5053
|
#onMouseMove(evt) {
|
|
4770
|
-
const rect = evt.currentTarget.getBoundingClientRect();
|
|
5054
|
+
const rect = this.#cachedRect ?? evt.currentTarget.getBoundingClientRect();
|
|
4771
5055
|
this.#emitX = (evt.clientX - rect.left) / rect.width;
|
|
4772
5056
|
this.#emitY = (evt.clientY - rect.top) / rect.height;
|
|
4773
5057
|
this.#mouseOnCanvas = true;
|
|
@@ -4861,29 +5145,20 @@ var SparklerParticle = class {
|
|
|
4861
5145
|
}
|
|
4862
5146
|
};
|
|
4863
5147
|
//#endregion
|
|
4864
|
-
//#region src/sparklers/
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
const layer = new SparklerLayer(config);
|
|
4869
|
-
super(canvas, layer, 60, config.canvasOptions ?? { colorSpace: "display-p3" });
|
|
4870
|
-
this.#layer = layer;
|
|
4871
|
-
}
|
|
4872
|
-
setPosition(x, y) {
|
|
4873
|
-
this.#layer.setPosition(x, y);
|
|
4874
|
-
}
|
|
4875
|
-
};
|
|
5148
|
+
//#region src/sparklers/index.ts
|
|
5149
|
+
function createSparklers(config) {
|
|
5150
|
+
return new Sparklers(config);
|
|
5151
|
+
}
|
|
4876
5152
|
//#endregion
|
|
4877
5153
|
//#region src/stars/consts.ts
|
|
4878
5154
|
const MULBERRY$3 = mulberry32(13);
|
|
4879
5155
|
//#endregion
|
|
4880
5156
|
//#region src/stars/layer.ts
|
|
4881
|
-
var
|
|
5157
|
+
var Stars = class extends Effect {
|
|
4882
5158
|
#mode;
|
|
4883
5159
|
#twinkleSpeed;
|
|
4884
5160
|
#colorRGB;
|
|
4885
5161
|
#scale;
|
|
4886
|
-
#verticalFade;
|
|
4887
5162
|
#shootingStarSystem;
|
|
4888
5163
|
#starCount;
|
|
4889
5164
|
#time = 0;
|
|
@@ -4894,7 +5169,6 @@ var StarLayer = class extends SimulationLayer {
|
|
|
4894
5169
|
this.#starCount = config.starCount ?? 150;
|
|
4895
5170
|
this.#twinkleSpeed = config.twinkleSpeed ?? 1;
|
|
4896
5171
|
this.#scale = config.scale ?? 1;
|
|
4897
|
-
this.#verticalFade = config.verticalFade ?? null;
|
|
4898
5172
|
this.#colorRGB = hexToRGB(config.color ?? "#ffffff");
|
|
4899
5173
|
const shootingColorRGB = hexToRGB(config.shootingColor ?? "#ffffff");
|
|
4900
5174
|
this.#shootingStarSystem = this.#mode === "shooting" || this.#mode === "both" ? new ShootingStarSystem({
|
|
@@ -4907,11 +5181,14 @@ var StarLayer = class extends SimulationLayer {
|
|
|
4907
5181
|
alphaMin: .8,
|
|
4908
5182
|
alphaRange: .2,
|
|
4909
5183
|
decayMin: .01,
|
|
4910
|
-
decayRange: .015
|
|
4911
|
-
verticalFade: this.#verticalFade ?? void 0
|
|
5184
|
+
decayRange: .015
|
|
4912
5185
|
}, () => MULBERRY$3.next()) : null;
|
|
4913
5186
|
if (this.#mode === "sky" || this.#mode === "both") for (let i = 0; i < this.#starCount; ++i) this.#stars.push(this.#createStar());
|
|
4914
5187
|
}
|
|
5188
|
+
configure(config) {
|
|
5189
|
+
if (config.twinkleSpeed !== void 0) this.#twinkleSpeed = config.twinkleSpeed;
|
|
5190
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
5191
|
+
}
|
|
4915
5192
|
tick(dt, width, height) {
|
|
4916
5193
|
this.#time += .02 * dt;
|
|
4917
5194
|
this.#shootingStarSystem?.tick(dt, width, height);
|
|
@@ -4923,13 +5200,7 @@ var StarLayer = class extends SimulationLayer {
|
|
|
4923
5200
|
for (const star of this.#stars) {
|
|
4924
5201
|
const px = star.x * width;
|
|
4925
5202
|
const py = star.y * height;
|
|
4926
|
-
|
|
4927
|
-
if (this.#verticalFade) {
|
|
4928
|
-
const [fadeStart, fadeEnd] = this.#verticalFade;
|
|
4929
|
-
const fadeFactor = 1 - Math.max(0, Math.min(1, (star.y - fadeStart) / (fadeEnd - fadeStart)));
|
|
4930
|
-
alpha *= fadeFactor;
|
|
4931
|
-
if (alpha <= 0) continue;
|
|
4932
|
-
}
|
|
5203
|
+
const alpha = star.brightness * (.3 + .7 * (.5 + .5 * Math.sin(this.#time * star.twinkleSpeed * this.#twinkleSpeed + star.twinklePhase)));
|
|
4933
5204
|
const size = star.size * this.#scale;
|
|
4934
5205
|
ctx.globalAlpha = alpha;
|
|
4935
5206
|
ctx.beginPath();
|
|
@@ -4967,12 +5238,10 @@ var StarLayer = class extends SimulationLayer {
|
|
|
4967
5238
|
}
|
|
4968
5239
|
};
|
|
4969
5240
|
//#endregion
|
|
4970
|
-
//#region src/stars/
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
}
|
|
4975
|
-
};
|
|
5241
|
+
//#region src/stars/index.ts
|
|
5242
|
+
function createStars(config) {
|
|
5243
|
+
return new Stars(config);
|
|
5244
|
+
}
|
|
4976
5245
|
//#endregion
|
|
4977
5246
|
//#region src/streamers/consts.ts
|
|
4978
5247
|
const MULBERRY$2 = mulberry32(13);
|
|
@@ -4988,7 +5257,7 @@ const STREAMER_COLORS = [
|
|
|
4988
5257
|
];
|
|
4989
5258
|
//#endregion
|
|
4990
5259
|
//#region src/streamers/layer.ts
|
|
4991
|
-
var
|
|
5260
|
+
var Streamers = class extends Effect {
|
|
4992
5261
|
#colors;
|
|
4993
5262
|
#scale;
|
|
4994
5263
|
#speed;
|
|
@@ -5014,6 +5283,9 @@ var StreamerLayer = class extends SimulationLayer {
|
|
|
5014
5283
|
for (let i = 0; i < this.#count; i++) this.#streamers.push(this.#createStreamer(true));
|
|
5015
5284
|
}
|
|
5016
5285
|
}
|
|
5286
|
+
configure(config) {
|
|
5287
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
5288
|
+
}
|
|
5017
5289
|
tick(dt, width, height) {
|
|
5018
5290
|
this.#width = width;
|
|
5019
5291
|
this.#height = height;
|
|
@@ -5128,12 +5400,10 @@ var StreamerLayer = class extends SimulationLayer {
|
|
|
5128
5400
|
}
|
|
5129
5401
|
};
|
|
5130
5402
|
//#endregion
|
|
5131
|
-
//#region src/streamers/
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
}
|
|
5136
|
-
};
|
|
5403
|
+
//#region src/streamers/index.ts
|
|
5404
|
+
function createStreamers(config) {
|
|
5405
|
+
return new Streamers(config);
|
|
5406
|
+
}
|
|
5137
5407
|
//#endregion
|
|
5138
5408
|
//#region src/trail.ts
|
|
5139
5409
|
var Trail = class {
|
|
@@ -5247,12 +5517,11 @@ const DEFAULT_COLORS = [
|
|
|
5247
5517
|
"#3399cc",
|
|
5248
5518
|
"#66c2e0"
|
|
5249
5519
|
];
|
|
5250
|
-
var
|
|
5520
|
+
var Waves = class extends Effect {
|
|
5251
5521
|
#speed;
|
|
5252
|
-
#foamColor;
|
|
5253
5522
|
#foamAmount;
|
|
5254
5523
|
#scale;
|
|
5255
|
-
#
|
|
5524
|
+
#foamRGB;
|
|
5256
5525
|
#waves = [];
|
|
5257
5526
|
#foamParticles = [];
|
|
5258
5527
|
#maxFoamParticles;
|
|
@@ -5261,10 +5530,10 @@ var WaveLayer = class extends SimulationLayer {
|
|
|
5261
5530
|
const layers = config.layers ?? 5;
|
|
5262
5531
|
const colors = config.colors ?? DEFAULT_COLORS;
|
|
5263
5532
|
this.#speed = config.speed ?? 1;
|
|
5264
|
-
this.#foamColor = config.foamColor ?? "#ffffff";
|
|
5265
5533
|
this.#foamAmount = config.foamAmount ?? .4;
|
|
5266
5534
|
this.#scale = config.scale ?? 1;
|
|
5267
5535
|
this.#maxFoamParticles = 120;
|
|
5536
|
+
this.#foamRGB = hexToRGB(config.foamColor ?? "#ffffff");
|
|
5268
5537
|
if (innerWidth < 991) this.#maxFoamParticles = Math.floor(this.#maxFoamParticles / 2);
|
|
5269
5538
|
for (let i = 0; i < layers; i++) {
|
|
5270
5539
|
const depth = i / Math.max(layers - 1, 1);
|
|
@@ -5272,17 +5541,22 @@ var WaveLayer = class extends SimulationLayer {
|
|
|
5272
5541
|
this.#waves.push({
|
|
5273
5542
|
amplitude: (20 + MULBERRY$1.next() * 30) * (1 - depth * .4),
|
|
5274
5543
|
frequency: .005 + MULBERRY$1.next() * .008 + depth * .002,
|
|
5275
|
-
speed:
|
|
5544
|
+
speed: .4 + MULBERRY$1.next() * .6 + depth * .3,
|
|
5276
5545
|
phase: MULBERRY$1.next() * Math.PI * 2,
|
|
5277
5546
|
baseY: .35 + depth * .13,
|
|
5278
5547
|
color,
|
|
5279
|
-
foamThreshold: .6 + MULBERRY$1.next() * .3
|
|
5548
|
+
foamThreshold: .6 + MULBERRY$1.next() * .3,
|
|
5549
|
+
rgb: hexToRGB(color)
|
|
5280
5550
|
});
|
|
5281
5551
|
}
|
|
5282
5552
|
}
|
|
5553
|
+
configure(config) {
|
|
5554
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
5555
|
+
if (config.foamAmount !== void 0) this.#foamAmount = config.foamAmount;
|
|
5556
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
5557
|
+
}
|
|
5283
5558
|
tick(dt, width, height) {
|
|
5284
|
-
this.#
|
|
5285
|
-
for (const wave of this.#waves) wave.phase += .015 * wave.speed * dt;
|
|
5559
|
+
for (const wave of this.#waves) wave.phase += .015 * wave.speed * this.#speed * dt;
|
|
5286
5560
|
let aliveFoam = 0;
|
|
5287
5561
|
for (let i = 0; i < this.#foamParticles.length; i++) {
|
|
5288
5562
|
const foam = this.#foamParticles[i];
|
|
@@ -5312,6 +5586,7 @@ var WaveLayer = class extends SimulationLayer {
|
|
|
5312
5586
|
const step = 2;
|
|
5313
5587
|
for (let wi = 0; wi < this.#waves.length; wi++) {
|
|
5314
5588
|
const wave = this.#waves[wi];
|
|
5589
|
+
const [wr, wg, wb] = wave.rgb;
|
|
5315
5590
|
const centerY = wave.baseY * height;
|
|
5316
5591
|
ctx.beginPath();
|
|
5317
5592
|
ctx.moveTo(0, height);
|
|
@@ -5325,54 +5600,35 @@ var WaveLayer = class extends SimulationLayer {
|
|
|
5325
5600
|
ctx.lineTo(width, height);
|
|
5326
5601
|
ctx.closePath();
|
|
5327
5602
|
const gradient = ctx.createLinearGradient(0, centerY - wave.amplitude * this.#scale, 0, height);
|
|
5328
|
-
gradient.addColorStop(0,
|
|
5329
|
-
gradient.addColorStop(.4,
|
|
5330
|
-
gradient.addColorStop(1,
|
|
5603
|
+
gradient.addColorStop(0, `rgba(${wr}, ${wg}, ${wb}, 0.85)`);
|
|
5604
|
+
gradient.addColorStop(.4, `rgb(${wr}, ${wg}, ${wb})`);
|
|
5605
|
+
gradient.addColorStop(1, `rgb(${Math.floor(wr * .6)}, ${Math.floor(wg * .6)}, ${Math.floor(wb * .6)})`);
|
|
5331
5606
|
ctx.fillStyle = gradient;
|
|
5332
5607
|
ctx.fill();
|
|
5333
5608
|
}
|
|
5334
|
-
if (this.#foamAmount > 0)
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5609
|
+
if (this.#foamAmount > 0) {
|
|
5610
|
+
const [fr, fg, fb] = this.#foamRGB;
|
|
5611
|
+
for (const foam of this.#foamParticles) {
|
|
5612
|
+
if (foam.alpha <= 0) continue;
|
|
5613
|
+
ctx.beginPath();
|
|
5614
|
+
ctx.arc(foam.x, foam.y, foam.size * this.#scale, 0, Math.PI * 2);
|
|
5615
|
+
ctx.fillStyle = `rgba(${fr}, ${fg}, ${fb}, ${foam.alpha * this.#foamAmount})`;
|
|
5616
|
+
ctx.fill();
|
|
5617
|
+
}
|
|
5340
5618
|
}
|
|
5341
5619
|
}
|
|
5342
|
-
#adjustAlpha(color, alpha) {
|
|
5343
|
-
const canvas = document.createElement("canvas");
|
|
5344
|
-
canvas.width = 1;
|
|
5345
|
-
canvas.height = 1;
|
|
5346
|
-
const ctx = canvas.getContext("2d");
|
|
5347
|
-
ctx.fillStyle = color;
|
|
5348
|
-
ctx.fillRect(0, 0, 1, 1);
|
|
5349
|
-
const data = ctx.getImageData(0, 0, 1, 1).data;
|
|
5350
|
-
return `rgba(${data[0]}, ${data[1]}, ${data[2]}, ${alpha})`;
|
|
5351
|
-
}
|
|
5352
|
-
#darkenColor(color, factor) {
|
|
5353
|
-
const canvas = document.createElement("canvas");
|
|
5354
|
-
canvas.width = 1;
|
|
5355
|
-
canvas.height = 1;
|
|
5356
|
-
const ctx = canvas.getContext("2d");
|
|
5357
|
-
ctx.fillStyle = color;
|
|
5358
|
-
ctx.fillRect(0, 0, 1, 1);
|
|
5359
|
-
const data = ctx.getImageData(0, 0, 1, 1).data;
|
|
5360
|
-
return `rgb(${Math.floor(data[0] * factor)}, ${Math.floor(data[1] * factor)}, ${Math.floor(data[2] * factor)})`;
|
|
5361
|
-
}
|
|
5362
5620
|
};
|
|
5363
5621
|
//#endregion
|
|
5364
|
-
//#region src/waves/
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
}
|
|
5369
|
-
};
|
|
5622
|
+
//#region src/waves/index.ts
|
|
5623
|
+
function createWaves(config) {
|
|
5624
|
+
return new Waves(config);
|
|
5625
|
+
}
|
|
5370
5626
|
//#endregion
|
|
5371
5627
|
//#region src/wormhole/consts.ts
|
|
5372
5628
|
const MULBERRY = mulberry32(13);
|
|
5373
5629
|
//#endregion
|
|
5374
5630
|
//#region src/wormhole/layer.ts
|
|
5375
|
-
var
|
|
5631
|
+
var Wormhole = class extends Effect {
|
|
5376
5632
|
#speed;
|
|
5377
5633
|
#colorRGB;
|
|
5378
5634
|
#direction;
|
|
@@ -5401,6 +5657,10 @@ var WormholeLayer = class extends SimulationLayer {
|
|
|
5401
5657
|
for (let i = 0; i < this.#count; ++i) this.#particles.push(this.#createParticle(true));
|
|
5402
5658
|
}
|
|
5403
5659
|
}
|
|
5660
|
+
configure(config) {
|
|
5661
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
5662
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
5663
|
+
}
|
|
5404
5664
|
tick(dt, width, height) {
|
|
5405
5665
|
this.#width = width;
|
|
5406
5666
|
this.#height = height;
|
|
@@ -5492,13 +5752,11 @@ var WormholeLayer = class extends SimulationLayer {
|
|
|
5492
5752
|
}
|
|
5493
5753
|
};
|
|
5494
5754
|
//#endregion
|
|
5495
|
-
//#region src/wormhole/
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
}
|
|
5500
|
-
};
|
|
5755
|
+
//#region src/wormhole/index.ts
|
|
5756
|
+
function createWormhole(config) {
|
|
5757
|
+
return new Wormhole(config);
|
|
5758
|
+
}
|
|
5501
5759
|
//#endregion
|
|
5502
|
-
export {
|
|
5760
|
+
export { BalloonParticle, ConfettiParticle, EXPLOSION_CONFIGS, Effect, Explosion, FIREWORK_VARIANTS, FireflyParticle, Firework, LightningSystem, LimitedFrameRateCanvas, PALETTES, RaindropParticle, SHAPE_PATHS, Scene, ShootingStarSystem, Spark, SparklerParticle, SplashParticle, Trail, createAurora, createBalloons, createBubbles, createConfetti, createDonuts, createExplosion, createFireflies, createFireflySprite, createFirepit, createFireworks, createGlitter, createLanterns, createLeaves, createLightning, createMatrix, createOrbits, createParticles, createPetals, createPlasma, createRain, createSandstorm, createScene, createSnow, createSparklers, createStars, createStreamers, createWaves, createWormhole, parseColor };
|
|
5503
5761
|
|
|
5504
5762
|
//# sourceMappingURL=index.mjs.map
|