react-grid-lights 1.0.0 → 1.0.2
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 +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +197 -86
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +197 -86
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -27,7 +27,11 @@ interface GridProps {
|
|
|
27
27
|
splitChance?: number;
|
|
28
28
|
/** Speed at which trails fade (lower = slower fade) */
|
|
29
29
|
trailFadeSpeed?: number;
|
|
30
|
+
/** Enable spawning particles from the bottom as well as the top */
|
|
31
|
+
bidirectional?: boolean;
|
|
32
|
+
/** Length of the light trail (number of history points) */
|
|
33
|
+
trailLength?: number;
|
|
30
34
|
}
|
|
31
|
-
declare function Grid({ shape, cellSize, lineColor, lineWidth, className, animated, lightColor, lightSpeed, minTravel, maxTravel, spawnRate, splitChance, trailFadeSpeed, }: GridProps): react_jsx_runtime.JSX.Element;
|
|
35
|
+
declare function Grid({ shape, cellSize, lineColor, lineWidth, className, animated, lightColor, lightSpeed, minTravel, maxTravel, spawnRate, splitChance, trailFadeSpeed, bidirectional, trailLength, }: GridProps): react_jsx_runtime.JSX.Element;
|
|
32
36
|
|
|
33
37
|
export { Grid, type GridProps, Grid as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -27,7 +27,11 @@ interface GridProps {
|
|
|
27
27
|
splitChance?: number;
|
|
28
28
|
/** Speed at which trails fade (lower = slower fade) */
|
|
29
29
|
trailFadeSpeed?: number;
|
|
30
|
+
/** Enable spawning particles from the bottom as well as the top */
|
|
31
|
+
bidirectional?: boolean;
|
|
32
|
+
/** Length of the light trail (number of history points) */
|
|
33
|
+
trailLength?: number;
|
|
30
34
|
}
|
|
31
|
-
declare function Grid({ shape, cellSize, lineColor, lineWidth, className, animated, lightColor, lightSpeed, minTravel, maxTravel, spawnRate, splitChance, trailFadeSpeed, }: GridProps): react_jsx_runtime.JSX.Element;
|
|
35
|
+
declare function Grid({ shape, cellSize, lineColor, lineWidth, className, animated, lightColor, lightSpeed, minTravel, maxTravel, spawnRate, splitChance, trailFadeSpeed, bidirectional, trailLength, }: GridProps): react_jsx_runtime.JSX.Element;
|
|
32
36
|
|
|
33
37
|
export { Grid, type GridProps, Grid as default };
|
package/dist/index.js
CHANGED
|
@@ -42,7 +42,9 @@ function Grid({
|
|
|
42
42
|
maxTravel = 6,
|
|
43
43
|
spawnRate = 1e3,
|
|
44
44
|
splitChance = 0.3,
|
|
45
|
-
trailFadeSpeed = 0.01
|
|
45
|
+
trailFadeSpeed = 0.01,
|
|
46
|
+
bidirectional = false,
|
|
47
|
+
trailLength = 15
|
|
46
48
|
}) {
|
|
47
49
|
const canvasRef = (0, import_react.useRef)(null);
|
|
48
50
|
const containerRef = (0, import_react.useRef)(null);
|
|
@@ -50,6 +52,7 @@ function Grid({
|
|
|
50
52
|
const edgesRef = (0, import_react.useRef)([]);
|
|
51
53
|
const adjacencyRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
52
54
|
const topNodesRef = (0, import_react.useRef)([]);
|
|
55
|
+
const bottomNodesRef = (0, import_react.useRef)([]);
|
|
53
56
|
const animationRef = (0, import_react.useRef)(0);
|
|
54
57
|
const particlesRef = (0, import_react.useRef)([]);
|
|
55
58
|
const trailsRef = (0, import_react.useRef)([]);
|
|
@@ -59,6 +62,7 @@ function Grid({
|
|
|
59
62
|
const activeEdgesRef = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
60
63
|
const explosionsRef = (0, import_react.useRef)([]);
|
|
61
64
|
const nodeGlowsRef = (0, import_react.useRef)([]);
|
|
65
|
+
const spawnFromTopRef = (0, import_react.useRef)(true);
|
|
62
66
|
const nodeKey = (x, y) => `${Math.round(x * 100)},${Math.round(y * 100)}`;
|
|
63
67
|
const edgeKey = (n1, n2) => {
|
|
64
68
|
const keys = [n1.key, n2.key].sort();
|
|
@@ -71,79 +75,98 @@ function Grid({
|
|
|
71
75
|
}
|
|
72
76
|
return nodesRef.current.get(key);
|
|
73
77
|
}, []);
|
|
74
|
-
const addEdge = (0, import_react.useCallback)(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
adjacencyRef.current.
|
|
84
|
-
|
|
85
|
-
if (!adjacencyRef.current.has(to.key)) {
|
|
86
|
-
adjacencyRef.current.set(to.key, []);
|
|
87
|
-
}
|
|
88
|
-
adjacencyRef.current.get(from.key).push(edge);
|
|
89
|
-
adjacencyRef.current.get(to.key).push(edge);
|
|
90
|
-
}, [getOrCreateNode]);
|
|
91
|
-
const buildSquareGraph = (0, import_react.useCallback)((width, height) => {
|
|
92
|
-
nodesRef.current.clear();
|
|
93
|
-
edgesRef.current = [];
|
|
94
|
-
adjacencyRef.current.clear();
|
|
95
|
-
topNodesRef.current = [];
|
|
96
|
-
const cols = Math.ceil(width / cellSize) + 1;
|
|
97
|
-
const rows = Math.ceil(height / cellSize) + 1;
|
|
98
|
-
for (let i = 0; i <= cols; i++) {
|
|
99
|
-
for (let j = 0; j <= rows; j++) {
|
|
100
|
-
const x = i * cellSize;
|
|
101
|
-
const y = j * cellSize;
|
|
102
|
-
if (i < cols) addEdge(x, y, x + cellSize, y);
|
|
103
|
-
if (j < rows) addEdge(x, y, x, y + cellSize);
|
|
78
|
+
const addEdge = (0, import_react.useCallback)(
|
|
79
|
+
(x1, y1, x2, y2) => {
|
|
80
|
+
const from = getOrCreateNode(x1, y1);
|
|
81
|
+
const to = getOrCreateNode(x2, y2);
|
|
82
|
+
const key = edgeKey(from, to);
|
|
83
|
+
const existingEdge = edgesRef.current.find((e) => e.key === key);
|
|
84
|
+
if (existingEdge) return;
|
|
85
|
+
const edge = { from, to, key };
|
|
86
|
+
edgesRef.current.push(edge);
|
|
87
|
+
if (!adjacencyRef.current.has(from.key)) {
|
|
88
|
+
adjacencyRef.current.set(from.key, []);
|
|
104
89
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
for (let
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
vertices.push({
|
|
129
|
-
x: cx + size * Math.cos(angle),
|
|
130
|
-
y: cy + size * Math.sin(angle)
|
|
131
|
-
});
|
|
90
|
+
if (!adjacencyRef.current.has(to.key)) {
|
|
91
|
+
adjacencyRef.current.set(to.key, []);
|
|
92
|
+
}
|
|
93
|
+
adjacencyRef.current.get(from.key).push(edge);
|
|
94
|
+
adjacencyRef.current.get(to.key).push(edge);
|
|
95
|
+
},
|
|
96
|
+
[getOrCreateNode]
|
|
97
|
+
);
|
|
98
|
+
const buildSquareGraph = (0, import_react.useCallback)(
|
|
99
|
+
(width, height) => {
|
|
100
|
+
nodesRef.current.clear();
|
|
101
|
+
edgesRef.current = [];
|
|
102
|
+
adjacencyRef.current.clear();
|
|
103
|
+
topNodesRef.current = [];
|
|
104
|
+
bottomNodesRef.current = [];
|
|
105
|
+
const cols = Math.ceil(width / cellSize) + 1;
|
|
106
|
+
const rows = Math.ceil(height / cellSize) + 1;
|
|
107
|
+
for (let i = 0; i <= cols; i++) {
|
|
108
|
+
for (let j = 0; j <= rows; j++) {
|
|
109
|
+
const x = i * cellSize;
|
|
110
|
+
const y = j * cellSize;
|
|
111
|
+
if (i < cols) addEdge(x, y, x + cellSize, y);
|
|
112
|
+
if (j < rows) addEdge(x, y, x, y + cellSize);
|
|
132
113
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
114
|
+
}
|
|
115
|
+
const maxY = rows * cellSize;
|
|
116
|
+
for (let i = 0; i <= cols; i++) {
|
|
117
|
+
const topNode = nodesRef.current.get(nodeKey(i * cellSize, 0));
|
|
118
|
+
if (topNode) topNodesRef.current.push(topNode);
|
|
119
|
+
const bottomNode = nodesRef.current.get(nodeKey(i * cellSize, maxY));
|
|
120
|
+
if (bottomNode) bottomNodesRef.current.push(bottomNode);
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
[cellSize, addEdge]
|
|
124
|
+
);
|
|
125
|
+
const buildHexGraph = (0, import_react.useCallback)(
|
|
126
|
+
(width, height) => {
|
|
127
|
+
nodesRef.current.clear();
|
|
128
|
+
edgesRef.current = [];
|
|
129
|
+
adjacencyRef.current.clear();
|
|
130
|
+
topNodesRef.current = [];
|
|
131
|
+
bottomNodesRef.current = [];
|
|
132
|
+
const size = cellSize / 2;
|
|
133
|
+
const hexWidth = Math.sqrt(3) * size;
|
|
134
|
+
const vertSpacing = size * 1.5;
|
|
135
|
+
const cols = Math.ceil(width / hexWidth) + 2;
|
|
136
|
+
const rows = Math.ceil(height / vertSpacing) + 2;
|
|
137
|
+
for (let row = -1; row < rows; row++) {
|
|
138
|
+
for (let col = -1; col < cols; col++) {
|
|
139
|
+
const cx = col * hexWidth + (row % 2 === 0 ? 0 : hexWidth / 2);
|
|
140
|
+
const cy = row * vertSpacing;
|
|
141
|
+
const vertices = [];
|
|
142
|
+
for (let i = 0; i < 6; i++) {
|
|
143
|
+
const angle = Math.PI / 3 * i - Math.PI / 2;
|
|
144
|
+
vertices.push({
|
|
145
|
+
x: cx + size * Math.cos(angle),
|
|
146
|
+
y: cy + size * Math.sin(angle)
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
for (let i = 0; i < 6; i++) {
|
|
150
|
+
const v1 = vertices[i];
|
|
151
|
+
const v2 = vertices[(i + 1) % 6];
|
|
152
|
+
addEdge(v1.x, v1.y, v2.x, v2.y);
|
|
153
|
+
}
|
|
137
154
|
}
|
|
138
155
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
156
|
+
const allNodes = Array.from(nodesRef.current.values());
|
|
157
|
+
const visibleNodes = allNodes.filter((n) => n.y >= 0 && n.y <= height);
|
|
158
|
+
topNodesRef.current = visibleNodes.filter((n) => n.y <= size * 2).sort((a, b) => a.x - b.x);
|
|
159
|
+
bottomNodesRef.current = visibleNodes.filter((n) => n.y >= height - size * 2).sort((a, b) => a.x - b.x);
|
|
160
|
+
},
|
|
161
|
+
[cellSize, addEdge]
|
|
162
|
+
);
|
|
163
|
+
const getConnectedNodes = (0, import_react.useCallback)(
|
|
164
|
+
(node, excludeNode) => {
|
|
165
|
+
const edges = adjacencyRef.current.get(node.key) || [];
|
|
166
|
+
return edges.map((e) => e.from.key === node.key ? e.to : e.from).filter((n) => !excludeNode || n.key !== excludeNode.key);
|
|
167
|
+
},
|
|
168
|
+
[]
|
|
169
|
+
);
|
|
147
170
|
(0, import_react.useEffect)(() => {
|
|
148
171
|
const canvas = canvasRef.current;
|
|
149
172
|
const container = containerRef.current;
|
|
@@ -186,11 +209,44 @@ function Grid({
|
|
|
186
209
|
const drawParticles = (ctx) => {
|
|
187
210
|
for (const particle of particlesRef.current) {
|
|
188
211
|
if (particle.dead) continue;
|
|
189
|
-
const
|
|
190
|
-
|
|
212
|
+
const history = particle.history;
|
|
213
|
+
if (history.length === 0) continue;
|
|
214
|
+
const head = history[history.length - 1];
|
|
215
|
+
if (history.length >= 2) {
|
|
216
|
+
ctx.lineCap = "round";
|
|
217
|
+
ctx.lineJoin = "round";
|
|
218
|
+
const r = parseInt(lightColor.slice(1, 3), 16);
|
|
219
|
+
const g = parseInt(lightColor.slice(3, 5), 16);
|
|
220
|
+
const b = parseInt(lightColor.slice(5, 7), 16);
|
|
221
|
+
const lighterR = Math.floor(r + (255 - r) * 0.6);
|
|
222
|
+
const lighterG = Math.floor(g + (255 - g) * 0.6);
|
|
223
|
+
const lighterB = Math.floor(b + (255 - b) * 0.6);
|
|
224
|
+
ctx.strokeStyle = `rgb(${lighterR}, ${lighterG}, ${lighterB})`;
|
|
225
|
+
const maxWidth = 4;
|
|
226
|
+
const minWidth = 0.5;
|
|
227
|
+
for (let i = 1; i < history.length; i++) {
|
|
228
|
+
const progress = i / (history.length - 1);
|
|
229
|
+
ctx.lineWidth = minWidth + (maxWidth - minWidth) * progress;
|
|
230
|
+
ctx.beginPath();
|
|
231
|
+
ctx.moveTo(history[i - 1].x, history[i - 1].y);
|
|
232
|
+
ctx.lineTo(history[i].x, history[i].y);
|
|
233
|
+
ctx.stroke();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
191
236
|
ctx.fillStyle = lightColor;
|
|
192
237
|
ctx.beginPath();
|
|
193
|
-
|
|
238
|
+
let angle = 0;
|
|
239
|
+
if (history.length >= 2) {
|
|
240
|
+
const prev = history[history.length - 2];
|
|
241
|
+
angle = Math.atan2(head.y - prev.y, head.x - prev.x);
|
|
242
|
+
}
|
|
243
|
+
ctx.save();
|
|
244
|
+
ctx.translate(head.x, head.y);
|
|
245
|
+
ctx.rotate(angle);
|
|
246
|
+
ctx.moveTo(-3, 0);
|
|
247
|
+
ctx.quadraticCurveTo(1, -2.5, 2, 0);
|
|
248
|
+
ctx.quadraticCurveTo(1, 2.5, -3, 0);
|
|
249
|
+
ctx.restore();
|
|
194
250
|
ctx.fill();
|
|
195
251
|
}
|
|
196
252
|
};
|
|
@@ -210,7 +266,9 @@ function Grid({
|
|
|
210
266
|
explosion.radius += 0.5;
|
|
211
267
|
explosion.opacity -= 0.08;
|
|
212
268
|
}
|
|
213
|
-
explosionsRef.current = explosionsRef.current.filter(
|
|
269
|
+
explosionsRef.current = explosionsRef.current.filter(
|
|
270
|
+
(e) => e.opacity > 0
|
|
271
|
+
);
|
|
214
272
|
};
|
|
215
273
|
const createExplosion = (x, y) => {
|
|
216
274
|
explosionsRef.current.push({
|
|
@@ -251,17 +309,21 @@ function Grid({
|
|
|
251
309
|
const keys = [n1.key, n2.key].sort();
|
|
252
310
|
return `${keys[0]}-${keys[1]}`;
|
|
253
311
|
};
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
const
|
|
312
|
+
const trySpawn = (fromTop) => {
|
|
313
|
+
const sourceNodes = fromTop ? topNodesRef.current : bottomNodesRef.current;
|
|
314
|
+
const direction = fromTop ? 1 : -1;
|
|
315
|
+
if (sourceNodes.length === 0) return false;
|
|
316
|
+
const startNode = sourceNodes[Math.floor(Math.random() * sourceNodes.length)];
|
|
257
317
|
const connectedNodes = getConnectedNodes(startNode);
|
|
258
|
-
const
|
|
259
|
-
|
|
318
|
+
const preferredNodes = connectedNodes.filter(
|
|
319
|
+
(n) => fromTop ? n.y > startNode.y : n.y < startNode.y
|
|
320
|
+
);
|
|
321
|
+
const targetNodes = preferredNodes.length > 0 ? preferredNodes : connectedNodes;
|
|
260
322
|
const availableNodes = targetNodes.filter((n) => {
|
|
261
323
|
const key = makeEdgeKey(startNode, n);
|
|
262
324
|
return !activeEdgesRef.current.has(key);
|
|
263
325
|
});
|
|
264
|
-
if (availableNodes.length === 0) return;
|
|
326
|
+
if (availableNodes.length === 0) return false;
|
|
265
327
|
const targetNode = availableNodes[Math.floor(Math.random() * availableNodes.length)];
|
|
266
328
|
const edgeKeyStr = makeEdgeKey(startNode, targetNode);
|
|
267
329
|
activeEdgesRef.current.add(edgeKeyStr);
|
|
@@ -273,7 +335,9 @@ function Grid({
|
|
|
273
335
|
traveled: 0,
|
|
274
336
|
maxTravel: getRandomTravel(),
|
|
275
337
|
canSplit: true,
|
|
276
|
-
dead: false
|
|
338
|
+
dead: false,
|
|
339
|
+
direction,
|
|
340
|
+
history: [{ x: startNode.x, y: startNode.y }]
|
|
277
341
|
});
|
|
278
342
|
trailsRef.current.push({
|
|
279
343
|
fromX: startNode.x,
|
|
@@ -284,17 +348,39 @@ function Grid({
|
|
|
284
348
|
opacity: 1,
|
|
285
349
|
edgeKey: edgeKeyStr
|
|
286
350
|
});
|
|
351
|
+
return true;
|
|
352
|
+
};
|
|
353
|
+
const spawnParticle = () => {
|
|
354
|
+
if (bidirectional) {
|
|
355
|
+
const fromTop = spawnFromTopRef.current;
|
|
356
|
+
spawnFromTopRef.current = !spawnFromTopRef.current;
|
|
357
|
+
if (!trySpawn(fromTop)) {
|
|
358
|
+
trySpawn(!fromTop);
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
trySpawn(true);
|
|
362
|
+
}
|
|
287
363
|
};
|
|
288
364
|
const updateParticles = () => {
|
|
289
365
|
const newParticles = [];
|
|
366
|
+
const maxHistoryLength = trailLength;
|
|
290
367
|
for (const particle of particlesRef.current) {
|
|
291
368
|
if (particle.dead) continue;
|
|
292
369
|
particle.progress += lightSpeed * 0.02;
|
|
370
|
+
const currentX = particle.currentNode.x + (particle.targetNode.x - particle.currentNode.x) * particle.progress;
|
|
371
|
+
const currentY = particle.currentNode.y + (particle.targetNode.y - particle.currentNode.y) * particle.progress;
|
|
372
|
+
particle.history.push({ x: currentX, y: currentY });
|
|
373
|
+
if (particle.history.length > maxHistoryLength) {
|
|
374
|
+
particle.history.shift();
|
|
375
|
+
}
|
|
293
376
|
const trailIndex = trailsRef.current.findIndex(
|
|
294
377
|
(t) => t.fromX === particle.currentNode.x && t.fromY === particle.currentNode.y && t.toX === particle.targetNode.x && t.toY === particle.targetNode.y && t.progress < 1
|
|
295
378
|
);
|
|
296
379
|
if (trailIndex !== -1) {
|
|
297
|
-
trailsRef.current[trailIndex].progress = Math.min(
|
|
380
|
+
trailsRef.current[trailIndex].progress = Math.min(
|
|
381
|
+
particle.progress,
|
|
382
|
+
1
|
|
383
|
+
);
|
|
298
384
|
}
|
|
299
385
|
if (particle.progress >= 1) {
|
|
300
386
|
createNodeGlow(particle.targetNode.x, particle.targetNode.y);
|
|
@@ -307,7 +393,10 @@ function Grid({
|
|
|
307
393
|
continue;
|
|
308
394
|
}
|
|
309
395
|
const currentNode = particle.targetNode;
|
|
310
|
-
const connectedNodes = getConnectedNodes(
|
|
396
|
+
const connectedNodes = getConnectedNodes(
|
|
397
|
+
currentNode,
|
|
398
|
+
particle.currentNode
|
|
399
|
+
);
|
|
311
400
|
const availableNodes = connectedNodes.filter((n) => {
|
|
312
401
|
const key = makeEdgeKey(currentNode, n);
|
|
313
402
|
return !activeEdgesRef.current.has(key);
|
|
@@ -319,7 +408,9 @@ function Grid({
|
|
|
319
408
|
}
|
|
320
409
|
const shouldSplit = particle.canSplit && Math.random() < splitChance && availableNodes.length >= 2;
|
|
321
410
|
if (shouldSplit) {
|
|
322
|
-
const shuffled = [...availableNodes].sort(
|
|
411
|
+
const shuffled = [...availableNodes].sort(
|
|
412
|
+
() => Math.random() - 0.5
|
|
413
|
+
);
|
|
323
414
|
const target1 = shuffled[0];
|
|
324
415
|
const target2 = shuffled[1];
|
|
325
416
|
const edgeKey1 = makeEdgeKey(currentNode, target1);
|
|
@@ -347,7 +438,9 @@ function Grid({
|
|
|
347
438
|
traveled: particle.traveled,
|
|
348
439
|
maxTravel: particle.maxTravel,
|
|
349
440
|
canSplit: false,
|
|
350
|
-
dead: false
|
|
441
|
+
dead: false,
|
|
442
|
+
direction: particle.direction,
|
|
443
|
+
history: [{ x: currentNode.x, y: currentNode.y }]
|
|
351
444
|
});
|
|
352
445
|
trailsRef.current.push({
|
|
353
446
|
fromX: currentNode.x,
|
|
@@ -445,7 +538,25 @@ function Grid({
|
|
|
445
538
|
resizeObserver.disconnect();
|
|
446
539
|
cancelAnimationFrame(animationRef.current);
|
|
447
540
|
};
|
|
448
|
-
}, [
|
|
541
|
+
}, [
|
|
542
|
+
shape,
|
|
543
|
+
cellSize,
|
|
544
|
+
lineColor,
|
|
545
|
+
lineWidth,
|
|
546
|
+
animated,
|
|
547
|
+
lightColor,
|
|
548
|
+
lightSpeed,
|
|
549
|
+
minTravel,
|
|
550
|
+
maxTravel,
|
|
551
|
+
spawnRate,
|
|
552
|
+
splitChance,
|
|
553
|
+
trailFadeSpeed,
|
|
554
|
+
bidirectional,
|
|
555
|
+
trailLength,
|
|
556
|
+
buildSquareGraph,
|
|
557
|
+
buildHexGraph,
|
|
558
|
+
getConnectedNodes
|
|
559
|
+
]);
|
|
449
560
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: containerRef, className: `relative w-full h-full ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("canvas", { ref: canvasRef, className: "absolute inset-0" }) });
|
|
450
561
|
}
|
|
451
562
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/Grid.tsx"],"sourcesContent":["export { Grid, type GridProps } from \"./Grid\";\nexport { Grid as default } from \"./Grid\";\n","\"use client\";\n\nimport { useEffect, useRef, useCallback } from \"react\";\n\nexport interface GridProps {\n /** Grid shape: 4 for squares, 6 for hexagons */\n shape?: 4 | 6;\n /** Size of each cell in pixels */\n cellSize?: number;\n /** Color of the grid lines (use \"transparent\" to hide) */\n lineColor?: string;\n /** Width of the grid lines */\n lineWidth?: number;\n /** Additional CSS classes */\n className?: string;\n /** Enable animated light particles */\n animated?: boolean;\n /** Color of the light particles and trails */\n lightColor?: string;\n /** Speed of the light particles (1-5 recommended) */\n lightSpeed?: number;\n /** Minimum travel distance before particle dies */\n minTravel?: number;\n /** Maximum travel distance before particle dies */\n maxTravel?: number;\n /** Milliseconds between particle spawns */\n spawnRate?: number;\n /** Probability of particle splitting (0-1) */\n splitChance?: number;\n /** Speed at which trails fade (lower = slower fade) */\n trailFadeSpeed?: number;\n}\n\ninterface Node {\n x: number;\n y: number;\n key: string;\n}\n\ninterface Edge {\n from: Node;\n to: Node;\n key: string;\n}\n\ninterface Particle {\n id: number;\n currentNode: Node;\n targetNode: Node;\n progress: number;\n traveled: number;\n maxTravel: number;\n canSplit: boolean;\n dead: boolean;\n}\n\ninterface Trail {\n fromX: number;\n fromY: number;\n toX: number;\n toY: number;\n progress: number;\n opacity: number;\n edgeKey: string;\n}\n\ninterface Explosion {\n x: number;\n y: number;\n radius: number;\n maxRadius: number;\n opacity: number;\n}\n\ninterface NodeGlow {\n x: number;\n y: number;\n opacity: number;\n}\n\nexport function Grid({\n shape = 4,\n cellSize = 40,\n lineColor = \"#e5e7eb\",\n lineWidth = 1,\n className = \"\",\n animated = false,\n lightColor = \"#3b82f6\",\n lightSpeed = 2,\n minTravel = 2,\n maxTravel = 6,\n spawnRate = 1000,\n splitChance = 0.3,\n trailFadeSpeed = 0.01,\n}: GridProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const nodesRef = useRef<Map<string, Node>>(new Map());\n const edgesRef = useRef<Edge[]>([]);\n const adjacencyRef = useRef<Map<string, Edge[]>>(new Map());\n const topNodesRef = useRef<Node[]>([]);\n const animationRef = useRef<number>(0);\n const particlesRef = useRef<Particle[]>([]);\n const trailsRef = useRef<Trail[]>([]);\n const lastSpawnRef = useRef<number>(0);\n const particleIdRef = useRef<number>(0);\n const dimensionsRef = useRef({ width: 0, height: 0 });\n const activeEdgesRef = useRef<Set<string>>(new Set());\n const explosionsRef = useRef<Explosion[]>([]);\n const nodeGlowsRef = useRef<NodeGlow[]>([]);\n\n const nodeKey = (x: number, y: number) => `${Math.round(x * 100)},${Math.round(y * 100)}`;\n const edgeKey = (n1: Node, n2: Node) => {\n const keys = [n1.key, n2.key].sort();\n return `${keys[0]}-${keys[1]}`;\n };\n\n const getOrCreateNode = useCallback((x: number, y: number): Node => {\n const key = nodeKey(x, y);\n if (!nodesRef.current.has(key)) {\n nodesRef.current.set(key, { x, y, key });\n }\n return nodesRef.current.get(key)!;\n }, []);\n\n const addEdge = useCallback((x1: number, y1: number, x2: number, y2: number) => {\n const from = getOrCreateNode(x1, y1);\n const to = getOrCreateNode(x2, y2);\n const key = edgeKey(from, to);\n\n const existingEdge = edgesRef.current.find(e => e.key === key);\n if (existingEdge) return;\n\n const edge: Edge = { from, to, key };\n edgesRef.current.push(edge);\n\n if (!adjacencyRef.current.has(from.key)) {\n adjacencyRef.current.set(from.key, []);\n }\n if (!adjacencyRef.current.has(to.key)) {\n adjacencyRef.current.set(to.key, []);\n }\n adjacencyRef.current.get(from.key)!.push(edge);\n adjacencyRef.current.get(to.key)!.push(edge);\n }, [getOrCreateNode]);\n\n const buildSquareGraph = useCallback((width: number, height: number) => {\n nodesRef.current.clear();\n edgesRef.current = [];\n adjacencyRef.current.clear();\n topNodesRef.current = [];\n\n const cols = Math.ceil(width / cellSize) + 1;\n const rows = Math.ceil(height / cellSize) + 1;\n\n for (let i = 0; i <= cols; i++) {\n for (let j = 0; j <= rows; j++) {\n const x = i * cellSize;\n const y = j * cellSize;\n if (i < cols) addEdge(x, y, x + cellSize, y);\n if (j < rows) addEdge(x, y, x, y + cellSize);\n }\n }\n\n for (let i = 0; i <= cols; i++) {\n const node = nodesRef.current.get(nodeKey(i * cellSize, 0));\n if (node) topNodesRef.current.push(node);\n }\n }, [cellSize, addEdge]);\n\n const buildHexGraph = useCallback((width: number, height: number) => {\n nodesRef.current.clear();\n edgesRef.current = [];\n adjacencyRef.current.clear();\n topNodesRef.current = [];\n\n const size = cellSize / 2;\n const hexWidth = Math.sqrt(3) * size;\n const vertSpacing = size * 1.5;\n\n const cols = Math.ceil(width / hexWidth) + 2;\n const rows = Math.ceil(height / vertSpacing) + 2;\n\n for (let row = -1; row < rows; row++) {\n for (let col = -1; col < cols; col++) {\n const cx = col * hexWidth + (row % 2 === 0 ? 0 : hexWidth / 2);\n const cy = row * vertSpacing;\n\n const vertices: { x: number; y: number }[] = [];\n for (let i = 0; i < 6; i++) {\n const angle = (Math.PI / 3) * i - Math.PI / 2;\n vertices.push({\n x: cx + size * Math.cos(angle),\n y: cy + size * Math.sin(angle),\n });\n }\n\n for (let i = 0; i < 6; i++) {\n const v1 = vertices[i];\n const v2 = vertices[(i + 1) % 6];\n addEdge(v1.x, v1.y, v2.x, v2.y);\n }\n }\n }\n\n const sortedNodes = Array.from(nodesRef.current.values())\n .filter(n => n.y >= 0 && n.y <= size)\n .sort((a, b) => a.x - b.x);\n topNodesRef.current = sortedNodes;\n }, [cellSize, addEdge]);\n\n const getConnectedNodes = useCallback((node: Node, excludeNode?: Node): Node[] => {\n const edges = adjacencyRef.current.get(node.key) || [];\n return edges\n .map(e => (e.from.key === node.key ? e.to : e.from))\n .filter(n => !excludeNode || n.key !== excludeNode.key);\n }, []);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n const container = containerRef.current;\n if (!canvas || !container) return;\n\n let dpr = 1;\n\n const drawGrid = (ctx: CanvasRenderingContext2D, width: number, height: number) => {\n ctx.clearRect(0, 0, width, height);\n ctx.strokeStyle = lineColor;\n ctx.lineWidth = lineWidth;\n ctx.beginPath();\n\n for (const edge of edgesRef.current) {\n ctx.moveTo(edge.from.x, edge.from.y);\n ctx.lineTo(edge.to.x, edge.to.y);\n }\n\n ctx.stroke();\n };\n\n const drawTrails = (ctx: CanvasRenderingContext2D) => {\n for (const trail of trailsRef.current) {\n if (trail.opacity <= 0) continue;\n\n const alpha = Math.floor(trail.opacity * 0.08 * 255).toString(16).padStart(2, '0');\n\n ctx.strokeStyle = lightColor + alpha;\n ctx.lineWidth = 1;\n ctx.lineCap = \"round\";\n ctx.beginPath();\n ctx.moveTo(trail.fromX, trail.fromY);\n\n if (trail.progress < 1) {\n const endX = trail.fromX + (trail.toX - trail.fromX) * trail.progress;\n const endY = trail.fromY + (trail.toY - trail.fromY) * trail.progress;\n ctx.lineTo(endX, endY);\n } else {\n ctx.lineTo(trail.toX, trail.toY);\n }\n ctx.stroke();\n\n ctx.shadowColor = lightColor;\n ctx.shadowBlur = 2;\n ctx.stroke();\n ctx.shadowBlur = 0;\n }\n };\n\n const drawParticles = (ctx: CanvasRenderingContext2D) => {\n for (const particle of particlesRef.current) {\n if (particle.dead) continue;\n\n const x = particle.currentNode.x + (particle.targetNode.x - particle.currentNode.x) * particle.progress;\n const y = particle.currentNode.y + (particle.targetNode.y - particle.currentNode.y) * particle.progress;\n\n ctx.fillStyle = lightColor;\n ctx.beginPath();\n ctx.arc(x, y, 3, 0, Math.PI * 2);\n ctx.fill();\n }\n };\n\n const drawExplosions = (ctx: CanvasRenderingContext2D) => {\n for (const explosion of explosionsRef.current) {\n if (explosion.opacity <= 0) continue;\n\n const alpha = Math.floor(explosion.opacity * 255).toString(16).padStart(2, '0');\n ctx.strokeStyle = lightColor + alpha;\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.arc(explosion.x, explosion.y, explosion.radius, 0, Math.PI * 2);\n ctx.stroke();\n }\n };\n\n const updateExplosions = () => {\n for (const explosion of explosionsRef.current) {\n explosion.radius += 0.5;\n explosion.opacity -= 0.08;\n }\n explosionsRef.current = explosionsRef.current.filter(e => e.opacity > 0);\n };\n\n const createExplosion = (x: number, y: number) => {\n explosionsRef.current.push({\n x,\n y,\n radius: 2,\n maxRadius: 8,\n opacity: 1,\n });\n };\n\n const createNodeGlow = (x: number, y: number) => {\n nodeGlowsRef.current.push({\n x,\n y,\n opacity: 1,\n });\n };\n\n const drawNodeGlows = (ctx: CanvasRenderingContext2D) => {\n for (const glow of nodeGlowsRef.current) {\n if (glow.opacity <= 0) continue;\n\n const alpha = Math.floor(glow.opacity * 0.4 * 255).toString(16).padStart(2, '0');\n ctx.fillStyle = lightColor + alpha;\n ctx.beginPath();\n ctx.arc(glow.x, glow.y, 2, 0, Math.PI * 2);\n ctx.fill();\n }\n };\n\n const updateNodeGlows = () => {\n for (const glow of nodeGlowsRef.current) {\n glow.opacity -= trailFadeSpeed * 3;\n }\n nodeGlowsRef.current = nodeGlowsRef.current.filter(g => g.opacity > 0);\n };\n\n const getRandomTravel = () => {\n return Math.floor(Math.random() * (maxTravel - minTravel + 1)) + minTravel;\n };\n\n const makeEdgeKey = (n1: Node, n2: Node) => {\n const keys = [n1.key, n2.key].sort();\n return `${keys[0]}-${keys[1]}`;\n };\n\n const spawnParticle = () => {\n if (topNodesRef.current.length === 0) return;\n\n const startNode = topNodesRef.current[Math.floor(Math.random() * topNodesRef.current.length)];\n const connectedNodes = getConnectedNodes(startNode);\n\n const downwardNodes = connectedNodes.filter(n => n.y > startNode.y);\n const targetNodes = downwardNodes.length > 0 ? downwardNodes : connectedNodes;\n\n const availableNodes = targetNodes.filter(n => {\n const key = makeEdgeKey(startNode, n);\n return !activeEdgesRef.current.has(key);\n });\n\n if (availableNodes.length === 0) return;\n\n const targetNode = availableNodes[Math.floor(Math.random() * availableNodes.length)];\n const edgeKeyStr = makeEdgeKey(startNode, targetNode);\n activeEdgesRef.current.add(edgeKeyStr);\n\n particlesRef.current.push({\n id: particleIdRef.current++,\n currentNode: startNode,\n targetNode,\n progress: 0,\n traveled: 0,\n maxTravel: getRandomTravel(),\n canSplit: true,\n dead: false,\n });\n\n trailsRef.current.push({\n fromX: startNode.x,\n fromY: startNode.y,\n toX: targetNode.x,\n toY: targetNode.y,\n progress: 0,\n opacity: 1,\n edgeKey: edgeKeyStr,\n });\n };\n\n const updateParticles = () => {\n const newParticles: Particle[] = [];\n\n for (const particle of particlesRef.current) {\n if (particle.dead) continue;\n\n particle.progress += lightSpeed * 0.02;\n\n const trailIndex = trailsRef.current.findIndex(\n t => t.fromX === particle.currentNode.x &&\n t.fromY === particle.currentNode.y &&\n t.toX === particle.targetNode.x &&\n t.toY === particle.targetNode.y &&\n t.progress < 1\n );\n if (trailIndex !== -1) {\n trailsRef.current[trailIndex].progress = Math.min(particle.progress, 1);\n }\n\n if (particle.progress >= 1) {\n createNodeGlow(particle.targetNode.x, particle.targetNode.y);\n particle.traveled++;\n\n if (particle.traveled >= particle.maxTravel) {\n const x = particle.targetNode.x;\n const y = particle.targetNode.y;\n createExplosion(x, y);\n particle.dead = true;\n continue;\n }\n\n const currentNode = particle.targetNode;\n const connectedNodes = getConnectedNodes(currentNode, particle.currentNode);\n\n const availableNodes = connectedNodes.filter(n => {\n const key = makeEdgeKey(currentNode, n);\n return !activeEdgesRef.current.has(key);\n });\n\n if (availableNodes.length === 0) {\n createExplosion(currentNode.x, currentNode.y);\n particle.dead = true;\n continue;\n }\n\n const shouldSplit = particle.canSplit && Math.random() < splitChance && availableNodes.length >= 2;\n\n if (shouldSplit) {\n const shuffled = [...availableNodes].sort(() => Math.random() - 0.5);\n const target1 = shuffled[0];\n const target2 = shuffled[1];\n\n const edgeKey1 = makeEdgeKey(currentNode, target1);\n const edgeKey2 = makeEdgeKey(currentNode, target2);\n activeEdgesRef.current.add(edgeKey1);\n activeEdgesRef.current.add(edgeKey2);\n\n particle.currentNode = currentNode;\n particle.targetNode = target1;\n particle.progress = 0;\n particle.canSplit = false;\n\n trailsRef.current.push({\n fromX: currentNode.x,\n fromY: currentNode.y,\n toX: target1.x,\n toY: target1.y,\n progress: 0,\n opacity: 1,\n edgeKey: edgeKey1,\n });\n\n newParticles.push({\n id: particleIdRef.current++,\n currentNode: currentNode,\n targetNode: target2,\n progress: 0,\n traveled: particle.traveled,\n maxTravel: particle.maxTravel,\n canSplit: false,\n dead: false,\n });\n\n trailsRef.current.push({\n fromX: currentNode.x,\n fromY: currentNode.y,\n toX: target2.x,\n toY: target2.y,\n progress: 0,\n opacity: 1,\n edgeKey: edgeKey2,\n });\n } else {\n const targetNode = availableNodes[Math.floor(Math.random() * availableNodes.length)];\n const newEdgeKey = makeEdgeKey(currentNode, targetNode);\n activeEdgesRef.current.add(newEdgeKey);\n\n particle.currentNode = currentNode;\n particle.targetNode = targetNode;\n particle.progress = 0;\n\n trailsRef.current.push({\n fromX: currentNode.x,\n fromY: currentNode.y,\n toX: targetNode.x,\n toY: targetNode.y,\n progress: 0,\n opacity: 1,\n edgeKey: newEdgeKey,\n });\n }\n }\n }\n\n particlesRef.current.push(...newParticles);\n particlesRef.current = particlesRef.current.filter(p => !p.dead);\n };\n\n const updateTrails = () => {\n for (const trail of trailsRef.current) {\n if (trail.progress >= 1) {\n trail.opacity -= trailFadeSpeed;\n }\n }\n const fadedTrails = trailsRef.current.filter(t => t.opacity <= 0);\n for (const trail of fadedTrails) {\n activeEdgesRef.current.delete(trail.edgeKey);\n }\n trailsRef.current = trailsRef.current.filter(t => t.opacity > 0);\n };\n\n const animate = (timestamp: number) => {\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n const { width, height } = dimensionsRef.current;\n\n ctx.save();\n ctx.scale(dpr, dpr);\n drawGrid(ctx, width, height);\n\n if (animated) {\n if (timestamp - lastSpawnRef.current > spawnRate) {\n spawnParticle();\n lastSpawnRef.current = timestamp;\n }\n\n updateParticles();\n updateTrails();\n updateExplosions();\n updateNodeGlows();\n drawTrails(ctx);\n drawNodeGlows(ctx);\n drawParticles(ctx);\n drawExplosions(ctx);\n }\n\n ctx.restore();\n animationRef.current = requestAnimationFrame(animate);\n };\n\n const setup = () => {\n const { width, height } = container.getBoundingClientRect();\n dimensionsRef.current = { width, height };\n dpr = window.devicePixelRatio || 1;\n\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n\n if (shape === 4) {\n buildSquareGraph(width, height);\n } else {\n buildHexGraph(width, height);\n }\n\n particlesRef.current = [];\n trailsRef.current = [];\n activeEdgesRef.current.clear();\n explosionsRef.current = [];\n nodeGlowsRef.current = [];\n };\n\n const resizeObserver = new ResizeObserver(() => {\n setup();\n });\n\n resizeObserver.observe(container);\n setup();\n animationRef.current = requestAnimationFrame(animate);\n\n return () => {\n resizeObserver.disconnect();\n cancelAnimationFrame(animationRef.current);\n };\n }, [shape, cellSize, lineColor, lineWidth, animated, lightColor, lightSpeed, minTravel, maxTravel, spawnRate, splitChance, trailFadeSpeed, buildSquareGraph, buildHexGraph, getConnectedNodes]);\n\n return (\n <div ref={containerRef} className={`relative w-full h-full ${className}`}>\n <canvas ref={canvasRef} className=\"absolute inset-0\" />\n </div>\n );\n}\n\nexport default Grid;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/Grid.tsx"],"sourcesContent":["export { Grid, type GridProps } from \"./Grid\";\nexport { Grid as default } from \"./Grid\";\n","'use client';\n\nimport { useEffect, useRef, useCallback } from 'react';\n\nexport interface GridProps {\n /** Grid shape: 4 for squares, 6 for hexagons */\n shape?: 4 | 6;\n /** Size of each cell in pixels */\n cellSize?: number;\n /** Color of the grid lines (use \"transparent\" to hide) */\n lineColor?: string;\n /** Width of the grid lines */\n lineWidth?: number;\n /** Additional CSS classes */\n className?: string;\n /** Enable animated light particles */\n animated?: boolean;\n /** Color of the light particles and trails */\n lightColor?: string;\n /** Speed of the light particles (1-5 recommended) */\n lightSpeed?: number;\n /** Minimum travel distance before particle dies */\n minTravel?: number;\n /** Maximum travel distance before particle dies */\n maxTravel?: number;\n /** Milliseconds between particle spawns */\n spawnRate?: number;\n /** Probability of particle splitting (0-1) */\n splitChance?: number;\n /** Speed at which trails fade (lower = slower fade) */\n trailFadeSpeed?: number;\n /** Enable spawning particles from the bottom as well as the top */\n bidirectional?: boolean;\n /** Length of the light trail (number of history points) */\n trailLength?: number;\n}\n\ninterface Node {\n x: number;\n y: number;\n key: string;\n}\n\ninterface Edge {\n from: Node;\n to: Node;\n key: string;\n}\n\ninterface Particle {\n id: number;\n currentNode: Node;\n targetNode: Node;\n progress: number;\n traveled: number;\n maxTravel: number;\n canSplit: boolean;\n dead: boolean;\n direction: 1 | -1;\n history: { x: number; y: number }[];\n}\n\ninterface Trail {\n fromX: number;\n fromY: number;\n toX: number;\n toY: number;\n progress: number;\n opacity: number;\n edgeKey: string;\n}\n\ninterface Explosion {\n x: number;\n y: number;\n radius: number;\n maxRadius: number;\n opacity: number;\n}\n\ninterface NodeGlow {\n x: number;\n y: number;\n opacity: number;\n}\n\nexport function Grid({\n shape = 4,\n cellSize = 40,\n lineColor = '#e5e7eb',\n lineWidth = 1,\n className = '',\n animated = false,\n lightColor = '#3b82f6',\n lightSpeed = 2,\n minTravel = 2,\n maxTravel = 6,\n spawnRate = 1000,\n splitChance = 0.3,\n trailFadeSpeed = 0.01,\n bidirectional = false,\n trailLength = 15,\n}: GridProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const nodesRef = useRef<Map<string, Node>>(new Map());\n const edgesRef = useRef<Edge[]>([]);\n const adjacencyRef = useRef<Map<string, Edge[]>>(new Map());\n const topNodesRef = useRef<Node[]>([]);\n const bottomNodesRef = useRef<Node[]>([]);\n const animationRef = useRef<number>(0);\n const particlesRef = useRef<Particle[]>([]);\n const trailsRef = useRef<Trail[]>([]);\n const lastSpawnRef = useRef<number>(0);\n const particleIdRef = useRef<number>(0);\n const dimensionsRef = useRef({ width: 0, height: 0 });\n const activeEdgesRef = useRef<Set<string>>(new Set());\n const explosionsRef = useRef<Explosion[]>([]);\n const nodeGlowsRef = useRef<NodeGlow[]>([]);\n const spawnFromTopRef = useRef<boolean>(true);\n\n const nodeKey = (x: number, y: number) =>\n `${Math.round(x * 100)},${Math.round(y * 100)}`;\n const edgeKey = (n1: Node, n2: Node) => {\n const keys = [n1.key, n2.key].sort();\n return `${keys[0]}-${keys[1]}`;\n };\n\n const getOrCreateNode = useCallback((x: number, y: number): Node => {\n const key = nodeKey(x, y);\n if (!nodesRef.current.has(key)) {\n nodesRef.current.set(key, { x, y, key });\n }\n return nodesRef.current.get(key)!;\n }, []);\n\n const addEdge = useCallback(\n (x1: number, y1: number, x2: number, y2: number) => {\n const from = getOrCreateNode(x1, y1);\n const to = getOrCreateNode(x2, y2);\n const key = edgeKey(from, to);\n\n const existingEdge = edgesRef.current.find((e) => e.key === key);\n if (existingEdge) return;\n\n const edge: Edge = { from, to, key };\n edgesRef.current.push(edge);\n\n if (!adjacencyRef.current.has(from.key)) {\n adjacencyRef.current.set(from.key, []);\n }\n if (!adjacencyRef.current.has(to.key)) {\n adjacencyRef.current.set(to.key, []);\n }\n adjacencyRef.current.get(from.key)!.push(edge);\n adjacencyRef.current.get(to.key)!.push(edge);\n },\n [getOrCreateNode]\n );\n\n const buildSquareGraph = useCallback(\n (width: number, height: number) => {\n nodesRef.current.clear();\n edgesRef.current = [];\n adjacencyRef.current.clear();\n topNodesRef.current = [];\n bottomNodesRef.current = [];\n\n const cols = Math.ceil(width / cellSize) + 1;\n const rows = Math.ceil(height / cellSize) + 1;\n\n for (let i = 0; i <= cols; i++) {\n for (let j = 0; j <= rows; j++) {\n const x = i * cellSize;\n const y = j * cellSize;\n if (i < cols) addEdge(x, y, x + cellSize, y);\n if (j < rows) addEdge(x, y, x, y + cellSize);\n }\n }\n\n const maxY = rows * cellSize;\n for (let i = 0; i <= cols; i++) {\n const topNode = nodesRef.current.get(nodeKey(i * cellSize, 0));\n if (topNode) topNodesRef.current.push(topNode);\n\n const bottomNode = nodesRef.current.get(nodeKey(i * cellSize, maxY));\n if (bottomNode) bottomNodesRef.current.push(bottomNode);\n }\n },\n [cellSize, addEdge]\n );\n\n const buildHexGraph = useCallback(\n (width: number, height: number) => {\n nodesRef.current.clear();\n edgesRef.current = [];\n adjacencyRef.current.clear();\n topNodesRef.current = [];\n bottomNodesRef.current = [];\n\n const size = cellSize / 2;\n const hexWidth = Math.sqrt(3) * size;\n const vertSpacing = size * 1.5;\n\n const cols = Math.ceil(width / hexWidth) + 2;\n const rows = Math.ceil(height / vertSpacing) + 2;\n\n for (let row = -1; row < rows; row++) {\n for (let col = -1; col < cols; col++) {\n const cx = col * hexWidth + (row % 2 === 0 ? 0 : hexWidth / 2);\n const cy = row * vertSpacing;\n\n const vertices: { x: number; y: number }[] = [];\n for (let i = 0; i < 6; i++) {\n const angle = (Math.PI / 3) * i - Math.PI / 2;\n vertices.push({\n x: cx + size * Math.cos(angle),\n y: cy + size * Math.sin(angle),\n });\n }\n\n for (let i = 0; i < 6; i++) {\n const v1 = vertices[i];\n const v2 = vertices[(i + 1) % 6];\n addEdge(v1.x, v1.y, v2.x, v2.y);\n }\n }\n }\n\n const allNodes = Array.from(nodesRef.current.values());\n\n const visibleNodes = allNodes.filter((n) => n.y >= 0 && n.y <= height);\n\n topNodesRef.current = visibleNodes\n .filter((n) => n.y <= size * 2)\n .sort((a, b) => a.x - b.x);\n\n bottomNodesRef.current = visibleNodes\n .filter((n) => n.y >= height - size * 2)\n .sort((a, b) => a.x - b.x);\n },\n [cellSize, addEdge]\n );\n\n const getConnectedNodes = useCallback(\n (node: Node, excludeNode?: Node): Node[] => {\n const edges = adjacencyRef.current.get(node.key) || [];\n return edges\n .map((e) => (e.from.key === node.key ? e.to : e.from))\n .filter((n) => !excludeNode || n.key !== excludeNode.key);\n },\n []\n );\n\n useEffect(() => {\n const canvas = canvasRef.current;\n const container = containerRef.current;\n if (!canvas || !container) return;\n\n let dpr = 1;\n\n const drawGrid = (\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number\n ) => {\n ctx.clearRect(0, 0, width, height);\n ctx.strokeStyle = lineColor;\n ctx.lineWidth = lineWidth;\n ctx.beginPath();\n\n for (const edge of edgesRef.current) {\n ctx.moveTo(edge.from.x, edge.from.y);\n ctx.lineTo(edge.to.x, edge.to.y);\n }\n\n ctx.stroke();\n };\n\n const drawTrails = (ctx: CanvasRenderingContext2D) => {\n for (const trail of trailsRef.current) {\n if (trail.opacity <= 0) continue;\n\n const alpha = Math.floor(trail.opacity * 0.08 * 255)\n .toString(16)\n .padStart(2, '0');\n\n ctx.strokeStyle = lightColor + alpha;\n ctx.lineWidth = 1;\n ctx.lineCap = 'round';\n ctx.beginPath();\n ctx.moveTo(trail.fromX, trail.fromY);\n\n if (trail.progress < 1) {\n const endX = trail.fromX + (trail.toX - trail.fromX) * trail.progress;\n const endY = trail.fromY + (trail.toY - trail.fromY) * trail.progress;\n ctx.lineTo(endX, endY);\n } else {\n ctx.lineTo(trail.toX, trail.toY);\n }\n ctx.stroke();\n\n ctx.shadowColor = lightColor;\n ctx.shadowBlur = 2;\n ctx.stroke();\n ctx.shadowBlur = 0;\n }\n };\n\n const drawParticles = (ctx: CanvasRenderingContext2D) => {\n for (const particle of particlesRef.current) {\n if (particle.dead) continue;\n\n const history = particle.history;\n if (history.length === 0) continue;\n\n const head = history[history.length - 1];\n\n if (history.length >= 2) {\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n const r = parseInt(lightColor.slice(1, 3), 16);\n const g = parseInt(lightColor.slice(3, 5), 16);\n const b = parseInt(lightColor.slice(5, 7), 16);\n const lighterR = Math.floor(r + (255 - r) * 0.6);\n const lighterG = Math.floor(g + (255 - g) * 0.6);\n const lighterB = Math.floor(b + (255 - b) * 0.6);\n ctx.strokeStyle = `rgb(${lighterR}, ${lighterG}, ${lighterB})`;\n\n const maxWidth = 4;\n const minWidth = 0.5;\n for (let i = 1; i < history.length; i++) {\n const progress = i / (history.length - 1);\n ctx.lineWidth = minWidth + (maxWidth - minWidth) * progress;\n ctx.beginPath();\n ctx.moveTo(history[i - 1].x, history[i - 1].y);\n ctx.lineTo(history[i].x, history[i].y);\n ctx.stroke();\n }\n }\n\n ctx.fillStyle = lightColor;\n ctx.beginPath();\n let angle = 0;\n if (history.length >= 2) {\n const prev = history[history.length - 2];\n angle = Math.atan2(head.y - prev.y, head.x - prev.x);\n }\n ctx.save();\n ctx.translate(head.x, head.y);\n ctx.rotate(angle);\n ctx.moveTo(-3, 0);\n ctx.quadraticCurveTo(1, -2.5, 2, 0);\n ctx.quadraticCurveTo(1, 2.5, -3, 0);\n ctx.restore();\n ctx.fill();\n }\n };\n\n const drawExplosions = (ctx: CanvasRenderingContext2D) => {\n for (const explosion of explosionsRef.current) {\n if (explosion.opacity <= 0) continue;\n\n const alpha = Math.floor(explosion.opacity * 255)\n .toString(16)\n .padStart(2, '0');\n ctx.strokeStyle = lightColor + alpha;\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.arc(explosion.x, explosion.y, explosion.radius, 0, Math.PI * 2);\n ctx.stroke();\n }\n };\n\n const updateExplosions = () => {\n for (const explosion of explosionsRef.current) {\n explosion.radius += 0.5;\n explosion.opacity -= 0.08;\n }\n explosionsRef.current = explosionsRef.current.filter(\n (e) => e.opacity > 0\n );\n };\n\n const createExplosion = (x: number, y: number) => {\n explosionsRef.current.push({\n x,\n y,\n radius: 2,\n maxRadius: 8,\n opacity: 1,\n });\n };\n\n const createNodeGlow = (x: number, y: number) => {\n nodeGlowsRef.current.push({\n x,\n y,\n opacity: 1,\n });\n };\n\n const drawNodeGlows = (ctx: CanvasRenderingContext2D) => {\n for (const glow of nodeGlowsRef.current) {\n if (glow.opacity <= 0) continue;\n\n const alpha = Math.floor(glow.opacity * 0.4 * 255)\n .toString(16)\n .padStart(2, '0');\n ctx.fillStyle = lightColor + alpha;\n ctx.beginPath();\n ctx.arc(glow.x, glow.y, 2, 0, Math.PI * 2);\n ctx.fill();\n }\n };\n\n const updateNodeGlows = () => {\n for (const glow of nodeGlowsRef.current) {\n glow.opacity -= trailFadeSpeed * 3;\n }\n nodeGlowsRef.current = nodeGlowsRef.current.filter((g) => g.opacity > 0);\n };\n\n const getRandomTravel = () => {\n return (\n Math.floor(Math.random() * (maxTravel - minTravel + 1)) + minTravel\n );\n };\n\n const makeEdgeKey = (n1: Node, n2: Node) => {\n const keys = [n1.key, n2.key].sort();\n return `${keys[0]}-${keys[1]}`;\n };\n\n const trySpawn = (fromTop: boolean): boolean => {\n const sourceNodes = fromTop\n ? topNodesRef.current\n : bottomNodesRef.current;\n const direction: 1 | -1 = fromTop ? 1 : -1;\n\n if (sourceNodes.length === 0) return false;\n\n const startNode =\n sourceNodes[Math.floor(Math.random() * sourceNodes.length)];\n const connectedNodes = getConnectedNodes(startNode);\n\n const preferredNodes = connectedNodes.filter((n) =>\n fromTop ? n.y > startNode.y : n.y < startNode.y\n );\n const targetNodes =\n preferredNodes.length > 0 ? preferredNodes : connectedNodes;\n\n const availableNodes = targetNodes.filter((n) => {\n const key = makeEdgeKey(startNode, n);\n return !activeEdgesRef.current.has(key);\n });\n\n if (availableNodes.length === 0) return false;\n\n const targetNode =\n availableNodes[Math.floor(Math.random() * availableNodes.length)];\n const edgeKeyStr = makeEdgeKey(startNode, targetNode);\n activeEdgesRef.current.add(edgeKeyStr);\n\n particlesRef.current.push({\n id: particleIdRef.current++,\n currentNode: startNode,\n targetNode,\n progress: 0,\n traveled: 0,\n maxTravel: getRandomTravel(),\n canSplit: true,\n dead: false,\n direction,\n history: [{ x: startNode.x, y: startNode.y }],\n });\n\n trailsRef.current.push({\n fromX: startNode.x,\n fromY: startNode.y,\n toX: targetNode.x,\n toY: targetNode.y,\n progress: 0,\n opacity: 1,\n edgeKey: edgeKeyStr,\n });\n\n return true;\n };\n\n const spawnParticle = () => {\n if (bidirectional) {\n const fromTop = spawnFromTopRef.current;\n spawnFromTopRef.current = !spawnFromTopRef.current;\n\n if (!trySpawn(fromTop)) {\n trySpawn(!fromTop);\n }\n } else {\n trySpawn(true);\n }\n };\n\n const updateParticles = () => {\n const newParticles: Particle[] = [];\n const maxHistoryLength = trailLength;\n\n for (const particle of particlesRef.current) {\n if (particle.dead) continue;\n\n particle.progress += lightSpeed * 0.02;\n\n const currentX =\n particle.currentNode.x +\n (particle.targetNode.x - particle.currentNode.x) * particle.progress;\n const currentY =\n particle.currentNode.y +\n (particle.targetNode.y - particle.currentNode.y) * particle.progress;\n particle.history.push({ x: currentX, y: currentY });\n if (particle.history.length > maxHistoryLength) {\n particle.history.shift();\n }\n\n const trailIndex = trailsRef.current.findIndex(\n (t) =>\n t.fromX === particle.currentNode.x &&\n t.fromY === particle.currentNode.y &&\n t.toX === particle.targetNode.x &&\n t.toY === particle.targetNode.y &&\n t.progress < 1\n );\n if (trailIndex !== -1) {\n trailsRef.current[trailIndex].progress = Math.min(\n particle.progress,\n 1\n );\n }\n\n if (particle.progress >= 1) {\n createNodeGlow(particle.targetNode.x, particle.targetNode.y);\n particle.traveled++;\n\n if (particle.traveled >= particle.maxTravel) {\n const x = particle.targetNode.x;\n const y = particle.targetNode.y;\n createExplosion(x, y);\n particle.dead = true;\n continue;\n }\n\n const currentNode = particle.targetNode;\n const connectedNodes = getConnectedNodes(\n currentNode,\n particle.currentNode\n );\n\n const availableNodes = connectedNodes.filter((n) => {\n const key = makeEdgeKey(currentNode, n);\n return !activeEdgesRef.current.has(key);\n });\n\n if (availableNodes.length === 0) {\n createExplosion(currentNode.x, currentNode.y);\n particle.dead = true;\n continue;\n }\n\n const shouldSplit =\n particle.canSplit &&\n Math.random() < splitChance &&\n availableNodes.length >= 2;\n\n if (shouldSplit) {\n const shuffled = [...availableNodes].sort(\n () => Math.random() - 0.5\n );\n const target1 = shuffled[0];\n const target2 = shuffled[1];\n\n const edgeKey1 = makeEdgeKey(currentNode, target1);\n const edgeKey2 = makeEdgeKey(currentNode, target2);\n activeEdgesRef.current.add(edgeKey1);\n activeEdgesRef.current.add(edgeKey2);\n\n particle.currentNode = currentNode;\n particle.targetNode = target1;\n particle.progress = 0;\n particle.canSplit = false;\n\n trailsRef.current.push({\n fromX: currentNode.x,\n fromY: currentNode.y,\n toX: target1.x,\n toY: target1.y,\n progress: 0,\n opacity: 1,\n edgeKey: edgeKey1,\n });\n\n newParticles.push({\n id: particleIdRef.current++,\n currentNode: currentNode,\n targetNode: target2,\n progress: 0,\n traveled: particle.traveled,\n maxTravel: particle.maxTravel,\n canSplit: false,\n dead: false,\n direction: particle.direction,\n history: [{ x: currentNode.x, y: currentNode.y }],\n });\n\n trailsRef.current.push({\n fromX: currentNode.x,\n fromY: currentNode.y,\n toX: target2.x,\n toY: target2.y,\n progress: 0,\n opacity: 1,\n edgeKey: edgeKey2,\n });\n } else {\n const targetNode =\n availableNodes[Math.floor(Math.random() * availableNodes.length)];\n const newEdgeKey = makeEdgeKey(currentNode, targetNode);\n activeEdgesRef.current.add(newEdgeKey);\n\n particle.currentNode = currentNode;\n particle.targetNode = targetNode;\n particle.progress = 0;\n\n trailsRef.current.push({\n fromX: currentNode.x,\n fromY: currentNode.y,\n toX: targetNode.x,\n toY: targetNode.y,\n progress: 0,\n opacity: 1,\n edgeKey: newEdgeKey,\n });\n }\n }\n }\n\n particlesRef.current.push(...newParticles);\n particlesRef.current = particlesRef.current.filter((p) => !p.dead);\n };\n\n const updateTrails = () => {\n for (const trail of trailsRef.current) {\n if (trail.progress >= 1) {\n trail.opacity -= trailFadeSpeed;\n }\n }\n const fadedTrails = trailsRef.current.filter((t) => t.opacity <= 0);\n for (const trail of fadedTrails) {\n activeEdgesRef.current.delete(trail.edgeKey);\n }\n trailsRef.current = trailsRef.current.filter((t) => t.opacity > 0);\n };\n\n const animate = (timestamp: number) => {\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const { width, height } = dimensionsRef.current;\n\n ctx.save();\n ctx.scale(dpr, dpr);\n drawGrid(ctx, width, height);\n\n if (animated) {\n if (timestamp - lastSpawnRef.current > spawnRate) {\n spawnParticle();\n lastSpawnRef.current = timestamp;\n }\n\n updateParticles();\n updateTrails();\n updateExplosions();\n updateNodeGlows();\n drawTrails(ctx);\n drawNodeGlows(ctx);\n drawParticles(ctx);\n drawExplosions(ctx);\n }\n\n ctx.restore();\n animationRef.current = requestAnimationFrame(animate);\n };\n\n const setup = () => {\n const { width, height } = container.getBoundingClientRect();\n dimensionsRef.current = { width, height };\n dpr = window.devicePixelRatio || 1;\n\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n\n if (shape === 4) {\n buildSquareGraph(width, height);\n } else {\n buildHexGraph(width, height);\n }\n\n particlesRef.current = [];\n trailsRef.current = [];\n activeEdgesRef.current.clear();\n explosionsRef.current = [];\n nodeGlowsRef.current = [];\n };\n\n const resizeObserver = new ResizeObserver(() => {\n setup();\n });\n\n resizeObserver.observe(container);\n setup();\n animationRef.current = requestAnimationFrame(animate);\n\n return () => {\n resizeObserver.disconnect();\n cancelAnimationFrame(animationRef.current);\n };\n }, [\n shape,\n cellSize,\n lineColor,\n lineWidth,\n animated,\n lightColor,\n lightSpeed,\n minTravel,\n maxTravel,\n spawnRate,\n splitChance,\n trailFadeSpeed,\n bidirectional,\n trailLength,\n buildSquareGraph,\n buildHexGraph,\n getConnectedNodes,\n ]);\n\n return (\n <div ref={containerRef} className={`relative w-full h-full ${className}`}>\n <canvas ref={canvasRef} className=\"absolute inset-0\" />\n </div>\n );\n}\n\nexport default Grid;\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -16,7 +16,9 @@ function Grid({
|
|
|
16
16
|
maxTravel = 6,
|
|
17
17
|
spawnRate = 1e3,
|
|
18
18
|
splitChance = 0.3,
|
|
19
|
-
trailFadeSpeed = 0.01
|
|
19
|
+
trailFadeSpeed = 0.01,
|
|
20
|
+
bidirectional = false,
|
|
21
|
+
trailLength = 15
|
|
20
22
|
}) {
|
|
21
23
|
const canvasRef = useRef(null);
|
|
22
24
|
const containerRef = useRef(null);
|
|
@@ -24,6 +26,7 @@ function Grid({
|
|
|
24
26
|
const edgesRef = useRef([]);
|
|
25
27
|
const adjacencyRef = useRef(/* @__PURE__ */ new Map());
|
|
26
28
|
const topNodesRef = useRef([]);
|
|
29
|
+
const bottomNodesRef = useRef([]);
|
|
27
30
|
const animationRef = useRef(0);
|
|
28
31
|
const particlesRef = useRef([]);
|
|
29
32
|
const trailsRef = useRef([]);
|
|
@@ -33,6 +36,7 @@ function Grid({
|
|
|
33
36
|
const activeEdgesRef = useRef(/* @__PURE__ */ new Set());
|
|
34
37
|
const explosionsRef = useRef([]);
|
|
35
38
|
const nodeGlowsRef = useRef([]);
|
|
39
|
+
const spawnFromTopRef = useRef(true);
|
|
36
40
|
const nodeKey = (x, y) => `${Math.round(x * 100)},${Math.round(y * 100)}`;
|
|
37
41
|
const edgeKey = (n1, n2) => {
|
|
38
42
|
const keys = [n1.key, n2.key].sort();
|
|
@@ -45,79 +49,98 @@ function Grid({
|
|
|
45
49
|
}
|
|
46
50
|
return nodesRef.current.get(key);
|
|
47
51
|
}, []);
|
|
48
|
-
const addEdge = useCallback(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
adjacencyRef.current.
|
|
58
|
-
|
|
59
|
-
if (!adjacencyRef.current.has(to.key)) {
|
|
60
|
-
adjacencyRef.current.set(to.key, []);
|
|
61
|
-
}
|
|
62
|
-
adjacencyRef.current.get(from.key).push(edge);
|
|
63
|
-
adjacencyRef.current.get(to.key).push(edge);
|
|
64
|
-
}, [getOrCreateNode]);
|
|
65
|
-
const buildSquareGraph = useCallback((width, height) => {
|
|
66
|
-
nodesRef.current.clear();
|
|
67
|
-
edgesRef.current = [];
|
|
68
|
-
adjacencyRef.current.clear();
|
|
69
|
-
topNodesRef.current = [];
|
|
70
|
-
const cols = Math.ceil(width / cellSize) + 1;
|
|
71
|
-
const rows = Math.ceil(height / cellSize) + 1;
|
|
72
|
-
for (let i = 0; i <= cols; i++) {
|
|
73
|
-
for (let j = 0; j <= rows; j++) {
|
|
74
|
-
const x = i * cellSize;
|
|
75
|
-
const y = j * cellSize;
|
|
76
|
-
if (i < cols) addEdge(x, y, x + cellSize, y);
|
|
77
|
-
if (j < rows) addEdge(x, y, x, y + cellSize);
|
|
52
|
+
const addEdge = useCallback(
|
|
53
|
+
(x1, y1, x2, y2) => {
|
|
54
|
+
const from = getOrCreateNode(x1, y1);
|
|
55
|
+
const to = getOrCreateNode(x2, y2);
|
|
56
|
+
const key = edgeKey(from, to);
|
|
57
|
+
const existingEdge = edgesRef.current.find((e) => e.key === key);
|
|
58
|
+
if (existingEdge) return;
|
|
59
|
+
const edge = { from, to, key };
|
|
60
|
+
edgesRef.current.push(edge);
|
|
61
|
+
if (!adjacencyRef.current.has(from.key)) {
|
|
62
|
+
adjacencyRef.current.set(from.key, []);
|
|
78
63
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
for (let
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
vertices.push({
|
|
103
|
-
x: cx + size * Math.cos(angle),
|
|
104
|
-
y: cy + size * Math.sin(angle)
|
|
105
|
-
});
|
|
64
|
+
if (!adjacencyRef.current.has(to.key)) {
|
|
65
|
+
adjacencyRef.current.set(to.key, []);
|
|
66
|
+
}
|
|
67
|
+
adjacencyRef.current.get(from.key).push(edge);
|
|
68
|
+
adjacencyRef.current.get(to.key).push(edge);
|
|
69
|
+
},
|
|
70
|
+
[getOrCreateNode]
|
|
71
|
+
);
|
|
72
|
+
const buildSquareGraph = useCallback(
|
|
73
|
+
(width, height) => {
|
|
74
|
+
nodesRef.current.clear();
|
|
75
|
+
edgesRef.current = [];
|
|
76
|
+
adjacencyRef.current.clear();
|
|
77
|
+
topNodesRef.current = [];
|
|
78
|
+
bottomNodesRef.current = [];
|
|
79
|
+
const cols = Math.ceil(width / cellSize) + 1;
|
|
80
|
+
const rows = Math.ceil(height / cellSize) + 1;
|
|
81
|
+
for (let i = 0; i <= cols; i++) {
|
|
82
|
+
for (let j = 0; j <= rows; j++) {
|
|
83
|
+
const x = i * cellSize;
|
|
84
|
+
const y = j * cellSize;
|
|
85
|
+
if (i < cols) addEdge(x, y, x + cellSize, y);
|
|
86
|
+
if (j < rows) addEdge(x, y, x, y + cellSize);
|
|
106
87
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
88
|
+
}
|
|
89
|
+
const maxY = rows * cellSize;
|
|
90
|
+
for (let i = 0; i <= cols; i++) {
|
|
91
|
+
const topNode = nodesRef.current.get(nodeKey(i * cellSize, 0));
|
|
92
|
+
if (topNode) topNodesRef.current.push(topNode);
|
|
93
|
+
const bottomNode = nodesRef.current.get(nodeKey(i * cellSize, maxY));
|
|
94
|
+
if (bottomNode) bottomNodesRef.current.push(bottomNode);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
[cellSize, addEdge]
|
|
98
|
+
);
|
|
99
|
+
const buildHexGraph = useCallback(
|
|
100
|
+
(width, height) => {
|
|
101
|
+
nodesRef.current.clear();
|
|
102
|
+
edgesRef.current = [];
|
|
103
|
+
adjacencyRef.current.clear();
|
|
104
|
+
topNodesRef.current = [];
|
|
105
|
+
bottomNodesRef.current = [];
|
|
106
|
+
const size = cellSize / 2;
|
|
107
|
+
const hexWidth = Math.sqrt(3) * size;
|
|
108
|
+
const vertSpacing = size * 1.5;
|
|
109
|
+
const cols = Math.ceil(width / hexWidth) + 2;
|
|
110
|
+
const rows = Math.ceil(height / vertSpacing) + 2;
|
|
111
|
+
for (let row = -1; row < rows; row++) {
|
|
112
|
+
for (let col = -1; col < cols; col++) {
|
|
113
|
+
const cx = col * hexWidth + (row % 2 === 0 ? 0 : hexWidth / 2);
|
|
114
|
+
const cy = row * vertSpacing;
|
|
115
|
+
const vertices = [];
|
|
116
|
+
for (let i = 0; i < 6; i++) {
|
|
117
|
+
const angle = Math.PI / 3 * i - Math.PI / 2;
|
|
118
|
+
vertices.push({
|
|
119
|
+
x: cx + size * Math.cos(angle),
|
|
120
|
+
y: cy + size * Math.sin(angle)
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
for (let i = 0; i < 6; i++) {
|
|
124
|
+
const v1 = vertices[i];
|
|
125
|
+
const v2 = vertices[(i + 1) % 6];
|
|
126
|
+
addEdge(v1.x, v1.y, v2.x, v2.y);
|
|
127
|
+
}
|
|
111
128
|
}
|
|
112
129
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
130
|
+
const allNodes = Array.from(nodesRef.current.values());
|
|
131
|
+
const visibleNodes = allNodes.filter((n) => n.y >= 0 && n.y <= height);
|
|
132
|
+
topNodesRef.current = visibleNodes.filter((n) => n.y <= size * 2).sort((a, b) => a.x - b.x);
|
|
133
|
+
bottomNodesRef.current = visibleNodes.filter((n) => n.y >= height - size * 2).sort((a, b) => a.x - b.x);
|
|
134
|
+
},
|
|
135
|
+
[cellSize, addEdge]
|
|
136
|
+
);
|
|
137
|
+
const getConnectedNodes = useCallback(
|
|
138
|
+
(node, excludeNode) => {
|
|
139
|
+
const edges = adjacencyRef.current.get(node.key) || [];
|
|
140
|
+
return edges.map((e) => e.from.key === node.key ? e.to : e.from).filter((n) => !excludeNode || n.key !== excludeNode.key);
|
|
141
|
+
},
|
|
142
|
+
[]
|
|
143
|
+
);
|
|
121
144
|
useEffect(() => {
|
|
122
145
|
const canvas = canvasRef.current;
|
|
123
146
|
const container = containerRef.current;
|
|
@@ -160,11 +183,44 @@ function Grid({
|
|
|
160
183
|
const drawParticles = (ctx) => {
|
|
161
184
|
for (const particle of particlesRef.current) {
|
|
162
185
|
if (particle.dead) continue;
|
|
163
|
-
const
|
|
164
|
-
|
|
186
|
+
const history = particle.history;
|
|
187
|
+
if (history.length === 0) continue;
|
|
188
|
+
const head = history[history.length - 1];
|
|
189
|
+
if (history.length >= 2) {
|
|
190
|
+
ctx.lineCap = "round";
|
|
191
|
+
ctx.lineJoin = "round";
|
|
192
|
+
const r = parseInt(lightColor.slice(1, 3), 16);
|
|
193
|
+
const g = parseInt(lightColor.slice(3, 5), 16);
|
|
194
|
+
const b = parseInt(lightColor.slice(5, 7), 16);
|
|
195
|
+
const lighterR = Math.floor(r + (255 - r) * 0.6);
|
|
196
|
+
const lighterG = Math.floor(g + (255 - g) * 0.6);
|
|
197
|
+
const lighterB = Math.floor(b + (255 - b) * 0.6);
|
|
198
|
+
ctx.strokeStyle = `rgb(${lighterR}, ${lighterG}, ${lighterB})`;
|
|
199
|
+
const maxWidth = 4;
|
|
200
|
+
const minWidth = 0.5;
|
|
201
|
+
for (let i = 1; i < history.length; i++) {
|
|
202
|
+
const progress = i / (history.length - 1);
|
|
203
|
+
ctx.lineWidth = minWidth + (maxWidth - minWidth) * progress;
|
|
204
|
+
ctx.beginPath();
|
|
205
|
+
ctx.moveTo(history[i - 1].x, history[i - 1].y);
|
|
206
|
+
ctx.lineTo(history[i].x, history[i].y);
|
|
207
|
+
ctx.stroke();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
165
210
|
ctx.fillStyle = lightColor;
|
|
166
211
|
ctx.beginPath();
|
|
167
|
-
|
|
212
|
+
let angle = 0;
|
|
213
|
+
if (history.length >= 2) {
|
|
214
|
+
const prev = history[history.length - 2];
|
|
215
|
+
angle = Math.atan2(head.y - prev.y, head.x - prev.x);
|
|
216
|
+
}
|
|
217
|
+
ctx.save();
|
|
218
|
+
ctx.translate(head.x, head.y);
|
|
219
|
+
ctx.rotate(angle);
|
|
220
|
+
ctx.moveTo(-3, 0);
|
|
221
|
+
ctx.quadraticCurveTo(1, -2.5, 2, 0);
|
|
222
|
+
ctx.quadraticCurveTo(1, 2.5, -3, 0);
|
|
223
|
+
ctx.restore();
|
|
168
224
|
ctx.fill();
|
|
169
225
|
}
|
|
170
226
|
};
|
|
@@ -184,7 +240,9 @@ function Grid({
|
|
|
184
240
|
explosion.radius += 0.5;
|
|
185
241
|
explosion.opacity -= 0.08;
|
|
186
242
|
}
|
|
187
|
-
explosionsRef.current = explosionsRef.current.filter(
|
|
243
|
+
explosionsRef.current = explosionsRef.current.filter(
|
|
244
|
+
(e) => e.opacity > 0
|
|
245
|
+
);
|
|
188
246
|
};
|
|
189
247
|
const createExplosion = (x, y) => {
|
|
190
248
|
explosionsRef.current.push({
|
|
@@ -225,17 +283,21 @@ function Grid({
|
|
|
225
283
|
const keys = [n1.key, n2.key].sort();
|
|
226
284
|
return `${keys[0]}-${keys[1]}`;
|
|
227
285
|
};
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
const
|
|
286
|
+
const trySpawn = (fromTop) => {
|
|
287
|
+
const sourceNodes = fromTop ? topNodesRef.current : bottomNodesRef.current;
|
|
288
|
+
const direction = fromTop ? 1 : -1;
|
|
289
|
+
if (sourceNodes.length === 0) return false;
|
|
290
|
+
const startNode = sourceNodes[Math.floor(Math.random() * sourceNodes.length)];
|
|
231
291
|
const connectedNodes = getConnectedNodes(startNode);
|
|
232
|
-
const
|
|
233
|
-
|
|
292
|
+
const preferredNodes = connectedNodes.filter(
|
|
293
|
+
(n) => fromTop ? n.y > startNode.y : n.y < startNode.y
|
|
294
|
+
);
|
|
295
|
+
const targetNodes = preferredNodes.length > 0 ? preferredNodes : connectedNodes;
|
|
234
296
|
const availableNodes = targetNodes.filter((n) => {
|
|
235
297
|
const key = makeEdgeKey(startNode, n);
|
|
236
298
|
return !activeEdgesRef.current.has(key);
|
|
237
299
|
});
|
|
238
|
-
if (availableNodes.length === 0) return;
|
|
300
|
+
if (availableNodes.length === 0) return false;
|
|
239
301
|
const targetNode = availableNodes[Math.floor(Math.random() * availableNodes.length)];
|
|
240
302
|
const edgeKeyStr = makeEdgeKey(startNode, targetNode);
|
|
241
303
|
activeEdgesRef.current.add(edgeKeyStr);
|
|
@@ -247,7 +309,9 @@ function Grid({
|
|
|
247
309
|
traveled: 0,
|
|
248
310
|
maxTravel: getRandomTravel(),
|
|
249
311
|
canSplit: true,
|
|
250
|
-
dead: false
|
|
312
|
+
dead: false,
|
|
313
|
+
direction,
|
|
314
|
+
history: [{ x: startNode.x, y: startNode.y }]
|
|
251
315
|
});
|
|
252
316
|
trailsRef.current.push({
|
|
253
317
|
fromX: startNode.x,
|
|
@@ -258,17 +322,39 @@ function Grid({
|
|
|
258
322
|
opacity: 1,
|
|
259
323
|
edgeKey: edgeKeyStr
|
|
260
324
|
});
|
|
325
|
+
return true;
|
|
326
|
+
};
|
|
327
|
+
const spawnParticle = () => {
|
|
328
|
+
if (bidirectional) {
|
|
329
|
+
const fromTop = spawnFromTopRef.current;
|
|
330
|
+
spawnFromTopRef.current = !spawnFromTopRef.current;
|
|
331
|
+
if (!trySpawn(fromTop)) {
|
|
332
|
+
trySpawn(!fromTop);
|
|
333
|
+
}
|
|
334
|
+
} else {
|
|
335
|
+
trySpawn(true);
|
|
336
|
+
}
|
|
261
337
|
};
|
|
262
338
|
const updateParticles = () => {
|
|
263
339
|
const newParticles = [];
|
|
340
|
+
const maxHistoryLength = trailLength;
|
|
264
341
|
for (const particle of particlesRef.current) {
|
|
265
342
|
if (particle.dead) continue;
|
|
266
343
|
particle.progress += lightSpeed * 0.02;
|
|
344
|
+
const currentX = particle.currentNode.x + (particle.targetNode.x - particle.currentNode.x) * particle.progress;
|
|
345
|
+
const currentY = particle.currentNode.y + (particle.targetNode.y - particle.currentNode.y) * particle.progress;
|
|
346
|
+
particle.history.push({ x: currentX, y: currentY });
|
|
347
|
+
if (particle.history.length > maxHistoryLength) {
|
|
348
|
+
particle.history.shift();
|
|
349
|
+
}
|
|
267
350
|
const trailIndex = trailsRef.current.findIndex(
|
|
268
351
|
(t) => t.fromX === particle.currentNode.x && t.fromY === particle.currentNode.y && t.toX === particle.targetNode.x && t.toY === particle.targetNode.y && t.progress < 1
|
|
269
352
|
);
|
|
270
353
|
if (trailIndex !== -1) {
|
|
271
|
-
trailsRef.current[trailIndex].progress = Math.min(
|
|
354
|
+
trailsRef.current[trailIndex].progress = Math.min(
|
|
355
|
+
particle.progress,
|
|
356
|
+
1
|
|
357
|
+
);
|
|
272
358
|
}
|
|
273
359
|
if (particle.progress >= 1) {
|
|
274
360
|
createNodeGlow(particle.targetNode.x, particle.targetNode.y);
|
|
@@ -281,7 +367,10 @@ function Grid({
|
|
|
281
367
|
continue;
|
|
282
368
|
}
|
|
283
369
|
const currentNode = particle.targetNode;
|
|
284
|
-
const connectedNodes = getConnectedNodes(
|
|
370
|
+
const connectedNodes = getConnectedNodes(
|
|
371
|
+
currentNode,
|
|
372
|
+
particle.currentNode
|
|
373
|
+
);
|
|
285
374
|
const availableNodes = connectedNodes.filter((n) => {
|
|
286
375
|
const key = makeEdgeKey(currentNode, n);
|
|
287
376
|
return !activeEdgesRef.current.has(key);
|
|
@@ -293,7 +382,9 @@ function Grid({
|
|
|
293
382
|
}
|
|
294
383
|
const shouldSplit = particle.canSplit && Math.random() < splitChance && availableNodes.length >= 2;
|
|
295
384
|
if (shouldSplit) {
|
|
296
|
-
const shuffled = [...availableNodes].sort(
|
|
385
|
+
const shuffled = [...availableNodes].sort(
|
|
386
|
+
() => Math.random() - 0.5
|
|
387
|
+
);
|
|
297
388
|
const target1 = shuffled[0];
|
|
298
389
|
const target2 = shuffled[1];
|
|
299
390
|
const edgeKey1 = makeEdgeKey(currentNode, target1);
|
|
@@ -321,7 +412,9 @@ function Grid({
|
|
|
321
412
|
traveled: particle.traveled,
|
|
322
413
|
maxTravel: particle.maxTravel,
|
|
323
414
|
canSplit: false,
|
|
324
|
-
dead: false
|
|
415
|
+
dead: false,
|
|
416
|
+
direction: particle.direction,
|
|
417
|
+
history: [{ x: currentNode.x, y: currentNode.y }]
|
|
325
418
|
});
|
|
326
419
|
trailsRef.current.push({
|
|
327
420
|
fromX: currentNode.x,
|
|
@@ -419,7 +512,25 @@ function Grid({
|
|
|
419
512
|
resizeObserver.disconnect();
|
|
420
513
|
cancelAnimationFrame(animationRef.current);
|
|
421
514
|
};
|
|
422
|
-
}, [
|
|
515
|
+
}, [
|
|
516
|
+
shape,
|
|
517
|
+
cellSize,
|
|
518
|
+
lineColor,
|
|
519
|
+
lineWidth,
|
|
520
|
+
animated,
|
|
521
|
+
lightColor,
|
|
522
|
+
lightSpeed,
|
|
523
|
+
minTravel,
|
|
524
|
+
maxTravel,
|
|
525
|
+
spawnRate,
|
|
526
|
+
splitChance,
|
|
527
|
+
trailFadeSpeed,
|
|
528
|
+
bidirectional,
|
|
529
|
+
trailLength,
|
|
530
|
+
buildSquareGraph,
|
|
531
|
+
buildHexGraph,
|
|
532
|
+
getConnectedNodes
|
|
533
|
+
]);
|
|
423
534
|
return /* @__PURE__ */ jsx("div", { ref: containerRef, className: `relative w-full h-full ${className}`, children: /* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "absolute inset-0" }) });
|
|
424
535
|
}
|
|
425
536
|
export {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/Grid.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useCallback } from \"react\";\n\nexport interface GridProps {\n /** Grid shape: 4 for squares, 6 for hexagons */\n shape?: 4 | 6;\n /** Size of each cell in pixels */\n cellSize?: number;\n /** Color of the grid lines (use \"transparent\" to hide) */\n lineColor?: string;\n /** Width of the grid lines */\n lineWidth?: number;\n /** Additional CSS classes */\n className?: string;\n /** Enable animated light particles */\n animated?: boolean;\n /** Color of the light particles and trails */\n lightColor?: string;\n /** Speed of the light particles (1-5 recommended) */\n lightSpeed?: number;\n /** Minimum travel distance before particle dies */\n minTravel?: number;\n /** Maximum travel distance before particle dies */\n maxTravel?: number;\n /** Milliseconds between particle spawns */\n spawnRate?: number;\n /** Probability of particle splitting (0-1) */\n splitChance?: number;\n /** Speed at which trails fade (lower = slower fade) */\n trailFadeSpeed?: number;\n}\n\ninterface Node {\n x: number;\n y: number;\n key: string;\n}\n\ninterface Edge {\n from: Node;\n to: Node;\n key: string;\n}\n\ninterface Particle {\n id: number;\n currentNode: Node;\n targetNode: Node;\n progress: number;\n traveled: number;\n maxTravel: number;\n canSplit: boolean;\n dead: boolean;\n}\n\ninterface Trail {\n fromX: number;\n fromY: number;\n toX: number;\n toY: number;\n progress: number;\n opacity: number;\n edgeKey: string;\n}\n\ninterface Explosion {\n x: number;\n y: number;\n radius: number;\n maxRadius: number;\n opacity: number;\n}\n\ninterface NodeGlow {\n x: number;\n y: number;\n opacity: number;\n}\n\nexport function Grid({\n shape = 4,\n cellSize = 40,\n lineColor = \"#e5e7eb\",\n lineWidth = 1,\n className = \"\",\n animated = false,\n lightColor = \"#3b82f6\",\n lightSpeed = 2,\n minTravel = 2,\n maxTravel = 6,\n spawnRate = 1000,\n splitChance = 0.3,\n trailFadeSpeed = 0.01,\n}: GridProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const nodesRef = useRef<Map<string, Node>>(new Map());\n const edgesRef = useRef<Edge[]>([]);\n const adjacencyRef = useRef<Map<string, Edge[]>>(new Map());\n const topNodesRef = useRef<Node[]>([]);\n const animationRef = useRef<number>(0);\n const particlesRef = useRef<Particle[]>([]);\n const trailsRef = useRef<Trail[]>([]);\n const lastSpawnRef = useRef<number>(0);\n const particleIdRef = useRef<number>(0);\n const dimensionsRef = useRef({ width: 0, height: 0 });\n const activeEdgesRef = useRef<Set<string>>(new Set());\n const explosionsRef = useRef<Explosion[]>([]);\n const nodeGlowsRef = useRef<NodeGlow[]>([]);\n\n const nodeKey = (x: number, y: number) => `${Math.round(x * 100)},${Math.round(y * 100)}`;\n const edgeKey = (n1: Node, n2: Node) => {\n const keys = [n1.key, n2.key].sort();\n return `${keys[0]}-${keys[1]}`;\n };\n\n const getOrCreateNode = useCallback((x: number, y: number): Node => {\n const key = nodeKey(x, y);\n if (!nodesRef.current.has(key)) {\n nodesRef.current.set(key, { x, y, key });\n }\n return nodesRef.current.get(key)!;\n }, []);\n\n const addEdge = useCallback((x1: number, y1: number, x2: number, y2: number) => {\n const from = getOrCreateNode(x1, y1);\n const to = getOrCreateNode(x2, y2);\n const key = edgeKey(from, to);\n\n const existingEdge = edgesRef.current.find(e => e.key === key);\n if (existingEdge) return;\n\n const edge: Edge = { from, to, key };\n edgesRef.current.push(edge);\n\n if (!adjacencyRef.current.has(from.key)) {\n adjacencyRef.current.set(from.key, []);\n }\n if (!adjacencyRef.current.has(to.key)) {\n adjacencyRef.current.set(to.key, []);\n }\n adjacencyRef.current.get(from.key)!.push(edge);\n adjacencyRef.current.get(to.key)!.push(edge);\n }, [getOrCreateNode]);\n\n const buildSquareGraph = useCallback((width: number, height: number) => {\n nodesRef.current.clear();\n edgesRef.current = [];\n adjacencyRef.current.clear();\n topNodesRef.current = [];\n\n const cols = Math.ceil(width / cellSize) + 1;\n const rows = Math.ceil(height / cellSize) + 1;\n\n for (let i = 0; i <= cols; i++) {\n for (let j = 0; j <= rows; j++) {\n const x = i * cellSize;\n const y = j * cellSize;\n if (i < cols) addEdge(x, y, x + cellSize, y);\n if (j < rows) addEdge(x, y, x, y + cellSize);\n }\n }\n\n for (let i = 0; i <= cols; i++) {\n const node = nodesRef.current.get(nodeKey(i * cellSize, 0));\n if (node) topNodesRef.current.push(node);\n }\n }, [cellSize, addEdge]);\n\n const buildHexGraph = useCallback((width: number, height: number) => {\n nodesRef.current.clear();\n edgesRef.current = [];\n adjacencyRef.current.clear();\n topNodesRef.current = [];\n\n const size = cellSize / 2;\n const hexWidth = Math.sqrt(3) * size;\n const vertSpacing = size * 1.5;\n\n const cols = Math.ceil(width / hexWidth) + 2;\n const rows = Math.ceil(height / vertSpacing) + 2;\n\n for (let row = -1; row < rows; row++) {\n for (let col = -1; col < cols; col++) {\n const cx = col * hexWidth + (row % 2 === 0 ? 0 : hexWidth / 2);\n const cy = row * vertSpacing;\n\n const vertices: { x: number; y: number }[] = [];\n for (let i = 0; i < 6; i++) {\n const angle = (Math.PI / 3) * i - Math.PI / 2;\n vertices.push({\n x: cx + size * Math.cos(angle),\n y: cy + size * Math.sin(angle),\n });\n }\n\n for (let i = 0; i < 6; i++) {\n const v1 = vertices[i];\n const v2 = vertices[(i + 1) % 6];\n addEdge(v1.x, v1.y, v2.x, v2.y);\n }\n }\n }\n\n const sortedNodes = Array.from(nodesRef.current.values())\n .filter(n => n.y >= 0 && n.y <= size)\n .sort((a, b) => a.x - b.x);\n topNodesRef.current = sortedNodes;\n }, [cellSize, addEdge]);\n\n const getConnectedNodes = useCallback((node: Node, excludeNode?: Node): Node[] => {\n const edges = adjacencyRef.current.get(node.key) || [];\n return edges\n .map(e => (e.from.key === node.key ? e.to : e.from))\n .filter(n => !excludeNode || n.key !== excludeNode.key);\n }, []);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n const container = containerRef.current;\n if (!canvas || !container) return;\n\n let dpr = 1;\n\n const drawGrid = (ctx: CanvasRenderingContext2D, width: number, height: number) => {\n ctx.clearRect(0, 0, width, height);\n ctx.strokeStyle = lineColor;\n ctx.lineWidth = lineWidth;\n ctx.beginPath();\n\n for (const edge of edgesRef.current) {\n ctx.moveTo(edge.from.x, edge.from.y);\n ctx.lineTo(edge.to.x, edge.to.y);\n }\n\n ctx.stroke();\n };\n\n const drawTrails = (ctx: CanvasRenderingContext2D) => {\n for (const trail of trailsRef.current) {\n if (trail.opacity <= 0) continue;\n\n const alpha = Math.floor(trail.opacity * 0.08 * 255).toString(16).padStart(2, '0');\n\n ctx.strokeStyle = lightColor + alpha;\n ctx.lineWidth = 1;\n ctx.lineCap = \"round\";\n ctx.beginPath();\n ctx.moveTo(trail.fromX, trail.fromY);\n\n if (trail.progress < 1) {\n const endX = trail.fromX + (trail.toX - trail.fromX) * trail.progress;\n const endY = trail.fromY + (trail.toY - trail.fromY) * trail.progress;\n ctx.lineTo(endX, endY);\n } else {\n ctx.lineTo(trail.toX, trail.toY);\n }\n ctx.stroke();\n\n ctx.shadowColor = lightColor;\n ctx.shadowBlur = 2;\n ctx.stroke();\n ctx.shadowBlur = 0;\n }\n };\n\n const drawParticles = (ctx: CanvasRenderingContext2D) => {\n for (const particle of particlesRef.current) {\n if (particle.dead) continue;\n\n const x = particle.currentNode.x + (particle.targetNode.x - particle.currentNode.x) * particle.progress;\n const y = particle.currentNode.y + (particle.targetNode.y - particle.currentNode.y) * particle.progress;\n\n ctx.fillStyle = lightColor;\n ctx.beginPath();\n ctx.arc(x, y, 3, 0, Math.PI * 2);\n ctx.fill();\n }\n };\n\n const drawExplosions = (ctx: CanvasRenderingContext2D) => {\n for (const explosion of explosionsRef.current) {\n if (explosion.opacity <= 0) continue;\n\n const alpha = Math.floor(explosion.opacity * 255).toString(16).padStart(2, '0');\n ctx.strokeStyle = lightColor + alpha;\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.arc(explosion.x, explosion.y, explosion.radius, 0, Math.PI * 2);\n ctx.stroke();\n }\n };\n\n const updateExplosions = () => {\n for (const explosion of explosionsRef.current) {\n explosion.radius += 0.5;\n explosion.opacity -= 0.08;\n }\n explosionsRef.current = explosionsRef.current.filter(e => e.opacity > 0);\n };\n\n const createExplosion = (x: number, y: number) => {\n explosionsRef.current.push({\n x,\n y,\n radius: 2,\n maxRadius: 8,\n opacity: 1,\n });\n };\n\n const createNodeGlow = (x: number, y: number) => {\n nodeGlowsRef.current.push({\n x,\n y,\n opacity: 1,\n });\n };\n\n const drawNodeGlows = (ctx: CanvasRenderingContext2D) => {\n for (const glow of nodeGlowsRef.current) {\n if (glow.opacity <= 0) continue;\n\n const alpha = Math.floor(glow.opacity * 0.4 * 255).toString(16).padStart(2, '0');\n ctx.fillStyle = lightColor + alpha;\n ctx.beginPath();\n ctx.arc(glow.x, glow.y, 2, 0, Math.PI * 2);\n ctx.fill();\n }\n };\n\n const updateNodeGlows = () => {\n for (const glow of nodeGlowsRef.current) {\n glow.opacity -= trailFadeSpeed * 3;\n }\n nodeGlowsRef.current = nodeGlowsRef.current.filter(g => g.opacity > 0);\n };\n\n const getRandomTravel = () => {\n return Math.floor(Math.random() * (maxTravel - minTravel + 1)) + minTravel;\n };\n\n const makeEdgeKey = (n1: Node, n2: Node) => {\n const keys = [n1.key, n2.key].sort();\n return `${keys[0]}-${keys[1]}`;\n };\n\n const spawnParticle = () => {\n if (topNodesRef.current.length === 0) return;\n\n const startNode = topNodesRef.current[Math.floor(Math.random() * topNodesRef.current.length)];\n const connectedNodes = getConnectedNodes(startNode);\n\n const downwardNodes = connectedNodes.filter(n => n.y > startNode.y);\n const targetNodes = downwardNodes.length > 0 ? downwardNodes : connectedNodes;\n\n const availableNodes = targetNodes.filter(n => {\n const key = makeEdgeKey(startNode, n);\n return !activeEdgesRef.current.has(key);\n });\n\n if (availableNodes.length === 0) return;\n\n const targetNode = availableNodes[Math.floor(Math.random() * availableNodes.length)];\n const edgeKeyStr = makeEdgeKey(startNode, targetNode);\n activeEdgesRef.current.add(edgeKeyStr);\n\n particlesRef.current.push({\n id: particleIdRef.current++,\n currentNode: startNode,\n targetNode,\n progress: 0,\n traveled: 0,\n maxTravel: getRandomTravel(),\n canSplit: true,\n dead: false,\n });\n\n trailsRef.current.push({\n fromX: startNode.x,\n fromY: startNode.y,\n toX: targetNode.x,\n toY: targetNode.y,\n progress: 0,\n opacity: 1,\n edgeKey: edgeKeyStr,\n });\n };\n\n const updateParticles = () => {\n const newParticles: Particle[] = [];\n\n for (const particle of particlesRef.current) {\n if (particle.dead) continue;\n\n particle.progress += lightSpeed * 0.02;\n\n const trailIndex = trailsRef.current.findIndex(\n t => t.fromX === particle.currentNode.x &&\n t.fromY === particle.currentNode.y &&\n t.toX === particle.targetNode.x &&\n t.toY === particle.targetNode.y &&\n t.progress < 1\n );\n if (trailIndex !== -1) {\n trailsRef.current[trailIndex].progress = Math.min(particle.progress, 1);\n }\n\n if (particle.progress >= 1) {\n createNodeGlow(particle.targetNode.x, particle.targetNode.y);\n particle.traveled++;\n\n if (particle.traveled >= particle.maxTravel) {\n const x = particle.targetNode.x;\n const y = particle.targetNode.y;\n createExplosion(x, y);\n particle.dead = true;\n continue;\n }\n\n const currentNode = particle.targetNode;\n const connectedNodes = getConnectedNodes(currentNode, particle.currentNode);\n\n const availableNodes = connectedNodes.filter(n => {\n const key = makeEdgeKey(currentNode, n);\n return !activeEdgesRef.current.has(key);\n });\n\n if (availableNodes.length === 0) {\n createExplosion(currentNode.x, currentNode.y);\n particle.dead = true;\n continue;\n }\n\n const shouldSplit = particle.canSplit && Math.random() < splitChance && availableNodes.length >= 2;\n\n if (shouldSplit) {\n const shuffled = [...availableNodes].sort(() => Math.random() - 0.5);\n const target1 = shuffled[0];\n const target2 = shuffled[1];\n\n const edgeKey1 = makeEdgeKey(currentNode, target1);\n const edgeKey2 = makeEdgeKey(currentNode, target2);\n activeEdgesRef.current.add(edgeKey1);\n activeEdgesRef.current.add(edgeKey2);\n\n particle.currentNode = currentNode;\n particle.targetNode = target1;\n particle.progress = 0;\n particle.canSplit = false;\n\n trailsRef.current.push({\n fromX: currentNode.x,\n fromY: currentNode.y,\n toX: target1.x,\n toY: target1.y,\n progress: 0,\n opacity: 1,\n edgeKey: edgeKey1,\n });\n\n newParticles.push({\n id: particleIdRef.current++,\n currentNode: currentNode,\n targetNode: target2,\n progress: 0,\n traveled: particle.traveled,\n maxTravel: particle.maxTravel,\n canSplit: false,\n dead: false,\n });\n\n trailsRef.current.push({\n fromX: currentNode.x,\n fromY: currentNode.y,\n toX: target2.x,\n toY: target2.y,\n progress: 0,\n opacity: 1,\n edgeKey: edgeKey2,\n });\n } else {\n const targetNode = availableNodes[Math.floor(Math.random() * availableNodes.length)];\n const newEdgeKey = makeEdgeKey(currentNode, targetNode);\n activeEdgesRef.current.add(newEdgeKey);\n\n particle.currentNode = currentNode;\n particle.targetNode = targetNode;\n particle.progress = 0;\n\n trailsRef.current.push({\n fromX: currentNode.x,\n fromY: currentNode.y,\n toX: targetNode.x,\n toY: targetNode.y,\n progress: 0,\n opacity: 1,\n edgeKey: newEdgeKey,\n });\n }\n }\n }\n\n particlesRef.current.push(...newParticles);\n particlesRef.current = particlesRef.current.filter(p => !p.dead);\n };\n\n const updateTrails = () => {\n for (const trail of trailsRef.current) {\n if (trail.progress >= 1) {\n trail.opacity -= trailFadeSpeed;\n }\n }\n const fadedTrails = trailsRef.current.filter(t => t.opacity <= 0);\n for (const trail of fadedTrails) {\n activeEdgesRef.current.delete(trail.edgeKey);\n }\n trailsRef.current = trailsRef.current.filter(t => t.opacity > 0);\n };\n\n const animate = (timestamp: number) => {\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n const { width, height } = dimensionsRef.current;\n\n ctx.save();\n ctx.scale(dpr, dpr);\n drawGrid(ctx, width, height);\n\n if (animated) {\n if (timestamp - lastSpawnRef.current > spawnRate) {\n spawnParticle();\n lastSpawnRef.current = timestamp;\n }\n\n updateParticles();\n updateTrails();\n updateExplosions();\n updateNodeGlows();\n drawTrails(ctx);\n drawNodeGlows(ctx);\n drawParticles(ctx);\n drawExplosions(ctx);\n }\n\n ctx.restore();\n animationRef.current = requestAnimationFrame(animate);\n };\n\n const setup = () => {\n const { width, height } = container.getBoundingClientRect();\n dimensionsRef.current = { width, height };\n dpr = window.devicePixelRatio || 1;\n\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n\n if (shape === 4) {\n buildSquareGraph(width, height);\n } else {\n buildHexGraph(width, height);\n }\n\n particlesRef.current = [];\n trailsRef.current = [];\n activeEdgesRef.current.clear();\n explosionsRef.current = [];\n nodeGlowsRef.current = [];\n };\n\n const resizeObserver = new ResizeObserver(() => {\n setup();\n });\n\n resizeObserver.observe(container);\n setup();\n animationRef.current = requestAnimationFrame(animate);\n\n return () => {\n resizeObserver.disconnect();\n cancelAnimationFrame(animationRef.current);\n };\n }, [shape, cellSize, lineColor, lineWidth, animated, lightColor, lightSpeed, minTravel, maxTravel, spawnRate, splitChance, trailFadeSpeed, buildSquareGraph, buildHexGraph, getConnectedNodes]);\n\n return (\n <div ref={containerRef} className={`relative w-full h-full ${className}`}>\n <canvas ref={canvasRef} className=\"absolute inset-0\" />\n </div>\n );\n}\n\nexport default Grid;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/Grid.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef, useCallback } from 'react';\n\nexport interface GridProps {\n /** Grid shape: 4 for squares, 6 for hexagons */\n shape?: 4 | 6;\n /** Size of each cell in pixels */\n cellSize?: number;\n /** Color of the grid lines (use \"transparent\" to hide) */\n lineColor?: string;\n /** Width of the grid lines */\n lineWidth?: number;\n /** Additional CSS classes */\n className?: string;\n /** Enable animated light particles */\n animated?: boolean;\n /** Color of the light particles and trails */\n lightColor?: string;\n /** Speed of the light particles (1-5 recommended) */\n lightSpeed?: number;\n /** Minimum travel distance before particle dies */\n minTravel?: number;\n /** Maximum travel distance before particle dies */\n maxTravel?: number;\n /** Milliseconds between particle spawns */\n spawnRate?: number;\n /** Probability of particle splitting (0-1) */\n splitChance?: number;\n /** Speed at which trails fade (lower = slower fade) */\n trailFadeSpeed?: number;\n /** Enable spawning particles from the bottom as well as the top */\n bidirectional?: boolean;\n /** Length of the light trail (number of history points) */\n trailLength?: number;\n}\n\ninterface Node {\n x: number;\n y: number;\n key: string;\n}\n\ninterface Edge {\n from: Node;\n to: Node;\n key: string;\n}\n\ninterface Particle {\n id: number;\n currentNode: Node;\n targetNode: Node;\n progress: number;\n traveled: number;\n maxTravel: number;\n canSplit: boolean;\n dead: boolean;\n direction: 1 | -1;\n history: { x: number; y: number }[];\n}\n\ninterface Trail {\n fromX: number;\n fromY: number;\n toX: number;\n toY: number;\n progress: number;\n opacity: number;\n edgeKey: string;\n}\n\ninterface Explosion {\n x: number;\n y: number;\n radius: number;\n maxRadius: number;\n opacity: number;\n}\n\ninterface NodeGlow {\n x: number;\n y: number;\n opacity: number;\n}\n\nexport function Grid({\n shape = 4,\n cellSize = 40,\n lineColor = '#e5e7eb',\n lineWidth = 1,\n className = '',\n animated = false,\n lightColor = '#3b82f6',\n lightSpeed = 2,\n minTravel = 2,\n maxTravel = 6,\n spawnRate = 1000,\n splitChance = 0.3,\n trailFadeSpeed = 0.01,\n bidirectional = false,\n trailLength = 15,\n}: GridProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const nodesRef = useRef<Map<string, Node>>(new Map());\n const edgesRef = useRef<Edge[]>([]);\n const adjacencyRef = useRef<Map<string, Edge[]>>(new Map());\n const topNodesRef = useRef<Node[]>([]);\n const bottomNodesRef = useRef<Node[]>([]);\n const animationRef = useRef<number>(0);\n const particlesRef = useRef<Particle[]>([]);\n const trailsRef = useRef<Trail[]>([]);\n const lastSpawnRef = useRef<number>(0);\n const particleIdRef = useRef<number>(0);\n const dimensionsRef = useRef({ width: 0, height: 0 });\n const activeEdgesRef = useRef<Set<string>>(new Set());\n const explosionsRef = useRef<Explosion[]>([]);\n const nodeGlowsRef = useRef<NodeGlow[]>([]);\n const spawnFromTopRef = useRef<boolean>(true);\n\n const nodeKey = (x: number, y: number) =>\n `${Math.round(x * 100)},${Math.round(y * 100)}`;\n const edgeKey = (n1: Node, n2: Node) => {\n const keys = [n1.key, n2.key].sort();\n return `${keys[0]}-${keys[1]}`;\n };\n\n const getOrCreateNode = useCallback((x: number, y: number): Node => {\n const key = nodeKey(x, y);\n if (!nodesRef.current.has(key)) {\n nodesRef.current.set(key, { x, y, key });\n }\n return nodesRef.current.get(key)!;\n }, []);\n\n const addEdge = useCallback(\n (x1: number, y1: number, x2: number, y2: number) => {\n const from = getOrCreateNode(x1, y1);\n const to = getOrCreateNode(x2, y2);\n const key = edgeKey(from, to);\n\n const existingEdge = edgesRef.current.find((e) => e.key === key);\n if (existingEdge) return;\n\n const edge: Edge = { from, to, key };\n edgesRef.current.push(edge);\n\n if (!adjacencyRef.current.has(from.key)) {\n adjacencyRef.current.set(from.key, []);\n }\n if (!adjacencyRef.current.has(to.key)) {\n adjacencyRef.current.set(to.key, []);\n }\n adjacencyRef.current.get(from.key)!.push(edge);\n adjacencyRef.current.get(to.key)!.push(edge);\n },\n [getOrCreateNode]\n );\n\n const buildSquareGraph = useCallback(\n (width: number, height: number) => {\n nodesRef.current.clear();\n edgesRef.current = [];\n adjacencyRef.current.clear();\n topNodesRef.current = [];\n bottomNodesRef.current = [];\n\n const cols = Math.ceil(width / cellSize) + 1;\n const rows = Math.ceil(height / cellSize) + 1;\n\n for (let i = 0; i <= cols; i++) {\n for (let j = 0; j <= rows; j++) {\n const x = i * cellSize;\n const y = j * cellSize;\n if (i < cols) addEdge(x, y, x + cellSize, y);\n if (j < rows) addEdge(x, y, x, y + cellSize);\n }\n }\n\n const maxY = rows * cellSize;\n for (let i = 0; i <= cols; i++) {\n const topNode = nodesRef.current.get(nodeKey(i * cellSize, 0));\n if (topNode) topNodesRef.current.push(topNode);\n\n const bottomNode = nodesRef.current.get(nodeKey(i * cellSize, maxY));\n if (bottomNode) bottomNodesRef.current.push(bottomNode);\n }\n },\n [cellSize, addEdge]\n );\n\n const buildHexGraph = useCallback(\n (width: number, height: number) => {\n nodesRef.current.clear();\n edgesRef.current = [];\n adjacencyRef.current.clear();\n topNodesRef.current = [];\n bottomNodesRef.current = [];\n\n const size = cellSize / 2;\n const hexWidth = Math.sqrt(3) * size;\n const vertSpacing = size * 1.5;\n\n const cols = Math.ceil(width / hexWidth) + 2;\n const rows = Math.ceil(height / vertSpacing) + 2;\n\n for (let row = -1; row < rows; row++) {\n for (let col = -1; col < cols; col++) {\n const cx = col * hexWidth + (row % 2 === 0 ? 0 : hexWidth / 2);\n const cy = row * vertSpacing;\n\n const vertices: { x: number; y: number }[] = [];\n for (let i = 0; i < 6; i++) {\n const angle = (Math.PI / 3) * i - Math.PI / 2;\n vertices.push({\n x: cx + size * Math.cos(angle),\n y: cy + size * Math.sin(angle),\n });\n }\n\n for (let i = 0; i < 6; i++) {\n const v1 = vertices[i];\n const v2 = vertices[(i + 1) % 6];\n addEdge(v1.x, v1.y, v2.x, v2.y);\n }\n }\n }\n\n const allNodes = Array.from(nodesRef.current.values());\n\n const visibleNodes = allNodes.filter((n) => n.y >= 0 && n.y <= height);\n\n topNodesRef.current = visibleNodes\n .filter((n) => n.y <= size * 2)\n .sort((a, b) => a.x - b.x);\n\n bottomNodesRef.current = visibleNodes\n .filter((n) => n.y >= height - size * 2)\n .sort((a, b) => a.x - b.x);\n },\n [cellSize, addEdge]\n );\n\n const getConnectedNodes = useCallback(\n (node: Node, excludeNode?: Node): Node[] => {\n const edges = adjacencyRef.current.get(node.key) || [];\n return edges\n .map((e) => (e.from.key === node.key ? e.to : e.from))\n .filter((n) => !excludeNode || n.key !== excludeNode.key);\n },\n []\n );\n\n useEffect(() => {\n const canvas = canvasRef.current;\n const container = containerRef.current;\n if (!canvas || !container) return;\n\n let dpr = 1;\n\n const drawGrid = (\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number\n ) => {\n ctx.clearRect(0, 0, width, height);\n ctx.strokeStyle = lineColor;\n ctx.lineWidth = lineWidth;\n ctx.beginPath();\n\n for (const edge of edgesRef.current) {\n ctx.moveTo(edge.from.x, edge.from.y);\n ctx.lineTo(edge.to.x, edge.to.y);\n }\n\n ctx.stroke();\n };\n\n const drawTrails = (ctx: CanvasRenderingContext2D) => {\n for (const trail of trailsRef.current) {\n if (trail.opacity <= 0) continue;\n\n const alpha = Math.floor(trail.opacity * 0.08 * 255)\n .toString(16)\n .padStart(2, '0');\n\n ctx.strokeStyle = lightColor + alpha;\n ctx.lineWidth = 1;\n ctx.lineCap = 'round';\n ctx.beginPath();\n ctx.moveTo(trail.fromX, trail.fromY);\n\n if (trail.progress < 1) {\n const endX = trail.fromX + (trail.toX - trail.fromX) * trail.progress;\n const endY = trail.fromY + (trail.toY - trail.fromY) * trail.progress;\n ctx.lineTo(endX, endY);\n } else {\n ctx.lineTo(trail.toX, trail.toY);\n }\n ctx.stroke();\n\n ctx.shadowColor = lightColor;\n ctx.shadowBlur = 2;\n ctx.stroke();\n ctx.shadowBlur = 0;\n }\n };\n\n const drawParticles = (ctx: CanvasRenderingContext2D) => {\n for (const particle of particlesRef.current) {\n if (particle.dead) continue;\n\n const history = particle.history;\n if (history.length === 0) continue;\n\n const head = history[history.length - 1];\n\n if (history.length >= 2) {\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n const r = parseInt(lightColor.slice(1, 3), 16);\n const g = parseInt(lightColor.slice(3, 5), 16);\n const b = parseInt(lightColor.slice(5, 7), 16);\n const lighterR = Math.floor(r + (255 - r) * 0.6);\n const lighterG = Math.floor(g + (255 - g) * 0.6);\n const lighterB = Math.floor(b + (255 - b) * 0.6);\n ctx.strokeStyle = `rgb(${lighterR}, ${lighterG}, ${lighterB})`;\n\n const maxWidth = 4;\n const minWidth = 0.5;\n for (let i = 1; i < history.length; i++) {\n const progress = i / (history.length - 1);\n ctx.lineWidth = minWidth + (maxWidth - minWidth) * progress;\n ctx.beginPath();\n ctx.moveTo(history[i - 1].x, history[i - 1].y);\n ctx.lineTo(history[i].x, history[i].y);\n ctx.stroke();\n }\n }\n\n ctx.fillStyle = lightColor;\n ctx.beginPath();\n let angle = 0;\n if (history.length >= 2) {\n const prev = history[history.length - 2];\n angle = Math.atan2(head.y - prev.y, head.x - prev.x);\n }\n ctx.save();\n ctx.translate(head.x, head.y);\n ctx.rotate(angle);\n ctx.moveTo(-3, 0);\n ctx.quadraticCurveTo(1, -2.5, 2, 0);\n ctx.quadraticCurveTo(1, 2.5, -3, 0);\n ctx.restore();\n ctx.fill();\n }\n };\n\n const drawExplosions = (ctx: CanvasRenderingContext2D) => {\n for (const explosion of explosionsRef.current) {\n if (explosion.opacity <= 0) continue;\n\n const alpha = Math.floor(explosion.opacity * 255)\n .toString(16)\n .padStart(2, '0');\n ctx.strokeStyle = lightColor + alpha;\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.arc(explosion.x, explosion.y, explosion.radius, 0, Math.PI * 2);\n ctx.stroke();\n }\n };\n\n const updateExplosions = () => {\n for (const explosion of explosionsRef.current) {\n explosion.radius += 0.5;\n explosion.opacity -= 0.08;\n }\n explosionsRef.current = explosionsRef.current.filter(\n (e) => e.opacity > 0\n );\n };\n\n const createExplosion = (x: number, y: number) => {\n explosionsRef.current.push({\n x,\n y,\n radius: 2,\n maxRadius: 8,\n opacity: 1,\n });\n };\n\n const createNodeGlow = (x: number, y: number) => {\n nodeGlowsRef.current.push({\n x,\n y,\n opacity: 1,\n });\n };\n\n const drawNodeGlows = (ctx: CanvasRenderingContext2D) => {\n for (const glow of nodeGlowsRef.current) {\n if (glow.opacity <= 0) continue;\n\n const alpha = Math.floor(glow.opacity * 0.4 * 255)\n .toString(16)\n .padStart(2, '0');\n ctx.fillStyle = lightColor + alpha;\n ctx.beginPath();\n ctx.arc(glow.x, glow.y, 2, 0, Math.PI * 2);\n ctx.fill();\n }\n };\n\n const updateNodeGlows = () => {\n for (const glow of nodeGlowsRef.current) {\n glow.opacity -= trailFadeSpeed * 3;\n }\n nodeGlowsRef.current = nodeGlowsRef.current.filter((g) => g.opacity > 0);\n };\n\n const getRandomTravel = () => {\n return (\n Math.floor(Math.random() * (maxTravel - minTravel + 1)) + minTravel\n );\n };\n\n const makeEdgeKey = (n1: Node, n2: Node) => {\n const keys = [n1.key, n2.key].sort();\n return `${keys[0]}-${keys[1]}`;\n };\n\n const trySpawn = (fromTop: boolean): boolean => {\n const sourceNodes = fromTop\n ? topNodesRef.current\n : bottomNodesRef.current;\n const direction: 1 | -1 = fromTop ? 1 : -1;\n\n if (sourceNodes.length === 0) return false;\n\n const startNode =\n sourceNodes[Math.floor(Math.random() * sourceNodes.length)];\n const connectedNodes = getConnectedNodes(startNode);\n\n const preferredNodes = connectedNodes.filter((n) =>\n fromTop ? n.y > startNode.y : n.y < startNode.y\n );\n const targetNodes =\n preferredNodes.length > 0 ? preferredNodes : connectedNodes;\n\n const availableNodes = targetNodes.filter((n) => {\n const key = makeEdgeKey(startNode, n);\n return !activeEdgesRef.current.has(key);\n });\n\n if (availableNodes.length === 0) return false;\n\n const targetNode =\n availableNodes[Math.floor(Math.random() * availableNodes.length)];\n const edgeKeyStr = makeEdgeKey(startNode, targetNode);\n activeEdgesRef.current.add(edgeKeyStr);\n\n particlesRef.current.push({\n id: particleIdRef.current++,\n currentNode: startNode,\n targetNode,\n progress: 0,\n traveled: 0,\n maxTravel: getRandomTravel(),\n canSplit: true,\n dead: false,\n direction,\n history: [{ x: startNode.x, y: startNode.y }],\n });\n\n trailsRef.current.push({\n fromX: startNode.x,\n fromY: startNode.y,\n toX: targetNode.x,\n toY: targetNode.y,\n progress: 0,\n opacity: 1,\n edgeKey: edgeKeyStr,\n });\n\n return true;\n };\n\n const spawnParticle = () => {\n if (bidirectional) {\n const fromTop = spawnFromTopRef.current;\n spawnFromTopRef.current = !spawnFromTopRef.current;\n\n if (!trySpawn(fromTop)) {\n trySpawn(!fromTop);\n }\n } else {\n trySpawn(true);\n }\n };\n\n const updateParticles = () => {\n const newParticles: Particle[] = [];\n const maxHistoryLength = trailLength;\n\n for (const particle of particlesRef.current) {\n if (particle.dead) continue;\n\n particle.progress += lightSpeed * 0.02;\n\n const currentX =\n particle.currentNode.x +\n (particle.targetNode.x - particle.currentNode.x) * particle.progress;\n const currentY =\n particle.currentNode.y +\n (particle.targetNode.y - particle.currentNode.y) * particle.progress;\n particle.history.push({ x: currentX, y: currentY });\n if (particle.history.length > maxHistoryLength) {\n particle.history.shift();\n }\n\n const trailIndex = trailsRef.current.findIndex(\n (t) =>\n t.fromX === particle.currentNode.x &&\n t.fromY === particle.currentNode.y &&\n t.toX === particle.targetNode.x &&\n t.toY === particle.targetNode.y &&\n t.progress < 1\n );\n if (trailIndex !== -1) {\n trailsRef.current[trailIndex].progress = Math.min(\n particle.progress,\n 1\n );\n }\n\n if (particle.progress >= 1) {\n createNodeGlow(particle.targetNode.x, particle.targetNode.y);\n particle.traveled++;\n\n if (particle.traveled >= particle.maxTravel) {\n const x = particle.targetNode.x;\n const y = particle.targetNode.y;\n createExplosion(x, y);\n particle.dead = true;\n continue;\n }\n\n const currentNode = particle.targetNode;\n const connectedNodes = getConnectedNodes(\n currentNode,\n particle.currentNode\n );\n\n const availableNodes = connectedNodes.filter((n) => {\n const key = makeEdgeKey(currentNode, n);\n return !activeEdgesRef.current.has(key);\n });\n\n if (availableNodes.length === 0) {\n createExplosion(currentNode.x, currentNode.y);\n particle.dead = true;\n continue;\n }\n\n const shouldSplit =\n particle.canSplit &&\n Math.random() < splitChance &&\n availableNodes.length >= 2;\n\n if (shouldSplit) {\n const shuffled = [...availableNodes].sort(\n () => Math.random() - 0.5\n );\n const target1 = shuffled[0];\n const target2 = shuffled[1];\n\n const edgeKey1 = makeEdgeKey(currentNode, target1);\n const edgeKey2 = makeEdgeKey(currentNode, target2);\n activeEdgesRef.current.add(edgeKey1);\n activeEdgesRef.current.add(edgeKey2);\n\n particle.currentNode = currentNode;\n particle.targetNode = target1;\n particle.progress = 0;\n particle.canSplit = false;\n\n trailsRef.current.push({\n fromX: currentNode.x,\n fromY: currentNode.y,\n toX: target1.x,\n toY: target1.y,\n progress: 0,\n opacity: 1,\n edgeKey: edgeKey1,\n });\n\n newParticles.push({\n id: particleIdRef.current++,\n currentNode: currentNode,\n targetNode: target2,\n progress: 0,\n traveled: particle.traveled,\n maxTravel: particle.maxTravel,\n canSplit: false,\n dead: false,\n direction: particle.direction,\n history: [{ x: currentNode.x, y: currentNode.y }],\n });\n\n trailsRef.current.push({\n fromX: currentNode.x,\n fromY: currentNode.y,\n toX: target2.x,\n toY: target2.y,\n progress: 0,\n opacity: 1,\n edgeKey: edgeKey2,\n });\n } else {\n const targetNode =\n availableNodes[Math.floor(Math.random() * availableNodes.length)];\n const newEdgeKey = makeEdgeKey(currentNode, targetNode);\n activeEdgesRef.current.add(newEdgeKey);\n\n particle.currentNode = currentNode;\n particle.targetNode = targetNode;\n particle.progress = 0;\n\n trailsRef.current.push({\n fromX: currentNode.x,\n fromY: currentNode.y,\n toX: targetNode.x,\n toY: targetNode.y,\n progress: 0,\n opacity: 1,\n edgeKey: newEdgeKey,\n });\n }\n }\n }\n\n particlesRef.current.push(...newParticles);\n particlesRef.current = particlesRef.current.filter((p) => !p.dead);\n };\n\n const updateTrails = () => {\n for (const trail of trailsRef.current) {\n if (trail.progress >= 1) {\n trail.opacity -= trailFadeSpeed;\n }\n }\n const fadedTrails = trailsRef.current.filter((t) => t.opacity <= 0);\n for (const trail of fadedTrails) {\n activeEdgesRef.current.delete(trail.edgeKey);\n }\n trailsRef.current = trailsRef.current.filter((t) => t.opacity > 0);\n };\n\n const animate = (timestamp: number) => {\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const { width, height } = dimensionsRef.current;\n\n ctx.save();\n ctx.scale(dpr, dpr);\n drawGrid(ctx, width, height);\n\n if (animated) {\n if (timestamp - lastSpawnRef.current > spawnRate) {\n spawnParticle();\n lastSpawnRef.current = timestamp;\n }\n\n updateParticles();\n updateTrails();\n updateExplosions();\n updateNodeGlows();\n drawTrails(ctx);\n drawNodeGlows(ctx);\n drawParticles(ctx);\n drawExplosions(ctx);\n }\n\n ctx.restore();\n animationRef.current = requestAnimationFrame(animate);\n };\n\n const setup = () => {\n const { width, height } = container.getBoundingClientRect();\n dimensionsRef.current = { width, height };\n dpr = window.devicePixelRatio || 1;\n\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n\n if (shape === 4) {\n buildSquareGraph(width, height);\n } else {\n buildHexGraph(width, height);\n }\n\n particlesRef.current = [];\n trailsRef.current = [];\n activeEdgesRef.current.clear();\n explosionsRef.current = [];\n nodeGlowsRef.current = [];\n };\n\n const resizeObserver = new ResizeObserver(() => {\n setup();\n });\n\n resizeObserver.observe(container);\n setup();\n animationRef.current = requestAnimationFrame(animate);\n\n return () => {\n resizeObserver.disconnect();\n cancelAnimationFrame(animationRef.current);\n };\n }, [\n shape,\n cellSize,\n lineColor,\n lineWidth,\n animated,\n lightColor,\n lightSpeed,\n minTravel,\n maxTravel,\n spawnRate,\n splitChance,\n trailFadeSpeed,\n bidirectional,\n trailLength,\n buildSquareGraph,\n buildHexGraph,\n getConnectedNodes,\n ]);\n\n return (\n <div ref={containerRef} className={`relative w-full h-full ${className}`}>\n <canvas ref={canvasRef} className=\"absolute inset-0\" />\n </div>\n );\n}\n\nexport default Grid;\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-grid-lights",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A React component for animated grid backgrounds with traveling light particles. Supports square and hexagonal grids with customizable animations.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|