@basmilius/sparkle 1.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/dist/index.d.mts +1192 -14
  2. package/dist/index.d.mts.map +1 -1
  3. package/dist/index.mjs +4552 -370
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +3 -2
  6. package/src/aurora/consts.ts +3 -0
  7. package/src/aurora/index.ts +4 -0
  8. package/src/aurora/layer.ts +152 -0
  9. package/src/aurora/simulation.ts +19 -0
  10. package/src/aurora/types.ts +13 -0
  11. package/src/balloons/consts.ts +3 -0
  12. package/src/balloons/index.ts +6 -0
  13. package/src/balloons/layer.ts +138 -0
  14. package/src/balloons/particle.ts +110 -0
  15. package/src/balloons/simulation.ts +19 -0
  16. package/src/balloons/types.ts +14 -0
  17. package/src/bubbles/consts.ts +3 -0
  18. package/src/bubbles/index.ts +4 -0
  19. package/src/bubbles/layer.ts +233 -0
  20. package/src/bubbles/simulation.ts +20 -0
  21. package/src/bubbles/types.ts +21 -0
  22. package/src/canvas.ts +20 -1
  23. package/src/color.ts +10 -0
  24. package/src/confetti/consts.ts +13 -13
  25. package/src/confetti/index.ts +6 -0
  26. package/src/confetti/layer.ts +152 -0
  27. package/src/confetti/particle.ts +105 -0
  28. package/src/confetti/shapes.ts +104 -0
  29. package/src/confetti/simulation.ts +9 -203
  30. package/src/confetti/types.ts +4 -1
  31. package/src/distance.ts +1 -1
  32. package/src/donuts/consts.ts +19 -0
  33. package/src/donuts/donut.ts +12 -0
  34. package/src/donuts/index.ts +3 -0
  35. package/src/donuts/layer.ts +270 -0
  36. package/src/donuts/simulation.ts +25 -0
  37. package/src/fireflies/consts.ts +3 -0
  38. package/src/fireflies/index.ts +6 -0
  39. package/src/fireflies/layer.ts +152 -0
  40. package/src/fireflies/particle.ts +124 -0
  41. package/src/fireflies/simulation.ts +18 -0
  42. package/src/fireflies/types.ts +17 -0
  43. package/src/firepit/consts.ts +3 -0
  44. package/src/firepit/index.ts +4 -0
  45. package/src/firepit/layer.ts +174 -0
  46. package/src/firepit/simulation.ts +17 -0
  47. package/src/firepit/types.ts +20 -0
  48. package/src/fireworks/explosion.ts +8 -8
  49. package/src/fireworks/firework.ts +9 -8
  50. package/src/fireworks/index.ts +6 -2
  51. package/src/fireworks/layer.ts +452 -0
  52. package/src/fireworks/simulation.ts +9 -484
  53. package/src/fireworks/spark.ts +7 -7
  54. package/src/glitter/consts.ts +13 -0
  55. package/src/glitter/index.ts +4 -0
  56. package/src/glitter/layer.ts +173 -0
  57. package/src/glitter/simulation.ts +19 -0
  58. package/src/glitter/types.ts +23 -0
  59. package/src/index.ts +28 -0
  60. package/src/lanterns/consts.ts +13 -0
  61. package/src/lanterns/index.ts +4 -0
  62. package/src/lanterns/layer.ts +166 -0
  63. package/src/lanterns/simulation.ts +17 -0
  64. package/src/lanterns/types.ts +14 -0
  65. package/src/layer.ts +24 -0
  66. package/src/layered.ts +185 -0
  67. package/src/leaves/consts.ts +16 -0
  68. package/src/leaves/index.ts +4 -0
  69. package/src/leaves/layer.ts +251 -0
  70. package/src/leaves/simulation.ts +18 -0
  71. package/src/leaves/types.ts +16 -0
  72. package/src/lightning/consts.ts +3 -0
  73. package/src/lightning/index.ts +6 -0
  74. package/src/lightning/layer.ts +41 -0
  75. package/src/lightning/simulation.ts +17 -0
  76. package/src/lightning/system.ts +196 -0
  77. package/src/lightning/types.ts +12 -0
  78. package/src/matrix/consts.ts +5 -0
  79. package/src/matrix/index.ts +4 -0
  80. package/src/matrix/layer.ts +146 -0
  81. package/src/matrix/simulation.ts +18 -0
  82. package/src/matrix/types.ts +8 -0
  83. package/src/orbits/consts.ts +13 -0
  84. package/src/orbits/index.ts +4 -0
  85. package/src/orbits/layer.ts +183 -0
  86. package/src/orbits/simulation.ts +19 -0
  87. package/src/orbits/types.ts +16 -0
  88. package/src/particles/consts.ts +3 -0
  89. package/src/particles/index.ts +4 -0
  90. package/src/particles/layer.ts +317 -0
  91. package/src/particles/simulation.ts +26 -0
  92. package/src/particles/types.ts +10 -0
  93. package/src/petals/consts.ts +13 -0
  94. package/src/petals/index.ts +4 -0
  95. package/src/petals/layer.ts +158 -0
  96. package/src/petals/simulation.ts +18 -0
  97. package/src/petals/types.ts +15 -0
  98. package/src/plasma/consts.ts +3 -0
  99. package/src/plasma/index.ts +4 -0
  100. package/src/plasma/layer.ts +92 -0
  101. package/src/plasma/simulation.ts +17 -0
  102. package/src/plasma/types.ts +5 -0
  103. package/src/rain/consts.ts +3 -0
  104. package/src/rain/index.ts +6 -0
  105. package/src/rain/layer.ts +172 -0
  106. package/src/rain/particle.ts +132 -0
  107. package/src/rain/simulation.ts +21 -0
  108. package/src/rain/types.ts +22 -0
  109. package/src/sandstorm/consts.ts +3 -0
  110. package/src/sandstorm/index.ts +4 -0
  111. package/src/sandstorm/layer.ts +135 -0
  112. package/src/sandstorm/simulation.ts +18 -0
  113. package/src/sandstorm/types.ts +10 -0
  114. package/src/shooting-stars/index.ts +3 -0
  115. package/src/shooting-stars/system.ts +149 -0
  116. package/src/shooting-stars/types.ts +10 -0
  117. package/src/simulation-canvas.ts +47 -0
  118. package/src/snow/consts.ts +2 -2
  119. package/src/snow/index.ts +1 -0
  120. package/src/snow/layer.ts +263 -0
  121. package/src/snow/simulation.ts +4 -288
  122. package/src/sparklers/consts.ts +3 -0
  123. package/src/sparklers/index.ts +6 -0
  124. package/src/sparklers/layer.ts +174 -0
  125. package/src/sparklers/particle.ts +89 -0
  126. package/src/sparklers/simulation.ts +30 -0
  127. package/src/sparklers/types.ts +13 -0
  128. package/src/stars/consts.ts +3 -0
  129. package/src/stars/index.ts +4 -0
  130. package/src/stars/layer.ts +133 -0
  131. package/src/stars/simulation.ts +22 -0
  132. package/src/stars/types.ts +12 -0
  133. package/src/streamers/consts.ts +14 -0
  134. package/src/streamers/index.ts +4 -0
  135. package/src/streamers/layer.ts +211 -0
  136. package/src/streamers/simulation.ts +16 -0
  137. package/src/streamers/types.ts +14 -0
  138. package/src/trail.ts +140 -0
  139. package/src/waves/consts.ts +3 -0
  140. package/src/waves/index.ts +4 -0
  141. package/src/waves/layer.ts +167 -0
  142. package/src/waves/simulation.ts +18 -0
  143. package/src/waves/types.ts +9 -0
  144. package/src/wormhole/consts.ts +3 -0
  145. package/src/wormhole/index.ts +4 -0
  146. package/src/wormhole/layer.ts +181 -0
  147. package/src/wormhole/simulation.ts +17 -0
  148. package/src/wormhole/types.ts +10 -0
