@basmilius/sparkle 2.3.0 → 2.5.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 (126) hide show
  1. package/dist/index.d.mts +637 -1
  2. package/dist/index.d.mts.map +1 -1
  3. package/dist/index.mjs +6964 -2577
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +1 -1
  6. package/src/balloons/layer.ts +4 -3
  7. package/src/black-hole/consts.ts +3 -0
  8. package/src/black-hole/index.ts +10 -0
  9. package/src/black-hole/layer.ts +193 -0
  10. package/src/black-hole/types.ts +8 -0
  11. package/src/boids/consts.ts +8 -0
  12. package/src/boids/index.ts +9 -0
  13. package/src/boids/layer.ts +245 -0
  14. package/src/boids/types.ts +7 -0
  15. package/src/butterflies/consts.ts +3 -0
  16. package/src/butterflies/index.ts +9 -0
  17. package/src/butterflies/layer.ts +246 -0
  18. package/src/butterflies/types.ts +23 -0
  19. package/src/caustics/consts.ts +3 -0
  20. package/src/caustics/index.ts +9 -0
  21. package/src/caustics/layer.ts +107 -0
  22. package/src/clouds/consts.ts +3 -0
  23. package/src/clouds/index.ts +9 -0
  24. package/src/clouds/layer.ts +167 -0
  25. package/src/clouds/types.ts +9 -0
  26. package/src/confetti/layer.ts +3 -2
  27. package/src/constellation/consts.ts +3 -0
  28. package/src/constellation/index.ts +10 -0
  29. package/src/constellation/layer.ts +256 -0
  30. package/src/constellation/types.ts +11 -0
  31. package/src/coral-reef/consts.ts +3 -0
  32. package/src/coral-reef/index.ts +10 -0
  33. package/src/coral-reef/layer.ts +276 -0
  34. package/src/coral-reef/types.ts +31 -0
  35. package/src/crystallization/consts.ts +3 -0
  36. package/src/crystallization/index.ts +10 -0
  37. package/src/crystallization/layer.ts +318 -0
  38. package/src/crystallization/types.ts +25 -0
  39. package/src/digital-rain/consts.ts +7 -0
  40. package/src/digital-rain/index.ts +10 -0
  41. package/src/digital-rain/layer.ts +195 -0
  42. package/src/digital-rain/types.ts +10 -0
  43. package/src/donuts/layer.ts +5 -3
  44. package/src/glitch/consts.ts +3 -0
  45. package/src/glitch/index.ts +9 -0
  46. package/src/glitch/layer.ts +231 -0
  47. package/src/glitch/types.ts +28 -0
  48. package/src/gradient-flow/consts.ts +3 -0
  49. package/src/gradient-flow/index.ts +9 -0
  50. package/src/gradient-flow/layer.ts +134 -0
  51. package/src/gradient-flow/types.ts +8 -0
  52. package/src/hologram/consts.ts +5 -0
  53. package/src/hologram/index.ts +9 -0
  54. package/src/hologram/layer.ts +205 -0
  55. package/src/hologram/types.ts +20 -0
  56. package/src/hyper-space/consts.ts +3 -0
  57. package/src/hyper-space/index.ts +10 -0
  58. package/src/hyper-space/layer.ts +167 -0
  59. package/src/hyper-space/types.ts +8 -0
  60. package/src/index.ts +29 -0
  61. package/src/interference/consts.ts +9 -0
  62. package/src/interference/index.ts +9 -0
  63. package/src/interference/layer.ts +129 -0
  64. package/src/kaleidoscope/consts.ts +12 -0
  65. package/src/kaleidoscope/index.ts +9 -0
  66. package/src/kaleidoscope/layer.ts +213 -0
  67. package/src/kaleidoscope/types.ts +19 -0
  68. package/src/lanterns/layer.ts +3 -2
  69. package/src/lava/consts.ts +3 -0
  70. package/src/lava/index.ts +9 -0
  71. package/src/lava/layer.ts +152 -0
  72. package/src/lava/types.ts +13 -0
  73. package/src/leaves/layer.ts +3 -2
  74. package/src/murmuration/consts.ts +3 -0
  75. package/src/murmuration/index.ts +10 -0
  76. package/src/murmuration/layer.ts +279 -0
  77. package/src/murmuration/types.ts +7 -0
  78. package/src/nebula/consts.ts +3 -0
  79. package/src/nebula/index.ts +10 -0
  80. package/src/nebula/layer.ts +150 -0
  81. package/src/nebula/types.ts +20 -0
  82. package/src/neon/consts.ts +5 -0
  83. package/src/neon/index.ts +9 -0
  84. package/src/neon/layer.ts +213 -0
  85. package/src/neon/types.ts +18 -0
  86. package/src/petals/layer.ts +3 -2
  87. package/src/pollen/consts.ts +3 -0
  88. package/src/pollen/index.ts +10 -0
  89. package/src/pollen/layer.ts +181 -0
  90. package/src/pollen/types.ts +10 -0
  91. package/src/popcorn/consts.ts +3 -0
  92. package/src/popcorn/index.ts +10 -0
  93. package/src/popcorn/layer.ts +218 -0
  94. package/src/popcorn/types.ts +13 -0
  95. package/src/portal/consts.ts +3 -0
  96. package/src/portal/index.ts +10 -0
  97. package/src/portal/layer.ts +251 -0
  98. package/src/portal/types.ts +10 -0
  99. package/src/pulse-grid/consts.ts +3 -0
  100. package/src/pulse-grid/index.ts +10 -0
  101. package/src/pulse-grid/layer.ts +185 -0
  102. package/src/pulse-grid/types.ts +8 -0
  103. package/src/roots/consts.ts +3 -0
  104. package/src/roots/index.ts +9 -0
  105. package/src/roots/layer.ts +218 -0
  106. package/src/roots/types.ts +23 -0
  107. package/src/smoke/consts.ts +3 -0
  108. package/src/smoke/index.ts +9 -0
  109. package/src/smoke/layer.ts +182 -0
  110. package/src/smoke/types.ts +14 -0
  111. package/src/snow/layer.ts +3 -2
  112. package/src/topography/consts.ts +3 -0
  113. package/src/topography/index.ts +9 -0
  114. package/src/topography/layer.ts +141 -0
  115. package/src/tornado/consts.ts +3 -0
  116. package/src/tornado/index.ts +10 -0
  117. package/src/tornado/layer.ts +271 -0
  118. package/src/tornado/types.ts +22 -0
  119. package/src/volcano/consts.ts +3 -0
  120. package/src/volcano/index.ts +10 -0
  121. package/src/volcano/layer.ts +261 -0
  122. package/src/volcano/types.ts +10 -0
  123. package/src/voronoi/consts.ts +3 -0
  124. package/src/voronoi/index.ts +10 -0
  125. package/src/voronoi/layer.ts +197 -0
  126. package/src/voronoi/types.ts +7 -0
