@basmilius/sparkle 2.1.0 → 2.3.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 +317 -459
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1258 -949
- 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 +92 -2
- 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/confetti/shapes.ts +84 -97
- 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 +204 -0
- package/src/shooting-stars/system.ts +26 -24
- package/src/shooting-stars/types.ts +2 -1
- package/src/simulation-canvas.ts +45 -6
- 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,141 +1,33 @@
|
|
|
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;
|
|
5
|
+
static #globalFrameRate = null;
|
|
6
|
+
static #showFps = false;
|
|
133
7
|
static get globalSpeed() {
|
|
134
8
|
return LimitedFrameRateCanvas.#globalSpeed;
|
|
135
9
|
}
|
|
136
10
|
static set globalSpeed(value) {
|
|
137
11
|
LimitedFrameRateCanvas.#globalSpeed = value;
|
|
138
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Global frame rate override for all canvas instances.
|
|
15
|
+
* null = use each instance's own frame rate.
|
|
16
|
+
* 0 = unlimited (render as fast as the browser allows).
|
|
17
|
+
* Any positive number = cap at that many frames per second.
|
|
18
|
+
*/
|
|
19
|
+
static get globalFrameRate() {
|
|
20
|
+
return LimitedFrameRateCanvas.#globalFrameRate;
|
|
21
|
+
}
|
|
22
|
+
static set globalFrameRate(value) {
|
|
23
|
+
LimitedFrameRateCanvas.#globalFrameRate = value;
|
|
24
|
+
}
|
|
25
|
+
static get showFps() {
|
|
26
|
+
return LimitedFrameRateCanvas.#showFps;
|
|
27
|
+
}
|
|
28
|
+
static set showFps(value) {
|
|
29
|
+
LimitedFrameRateCanvas.#showFps = value;
|
|
30
|
+
}
|
|
139
31
|
#canvas;
|
|
140
32
|
#context;
|
|
141
33
|
#frameRate;
|
|
@@ -150,6 +42,9 @@ var LimitedFrameRateCanvas = class LimitedFrameRateCanvas {
|
|
|
150
42
|
#isStopped = true;
|
|
151
43
|
#height = 540;
|
|
152
44
|
#width = 960;
|
|
45
|
+
#fps = "0.0";
|
|
46
|
+
#fpsFrames = 0;
|
|
47
|
+
#fpsTime = 0;
|
|
153
48
|
get canvas() {
|
|
154
49
|
return this.#canvas;
|
|
155
50
|
}
|
|
@@ -168,6 +63,9 @@ var LimitedFrameRateCanvas = class LimitedFrameRateCanvas {
|
|
|
168
63
|
set speed(value) {
|
|
169
64
|
this.#speed = value;
|
|
170
65
|
}
|
|
66
|
+
get dpr() {
|
|
67
|
+
return devicePixelRatio;
|
|
68
|
+
}
|
|
171
69
|
get frameRate() {
|
|
172
70
|
return this.#frameRate;
|
|
173
71
|
}
|
|
@@ -190,7 +88,7 @@ var LimitedFrameRateCanvas = class LimitedFrameRateCanvas {
|
|
|
190
88
|
this.#canvas = canvas;
|
|
191
89
|
this.#context = canvas.getContext("2d", options);
|
|
192
90
|
this.#frameRate = frameRate;
|
|
193
|
-
this.#target = 1e3 / frameRate;
|
|
91
|
+
this.#target = frameRate > 0 ? 1e3 / frameRate : 0;
|
|
194
92
|
this.onVisibilityChange = this.onVisibilityChange.bind(this);
|
|
195
93
|
this.onResize = this.onResize.bind(this);
|
|
196
94
|
document.addEventListener("visibilitychange", this.onVisibilityChange, { passive: true });
|
|
@@ -200,12 +98,27 @@ var LimitedFrameRateCanvas = class LimitedFrameRateCanvas {
|
|
|
200
98
|
if (this.#isStopped) return;
|
|
201
99
|
this.#current = Date.now();
|
|
202
100
|
this.#frame = requestAnimationFrame(this.loop.bind(this));
|
|
203
|
-
|
|
101
|
+
const globalRate = LimitedFrameRateCanvas.#globalFrameRate;
|
|
102
|
+
const effectiveTarget = globalRate !== null ? globalRate > 0 ? 1e3 / globalRate : 0 : this.#target;
|
|
103
|
+
if (effectiveTarget > 0 && this.#then > 0 && this.#current - this.#then + 1 < effectiveTarget) return;
|
|
204
104
|
this.#now = this.#current;
|
|
205
105
|
this.#delta = this.#now - this.#then;
|
|
206
106
|
++this.#ticks;
|
|
207
107
|
this.tick();
|
|
208
108
|
this.draw();
|
|
109
|
+
if (LimitedFrameRateCanvas.#showFps) {
|
|
110
|
+
++this.#fpsFrames;
|
|
111
|
+
if (this.#fpsTime === 0) this.#fpsTime = this.#current;
|
|
112
|
+
else {
|
|
113
|
+
const elapsed = this.#current - this.#fpsTime;
|
|
114
|
+
if (elapsed >= 1e3) {
|
|
115
|
+
this.#fps = (Math.round(this.#fpsFrames * 1e4 / elapsed) / 10).toFixed(1);
|
|
116
|
+
this.#fpsFrames = 0;
|
|
117
|
+
this.#fpsTime = this.#current;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
this.#drawFps();
|
|
121
|
+
}
|
|
209
122
|
this.#then = this.#now;
|
|
210
123
|
}
|
|
211
124
|
start() {
|
|
@@ -217,6 +130,36 @@ var LimitedFrameRateCanvas = class LimitedFrameRateCanvas {
|
|
|
217
130
|
this.#isStopped = true;
|
|
218
131
|
cancelAnimationFrame(this.#frame);
|
|
219
132
|
}
|
|
133
|
+
pause() {
|
|
134
|
+
this.#isStopped = true;
|
|
135
|
+
cancelAnimationFrame(this.#frame);
|
|
136
|
+
}
|
|
137
|
+
resume() {
|
|
138
|
+
if (this.#isStopped) {
|
|
139
|
+
this.#isStopped = false;
|
|
140
|
+
this.#frame = requestAnimationFrame(this.loop.bind(this));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
#drawFps() {
|
|
144
|
+
const ctx = this.#context;
|
|
145
|
+
const text = `${this.#fps} FPS`;
|
|
146
|
+
const x = 9;
|
|
147
|
+
const y = 9;
|
|
148
|
+
const paddingX = 6;
|
|
149
|
+
const paddingY = 4;
|
|
150
|
+
ctx.save();
|
|
151
|
+
ctx.font = "700 10px ui-monospace, monospace";
|
|
152
|
+
const boxWidth = ctx.measureText(text).width + paddingX * 2;
|
|
153
|
+
const boxHeight = 11 + paddingY * 2;
|
|
154
|
+
ctx.fillStyle = "rgba(0, 0, 0, 0.45)";
|
|
155
|
+
ctx.beginPath();
|
|
156
|
+
ctx.roundRect(x, y, boxWidth, boxHeight, 3);
|
|
157
|
+
ctx.fill();
|
|
158
|
+
ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
|
|
159
|
+
ctx.textBaseline = "middle";
|
|
160
|
+
ctx.fillText(text, x + paddingX, y + boxHeight / 1.9);
|
|
161
|
+
ctx.restore();
|
|
162
|
+
}
|
|
220
163
|
draw() {
|
|
221
164
|
throw new Error("LimitedFrameRateCanvas::draw() should be overwritten.");
|
|
222
165
|
}
|
|
@@ -245,18 +188,99 @@ var LimitedFrameRateCanvas = class LimitedFrameRateCanvas {
|
|
|
245
188
|
}
|
|
246
189
|
};
|
|
247
190
|
//#endregion
|
|
191
|
+
//#region src/fade.ts
|
|
192
|
+
function parseSide(side) {
|
|
193
|
+
return typeof side === "number" ? [0, side] : side;
|
|
194
|
+
}
|
|
195
|
+
function applyEdgeFade(ctx, width, height, fade) {
|
|
196
|
+
ctx.globalCompositeOperation = "destination-out";
|
|
197
|
+
if (fade.top !== void 0) {
|
|
198
|
+
const [near, far] = parseSide(fade.top);
|
|
199
|
+
const nearPx = near * height;
|
|
200
|
+
const farPx = far * height;
|
|
201
|
+
if (nearPx > 0) {
|
|
202
|
+
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
203
|
+
ctx.fillRect(0, 0, width, nearPx);
|
|
204
|
+
}
|
|
205
|
+
if (farPx > nearPx) {
|
|
206
|
+
const gradient = ctx.createLinearGradient(0, nearPx, 0, farPx);
|
|
207
|
+
gradient.addColorStop(0, "rgba(0,0,0,1)");
|
|
208
|
+
gradient.addColorStop(1, "rgba(0,0,0,0)");
|
|
209
|
+
ctx.fillStyle = gradient;
|
|
210
|
+
ctx.fillRect(0, nearPx, width, farPx - nearPx);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (fade.bottom !== void 0) {
|
|
214
|
+
const [near, far] = parseSide(fade.bottom);
|
|
215
|
+
const nearPx = near * height;
|
|
216
|
+
const farPx = far * height;
|
|
217
|
+
if (nearPx > 0) {
|
|
218
|
+
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
219
|
+
ctx.fillRect(0, height - nearPx, width, nearPx);
|
|
220
|
+
}
|
|
221
|
+
if (farPx > nearPx) {
|
|
222
|
+
const gradient = ctx.createLinearGradient(0, height - farPx, 0, height - nearPx);
|
|
223
|
+
gradient.addColorStop(0, "rgba(0,0,0,0)");
|
|
224
|
+
gradient.addColorStop(1, "rgba(0,0,0,1)");
|
|
225
|
+
ctx.fillStyle = gradient;
|
|
226
|
+
ctx.fillRect(0, height - farPx, width, farPx - nearPx);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (fade.left !== void 0) {
|
|
230
|
+
const [near, far] = parseSide(fade.left);
|
|
231
|
+
const nearPx = near * width;
|
|
232
|
+
const farPx = far * width;
|
|
233
|
+
if (nearPx > 0) {
|
|
234
|
+
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
235
|
+
ctx.fillRect(0, 0, nearPx, height);
|
|
236
|
+
}
|
|
237
|
+
if (farPx > nearPx) {
|
|
238
|
+
const gradient = ctx.createLinearGradient(nearPx, 0, farPx, 0);
|
|
239
|
+
gradient.addColorStop(0, "rgba(0,0,0,1)");
|
|
240
|
+
gradient.addColorStop(1, "rgba(0,0,0,0)");
|
|
241
|
+
ctx.fillStyle = gradient;
|
|
242
|
+
ctx.fillRect(nearPx, 0, farPx - nearPx, height);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (fade.right !== void 0) {
|
|
246
|
+
const [near, far] = parseSide(fade.right);
|
|
247
|
+
const nearPx = near * width;
|
|
248
|
+
const farPx = far * width;
|
|
249
|
+
if (nearPx > 0) {
|
|
250
|
+
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
251
|
+
ctx.fillRect(width - nearPx, 0, nearPx, height);
|
|
252
|
+
}
|
|
253
|
+
if (farPx > nearPx) {
|
|
254
|
+
const gradient = ctx.createLinearGradient(width - farPx, 0, width - nearPx, 0);
|
|
255
|
+
gradient.addColorStop(0, "rgba(0,0,0,0)");
|
|
256
|
+
gradient.addColorStop(1, "rgba(0,0,0,1)");
|
|
257
|
+
ctx.fillStyle = gradient;
|
|
258
|
+
ctx.fillRect(width - farPx, 0, farPx - nearPx, height);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
ctx.globalCompositeOperation = "source-over";
|
|
262
|
+
}
|
|
263
|
+
//#endregion
|
|
248
264
|
//#region src/simulation-canvas.ts
|
|
249
265
|
var SimulationCanvas = class extends LimitedFrameRateCanvas {
|
|
250
266
|
#simulation;
|
|
267
|
+
#contextOptions;
|
|
268
|
+
#offscreen = null;
|
|
269
|
+
#offscreenCtx = null;
|
|
251
270
|
constructor(canvas, simulation, frameRate = 60, options = { colorSpace: "display-p3" }) {
|
|
252
271
|
super(canvas, frameRate, options);
|
|
253
272
|
this.#simulation = simulation;
|
|
273
|
+
this.#contextOptions = options;
|
|
254
274
|
canvas.style.position = "absolute";
|
|
255
275
|
canvas.style.top = "0";
|
|
256
276
|
canvas.style.left = "0";
|
|
257
277
|
canvas.style.height = "100%";
|
|
258
278
|
canvas.style.width = "100%";
|
|
259
279
|
}
|
|
280
|
+
withFade(fade) {
|
|
281
|
+
this.#simulation.fade = fade;
|
|
282
|
+
return this;
|
|
283
|
+
}
|
|
260
284
|
start() {
|
|
261
285
|
this.#simulation.onMount(this.canvas);
|
|
262
286
|
super.start();
|
|
@@ -266,12 +290,23 @@ var SimulationCanvas = class extends LimitedFrameRateCanvas {
|
|
|
266
290
|
super.destroy();
|
|
267
291
|
}
|
|
268
292
|
draw() {
|
|
269
|
-
|
|
270
|
-
this.canvas.
|
|
293
|
+
const dpr = this.dpr;
|
|
294
|
+
this.canvas.height = this.height * dpr;
|
|
295
|
+
this.canvas.width = this.width * dpr;
|
|
271
296
|
const ctx = this.context;
|
|
272
|
-
ctx.
|
|
273
|
-
this.#simulation.
|
|
274
|
-
|
|
297
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
298
|
+
if (this.#simulation.fade) {
|
|
299
|
+
const offCtx = this.#getOffscreenCtx(this.width * dpr, this.height * dpr);
|
|
300
|
+
offCtx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
301
|
+
offCtx.clearRect(0, 0, this.width, this.height);
|
|
302
|
+
this.#simulation.draw(offCtx, this.width, this.height);
|
|
303
|
+
applyEdgeFade(offCtx, this.width, this.height, this.#simulation.fade);
|
|
304
|
+
ctx.drawImage(this.#offscreen, 0, 0, this.width, this.height);
|
|
305
|
+
} else {
|
|
306
|
+
ctx.save();
|
|
307
|
+
this.#simulation.draw(ctx, this.width, this.height);
|
|
308
|
+
ctx.restore();
|
|
309
|
+
}
|
|
275
310
|
}
|
|
276
311
|
tick() {
|
|
277
312
|
const dt = (this.delta > 0 && this.delta < 200 ? this.delta / (1e3 / 60) : 1) * this.speed * LimitedFrameRateCanvas.globalSpeed;
|
|
@@ -279,32 +314,230 @@ var SimulationCanvas = class extends LimitedFrameRateCanvas {
|
|
|
279
314
|
}
|
|
280
315
|
onResize() {
|
|
281
316
|
super.onResize();
|
|
317
|
+
if (this.#offscreen) {
|
|
318
|
+
this.#offscreen.width = this.width * this.dpr;
|
|
319
|
+
this.#offscreen.height = this.height * this.dpr;
|
|
320
|
+
}
|
|
282
321
|
this.#simulation.onResize(this.width, this.height);
|
|
283
322
|
}
|
|
323
|
+
#getOffscreenCtx(width, height) {
|
|
324
|
+
if (!this.#offscreen) {
|
|
325
|
+
this.#offscreen = document.createElement("canvas");
|
|
326
|
+
this.#offscreen.width = width;
|
|
327
|
+
this.#offscreen.height = height;
|
|
328
|
+
this.#offscreenCtx = this.#offscreen.getContext("2d", this.#contextOptions);
|
|
329
|
+
}
|
|
330
|
+
return this.#offscreenCtx;
|
|
331
|
+
}
|
|
284
332
|
};
|
|
285
333
|
//#endregion
|
|
286
|
-
//#region src/
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
334
|
+
//#region src/effect.ts
|
|
335
|
+
/**
|
|
336
|
+
* Base class for all visual effects. Implements the internal SimulationLayer interface
|
|
337
|
+
* so that effects can be used both standalone (via mount()) and composed in a Scene.
|
|
338
|
+
*
|
|
339
|
+
* @example Standalone usage
|
|
340
|
+
* const snow = new Snow({ particles: 200 });
|
|
341
|
+
* snow.mount(canvas).start();
|
|
342
|
+
*
|
|
343
|
+
* @example Scene composition
|
|
344
|
+
* const scene = new Scene()
|
|
345
|
+
* .mount(canvas)
|
|
346
|
+
* .layer(new Aurora())
|
|
347
|
+
* .layer(new Snow())
|
|
348
|
+
* .start();
|
|
349
|
+
*/
|
|
350
|
+
var Effect = class {
|
|
351
|
+
#canvas = null;
|
|
352
|
+
fade = null;
|
|
353
|
+
configure(_config) {}
|
|
354
|
+
onResize(_width, _height) {}
|
|
355
|
+
onMount(_canvas) {}
|
|
356
|
+
onUnmount(_canvas) {}
|
|
357
|
+
/**
|
|
358
|
+
* Apply an edge fade mask when rendering this effect standalone or in a Scene.
|
|
359
|
+
*/
|
|
360
|
+
withFade(fade) {
|
|
361
|
+
this.fade = fade;
|
|
362
|
+
return this;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Mount this effect to a canvas element or CSS selector, creating the render loop.
|
|
366
|
+
* Must be called before start().
|
|
367
|
+
*/
|
|
368
|
+
mount(canvas, options = { colorSpace: "display-p3" }, frameRate = 60) {
|
|
369
|
+
if (typeof canvas === "string") {
|
|
370
|
+
const el = document.querySelector(canvas);
|
|
371
|
+
if (!el) throw new Error(`Effect.mount(): no element found for selector "${canvas}".`);
|
|
372
|
+
canvas = el;
|
|
373
|
+
}
|
|
374
|
+
this.#canvas = new SimulationCanvas(canvas, this, frameRate, options);
|
|
375
|
+
return this;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Remove this effect from its canvas and clean up the render loop.
|
|
379
|
+
*/
|
|
380
|
+
unmount() {
|
|
381
|
+
this.#canvas?.destroy();
|
|
382
|
+
this.#canvas = null;
|
|
383
|
+
return this;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Start the render loop. Call mount() first.
|
|
387
|
+
*/
|
|
388
|
+
start() {
|
|
389
|
+
this.#canvas?.start();
|
|
390
|
+
return this;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Pause rendering without destroying state. Use resume() to continue.
|
|
394
|
+
*/
|
|
395
|
+
pause() {
|
|
396
|
+
this.#canvas?.pause();
|
|
397
|
+
return this;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Resume rendering after a pause().
|
|
401
|
+
*/
|
|
402
|
+
resume() {
|
|
403
|
+
this.#canvas?.resume();
|
|
404
|
+
return this;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Stop rendering and call onUnmount(). Safe to call multiple times.
|
|
408
|
+
*/
|
|
409
|
+
destroy() {
|
|
410
|
+
this.unmount();
|
|
290
411
|
}
|
|
291
412
|
};
|
|
292
413
|
//#endregion
|
|
293
|
-
//#region src/
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
414
|
+
//#region src/aurora/consts.ts
|
|
415
|
+
const MULBERRY$23 = mulberry32(13);
|
|
416
|
+
//#endregion
|
|
417
|
+
//#region src/aurora/layer.ts
|
|
418
|
+
const DEFAULT_COLORS$4 = [
|
|
419
|
+
"#9922ff",
|
|
420
|
+
"#4455ff",
|
|
421
|
+
"#0077ee",
|
|
422
|
+
"#00aabb",
|
|
423
|
+
"#22ddff"
|
|
424
|
+
];
|
|
425
|
+
const TOP_HUE = 265;
|
|
426
|
+
var Aurora = class extends Effect {
|
|
427
|
+
#speed;
|
|
428
|
+
#intensity;
|
|
429
|
+
#waveAmplitude;
|
|
430
|
+
#verticalPosition;
|
|
431
|
+
#bands = [];
|
|
432
|
+
constructor(config = {}) {
|
|
433
|
+
super();
|
|
434
|
+
const bandCount = config.bands ?? 5;
|
|
435
|
+
const colors = config.colors ?? DEFAULT_COLORS$4;
|
|
436
|
+
this.#speed = config.speed ?? 1;
|
|
437
|
+
this.#intensity = config.intensity ?? .8;
|
|
438
|
+
this.#waveAmplitude = config.waveAmplitude ?? 1;
|
|
439
|
+
this.#verticalPosition = config.verticalPosition ?? .68;
|
|
440
|
+
const clusterCenters = [.35, .65];
|
|
441
|
+
for (let i = 0; i < bandCount; i++) {
|
|
442
|
+
const color = colors[i % colors.length];
|
|
443
|
+
const [r, g, b] = hexToRGB(color);
|
|
444
|
+
const hue = this.#rgbToHue(r, g, b);
|
|
445
|
+
const cluster = clusterCenters[i % clusterCenters.length];
|
|
446
|
+
this.#bands.push({
|
|
447
|
+
x: cluster + (MULBERRY$23.next() - .5) * .22,
|
|
448
|
+
baseY: (MULBERRY$23.next() - .5) * .08,
|
|
449
|
+
height: .5 + MULBERRY$23.next() * .3,
|
|
450
|
+
sigma: 160 + MULBERRY$23.next() * 110,
|
|
451
|
+
phase1: MULBERRY$23.next() * Math.PI * 2,
|
|
452
|
+
phase2: MULBERRY$23.next() * Math.PI * 2,
|
|
453
|
+
amplitude1: .015 + MULBERRY$23.next() * .025,
|
|
454
|
+
frequency1: .003 + MULBERRY$23.next() * .004,
|
|
455
|
+
speed: .4 + MULBERRY$23.next() * .6,
|
|
456
|
+
hue,
|
|
457
|
+
opacity: .5 + MULBERRY$23.next() * .3
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
configure(config) {
|
|
462
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
463
|
+
if (config.intensity !== void 0) this.#intensity = config.intensity;
|
|
464
|
+
if (config.waveAmplitude !== void 0) this.#waveAmplitude = config.waveAmplitude;
|
|
465
|
+
if (config.verticalPosition !== void 0) this.#verticalPosition = config.verticalPosition;
|
|
466
|
+
}
|
|
467
|
+
tick(dt, _width, _height) {
|
|
468
|
+
for (const band of this.#bands) {
|
|
469
|
+
band.phase1 += .005 * band.speed * this.#speed * dt;
|
|
470
|
+
band.phase2 += .008 * band.speed * this.#speed * dt;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
draw(ctx, width, height) {
|
|
474
|
+
const bg = ctx.createLinearGradient(0, 0, 0, height);
|
|
475
|
+
bg.addColorStop(0, "#000000");
|
|
476
|
+
bg.addColorStop(.5, "#050012");
|
|
477
|
+
bg.addColorStop(1, "#0a0025");
|
|
478
|
+
ctx.fillStyle = bg;
|
|
479
|
+
ctx.fillRect(0, 0, width, height);
|
|
480
|
+
ctx.globalCompositeOperation = "screen";
|
|
481
|
+
const step = 4;
|
|
482
|
+
const scale = width / 1920;
|
|
483
|
+
for (const band of this.#bands) {
|
|
484
|
+
const swayX = band.amplitude1 * width * Math.sin(band.phase1);
|
|
485
|
+
const cx = band.x * width + swayX;
|
|
486
|
+
const baseY = (this.#verticalPosition + band.baseY) * height;
|
|
487
|
+
const rayHeight = band.height * height * (height / 800);
|
|
488
|
+
const sigma = band.sigma * scale;
|
|
489
|
+
const cutoff = sigma * 3.5;
|
|
490
|
+
const sigmaSq2 = 2 * sigma * sigma;
|
|
491
|
+
const midHue = (band.hue + TOP_HUE) / 2;
|
|
492
|
+
const waveRange = height * .035 * this.#waveAmplitude;
|
|
493
|
+
const xStart = Math.max(0, Math.floor((cx - cutoff) / step) * step);
|
|
494
|
+
const xEnd = Math.min(width, Math.ceil((cx + cutoff) / step) * step);
|
|
495
|
+
const centreBase = baseY + Math.sin(band.frequency1 * cx + band.phase2) * waveRange;
|
|
496
|
+
const centreTop = centreBase - rayHeight;
|
|
497
|
+
const centreFadeBottom = centreBase + rayHeight * .1;
|
|
498
|
+
const gradient = ctx.createLinearGradient(0, centreFadeBottom, 0, centreTop);
|
|
499
|
+
gradient.addColorStop(0, `hsla(${band.hue}, 100%, 90%, 0)`);
|
|
500
|
+
gradient.addColorStop(.04, `hsla(${band.hue}, 100%, 90%, 0.55)`);
|
|
501
|
+
gradient.addColorStop(.1, `hsla(${band.hue}, 90%, 72%, 1)`);
|
|
502
|
+
gradient.addColorStop(.32, `hsla(${band.hue}, 85%, 62%, 0.75)`);
|
|
503
|
+
gradient.addColorStop(.62, `hsla(${midHue}, 80%, 56%, 0.35)`);
|
|
504
|
+
gradient.addColorStop(.86, `hsla(${TOP_HUE}, 75%, 50%, 0.12)`);
|
|
505
|
+
gradient.addColorStop(1, `hsla(${TOP_HUE}, 70%, 45%, 0)`);
|
|
506
|
+
ctx.fillStyle = gradient;
|
|
507
|
+
for (let x = xStart; x < xEnd; x += step) {
|
|
508
|
+
const dx = x - cx;
|
|
509
|
+
const alpha = Math.exp(-dx * dx / sigmaSq2);
|
|
510
|
+
if (alpha < .015) continue;
|
|
511
|
+
const colBase = baseY + Math.sin(band.frequency1 * x + band.phase2) * waveRange;
|
|
512
|
+
const colTop = colBase - rayHeight;
|
|
513
|
+
const fadeBottom = colBase + rayHeight * .1;
|
|
514
|
+
ctx.globalAlpha = alpha * band.opacity * this.#intensity;
|
|
515
|
+
ctx.fillRect(x, colTop, step, fadeBottom - colTop + 1);
|
|
516
|
+
}
|
|
517
|
+
ctx.globalAlpha = 1;
|
|
518
|
+
}
|
|
519
|
+
ctx.globalCompositeOperation = "source-over";
|
|
520
|
+
}
|
|
521
|
+
#rgbToHue(r, g, b) {
|
|
522
|
+
r /= 255;
|
|
523
|
+
g /= 255;
|
|
524
|
+
b /= 255;
|
|
525
|
+
const max = Math.max(r, g, b);
|
|
526
|
+
const delta = max - Math.min(r, g, b);
|
|
527
|
+
if (delta === 0) return 0;
|
|
528
|
+
let hue;
|
|
529
|
+
if (max === r) hue = (g - b) / delta % 6;
|
|
530
|
+
else if (max === g) hue = (b - r) / delta + 2;
|
|
531
|
+
else hue = (r - g) / delta + 4;
|
|
532
|
+
hue = Math.round(hue * 60);
|
|
533
|
+
if (hue < 0) hue += 360;
|
|
534
|
+
return hue;
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
//#endregion
|
|
538
|
+
//#region src/aurora/index.ts
|
|
539
|
+
function createAurora(config) {
|
|
540
|
+
return new Aurora(config);
|
|
308
541
|
}
|
|
309
542
|
//#endregion
|
|
310
543
|
//#region src/balloons/consts.ts
|
|
@@ -319,7 +552,7 @@ const DEFAULT_COLORS$3 = [
|
|
|
319
552
|
"#ff88cc",
|
|
320
553
|
"#8844ff"
|
|
321
554
|
];
|
|
322
|
-
var
|
|
555
|
+
var Balloons = class extends Effect {
|
|
323
556
|
#scale;
|
|
324
557
|
#speed;
|
|
325
558
|
#driftAmount;
|
|
@@ -341,6 +574,11 @@ var BalloonLayer = class extends SimulationLayer {
|
|
|
341
574
|
if (innerWidth < 991) this.#maxCount = Math.floor(this.#maxCount / 2);
|
|
342
575
|
for (let i = 0; i < this.#maxCount; ++i) this.#balloons.push(this.#createBalloon(true));
|
|
343
576
|
}
|
|
577
|
+
configure(config) {
|
|
578
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
579
|
+
if (config.driftAmount !== void 0) this.#driftAmount = config.driftAmount;
|
|
580
|
+
if (config.stringLength !== void 0) this.#stringLengthMul = config.stringLength;
|
|
581
|
+
}
|
|
344
582
|
tick(dt, width, height) {
|
|
345
583
|
this.#time += .015 * dt * this.#speed;
|
|
346
584
|
for (let i = 0; i < this.#balloons.length; i++) {
|
|
@@ -359,9 +597,9 @@ var BalloonLayer = class extends SimulationLayer {
|
|
|
359
597
|
const rx = balloon.radiusX * this.#scale;
|
|
360
598
|
const ry = balloon.radiusY * this.#scale;
|
|
361
599
|
const [r, g, b] = balloon.color;
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
ctx.
|
|
600
|
+
const cos = Math.cos(balloon.rotation);
|
|
601
|
+
const sin = Math.sin(balloon.rotation);
|
|
602
|
+
ctx.setTransform(cos, sin, -sin, cos, px, py);
|
|
365
603
|
const gradient = ctx.createRadialGradient(-rx * .3, -ry * .3, rx * .1, 0, 0, Math.max(rx, ry));
|
|
366
604
|
gradient.addColorStop(0, `rgba(${Math.min(255, r + 80)}, ${Math.min(255, g + 80)}, ${Math.min(255, b + 80)}, 0.95)`);
|
|
367
605
|
gradient.addColorStop(.6, `rgba(${r}, ${g}, ${b}, 0.9)`);
|
|
@@ -383,15 +621,21 @@ var BalloonLayer = class extends SimulationLayer {
|
|
|
383
621
|
ctx.fillStyle = `rgba(${Math.max(0, r - 30)}, ${Math.max(0, g - 30)}, ${Math.max(0, b - 30)}, 0.9)`;
|
|
384
622
|
ctx.fill();
|
|
385
623
|
const stringLen = balloon.stringLength * this.#scale * this.#stringLengthMul;
|
|
386
|
-
const
|
|
624
|
+
const knotBaseY = knotY + 5 * this.#scale;
|
|
625
|
+
const ph = balloon.driftPhase;
|
|
626
|
+
const fr = balloon.driftFreq;
|
|
627
|
+
const swingAmt = 10 * this.#scale * this.#driftAmount;
|
|
628
|
+
const midSwing = Math.sin(this.#time * fr + ph - .3) * swingAmt * .55;
|
|
629
|
+
const tipSwing = Math.sin(this.#time * fr + ph - .8) * swingAmt;
|
|
630
|
+
const flutter = Math.sin(this.#time * fr * 2.5 + ph * 1.4 + 1.8) * 2.5 * this.#scale;
|
|
387
631
|
ctx.beginPath();
|
|
388
|
-
ctx.moveTo(0,
|
|
389
|
-
ctx.
|
|
632
|
+
ctx.moveTo(0, knotBaseY);
|
|
633
|
+
ctx.bezierCurveTo(midSwing * .35, knotBaseY + stringLen * .3, midSwing + flutter * .5, knotBaseY + stringLen * .65, tipSwing + flutter, knotBaseY + stringLen);
|
|
390
634
|
ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, 0.4)`;
|
|
391
635
|
ctx.lineWidth = 1;
|
|
392
636
|
ctx.stroke();
|
|
393
|
-
ctx.restore();
|
|
394
637
|
}
|
|
638
|
+
ctx.resetTransform();
|
|
395
639
|
}
|
|
396
640
|
#createBalloon(initialSpread) {
|
|
397
641
|
const colorIndex = Math.floor(MULBERRY$22.next() * this.#colorRGBs.length);
|
|
@@ -496,12 +740,32 @@ var BalloonParticle = class {
|
|
|
496
740
|
}
|
|
497
741
|
};
|
|
498
742
|
//#endregion
|
|
499
|
-
//#region src/balloons/
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
743
|
+
//#region src/balloons/index.ts
|
|
744
|
+
function createBalloons(config) {
|
|
745
|
+
return new Balloons(config);
|
|
746
|
+
}
|
|
747
|
+
//#endregion
|
|
748
|
+
//#region src/color.ts
|
|
749
|
+
const cache = /* @__PURE__ */ new Map();
|
|
750
|
+
function parseColor(fillStyle) {
|
|
751
|
+
const cached = cache.get(fillStyle);
|
|
752
|
+
if (cached) return cached;
|
|
753
|
+
const canvas = document.createElement("canvas");
|
|
754
|
+
canvas.width = 1;
|
|
755
|
+
canvas.height = 1;
|
|
756
|
+
const ctx = canvas.getContext("2d");
|
|
757
|
+
ctx.fillStyle = fillStyle;
|
|
758
|
+
ctx.fillRect(0, 0, 1, 1);
|
|
759
|
+
const data = ctx.getImageData(0, 0, 1, 1).data;
|
|
760
|
+
const result = {
|
|
761
|
+
r: data[0],
|
|
762
|
+
g: data[1],
|
|
763
|
+
b: data[2],
|
|
764
|
+
a: data[3] / 255
|
|
765
|
+
};
|
|
766
|
+
cache.set(fillStyle, result);
|
|
767
|
+
return result;
|
|
768
|
+
}
|
|
505
769
|
//#endregion
|
|
506
770
|
//#region src/bubbles/consts.ts
|
|
507
771
|
const MULBERRY$21 = mulberry32(13);
|
|
@@ -512,7 +776,7 @@ const DEFAULT_COLORS$2 = [
|
|
|
512
776
|
"#aaddff",
|
|
513
777
|
"#ccbbff"
|
|
514
778
|
];
|
|
515
|
-
var
|
|
779
|
+
var Bubbles = class extends Effect {
|
|
516
780
|
#scale;
|
|
517
781
|
#speed;
|
|
518
782
|
#sizeRange;
|
|
@@ -548,6 +812,10 @@ var BubbleLayer = class extends SimulationLayer {
|
|
|
548
812
|
canvas.removeEventListener("click", this.#onClickBound);
|
|
549
813
|
this.#canvas = null;
|
|
550
814
|
}
|
|
815
|
+
configure(config) {
|
|
816
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
817
|
+
if (config.wobbleAmount !== void 0) this.#wobbleAmount = config.wobbleAmount;
|
|
818
|
+
}
|
|
551
819
|
tick(dt, width, height) {
|
|
552
820
|
this.#time += .01 * dt;
|
|
553
821
|
for (let i = 0; i < this.#bubbles.length; i++) {
|
|
@@ -646,16 +914,10 @@ var BubbleLayer = class extends SimulationLayer {
|
|
|
646
914
|
}
|
|
647
915
|
}
|
|
648
916
|
#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;
|
|
917
|
+
const { r: r255, g: g255, b: b255 } = parseColor(color);
|
|
918
|
+
let r = r255 / 255;
|
|
919
|
+
let g = g255 / 255;
|
|
920
|
+
let b = b255 / 255;
|
|
659
921
|
const max = Math.max(r, g, b);
|
|
660
922
|
const delta = max - Math.min(r, g, b);
|
|
661
923
|
if (delta === 0) return 0;
|
|
@@ -669,12 +931,10 @@ var BubbleLayer = class extends SimulationLayer {
|
|
|
669
931
|
}
|
|
670
932
|
};
|
|
671
933
|
//#endregion
|
|
672
|
-
//#region src/bubbles/
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
}
|
|
677
|
-
};
|
|
934
|
+
//#region src/bubbles/index.ts
|
|
935
|
+
function createBubbles(config) {
|
|
936
|
+
return new Bubbles(config);
|
|
937
|
+
}
|
|
678
938
|
//#endregion
|
|
679
939
|
//#region src/confetti/consts.ts
|
|
680
940
|
const PALETTES = {
|
|
@@ -744,101 +1004,85 @@ const MULBERRY$20 = mulberry32(13);
|
|
|
744
1004
|
//#endregion
|
|
745
1005
|
//#region src/confetti/shapes.ts
|
|
746
1006
|
const TWO_PI$1 = Math.PI * 2;
|
|
747
|
-
|
|
748
|
-
bowtie
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
const
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
else path.lineTo(r * Math.cos(angle), r * Math.sin(angle));
|
|
823
|
-
}
|
|
824
|
-
path.closePath();
|
|
825
|
-
return path;
|
|
826
|
-
})(),
|
|
827
|
-
triangle: (() => {
|
|
828
|
-
const path = new Path2D();
|
|
829
|
-
for (let i = 0; i < 3; i++) {
|
|
830
|
-
const angle = i * 2 * Math.PI / 3 - Math.PI / 2;
|
|
831
|
-
if (i === 0) path.moveTo(Math.cos(angle), Math.sin(angle));
|
|
832
|
-
else path.lineTo(Math.cos(angle), Math.sin(angle));
|
|
833
|
-
}
|
|
834
|
-
path.closePath();
|
|
835
|
-
return path;
|
|
836
|
-
})()
|
|
837
|
-
};
|
|
1007
|
+
function buildShapePaths() {
|
|
1008
|
+
const bowtie = new Path2D();
|
|
1009
|
+
bowtie.moveTo(-1, -.7);
|
|
1010
|
+
bowtie.lineTo(0, 0);
|
|
1011
|
+
bowtie.lineTo(-1, .7);
|
|
1012
|
+
bowtie.closePath();
|
|
1013
|
+
bowtie.moveTo(1, -.7);
|
|
1014
|
+
bowtie.lineTo(0, 0);
|
|
1015
|
+
bowtie.lineTo(1, .7);
|
|
1016
|
+
bowtie.closePath();
|
|
1017
|
+
const circle = new Path2D();
|
|
1018
|
+
circle.ellipse(0, 0, .6, 1, 0, 0, TWO_PI$1);
|
|
1019
|
+
const crescent = new Path2D();
|
|
1020
|
+
crescent.arc(0, 0, 1, 0, TWO_PI$1, false);
|
|
1021
|
+
crescent.arc(.45, 0, .9, 0, TWO_PI$1, true);
|
|
1022
|
+
const diamond = new Path2D();
|
|
1023
|
+
diamond.moveTo(0, -1);
|
|
1024
|
+
diamond.lineTo(.6, 0);
|
|
1025
|
+
diamond.lineTo(0, 1);
|
|
1026
|
+
diamond.lineTo(-.6, 0);
|
|
1027
|
+
diamond.closePath();
|
|
1028
|
+
const heart = new Path2D();
|
|
1029
|
+
heart.moveTo(0, 1);
|
|
1030
|
+
heart.bezierCurveTo(-.4, .55, -1, .1, -1, -.35);
|
|
1031
|
+
heart.bezierCurveTo(-1, -.8, -.5, -1, 0, -.6);
|
|
1032
|
+
heart.bezierCurveTo(.5, -1, 1, -.8, 1, -.35);
|
|
1033
|
+
heart.bezierCurveTo(1, .1, .4, .55, 0, 1);
|
|
1034
|
+
heart.closePath();
|
|
1035
|
+
const hexagon = new Path2D();
|
|
1036
|
+
for (let i = 0; i < 6; i++) {
|
|
1037
|
+
const angle = i * Math.PI / 3 - Math.PI / 2;
|
|
1038
|
+
if (i === 0) hexagon.moveTo(Math.cos(angle), Math.sin(angle));
|
|
1039
|
+
else hexagon.lineTo(Math.cos(angle), Math.sin(angle));
|
|
1040
|
+
}
|
|
1041
|
+
hexagon.closePath();
|
|
1042
|
+
const ribbon = new Path2D();
|
|
1043
|
+
ribbon.rect(-.2, -1, .4, 2);
|
|
1044
|
+
const ring = new Path2D();
|
|
1045
|
+
ring.arc(0, 0, 1, 0, TWO_PI$1, false);
|
|
1046
|
+
ring.arc(0, 0, .55, 0, TWO_PI$1, true);
|
|
1047
|
+
const square = new Path2D();
|
|
1048
|
+
square.rect(-.7, -.7, 1.4, 1.4);
|
|
1049
|
+
const star = new Path2D();
|
|
1050
|
+
for (let i = 0; i < 10; i++) {
|
|
1051
|
+
const r = i % 2 === 0 ? 1 : .42;
|
|
1052
|
+
const angle = i * Math.PI / 5 - Math.PI / 2;
|
|
1053
|
+
if (i === 0) star.moveTo(r * Math.cos(angle), r * Math.sin(angle));
|
|
1054
|
+
else star.lineTo(r * Math.cos(angle), r * Math.sin(angle));
|
|
1055
|
+
}
|
|
1056
|
+
star.closePath();
|
|
1057
|
+
const triangle = new Path2D();
|
|
1058
|
+
for (let i = 0; i < 3; i++) {
|
|
1059
|
+
const angle = i * 2 * Math.PI / 3 - Math.PI / 2;
|
|
1060
|
+
if (i === 0) triangle.moveTo(Math.cos(angle), Math.sin(angle));
|
|
1061
|
+
else triangle.lineTo(Math.cos(angle), Math.sin(angle));
|
|
1062
|
+
}
|
|
1063
|
+
triangle.closePath();
|
|
1064
|
+
return {
|
|
1065
|
+
bowtie,
|
|
1066
|
+
circle,
|
|
1067
|
+
crescent,
|
|
1068
|
+
diamond,
|
|
1069
|
+
heart,
|
|
1070
|
+
hexagon,
|
|
1071
|
+
ribbon,
|
|
1072
|
+
ring,
|
|
1073
|
+
square,
|
|
1074
|
+
star,
|
|
1075
|
+
triangle
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
let _shapePaths = null;
|
|
1079
|
+
const SHAPE_PATHS = new Proxy({}, { get(_, key) {
|
|
1080
|
+
return (_shapePaths ??= buildShapePaths())[key];
|
|
1081
|
+
} });
|
|
838
1082
|
//#endregion
|
|
839
1083
|
//#region src/confetti/layer.ts
|
|
840
1084
|
const TWO_PI = Math.PI * 2;
|
|
841
|
-
var
|
|
1085
|
+
var Confetti = class extends Effect {
|
|
842
1086
|
#scale;
|
|
843
1087
|
#particles = [];
|
|
844
1088
|
#width = 0;
|
|
@@ -852,7 +1096,7 @@ var ConfettiLayer = class extends SimulationLayer {
|
|
|
852
1096
|
this.#width = width;
|
|
853
1097
|
this.#height = height;
|
|
854
1098
|
}
|
|
855
|
-
|
|
1099
|
+
burst(config) {
|
|
856
1100
|
const width = this.#width;
|
|
857
1101
|
const height = this.#height;
|
|
858
1102
|
const resolved = {
|
|
@@ -987,28 +1231,28 @@ var ConfettiParticle = class {
|
|
|
987
1231
|
const scale = config.scale ?? 1;
|
|
988
1232
|
const spread = config.spread ?? 45;
|
|
989
1233
|
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 =
|
|
1234
|
+
const launchAngle = -(direction * Math.PI / 180) + .5 * spread * Math.PI / 180 - MULBERRY$20.next() * spread * Math.PI / 180;
|
|
1235
|
+
const speed = startVelocity * (.5 + MULBERRY$20.next());
|
|
1236
|
+
const rotAngle = MULBERRY$20.next() * Math.PI * 2;
|
|
993
1237
|
this.#colorStr = color;
|
|
994
1238
|
this.#gravity = (config.gravity ?? 1) * scale;
|
|
995
1239
|
this.#shape = shape;
|
|
996
|
-
this.#size = (5 +
|
|
1240
|
+
this.#size = (5 + MULBERRY$20.next() * 5) * scale;
|
|
997
1241
|
this.#totalTicks = config.ticks ?? 200;
|
|
998
1242
|
this.#x = position.x;
|
|
999
1243
|
this.#y = position.y;
|
|
1000
1244
|
this.#vx = Math.cos(launchAngle) * speed;
|
|
1001
1245
|
this.#vy = Math.sin(launchAngle) * speed;
|
|
1002
|
-
this.#decay = (config.decay ?? .9) - .05 +
|
|
1003
|
-
this.#flipAngle =
|
|
1004
|
-
this.#flipSpeed = .03 +
|
|
1246
|
+
this.#decay = (config.decay ?? .9) - .05 + MULBERRY$20.next() * .1;
|
|
1247
|
+
this.#flipAngle = MULBERRY$20.next() * Math.PI * 2;
|
|
1248
|
+
this.#flipSpeed = .03 + MULBERRY$20.next() * .05;
|
|
1005
1249
|
this.#rotAngle = rotAngle;
|
|
1006
1250
|
this.#rotCos = Math.cos(rotAngle);
|
|
1007
1251
|
this.#rotSin = Math.sin(rotAngle);
|
|
1008
|
-
this.#rotSpeed = (
|
|
1009
|
-
this.#swing =
|
|
1010
|
-
this.#swingAmp = .5 +
|
|
1011
|
-
this.#swingSpeed = .025 +
|
|
1252
|
+
this.#rotSpeed = (MULBERRY$20.next() - .5) * .06;
|
|
1253
|
+
this.#swing = MULBERRY$20.next() * Math.PI * 2;
|
|
1254
|
+
this.#swingAmp = .5 + MULBERRY$20.next() * 1.5;
|
|
1255
|
+
this.#swingSpeed = .025 + MULBERRY$20.next() * .035;
|
|
1012
1256
|
}
|
|
1013
1257
|
draw(ctx) {
|
|
1014
1258
|
ctx.save();
|
|
@@ -1034,20 +1278,10 @@ var ConfettiParticle = class {
|
|
|
1034
1278
|
}
|
|
1035
1279
|
};
|
|
1036
1280
|
//#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
|
-
};
|
|
1281
|
+
//#region src/confetti/index.ts
|
|
1282
|
+
function createConfetti(config) {
|
|
1283
|
+
return new Confetti(config);
|
|
1284
|
+
}
|
|
1051
1285
|
//#endregion
|
|
1052
1286
|
//#region src/donuts/consts.ts
|
|
1053
1287
|
const MULBERRY$19 = mulberry32(13);
|
|
@@ -1067,7 +1301,7 @@ const DEFAULT_CONFIG = {
|
|
|
1067
1301
|
};
|
|
1068
1302
|
//#endregion
|
|
1069
1303
|
//#region src/donuts/layer.ts
|
|
1070
|
-
var
|
|
1304
|
+
var Donuts = class extends Effect {
|
|
1071
1305
|
#background;
|
|
1072
1306
|
#collisionPadding;
|
|
1073
1307
|
#colors;
|
|
@@ -1128,6 +1362,12 @@ var DonutLayer = class extends SimulationLayer {
|
|
|
1128
1362
|
canvas.removeEventListener("mousemove", this.#onMouseMoveBound);
|
|
1129
1363
|
canvas.removeEventListener("mouseleave", this.#onMouseLeaveBound);
|
|
1130
1364
|
}
|
|
1365
|
+
configure(config) {
|
|
1366
|
+
if (config.mouseAvoidance !== void 0) this.#mouseAvoidance = config.mouseAvoidance;
|
|
1367
|
+
if (config.mouseAvoidanceRadius !== void 0) this.#mouseAvoidanceRadius = config.mouseAvoidanceRadius;
|
|
1368
|
+
if (config.mouseAvoidanceStrength !== void 0) this.#mouseAvoidanceStrength = config.mouseAvoidanceStrength;
|
|
1369
|
+
if (config.repulsionStrength !== void 0) this.#repulsionStrength = config.repulsionStrength;
|
|
1370
|
+
}
|
|
1131
1371
|
tick(dt, width, height) {
|
|
1132
1372
|
this.#width = width;
|
|
1133
1373
|
this.#height = height;
|
|
@@ -1140,17 +1380,17 @@ var DonutLayer = class extends SimulationLayer {
|
|
|
1140
1380
|
ctx.fillStyle = this.#background;
|
|
1141
1381
|
ctx.fillRect(0, 0, width, height);
|
|
1142
1382
|
for (const donut of this.#donuts) {
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
ctx.
|
|
1383
|
+
const cos = Math.cos(donut.angle);
|
|
1384
|
+
const sin = Math.sin(donut.angle);
|
|
1385
|
+
ctx.setTransform(cos, sin, -sin, cos, donut.x, donut.y);
|
|
1146
1386
|
ctx.beginPath();
|
|
1147
1387
|
ctx.arc(0, 0, donut.outerRadius, 0, Math.PI * 2);
|
|
1148
1388
|
ctx.arc(0, 0, donut.innerRadius, 0, Math.PI * 2, true);
|
|
1149
1389
|
ctx.closePath();
|
|
1150
1390
|
ctx.fillStyle = donut.color;
|
|
1151
1391
|
ctx.fill();
|
|
1152
|
-
ctx.restore();
|
|
1153
1392
|
}
|
|
1393
|
+
ctx.resetTransform();
|
|
1154
1394
|
}
|
|
1155
1395
|
#updateDonut(donut, dt) {
|
|
1156
1396
|
if (Math.sqrt(donut.vx * donut.vx + donut.vy * donut.vy) > donut.speed) {
|
|
@@ -1270,12 +1510,10 @@ var DonutLayer = class extends SimulationLayer {
|
|
|
1270
1510
|
}
|
|
1271
1511
|
};
|
|
1272
1512
|
//#endregion
|
|
1273
|
-
//#region src/donuts/
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
}
|
|
1278
|
-
};
|
|
1513
|
+
//#region src/donuts/index.ts
|
|
1514
|
+
function createDonuts(config) {
|
|
1515
|
+
return new Donuts(config);
|
|
1516
|
+
}
|
|
1279
1517
|
//#endregion
|
|
1280
1518
|
//#region src/fireflies/consts.ts
|
|
1281
1519
|
const MULBERRY$18 = mulberry32(13);
|
|
@@ -1284,7 +1522,7 @@ const MULBERRY$18 = mulberry32(13);
|
|
|
1284
1522
|
const SPRITE_SIZE$1 = 64;
|
|
1285
1523
|
const SPRITE_CENTER$1 = SPRITE_SIZE$1 / 2;
|
|
1286
1524
|
const SPRITE_RADIUS$1 = SPRITE_SIZE$1 / 2;
|
|
1287
|
-
var
|
|
1525
|
+
var Fireflies = class extends Effect {
|
|
1288
1526
|
#scale;
|
|
1289
1527
|
#size;
|
|
1290
1528
|
#speed;
|
|
@@ -1305,6 +1543,10 @@ var FireflyLayer = class extends SimulationLayer {
|
|
|
1305
1543
|
this.#sprite = this.#createSprite(r, g, b);
|
|
1306
1544
|
for (let i = 0; i < this.#maxCount; ++i) this.#fireflies.push(this.#createFirefly());
|
|
1307
1545
|
}
|
|
1546
|
+
configure(config) {
|
|
1547
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
1548
|
+
if (config.glowSpeed !== void 0) this.#glowSpeed = config.glowSpeed;
|
|
1549
|
+
}
|
|
1308
1550
|
tick(dt, _width, _height) {
|
|
1309
1551
|
this.#time += .02 * dt * this.#speed;
|
|
1310
1552
|
for (const firefly of this.#fireflies) {
|
|
@@ -1478,18 +1720,16 @@ var FireflyParticle = class {
|
|
|
1478
1720
|
}
|
|
1479
1721
|
};
|
|
1480
1722
|
//#endregion
|
|
1481
|
-
//#region src/fireflies/
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
}
|
|
1486
|
-
};
|
|
1723
|
+
//#region src/fireflies/index.ts
|
|
1724
|
+
function createFireflies(config) {
|
|
1725
|
+
return new Fireflies(config);
|
|
1726
|
+
}
|
|
1487
1727
|
//#endregion
|
|
1488
1728
|
//#region src/firepit/consts.ts
|
|
1489
1729
|
const MULBERRY$17 = mulberry32(13);
|
|
1490
1730
|
//#endregion
|
|
1491
1731
|
//#region src/firepit/layer.ts
|
|
1492
|
-
var
|
|
1732
|
+
var Firepit = class extends Effect {
|
|
1493
1733
|
#scale;
|
|
1494
1734
|
#flameWidth;
|
|
1495
1735
|
#flameHeight;
|
|
@@ -1515,6 +1755,11 @@ var FirepitLayer = class extends SimulationLayer {
|
|
|
1515
1755
|
height: this.#flameHeight * (.7 + MULBERRY$17.next() * .3)
|
|
1516
1756
|
});
|
|
1517
1757
|
}
|
|
1758
|
+
configure(config) {
|
|
1759
|
+
if (config.intensity !== void 0) this.#intensity = config.intensity;
|
|
1760
|
+
if (config.flameWidth !== void 0) this.#flameWidth = config.flameWidth;
|
|
1761
|
+
if (config.flameHeight !== void 0) this.#flameHeight = config.flameHeight;
|
|
1762
|
+
}
|
|
1518
1763
|
tick(dt, _width, _height) {
|
|
1519
1764
|
this.#time += .03 * dt * this.#intensity;
|
|
1520
1765
|
if (this.#embers.length < this.#maxEmbers && MULBERRY$17.next() < .3 * this.#intensity * dt) this.#embers.push(this.#createEmber());
|
|
@@ -1611,12 +1856,10 @@ var FirepitLayer = class extends SimulationLayer {
|
|
|
1611
1856
|
}
|
|
1612
1857
|
};
|
|
1613
1858
|
//#endregion
|
|
1614
|
-
//#region src/firepit/
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
}
|
|
1619
|
-
};
|
|
1859
|
+
//#region src/firepit/index.ts
|
|
1860
|
+
function createFirepit(config) {
|
|
1861
|
+
return new Firepit(config);
|
|
1862
|
+
}
|
|
1620
1863
|
//#endregion
|
|
1621
1864
|
//#region src/fireworks/consts.ts
|
|
1622
1865
|
const MULBERRY$16 = mulberry32(13);
|
|
@@ -1923,7 +2166,7 @@ var Explosion = class {
|
|
|
1923
2166
|
}
|
|
1924
2167
|
checkCrackle() {
|
|
1925
2168
|
if (this.#type !== "crackle" || this.#hasCrackled) return false;
|
|
1926
|
-
if (this.#alpha <=
|
|
2169
|
+
if (this.#alpha <= .4) {
|
|
1927
2170
|
this.#hasCrackled = true;
|
|
1928
2171
|
return true;
|
|
1929
2172
|
}
|
|
@@ -2032,6 +2275,158 @@ var Explosion = class {
|
|
|
2032
2275
|
}
|
|
2033
2276
|
};
|
|
2034
2277
|
//#endregion
|
|
2278
|
+
//#region src/fireworks/create-explosion.ts
|
|
2279
|
+
function between(rng, min, max) {
|
|
2280
|
+
return min + rng() * (max - min);
|
|
2281
|
+
}
|
|
2282
|
+
/**
|
|
2283
|
+
* Creates an array of {@link Explosion} particles for the given firework variant.
|
|
2284
|
+
* Use this to fire a fully formed explosion burst in your own render loop without
|
|
2285
|
+
* needing a {@link Fireworks} instance.
|
|
2286
|
+
*
|
|
2287
|
+
* @param variant - The firework variant to create.
|
|
2288
|
+
* @param position - The center position of the explosion in canvas pixels.
|
|
2289
|
+
* @param hue - Base hue in degrees (0–360).
|
|
2290
|
+
* @param options - Optional overrides for `lineWidth` (default `5`) and `scale` (default `1`).
|
|
2291
|
+
* @param rng - RNG function returning values in [0, 1). Defaults to `Math.random`.
|
|
2292
|
+
*/
|
|
2293
|
+
function createExplosion(variant, position, hue, options = {}, rng = Math.random) {
|
|
2294
|
+
const lineWidth = options.lineWidth ?? 5;
|
|
2295
|
+
const scale = options.scale ?? 1;
|
|
2296
|
+
const explosions = [];
|
|
2297
|
+
switch (variant) {
|
|
2298
|
+
case "saturn":
|
|
2299
|
+
createSaturn(explosions, position, hue, lineWidth, scale, rng);
|
|
2300
|
+
break;
|
|
2301
|
+
case "dahlia":
|
|
2302
|
+
createDahlia(explosions, position, hue, lineWidth, scale, rng);
|
|
2303
|
+
break;
|
|
2304
|
+
case "heart":
|
|
2305
|
+
createHeart(explosions, position, hue, lineWidth, scale, rng);
|
|
2306
|
+
break;
|
|
2307
|
+
case "spiral":
|
|
2308
|
+
createSpiral(explosions, position, hue, lineWidth, scale, rng);
|
|
2309
|
+
break;
|
|
2310
|
+
case "flower":
|
|
2311
|
+
createFlower(explosions, position, hue, lineWidth, scale, rng);
|
|
2312
|
+
break;
|
|
2313
|
+
case "concentric":
|
|
2314
|
+
createConcentric(explosions, position, hue, lineWidth, scale, rng);
|
|
2315
|
+
break;
|
|
2316
|
+
default: {
|
|
2317
|
+
const type = variant;
|
|
2318
|
+
const config = EXPLOSION_CONFIGS[type];
|
|
2319
|
+
const count = Math.floor(between(rng, config.particleCount[0], config.particleCount[1]));
|
|
2320
|
+
const effectiveHue = type === "brocade" ? between(rng, 35, 50) : hue;
|
|
2321
|
+
for (let i = 0; i < count; i++) {
|
|
2322
|
+
let angle;
|
|
2323
|
+
let speed;
|
|
2324
|
+
if (type === "ring") {
|
|
2325
|
+
angle = i / count * Math.PI * 2;
|
|
2326
|
+
speed = between(rng, config.speed[0], config.speed[1]) * .5 + config.speed[0] * .5;
|
|
2327
|
+
} else if (type === "palm" || type === "horsetail") {
|
|
2328
|
+
const spread = type === "horsetail" ? Math.PI / 8 : Math.PI / 5;
|
|
2329
|
+
angle = -Math.PI / 2 + between(rng, -spread, spread);
|
|
2330
|
+
}
|
|
2331
|
+
explosions.push(new Explosion(position, effectiveHue, lineWidth, type, scale, angle, speed));
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
return explosions;
|
|
2336
|
+
}
|
|
2337
|
+
function createSaturn(explosions, position, hue, lineWidth, scale, rng) {
|
|
2338
|
+
const velocity = between(rng, 4, 6);
|
|
2339
|
+
const shellCount = Math.floor(between(rng, 25, 35));
|
|
2340
|
+
for (let i = 0; i < shellCount; i++) {
|
|
2341
|
+
const rad = i / shellCount * Math.PI * 2;
|
|
2342
|
+
explosions.push(new Explosion(position, hue, lineWidth, "peony", scale, rad + between(rng, -.05, .05), velocity + between(rng, -.25, .25)));
|
|
2343
|
+
}
|
|
2344
|
+
const fillCount = Math.floor(between(rng, 40, 60));
|
|
2345
|
+
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)));
|
|
2346
|
+
const ringRotation = between(rng, 0, Math.PI * 2);
|
|
2347
|
+
const ringCount = Math.floor(between(rng, 40, 55));
|
|
2348
|
+
const ringVx = velocity * between(rng, 2, 3);
|
|
2349
|
+
const ringVy = velocity * .6;
|
|
2350
|
+
for (let i = 0; i < ringCount; i++) {
|
|
2351
|
+
const rad = i / ringCount * Math.PI * 2;
|
|
2352
|
+
const cx = Math.cos(rad) * ringVx + between(rng, -.25, .25);
|
|
2353
|
+
const cy = Math.sin(rad) * ringVy + between(rng, -.25, .25);
|
|
2354
|
+
const cosR = Math.cos(ringRotation);
|
|
2355
|
+
const sinR = Math.sin(ringRotation);
|
|
2356
|
+
const vx = cx * cosR - cy * sinR;
|
|
2357
|
+
const vy = cx * sinR + cy * cosR;
|
|
2358
|
+
const vz = Math.sin(rad) * velocity * .8;
|
|
2359
|
+
explosions.push(new Explosion(position, hue + 60, lineWidth, "ring", scale, Math.atan2(vy, vx), Math.sqrt(vx * vx + vy * vy), vz));
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
function createDahlia(explosions, position, hue, lineWidth, scale, rng) {
|
|
2363
|
+
const petalCount = Math.floor(between(rng, 6, 9));
|
|
2364
|
+
const particlesPerPetal = Math.floor(between(rng, 8, 12));
|
|
2365
|
+
for (let petal = 0; petal < petalCount; petal++) {
|
|
2366
|
+
const baseAngle = petal / petalCount * Math.PI * 2;
|
|
2367
|
+
const petalHue = hue + (petal % 2 === 0 ? 25 : -25);
|
|
2368
|
+
for (let i = 0; i < particlesPerPetal; i++) explosions.push(new Explosion(position, petalHue, lineWidth, "dahlia", scale, baseAngle + between(rng, -.3, .3)));
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
function createHeart(explosions, position, hue, lineWidth, scale, rng) {
|
|
2372
|
+
const velocity = between(rng, 3, 5);
|
|
2373
|
+
const count = Math.floor(between(rng, 60, 80));
|
|
2374
|
+
const rotation = between(rng, -.3, .3);
|
|
2375
|
+
const cosR = Math.cos(rotation);
|
|
2376
|
+
const sinR = Math.sin(rotation);
|
|
2377
|
+
for (let i = 0; i < count; i++) {
|
|
2378
|
+
const t = i / count * Math.PI * 2;
|
|
2379
|
+
const hx = 16 * Math.pow(Math.sin(t), 3);
|
|
2380
|
+
const hy = -(13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t));
|
|
2381
|
+
const s = velocity / 16;
|
|
2382
|
+
const vx = hx * s;
|
|
2383
|
+
const vy = hy * s;
|
|
2384
|
+
const rvx = vx * cosR - vy * sinR;
|
|
2385
|
+
const rvy = vx * sinR + vy * cosR;
|
|
2386
|
+
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))));
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
function createSpiral(explosions, position, hue, lineWidth, scale, rng) {
|
|
2390
|
+
const arms = Math.floor(between(rng, 3, 5));
|
|
2391
|
+
const particlesPerArm = Math.floor(between(rng, 15, 20));
|
|
2392
|
+
const twist = between(rng, 2, 3.5);
|
|
2393
|
+
const baseRotation = between(rng, 0, Math.PI * 2);
|
|
2394
|
+
for (let arm = 0; arm < arms; arm++) {
|
|
2395
|
+
const baseAngle = baseRotation + arm / arms * Math.PI * 2;
|
|
2396
|
+
const armHue = hue + arm * (360 / arms / 3);
|
|
2397
|
+
for (let i = 0; i < particlesPerArm; i++) {
|
|
2398
|
+
const progress = i / particlesPerArm;
|
|
2399
|
+
explosions.push(new Explosion(position, armHue, lineWidth, "spiral", scale, baseAngle + progress * twist, 2 + progress * 8 + between(rng, -.3, .3)));
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
function createFlower(explosions, position, hue, lineWidth, scale, rng) {
|
|
2404
|
+
const velocity = between(rng, 4, 7);
|
|
2405
|
+
const count = Math.floor(between(rng, 70, 90));
|
|
2406
|
+
const petals = Math.floor(between(rng, 2, 4));
|
|
2407
|
+
const rotation = between(rng, 0, Math.PI * 2);
|
|
2408
|
+
for (let i = 0; i < count; i++) {
|
|
2409
|
+
const t = i / count * Math.PI * 2;
|
|
2410
|
+
const speed = velocity * Math.abs(Math.cos(petals * t));
|
|
2411
|
+
if (speed < .3) continue;
|
|
2412
|
+
explosions.push(new Explosion(position, hue + between(rng, -15, 15), lineWidth, "flower", scale, t + rotation, speed + between(rng, -.2, .2)));
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
function createConcentric(explosions, position, hue, lineWidth, scale, rng) {
|
|
2416
|
+
const outerCount = Math.floor(between(rng, 35, 50));
|
|
2417
|
+
const outerSpeed = between(rng, 7, 10);
|
|
2418
|
+
for (let i = 0; i < outerCount; i++) {
|
|
2419
|
+
const angle = i / outerCount * Math.PI * 2;
|
|
2420
|
+
explosions.push(new Explosion(position, hue, lineWidth, "ring", scale, angle + between(rng, -.05, .05), outerSpeed + between(rng, -.25, .25)));
|
|
2421
|
+
}
|
|
2422
|
+
const innerCount = Math.floor(between(rng, 25, 35));
|
|
2423
|
+
const innerSpeed = between(rng, 3, 5);
|
|
2424
|
+
for (let i = 0; i < innerCount; i++) {
|
|
2425
|
+
const angle = i / innerCount * Math.PI * 2;
|
|
2426
|
+
explosions.push(new Explosion(position, hue + 120, lineWidth, "ring", scale, angle + between(rng, -.05, .05), innerSpeed + between(rng, -.25, .25)));
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
//#endregion
|
|
2035
2430
|
//#region src/distance.ts
|
|
2036
2431
|
function distance(a, b) {
|
|
2037
2432
|
let x = a.x - b.x;
|
|
@@ -2047,7 +2442,7 @@ var Spark = class {
|
|
|
2047
2442
|
#size;
|
|
2048
2443
|
#decay;
|
|
2049
2444
|
#friction = .94;
|
|
2050
|
-
#gravity = .
|
|
2445
|
+
#gravity = .3;
|
|
2051
2446
|
#alpha = 1;
|
|
2052
2447
|
get isDead() {
|
|
2053
2448
|
return this.#alpha <= 0;
|
|
@@ -2062,7 +2457,7 @@ var Spark = class {
|
|
|
2062
2457
|
this.#decay = MULBERRY$16.nextBetween(.03, .08);
|
|
2063
2458
|
this.#velocity = {
|
|
2064
2459
|
x: velocityX + MULBERRY$16.nextBetween(-1.5, 1.5),
|
|
2065
|
-
y: velocityY + MULBERRY$16.nextBetween(-2,
|
|
2460
|
+
y: velocityY + MULBERRY$16.nextBetween(-2, 2)
|
|
2066
2461
|
};
|
|
2067
2462
|
}
|
|
2068
2463
|
draw(ctx) {
|
|
@@ -2175,7 +2570,7 @@ var Firework = class extends EventTarget {
|
|
|
2175
2570
|
};
|
|
2176
2571
|
//#endregion
|
|
2177
2572
|
//#region src/fireworks/layer.ts
|
|
2178
|
-
var
|
|
2573
|
+
var Fireworks = class extends Effect {
|
|
2179
2574
|
#explosions = [];
|
|
2180
2575
|
#fireworks = [];
|
|
2181
2576
|
#sparks = [];
|
|
@@ -2183,6 +2578,7 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2183
2578
|
#spawnTimer = 0;
|
|
2184
2579
|
#positionRandom = MULBERRY$16.fork();
|
|
2185
2580
|
#autoSpawn;
|
|
2581
|
+
#variants;
|
|
2186
2582
|
#baseSize;
|
|
2187
2583
|
#scale;
|
|
2188
2584
|
#tailWidth;
|
|
@@ -2192,6 +2588,7 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2192
2588
|
super();
|
|
2193
2589
|
const scale = config.scale ?? 1;
|
|
2194
2590
|
this.#autoSpawn = config.autoSpawn ?? true;
|
|
2591
|
+
this.#variants = config.variants?.length ? [...config.variants] : [...FIREWORK_VARIANTS];
|
|
2195
2592
|
this.#baseSize = 5 * scale;
|
|
2196
2593
|
this.#scale = scale;
|
|
2197
2594
|
this.#tailWidth = 2 * scale;
|
|
@@ -2200,13 +2597,18 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2200
2597
|
this.#width = width;
|
|
2201
2598
|
this.#height = height;
|
|
2202
2599
|
}
|
|
2203
|
-
|
|
2600
|
+
launch(variant, position) {
|
|
2204
2601
|
const pos = position ?? {
|
|
2205
2602
|
x: this.#width / 2,
|
|
2206
2603
|
y: this.#height * .4
|
|
2207
2604
|
};
|
|
2208
2605
|
this.#hue = MULBERRY$16.nextBetween(0, 360);
|
|
2209
|
-
this.#
|
|
2606
|
+
this.#spawnExplosion(pos, this.#hue, variant);
|
|
2607
|
+
}
|
|
2608
|
+
configure(config) {
|
|
2609
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
2610
|
+
if (config.autoSpawn !== void 0) this.#autoSpawn = config.autoSpawn;
|
|
2611
|
+
if (Array.isArray(config.variants) && config.variants.length > 0) this.#variants = [...config.variants];
|
|
2210
2612
|
}
|
|
2211
2613
|
tick(dt, width, height) {
|
|
2212
2614
|
this.#width = width;
|
|
@@ -2223,7 +2625,8 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2223
2625
|
}
|
|
2224
2626
|
for (const firework of this.#fireworks) {
|
|
2225
2627
|
firework.tick(dt);
|
|
2226
|
-
|
|
2628
|
+
const collected = firework.collectSparks();
|
|
2629
|
+
for (let i = 0; i < collected.length; i++) this.#sparks.push(collected[i]);
|
|
2227
2630
|
}
|
|
2228
2631
|
for (const explosion of this.#explosions) explosion.tick(dt);
|
|
2229
2632
|
for (const spark of this.#sparks) spark.tick(dt);
|
|
@@ -2234,12 +2637,20 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2234
2637
|
const angle = explosion.angle + Math.PI / 2 * i + Math.PI / 4;
|
|
2235
2638
|
newExplosions.push(new Explosion(explosion.position, explosion.hue, this.#baseSize * .6, "peony", this.#scale, angle, MULBERRY$16.nextBetween(3, 6)));
|
|
2236
2639
|
}
|
|
2237
|
-
if (explosion.checkCrackle()) for (let j = 0; j <
|
|
2640
|
+
if (explosion.checkCrackle()) for (let j = 0; j < 14; j++) {
|
|
2641
|
+
const angle = MULBERRY$16.nextBetween(0, Math.PI * 2);
|
|
2642
|
+
const speed = MULBERRY$16.nextBetween(3, 8);
|
|
2643
|
+
newSparks.push(new Spark(explosion.position, explosion.hue + MULBERRY$16.nextBetween(-30, 30), Math.cos(angle) * speed, Math.sin(angle) * speed));
|
|
2644
|
+
}
|
|
2238
2645
|
}
|
|
2239
2646
|
this.#explosions.push(...newExplosions);
|
|
2240
2647
|
this.#sparks.push(...newSparks);
|
|
2241
|
-
|
|
2242
|
-
|
|
2648
|
+
let aliveExplosions = 0;
|
|
2649
|
+
for (let i = 0; i < this.#explosions.length; i++) if (!this.#explosions[i].isDead) this.#explosions[aliveExplosions++] = this.#explosions[i];
|
|
2650
|
+
this.#explosions.length = aliveExplosions;
|
|
2651
|
+
let aliveSparks = 0;
|
|
2652
|
+
for (let i = 0; i < this.#sparks.length; i++) if (!this.#sparks[i].isDead) this.#sparks[aliveSparks++] = this.#sparks[i];
|
|
2653
|
+
this.#sparks.length = aliveSparks;
|
|
2243
2654
|
}
|
|
2244
2655
|
draw(ctx, width, height) {
|
|
2245
2656
|
if (ctx.canvas.width !== width || ctx.canvas.height !== height) {
|
|
@@ -2252,153 +2663,13 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2252
2663
|
for (const firework of this.#fireworks) firework.draw(ctx);
|
|
2253
2664
|
ctx.globalCompositeOperation = "source-over";
|
|
2254
2665
|
}
|
|
2255
|
-
#
|
|
2666
|
+
#spawnExplosion(position, hue, variant) {
|
|
2256
2667
|
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
|
-
}
|
|
2668
|
+
const rng = () => MULBERRY$16.nextBetween(0, 1);
|
|
2669
|
+
this.#explosions.push(...createExplosion(selected, position, hue, {
|
|
2670
|
+
lineWidth: this.#baseSize,
|
|
2671
|
+
scale: this.#scale
|
|
2672
|
+
}, rng));
|
|
2402
2673
|
}
|
|
2403
2674
|
#createFirework(position) {
|
|
2404
2675
|
const hue = this.#hue;
|
|
@@ -2413,43 +2684,20 @@ var FireworkLayer = class extends SimulationLayer {
|
|
|
2413
2684
|
}, hue, this.#tailWidth, this.#baseSize);
|
|
2414
2685
|
firework.addEventListener("remove", () => {
|
|
2415
2686
|
this.#fireworks.splice(this.#fireworks.indexOf(firework), 1);
|
|
2416
|
-
this.#
|
|
2687
|
+
this.#spawnExplosion(firework.position, hue);
|
|
2417
2688
|
}, { once: true });
|
|
2418
2689
|
this.#fireworks.push(firework);
|
|
2419
2690
|
}
|
|
2420
2691
|
#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";
|
|
2692
|
+
const index = Math.floor(MULBERRY$16.nextBetween(0, this.#variants.length));
|
|
2693
|
+
return this.#variants[index];
|
|
2438
2694
|
}
|
|
2439
2695
|
};
|
|
2440
2696
|
//#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
|
-
};
|
|
2697
|
+
//#region src/fireworks/index.ts
|
|
2698
|
+
function createFireworks(config) {
|
|
2699
|
+
return new Fireworks(config);
|
|
2700
|
+
}
|
|
2453
2701
|
//#endregion
|
|
2454
2702
|
//#region src/glitter/consts.ts
|
|
2455
2703
|
const MULBERRY$15 = mulberry32(13);
|
|
@@ -2464,7 +2712,7 @@ const GLITTER_COLORS = [
|
|
|
2464
2712
|
];
|
|
2465
2713
|
//#endregion
|
|
2466
2714
|
//#region src/glitter/layer.ts
|
|
2467
|
-
var
|
|
2715
|
+
var Glitter = class extends Effect {
|
|
2468
2716
|
#scale;
|
|
2469
2717
|
#size;
|
|
2470
2718
|
#speed;
|
|
@@ -2487,6 +2735,10 @@ var GlitterLayer = class extends SimulationLayer {
|
|
|
2487
2735
|
if (innerWidth < 991) this.#maxCount = Math.floor(this.#maxCount / 2);
|
|
2488
2736
|
for (let i = 0; i < this.#maxCount; ++i) this.#falling.push(this.#createFallingPiece(true));
|
|
2489
2737
|
}
|
|
2738
|
+
configure(config) {
|
|
2739
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
2740
|
+
if (config.groundLevel !== void 0) this.#groundLevel = config.groundLevel;
|
|
2741
|
+
}
|
|
2490
2742
|
tick(dt, _width, _height) {
|
|
2491
2743
|
this.#time += .03 * dt;
|
|
2492
2744
|
let alive = 0;
|
|
@@ -2586,12 +2838,10 @@ var GlitterLayer = class extends SimulationLayer {
|
|
|
2586
2838
|
}
|
|
2587
2839
|
};
|
|
2588
2840
|
//#endregion
|
|
2589
|
-
//#region src/glitter/
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
}
|
|
2594
|
-
};
|
|
2841
|
+
//#region src/glitter/index.ts
|
|
2842
|
+
function createGlitter(config) {
|
|
2843
|
+
return new Glitter(config);
|
|
2844
|
+
}
|
|
2595
2845
|
//#endregion
|
|
2596
2846
|
//#region src/lanterns/consts.ts
|
|
2597
2847
|
const MULBERRY$14 = mulberry32(13);
|
|
@@ -2606,7 +2856,7 @@ const LANTERN_COLORS = [
|
|
|
2606
2856
|
];
|
|
2607
2857
|
//#endregion
|
|
2608
2858
|
//#region src/lanterns/layer.ts
|
|
2609
|
-
var
|
|
2859
|
+
var Lanterns = class extends Effect {
|
|
2610
2860
|
#scale;
|
|
2611
2861
|
#speed;
|
|
2612
2862
|
#size;
|
|
@@ -2614,6 +2864,8 @@ var LanternLayer = class extends SimulationLayer {
|
|
|
2614
2864
|
#maxCount;
|
|
2615
2865
|
#time = 0;
|
|
2616
2866
|
#lanterns = [];
|
|
2867
|
+
#sortedLanterns = [];
|
|
2868
|
+
#sortDirty = true;
|
|
2617
2869
|
constructor(config = {}) {
|
|
2618
2870
|
super();
|
|
2619
2871
|
this.#scale = config.scale ?? 1;
|
|
@@ -2624,6 +2876,9 @@ var LanternLayer = class extends SimulationLayer {
|
|
|
2624
2876
|
if (innerWidth < 991) this.#maxCount = Math.floor(this.#maxCount / 2);
|
|
2625
2877
|
for (let i = 0; i < this.#maxCount; ++i) this.#lanterns.push(this.#createLantern(true));
|
|
2626
2878
|
}
|
|
2879
|
+
configure(config) {
|
|
2880
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
2881
|
+
}
|
|
2627
2882
|
tick(dt, width, height) {
|
|
2628
2883
|
this.#time += .02 * dt * this.#speed;
|
|
2629
2884
|
for (let i = 0; i < this.#lanterns.length; i++) {
|
|
@@ -2631,11 +2886,18 @@ var LanternLayer = class extends SimulationLayer {
|
|
|
2631
2886
|
lantern.y -= lantern.vy * this.#speed * dt / (height * 1.5);
|
|
2632
2887
|
const sway = Math.sin(this.#time * lantern.swaySpeed + lantern.swayPhase) * lantern.swayAmplitude;
|
|
2633
2888
|
lantern.x += sway * dt / (width * 8);
|
|
2634
|
-
if (lantern.y < -.15)
|
|
2889
|
+
if (lantern.y < -.15) {
|
|
2890
|
+
this.#lanterns[i] = this.#createLantern(false);
|
|
2891
|
+
this.#sortDirty = true;
|
|
2892
|
+
}
|
|
2635
2893
|
}
|
|
2636
2894
|
}
|
|
2637
2895
|
draw(ctx, width, height) {
|
|
2638
|
-
|
|
2896
|
+
if (this.#sortDirty) {
|
|
2897
|
+
this.#sortedLanterns = [...this.#lanterns].sort((a, b) => a.size - b.size);
|
|
2898
|
+
this.#sortDirty = false;
|
|
2899
|
+
}
|
|
2900
|
+
const sorted = this.#sortedLanterns;
|
|
2639
2901
|
for (const lantern of sorted) {
|
|
2640
2902
|
const px = lantern.x * width;
|
|
2641
2903
|
const py = lantern.y * height;
|
|
@@ -2653,221 +2915,79 @@ var LanternLayer = class extends SimulationLayer {
|
|
|
2653
2915
|
ctx.beginPath();
|
|
2654
2916
|
ctx.arc(px, py, glowRadius, 0, Math.PI * 2);
|
|
2655
2917
|
ctx.fill();
|
|
2656
|
-
ctx.
|
|
2657
|
-
ctx.translate(px, py);
|
|
2918
|
+
ctx.setTransform(1, 0, 0, 1, px, py);
|
|
2658
2919
|
const bodyW = size * .8;
|
|
2659
2920
|
const bodyH = size;
|
|
2660
2921
|
const topW = bodyW * .6;
|
|
2661
|
-
ctx.beginPath();
|
|
2662
|
-
ctx.moveTo(-topW, -bodyH * .5);
|
|
2663
|
-
ctx.quadraticCurveTo(-bodyW, 0, -bodyW * .7, bodyH * .5);
|
|
2664
|
-
ctx.lineTo(bodyW * .7, bodyH * .5);
|
|
2665
|
-
ctx.quadraticCurveTo(bodyW, 0, topW, -bodyH * .5);
|
|
2666
|
-
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;
|
|
2922
|
+
ctx.beginPath();
|
|
2923
|
+
ctx.moveTo(-topW, -bodyH * .5);
|
|
2924
|
+
ctx.quadraticCurveTo(-bodyW, 0, -bodyW * .7, bodyH * .5);
|
|
2925
|
+
ctx.lineTo(bodyW * .7, bodyH * .5);
|
|
2926
|
+
ctx.quadraticCurveTo(bodyW, 0, topW, -bodyH * .5);
|
|
2927
|
+
ctx.closePath();
|
|
2928
|
+
const bodyGradient = ctx.createLinearGradient(0, -bodyH * .5, 0, bodyH * .5);
|
|
2929
|
+
bodyGradient.addColorStop(0, `rgba(${Math.min(255, r + 60)}, ${Math.min(255, g + 60)}, ${Math.min(255, b + 30)}, ${alpha * .9})`);
|
|
2930
|
+
bodyGradient.addColorStop(.5, `rgba(${r}, ${g}, ${b}, ${alpha * .85})`);
|
|
2931
|
+
bodyGradient.addColorStop(1, `rgba(${Math.max(0, r - 30)}, ${Math.max(0, g - 30)}, ${Math.max(0, b - 20)}, ${alpha * .8})`);
|
|
2932
|
+
ctx.fillStyle = bodyGradient;
|
|
2933
|
+
ctx.fill();
|
|
2934
|
+
ctx.beginPath();
|
|
2935
|
+
ctx.moveTo(-topW * .7, -bodyH * .55);
|
|
2936
|
+
ctx.lineTo(topW * .7, -bodyH * .55);
|
|
2937
|
+
ctx.lineWidth = size * .06;
|
|
2938
|
+
ctx.strokeStyle = `rgba(${Math.max(0, r - 40)}, ${Math.max(0, g - 40)}, ${Math.max(0, b - 40)}, ${alpha * .7})`;
|
|
2939
|
+
ctx.stroke();
|
|
2940
|
+
const flameH = bodyH * .3;
|
|
2941
|
+
const flameW = bodyW * .15;
|
|
2942
|
+
const flameFlicker = Math.sin(this.#time * 8 + lantern.glowPhase) * flameW * .3;
|
|
2943
|
+
const flameGradient = ctx.createRadialGradient(flameFlicker, -flameH * .1, 0, flameFlicker, -flameH * .1, flameH);
|
|
2944
|
+
flameGradient.addColorStop(0, `rgba(255, 255, 200, ${alpha * .95})`);
|
|
2945
|
+
flameGradient.addColorStop(.3, `rgba(255, 200, 80, ${alpha * .7})`);
|
|
2946
|
+
flameGradient.addColorStop(.7, `rgba(255, 140, 40, ${alpha * .3})`);
|
|
2947
|
+
flameGradient.addColorStop(1, `rgba(255, 100, 20, 0)`);
|
|
2948
|
+
ctx.beginPath();
|
|
2949
|
+
ctx.moveTo(-flameW + flameFlicker, flameH * .2);
|
|
2950
|
+
ctx.quadraticCurveTo(-flameW * .5 + flameFlicker, -flameH * .3, flameFlicker, -flameH);
|
|
2951
|
+
ctx.quadraticCurveTo(flameW * .5 + flameFlicker, -flameH * .3, flameW + flameFlicker, flameH * .2);
|
|
2952
|
+
ctx.closePath();
|
|
2953
|
+
ctx.fillStyle = flameGradient;
|
|
2954
|
+
ctx.fill();
|
|
2955
|
+
const stringLen = size * .6;
|
|
2956
|
+
const stringDrift = Math.sin(this.#time * 1.5 + lantern.swayPhase) * size * .1;
|
|
2957
|
+
ctx.beginPath();
|
|
2958
|
+
ctx.moveTo(0, bodyH * .5);
|
|
2959
|
+
ctx.quadraticCurveTo(stringDrift, bodyH * .5 + stringLen * .5, -stringDrift * .5, bodyH * .5 + stringLen);
|
|
2960
|
+
ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${alpha * .4})`;
|
|
2961
|
+
ctx.lineWidth = size * .04;
|
|
2962
|
+
ctx.stroke();
|
|
2963
|
+
ctx.resetTransform();
|
|
2857
2964
|
}
|
|
2858
|
-
for (const layer of this.#layers) layer.onResize(this.width, this.height);
|
|
2859
2965
|
}
|
|
2860
|
-
#
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2966
|
+
#createLantern(initialSpread) {
|
|
2967
|
+
const colorIndex = Math.floor(MULBERRY$14.next() * this.#colorRGBs.length);
|
|
2968
|
+
const sizeVariation = .6 + MULBERRY$14.next() * .8;
|
|
2969
|
+
return {
|
|
2970
|
+
x: .05 + MULBERRY$14.next() * .9,
|
|
2971
|
+
y: initialSpread ? MULBERRY$14.next() * 1.3 : 1.15 + MULBERRY$14.next() * .2,
|
|
2972
|
+
vx: 0,
|
|
2973
|
+
vy: .2 + MULBERRY$14.next() * .6,
|
|
2974
|
+
size: this.#size * sizeVariation,
|
|
2975
|
+
glowPhase: MULBERRY$14.next() * Math.PI * 2,
|
|
2976
|
+
glowSpeed: .8 + MULBERRY$14.next() * 1.2,
|
|
2977
|
+
swayPhase: MULBERRY$14.next() * Math.PI * 2,
|
|
2978
|
+
swaySpeed: .4 + MULBERRY$14.next() * .8,
|
|
2979
|
+
swayAmplitude: .3 + MULBERRY$14.next() * .7,
|
|
2980
|
+
colorIndex,
|
|
2981
|
+
opacity: .7 + MULBERRY$14.next() * .3
|
|
2982
|
+
};
|
|
2868
2983
|
}
|
|
2869
2984
|
};
|
|
2870
2985
|
//#endregion
|
|
2986
|
+
//#region src/lanterns/index.ts
|
|
2987
|
+
function createLanterns(config) {
|
|
2988
|
+
return new Lanterns(config);
|
|
2989
|
+
}
|
|
2990
|
+
//#endregion
|
|
2871
2991
|
//#region src/leaves/consts.ts
|
|
2872
2992
|
const MULBERRY$13 = mulberry32(13);
|
|
2873
2993
|
const LEAF_COLORS = [
|
|
@@ -2884,7 +3004,7 @@ const LEAF_COLORS = [
|
|
|
2884
3004
|
];
|
|
2885
3005
|
//#endregion
|
|
2886
3006
|
//#region src/leaves/layer.ts
|
|
2887
|
-
var
|
|
3007
|
+
var Leaves = class extends Effect {
|
|
2888
3008
|
#scale;
|
|
2889
3009
|
#size;
|
|
2890
3010
|
#speed;
|
|
@@ -2910,6 +3030,10 @@ var LeafLayer = class extends SimulationLayer {
|
|
|
2910
3030
|
onResize(_width, height) {
|
|
2911
3031
|
this.#height = height;
|
|
2912
3032
|
}
|
|
3033
|
+
configure(config) {
|
|
3034
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
3035
|
+
if (config.wind !== void 0) this.#wind = config.wind;
|
|
3036
|
+
}
|
|
2913
3037
|
tick(dt, _width, height) {
|
|
2914
3038
|
this.#height = height;
|
|
2915
3039
|
const speedFactor = height / 540 / this.#speed;
|
|
@@ -2944,14 +3068,13 @@ var LeafLayer = class extends SimulationLayer {
|
|
|
2944
3068
|
const py = leaf.y * height;
|
|
2945
3069
|
const displaySize = leaf.size * leaf.depth;
|
|
2946
3070
|
const scaleX = Math.cos(leaf.flipAngle);
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
ctx.
|
|
2950
|
-
ctx.scale(scaleX, 1);
|
|
3071
|
+
const cos = Math.cos(leaf.rotation);
|
|
3072
|
+
const sin = Math.sin(leaf.rotation);
|
|
3073
|
+
ctx.setTransform(cos * scaleX, sin * scaleX, -sin, cos, px, py);
|
|
2951
3074
|
ctx.globalAlpha = .3 + leaf.depth * .7;
|
|
2952
3075
|
ctx.drawImage(this.#sprites[leaf.colorIndex % this.#sprites.length], -displaySize / 2, -displaySize / 2, displaySize, displaySize);
|
|
2953
|
-
ctx.restore();
|
|
2954
3076
|
}
|
|
3077
|
+
ctx.resetTransform();
|
|
2955
3078
|
ctx.globalAlpha = 1;
|
|
2956
3079
|
}
|
|
2957
3080
|
#createSprites() {
|
|
@@ -3080,12 +3203,10 @@ var LeafLayer = class extends SimulationLayer {
|
|
|
3080
3203
|
}
|
|
3081
3204
|
};
|
|
3082
3205
|
//#endregion
|
|
3083
|
-
//#region src/leaves/
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
}
|
|
3088
|
-
};
|
|
3206
|
+
//#region src/leaves/index.ts
|
|
3207
|
+
function createLeaves(config) {
|
|
3208
|
+
return new Leaves(config);
|
|
3209
|
+
}
|
|
3089
3210
|
//#endregion
|
|
3090
3211
|
//#region src/lightning/consts.ts
|
|
3091
3212
|
const MULBERRY$12 = mulberry32(13);
|
|
@@ -3233,7 +3354,7 @@ var LightningSystem = class {
|
|
|
3233
3354
|
};
|
|
3234
3355
|
//#endregion
|
|
3235
3356
|
//#region src/lightning/layer.ts
|
|
3236
|
-
var
|
|
3357
|
+
var Lightning = class extends Effect {
|
|
3237
3358
|
#system;
|
|
3238
3359
|
#enableFlash;
|
|
3239
3360
|
constructor(config = {}) {
|
|
@@ -3264,19 +3385,17 @@ var LightningLayer = class extends SimulationLayer {
|
|
|
3264
3385
|
}
|
|
3265
3386
|
};
|
|
3266
3387
|
//#endregion
|
|
3267
|
-
//#region src/lightning/
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
}
|
|
3272
|
-
};
|
|
3388
|
+
//#region src/lightning/index.ts
|
|
3389
|
+
function createLightning(config) {
|
|
3390
|
+
return new Lightning(config);
|
|
3391
|
+
}
|
|
3273
3392
|
//#endregion
|
|
3274
3393
|
//#region src/matrix/consts.ts
|
|
3275
3394
|
const MULBERRY$11 = mulberry32(13);
|
|
3276
3395
|
const MATRIX_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
3277
3396
|
//#endregion
|
|
3278
3397
|
//#region src/matrix/layer.ts
|
|
3279
|
-
var
|
|
3398
|
+
var Matrix = class extends Effect {
|
|
3280
3399
|
#scale;
|
|
3281
3400
|
#speed;
|
|
3282
3401
|
#fontSize;
|
|
@@ -3315,6 +3434,10 @@ var MatrixLayer = class extends SimulationLayer {
|
|
|
3315
3434
|
}
|
|
3316
3435
|
}
|
|
3317
3436
|
}
|
|
3437
|
+
configure(config) {
|
|
3438
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
3439
|
+
if (config.trailLength !== void 0) this.#trailLength = config.trailLength;
|
|
3440
|
+
}
|
|
3318
3441
|
tick(dt, width, height) {
|
|
3319
3442
|
this.#width = width;
|
|
3320
3443
|
this.#height = height;
|
|
@@ -3366,12 +3489,10 @@ var MatrixLayer = class extends SimulationLayer {
|
|
|
3366
3489
|
}
|
|
3367
3490
|
};
|
|
3368
3491
|
//#endregion
|
|
3369
|
-
//#region src/matrix/
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
}
|
|
3374
|
-
};
|
|
3492
|
+
//#region src/matrix/index.ts
|
|
3493
|
+
function createMatrix(config) {
|
|
3494
|
+
return new Matrix(config);
|
|
3495
|
+
}
|
|
3375
3496
|
//#endregion
|
|
3376
3497
|
//#region src/orbits/consts.ts
|
|
3377
3498
|
const MULBERRY$10 = mulberry32(13);
|
|
@@ -3386,7 +3507,7 @@ const ORBIT_COLORS = [
|
|
|
3386
3507
|
];
|
|
3387
3508
|
//#endregion
|
|
3388
3509
|
//#region src/orbits/layer.ts
|
|
3389
|
-
var
|
|
3510
|
+
var Orbits = class extends Effect {
|
|
3390
3511
|
#centerCount;
|
|
3391
3512
|
#orbitersPerCenter;
|
|
3392
3513
|
#speed;
|
|
@@ -3421,6 +3542,12 @@ var OrbitLayer = class extends SimulationLayer {
|
|
|
3421
3542
|
for (let ci = 0; ci < this.#centers.length; ci++) for (let oi = 0; oi < count; oi++) this.#orbiters.push(this.#createOrbiter(ci));
|
|
3422
3543
|
}
|
|
3423
3544
|
}
|
|
3545
|
+
configure(config) {
|
|
3546
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
3547
|
+
if (config.trailLength !== void 0) this.#trailLength = config.trailLength;
|
|
3548
|
+
if (config.showCenters !== void 0) this.#showCenters = config.showCenters;
|
|
3549
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
3550
|
+
}
|
|
3424
3551
|
tick(dt, width, height) {
|
|
3425
3552
|
this.#time += .01 * dt * this.#speed;
|
|
3426
3553
|
for (const orbiter of this.#orbiters) {
|
|
@@ -3437,11 +3564,20 @@ var OrbitLayer = class extends SimulationLayer {
|
|
|
3437
3564
|
const rotatedY = localX * Math.sin(orbiter.tilt * .3) + localY * Math.cos(orbiter.tilt * .3);
|
|
3438
3565
|
const px = cx + rotatedX;
|
|
3439
3566
|
const py = cy + rotatedY;
|
|
3440
|
-
orbiter.trail
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3567
|
+
const trail = orbiter.trail;
|
|
3568
|
+
const maxLen = this.#trailLength;
|
|
3569
|
+
if (trail.length < maxLen) {
|
|
3570
|
+
trail.push({
|
|
3571
|
+
x: px,
|
|
3572
|
+
y: py
|
|
3573
|
+
});
|
|
3574
|
+
orbiter.trailHead = trail.length - 1;
|
|
3575
|
+
} else {
|
|
3576
|
+
const next = (orbiter.trailHead + 1) % maxLen;
|
|
3577
|
+
trail[next].x = px;
|
|
3578
|
+
trail[next].y = py;
|
|
3579
|
+
orbiter.trailHead = next;
|
|
3580
|
+
}
|
|
3445
3581
|
}
|
|
3446
3582
|
}
|
|
3447
3583
|
draw(ctx, width, height) {
|
|
@@ -3466,21 +3602,28 @@ var OrbitLayer = class extends SimulationLayer {
|
|
|
3466
3602
|
ctx.globalCompositeOperation = "lighter";
|
|
3467
3603
|
for (const orbiter of this.#orbiters) {
|
|
3468
3604
|
const [cr, cg, cb] = hexToRGB(orbiter.color);
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
const
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3605
|
+
const trail = orbiter.trail;
|
|
3606
|
+
const trailLen = trail.length;
|
|
3607
|
+
if (trailLen > 1) {
|
|
3608
|
+
const oldest = trailLen === this.#trailLength ? (orbiter.trailHead + 1) % trailLen : 0;
|
|
3609
|
+
for (let ti = 0; ti < trailLen - 1; ti++) {
|
|
3610
|
+
const progress = (ti + 1) / trailLen;
|
|
3611
|
+
const trailAlpha = progress * .5;
|
|
3612
|
+
const trailWidth = orbiter.size * progress * this.#scale;
|
|
3613
|
+
if (trailAlpha < .01) continue;
|
|
3614
|
+
const idx0 = (oldest + ti) % trailLen;
|
|
3615
|
+
const idx1 = (oldest + ti + 1) % trailLen;
|
|
3616
|
+
ctx.globalAlpha = trailAlpha;
|
|
3617
|
+
ctx.strokeStyle = `rgb(${cr}, ${cg}, ${cb})`;
|
|
3618
|
+
ctx.lineWidth = trailWidth;
|
|
3619
|
+
ctx.beginPath();
|
|
3620
|
+
ctx.moveTo(trail[idx0].x, trail[idx0].y);
|
|
3621
|
+
ctx.lineTo(trail[idx1].x, trail[idx1].y);
|
|
3622
|
+
ctx.stroke();
|
|
3623
|
+
}
|
|
3481
3624
|
}
|
|
3482
|
-
if (
|
|
3483
|
-
const head =
|
|
3625
|
+
if (trailLen > 0) {
|
|
3626
|
+
const head = trail[orbiter.trailHead];
|
|
3484
3627
|
const headSize = orbiter.size * this.#scale;
|
|
3485
3628
|
const glow = ctx.createRadialGradient(head.x, head.y, 0, head.x, head.y, headSize * 3);
|
|
3486
3629
|
glow.addColorStop(0, `rgba(${cr}, ${cg}, ${cb}, 0.9)`);
|
|
@@ -3512,23 +3655,22 @@ var OrbitLayer = class extends SimulationLayer {
|
|
|
3512
3655
|
tilt: MULBERRY$10.next() * Math.PI,
|
|
3513
3656
|
size: 1.5 + MULBERRY$10.next() * 2.5,
|
|
3514
3657
|
color: this.#colors[Math.floor(MULBERRY$10.next() * this.#colors.length)],
|
|
3515
|
-
trail: []
|
|
3658
|
+
trail: [],
|
|
3659
|
+
trailHead: 0
|
|
3516
3660
|
};
|
|
3517
3661
|
}
|
|
3518
3662
|
};
|
|
3519
3663
|
//#endregion
|
|
3520
|
-
//#region src/orbits/
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
}
|
|
3525
|
-
};
|
|
3664
|
+
//#region src/orbits/index.ts
|
|
3665
|
+
function createOrbits(config) {
|
|
3666
|
+
return new Orbits(config);
|
|
3667
|
+
}
|
|
3526
3668
|
//#endregion
|
|
3527
3669
|
//#region src/particles/consts.ts
|
|
3528
3670
|
const MULBERRY$9 = mulberry32(13);
|
|
3529
3671
|
//#endregion
|
|
3530
3672
|
//#region src/particles/layer.ts
|
|
3531
|
-
var
|
|
3673
|
+
var Particles = class extends Effect {
|
|
3532
3674
|
#scale;
|
|
3533
3675
|
#connectionDistance;
|
|
3534
3676
|
#lineWidth;
|
|
@@ -3575,6 +3717,16 @@ var ParticleLayer = class extends SimulationLayer {
|
|
|
3575
3717
|
this.#onMouseMoveBound = this.#onMouseMove.bind(this);
|
|
3576
3718
|
this.#onMouseLeaveBound = this.#onMouseLeave.bind(this);
|
|
3577
3719
|
}
|
|
3720
|
+
configure(config) {
|
|
3721
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
3722
|
+
if (config.connectionDistance !== void 0) this.#connectionDistance = config.connectionDistance * this.#scale;
|
|
3723
|
+
if (config.lineWidth !== void 0) this.#lineWidth = config.lineWidth;
|
|
3724
|
+
if (config.mouseMode !== void 0) this.#mouseMode = config.mouseMode;
|
|
3725
|
+
if (config.mouseRadius !== void 0) this.#mouseRadius = config.mouseRadius * this.#scale;
|
|
3726
|
+
if (config.mouseStrength !== void 0) this.#mouseStrength = config.mouseStrength;
|
|
3727
|
+
if (config.particleForces !== void 0) this.#particleForces = config.particleForces;
|
|
3728
|
+
if (config.glow !== void 0) this.#glow = config.glow;
|
|
3729
|
+
}
|
|
3578
3730
|
onResize(width, height) {
|
|
3579
3731
|
this.#width = width;
|
|
3580
3732
|
this.#height = height;
|
|
@@ -3757,12 +3909,10 @@ var ParticleLayer = class extends SimulationLayer {
|
|
|
3757
3909
|
}
|
|
3758
3910
|
};
|
|
3759
3911
|
//#endregion
|
|
3760
|
-
//#region src/particles/
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
}
|
|
3765
|
-
};
|
|
3912
|
+
//#region src/particles/index.ts
|
|
3913
|
+
function createParticles(config) {
|
|
3914
|
+
return new Particles(config);
|
|
3915
|
+
}
|
|
3766
3916
|
//#endregion
|
|
3767
3917
|
//#region src/petals/consts.ts
|
|
3768
3918
|
const MULBERRY$8 = mulberry32(13);
|
|
@@ -3777,7 +3927,7 @@ const PETAL_COLORS = [
|
|
|
3777
3927
|
];
|
|
3778
3928
|
//#endregion
|
|
3779
3929
|
//#region src/petals/layer.ts
|
|
3780
|
-
var
|
|
3930
|
+
var Petals = class extends Effect {
|
|
3781
3931
|
#scale;
|
|
3782
3932
|
#size;
|
|
3783
3933
|
#speed;
|
|
@@ -3799,6 +3949,10 @@ var PetalLayer = class extends SimulationLayer {
|
|
|
3799
3949
|
this.#sprites = this.#createSprites();
|
|
3800
3950
|
for (let i = 0; i < this.#maxCount; ++i) this.#petals.push(this.#createPetal(true));
|
|
3801
3951
|
}
|
|
3952
|
+
configure(config) {
|
|
3953
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
3954
|
+
if (config.wind !== void 0) this.#wind = config.wind;
|
|
3955
|
+
}
|
|
3802
3956
|
tick(dt, _width, height) {
|
|
3803
3957
|
const speedFactor = height / 540 / this.#speed;
|
|
3804
3958
|
this.#time += .012 * dt;
|
|
@@ -3829,14 +3983,13 @@ var PetalLayer = class extends SimulationLayer {
|
|
|
3829
3983
|
const py = petal.y * height;
|
|
3830
3984
|
const displaySize = petal.size * petal.depth;
|
|
3831
3985
|
const scaleX = Math.cos(petal.flipAngle);
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
ctx.
|
|
3835
|
-
ctx.scale(scaleX, 1);
|
|
3986
|
+
const cos = Math.cos(petal.rotation);
|
|
3987
|
+
const sin = Math.sin(petal.rotation);
|
|
3988
|
+
ctx.setTransform(cos * scaleX, sin * scaleX, -sin, cos, px, py);
|
|
3836
3989
|
ctx.globalAlpha = .4 + petal.depth * .6;
|
|
3837
3990
|
ctx.drawImage(this.#sprites[petal.colorIndex % this.#sprites.length], -displaySize / 2, -displaySize / 2, displaySize, displaySize);
|
|
3838
|
-
ctx.restore();
|
|
3839
3991
|
}
|
|
3992
|
+
ctx.resetTransform();
|
|
3840
3993
|
ctx.globalAlpha = 1;
|
|
3841
3994
|
}
|
|
3842
3995
|
#createSprites() {
|
|
@@ -3888,12 +4041,10 @@ var PetalLayer = class extends SimulationLayer {
|
|
|
3888
4041
|
}
|
|
3889
4042
|
};
|
|
3890
4043
|
//#endregion
|
|
3891
|
-
//#region src/petals/
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
}
|
|
3896
|
-
};
|
|
4044
|
+
//#region src/petals/index.ts
|
|
4045
|
+
function createPetals(config) {
|
|
4046
|
+
return new Petals(config);
|
|
4047
|
+
}
|
|
3897
4048
|
//#endregion
|
|
3898
4049
|
//#region src/plasma/layer.ts
|
|
3899
4050
|
const DEFAULT_PALETTE = [
|
|
@@ -3923,7 +4074,7 @@ const DEFAULT_PALETTE = [
|
|
|
3923
4074
|
b: 100
|
|
3924
4075
|
}
|
|
3925
4076
|
];
|
|
3926
|
-
var
|
|
4077
|
+
var Plasma = class extends Effect {
|
|
3927
4078
|
#speed;
|
|
3928
4079
|
#scale;
|
|
3929
4080
|
#resolution;
|
|
@@ -3939,6 +4090,10 @@ var PlasmaLayer = class extends SimulationLayer {
|
|
|
3939
4090
|
this.#resolution = config.resolution ?? 4;
|
|
3940
4091
|
this.#palette = config.palette ?? DEFAULT_PALETTE;
|
|
3941
4092
|
}
|
|
4093
|
+
configure(config) {
|
|
4094
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
4095
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
4096
|
+
}
|
|
3942
4097
|
tick(dt, _width, _height) {
|
|
3943
4098
|
this.#time += .02 * dt * this.#speed;
|
|
3944
4099
|
}
|
|
@@ -3983,12 +4138,10 @@ var PlasmaLayer = class extends SimulationLayer {
|
|
|
3983
4138
|
}
|
|
3984
4139
|
};
|
|
3985
4140
|
//#endregion
|
|
3986
|
-
//#region src/plasma/
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
}
|
|
3991
|
-
};
|
|
4141
|
+
//#region src/plasma/index.ts
|
|
4142
|
+
function createPlasma(config) {
|
|
4143
|
+
return new Plasma(config);
|
|
4144
|
+
}
|
|
3992
4145
|
//#endregion
|
|
3993
4146
|
//#region src/rain/consts.ts
|
|
3994
4147
|
const MULBERRY$7 = mulberry32(13);
|
|
@@ -4014,7 +4167,7 @@ const VARIANT_PRESETS = {
|
|
|
4014
4167
|
splashes: true
|
|
4015
4168
|
}
|
|
4016
4169
|
};
|
|
4017
|
-
var
|
|
4170
|
+
var Rain = class extends Effect {
|
|
4018
4171
|
#scale;
|
|
4019
4172
|
#speed;
|
|
4020
4173
|
#wind;
|
|
@@ -4042,6 +4195,11 @@ var RainLayer = class extends SimulationLayer {
|
|
|
4042
4195
|
if (innerWidth < 991) this.#maxDrops = Math.floor(this.#maxDrops / 2);
|
|
4043
4196
|
for (let i = 0; i < this.#maxDrops; ++i) this.#drops.push(this.#createDrop(true));
|
|
4044
4197
|
}
|
|
4198
|
+
configure(config) {
|
|
4199
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
4200
|
+
if (config.wind !== void 0) this.#wind = config.wind;
|
|
4201
|
+
if (config.splashes !== void 0) this.#enableSplashes = config.splashes;
|
|
4202
|
+
}
|
|
4045
4203
|
tick(dt, width, height) {
|
|
4046
4204
|
let aliveDrops = 0;
|
|
4047
4205
|
for (let i = 0; i < this.#drops.length; i++) {
|
|
@@ -4228,18 +4386,16 @@ var SplashParticle = class SplashParticle {
|
|
|
4228
4386
|
}
|
|
4229
4387
|
};
|
|
4230
4388
|
//#endregion
|
|
4231
|
-
//#region src/rain/
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
}
|
|
4236
|
-
};
|
|
4389
|
+
//#region src/rain/index.ts
|
|
4390
|
+
function createRain(config) {
|
|
4391
|
+
return new Rain(config);
|
|
4392
|
+
}
|
|
4237
4393
|
//#endregion
|
|
4238
4394
|
//#region src/sandstorm/consts.ts
|
|
4239
4395
|
const MULBERRY$6 = mulberry32(13);
|
|
4240
4396
|
//#endregion
|
|
4241
4397
|
//#region src/sandstorm/layer.ts
|
|
4242
|
-
var
|
|
4398
|
+
var Sandstorm = class extends Effect {
|
|
4243
4399
|
#scale;
|
|
4244
4400
|
#wind;
|
|
4245
4401
|
#turbulence;
|
|
@@ -4264,6 +4420,10 @@ var SandstormLayer = class extends SimulationLayer {
|
|
|
4264
4420
|
if (innerWidth < 991) this.#maxCount = Math.floor(this.#maxCount / 2);
|
|
4265
4421
|
for (let i = 0; i < this.#maxCount; ++i) this.#grains.push(this.#createGrain(true));
|
|
4266
4422
|
}
|
|
4423
|
+
configure(config) {
|
|
4424
|
+
if (config.wind !== void 0) this.#wind = config.wind;
|
|
4425
|
+
if (config.turbulence !== void 0) this.#turbulence = config.turbulence;
|
|
4426
|
+
}
|
|
4267
4427
|
tick(dt, width, height) {
|
|
4268
4428
|
this.#time += .02 * dt;
|
|
4269
4429
|
const gustX = Math.sin(this.#time * .3) * .5 + Math.sin(this.#time * .8 + 1) * .3 + Math.sin(this.#time * 2.1) * .2;
|
|
@@ -4338,12 +4498,165 @@ var SandstormLayer = class extends SimulationLayer {
|
|
|
4338
4498
|
}
|
|
4339
4499
|
};
|
|
4340
4500
|
//#endregion
|
|
4341
|
-
//#region src/sandstorm/
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4501
|
+
//#region src/sandstorm/index.ts
|
|
4502
|
+
function createSandstorm(config) {
|
|
4503
|
+
return new Sandstorm(config);
|
|
4504
|
+
}
|
|
4505
|
+
//#endregion
|
|
4506
|
+
//#region src/scene.ts
|
|
4507
|
+
/**
|
|
4508
|
+
* Internal canvas runner that drives all layers in a Scene.
|
|
4509
|
+
*/
|
|
4510
|
+
var SceneCanvas = class extends LimitedFrameRateCanvas {
|
|
4511
|
+
#layers;
|
|
4512
|
+
#contextOptions;
|
|
4513
|
+
#offscreen = null;
|
|
4514
|
+
#offscreenCtx = null;
|
|
4515
|
+
constructor(canvas, layers, frameRate, options) {
|
|
4516
|
+
super(canvas, frameRate, options);
|
|
4517
|
+
this.#layers = layers;
|
|
4518
|
+
this.#contextOptions = options;
|
|
4519
|
+
canvas.style.position = "absolute";
|
|
4520
|
+
canvas.style.top = "0";
|
|
4521
|
+
canvas.style.left = "0";
|
|
4522
|
+
canvas.style.height = "100%";
|
|
4523
|
+
canvas.style.width = "100%";
|
|
4524
|
+
}
|
|
4525
|
+
start() {
|
|
4526
|
+
for (const layer of this.#layers) layer.onMount(this.canvas);
|
|
4527
|
+
super.start();
|
|
4528
|
+
}
|
|
4529
|
+
destroy() {
|
|
4530
|
+
for (const layer of this.#layers) layer.onUnmount(this.canvas);
|
|
4531
|
+
super.destroy();
|
|
4532
|
+
}
|
|
4533
|
+
draw() {
|
|
4534
|
+
const dpr = this.dpr;
|
|
4535
|
+
this.canvas.height = this.height * dpr;
|
|
4536
|
+
this.canvas.width = this.width * dpr;
|
|
4537
|
+
const ctx = this.context;
|
|
4538
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
4539
|
+
ctx.clearRect(0, 0, this.width, this.height);
|
|
4540
|
+
for (const layer of this.#layers) if (layer.fade) {
|
|
4541
|
+
const offCtx = this.#getOffscreenCtx(this.width * dpr, this.height * dpr);
|
|
4542
|
+
offCtx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
4543
|
+
offCtx.clearRect(0, 0, this.width, this.height);
|
|
4544
|
+
layer.draw(offCtx, this.width, this.height);
|
|
4545
|
+
applyEdgeFade(offCtx, this.width, this.height, layer.fade);
|
|
4546
|
+
ctx.drawImage(this.#offscreen, 0, 0, this.width, this.height);
|
|
4547
|
+
} else {
|
|
4548
|
+
ctx.save();
|
|
4549
|
+
layer.draw(ctx, this.width, this.height);
|
|
4550
|
+
ctx.restore();
|
|
4551
|
+
}
|
|
4552
|
+
}
|
|
4553
|
+
tick() {
|
|
4554
|
+
const dt = (this.delta > 0 && this.delta < 200 ? this.delta / (1e3 / 60) : 1) * this.speed * LimitedFrameRateCanvas.globalSpeed;
|
|
4555
|
+
for (const layer of this.#layers) layer.tick(dt, this.width, this.height);
|
|
4556
|
+
}
|
|
4557
|
+
onResize() {
|
|
4558
|
+
super.onResize();
|
|
4559
|
+
if (this.#offscreen) {
|
|
4560
|
+
this.#offscreen.width = this.width * this.dpr;
|
|
4561
|
+
this.#offscreen.height = this.height * this.dpr;
|
|
4562
|
+
}
|
|
4563
|
+
for (const layer of this.#layers) layer.onResize(this.width, this.height);
|
|
4564
|
+
}
|
|
4565
|
+
#getOffscreenCtx(width, height) {
|
|
4566
|
+
if (!this.#offscreen) {
|
|
4567
|
+
this.#offscreen = document.createElement("canvas");
|
|
4568
|
+
this.#offscreen.width = width;
|
|
4569
|
+
this.#offscreen.height = height;
|
|
4570
|
+
this.#offscreenCtx = this.#offscreen.getContext("2d", this.#contextOptions);
|
|
4571
|
+
}
|
|
4572
|
+
return this.#offscreenCtx;
|
|
4573
|
+
}
|
|
4574
|
+
};
|
|
4575
|
+
/**
|
|
4576
|
+
* Composable canvas that renders multiple Effect layers in order (first = bottom, last = top).
|
|
4577
|
+
*
|
|
4578
|
+
* @example
|
|
4579
|
+
* const scene = new Scene()
|
|
4580
|
+
* .mount(canvas)
|
|
4581
|
+
* .layer(new Aurora({ bands: 5 }))
|
|
4582
|
+
* .layer(new Stars().withFade({ bottom: 0.4 }))
|
|
4583
|
+
* .start();
|
|
4584
|
+
*/
|
|
4585
|
+
var Scene = class {
|
|
4586
|
+
#layers = [];
|
|
4587
|
+
#frameRate;
|
|
4588
|
+
#defaultOptions;
|
|
4589
|
+
#runner = null;
|
|
4590
|
+
constructor(frameRate = 60, options = { colorSpace: "display-p3" }) {
|
|
4591
|
+
this.#frameRate = frameRate;
|
|
4592
|
+
this.#defaultOptions = options;
|
|
4593
|
+
}
|
|
4594
|
+
/**
|
|
4595
|
+
* Mount the scene to a canvas element or CSS selector.
|
|
4596
|
+
*/
|
|
4597
|
+
mount(canvas, options) {
|
|
4598
|
+
if (typeof canvas === "string") {
|
|
4599
|
+
const el = document.querySelector(canvas);
|
|
4600
|
+
if (!el) throw new Error(`Scene.mount(): no element found for selector "${canvas}".`);
|
|
4601
|
+
canvas = el;
|
|
4602
|
+
}
|
|
4603
|
+
this.#runner?.destroy();
|
|
4604
|
+
this.#runner = new SceneCanvas(canvas, this.#layers, this.#frameRate, options ?? this.#defaultOptions);
|
|
4605
|
+
return this;
|
|
4606
|
+
}
|
|
4607
|
+
/**
|
|
4608
|
+
* Add an effect layer. Layers are rendered in the order they are added.
|
|
4609
|
+
* If the scene is already running, the layer is mounted immediately.
|
|
4610
|
+
*/
|
|
4611
|
+
layer(effect) {
|
|
4612
|
+
this.#layers.push(effect);
|
|
4613
|
+
if (this.#runner?.isTicking) effect.onMount(this.#runner.canvas);
|
|
4614
|
+
return this;
|
|
4615
|
+
}
|
|
4616
|
+
/**
|
|
4617
|
+
* Start the render loop.
|
|
4618
|
+
*/
|
|
4619
|
+
start() {
|
|
4620
|
+
this.#runner?.start();
|
|
4621
|
+
return this;
|
|
4622
|
+
}
|
|
4623
|
+
/**
|
|
4624
|
+
* Pause rendering without destroying state. Use resume() to continue.
|
|
4625
|
+
*/
|
|
4626
|
+
pause() {
|
|
4627
|
+
this.#runner?.pause();
|
|
4628
|
+
return this;
|
|
4629
|
+
}
|
|
4630
|
+
/**
|
|
4631
|
+
* Resume rendering after pause().
|
|
4632
|
+
*/
|
|
4633
|
+
resume() {
|
|
4634
|
+
this.#runner?.resume();
|
|
4635
|
+
return this;
|
|
4636
|
+
}
|
|
4637
|
+
/**
|
|
4638
|
+
* Stop and destroy all layers.
|
|
4639
|
+
*/
|
|
4640
|
+
destroy() {
|
|
4641
|
+
this.#runner?.destroy();
|
|
4642
|
+
this.#runner = null;
|
|
4643
|
+
}
|
|
4644
|
+
get speed() {
|
|
4645
|
+
return this.#runner?.speed ?? 1;
|
|
4646
|
+
}
|
|
4647
|
+
set speed(value) {
|
|
4648
|
+
if (this.#runner) this.#runner.speed = value;
|
|
4649
|
+
}
|
|
4650
|
+
get isTicking() {
|
|
4651
|
+
return this.#runner?.isTicking ?? false;
|
|
4345
4652
|
}
|
|
4346
4653
|
};
|
|
4654
|
+
/**
|
|
4655
|
+
* Factory alternative to `new Scene()`. Call .mount() and .layer() on the returned instance.
|
|
4656
|
+
*/
|
|
4657
|
+
function createScene(frameRate, options) {
|
|
4658
|
+
return new Scene(frameRate, options);
|
|
4659
|
+
}
|
|
4347
4660
|
//#endregion
|
|
4348
4661
|
//#region src/shooting-stars/system.ts
|
|
4349
4662
|
var ShootingStarSystem = class {
|
|
@@ -4357,10 +4670,8 @@ var ShootingStarSystem = class {
|
|
|
4357
4670
|
#alphaRange;
|
|
4358
4671
|
#decayMin;
|
|
4359
4672
|
#decayRange;
|
|
4360
|
-
#verticalFade;
|
|
4361
4673
|
#rng;
|
|
4362
4674
|
#cooldown;
|
|
4363
|
-
#height = 0;
|
|
4364
4675
|
#stars = [];
|
|
4365
4676
|
constructor(config, rng) {
|
|
4366
4677
|
this.#interval = config.interval;
|
|
@@ -4377,12 +4688,10 @@ var ShootingStarSystem = class {
|
|
|
4377
4688
|
this.#alphaRange = config.alphaRange ?? .3;
|
|
4378
4689
|
this.#decayMin = config.decayMin ?? .008;
|
|
4379
4690
|
this.#decayRange = config.decayRange ?? .01;
|
|
4380
|
-
this.#verticalFade = config.verticalFade ?? null;
|
|
4381
4691
|
this.#rng = rng;
|
|
4382
4692
|
this.#cooldown = this.#interval[0] + this.#rng() * (this.#interval[1] - this.#interval[0]);
|
|
4383
4693
|
}
|
|
4384
4694
|
tick(dt, width, height) {
|
|
4385
|
-
this.#height = height;
|
|
4386
4695
|
this.#cooldown -= dt;
|
|
4387
4696
|
if (this.#cooldown <= 0) {
|
|
4388
4697
|
this.#stars.push(this.#create(width, height));
|
|
@@ -4391,17 +4700,24 @@ var ShootingStarSystem = class {
|
|
|
4391
4700
|
let alive = 0;
|
|
4392
4701
|
for (let i = 0; i < this.#stars.length; i++) {
|
|
4393
4702
|
const star = this.#stars[i];
|
|
4394
|
-
star.trail
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4703
|
+
const trail = star.trail;
|
|
4704
|
+
const maxLen = this.#trailLength;
|
|
4705
|
+
if (trail.length < maxLen) {
|
|
4706
|
+
trail.push({
|
|
4707
|
+
x: star.x,
|
|
4708
|
+
y: star.y
|
|
4709
|
+
});
|
|
4710
|
+
star.trailHead = trail.length - 1;
|
|
4711
|
+
} else {
|
|
4712
|
+
const next = (star.trailHead + 1) % maxLen;
|
|
4713
|
+
trail[next].x = star.x;
|
|
4714
|
+
trail[next].y = star.y;
|
|
4715
|
+
star.trailHead = next;
|
|
4716
|
+
}
|
|
4399
4717
|
star.x += star.vx * this.#speed * dt;
|
|
4400
4718
|
star.y += star.vy * this.#speed * dt;
|
|
4401
4719
|
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;
|
|
4720
|
+
if (star.alpha > 0 && star.x > -50 && star.x < width + 50 && star.y < height + 50) this.#stars[alive++] = star;
|
|
4405
4721
|
}
|
|
4406
4722
|
this.#stars.length = alive;
|
|
4407
4723
|
}
|
|
@@ -4409,23 +4725,22 @@ var ShootingStarSystem = class {
|
|
|
4409
4725
|
const [cr, cg, cb] = this.#color;
|
|
4410
4726
|
ctx.globalCompositeOperation = "lighter";
|
|
4411
4727
|
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;
|
|
4728
|
+
const trail = star.trail;
|
|
4729
|
+
const trailLen = trail.length;
|
|
4730
|
+
const oldest = trailLen === this.#trailLength ? (star.trailHead + 1) % trailLen : 0;
|
|
4731
|
+
for (let t = 0; t < trailLen; t++) {
|
|
4732
|
+
const progress = t / trailLen;
|
|
4733
|
+
const trailAlpha = star.alpha * progress * this.#trailAlphaFactor;
|
|
4420
4734
|
const trailSize = star.size * progress * this.#scale;
|
|
4421
4735
|
if (trailAlpha < .01) continue;
|
|
4736
|
+
const idx = (oldest + t) % trailLen;
|
|
4422
4737
|
ctx.globalAlpha = trailAlpha;
|
|
4423
4738
|
ctx.beginPath();
|
|
4424
|
-
ctx.arc(
|
|
4739
|
+
ctx.arc(trail[idx].x, trail[idx].y, trailSize, 0, Math.PI * 2);
|
|
4425
4740
|
ctx.fillStyle = `rgb(${cr}, ${cg}, ${cb})`;
|
|
4426
4741
|
ctx.fill();
|
|
4427
4742
|
}
|
|
4428
|
-
const alpha = star.alpha
|
|
4743
|
+
const alpha = star.alpha;
|
|
4429
4744
|
const headSize = star.size * 2 * this.#scale;
|
|
4430
4745
|
const glow = ctx.createRadialGradient(star.x, star.y, 0, star.x, star.y, headSize);
|
|
4431
4746
|
glow.addColorStop(0, `rgba(${cr}, ${cg}, ${cb}, ${alpha})`);
|
|
@@ -4453,7 +4768,8 @@ var ShootingStarSystem = class {
|
|
|
4453
4768
|
alpha: this.#alphaMin + this.#rng() * this.#alphaRange,
|
|
4454
4769
|
size: 1.5 + this.#rng() * 2,
|
|
4455
4770
|
decay: this.#decayMin + this.#rng() * this.#decayRange,
|
|
4456
|
-
trail: []
|
|
4771
|
+
trail: [],
|
|
4772
|
+
trailHead: 0
|
|
4457
4773
|
};
|
|
4458
4774
|
}
|
|
4459
4775
|
};
|
|
@@ -4465,7 +4781,7 @@ const MULBERRY$5 = mulberry32(13);
|
|
|
4465
4781
|
const SPRITE_SIZE = 64;
|
|
4466
4782
|
const SPRITE_CENTER = SPRITE_SIZE / 2;
|
|
4467
4783
|
const SPRITE_RADIUS = SPRITE_SIZE / 2;
|
|
4468
|
-
var
|
|
4784
|
+
var Snow = class extends Effect {
|
|
4469
4785
|
#scale;
|
|
4470
4786
|
#size;
|
|
4471
4787
|
#speed;
|
|
@@ -4488,6 +4804,9 @@ var SnowLayer = class extends SimulationLayer {
|
|
|
4488
4804
|
this.#sprites = this.#createSprites(r, g, b);
|
|
4489
4805
|
for (let i = 0; i < this.#maxParticles; ++i) this.#snowflakes.push(this.#createSnowflake(true));
|
|
4490
4806
|
}
|
|
4807
|
+
configure(config) {
|
|
4808
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
4809
|
+
}
|
|
4491
4810
|
onResize(_width, height) {
|
|
4492
4811
|
this.#height = height;
|
|
4493
4812
|
}
|
|
@@ -4530,11 +4849,11 @@ var SnowLayer = class extends SimulationLayer {
|
|
|
4530
4849
|
if (displaySize < .5) continue;
|
|
4531
4850
|
ctx.globalAlpha = this.#baseOpacity * (.15 + snowflake.depth * .85);
|
|
4532
4851
|
if (snowflake.spriteIndex === 3) {
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
ctx.
|
|
4852
|
+
const cos = Math.cos(snowflake.rotation);
|
|
4853
|
+
const sin = Math.sin(snowflake.rotation);
|
|
4854
|
+
ctx.setTransform(cos, sin, -sin, cos, px, py);
|
|
4536
4855
|
ctx.drawImage(this.#sprites[snowflake.spriteIndex], -displayRadius, -displayRadius, displaySize, displaySize);
|
|
4537
|
-
ctx.
|
|
4856
|
+
ctx.resetTransform();
|
|
4538
4857
|
} else ctx.drawImage(this.#sprites[snowflake.spriteIndex], px - displayRadius, py - displayRadius, displaySize, displaySize);
|
|
4539
4858
|
}
|
|
4540
4859
|
ctx.globalAlpha = 1;
|
|
@@ -4647,12 +4966,10 @@ var SnowLayer = class extends SimulationLayer {
|
|
|
4647
4966
|
}
|
|
4648
4967
|
};
|
|
4649
4968
|
//#endregion
|
|
4650
|
-
//#region src/snow/
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
}
|
|
4655
|
-
};
|
|
4969
|
+
//#region src/snow/index.ts
|
|
4970
|
+
function createSnow(config) {
|
|
4971
|
+
return new Snow(config);
|
|
4972
|
+
}
|
|
4656
4973
|
//#endregion
|
|
4657
4974
|
//#region src/sparklers/consts.ts
|
|
4658
4975
|
const MULBERRY$4 = mulberry32(13);
|
|
@@ -4664,7 +4981,7 @@ const DEFAULT_COLORS$1 = [
|
|
|
4664
4981
|
"#ffffff",
|
|
4665
4982
|
"#ffee88"
|
|
4666
4983
|
];
|
|
4667
|
-
var
|
|
4984
|
+
var Sparklers = class extends Effect {
|
|
4668
4985
|
#scale;
|
|
4669
4986
|
#emitRate;
|
|
4670
4987
|
#maxSparks;
|
|
@@ -4681,6 +4998,8 @@ var SparklerLayer = class extends SimulationLayer {
|
|
|
4681
4998
|
#emitY = .5;
|
|
4682
4999
|
#mouseOnCanvas = false;
|
|
4683
5000
|
#sparks = [];
|
|
5001
|
+
#mountedCanvas = null;
|
|
5002
|
+
#cachedRect = null;
|
|
4684
5003
|
constructor(config = {}) {
|
|
4685
5004
|
super();
|
|
4686
5005
|
this.#scale = config.scale ?? 1;
|
|
@@ -4696,11 +5015,13 @@ var SparklerLayer = class extends SimulationLayer {
|
|
|
4696
5015
|
this.#onMouseMoveBound = this.#onMouseMove.bind(this);
|
|
4697
5016
|
this.#onMouseLeaveBound = this.#onMouseLeave.bind(this);
|
|
4698
5017
|
}
|
|
4699
|
-
|
|
5018
|
+
moveTo(x, y) {
|
|
4700
5019
|
this.#emitX = x;
|
|
4701
5020
|
this.#emitY = y;
|
|
4702
5021
|
}
|
|
4703
5022
|
onMount(canvas) {
|
|
5023
|
+
this.#mountedCanvas = canvas;
|
|
5024
|
+
this.#cachedRect = canvas.getBoundingClientRect();
|
|
4704
5025
|
if (this.#hoverMode) {
|
|
4705
5026
|
canvas.addEventListener("mousemove", this.#onMouseMoveBound, { passive: true });
|
|
4706
5027
|
canvas.addEventListener("mouseleave", this.#onMouseLeaveBound, { passive: true });
|
|
@@ -4709,12 +5030,26 @@ var SparklerLayer = class extends SimulationLayer {
|
|
|
4709
5030
|
onUnmount(canvas) {
|
|
4710
5031
|
canvas.removeEventListener("mousemove", this.#onMouseMoveBound);
|
|
4711
5032
|
canvas.removeEventListener("mouseleave", this.#onMouseLeaveBound);
|
|
5033
|
+
this.#mountedCanvas = null;
|
|
5034
|
+
this.#cachedRect = null;
|
|
5035
|
+
}
|
|
5036
|
+
onResize() {
|
|
5037
|
+
if (this.#mountedCanvas) this.#cachedRect = this.#mountedCanvas.getBoundingClientRect();
|
|
5038
|
+
}
|
|
5039
|
+
configure(config) {
|
|
5040
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
5041
|
+
if (config.emitRate !== void 0) this.#emitRate = config.emitRate;
|
|
5042
|
+
if (config.friction !== void 0) this.#friction = config.friction;
|
|
5043
|
+
if (config.gravity !== void 0) this.#gravity = config.gravity;
|
|
5044
|
+
if (config.trailLength !== void 0) this.#trailLength = config.trailLength;
|
|
5045
|
+
if (config.hoverMode !== void 0) this.#hoverMode = config.hoverMode;
|
|
4712
5046
|
}
|
|
4713
5047
|
tick(dt, width, height) {
|
|
4714
5048
|
if (!this.#hoverMode || this.#mouseOnCanvas) {
|
|
4715
5049
|
const emitCount = Math.min(this.#emitRate, this.#maxSparks - this.#sparks.length);
|
|
4716
5050
|
for (let i = 0; i < emitCount; i++) this.#sparks.push(this.#createSpark(width, height));
|
|
4717
5051
|
}
|
|
5052
|
+
const frictionFactor = Math.pow(this.#friction, dt);
|
|
4718
5053
|
let alive = 0;
|
|
4719
5054
|
for (let i = 0; i < this.#sparks.length; i++) {
|
|
4720
5055
|
const spark = this.#sparks[i];
|
|
@@ -4723,8 +5058,8 @@ var SparklerLayer = class extends SimulationLayer {
|
|
|
4723
5058
|
y: spark.y
|
|
4724
5059
|
});
|
|
4725
5060
|
if (spark.trail.length > this.#trailLength) spark.trail.shift();
|
|
4726
|
-
spark.vx *=
|
|
4727
|
-
spark.vy *=
|
|
5061
|
+
spark.vx *= frictionFactor;
|
|
5062
|
+
spark.vy *= frictionFactor;
|
|
4728
5063
|
spark.vy += this.#gravity * this.#scale * dt;
|
|
4729
5064
|
spark.x += spark.vx * dt;
|
|
4730
5065
|
spark.y += spark.vy * dt;
|
|
@@ -4767,7 +5102,7 @@ var SparklerLayer = class extends SimulationLayer {
|
|
|
4767
5102
|
ctx.globalCompositeOperation = "source-over";
|
|
4768
5103
|
}
|
|
4769
5104
|
#onMouseMove(evt) {
|
|
4770
|
-
const rect = evt.currentTarget.getBoundingClientRect();
|
|
5105
|
+
const rect = this.#cachedRect ?? evt.currentTarget.getBoundingClientRect();
|
|
4771
5106
|
this.#emitX = (evt.clientX - rect.left) / rect.width;
|
|
4772
5107
|
this.#emitY = (evt.clientY - rect.top) / rect.height;
|
|
4773
5108
|
this.#mouseOnCanvas = true;
|
|
@@ -4861,29 +5196,20 @@ var SparklerParticle = class {
|
|
|
4861
5196
|
}
|
|
4862
5197
|
};
|
|
4863
5198
|
//#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
|
-
};
|
|
5199
|
+
//#region src/sparklers/index.ts
|
|
5200
|
+
function createSparklers(config) {
|
|
5201
|
+
return new Sparklers(config);
|
|
5202
|
+
}
|
|
4876
5203
|
//#endregion
|
|
4877
5204
|
//#region src/stars/consts.ts
|
|
4878
5205
|
const MULBERRY$3 = mulberry32(13);
|
|
4879
5206
|
//#endregion
|
|
4880
5207
|
//#region src/stars/layer.ts
|
|
4881
|
-
var
|
|
5208
|
+
var Stars = class extends Effect {
|
|
4882
5209
|
#mode;
|
|
4883
5210
|
#twinkleSpeed;
|
|
4884
5211
|
#colorRGB;
|
|
4885
5212
|
#scale;
|
|
4886
|
-
#verticalFade;
|
|
4887
5213
|
#shootingStarSystem;
|
|
4888
5214
|
#starCount;
|
|
4889
5215
|
#time = 0;
|
|
@@ -4894,7 +5220,6 @@ var StarLayer = class extends SimulationLayer {
|
|
|
4894
5220
|
this.#starCount = config.starCount ?? 150;
|
|
4895
5221
|
this.#twinkleSpeed = config.twinkleSpeed ?? 1;
|
|
4896
5222
|
this.#scale = config.scale ?? 1;
|
|
4897
|
-
this.#verticalFade = config.verticalFade ?? null;
|
|
4898
5223
|
this.#colorRGB = hexToRGB(config.color ?? "#ffffff");
|
|
4899
5224
|
const shootingColorRGB = hexToRGB(config.shootingColor ?? "#ffffff");
|
|
4900
5225
|
this.#shootingStarSystem = this.#mode === "shooting" || this.#mode === "both" ? new ShootingStarSystem({
|
|
@@ -4907,11 +5232,14 @@ var StarLayer = class extends SimulationLayer {
|
|
|
4907
5232
|
alphaMin: .8,
|
|
4908
5233
|
alphaRange: .2,
|
|
4909
5234
|
decayMin: .01,
|
|
4910
|
-
decayRange: .015
|
|
4911
|
-
verticalFade: this.#verticalFade ?? void 0
|
|
5235
|
+
decayRange: .015
|
|
4912
5236
|
}, () => MULBERRY$3.next()) : null;
|
|
4913
5237
|
if (this.#mode === "sky" || this.#mode === "both") for (let i = 0; i < this.#starCount; ++i) this.#stars.push(this.#createStar());
|
|
4914
5238
|
}
|
|
5239
|
+
configure(config) {
|
|
5240
|
+
if (config.twinkleSpeed !== void 0) this.#twinkleSpeed = config.twinkleSpeed;
|
|
5241
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
5242
|
+
}
|
|
4915
5243
|
tick(dt, width, height) {
|
|
4916
5244
|
this.#time += .02 * dt;
|
|
4917
5245
|
this.#shootingStarSystem?.tick(dt, width, height);
|
|
@@ -4923,13 +5251,7 @@ var StarLayer = class extends SimulationLayer {
|
|
|
4923
5251
|
for (const star of this.#stars) {
|
|
4924
5252
|
const px = star.x * width;
|
|
4925
5253
|
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
|
-
}
|
|
5254
|
+
const alpha = star.brightness * (.3 + .7 * (.5 + .5 * Math.sin(this.#time * star.twinkleSpeed * this.#twinkleSpeed + star.twinklePhase)));
|
|
4933
5255
|
const size = star.size * this.#scale;
|
|
4934
5256
|
ctx.globalAlpha = alpha;
|
|
4935
5257
|
ctx.beginPath();
|
|
@@ -4967,12 +5289,10 @@ var StarLayer = class extends SimulationLayer {
|
|
|
4967
5289
|
}
|
|
4968
5290
|
};
|
|
4969
5291
|
//#endregion
|
|
4970
|
-
//#region src/stars/
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
}
|
|
4975
|
-
};
|
|
5292
|
+
//#region src/stars/index.ts
|
|
5293
|
+
function createStars(config) {
|
|
5294
|
+
return new Stars(config);
|
|
5295
|
+
}
|
|
4976
5296
|
//#endregion
|
|
4977
5297
|
//#region src/streamers/consts.ts
|
|
4978
5298
|
const MULBERRY$2 = mulberry32(13);
|
|
@@ -4988,7 +5308,7 @@ const STREAMER_COLORS = [
|
|
|
4988
5308
|
];
|
|
4989
5309
|
//#endregion
|
|
4990
5310
|
//#region src/streamers/layer.ts
|
|
4991
|
-
var
|
|
5311
|
+
var Streamers = class extends Effect {
|
|
4992
5312
|
#colors;
|
|
4993
5313
|
#scale;
|
|
4994
5314
|
#speed;
|
|
@@ -5014,6 +5334,9 @@ var StreamerLayer = class extends SimulationLayer {
|
|
|
5014
5334
|
for (let i = 0; i < this.#count; i++) this.#streamers.push(this.#createStreamer(true));
|
|
5015
5335
|
}
|
|
5016
5336
|
}
|
|
5337
|
+
configure(config) {
|
|
5338
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
5339
|
+
}
|
|
5017
5340
|
tick(dt, width, height) {
|
|
5018
5341
|
this.#width = width;
|
|
5019
5342
|
this.#height = height;
|
|
@@ -5128,12 +5451,10 @@ var StreamerLayer = class extends SimulationLayer {
|
|
|
5128
5451
|
}
|
|
5129
5452
|
};
|
|
5130
5453
|
//#endregion
|
|
5131
|
-
//#region src/streamers/
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
}
|
|
5136
|
-
};
|
|
5454
|
+
//#region src/streamers/index.ts
|
|
5455
|
+
function createStreamers(config) {
|
|
5456
|
+
return new Streamers(config);
|
|
5457
|
+
}
|
|
5137
5458
|
//#endregion
|
|
5138
5459
|
//#region src/trail.ts
|
|
5139
5460
|
var Trail = class {
|
|
@@ -5247,12 +5568,11 @@ const DEFAULT_COLORS = [
|
|
|
5247
5568
|
"#3399cc",
|
|
5248
5569
|
"#66c2e0"
|
|
5249
5570
|
];
|
|
5250
|
-
var
|
|
5571
|
+
var Waves = class extends Effect {
|
|
5251
5572
|
#speed;
|
|
5252
|
-
#foamColor;
|
|
5253
5573
|
#foamAmount;
|
|
5254
5574
|
#scale;
|
|
5255
|
-
#
|
|
5575
|
+
#foamRGB;
|
|
5256
5576
|
#waves = [];
|
|
5257
5577
|
#foamParticles = [];
|
|
5258
5578
|
#maxFoamParticles;
|
|
@@ -5261,10 +5581,10 @@ var WaveLayer = class extends SimulationLayer {
|
|
|
5261
5581
|
const layers = config.layers ?? 5;
|
|
5262
5582
|
const colors = config.colors ?? DEFAULT_COLORS;
|
|
5263
5583
|
this.#speed = config.speed ?? 1;
|
|
5264
|
-
this.#foamColor = config.foamColor ?? "#ffffff";
|
|
5265
5584
|
this.#foamAmount = config.foamAmount ?? .4;
|
|
5266
5585
|
this.#scale = config.scale ?? 1;
|
|
5267
5586
|
this.#maxFoamParticles = 120;
|
|
5587
|
+
this.#foamRGB = hexToRGB(config.foamColor ?? "#ffffff");
|
|
5268
5588
|
if (innerWidth < 991) this.#maxFoamParticles = Math.floor(this.#maxFoamParticles / 2);
|
|
5269
5589
|
for (let i = 0; i < layers; i++) {
|
|
5270
5590
|
const depth = i / Math.max(layers - 1, 1);
|
|
@@ -5272,17 +5592,22 @@ var WaveLayer = class extends SimulationLayer {
|
|
|
5272
5592
|
this.#waves.push({
|
|
5273
5593
|
amplitude: (20 + MULBERRY$1.next() * 30) * (1 - depth * .4),
|
|
5274
5594
|
frequency: .005 + MULBERRY$1.next() * .008 + depth * .002,
|
|
5275
|
-
speed:
|
|
5595
|
+
speed: .4 + MULBERRY$1.next() * .6 + depth * .3,
|
|
5276
5596
|
phase: MULBERRY$1.next() * Math.PI * 2,
|
|
5277
5597
|
baseY: .35 + depth * .13,
|
|
5278
5598
|
color,
|
|
5279
|
-
foamThreshold: .6 + MULBERRY$1.next() * .3
|
|
5599
|
+
foamThreshold: .6 + MULBERRY$1.next() * .3,
|
|
5600
|
+
rgb: hexToRGB(color)
|
|
5280
5601
|
});
|
|
5281
5602
|
}
|
|
5282
5603
|
}
|
|
5604
|
+
configure(config) {
|
|
5605
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
5606
|
+
if (config.foamAmount !== void 0) this.#foamAmount = config.foamAmount;
|
|
5607
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
5608
|
+
}
|
|
5283
5609
|
tick(dt, width, height) {
|
|
5284
|
-
this.#
|
|
5285
|
-
for (const wave of this.#waves) wave.phase += .015 * wave.speed * dt;
|
|
5610
|
+
for (const wave of this.#waves) wave.phase += .015 * wave.speed * this.#speed * dt;
|
|
5286
5611
|
let aliveFoam = 0;
|
|
5287
5612
|
for (let i = 0; i < this.#foamParticles.length; i++) {
|
|
5288
5613
|
const foam = this.#foamParticles[i];
|
|
@@ -5312,6 +5637,7 @@ var WaveLayer = class extends SimulationLayer {
|
|
|
5312
5637
|
const step = 2;
|
|
5313
5638
|
for (let wi = 0; wi < this.#waves.length; wi++) {
|
|
5314
5639
|
const wave = this.#waves[wi];
|
|
5640
|
+
const [wr, wg, wb] = wave.rgb;
|
|
5315
5641
|
const centerY = wave.baseY * height;
|
|
5316
5642
|
ctx.beginPath();
|
|
5317
5643
|
ctx.moveTo(0, height);
|
|
@@ -5325,54 +5651,35 @@ var WaveLayer = class extends SimulationLayer {
|
|
|
5325
5651
|
ctx.lineTo(width, height);
|
|
5326
5652
|
ctx.closePath();
|
|
5327
5653
|
const gradient = ctx.createLinearGradient(0, centerY - wave.amplitude * this.#scale, 0, height);
|
|
5328
|
-
gradient.addColorStop(0,
|
|
5329
|
-
gradient.addColorStop(.4,
|
|
5330
|
-
gradient.addColorStop(1,
|
|
5654
|
+
gradient.addColorStop(0, `rgba(${wr}, ${wg}, ${wb}, 0.85)`);
|
|
5655
|
+
gradient.addColorStop(.4, `rgb(${wr}, ${wg}, ${wb})`);
|
|
5656
|
+
gradient.addColorStop(1, `rgb(${Math.floor(wr * .6)}, ${Math.floor(wg * .6)}, ${Math.floor(wb * .6)})`);
|
|
5331
5657
|
ctx.fillStyle = gradient;
|
|
5332
5658
|
ctx.fill();
|
|
5333
5659
|
}
|
|
5334
|
-
if (this.#foamAmount > 0)
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5660
|
+
if (this.#foamAmount > 0) {
|
|
5661
|
+
const [fr, fg, fb] = this.#foamRGB;
|
|
5662
|
+
for (const foam of this.#foamParticles) {
|
|
5663
|
+
if (foam.alpha <= 0) continue;
|
|
5664
|
+
ctx.beginPath();
|
|
5665
|
+
ctx.arc(foam.x, foam.y, foam.size * this.#scale, 0, Math.PI * 2);
|
|
5666
|
+
ctx.fillStyle = `rgba(${fr}, ${fg}, ${fb}, ${foam.alpha * this.#foamAmount})`;
|
|
5667
|
+
ctx.fill();
|
|
5668
|
+
}
|
|
5340
5669
|
}
|
|
5341
5670
|
}
|
|
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
5671
|
};
|
|
5363
5672
|
//#endregion
|
|
5364
|
-
//#region src/waves/
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
}
|
|
5369
|
-
};
|
|
5673
|
+
//#region src/waves/index.ts
|
|
5674
|
+
function createWaves(config) {
|
|
5675
|
+
return new Waves(config);
|
|
5676
|
+
}
|
|
5370
5677
|
//#endregion
|
|
5371
5678
|
//#region src/wormhole/consts.ts
|
|
5372
5679
|
const MULBERRY = mulberry32(13);
|
|
5373
5680
|
//#endregion
|
|
5374
5681
|
//#region src/wormhole/layer.ts
|
|
5375
|
-
var
|
|
5682
|
+
var Wormhole = class extends Effect {
|
|
5376
5683
|
#speed;
|
|
5377
5684
|
#colorRGB;
|
|
5378
5685
|
#direction;
|
|
@@ -5401,6 +5708,10 @@ var WormholeLayer = class extends SimulationLayer {
|
|
|
5401
5708
|
for (let i = 0; i < this.#count; ++i) this.#particles.push(this.#createParticle(true));
|
|
5402
5709
|
}
|
|
5403
5710
|
}
|
|
5711
|
+
configure(config) {
|
|
5712
|
+
if (config.speed !== void 0) this.#speed = config.speed;
|
|
5713
|
+
if (config.scale !== void 0) this.#scale = config.scale;
|
|
5714
|
+
}
|
|
5404
5715
|
tick(dt, width, height) {
|
|
5405
5716
|
this.#width = width;
|
|
5406
5717
|
this.#height = height;
|
|
@@ -5492,13 +5803,11 @@ var WormholeLayer = class extends SimulationLayer {
|
|
|
5492
5803
|
}
|
|
5493
5804
|
};
|
|
5494
5805
|
//#endregion
|
|
5495
|
-
//#region src/wormhole/
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
}
|
|
5500
|
-
};
|
|
5806
|
+
//#region src/wormhole/index.ts
|
|
5807
|
+
function createWormhole(config) {
|
|
5808
|
+
return new Wormhole(config);
|
|
5809
|
+
}
|
|
5501
5810
|
//#endregion
|
|
5502
|
-
export {
|
|
5811
|
+
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
5812
|
|
|
5504
5813
|
//# sourceMappingURL=index.mjs.map
|