@@ -1,493 +1,18 @@
1
- import { LimitedFrameRateCanvas } from '../canvas';
1
+ import { SimulationCanvas } from '../simulation-canvas';
2
+ import { FireworkLayer } from './layer';
2
3
  import type { Point } from '../point';
3
- import { MULBERRY } from './consts';
4
- import { Explosion } from './explosion';
5
- import { Firework } from './firework';
6
- import { Spark } from './spark';
7
- import { EXPLOSION_CONFIGS, type ExplosionType, type FireworkSimulationConfig, type FireworkVariant } from './types';
4
+ import type { FireworkSimulationConfig, FireworkVariant } from './types';
8
5
 
9
- export class FireworkSimulation extends LimitedFrameRateCanvas {
10
- #explosions: Explosion[] = [];
11
- #fireworks: Firework[] = [];
12
- #sparks: Spark[] = [];
13
- #hue: number = 120;
14
- #positionRandom = MULBERRY.fork();
15
- readonly #autoSpawn: boolean;
16
- readonly #baseSize: number;
17
- readonly #scale: number;
18
- readonly #tailWidth: number;
6
+ export class FireworkSimulation extends SimulationCanvas {
7
+ readonly #layer: FireworkLayer;
19
8
 
20
9
  constructor(canvas: HTMLCanvasElement, config: FireworkSimulationConfig = {}) {
21
- super(canvas, 60, config.canvasOptions ?? {colorSpace: 'display-p3'});
22
-
23
- const scale = config.scale ?? 1;
24
- this.#autoSpawn = config.autoSpawn ?? true;
25
- this.#baseSize = 5 * scale;
26
- this.#scale = scale;
27
- this.#tailWidth = 2 * scale;
28
-
29
- this.canvas.style.position = 'absolute';
30
- this.canvas.style.top = '0';
31
- this.canvas.style.left = '0';
32
- this.canvas.style.height = '100%';
33
- this.canvas.style.width = '100%';
34
- }
35
-
36
- draw(): void {
37
- if (this.canvas.width !== this.width || this.canvas.height !== this.height) {
38
- this.canvas.width = this.width;
39
- this.canvas.height = this.height;
40
- }
41
-
42
- this.context.clearRect(0, 0, this.width, this.height);
43
- this.context.globalCompositeOperation = 'lighter';
44
-
45
- for (const spark of this.#sparks) {
46
- spark.draw(this.context);
47
- }
48
-
49
- for (const explosion of this.#explosions) {
50
- explosion.draw(this.context);
51
- }
52
-
53
- for (const firework of this.#fireworks) {
54
- firework.draw(this.context);
55
- }
10
+ const layer = new FireworkLayer(config);
11
+ super(canvas, layer, 60, config.canvasOptions ?? {colorSpace: 'display-p3'});
12
+ this.#layer = layer;
56
13
  }
57
14
 
58
15
  fireExplosion(variant: FireworkVariant, position?: Point): void {
59
- const pos = position ?? {x: this.width / 2, y: this.height * 0.4};
60
- this.#hue = MULBERRY.nextBetween(0, 360);
61
- this.#createExplosion(pos, this.#hue, variant);
62
- }
63
-
64
- tick(): void {
65
- if (this.#autoSpawn && this.#fireworks.length < 6 && this.ticks % (this.isSmall ? 60 : 30) === 0) {
66
- let count = MULBERRY.nextBetween(1, 100) < 10 ? 2 : 1;
67
-
68
- while (count--) {
69
- this.#hue = MULBERRY.nextBetween(0, 360);
70
- this.#createFirework();
71
- }
72
- }
73
-
74
- for (const firework of this.#fireworks) {
75
- firework.tick();
76
- this.#sparks.push(...firework.collectSparks());
77
- }
78
-
79
- for (const explosion of this.#explosions) {
80
- explosion.tick();
81
- }
82
-
83
- for (const spark of this.#sparks) {
84
- spark.tick();
85
- }
86
-
87
- const newExplosions: Explosion[] = [];
88
- const newSparks: Spark[] = [];
89
-
90
- for (const explosion of this.#explosions) {
91
- if (explosion.checkSplit()) {
92
- for (let i = 0; i < 4; i++) {
93
- const angle = explosion.angle + (Math.PI / 2) * i + Math.PI / 4;
94
-
95
- newExplosions.push(new Explosion(
96
- explosion.position,
97
- explosion.hue,
98
- this.#baseSize * 0.6,
99
- 'peony',
100
- this.#scale,
101
- angle,
102
- MULBERRY.nextBetween(3, 6)
103
- ));
104
- }
105
- }
106
-
107
- if (explosion.checkCrackle()) {
108
- for (let j = 0; j < 8; j++) {
109
- newSparks.push(new Spark(
110
- explosion.position,
111
- explosion.hue + MULBERRY.nextBetween(-30, 30)
112
- ));
113
- }
114
- }
115
- }
116
-
117
- this.#explosions.push(...newExplosions);
118
- this.#sparks.push(...newSparks);
119
-
120
- this.#explosions = this.#explosions.filter(e => !e.isDead);
121
- this.#sparks = this.#sparks.filter(s => !s.isDead);
122
- }
123
-
124
- #createExplosion(position: Point, hue: number, variant?: FireworkVariant): void {
125
- const selected = variant ?? this.#pickVariant();
126
-
127
- if (selected === 'saturn') {
128
- this.#createSaturnExplosion(position, hue);
129
- return;
130
- }
131
-
132
- if (selected === 'dahlia') {
133
- this.#createDahliaExplosion(position, hue);
134
- return;
135
- }
136
-
137
- if (selected === 'heart') {
138
- this.#createHeartExplosion(position, hue);
139
- return;
140
- }
141
-
142
- if (selected === 'spiral') {
143
- this.#createSpiralExplosion(position, hue);
144
- return;
145
- }
146
-
147
- if (selected === 'flower') {
148
- this.#createFlowerExplosion(position, hue);
149
- return;
150
- }
151
-
152
- if (selected === 'concentric') {
153
- this.#createConcentricExplosion(position, hue);
154
- return;
155
- }
156
-
157
- const type: ExplosionType = selected;
158
- const config = EXPLOSION_CONFIGS[type];
159
- const particleCount = Math.floor(MULBERRY.nextBetween(config.particleCount[0], config.particleCount[1]));
160
-
161
- const effectiveHue = type === 'brocade'
162
- ? MULBERRY.nextBetween(35, 50)
163
- : hue;
164
-
165
- for (let i = 0; i < particleCount; i++) {
166
- let angle: number | undefined;
167
- let speed: number | undefined;
168
-
169
- if (type === 'ring') {
170
- angle = (i / particleCount) * Math.PI * 2;
171
- speed = MULBERRY.nextBetween(config.speed[0], config.speed[1]) * 0.5 + config.speed[0] * 0.5;
172
- } else if (type === 'palm' || type === 'horsetail') {
173
- const spread = type === 'horsetail' ? Math.PI / 8 : Math.PI / 5;
174
- angle = -Math.PI / 2 + MULBERRY.nextBetween(-spread, spread);
175
- }
176
-
177
- this.#explosions.push(new Explosion(position, effectiveHue, this.#baseSize, type, this.#scale, angle, speed));
178
- }
179
- }
180
-
181
- #createSaturnExplosion(position: Point, hue: number): void {
182
- const velocity = MULBERRY.nextBetween(4, 6);
183
-
184
- // Outer shell — evenly spaced circle
185
- const shellCount = Math.floor(MULBERRY.nextBetween(25, 35));
186
-
187
- for (let i = 0; i < shellCount; i++) {
188
- const rad = (i / shellCount) * Math.PI * 2;
189
-
190
- this.#explosions.push(new Explosion(
191
- position,
192
- hue,
193
- this.#baseSize,
194
- 'peony',
195
- this.#scale,
196
- rad + MULBERRY.nextBetween(-0.05, 0.05),
197
- velocity + MULBERRY.nextBetween(-0.25, 0.25)
198
- ));
199
- }
200
-
201
- // Filled interior — random speeds from 0 to velocity for sphere fill
202
- const fillCount = Math.floor(MULBERRY.nextBetween(40, 60));
203
-
204
- for (let i = 0; i < fillCount; i++) {
205
- const rad = MULBERRY.nextBetween(0, Math.PI * 2);
206
- const speed = velocity * MULBERRY.nextBetween(0, 1);
207
-
208
- this.#explosions.push(new Explosion(
209
- position,
210
- hue,
211
- this.#baseSize,
212
- 'peony',
213
- this.#scale,
214
- rad,
215
- speed
216
- ));
217
- }
218
-
219
- // Elliptical ring — rotated 2D ellipse with z-depth
220
- const ringRotation = MULBERRY.nextBetween(0, Math.PI * 2);
221
- const ringCount = Math.floor(MULBERRY.nextBetween(40, 55));
222
- const ringVx = velocity * MULBERRY.nextBetween(2, 3);
223
- const ringVy = velocity * 0.6;
224
-
225
- for (let i = 0; i < ringCount; i++) {
226
- const rad = (i / ringCount) * Math.PI * 2;
227
-
228
- const cx = Math.cos(rad) * ringVx + MULBERRY.nextBetween(-0.25, 0.25);
229
- const cy = Math.sin(rad) * ringVy + MULBERRY.nextBetween(-0.25, 0.25);
230
-
231
- const cosR = Math.cos(ringRotation);
232
- const sinR = Math.sin(ringRotation);
233
- const vx = cx * cosR - cy * sinR;
234
- const vy = cx * sinR + cy * cosR;
235
-
236
- const screenAngle = Math.atan2(vy, vx);
237
- const screenSpeed = Math.sqrt(vx * vx + vy * vy);
238
- const vz = Math.sin(rad) * velocity * 0.8;
239
-
240
- this.#explosions.push(new Explosion(
241
- position,
242
- hue + 60,
243
- this.#baseSize,
244
- 'ring',
245
- this.#scale,
246
- screenAngle,
247
- screenSpeed,
248
- vz
249
- ));
250
- }
251
- }
252
-
253
- #createDahliaExplosion(position: Point, hue: number): void {
254
- const petalCount = Math.floor(MULBERRY.nextBetween(6, 9));
255
- const particlesPerPetal = Math.floor(MULBERRY.nextBetween(8, 12));
256
-
257
- for (let petal = 0; petal < petalCount; petal++) {
258
- const baseAngle = (petal / petalCount) * Math.PI * 2;
259
- const petalHue = hue + (petal % 2 === 0 ? 25 : -25);
260
-
261
- for (let i = 0; i < particlesPerPetal; i++) {
262
- const angle = baseAngle + MULBERRY.nextBetween(-0.3, 0.3);
263
-
264
- this.#explosions.push(new Explosion(
265
- position,
266
- petalHue,
267
- this.#baseSize,
268
- 'dahlia',
269
- this.#scale,
270
- angle
271
- ));
272
- }
273
- }
274
- }
275
-
276
- #createHeartExplosion(position: Point, hue: number): void {
277
- const velocity = MULBERRY.nextBetween(3, 5);
278
- const count = Math.floor(MULBERRY.nextBetween(60, 80));
279
- const rotation = MULBERRY.nextBetween(-0.3, 0.3);
280
-
281
- for (let i = 0; i < count; i++) {
282
- const t = (i / count) * Math.PI * 2;
283
-
284
- // Parametric heart curve
285
- const hx = 16 * Math.pow(Math.sin(t), 3);
286
- const hy = -(13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t));
287
-
288
- const scale = velocity / 16;
289
- const vx = hx * scale;
290
- const vy = hy * scale;
291
-
292
- // Rotate slightly
293
- const cosR = Math.cos(rotation);
294
- const sinR = Math.sin(rotation);
295
- const rvx = vx * cosR - vy * sinR;
296
- const rvy = vx * sinR + vy * cosR;
297
-
298
- const angle = Math.atan2(rvy, rvx);
299
- const speed = Math.sqrt(rvx * rvx + rvy * rvy);
300
-
301
- this.#explosions.push(new Explosion(
302
- position,
303
- hue,
304
- this.#baseSize,
305
- 'heart',
306
- this.#scale,
307
- angle,
308
- Math.max(0.1, speed + MULBERRY.nextBetween(-0.15, 0.15))
309
- ));
310
- }
311
- }
312
-
313
- #createSpiralExplosion(position: Point, hue: number): void {
314
- const arms = Math.floor(MULBERRY.nextBetween(3, 5));
315
- const particlesPerArm = Math.floor(MULBERRY.nextBetween(15, 20));
316
- const twist = MULBERRY.nextBetween(2, 3.5);
317
- const baseRotation = MULBERRY.nextBetween(0, Math.PI * 2);
318
-
319
- for (let arm = 0; arm < arms; arm++) {
320
- const baseAngle = baseRotation + (arm / arms) * Math.PI * 2;
321
- const armHue = hue + arm * (360 / arms / 3);
322
-
323
- for (let i = 0; i < particlesPerArm; i++) {
324
- const progress = i / particlesPerArm;
325
- const angle = baseAngle + progress * twist;
326
- const speed = 2 + progress * 8;
327
-
328
- this.#explosions.push(new Explosion(
329
- position,
330
- armHue,
331
- this.#baseSize,
332
- 'spiral',
333
- this.#scale,
334
- angle,
335
- speed + MULBERRY.nextBetween(-0.3, 0.3)
336
- ));
337
- }
338
- }
339
- }
340
-
341
- #createFlowerExplosion(position: Point, hue: number): void {
342
- const velocity = MULBERRY.nextBetween(4, 7);
343
- const count = Math.floor(MULBERRY.nextBetween(70, 90));
344
- const petals = Math.floor(MULBERRY.nextBetween(2, 4));
345
- const rotation = MULBERRY.nextBetween(0, Math.PI * 2);
346
-
347
- for (let i = 0; i < count; i++) {
348
- const t = (i / count) * Math.PI * 2;
349
-
350
- // Rose curve: r = |cos(n * theta)|
351
- const r = Math.abs(Math.cos(petals * t));
352
- const speed = velocity * r;
353
-
354
- if (speed < 0.3) {
355
- continue;
356
- }
357
-
358
- this.#explosions.push(new Explosion(
359
- position,
360
- hue + MULBERRY.nextBetween(-15, 15),
361
- this.#baseSize,
362
- 'flower',
363
- this.#scale,
364
- t + rotation,
365
- speed + MULBERRY.nextBetween(-0.2, 0.2)
366
- ));
367
- }
368
- }
369
-
370
- #createConcentricExplosion(position: Point, hue: number): void {
371
- const outerCount = Math.floor(MULBERRY.nextBetween(35, 50));
372
- const outerSpeed = MULBERRY.nextBetween(7, 10);
373
-
374
- for (let i = 0; i < outerCount; i++) {
375
- const angle = (i / outerCount) * Math.PI * 2;
376
-
377
- this.#explosions.push(new Explosion(
378
- position,
379
- hue,
380
- this.#baseSize,
381
- 'ring',
382
- this.#scale,
383
- angle + MULBERRY.nextBetween(-0.05, 0.05),
384
- outerSpeed + MULBERRY.nextBetween(-0.25, 0.25)
385
- ));
386
- }
387
-
388
- const innerCount = Math.floor(MULBERRY.nextBetween(25, 35));
389
- const innerSpeed = MULBERRY.nextBetween(3, 5);
390
-
391
- for (let i = 0; i < innerCount; i++) {
392
- const angle = (i / innerCount) * Math.PI * 2;
393
-
394
- this.#explosions.push(new Explosion(
395
- position,
396
- hue + 120,
397
- this.#baseSize,
398
- 'ring',
399
- this.#scale,
400
- angle + MULBERRY.nextBetween(-0.05, 0.05),
401
- innerSpeed + MULBERRY.nextBetween(-0.25, 0.25)
402
- ));
403
- }
404
- }
405
-
406
- #createFirework(position?: Point): void {
407
- const hue = this.#hue;
408
- const targetX = position?.x || this.#positionRandom.nextBetween(this.width * .1, this.width * .9);
409
- const targetY = position?.y || this.height * .1 + this.#positionRandom.nextBetween(0, this.height * .5);
410
- const startX = this.width * 0.3 + this.#positionRandom.nextBetween(0, this.width * 0.4);
411
-
412
- const firework = new Firework(
413
- {x: startX, y: this.height},
414
- {x: targetX, y: targetY},
415
- hue,
416
- this.#tailWidth,
417
- this.#baseSize
418
- );
419
-
420
- firework.addEventListener('remove', () => {
421
- this.#fireworks.splice(this.#fireworks.indexOf(firework), 1);
422
- this.#createExplosion(firework.position, hue);
423
- }, {once: true});
424
-
425
- this.#fireworks.push(firework);
426
- }
427
-
428
- #pickVariant(): FireworkVariant {
429
- const roll = MULBERRY.nextBetween(0, 100);
430
-
431
- if (roll < 12) {
432
- return 'peony';
433
- }
434
-
435
- if (roll < 22) {
436
- return 'chrysanthemum';
437
- }
438
-
439
- if (roll < 29) {
440
- return 'willow';
441
- }
442
-
443
- if (roll < 34) {
444
- return 'ring';
445
- }
446
-
447
- if (roll < 39) {
448
- return 'palm';
449
- }
450
-
451
- if (roll < 44) {
452
- return 'crackle';
453
- }
454
-
455
- if (roll < 48) {
456
- return 'crossette';
457
- }
458
-
459
- if (roll < 55) {
460
- return 'saturn';
461
- }
462
-
463
- if (roll < 62) {
464
- return 'dahlia';
465
- }
466
-
467
- if (roll < 67) {
468
- return 'brocade';
469
- }
470
-
471
- if (roll < 71) {
472
- return 'horsetail';
473
- }
474
-
475
- if (roll < 75) {
476
- return 'strobe';
477
- }
478
-
479
- if (roll < 82) {
480
- return 'heart';
481
- }
482
-
483
- if (roll < 89) {
484
- return 'spiral';
485
- }
486
-
487
- if (roll < 94) {
488
- return 'flower';
489
- }
490
-
491
- return 'concentric';
16
+ this.#layer.fireExplosion(variant, position);
492
17
  }