@@ -0,0 +1,197 @@
1
+ import { hexToRGB } from '@basmilius/utils';
2
+ import { Effect } from '../effect';
3
+ import { MULBERRY } from './consts';
4
+ import type { VoronoiCell } from './types';
5
+
6
+ export interface VoronoiConfig {
7
+ readonly cells?: number;
8
+ readonly speed?: number;
9
+ readonly colors?: string[];
10
+ readonly edgeColor?: string;
11
+ readonly edgeWidth?: number;
12
+ readonly scale?: number;
13
+ }
14
+
15
+ const DEFAULT_COLORS = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#f9ca24', '#6c5ce7', '#fd79a8', '#00b894', '#e17055'];
16
+
17
+ export class Voronoi extends Effect<VoronoiConfig> {
18
+ #speed: number;
19
+ #scale: number;
20
+ readonly #cellCount: number;
21
+ readonly #edgeWidth: number;
22
+ readonly #colorStrings: string[];
23
+ readonly #edgeColor: string;
24
+ #cells: VoronoiCell[] = [];
25
+
26
+ constructor(config: VoronoiConfig = {}) {
27
+ super();
28
+
29
+ this.#speed = config.speed ?? 0.5;
30
+ this.#scale = config.scale ?? 1;
31
+ this.#cellCount = config.cells ?? 20;
32
+ this.#edgeWidth = config.edgeWidth ?? 2;
33
+
34
+ const colors = config.colors ?? DEFAULT_COLORS;
35
+ const colorRGBs = colors.map(c => hexToRGB(c));
36
+ this.#colorStrings = colorRGBs.map(([r, g, b]) => `rgb(${r}, ${g}, ${b})`);
37
+
38
+ const [er, eg, eb] = hexToRGB(config.edgeColor ?? '#ffffff');
39
+ this.#edgeColor = `rgb(${er}, ${eg}, ${eb})`;
40
+ }
41
+
42
+ configure(config: Partial<VoronoiConfig>): void {
43
+ if (config.speed !== undefined) {
44
+ this.#speed = config.speed;
45
+ }
46
+ if (config.scale !== undefined) {
47
+ this.#scale = config.scale;
48
+ }
49
+ }
50
+
51
+ onResize(width: number, height: number): void {
52
+ this.#cells = [];
53
+
54
+ for (let idx = 0; idx < this.#cellCount; idx++) {
55
+ this.#cells.push({
56
+ x: MULBERRY.next() * width,
57
+ y: MULBERRY.next() * height,
58
+ vx: (MULBERRY.next() - 0.5) * 60,
59
+ vy: (MULBERRY.next() - 0.5) * 60,
60
+ color: idx % this.#colorStrings.length
61
+ });
62
+ }
63
+ }
64
+
65
+ tick(dt: number, width: number, height: number): void {
66
+ const speed = this.#speed;
67
+
68
+ for (let idx = 0; idx < this.#cells.length; idx++) {
69
+ const cell = this.#cells[idx];
70
+
71
+ cell.x += cell.vx * dt * 0.02 * speed;
72
+ cell.y += cell.vy * dt * 0.02 * speed;
73
+
74
+ if (cell.x < 0) {
75
+ cell.x = 0;
76
+ cell.vx = -cell.vx;
77
+ } else if (cell.x > width) {
78
+ cell.x = width;
79
+ cell.vx = -cell.vx;
80
+ }
81
+
82
+ if (cell.y < 0) {
83
+ cell.y = 0;
84
+ cell.vy = -cell.vy;
85
+ } else if (cell.y > height) {
86
+ cell.y = height;
87
+ cell.vy = -cell.vy;
88
+ }
89
+ }
90
+ }
91
+
92
+ draw(ctx: CanvasRenderingContext2D, width: number, height: number): void {
93
+ const cells = this.#cells;
94
+ const cellCount = cells.length;
95
+
96
+ if (cellCount === 0) {
97
+ return;
98
+ }
99
+
100
+ const edgeWidth = this.#edgeWidth * this.#scale;
101
+ const pad = 2;
102
+ const bounds: [number, number][] = [
103
+ [-pad, -pad],
104
+ [width + pad, -pad],
105
+ [width + pad, height + pad],
106
+ [-pad, height + pad]
107
+ ];
108
+
109
+ for (let ci = 0; ci < cellCount; ci++) {
110
+ const cell = cells[ci];
111
+ let polygon = bounds;
112
+
113
+ for (let cj = 0; cj < cellCount; cj++) {
114
+ if (ci === cj) {
115
+ continue;
116
+ }
117
+
118
+ const other = cells[cj];
119
+ const mx = (cell.x + other.x) * 0.5;
120
+ const my = (cell.y + other.y) * 0.5;
121
+ const nx = other.x - cell.x;
122
+ const ny = other.y - cell.y;
123
+
124
+ polygon = this.#clipPolygon(polygon, mx, my, nx, ny);
125
+
126
+ if (polygon.length === 0) {
127
+ break;
128
+ }
129
+ }
130
+
131
+ if (polygon.length < 3) {
132
+ continue;
133
+ }
134
+
135
+ ctx.fillStyle = this.#colorStrings[cell.color];
136
+ ctx.beginPath();
137
+ ctx.moveTo(polygon[0][0], polygon[0][1]);
138
+
139
+ for (let vi = 1; vi < polygon.length; vi++) {
140
+ ctx.lineTo(polygon[vi][0], polygon[vi][1]);
141
+ }
142
+
143
+ ctx.closePath();
144
+ ctx.fill();
145
+
146
+ if (edgeWidth > 0) {
147
+ ctx.strokeStyle = this.#edgeColor;
148
+ ctx.lineWidth = edgeWidth;
149
+ ctx.lineJoin = 'round';
150
+ ctx.stroke();
151
+ }
152
+ }
153
+ }
154
+
155
+ #clipPolygon(polygon: [number, number][], mx: number, my: number, nx: number, ny: number): [number, number][] {
156
+ const output: [number, number][] = [];
157
+ const len = polygon.length;
158
+
159
+ if (len === 0) {
160
+ return output;
161
+ }
162
+
163
+ let prevX = polygon[len - 1][0];
164
+ let prevY = polygon[len - 1][1];
165
+ let prevDot = (prevX - mx) * nx + (prevY - my) * ny;
166
+
167
+ for (let vi = 0; vi < len; vi++) {
168
+ const currX = polygon[vi][0];
169
+ const currY = polygon[vi][1];
170
+ const currDot = (currX - mx) * nx + (currY - my) * ny;
171
+
172
+ if (currDot <= 0) {
173
+ if (prevDot > 0) {
174
+ const t = prevDot / (prevDot - currDot);
175
+ output.push([
176
+ prevX + (currX - prevX) * t,
177
+ prevY + (currY - prevY) * t
178
+ ]);
179
+ }
180
+
181
+ output.push([currX, currY]);
182
+ } else if (prevDot <= 0) {
183
+ const t = prevDot / (prevDot - currDot);
184
+ output.push([
185
+ prevX + (currX - prevX) * t,
186
+ prevY + (currY - prevY) * t
187
+ ]);
188
+ }
189
+
190
+ prevX = currX;
191
+ prevY = currY;
192
+ prevDot = currDot;
193
+ }
194
+
195
+ return output;
196
+ }
197
+ }
@@ -0,0 +1,7 @@
1
+ export type VoronoiCell = {
2
+ x: number;
3
+ y: number;
4
+ vx: number;
5
+ vy: number;
6
+ color: number;
7
+ };