@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
@@ -0,0 +1,167 @@
1
+ import { SimulationLayer } from '../layer';
2
+ import { MULBERRY } from './consts';
3
+ import type { WaveSimulationConfig } from './simulation';
4
+ import type { Wave } from './types';
5
+
6
+ const DEFAULT_COLORS = ['#0a3d6b', '#0e5a8a', '#1a7ab5', '#3399cc', '#66c2e0'];
7
+
8
+ export class WaveLayer extends SimulationLayer {
9
+ readonly #speed: number;
10
+ readonly #foamColor: string;
11
+ readonly #foamAmount: number;
12
+ readonly #scale: number;
13
+ #time: number = 0;
14
+ #waves: Wave[] = [];
15
+ #foamParticles: {x: number; y: number; alpha: number; size: number}[] = [];
16
+ #maxFoamParticles: number;
17
+
18
+ constructor(config: WaveSimulationConfig = {}) {
19
+ super();
20
+
21
+ const layers = config.layers ?? 5;
22
+ const colors = config.colors ?? DEFAULT_COLORS;
23
+ this.#speed = config.speed ?? 1;
24
+ this.#foamColor = config.foamColor ?? '#ffffff';
25
+ this.#foamAmount = config.foamAmount ?? 0.4;
26
+ this.#scale = config.scale ?? 1;
27
+ this.#maxFoamParticles = 120;
28
+
29
+ if (innerWidth < 991) {
30
+ this.#maxFoamParticles = Math.floor(this.#maxFoamParticles / 2);
31
+ }
32
+
33
+ for (let i = 0; i < layers; i++) {
34
+ const depth = i / Math.max(layers - 1, 1);
35
+ const color = colors[i % colors.length];
36
+
37
+ this.#waves.push({
38
+ amplitude: (20 + MULBERRY.next() * 30) * (1 - depth * 0.4),
39
+ frequency: 0.005 + MULBERRY.next() * 0.008 + depth * 0.002,
40
+ speed: (0.4 + MULBERRY.next() * 0.6 + depth * 0.3) * this.#speed,
41
+ phase: MULBERRY.next() * Math.PI * 2,
42
+ baseY: 0.35 + depth * 0.13,
43
+ color,
44
+ foamThreshold: 0.6 + MULBERRY.next() * 0.3
45
+ });
46
+ }
47
+ }
48
+
49
+ tick(dt: number, width: number, height: number): void {
50
+ this.#time += 0.02 * dt * this.#speed;
51
+
52
+ for (const wave of this.#waves) {
53
+ wave.phase += 0.015 * wave.speed * dt;
54
+ }
55
+
56
+ let aliveFoam = 0;
57
+
58
+ for (let i = 0; i < this.#foamParticles.length; i++) {
59
+ const foam = this.#foamParticles[i];
60
+ foam.alpha -= (0.008 + MULBERRY.next() * 0.006) * dt;
61
+ foam.x += (MULBERRY.next() - 0.5) * 0.5 * dt;
62
+ foam.y += (MULBERRY.next() - 0.5) * 0.3 * dt;
63
+
64
+ if (foam.alpha > 0) {
65
+ this.#foamParticles[aliveFoam++] = foam;
66
+ }
67
+ }
68
+
69
+ this.#foamParticles.length = aliveFoam;
70
+
71
+ if (this.#foamAmount > 0 && width > 0 && height > 0) {
72
+ const spawnCount = Math.ceil(2 * this.#foamAmount * dt);
73
+
74
+ for (let s = 0; s < spawnCount && this.#foamParticles.length < this.#maxFoamParticles; s++) {
75
+ const waveIndex = Math.floor(MULBERRY.next() * this.#waves.length);
76
+ const wave = this.#waves[waveIndex];
77
+ const x = MULBERRY.next() * width;
78
+ const centerY = wave.baseY * height;
79
+ const primary = wave.amplitude * Math.sin(wave.frequency * x + wave.phase);
80
+ const secondary = wave.amplitude * 0.4 * Math.sin(wave.frequency * 2.3 * x + wave.phase * 1.7 + 1.3);
81
+ const waveY = centerY + (primary + secondary) * this.#scale;
82
+
83
+ const slopeCheck = Math.cos(wave.frequency * x + wave.phase);
84
+
85
+ if (slopeCheck > wave.foamThreshold - 1) {
86
+ this.#foamParticles.push({
87
+ x,
88
+ y: waveY - MULBERRY.next() * 4 * this.#scale,
89
+ alpha: 0.4 + MULBERRY.next() * 0.6,
90
+ size: 1 + MULBERRY.next() * 3
91
+ });
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ draw(ctx: CanvasRenderingContext2D, width: number, height: number): void {
98
+
99
+ const step = 2;
100
+
101
+ for (let wi = 0; wi < this.#waves.length; wi++) {
102
+ const wave = this.#waves[wi];
103
+ const centerY = wave.baseY * height;
104
+
105
+ ctx.beginPath();
106
+ ctx.moveTo(0, height);
107
+
108
+ for (let x = 0; x <= width; x += step) {
109
+ const primary = wave.amplitude * Math.sin(wave.frequency * x + wave.phase);
110
+ const secondary = wave.amplitude * 0.4 * Math.sin(wave.frequency * 2.3 * x + wave.phase * 1.7 + 1.3);
111
+ const tertiary = wave.amplitude * 0.15 * Math.sin(wave.frequency * 4.1 * x + wave.phase * 0.6 + 2.8);
112
+ const waveY = centerY + (primary + secondary + tertiary) * this.#scale;
113
+
114
+ ctx.lineTo(x, waveY);
115
+ }
116
+
117
+ ctx.lineTo(width, height);
118
+ ctx.closePath();
119
+
120
+ const gradient = ctx.createLinearGradient(0, centerY - wave.amplitude * this.#scale, 0, height);
121
+ gradient.addColorStop(0, this.#adjustAlpha(wave.color, 0.85));
122
+ gradient.addColorStop(0.4, wave.color);
123
+ gradient.addColorStop(1, this.#darkenColor(wave.color, 0.6));
124
+
125
+ ctx.fillStyle = gradient;
126
+ ctx.fill();
127
+ }
128
+
129
+ if (this.#foamAmount > 0) {
130
+ for (const foam of this.#foamParticles) {
131
+ if (foam.alpha <= 0) {
132
+ continue;
133
+ }
134
+
135
+ ctx.beginPath();
136
+ ctx.arc(foam.x, foam.y, foam.size * this.#scale, 0, Math.PI * 2);
137
+ ctx.fillStyle = this.#adjustAlpha(this.#foamColor, foam.alpha * this.#foamAmount);
138
+ ctx.fill();
139
+ }
140
+ }
141
+ }
142
+
143
+ #adjustAlpha(color: string, alpha: number): string {
144
+ const canvas = document.createElement('canvas');
145
+ canvas.width = 1;
146
+ canvas.height = 1;
147
+ const ctx = canvas.getContext('2d')!;
148
+ ctx.fillStyle = color;
149
+ ctx.fillRect(0, 0, 1, 1);
150
+ const data = ctx.getImageData(0, 0, 1, 1).data;
151
+ return `rgba(${data[0]}, ${data[1]}, ${data[2]}, ${alpha})`;
152
+ }
153
+
154
+ #darkenColor(color: string, factor: number): string {
155
+ const canvas = document.createElement('canvas');
156
+ canvas.width = 1;
157
+ canvas.height = 1;
158
+ const ctx = canvas.getContext('2d')!;
159
+ ctx.fillStyle = color;
160
+ ctx.fillRect(0, 0, 1, 1);
161
+ const data = ctx.getImageData(0, 0, 1, 1).data;
162
+ const r = Math.floor(data[0] * factor);
163
+ const g = Math.floor(data[1] * factor);
164
+ const b = Math.floor(data[2] * factor);
165
+ return `rgb(${r}, ${g}, ${b})`;
166
+ }
167
+ }
@@ -0,0 +1,18 @@
1
+ import { SimulationCanvas } from '../simulation-canvas';
2
+ import { WaveLayer } from './layer';
3
+
4
+ export interface WaveSimulationConfig {
5
+ readonly layers?: number;
6
+ readonly speed?: number;
7
+ readonly colors?: string[];
8
+ readonly foamColor?: string;
9
+ readonly foamAmount?: number;
10
+ readonly scale?: number;
11
+ readonly canvasOptions?: CanvasRenderingContext2DSettings;
12
+ }
13
+
14
+ export class WaveSimulation extends SimulationCanvas {
15
+ constructor(canvas: HTMLCanvasElement, config: WaveSimulationConfig = {}) {
16
+ super(canvas, new WaveLayer(config), 60, config.canvasOptions ?? {colorSpace: 'display-p3'});
17
+ }
18
+ }
@@ -0,0 +1,9 @@
1
+ export type Wave = {
2
+ amplitude: number;
3
+ frequency: number;
4
+ speed: number;
5
+ phase: number;
6
+ baseY: number;
7
+ color: string;
8
+ foamThreshold: number;
9
+ };
@@ -0,0 +1,3 @@
1
+ import { type Mulberry32, mulberry32 } from '@basmilius/utils';
2
+
3
+ export const MULBERRY: Mulberry32 = mulberry32(13);
@@ -0,0 +1,4 @@
1
+ export { WormholeLayer } from './layer';
2
+ export { WormholeSimulation } from './simulation';
3
+ export type { WormholeSimulationConfig } from './simulation';
4
+ export type { WormholeDirection, WormholeParticle } from './types';
@@ -0,0 +1,181 @@
1
+ import { hexToRGB } from '@basmilius/utils';
2
+ import { SimulationLayer } from '../layer';
3
+ import { MULBERRY } from './consts';
4
+ import type { WormholeSimulationConfig } from './simulation';
5
+ import type { WormholeDirection, WormholeParticle } from './types';
6
+
7
+ export class WormholeLayer extends SimulationLayer {
8
+ readonly #speed: number;
9
+ readonly #colorRGB: [number, number, number];
10
+ readonly #direction: WormholeDirection;
11
+ readonly #scale: number;
12
+ #count: number;
13
+ #particles: WormholeParticle[] = [];
14
+ #width: number = 960;
15
+ #height: number = 540;
16
+ #initialized: boolean = false;
17
+
18
+ constructor(config: WormholeSimulationConfig = {}) {
19
+ super();
20
+
21
+ let count = config.count ?? 200;
22
+
23
+ this.#speed = config.speed ?? 1;
24
+ this.#colorRGB = hexToRGB(config.color ?? '#6699ff');
25
+ this.#direction = config.direction ?? 'inward';
26
+ this.#scale = config.scale ?? 1;
27
+
28
+ if (innerWidth < 991) {
29
+ count = Math.floor(count / 2);
30
+ }
31
+
32
+ this.#count = count;
33
+ }
34
+
35
+ onResize(width: number, height: number): void {
36
+ this.#width = width;
37
+ this.#height = height;
38
+
39
+ if (!this.#initialized) {
40
+ this.#initialized = true;
41
+ this.#particles = [];
42
+
43
+ for (let i = 0; i < this.#count; ++i) {
44
+ this.#particles.push(this.#createParticle(true));
45
+ }
46
+ }
47
+ }
48
+
49
+ tick(dt: number, width: number, height: number): void {
50
+ this.#width = width;
51
+ this.#height = height;
52
+
53
+ const maxRadius = Math.sqrt((width / 2) ** 2 + (height / 2) ** 2);
54
+
55
+ let alive = 0;
56
+
57
+ for (let i = 0; i < this.#particles.length; ++i) {
58
+ const particle = this.#particles[i];
59
+
60
+ if (this.#direction === 'inward') {
61
+ const normalizedDistance = particle.distance / maxRadius;
62
+ const acceleration = 1 + (1 - normalizedDistance) * 3;
63
+ particle.distance -= particle.speed * this.#speed * acceleration * dt * this.#scale;
64
+
65
+ particle.trail = 5 + (1 - normalizedDistance) * 25;
66
+
67
+ if (particle.distance > 0) {
68
+ this.#particles[alive++] = particle;
69
+ } else {
70
+ this.#particles[alive++] = this.#createParticle(false);
71
+ }
72
+ } else {
73
+ const normalizedDistance = particle.distance / maxRadius;
74
+ const acceleration = 1 + normalizedDistance * 3;
75
+ particle.distance += particle.speed * this.#speed * acceleration * dt * this.#scale;
76
+
77
+ particle.trail = 5 + normalizedDistance * 25;
78
+
79
+ if (particle.distance < maxRadius + 20) {
80
+ this.#particles[alive++] = particle;
81
+ } else {
82
+ this.#particles[alive++] = this.#createParticle(false);
83
+ }
84
+ }
85
+
86
+ particle.angle += (MULBERRY.next() - 0.5) * 0.002 * dt;
87
+ }
88
+
89
+ this.#particles.length = alive;
90
+ }
91
+
92
+ draw(ctx: CanvasRenderingContext2D, width: number, height: number): void {
93
+ const cx = width / 2;
94
+ const cy = height / 2;
95
+ const maxRadius = Math.sqrt(cx * cx + cy * cy);
96
+ const [cr, cg, cb] = this.#colorRGB;
97
+
98
+
99
+ const glowRadius = 40 * this.#scale;
100
+ const glow = ctx.createRadialGradient(cx, cy, 0, cx, cy, glowRadius);
101
+ glow.addColorStop(0, `rgba(${cr}, ${cg}, ${cb}, 0.25)`);
102
+ glow.addColorStop(0.4, `rgba(${cr}, ${cg}, ${cb}, 0.08)`);
103
+ glow.addColorStop(1, `rgba(${cr}, ${cg}, ${cb}, 0)`);
104
+
105
+ ctx.globalCompositeOperation = 'lighter';
106
+ ctx.globalAlpha = 1;
107
+ ctx.beginPath();
108
+ ctx.arc(cx, cy, glowRadius, 0, Math.PI * 2);
109
+ ctx.fillStyle = glow;
110
+ ctx.fill();
111
+
112
+ for (const particle of this.#particles) {
113
+ const normalizedDistance = particle.distance / maxRadius;
114
+ const px = cx + Math.cos(particle.angle) * particle.distance;
115
+ const py = cy + Math.sin(particle.angle) * particle.distance;
116
+
117
+ const trailFactor = this.#direction === 'inward' ? 1 : -1;
118
+ const trailLength = particle.trail * this.#scale;
119
+ const tx = px + Math.cos(particle.angle) * trailLength * trailFactor;
120
+ const ty = py + Math.sin(particle.angle) * trailLength * trailFactor;
121
+
122
+ let intensity: number;
123
+
124
+ if (this.#direction === 'inward') {
125
+ intensity = particle.brightness * (1 - normalizedDistance);
126
+ } else {
127
+ intensity = particle.brightness * normalizedDistance;
128
+ }
129
+
130
+ const alpha = Math.max(0.05, Math.min(1, intensity));
131
+ const lineWidth = Math.max(0.5, particle.size * this.#scale * (0.5 + intensity * 0.5));
132
+
133
+ const gradient = ctx.createLinearGradient(px, py, tx, ty);
134
+ gradient.addColorStop(0, `rgba(${cr}, ${cg}, ${cb}, ${alpha})`);
135
+ gradient.addColorStop(1, `rgba(${cr}, ${cg}, ${cb}, 0)`);
136
+
137
+ ctx.globalAlpha = 1;
138
+ ctx.beginPath();
139
+ ctx.moveTo(px, py);
140
+ ctx.lineTo(tx, ty);
141
+ ctx.strokeStyle = gradient;
142
+ ctx.lineWidth = lineWidth;
143
+ ctx.stroke();
144
+
145
+ ctx.globalAlpha = alpha;
146
+ ctx.beginPath();
147
+ ctx.arc(px, py, lineWidth * 0.6, 0, Math.PI * 2);
148
+ ctx.fillStyle = `rgb(${cr}, ${cg}, ${cb})`;
149
+ ctx.fill();
150
+ }
151
+
152
+ ctx.globalCompositeOperation = 'source-over';
153
+ ctx.globalAlpha = 1;
154
+ }
155
+
156
+ #createParticle(spread: boolean): WormholeParticle {
157
+ const maxRadius = Math.sqrt((this.#width / 2) ** 2 + (this.#height / 2) ** 2);
158
+ const angle = MULBERRY.next() * Math.PI * 2;
159
+
160
+ let distance: number;
161
+
162
+ if (this.#direction === 'inward') {
163
+ distance = spread
164
+ ? MULBERRY.next() * maxRadius
165
+ : maxRadius * (0.8 + MULBERRY.next() * 0.2);
166
+ } else {
167
+ distance = spread
168
+ ? MULBERRY.next() * maxRadius
169
+ : MULBERRY.next() * maxRadius * 0.1;
170
+ }
171
+
172
+ return {
173
+ angle,
174
+ distance,
175
+ speed: 0.5 + MULBERRY.next() * 1.5,
176
+ size: 0.8 + MULBERRY.next() * 2.2,
177
+ brightness: 0.4 + MULBERRY.next() * 0.6,
178
+ trail: 5
179
+ };
180
+ }
181
+ }
@@ -0,0 +1,17 @@
1
+ import { SimulationCanvas } from '../simulation-canvas';
2
+ import { WormholeLayer } from './layer';
3
+
4
+ export interface WormholeSimulationConfig {
5
+ readonly count?: number;
6
+ readonly speed?: number;
7
+ readonly color?: string;
8
+ readonly direction?: import('./types').WormholeDirection;
9
+ readonly scale?: number;
10
+ readonly canvasOptions?: CanvasRenderingContext2DSettings;
11
+ }
12
+
13
+ export class WormholeSimulation extends SimulationCanvas {
14
+ constructor(canvas: HTMLCanvasElement, config: WormholeSimulationConfig = {}) {
15
+ super(canvas, new WormholeLayer(config), 60, config.canvasOptions ?? {colorSpace: 'display-p3'});
16
+ }
17
+ }
@@ -0,0 +1,10 @@
1
+ export type WormholeDirection = 'inward' | 'outward';
2
+
3
+ export type WormholeParticle = {
4
+ angle: number;
5
+ distance: number;
6
+ speed: number;
7
+ size: number;
8
+ brightness: number;
9
+ trail: number;
10
+ };