493
18
  }
@@ -37,14 +37,14 @@ export class Spark {
37
37
  ctx.fill();
38
38
  }
39
39
 
40
- tick(): void {
41
- this.#velocity.x *= this.#friction;
42
- this.#velocity.y *= this.#friction;
43
- this.#velocity.y += this.#gravity;
40
+ tick(dt: number): void {
41
+ this.#velocity.x *= Math.pow(this.#friction, dt);
42
+ this.#velocity.y *= Math.pow(this.#friction, dt);
43
+ this.#velocity.y += this.#gravity * dt;
44
44
 
45
- this.#position.x += this.#velocity.x;
46
- this.#position.y += this.#velocity.y;
45
+ this.#position.x += this.#velocity.x * dt;
46
+ this.#position.y += this.#velocity.y * dt;
47
47
 
48
- this.#alpha -= this.#decay;
48
+ this.#alpha -= this.#decay * dt;
49
49
  }
50
50
  }
@@ -0,0 +1,13 @@
1
+ import { type Mulberry32, mulberry32 } from '@basmilius/utils';
2
+
3
+ export const MULBERRY: Mulberry32 = mulberry32(13);
4
+
5
+ export const GLITTER_COLORS: string[] = [
6
+ '#ffd700', // gold
7
+ '#c0c0c0', // silver
8
+ '#ff69b4', // pink
9
+ '#00bfff', // sky blue
10
+ '#ff4500', // orange-red
11
+ '#7fff00', // chartreuse
12
+ '#9370db' // medium purple
13
+ ];
@@ -0,0 +1,4 @@
1
+ export { GlitterLayer } from './layer';
2
+ export { GlitterSimulation } from './simulation';
3
+ export type { GlitterSimulationConfig } from './simulation';
4
+ export type { FallingGlitter, SettledGlitter } from './types';