jl-particle-interactive 0.2.2 → 0.3.1

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/README.md CHANGED
@@ -86,112 +86,85 @@ export default function App() {
86
86
 
87
87
  ---
88
88
 
89
- ## Examples
89
+ ## Text examples
90
90
 
91
- ### Text with a color palette
91
+ ### 1. Free-floating particles
92
92
 
93
- Assign multiple colors and each particle picks one at random.
93
+ When `text` is an empty string, particles scatter and drift freely across the canvas — great for ambient loading screens or decorative backgrounds.
94
94
 
95
95
  ```tsx
96
- <ParticleCanvas height="60vh">
97
- <TextParticleEngine
98
- text="React"
99
- particleColor={['#ff6b6b', '#feca57', '#48dbfb']}
100
- particleSize={1.5}
101
- />
102
- </ParticleCanvas>
103
- ```
104
-
105
- ---
106
-
107
- ### Repel on click
108
-
109
- Particles flee from the cursor while the mouse button is held down.
96
+ import { ParticleCanvas, TextParticleEngine } from 'jl-particle-interactive';
110
97
 
111
- ```tsx
112
- <ParticleCanvas height="60vh">
113
- <TextParticleEngine
114
- text="Boom"
115
- clickMode="repel"
116
- particleEase={2}
117
- />
118
- </ParticleCanvas>
98
+ export default function FloatingParticles() {
99
+ return (
100
+ <ParticleCanvas height="60vh" backgroundColor="#050505">
101
+ <TextParticleEngine
102
+ text=""
103
+ particleColor={['#60a5fa', '#a78bfa', '#34d399']}
104
+ particleSize={1.2}
105
+ isMagnet={true}
106
+ />
107
+ </ParticleCanvas>
108
+ );
109
+ }
119
110
  ```
120
111
 
121
112
  ---
122
113
 
123
- ### Attract on click
114
+ ### 2. Hello 🖐️ — magnetic hover + color palette
124
115
 
125
- The opposite particles swarm toward the cursor on press.
116
+ Particles form the text and spring toward the cursor on hover. Click and hold to repel them outward.
126
117
 
127
118
  ```tsx
128
- <ParticleCanvas height="60vh">
129
- <TextParticleEngine
130
- text="Pull"
131
- clickMode="attract"
132
- isMagnet={false}
133
- />
134
- </ParticleCanvas>
135
- ```
136
-
137
- ---
138
-
139
- ### Animated NET background
140
-
141
- A connected particle network moves behind your content.
119
+ import { ParticleCanvas, TextParticleEngine } from 'jl-particle-interactive';
142
120
 
143
- ```tsx
144
- <ParticleCanvas
145
- height="80vh"
146
- background={{
147
- name: 'NET',
148
- color: '#4ecdc4',
149
- density: 0.8,
150
- }}
151
- >
152
- <TextParticleEngine text="Network" particleColor="#ffffff" />
153
- </ParticleCanvas>
121
+ export default function HelloParticles() {
122
+ return (
123
+ <ParticleCanvas height="60vh" backgroundColor="#050505">
124
+ <TextParticleEngine
125
+ text="Hello 🖐️"
126
+ particleColor={['#f472b6', '#fb923c', '#facc15', '#34d399', '#60a5fa']}
127
+ particleSize={1.3}
128
+ particleEase={1.2}
129
+ isMagnet={true}
130
+ clickMode="repel"
131
+ particleShape="circle"
132
+ />
133
+ </ParticleCanvas>
134
+ );
135
+ }
154
136
  ```
155
137
 
156
138
  ---
157
139
 
158
- ### Jellyfish background
140
+ ### 3. Word carousel — cycles every 3 seconds
159
141
 
160
- Smooth, organic blobs that drift across the canvas.
142
+ The particles re-form automatically each time the `text` prop changes. No extra animation code needed.
161
143
 
162
144
  ```tsx
163
- <ParticleCanvas
164
- height="80vh"
165
- background={{
166
- name: 'JELLYFISH',
167
- colors: ['#ff6b6b', '#a29bfe', '#00cec9'],
168
- colorMode: 'wave',
169
- }}
170
- >
171
- <TextParticleEngine text="Fluid" particleColor="#ffffff" />
172
- </ParticleCanvas>
173
- ```
174
-
175
- ---
176
-
177
- ### Dynamic text
178
-
179
- Change the `text` prop and the particles re-form automatically.
145
+ import { useEffect, useState } from 'react';
146
+ import { ParticleCanvas, TextParticleEngine } from 'jl-particle-interactive';
180
147
 
181
- ```tsx
182
- const words = ['Hello', 'World', 'React'];
148
+ const words = ['Create', 'Inspire', 'React'];
183
149
 
184
- export default function Carousel() {
150
+ export default function WordCarousel() {
185
151
  const [index, setIndex] = useState(0);
186
152
 
187
153
  useEffect(() => {
188
- const id = setInterval(() => setIndex(i => (i + 1) % words.length), 2000);
154
+ const id = setInterval(() => setIndex(i => (i + 1) % words.length), 3000);
189
155
  return () => clearInterval(id);
190
156
  }, []);
191
157
 
192
158
  return (
193
- <ParticleCanvas height="60vh">
194
- <TextParticleEngine text={words[index]} />
159
+ <ParticleCanvas height="60vh" backgroundColor="#050505">
160
+ <TextParticleEngine
161
+ text={words[index]}
162
+ particleColor={['#60a5fa', '#a78bfa', '#f472b6']}
163
+ particleSize={1.5}
164
+ particleEase={1.2}
165
+ isMagnet={true}
166
+ particleShape="bean"
167
+ />
195
168
  </ParticleCanvas>
196
169
  );
197
170
  }
@@ -199,177 +172,141 @@ export default function Carousel() {
199
172
 
200
173
  ---
201
174
 
202
- ## Background guide
203
-
204
- The `background` prop on `ParticleCanvas` supports four usage patterns:
175
+ ## Background examples
205
176
 
206
- 1. No animated background
207
- 2. `FOLLOW_POINTER` swarm background
208
- 3. `NET` node-link graph background
209
- 4. `JELLYFISH` organic glow/swim background
177
+ Use `<ParticleBackground>` for standalone animated backgrounds. Set the mode with the `name` prop and pass all options through `config`.
210
178
 
211
- ### 1) No background engine
179
+ ### 1. FOLLOW_POINTER swarm that follows the cursor
212
180
 
213
- Use this when you only want text particles.
181
+ Particles form a loose swarm that chases the cursor across the canvas.
214
182
 
215
183
  ```tsx
216
- <ParticleCanvas background={{ name: 'NONE' }}>
217
- <TextParticleEngine text="Only Text" />
218
- </ParticleCanvas>
219
- ```
220
-
221
- ### 2) FOLLOW_POINTER background
184
+ import { ParticleBackground } from 'jl-particle-interactive';
222
185
 
223
- Particles form a swarm that follows the cursor smoothly.
224
-
225
- ```tsx
226
- <ParticleCanvas
227
- background={{
228
- name: 'FOLLOW_POINTER',
229
- orientation: 'diagonal',
230
- density: 1,
231
- shape: 'bean',
232
- colors: ['#00d4ff', '#6ee7b7', '#facc15'],
233
- colorMode: 'wave',
234
- particleSpeed: 1,
235
- pointerTrackingSpeed: 0.06,
236
- }}
237
- >
238
- <TextParticleEngine text="Follow" particleColor="255, 255, 255" />
239
- </ParticleCanvas>
186
+ export default function FollowPointerDemo() {
187
+ return (
188
+ <ParticleBackground
189
+ name="FOLLOW_POINTER"
190
+ height="60vh"
191
+ backgroundColor="#050505"
192
+ config={{
193
+ orientation: 'diagonal',
194
+ density: 1,
195
+ shape: 'bean',
196
+ colors: ['#00d4ff', '#6ee7b7', '#facc15'],
197
+ colorMode: 'wave',
198
+ particleSpeed: 1,
199
+ pointerTrackingSpeed: 0.06,
200
+ }}
201
+ />
202
+ );
203
+ }
240
204
  ```
241
205
 
242
- ### 3) NET background
243
-
244
- Moving nodes connect with lines. Great for tech-style hero sections.
245
-
246
- ```tsx
247
- <ParticleCanvas
248
- background={{
249
- name: 'NET',
250
- density: 0.9,
251
- shape: 'circle',
252
- colors: ['#7dd3fc', '#60a5fa'],
253
- colorMode: 'mixed',
254
- particleSpeed: 1,
255
- pointerTrackingSpeed: 0.08,
256
- }}
257
- >
258
- <TextParticleEngine text="Network" particleColor="255, 255, 255" />
259
- </ParticleCanvas>
260
- ```
206
+ ---
261
207
 
262
- ### 4) JELLYFISH background
208
+ ### 2. NET — connected node graph
263
209
 
264
- Soft organic particle body with pulse/swimming motion.
210
+ Particles bounce around and draw lines between nearby nodes. Great for tech-style hero sections.
265
211
 
266
212
  ```tsx
267
- <ParticleCanvas
268
- background={{
269
- name: 'JELLYFISH',
270
- density: 1.1,
271
- shape: 'bean',
272
- colors: ['#f472b6', '#a78bfa', '#22d3ee'],
273
- colorMode: 'wave',
274
- particleSpeed: 1,
275
- pointerTrackingSpeed: 0.02,
276
- }}
277
- >
278
- <TextParticleEngine text="Jelly" particleColor="255, 255, 255" />
279
- </ParticleCanvas>
213
+ import { ParticleBackground } from 'jl-particle-interactive';
214
+
215
+ export default function NetDemo() {
216
+ return (
217
+ <ParticleBackground
218
+ name="NET"
219
+ height="60vh"
220
+ backgroundColor="#050505"
221
+ config={{
222
+ density: 0.9,
223
+ shape: 'circle',
224
+ colors: ['#7dd3fc', '#60a5fa', '#a78bfa'],
225
+ colorMode: 'mixed',
226
+ particleSpeed: 1,
227
+ pointerTrackingSpeed: 0.08,
228
+ }}
229
+ />
230
+ );
231
+ }
280
232
  ```
281
233
 
282
- ### Background with transparent stage
234
+ ---
235
+
236
+ ### 3. JELLYFISH — organic pulsing glow
283
237
 
284
- Use `backgroundColor="transparent"` to place particles over your own image/gradient layer.
238
+ Soft concentric rings expand and contract in a slow breathing cycle. Particles drift with organic float noise.
285
239
 
286
240
  ```tsx
287
- <div style={{ background: 'linear-gradient(135deg, #0f172a, #111827)' }}>
288
- <ParticleCanvas
289
- height="70vh"
290
- backgroundColor="transparent"
291
- background={{ name: 'NET', density: 0.7, color: '#67e8f9' }}
292
- >
293
- <TextParticleEngine text="Overlay" backgroundColor="transparent" />
294
- </ParticleCanvas>
295
- </div>
296
- ```
241
+ import { ParticleBackground } from 'jl-particle-interactive';
297
242
 
298
- ### Full `BackgroundCanvas` type
299
-
300
- ```ts
301
- type BackgroundModeName = 'NONE' | 'FOLLOW_POINTER' | 'NET' | 'JELLYFISH';
302
- type ParticleOrientation = 'vertical' | 'horizontal' | 'diagonal';
303
-
304
- interface BackgroundCanvas {
305
- name: BackgroundModeName;
306
- orientation?: ParticleOrientation;
307
- density?: number;
308
- color?: string;
309
- colors?: string[];
310
- colorMode?: 'wave' | 'mixed';
311
- interactionRadius?: number;
312
- lineDistance?: number;
313
- shape?: 'circle' | 'square' | 'bean';
314
- particleSpeed?: number;
315
- pointerTrackingSpeed?: number;
243
+ export default function JellyfishDemo() {
244
+ return (
245
+ <ParticleBackground
246
+ name="JELLYFISH"
247
+ height="60vh"
248
+ backgroundColor="#050505"
249
+ config={{
250
+ density: 1.1,
251
+ shape: 'circle',
252
+ colors: ['#f472b6', '#a78bfa', '#22d3ee'],
253
+ colorMode: 'wave',
254
+ particleSpeed: 1,
255
+ pointerTrackingSpeed: 0.02,
256
+ }}
257
+ />
258
+ );
316
259
  }
317
260
  ```
318
261
 
319
- ### Option matrix (what applies to each mode)
320
-
321
- | Option | FOLLOW_POINTER | NET | JELLYFISH | Notes |
322
- |---|---|---|---|---|
323
- | `name` | ✓ | ✓ | ✓ | Mode selector |
324
- | `density` | ✓ | ✓ | ✓ | Particle count multiplier |
325
- | `color` | ✓ | ✓ | ✓ | Single hex/HSL/CSS color |
326
- | `colors` | ✓ | ✓ | ✓ | Palette override |
327
- | `colorMode` | ✓ | ✓ | ✓ | `wave` (default) or `mixed` |
328
- | `shape` | ✓ | ✓ | ✓ | `bean` default in FOLLOW_POINTER, `circle` in NET/JELLYFISH |
329
- | `particleSpeed` | ✓ | ✓ | ✓ | Animation speed multiplier |
330
- | `pointerTrackingSpeed` | ✓ | ✓ | ✓ | Cursor-follow/response smoothness |
331
- | `orientation` | ✓ | — | — | Only FOLLOW_POINTER (`vertical` default) |
332
- | `interactionRadius` | — | — | — | Declared in type, currently not applied in v0.2.1 |
333
- | `lineDistance` | — | — | — | Declared in type, currently not applied in v0.2.1 |
334
-
335
- ### Practical presets
336
-
337
- | Goal | Suggested config |
338
- |---|---|
339
- | Calm ambient hero | `JELLYFISH`, `density: 0.8`, `pointerTrackingSpeed: 0.015` |
340
- | High-energy interactive background | `FOLLOW_POINTER`, `density: 1.2`, `particleSpeed: 1.3`, `shape: 'bean'` |
341
- | Tech/network look | `NET`, `density: 0.9`, `colorMode: 'mixed'`, cool blue palette |
342
-
343
262
  ---
344
263
 
345
264
  ## API reference
346
265
 
347
- ### `<ParticleCanvas>`
266
+ ### `<ParticleBackground>`
267
+
268
+ Standalone background component. Use this when you want an animated background without any text particles.
348
269
 
349
270
  | Prop | Type | Default | Description |
350
271
  |---|---|---|---|
272
+ | `name` | `'NONE' \| 'FOLLOW_POINTER' \| 'NET' \| 'JELLYFISH'` | **required** | Background engine to render |
273
+ | `config` | `BackgroundConfig` | `undefined` | All engine options (see table below) |
351
274
  | `width` | `string \| number` | `'100%'` | Container width |
352
275
  | `height` | `string \| number` | `'60vh'` | Container height |
353
- | `backgroundColor` | `string` | `'#050505'` | Background color |
354
- | `background` | `BackgroundCanvas` | `{ name: 'NONE' }` | Animated background config |
276
+ | `backgroundColor` | `string` | `'#050505'` | Background fill color |
355
277
  | `className` | `string` | `''` | Additional CSS class |
356
278
  | `style` | `CSSProperties` | — | Inline style overrides |
357
279
 
358
- ### `BackgroundCanvas`
359
-
360
- | Prop | Type | Description |
361
- |---|---|---|
362
- | `name` | `'NONE' \| 'FOLLOW_POINTER' \| 'NET' \| 'JELLYFISH'` | Background mode |
363
- | `orientation` | `'vertical' \| 'horizontal' \| 'diagonal'` | Direction style for `FOLLOW_POINTER` |
364
- | `density` | `number` | Particle amount multiplier |
365
- | `color` | `string` | Single background particle color |
366
- | `colors` | `string[]` | Background particle palette |
367
- | `colorMode` | `'wave' \| 'mixed'` | Palette propagation mode |
368
- | `shape` | `'circle' \| 'square' \| 'bean'` | Particle drawing shape |
369
- | `particleSpeed` | `number` | Background animation speed multiplier |
370
- | `pointerTrackingSpeed` | `number` | Cursor tracking interpolation factor |
371
- | `interactionRadius` | `number` | Reserved in type (not applied in v0.2.1) |
372
- | `lineDistance` | `number` | Reserved in type (not applied in v0.2.1) |
280
+ ### `BackgroundConfig` (`config` prop options)
281
+
282
+ All fields are optional. Pass any combination inside the `config` prop of `<ParticleBackground>`.
283
+
284
+ | Option | Type | Applies to | Description |
285
+ |---|---|---|---|
286
+ | `density` | `number` | all modes | Particle count multiplier. Base counts: FOLLOW_POINTER=350, NET≈300, JELLYFISH=350 |
287
+ | `color` | `string` | all modes | Single hex color for all particles |
288
+ | `colors` | `string[]` | all modes | Palette of hex colors; overrides `color` |
289
+ | `colorMode` | `'wave' \| 'mixed'` | all modes | How colors propagate across particles |
290
+ | `shape` | `'circle' \| 'square' \| 'bean'` | all modes | Particle drawing shape |
291
+ | `particleSpeed` | `number` | all modes | Animation speed multiplier |
292
+ | `pointerTrackingSpeed` | `number` | all modes | How fast particles follow the cursor (lower = floatier) |
293
+ | `orientation` | `'vertical' \| 'horizontal' \| 'diagonal'` | FOLLOW_POINTER only | Swarm drift direction |
294
+ | `interactionRadius` | `number` | | Declared in type; not applied in current version |
295
+ | `lineDistance` | `number` | — | Declared in type; not applied in current version |
296
+
297
+ ### `<ParticleCanvas>`
298
+
299
+ Container that combines text particles with an optional background. Use `background` to activate a background engine alongside `<TextParticleEngine>` children.
300
+
301
+ | Prop | Type | Default | Description |
302
+ |---|---|---|---|
303
+ | `children` | `ReactNode` | — | Content rendered above background (z-index 10) |
304
+ | `width` | `string \| number` | `'100%'` | Container width |
305
+ | `height` | `string \| number` | `'60vh'` | Container height |
306
+ | `backgroundColor` | `string` | `'#050505'` | Background fill color |
307
+ | `background` | `BackgroundCanvas` | `{ name: 'NONE' }` | Background engine config (flat object with `name` + all options) |
308
+ | `className` | `string` | `''` | Additional CSS class |
309
+ | `style` | `CSSProperties` | — | Inline style overrides |
373
310
 
374
311
  ### `<TextParticleEngine>`
375
312
 
@@ -0,0 +1,12 @@
1
+ import { CSSProperties } from 'react';
2
+ import { BackgroundModeName, BackgroundCanvas } from '../../types/background';
3
+ export interface ParticleBackgroundProps {
4
+ name: BackgroundModeName;
5
+ config?: Omit<BackgroundCanvas, 'name'>;
6
+ width?: string | number;
7
+ height?: string | number;
8
+ backgroundColor?: string;
9
+ className?: string;
10
+ style?: CSSProperties;
11
+ }
12
+ export default function ParticleBackground({ name, config, width, height, backgroundColor, className, style, }: ParticleBackgroundProps): import("react/jsx-runtime").JSX.Element;
package/dist/index.d.ts CHANGED
@@ -2,12 +2,8 @@ export { default as ParticleCanvas } from './components/ParticleCanvas';
2
2
  export type { ParticleCanvasProps } from './components/ParticleCanvas';
3
3
  export { default as TextParticleEngine } from './components/text/TextParticleEngine';
4
4
  export type { TextParticleEngineProps } from './components/text/TextParticleEngine';
5
- export { default as BackgroundParticleEngine } from './components/background/BackgroundParticleEngine';
6
- export type { BackgroundParticleEngineProps } from './components/background/BackgroundParticleEngine';
7
- export { default as NetParticleEngine } from './components/background/NetParticleEngine';
8
- export type { NetParticleEngineProps } from './components/background/NetParticleEngine';
9
- export { default as JellyfishParticleEngine } from './components/background/JellyfishParticleEngine';
10
- export type { JellyfishParticleEngineProps } from './components/background/JellyfishParticleEngine';
5
+ export { default as ParticleBackground } from './components/background/ParticleBackground';
6
+ export type { ParticleBackgroundProps } from './components/background/ParticleBackground';
11
7
  export { useParticleInteraction, getMagnetTarget } from './hooks/useParticleInteraction';
12
8
  export type { ClickMode } from './hooks/useParticleInteraction';
13
9
  export { useTextParticles } from './hooks/text/useTextParticles';
@@ -1,30 +1,30 @@
1
1
  var J = Object.defineProperty;
2
2
  var K = (t, e, n) => e in t ? J(t, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : t[e] = n;
3
- var g = (t, e, n) => K(t, typeof e != "symbol" ? e + "" : e, n);
3
+ var m = (t, e, n) => K(t, typeof e != "symbol" ? e + "" : e, n);
4
4
  import { jsx as $, jsxs as _ } from "react/jsx-runtime";
5
5
  import { useRef as I, useEffect as L } from "react";
6
6
  function U(t, e, n, i) {
7
- let s = e + t.baseX, m = n + t.baseY;
8
- s += Math.sin(i * t.randomSpeed + t.baseY * 0.05) * 15 * t.z, m += Math.cos(i * t.randomSpeed + t.baseX * 0.05) * 15 * t.z;
9
- const r = s - t.x, o = m - t.y, h = r * 0.06, y = o * 0.06;
10
- return { forceX: h, forceY: y };
7
+ let s = e + t.baseX, y = n + t.baseY;
8
+ s += Math.sin(i * t.randomSpeed + t.baseY * 0.05) * 15 * t.z, y += Math.cos(i * t.randomSpeed + t.baseX * 0.05) * 15 * t.z;
9
+ const r = s - t.x, o = y - t.y, h = r * 0.06, g = o * 0.06;
10
+ return { forceX: h, forceY: g };
11
11
  }
12
- function Q(t, e, n, i, s, m) {
13
- const r = i, o = s, h = t.x - r, y = t.y - o, d = Math.max(Math.sqrt(h * h + y * y), 1);
12
+ function Q(t, e, n, i, s, y) {
13
+ const r = i, o = s, h = t.x - r, g = t.y - o, d = Math.max(Math.sqrt(h * h + g * g), 1);
14
14
  let c = 0, a = 0;
15
- const u = Math.sin(d * 0.02 - m * 3) * 2.5 * t.z;
16
- c += h / d * u, a += y / d * u;
17
- const P = Math.cos(d * 0.01 - m * 1 + t.randomSpeed) * 0.8 * t.z, q = -y / d, b = h / d;
18
- return c += q * P, a += b * P, { forceX: c, forceY: a, dxCenter: h, dyCenter: y, distToCenter: d };
15
+ const u = Math.sin(d * 0.02 - y * 3) * 2.5 * t.z;
16
+ c += h / d * u, a += g / d * u;
17
+ const P = Math.cos(d * 0.01 - y * 1 + t.randomSpeed) * 0.8 * t.z, q = -g / d, b = h / d;
18
+ return c += q * P, a += b * P, { forceX: c, forceY: a, dxCenter: h, dyCenter: g, distToCenter: d };
19
19
  }
20
20
  function V(t, e) {
21
21
  let s = Math.min(e / 400, 1) * 2.5 + t.sizeBias * 1;
22
22
  s < 0.4 && (s = 0), t.scale += (s - t.scale) * 0.15;
23
23
  }
24
- function Z(t, e, n, i, s, m) {
24
+ function Z(t, e, n, i, s, y) {
25
25
  let r = 0, o = 0;
26
26
  s === "horizontal" ? (r = 1, o = 0) : s === "diagonal" ? (r = -e / i, o = -n / i) : (r = -n / i, o = e / i);
27
- const h = Math.atan2(o, r), y = t.sizeBias > 0.3 ? 1 : 0, d = Math.max(0, Math.sin(m * 0.5 + t.randomSpeed * 10)), c = Math.sin(m * 3 + t.baseX * 0.1 + t.randomSpeed) * 0.5 * d * y;
27
+ const h = Math.atan2(o, r), g = t.sizeBias > 0.3 ? 1 : 0, d = Math.max(0, Math.sin(y * 0.5 + t.randomSpeed * 10)), c = Math.sin(y * 3 + t.baseX * 0.1 + t.randomSpeed) * 0.5 * d * g;
28
28
  r = Math.cos(h + c), o = Math.sin(h + c);
29
29
  const a = Math.max(1 - i / 400, 0.1);
30
30
  s === "horizontal" ? (t.dirX = t.dirX * (1 - 0.2) + r * 0.2, t.dirY = t.dirY * (1 - 0.2) + o * 0.2) : (t.dirX = t.dirX * (1 - a * 0.3) + r * a * 0.3, t.dirY = t.dirY * (1 - a * 0.3) + o * a * 0.3);
@@ -33,31 +33,31 @@ function Z(t, e, n, i, s, m) {
33
33
  }
34
34
  class tt {
35
35
  constructor(e, n, i) {
36
- g(this, "x");
37
- g(this, "y");
38
- g(this, "baseX");
36
+ m(this, "x");
37
+ m(this, "y");
38
+ m(this, "baseX");
39
39
  // Relative X to swarm center
40
- g(this, "baseY");
40
+ m(this, "baseY");
41
41
  // Relative Y to swarm center
42
- g(this, "z");
43
- g(this, "vx");
44
- g(this, "vy");
45
- g(this, "color");
46
- g(this, "targetColor", null);
47
- g(this, "colorDelay", 0);
48
- g(this, "angleTarget");
49
- g(this, "randomSpeed");
50
- g(this, "sizeBias");
51
- g(this, "scale");
52
- g(this, "dirX");
53
- g(this, "dirY");
54
- g(this, "initialized", !1);
42
+ m(this, "z");
43
+ m(this, "vx");
44
+ m(this, "vy");
45
+ m(this, "color");
46
+ m(this, "targetColor", null);
47
+ m(this, "colorDelay", 0);
48
+ m(this, "angleTarget");
49
+ m(this, "randomSpeed");
50
+ m(this, "sizeBias");
51
+ m(this, "scale");
52
+ m(this, "dirX");
53
+ m(this, "dirY");
54
+ m(this, "initialized", !1);
55
55
  this.x = e, this.y = n, this.baseX = e, this.baseY = n, this.z = Math.random() * 1.5 + 0.2, this.vx = 0, this.vy = 0, this.color = i, this.angleTarget = Math.random() * Math.PI * 2, this.randomSpeed = Math.random() * 2 + 1, this.sizeBias = Math.random(), this.scale = 1, this.dirX = Math.cos(this.angleTarget), this.dirY = Math.sin(this.angleTarget);
56
56
  }
57
- update(e, n, i, s, m, r, o, h = "vertical") {
57
+ update(e, n, i, s, y, r, o, h = "vertical") {
58
58
  this.initialized || (this.x = i + this.baseX, this.y = s + this.baseY, this.initialized = !0);
59
59
  const {
60
- forceX: y,
60
+ forceX: g,
61
61
  forceY: d,
62
62
  dxCenter: c,
63
63
  dyCenter: a,
@@ -66,13 +66,13 @@ class tt {
66
66
  forceX: u,
67
67
  forceY: w
68
68
  } = U(this, i, s, o);
69
- this.vx += y + u, this.vy += d + w, this.vx *= 0.75, this.vy *= 0.75, this.x += this.vx, this.y += this.vy, V(this, l), Z(this, c, a, l, h, o), this.targetColor && (this.colorDelay -= 1, this.colorDelay <= 0 && (this.color = this.targetColor, this.targetColor = null));
69
+ this.vx += g + u, this.vy += d + w, this.vx *= 0.75, this.vy *= 0.75, this.x += this.vx, this.y += this.vy, V(this, l), Z(this, c, a, l, h, o), this.targetColor && (this.colorDelay -= 1, this.colorDelay <= 0 && (this.color = this.targetColor, this.targetColor = null));
70
70
  }
71
71
  draw(e, n, i = "bean") {
72
72
  if (this.scale <= 0.05) return;
73
73
  e.fillStyle = this.color;
74
- const s = Math.sqrt(this.baseX * this.baseX + this.baseY * this.baseY), m = Math.max(0, 1 - s / 350);
75
- if (e.globalAlpha = Math.min(1, (0.5 + this.z * 0.5) * Math.min(this.scale, 1) * m), !(e.globalAlpha <= 0.01))
74
+ const s = Math.sqrt(this.baseX * this.baseX + this.baseY * this.baseY), y = Math.max(0, 1 - s / 350);
75
+ if (e.globalAlpha = Math.min(1, (0.5 + this.z * 0.5) * Math.min(this.scale, 1) * y), !(e.globalAlpha <= 0.01))
76
76
  if (i === "circle") {
77
77
  const r = Math.max(0.1, 2 * this.scale * this.z);
78
78
  e.beginPath(), e.arc(this.x, this.y, r, 0, Math.PI * 2), e.fill();
@@ -80,13 +80,13 @@ class tt {
80
80
  const r = Math.max(0.1, 2 * this.scale * this.z);
81
81
  e.fillRect(this.x - r, this.y - r, r * 2, r * 2);
82
82
  } else {
83
- const o = (6 + this.sizeBias * 6) * this.scale, h = Math.sin(n * 3.5 + this.baseX * 0.1 + this.randomSpeed * 5), y = 0.4 + 0.6 * ((h + 1) / 2), d = o * 0.5 * y, c = Math.max(0.8, this.z * 1.5 * this.scale * (0.8 + 0.2 * h)), a = Math.atan2(this.dirY, this.dirX);
83
+ const o = (6 + this.sizeBias * 6) * this.scale, h = Math.sin(n * 3.5 + this.baseX * 0.1 + this.randomSpeed * 5), g = 0.4 + 0.6 * ((h + 1) / 2), d = o * 0.5 * g, c = Math.max(0.8, this.z * 1.5 * this.scale * (0.8 + 0.2 * h)), a = Math.atan2(this.dirY, this.dirX);
84
84
  e.beginPath(), e.ellipse(this.x, this.y, d, c, a, 0, Math.PI * 2), e.fill();
85
85
  }
86
86
  }
87
87
  }
88
88
  function et({ config: t, backgroundColor: e }) {
89
- const n = I(null), i = I(null), s = I([]), m = I(0), r = I({ x: -1e3, y: -1e3, isDown: !1, active: !1 }), o = I({ x: 0, y: 0, initialized: !1 });
89
+ const n = I(null), i = I(null), s = I([]), y = I(0), r = I({ x: -1e3, y: -1e3, isDown: !1, active: !1 }), o = I({ x: 0, y: 0, initialized: !1 });
90
90
  L(() => {
91
91
  const c = (l) => {
92
92
  if (!n.current) return;
@@ -99,11 +99,11 @@ function et({ config: t, backgroundColor: e }) {
99
99
  window.removeEventListener("pointermove", c), window.removeEventListener("pointerleave", a);
100
100
  };
101
101
  }, []);
102
- const h = I(t), y = I(null), d = I(0);
102
+ const h = I(t), g = I(null), d = I(0);
103
103
  return L(() => {
104
104
  h.current = t;
105
105
  }, [t]), L(() => {
106
- if (y.current && (clearInterval(y.current), y.current = null), !t.colors || t.colors.length === 0) {
106
+ if (g.current && (clearInterval(g.current), g.current = null), !t.colors || t.colors.length === 0) {
107
107
  const a = t.color || "#8B5CF6";
108
108
  s.current.forEach((l) => {
109
109
  l.targetColor = a, l.colorDelay = Math.random() * 20;
@@ -119,11 +119,11 @@ function et({ config: t, backgroundColor: e }) {
119
119
  };
120
120
  return t.colorMode === "mixed" ? s.current.forEach((a, l) => {
121
121
  a.targetColor = t.colors[l % t.colors.length], a.colorDelay = Math.random() * 20;
122
- }) : (d.current = 0, c(t.colors[0]), t.colors.length > 1 && (y.current = setInterval(() => {
122
+ }) : (d.current = 0, c(t.colors[0]), t.colors.length > 1 && (g.current = setInterval(() => {
123
123
  const a = t.colors;
124
124
  d.current = (d.current + 1) % a.length, c(a[d.current]);
125
125
  }, 3e3))), () => {
126
- y.current && clearInterval(y.current);
126
+ g.current && clearInterval(g.current);
127
127
  };
128
128
  }, [t.colors, t.color, t.colorMode]), L(() => {
129
129
  if (!n.current || !i.current || h.current.name === "NONE") return;
@@ -179,49 +179,49 @@ function et({ config: t, backgroundColor: e }) {
179
179
  M.draw(w, P, x);
180
180
  }
181
181
  }
182
- m.current = requestAnimationFrame(q);
182
+ y.current = requestAnimationFrame(q);
183
183
  };
184
184
  return q(), () => {
185
- u.disconnect(), cancelAnimationFrame(m.current);
185
+ u.disconnect(), cancelAnimationFrame(y.current);
186
186
  };
187
187
  }, [e, t.density]), t.name === "NONE" ? null : /* @__PURE__ */ $("div", { ref: n, style: { position: "absolute", inset: 0, zIndex: 0, overflow: "hidden" }, children: /* @__PURE__ */ $("canvas", { ref: i, style: { display: "block", width: "100%", height: "100%" } }) });
188
188
  }
189
189
  class nt {
190
190
  constructor(e, n) {
191
- g(this, "x");
192
- g(this, "y");
193
- g(this, "vx");
194
- g(this, "vy");
195
- g(this, "radius");
196
- g(this, "currentColor", "#8B5CF6");
197
- g(this, "targetColor", null);
198
- g(this, "colorDelay", 0);
191
+ m(this, "x");
192
+ m(this, "y");
193
+ m(this, "vx");
194
+ m(this, "vy");
195
+ m(this, "radius");
196
+ m(this, "currentColor", "#8B5CF6");
197
+ m(this, "targetColor", null);
198
+ m(this, "colorDelay", 0);
199
199
  this.x = e, this.y = n;
200
200
  const i = Math.random() * Math.PI * 2, s = Math.random() * 0.5 + 0.1;
201
201
  this.vx = Math.cos(i) * s, this.vy = Math.sin(i) * s, this.radius = Math.random() * 1.5 + 1;
202
202
  }
203
- update(e, n, i, s, m = 1, r = 0.06) {
204
- if (this.x += this.vx * m, this.y += this.vy * m, this.x < 0 ? (this.x = 0, this.vx *= -1) : this.x > e && (this.x = e, this.vx *= -1), this.y < 0 ? (this.y = 0, this.vy *= -1) : this.y > n && (this.y = n, this.vy *= -1), i !== null && s !== null) {
205
- const o = i - this.x, h = s - this.y, y = o * o + h * h, d = 150, c = d * d;
206
- if (y < c) {
207
- const a = Math.sqrt(y), l = (d - a) / d, u = r / 0.06;
203
+ update(e, n, i, s, y = 1, r = 0.06) {
204
+ if (this.x += this.vx * y, this.y += this.vy * y, this.x < 0 ? (this.x = 0, this.vx *= -1) : this.x > e && (this.x = e, this.vx *= -1), this.y < 0 ? (this.y = 0, this.vy *= -1) : this.y > n && (this.y = n, this.vy *= -1), i !== null && s !== null) {
205
+ const o = i - this.x, h = s - this.y, g = o * o + h * h, d = 150, c = d * d;
206
+ if (g < c) {
207
+ const a = Math.sqrt(g), l = (d - a) / d, u = r / 0.06;
208
208
  this.x -= o / a * l * 2 * u, this.y -= h / a * l * 2 * u;
209
209
  }
210
210
  }
211
- this.targetColor && (this.colorDelay -= 1 * m, this.colorDelay <= 0 && (this.currentColor = this.targetColor, this.targetColor = null));
211
+ this.targetColor && (this.colorDelay -= 1 * y, this.colorDelay <= 0 && (this.currentColor = this.targetColor, this.targetColor = null));
212
212
  }
213
213
  draw(e, n = "circle", i = 0) {
214
214
  if (e.fillStyle = this.currentColor, n === "square")
215
215
  e.fillRect(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2);
216
216
  else if (n === "bean") {
217
- const s = Math.sin(i * 0.05 + this.x * 0.01 + this.y * 0.01), m = this.radius * 2 * (0.8 + 0.4 * s), r = this.radius * (0.8 + 0.2 * s), o = this.vx !== 0 || this.vy !== 0 ? Math.atan2(this.vy, this.vx) : 0;
218
- e.beginPath(), e.ellipse(this.x, this.y, m, r, o, 0, Math.PI * 2), e.fill();
217
+ const s = Math.sin(i * 0.05 + this.x * 0.01 + this.y * 0.01), y = this.radius * 2 * (0.8 + 0.4 * s), r = this.radius * (0.8 + 0.2 * s), o = this.vx !== 0 || this.vy !== 0 ? Math.atan2(this.vy, this.vx) : 0;
218
+ e.beginPath(), e.ellipse(this.x, this.y, y, r, o, 0, Math.PI * 2), e.fill();
219
219
  } else
220
220
  e.beginPath(), e.arc(this.x, this.y, this.radius, 0, Math.PI * 2), e.fill();
221
221
  }
222
222
  }
223
223
  function rt({ config: t, backgroundColor: e }) {
224
- const n = I(null), i = I(null), s = I([]), m = I(0), r = I({ x: -1e3, y: -1e3, active: !1 });
224
+ const n = I(null), i = I(null), s = I([]), y = I(0), r = I({ x: -1e3, y: -1e3, active: !1 });
225
225
  L(() => {
226
226
  const d = (a) => {
227
227
  if (!n.current) return;
@@ -234,11 +234,11 @@ function rt({ config: t, backgroundColor: e }) {
234
234
  window.removeEventListener("pointermove", d), window.removeEventListener("pointerleave", c);
235
235
  };
236
236
  }, []);
237
- const o = I(t), h = I(0), y = I(null);
237
+ const o = I(t), h = I(0), g = I(null);
238
238
  return L(() => {
239
239
  o.current = t;
240
240
  }, [t]), L(() => {
241
- if (y.current && (clearInterval(y.current), y.current = null), !t.colors || t.colors.length === 0) {
241
+ if (g.current && (clearInterval(g.current), g.current = null), !t.colors || t.colors.length === 0) {
242
242
  const l = t.color || "#8B5CF6";
243
243
  s.current.forEach((u) => {
244
244
  u.targetColor = l, u.colorDelay = Math.random() * 20;
@@ -253,11 +253,11 @@ function rt({ config: t, backgroundColor: e }) {
253
253
  };
254
254
  return t.colorMode === "mixed" ? s.current.forEach((l, u) => {
255
255
  l.targetColor = t.colors[u % t.colors.length], l.colorDelay = Math.random() * 20;
256
- }) : (h.current = 0, a(t.colors[0]), t.colors.length > 1 && (y.current = setInterval(() => {
256
+ }) : (h.current = 0, a(t.colors[0]), t.colors.length > 1 && (g.current = setInterval(() => {
257
257
  const l = t.colors;
258
258
  h.current = (h.current + 1) % l.length, a(l[h.current]);
259
259
  }, 3e3))), () => {
260
- y.current && clearInterval(y.current);
260
+ g.current && clearInterval(g.current);
261
261
  };
262
262
  }, [t.colors, t.color, t.colorMode]), L(() => {
263
263
  if (!n.current || !i.current) return;
@@ -304,44 +304,44 @@ function rt({ config: t, backgroundColor: e }) {
304
304
  u.beginPath(), u.moveTo(x.x, x.y), u.lineTo(b, C), u.strokeStyle = x.currentColor, u.globalAlpha = F * 0.8, u.lineWidth = 1.5, u.stroke();
305
305
  }
306
306
  }
307
- u.globalAlpha = 1, m.current = requestAnimationFrame(P);
307
+ u.globalAlpha = 1, y.current = requestAnimationFrame(P);
308
308
  };
309
309
  return P(), () => {
310
- l.disconnect(), cancelAnimationFrame(m.current);
310
+ l.disconnect(), cancelAnimationFrame(y.current);
311
311
  };
312
312
  }, [e, t.density]), /* @__PURE__ */ $("div", { ref: n, style: { position: "absolute", inset: 0, zIndex: 0, overflow: "hidden" }, children: /* @__PURE__ */ $("canvas", { ref: i, style: { display: "block", width: "100%", height: "100%" } }) });
313
313
  }
314
314
  class st {
315
315
  constructor(e, n, i, s) {
316
- g(this, "x", 0);
317
- g(this, "y", 0);
318
- g(this, "baseX");
319
- g(this, "baseY");
320
- g(this, "vx", 0);
321
- g(this, "vy", 0);
322
- g(this, "color");
323
- g(this, "size");
324
- g(this, "angle");
325
- g(this, "dist");
326
- g(this, "spring");
327
- g(this, "friction");
328
- g(this, "targetColor", null);
329
- g(this, "colorDelay", 0);
316
+ m(this, "x", 0);
317
+ m(this, "y", 0);
318
+ m(this, "baseX");
319
+ m(this, "baseY");
320
+ m(this, "vx", 0);
321
+ m(this, "vy", 0);
322
+ m(this, "color");
323
+ m(this, "size");
324
+ m(this, "angle");
325
+ m(this, "dist");
326
+ m(this, "spring");
327
+ m(this, "friction");
328
+ m(this, "targetColor", null);
329
+ m(this, "colorDelay", 0);
330
330
  this.baseX = e, this.baseY = n, this.color = i, this.size = s, this.angle = Math.atan2(n, e), this.dist = Math.sqrt(e * e + n * n);
331
- const m = Math.min(1, this.dist / 350);
332
- this.spring = 0.15 - m * 0.13, this.friction = 0.85 + m * 0.1;
331
+ const y = Math.min(1, this.dist / 350);
332
+ this.spring = 0.15 - y * 0.13, this.friction = 0.85 + y * 0.1;
333
333
  }
334
334
  update(e, n, i, s) {
335
- const r = 1 + Math.sin(this.angle * 3 + i * 1.2) * 0.05 + Math.cos(this.angle * 5 - i * 0.6) * 0.03, o = this.dist * s * r, h = Math.cos(this.angle) * o, y = Math.sin(this.angle) * o, d = this.dist * 0.1 * r, c = Math.sin(i * 3 + this.dist * 0.05) * d, a = e + h + Math.cos(this.angle + Math.PI / 2) * c, l = n + y + Math.sin(this.angle + Math.PI / 2) * c, u = a - this.x, w = l - this.y;
335
+ const r = 1 + Math.sin(this.angle * 3 + i * 1.2) * 0.05 + Math.cos(this.angle * 5 - i * 0.6) * 0.03, o = this.dist * s * r, h = Math.cos(this.angle) * o, g = Math.sin(this.angle) * o, d = this.dist * 0.1 * r, c = Math.sin(i * 3 + this.dist * 0.05) * d, a = e + h + Math.cos(this.angle + Math.PI / 2) * c, l = n + g + Math.sin(this.angle + Math.PI / 2) * c, u = a - this.x, w = l - this.y;
336
336
  this.vx += u * this.spring, this.vy += w * this.spring, this.vx *= this.friction, this.vy *= this.friction, this.x += this.vx, this.y += this.vy, this.targetColor && (this.colorDelay -= 1, this.colorDelay <= 0 && (this.color = this.targetColor, this.targetColor = null));
337
337
  }
338
338
  draw(e, n, i) {
339
- const s = Math.min(1, this.dist / 350), m = 1 + (1 - s) * (i - 1) * 1.5, r = this.size * m;
339
+ const s = Math.min(1, this.dist / 350), y = 1 + (1 - s) * (i - 1) * 1.5, r = this.size * y;
340
340
  e.globalAlpha = Math.max(0.15, 1 - s * 0.7), e.fillStyle = this.color, e.beginPath(), n === "circle" ? e.arc(this.x, this.y, r, 0, Math.PI * 2) : n === "square" ? e.rect(this.x - r, this.y - r, r * 2, r * 2) : e.ellipse(this.x, this.y, r * 1.5, r, 0, 0, Math.PI * 2), e.fill();
341
341
  }
342
342
  }
343
343
  function ot({ config: t, backgroundColor: e }) {
344
- const n = I(null), i = I(null), s = I([]), m = I(0), r = I({ x: -1e3, y: -1e3, active: !1 }), o = I({ x: 0, y: 0, initialized: !1, angle: -Math.PI / 2 });
344
+ const n = I(null), i = I(null), s = I([]), y = I(0), r = I({ x: -1e3, y: -1e3, active: !1 }), o = I({ x: 0, y: 0, initialized: !1, angle: -Math.PI / 2 });
345
345
  L(() => {
346
346
  const c = (a) => {
347
347
  if (!n.current) return;
@@ -352,7 +352,7 @@ function ot({ config: t, backgroundColor: e }) {
352
352
  window.removeEventListener("pointermove", c);
353
353
  };
354
354
  }, []);
355
- const h = I(t), y = I(0), d = I(null);
355
+ const h = I(t), g = I(0), d = I(null);
356
356
  return L(() => {
357
357
  h.current = t;
358
358
  }, [t]), L(() => {
@@ -370,9 +370,9 @@ function ot({ config: t, backgroundColor: e }) {
370
370
  };
371
371
  return t.colorMode === "mixed" ? s.current.forEach((a, l) => {
372
372
  a.targetColor = t.colors[l % t.colors.length], a.colorDelay = Math.max(0, a.dist * 0.2) + Math.random() * 10;
373
- }) : (y.current = 0, c(t.colors[0]), t.colors.length > 1 && (d.current = setInterval(() => {
373
+ }) : (g.current = 0, c(t.colors[0]), t.colors.length > 1 && (d.current = setInterval(() => {
374
374
  const a = t.colors;
375
- y.current = (y.current + 1) % a.length, c(a[y.current]);
375
+ g.current = (g.current + 1) % a.length, c(a[g.current]);
376
376
  }, 3e3))), () => {
377
377
  d.current && clearInterval(d.current);
378
378
  };
@@ -444,10 +444,10 @@ function ot({ config: t, backgroundColor: e }) {
444
444
  const G = h.current.shape || "circle";
445
445
  B.draw(w, G, E);
446
446
  }
447
- m.current = requestAnimationFrame(q);
447
+ y.current = requestAnimationFrame(q);
448
448
  };
449
449
  return q(), () => {
450
- u.disconnect(), cancelAnimationFrame(m.current);
450
+ u.disconnect(), cancelAnimationFrame(y.current);
451
451
  };
452
452
  }, [e, t.density]), /* @__PURE__ */ $(
453
453
  "div",
@@ -472,20 +472,20 @@ const it = {
472
472
  boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
473
473
  transition: "all 300ms ease-out"
474
474
  };
475
- function ft({
475
+ function ct({
476
476
  children: t,
477
477
  width: e = "100%",
478
478
  height: n = "60vh",
479
479
  backgroundColor: i = "#050505",
480
480
  className: s = "",
481
- style: m,
481
+ style: y,
482
482
  background: r = { name: "NONE" }
483
483
  }) {
484
484
  return /* @__PURE__ */ _(
485
485
  "div",
486
486
  {
487
487
  className: s,
488
- style: { ...it, width: e, height: n, backgroundColor: i, ...m },
488
+ style: { ...it, width: e, height: n, backgroundColor: i, ...y },
489
489
  children: [
490
490
  r.name === "FOLLOW_POINTER" && /* @__PURE__ */ $(et, { config: r, backgroundColor: i }),
491
491
  r.name === "NET" && /* @__PURE__ */ $(rt, { config: r, backgroundColor: i }),
@@ -495,7 +495,7 @@ function ft({
495
495
  }
496
496
  );
497
497
  }
498
- function ct(t) {
498
+ function at(t) {
499
499
  const e = I({ x: -1e3, y: -1e3, isDown: !1, active: !1 });
500
500
  return L(() => {
501
501
  const n = t.current;
@@ -505,70 +505,70 @@ function ct(t) {
505
505
  e.current.x = o.clientX - h.left, e.current.y = o.clientY - h.top, e.current.active = !0;
506
506
  }, s = () => {
507
507
  e.current.active = !1;
508
- }, m = () => {
508
+ }, y = () => {
509
509
  e.current.isDown = !0;
510
510
  }, r = () => {
511
511
  e.current.isDown = !1;
512
512
  };
513
- return n.addEventListener("pointermove", i), n.addEventListener("pointerleave", s), n.addEventListener("pointerdown", m), n.addEventListener("pointerup", r), n.style.touchAction = "none", () => {
514
- n.removeEventListener("pointermove", i), n.removeEventListener("pointerleave", s), n.removeEventListener("pointerdown", m), n.removeEventListener("pointerup", r);
513
+ return n.addEventListener("pointermove", i), n.addEventListener("pointerleave", s), n.addEventListener("pointerdown", y), n.addEventListener("pointerup", r), n.style.touchAction = "none", () => {
514
+ n.removeEventListener("pointermove", i), n.removeEventListener("pointerleave", s), n.removeEventListener("pointerdown", y), n.removeEventListener("pointerup", r);
515
515
  };
516
516
  }, [t]), e;
517
517
  }
518
- function at(t, e, n, i, s, m, r, o, h) {
519
- if (s === null || m === null || !o && h === "none")
518
+ function lt(t, e, n, i, s, y, r, o, h) {
519
+ if (s === null || y === null || !o && h === "none")
520
520
  return { x: n, y: i };
521
- let y = n, d = i;
522
- const c = s - t, a = m - e, l = c * c + a * a, u = Math.sqrt(l);
521
+ let g = n, d = i;
522
+ const c = s - t, a = y - e, l = c * c + a * a, u = Math.sqrt(l);
523
523
  if (o && !r && l < 3e4) {
524
524
  const P = (3e4 - l) / 3e4;
525
- y += c * P * 0.15, d += a * P * 0.15;
525
+ g += c * P * 0.15, d += a * P * 0.15;
526
526
  }
527
527
  if (r && h !== "none") {
528
528
  if (h === "attract") {
529
529
  if (l < 3e4) {
530
530
  const P = (3e4 - l) / 3e4;
531
- y += c * P * 0.8, d += a * P * 0.8;
531
+ g += c * P * 0.8, d += a * P * 0.8;
532
532
  }
533
533
  } else if (h === "repel" && l < 5e4 && u > 0) {
534
534
  const P = Math.pow(Math.max(0, 5e4 - l) / 5e4, 1.2);
535
- y -= c / u * P * 400, d -= a / u * P * 400;
535
+ g -= c / u * P * 400, d -= a / u * P * 400;
536
536
  }
537
537
  }
538
- return { x: y, y: d };
538
+ return { x: g, y: d };
539
539
  }
540
540
  class H {
541
541
  constructor(e, n, i = "255, 255, 255") {
542
- g(this, "x");
543
- g(this, "y");
544
- g(this, "vx");
545
- g(this, "vy");
546
- g(this, "targetX");
547
- g(this, "targetY");
548
- g(this, "baseColor");
549
- g(this, "opacity");
550
- g(this, "size");
551
- g(this, "sizeMultiplier");
552
- g(this, "friction");
553
- g(this, "ease");
554
- g(this, "easeMultiplier");
555
- g(this, "floatSpeed");
556
- g(this, "floatOffset");
557
- g(this, "randomSpeed");
542
+ m(this, "x");
543
+ m(this, "y");
544
+ m(this, "vx");
545
+ m(this, "vy");
546
+ m(this, "targetX");
547
+ m(this, "targetY");
548
+ m(this, "baseColor");
549
+ m(this, "opacity");
550
+ m(this, "size");
551
+ m(this, "sizeMultiplier");
552
+ m(this, "friction");
553
+ m(this, "ease");
554
+ m(this, "easeMultiplier");
555
+ m(this, "floatSpeed");
556
+ m(this, "floatOffset");
557
+ m(this, "randomSpeed");
558
558
  this.x = Math.random() * e, this.y = Math.random() * n, this.targetX = this.x, this.targetY = this.y, this.vx = 0, this.vy = 0, this.size = Math.random() * 1.8 + 0.5, this.sizeMultiplier = 1, this.baseColor = Array.isArray(i) ? i[Math.floor(Math.random() * i.length)] : i, this.opacity = 0.4 + Math.random() * 0.6, this.friction = 0.82 + Math.random() * 0.1, this.ease = 0.03 + Math.random() * 0.05, this.easeMultiplier = 1, this.floatSpeed = Math.random() * 0.02 + 5e-3, this.floatOffset = Math.random() * Math.PI * 2, this.randomSpeed = Math.random();
559
559
  }
560
- update(e, n, i = null, s = null, m = !1, r = !0, o = "none") {
561
- const { x: h, y } = at(
560
+ update(e, n, i = null, s = null, y = !1, r = !0, o = "none") {
561
+ const { x: h, y: g } = lt(
562
562
  this.x,
563
563
  this.y,
564
564
  this.targetX,
565
565
  this.targetY,
566
566
  i,
567
567
  s,
568
- m,
568
+ y,
569
569
  r,
570
570
  o
571
- ), d = h - this.x, c = y - this.y, a = n ? 0 : Math.cos(e * 0.01 + this.y * 0.01) * 0.5, l = n ? 0 : Math.sin(e * 0.01 + this.x * 0.01) * 0.5;
571
+ ), d = h - this.x, c = g - this.y, a = n ? 0 : Math.cos(e * 0.01 + this.y * 0.01) * 0.5, l = n ? 0 : Math.sin(e * 0.01 + this.x * 0.01) * 0.5;
572
572
  this.vx += d * (this.ease * this.easeMultiplier) + a, this.vy += c * (this.ease * this.easeMultiplier) + l, this.vx *= this.friction, this.vy *= this.friction, this.x += this.vx, this.y += this.vy;
573
573
  const u = n ? 0.2 : 2;
574
574
  this.x += Math.cos(e * this.floatSpeed + this.floatOffset) * u, this.y += Math.sin(e * this.floatSpeed + this.floatOffset) * u;
@@ -579,8 +579,8 @@ class H {
579
579
  if (n === "square")
580
580
  e.fillRect(this.x - s, this.y - s, s * 2, s * 2);
581
581
  else if (n === "bean") {
582
- const m = 6 + this.size * 2 * this.sizeMultiplier, r = Math.sin(i * 0.05 + this.x * 0.01 + this.randomSpeed * 5), o = 0.4 + 0.6 * ((r + 1) / 2), h = m * 0.5 * o, y = Math.max(0.8, s * 1.5 * (0.8 + 0.2 * r)), d = this.vx !== 0 || this.vy !== 0 ? Math.atan2(this.vy, this.vx) : 0;
583
- e.beginPath(), e.ellipse(this.x, this.y, h, y, d, 0, Math.PI * 2), e.fill();
582
+ const y = 6 + this.size * 2 * this.sizeMultiplier, r = Math.sin(i * 0.05 + this.x * 0.01 + this.randomSpeed * 5), o = 0.4 + 0.6 * ((r + 1) / 2), h = y * 0.5 * o, g = Math.max(0.8, s * 1.5 * (0.8 + 0.2 * r)), d = this.vx !== 0 || this.vy !== 0 ? Math.atan2(this.vy, this.vx) : 0;
583
+ e.beginPath(), e.ellipse(this.x, this.y, h, g, d, 0, Math.PI * 2), e.fill();
584
584
  } else
585
585
  e.beginPath(), e.arc(this.x, this.y, s, 0, Math.PI * 2), e.fill();
586
586
  }
@@ -592,36 +592,36 @@ function j(t, e, n) {
592
592
  const s = i.getContext("2d", { willReadFrequently: !0 });
593
593
  if (!s) return [];
594
594
  s.clearRect(0, 0, e, n);
595
- let m = Math.min(e, n) * 0.65;
596
- s.font = `bold ${m}px "Georgia", serif`;
595
+ let y = Math.min(e, n) * 0.65;
596
+ s.font = `bold ${y}px "Georgia", serif`;
597
597
  const r = s.measureText(t);
598
- r.width > e * 0.9 && (m = m * (e * 0.9) / r.width, s.font = `bold ${m}px "Georgia", serif`), s.fillStyle = "white", s.textAlign = "center", s.textBaseline = "middle", s.fillText(t, e / 2, n / 2.05);
599
- const h = s.getImageData(0, 0, e, n).data, y = [], d = window.innerWidth < 600 ? 6 : 8;
598
+ r.width > e * 0.9 && (y = y * (e * 0.9) / r.width, s.font = `bold ${y}px "Georgia", serif`), s.fillStyle = "white", s.textAlign = "center", s.textBaseline = "middle", s.fillText(t, e / 2, n / 2.05);
599
+ const h = s.getImageData(0, 0, e, n).data, g = [], d = window.innerWidth < 600 ? 6 : 8;
600
600
  for (let c = 0; c < n; c += d)
601
601
  for (let a = 0; a < e; a += d) {
602
602
  const l = (c * e + a) * 4;
603
- h[l + 3] > 128 && y.push({
603
+ h[l + 3] > 128 && g.push({
604
604
  x: a + (Math.random() - 0.5) * 4,
605
605
  y: c + (Math.random() - 0.5) * 4
606
606
  });
607
607
  }
608
- return y;
608
+ return g;
609
609
  }
610
- function lt(t, e, n) {
610
+ function ht(t, e, n) {
611
611
  const i = I(t);
612
612
  return L(() => {
613
613
  i.current = t;
614
- }, [t]), { getPixelsForText: j, updateTextTargets: (m, r, o) => {
614
+ }, [t]), { getPixelsForText: j, updateTextTargets: (y, r, o) => {
615
615
  var q, b;
616
- const h = r || ((q = n.current) == null ? void 0 : q.offsetWidth) || window.innerWidth, y = o || ((b = n.current) == null ? void 0 : b.offsetHeight) || window.innerHeight;
617
- if (!m) {
616
+ const h = r || ((q = n.current) == null ? void 0 : q.offsetWidth) || window.innerWidth, g = o || ((b = n.current) == null ? void 0 : b.offsetHeight) || window.innerHeight;
617
+ if (!y) {
618
618
  e.current.forEach((f) => {
619
- const p = 50 + Math.random() * (h - 100), R = 50 + Math.random() * (y - 100);
619
+ const p = 50 + Math.random() * (h - 100), R = 50 + Math.random() * (g - 100);
620
620
  (Math.abs(p - f.x) > 20 || Math.abs(R - f.y) > 20) && (f.vx += (Math.random() - 0.5) * 20, f.vy += (Math.random() - 0.5) * 20), f.targetX = p, f.targetY = R;
621
621
  });
622
622
  return;
623
623
  }
624
- const d = j(m, h, y);
624
+ const d = j(y, h, g);
625
625
  if (d.length === 0) return;
626
626
  const c = h * 0.15, a = d.map((C) => ({ pt: C, key: C.x + (Math.random() - 0.5) * c }));
627
627
  a.sort((C, f) => C.key - f.key);
@@ -666,14 +666,14 @@ function yt({
666
666
  particleSize: n = 1,
667
667
  particleDensity: i = 1,
668
668
  particleEase: s = 1,
669
- isMagnet: m = !0,
669
+ isMagnet: y = !0,
670
670
  clickMode: r = "none",
671
671
  particleShape: o = "circle",
672
672
  backgroundColor: h = "#050505"
673
673
  }) {
674
- const y = I(null), d = I(null), c = I([]), a = I(0), l = I(0), u = ct(d), w = I({ isMagnet: m, clickMode: r, particleShape: o, backgroundColor: h });
675
- w.current = { isMagnet: m, clickMode: r, particleShape: o, backgroundColor: h };
676
- const { updateTextTargets: P, textRef: q } = lt(
674
+ const g = I(null), d = I(null), c = I([]), a = I(0), l = I(0), u = at(d), w = I({ isMagnet: y, clickMode: r, particleShape: o, backgroundColor: h });
675
+ w.current = { isMagnet: y, clickMode: r, particleShape: o, backgroundColor: h };
676
+ const { updateTextTargets: P, textRef: q } = ht(
677
677
  t,
678
678
  c,
679
679
  d
@@ -701,7 +701,7 @@ function yt({
701
701
  f.easeMultiplier = s;
702
702
  });
703
703
  }, [s]), L(() => {
704
- if (c.current.length > 0 && y.current && d.current) {
704
+ if (c.current.length > 0 && g.current && d.current) {
705
705
  const f = window.innerWidth < 600 ? 1500 : 3e3, p = Math.floor(f * i), R = c.current.length;
706
706
  if (p > R) {
707
707
  const S = d.current.getBoundingClientRect(), D = b();
@@ -713,7 +713,7 @@ function yt({
713
713
  } else p < R && c.current.splice(p);
714
714
  }
715
715
  }, [i]), L(() => {
716
- const f = d.current, p = y.current;
716
+ const f = d.current, p = g.current;
717
717
  if (!f || !p) return;
718
718
  const R = (v) => {
719
719
  for (const X of v) {
@@ -753,20 +753,40 @@ function yt({
753
753
  children: /* @__PURE__ */ $(
754
754
  "canvas",
755
755
  {
756
- ref: y,
756
+ ref: g,
757
757
  style: { display: "block", width: "100%", height: "100%" }
758
758
  }
759
759
  )
760
760
  }
761
761
  );
762
762
  }
763
+ function gt({
764
+ name: t,
765
+ config: e,
766
+ width: n = "100%",
767
+ height: i = "60vh",
768
+ backgroundColor: s = "#050505",
769
+ className: y = "",
770
+ style: r
771
+ }) {
772
+ const o = { name: t, ...e };
773
+ return /* @__PURE__ */ $(
774
+ ct,
775
+ {
776
+ width: n,
777
+ height: i,
778
+ backgroundColor: s,
779
+ className: y,
780
+ style: r,
781
+ background: o
782
+ }
783
+ );
784
+ }
763
785
  export {
764
- et as BackgroundParticleEngine,
765
- ot as JellyfishParticleEngine,
766
- rt as NetParticleEngine,
767
- ft as ParticleCanvas,
786
+ gt as ParticleBackground,
787
+ ct as ParticleCanvas,
768
788
  yt as TextParticleEngine,
769
- at as getMagnetTarget,
770
- ct as useParticleInteraction,
771
- lt as useTextParticles
789
+ lt as getMagnetTarget,
790
+ at as useParticleInteraction,
791
+ ht as useTextParticles
772
792
  };
@@ -1 +1 @@
1
- (function(L,q){typeof exports=="object"&&typeof module<"u"?q(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],q):(L=typeof globalThis<"u"?globalThis:L||self,q(L.JlParticleInteractive={},L.ReactJsxRuntime,L.React))})(this,(function(L,q,f){"use strict";var lt=Object.defineProperty;var ht=(L,q,f)=>q in L?lt(L,q,{enumerable:!0,configurable:!0,writable:!0,value:f}):L[q]=f;var v=(L,q,f)=>ht(L,typeof q!="symbol"?q+"":q,f);function V(t,e,n,i){let s=e+t.baseX,m=n+t.baseY;s+=Math.sin(i*t.randomSpeed+t.baseY*.05)*15*t.z,m+=Math.cos(i*t.randomSpeed+t.baseX*.05)*15*t.z;const r=s-t.x,o=m-t.y,h=r*.06,g=o*.06;return{forceX:h,forceY:g}}function Z(t,e,n,i,s,m){const r=i,o=s,h=t.x-r,g=t.y-o,d=Math.max(Math.sqrt(h*h+g*g),1);let c=0,a=0;const u=Math.sin(d*.02-m*3)*2.5*t.z;c+=h/d*u,a+=g/d*u;const E=Math.cos(d*.01-m*1+t.randomSpeed)*.8*t.z,T=-g/d,b=h/d;return c+=T*E,a+=b*E,{forceX:c,forceY:a,dxCenter:h,dyCenter:g,distToCenter:d}}function tt(t,e){let s=Math.min(e/400,1)*2.5+t.sizeBias*1;s<.4&&(s=0),t.scale+=(s-t.scale)*.15}function et(t,e,n,i,s,m){let r=0,o=0;s==="horizontal"?(r=1,o=0):s==="diagonal"?(r=-e/i,o=-n/i):(r=-n/i,o=e/i);const h=Math.atan2(o,r),g=t.sizeBias>.3?1:0,d=Math.max(0,Math.sin(m*.5+t.randomSpeed*10)),c=Math.sin(m*3+t.baseX*.1+t.randomSpeed)*.5*d*g;r=Math.cos(h+c),o=Math.sin(h+c);const a=Math.max(1-i/400,.1);s==="horizontal"?(t.dirX=t.dirX*(1-.2)+r*.2,t.dirY=t.dirY*(1-.2)+o*.2):(t.dirX=t.dirX*(1-a*.3)+r*a*.3,t.dirY=t.dirY*(1-a*.3)+o*a*.3);const l=Math.sqrt(t.dirX*t.dirX+t.dirY*t.dirY);l>0&&(t.dirX/=l,t.dirY/=l)}class nt{constructor(e,n,i){v(this,"x");v(this,"y");v(this,"baseX");v(this,"baseY");v(this,"z");v(this,"vx");v(this,"vy");v(this,"color");v(this,"targetColor",null);v(this,"colorDelay",0);v(this,"angleTarget");v(this,"randomSpeed");v(this,"sizeBias");v(this,"scale");v(this,"dirX");v(this,"dirY");v(this,"initialized",!1);this.x=e,this.y=n,this.baseX=e,this.baseY=n,this.z=Math.random()*1.5+.2,this.vx=0,this.vy=0,this.color=i,this.angleTarget=Math.random()*Math.PI*2,this.randomSpeed=Math.random()*2+1,this.sizeBias=Math.random(),this.scale=1,this.dirX=Math.cos(this.angleTarget),this.dirY=Math.sin(this.angleTarget)}update(e,n,i,s,m,r,o,h="vertical"){this.initialized||(this.x=i+this.baseX,this.y=s+this.baseY,this.initialized=!0);const{forceX:g,forceY:d,dxCenter:c,dyCenter:a,distToCenter:l}=Z(this,e,n,i,s,o),{forceX:u,forceY:R}=V(this,i,s,o);this.vx+=g+u,this.vy+=d+R,this.vx*=.75,this.vy*=.75,this.x+=this.vx,this.y+=this.vy,tt(this,l),et(this,c,a,l,h,o),this.targetColor&&(this.colorDelay-=1,this.colorDelay<=0&&(this.color=this.targetColor,this.targetColor=null))}draw(e,n,i="bean"){if(this.scale<=.05)return;e.fillStyle=this.color;const s=Math.sqrt(this.baseX*this.baseX+this.baseY*this.baseY),m=Math.max(0,1-s/350);if(e.globalAlpha=Math.min(1,(.5+this.z*.5)*Math.min(this.scale,1)*m),!(e.globalAlpha<=.01))if(i==="circle"){const r=Math.max(.1,2*this.scale*this.z);e.beginPath(),e.arc(this.x,this.y,r,0,Math.PI*2),e.fill()}else if(i==="square"){const r=Math.max(.1,2*this.scale*this.z);e.fillRect(this.x-r,this.y-r,r*2,r*2)}else{const o=(6+this.sizeBias*6)*this.scale,h=Math.sin(n*3.5+this.baseX*.1+this.randomSpeed*5),g=.4+.6*((h+1)/2),d=o*.5*g,c=Math.max(.8,this.z*1.5*this.scale*(.8+.2*h)),a=Math.atan2(this.dirY,this.dirX);e.beginPath(),e.ellipse(this.x,this.y,d,c,a,0,Math.PI*2),e.fill()}}}function j({config:t,backgroundColor:e}){const n=f.useRef(null),i=f.useRef(null),s=f.useRef([]),m=f.useRef(0),r=f.useRef({x:-1e3,y:-1e3,isDown:!1,active:!1}),o=f.useRef({x:0,y:0,initialized:!1});f.useEffect(()=>{const c=l=>{if(!n.current)return;const u=n.current.getBoundingClientRect();r.current.x=l.clientX-u.left,r.current.y=l.clientY-u.top,r.current.active=!0},a=()=>{r.current.active=!1};return window.addEventListener("pointermove",c),window.addEventListener("pointerleave",a),()=>{window.removeEventListener("pointermove",c),window.removeEventListener("pointerleave",a)}},[]);const h=f.useRef(t),g=f.useRef(null),d=f.useRef(0);return f.useEffect(()=>{h.current=t},[t]),f.useEffect(()=>{if(g.current&&(clearInterval(g.current),g.current=null),!t.colors||t.colors.length===0){const a=t.color||"#8B5CF6";s.current.forEach(l=>{l.targetColor=a,l.colorDelay=Math.random()*20});return}const c=a=>{const l=r.current.active?r.current.x:o.current.x,u=r.current.active?r.current.y:o.current.y;s.current.forEach(R=>{const E=R.x-l,T=R.y-u,b=Math.sqrt(E*E+T*T);R.targetColor=a,R.colorDelay=Math.max(0,b*.15)})};return t.colorMode==="mixed"?s.current.forEach((a,l)=>{a.targetColor=t.colors[l%t.colors.length],a.colorDelay=Math.random()*20}):(d.current=0,c(t.colors[0]),t.colors.length>1&&(g.current=setInterval(()=>{const a=t.colors;d.current=(d.current+1)%a.length,c(a[d.current])},3e3))),()=>{g.current&&clearInterval(g.current)}},[t.colors,t.color,t.colorMode]),f.useEffect(()=>{if(!n.current||!i.current||h.current.name==="NONE")return;const c=i.current,a=n.current,l=b=>{for(const C of b){const{width:y,height:w}=C.contentRect,P=window.devicePixelRatio||1;c.width=y*P,c.height=w*P,c.style.width=`${y}px`,c.style.height=`${w}px`;const S=c.getContext("2d");S&&S.scale(P,P),s.current=[];const z=Math.floor(350*(h.current.density??1)),M=h.current.colors,D=h.current.colorMode||"wave";for(let x=0;x<z;x++){const p=Math.sqrt(Math.random())*350,X=Math.random()*Math.PI*2,Y=Math.cos(X)*p,A=Math.sin(X)*p;let F;if(M&&M.length>0)F=D==="mixed"?M[x%M.length]:M[0];else if(h.current.color)F=h.current.color;else{const B=210+Math.max(0,Math.min(1,(Y+350)/700))*130+(Math.random()*15-7.5),$=75+Math.random()*25,N=60+Math.random()*15;F=`hsl(${B}, ${$}%, ${N}%)`}s.current.push(new nt(Y,A,F))}}},u=new ResizeObserver(l);u.observe(a);const R=c.getContext("2d");let E=0;const T=()=>{const b=a.getBoundingClientRect();if(R.clearRect(0,0,b.width,b.height),e!=="transparent"&&(R.fillStyle=e,R.fillRect(0,0,b.width,b.height)),o.current.initialized||(o.current.x=b.width/2,o.current.y=b.height/2,o.current.initialized=!0),h.current.name==="FOLLOW_POINTER"){let C=b.width/2,y=b.height/2;const w=r.current.active?r.current.x:null,P=r.current.active?r.current.y:null;w!==null&&P!==null&&(C=w,y=P);const S=h.current.pointerTrackingSpeed??.06;o.current.x+=(C-o.current.x)*S,o.current.y+=(y-o.current.y)*S;const I=h.current.particleSpeed??1;E+=.012*I;const z=s.current,M=18,D=M*M;for(let x=0;x<z.length;x++){const p=z[x];for(let X=x+1;X<z.length;X++){const Y=z[X],A=p.x-Y.x,F=p.y-Y.y,W=A*A+F*F;if(W<D&&W>0){const B=Math.sqrt(W),$=(M-B)/M,N=A/B*$*.8,O=F/B*$*.8;p.x+=N,p.y+=O,Y.x-=N,Y.y-=O,p.vx+=N*.1,p.vy+=O*.1,Y.vx-=N*.1,Y.vy-=O*.1}}}for(const x of z){x.update(w,P,o.current.x,o.current.y,b.width,b.height,E,h.current.orientation);const p=h.current.shape||"bean";x.draw(R,E,p)}}m.current=requestAnimationFrame(T)};return T(),()=>{u.disconnect(),cancelAnimationFrame(m.current)}},[e,t.density]),t.name==="NONE"?null:q.jsx("div",{ref:n,style:{position:"absolute",inset:0,zIndex:0,overflow:"hidden"},children:q.jsx("canvas",{ref:i,style:{display:"block",width:"100%",height:"100%"}})})}class rt{constructor(e,n){v(this,"x");v(this,"y");v(this,"vx");v(this,"vy");v(this,"radius");v(this,"currentColor","#8B5CF6");v(this,"targetColor",null);v(this,"colorDelay",0);this.x=e,this.y=n;const i=Math.random()*Math.PI*2,s=Math.random()*.5+.1;this.vx=Math.cos(i)*s,this.vy=Math.sin(i)*s,this.radius=Math.random()*1.5+1}update(e,n,i,s,m=1,r=.06){if(this.x+=this.vx*m,this.y+=this.vy*m,this.x<0?(this.x=0,this.vx*=-1):this.x>e&&(this.x=e,this.vx*=-1),this.y<0?(this.y=0,this.vy*=-1):this.y>n&&(this.y=n,this.vy*=-1),i!==null&&s!==null){const o=i-this.x,h=s-this.y,g=o*o+h*h,d=150,c=d*d;if(g<c){const a=Math.sqrt(g),l=(d-a)/d,u=r/.06;this.x-=o/a*l*2*u,this.y-=h/a*l*2*u}}this.targetColor&&(this.colorDelay-=1*m,this.colorDelay<=0&&(this.currentColor=this.targetColor,this.targetColor=null))}draw(e,n="circle",i=0){if(e.fillStyle=this.currentColor,n==="square")e.fillRect(this.x-this.radius,this.y-this.radius,this.radius*2,this.radius*2);else if(n==="bean"){const s=Math.sin(i*.05+this.x*.01+this.y*.01),m=this.radius*2*(.8+.4*s),r=this.radius*(.8+.2*s),o=this.vx!==0||this.vy!==0?Math.atan2(this.vy,this.vx):0;e.beginPath(),e.ellipse(this.x,this.y,m,r,o,0,Math.PI*2),e.fill()}else e.beginPath(),e.arc(this.x,this.y,this.radius,0,Math.PI*2),e.fill()}}function H({config:t,backgroundColor:e}){const n=f.useRef(null),i=f.useRef(null),s=f.useRef([]),m=f.useRef(0),r=f.useRef({x:-1e3,y:-1e3,active:!1});f.useEffect(()=>{const d=a=>{if(!n.current)return;const l=n.current.getBoundingClientRect();r.current.x=a.clientX-l.left,r.current.y=a.clientY-l.top,r.current.active=!0},c=()=>{r.current.active=!1};return window.addEventListener("pointermove",d),window.addEventListener("pointerleave",c),()=>{window.removeEventListener("pointermove",d),window.removeEventListener("pointerleave",c)}},[]);const o=f.useRef(t),h=f.useRef(0),g=f.useRef(null);return f.useEffect(()=>{o.current=t},[t]),f.useEffect(()=>{if(g.current&&(clearInterval(g.current),g.current=null),!t.colors||t.colors.length===0){const l=t.color||"#8B5CF6";s.current.forEach(u=>{u.targetColor=l,u.colorDelay=Math.random()*20});return}const d=r.current.active?r.current.x:n.current?n.current.clientWidth/2:0,c=r.current.active?r.current.y:n.current?n.current.clientHeight/2:0,a=l=>{s.current.forEach(u=>{const R=u.x-d,E=u.y-c,T=Math.sqrt(R*R+E*E);u.targetColor=l,u.colorDelay=Math.max(0,T*.2)})};return t.colorMode==="mixed"?s.current.forEach((l,u)=>{l.targetColor=t.colors[u%t.colors.length],l.colorDelay=Math.random()*20}):(h.current=0,a(t.colors[0]),t.colors.length>1&&(g.current=setInterval(()=>{const l=t.colors;h.current=(h.current+1)%l.length,a(l[h.current])},3e3))),()=>{g.current&&clearInterval(g.current)}},[t.colors,t.color,t.colorMode]),f.useEffect(()=>{if(!n.current||!i.current)return;const d=i.current,c=n.current,a=T=>{for(const b of T){const{width:C,height:y}=b.contentRect,w=window.devicePixelRatio||1;d.width=C*w,d.height=y*w,d.style.width=`${C}px`,d.style.height=`${y}px`;const P=d.getContext("2d");P&&P.scale(w,w),s.current=[];const S=C*y,I=o.current.density??1,z=Math.min(Math.floor(300*I),Math.floor(S/6e3*I)),M=o.current.colors,D=o.current.colorMode||"wave";for(let x=0;x<z;x++){const p=new rt(Math.random()*C,Math.random()*y);M&&M.length>0?p.currentColor=D==="mixed"?M[x%M.length]:M[0]:o.current.color&&(p.currentColor=o.current.color),s.current.push(p)}}},l=new ResizeObserver(a);l.observe(c);const u=d.getContext("2d");let R=0;const E=()=>{R+=1;const T=c.getBoundingClientRect();u.clearRect(0,0,T.width,T.height),e!=="transparent"&&(u.fillStyle=e,u.fillRect(0,0,T.width,T.height));const b=r.current.active?r.current.x:null,C=r.current.active?r.current.y:null,y=s.current,w=o.current.shape||"circle",P=120,S=P*P,I=o.current.particleSpeed??1,z=o.current.pointerTrackingSpeed??.06;for(let M=0;M<y.length;M++){const D=y[M];D.update(T.width,T.height,b,C,I,z),u.globalAlpha=1,D.draw(u,w,R);for(let x=M+1;x<y.length;x++){const p=y[x],X=D.x-p.x,Y=D.y-p.y,A=X*X+Y*Y;if(A<S){const F=1-Math.sqrt(A)/P;u.beginPath(),u.moveTo(D.x,D.y),u.lineTo(p.x,p.y),u.strokeStyle=D.currentColor,u.globalAlpha=F*.5,u.lineWidth=1,u.stroke()}}}if(u.globalAlpha=1,b!==null&&C!==null)for(let x=0;x<y.length;x++){const p=y[x],X=p.x-b,Y=p.y-C,A=X*X+Y*Y;if(A<22500){const F=1-Math.sqrt(A)/150;u.beginPath(),u.moveTo(p.x,p.y),u.lineTo(b,C),u.strokeStyle=p.currentColor,u.globalAlpha=F*.8,u.lineWidth=1.5,u.stroke()}}u.globalAlpha=1,m.current=requestAnimationFrame(E)};return E(),()=>{l.disconnect(),cancelAnimationFrame(m.current)}},[e,t.density]),q.jsx("div",{ref:n,style:{position:"absolute",inset:0,zIndex:0,overflow:"hidden"},children:q.jsx("canvas",{ref:i,style:{display:"block",width:"100%",height:"100%"}})})}class st{constructor(e,n,i,s){v(this,"x",0);v(this,"y",0);v(this,"baseX");v(this,"baseY");v(this,"vx",0);v(this,"vy",0);v(this,"color");v(this,"size");v(this,"angle");v(this,"dist");v(this,"spring");v(this,"friction");v(this,"targetColor",null);v(this,"colorDelay",0);this.baseX=e,this.baseY=n,this.color=i,this.size=s,this.angle=Math.atan2(n,e),this.dist=Math.sqrt(e*e+n*n);const m=Math.min(1,this.dist/350);this.spring=.15-m*.13,this.friction=.85+m*.1}update(e,n,i,s){const r=1+Math.sin(this.angle*3+i*1.2)*.05+Math.cos(this.angle*5-i*.6)*.03,o=this.dist*s*r,h=Math.cos(this.angle)*o,g=Math.sin(this.angle)*o,d=this.dist*.1*r,c=Math.sin(i*3+this.dist*.05)*d,a=e+h+Math.cos(this.angle+Math.PI/2)*c,l=n+g+Math.sin(this.angle+Math.PI/2)*c,u=a-this.x,R=l-this.y;this.vx+=u*this.spring,this.vy+=R*this.spring,this.vx*=this.friction,this.vy*=this.friction,this.x+=this.vx,this.y+=this.vy,this.targetColor&&(this.colorDelay-=1,this.colorDelay<=0&&(this.color=this.targetColor,this.targetColor=null))}draw(e,n,i){const s=Math.min(1,this.dist/350),m=1+(1-s)*(i-1)*1.5,r=this.size*m;e.globalAlpha=Math.max(.15,1-s*.7),e.fillStyle=this.color,e.beginPath(),n==="circle"?e.arc(this.x,this.y,r,0,Math.PI*2):n==="square"?e.rect(this.x-r,this.y-r,r*2,r*2):e.ellipse(this.x,this.y,r*1.5,r,0,0,Math.PI*2),e.fill()}}function J({config:t,backgroundColor:e}){const n=f.useRef(null),i=f.useRef(null),s=f.useRef([]),m=f.useRef(0),r=f.useRef({x:-1e3,y:-1e3,active:!1}),o=f.useRef({x:0,y:0,initialized:!1,angle:-Math.PI/2});f.useEffect(()=>{const c=a=>{if(!n.current)return;const l=n.current.getBoundingClientRect();r.current.x=a.clientX-l.left,r.current.y=a.clientY-l.top,r.current.active=!0};return window.addEventListener("pointermove",c),()=>{window.removeEventListener("pointermove",c)}},[]);const h=f.useRef(t),g=f.useRef(0),d=f.useRef(null);return f.useEffect(()=>{h.current=t},[t]),f.useEffect(()=>{if(d.current&&(clearInterval(d.current),d.current=null),!t.colors||t.colors.length===0){const a=t.color||"#8B5CF6";s.current.forEach(l=>{l.targetColor=a,l.colorDelay=Math.random()*20});return}const c=a=>{s.current.forEach(l=>{l.targetColor=a,l.colorDelay=Math.max(0,l.dist*.2)})};return t.colorMode==="mixed"?s.current.forEach((a,l)=>{a.targetColor=t.colors[l%t.colors.length],a.colorDelay=Math.max(0,a.dist*.2)+Math.random()*10}):(g.current=0,c(t.colors[0]),t.colors.length>1&&(d.current=setInterval(()=>{const a=t.colors;g.current=(g.current+1)%a.length,c(a[g.current])},3e3))),()=>{d.current&&clearInterval(d.current)}},[t.colors,t.color,t.colorMode]),f.useEffect(()=>{if(!n.current||!i.current)return;const c=i.current,a=n.current,l=b=>{for(const C of b){const{width:y,height:w}=C.contentRect,P=window.devicePixelRatio||1;c.width=y*P,c.height=w*P,c.style.width=`${y}px`,c.style.height=`${w}px`;const S=c.getContext("2d");S&&S.scale(P,P),s.current=[];const z=Math.floor(350*(h.current.density??1)),M=h.current.colors,D=h.current.colorMode||"wave";for(let x=0;x<z;x++){const p=Math.random()*Math.PI*2,X=Math.sqrt(Math.random())*350,Y=Math.cos(p)*X,A=Math.sin(p)*X;let F;if(M&&M.length>0)F=D==="mixed"?M[x%M.length]:M[0];else if(h.current.color)F=h.current.color;else{const $=260+Math.random()*60,N=70+Math.random()*30,O=60+Math.random()*20;F=`hsl(${$}, ${N}%, ${O}%)`}let W=2+Math.random()*2;X>200&&(W*=.6),X<80&&(W*=1.5);const B=new st(Y,A,F,W);B.x=y/2,B.y=w/2,s.current.push(B)}}},u=new ResizeObserver(l);u.observe(a);const R=c.getContext("2d");let E=0;const T=()=>{const b=a.getBoundingClientRect();R.globalCompositeOperation="source-over",e==="transparent"?R.clearRect(0,0,b.width,b.height):(R.fillStyle=e,R.fillRect(0,0,b.width,b.height)),o.current.initialized||(o.current.x=b.width/2,o.current.y=b.height/2,o.current.initialized=!0);let C=b.width/2,y=b.height/2;const w=r.current.active?r.current.x:null,P=r.current.active?r.current.y:null;w!==null&&P!==null&&(C=w,y=P);const S=C-o.current.x,I=y-o.current.y,z=Math.sqrt(S*S+I*I);let M=0,D=0;z>1?(M=S/z,D=I/z,o.current.angle=Math.atan2(D,M)):(M=Math.cos(o.current.angle),D=Math.sin(o.current.angle));const x=h.current.particleSpeed??1;E+=.02*x;const p=E%4;let X=1,Y=1,A=0;if(p<1){const O=p;X=1-Math.sin(O*Math.PI)*.3,Y=1+Math.sin(O*Math.PI)*.15,A=Math.sin(O*Math.PI)*12}else{const O=(p-1)/3;X=.7+.3*Math.sin(O*Math.PI/2),Y=1,A=0}const F=h.current.pointerTrackingSpeed??.02;o.current.x+=S*F,o.current.y+=I*F,o.current.x+=M*A*x,o.current.y+=D*A*x;const B=200*(Y+(p<1?p*.15:0)),$=R.createRadialGradient(o.current.x,o.current.y,0,o.current.x,o.current.y,B);$.addColorStop(0,"rgba(80, 150, 255, 0.05)"),$.addColorStop(1,"rgba(80, 150, 255, 0)"),R.fillStyle=$,R.beginPath(),R.arc(o.current.x,o.current.y,B,0,Math.PI*2),R.fill();const N=s.current;R.globalCompositeOperation="source-over";for(const O of N){O.update(o.current.x,o.current.y,E,X);const at=h.current.shape||"circle";O.draw(R,at,Y)}m.current=requestAnimationFrame(T)};return T(),()=>{u.disconnect(),cancelAnimationFrame(m.current)}},[e,t.density]),q.jsx("div",{ref:n,style:{position:"absolute",inset:0,zIndex:0,overflow:"hidden",pointerEvents:"none"},children:q.jsx("canvas",{ref:i,style:{display:"block",width:"100%",height:"100%",pointerEvents:"none"}})})}const ot={position:"relative",border:"1px solid rgba(255, 255, 255, 0.1)",borderRadius:"1rem",overflow:"hidden",boxShadow:"0 25px 50px -12px rgba(0, 0, 0, 0.25)",transition:"all 300ms ease-out"};function it({children:t,width:e="100%",height:n="60vh",backgroundColor:i="#050505",className:s="",style:m,background:r={name:"NONE"}}){return q.jsxs("div",{className:s,style:{...ot,width:e,height:n,backgroundColor:i,...m},children:[r.name==="FOLLOW_POINTER"&&q.jsx(j,{config:r,backgroundColor:i}),r.name==="NET"&&q.jsx(H,{config:r,backgroundColor:i}),r.name==="JELLYFISH"&&q.jsx(J,{config:r,backgroundColor:i}),q.jsx("div",{style:{position:"relative",zIndex:10,width:"100%",height:"100%"},children:t})]})}function G(t){const e=f.useRef({x:-1e3,y:-1e3,isDown:!1,active:!1});return f.useEffect(()=>{const n=t.current;if(!n)return;const i=o=>{const h=n.getBoundingClientRect();e.current.x=o.clientX-h.left,e.current.y=o.clientY-h.top,e.current.active=!0},s=()=>{e.current.active=!1},m=()=>{e.current.isDown=!0},r=()=>{e.current.isDown=!1};return n.addEventListener("pointermove",i),n.addEventListener("pointerleave",s),n.addEventListener("pointerdown",m),n.addEventListener("pointerup",r),n.style.touchAction="none",()=>{n.removeEventListener("pointermove",i),n.removeEventListener("pointerleave",s),n.removeEventListener("pointerdown",m),n.removeEventListener("pointerup",r)}},[t]),e}function K(t,e,n,i,s,m,r,o,h){if(s===null||m===null||!o&&h==="none")return{x:n,y:i};let g=n,d=i;const c=s-t,a=m-e,l=c*c+a*a,u=Math.sqrt(l);if(o&&!r&&l<3e4){const E=(3e4-l)/3e4;g+=c*E*.15,d+=a*E*.15}if(r&&h!=="none"){if(h==="attract"){if(l<3e4){const E=(3e4-l)/3e4;g+=c*E*.8,d+=a*E*.8}}else if(h==="repel"&&l<5e4&&u>0){const E=Math.pow(Math.max(0,5e4-l)/5e4,1.2);g-=c/u*E*400,d-=a/u*E*400}}return{x:g,y:d}}class _{constructor(e,n,i="255, 255, 255"){v(this,"x");v(this,"y");v(this,"vx");v(this,"vy");v(this,"targetX");v(this,"targetY");v(this,"baseColor");v(this,"opacity");v(this,"size");v(this,"sizeMultiplier");v(this,"friction");v(this,"ease");v(this,"easeMultiplier");v(this,"floatSpeed");v(this,"floatOffset");v(this,"randomSpeed");this.x=Math.random()*e,this.y=Math.random()*n,this.targetX=this.x,this.targetY=this.y,this.vx=0,this.vy=0,this.size=Math.random()*1.8+.5,this.sizeMultiplier=1,this.baseColor=Array.isArray(i)?i[Math.floor(Math.random()*i.length)]:i,this.opacity=.4+Math.random()*.6,this.friction=.82+Math.random()*.1,this.ease=.03+Math.random()*.05,this.easeMultiplier=1,this.floatSpeed=Math.random()*.02+.005,this.floatOffset=Math.random()*Math.PI*2,this.randomSpeed=Math.random()}update(e,n,i=null,s=null,m=!1,r=!0,o="none"){const{x:h,y:g}=K(this.x,this.y,this.targetX,this.targetY,i,s,m,r,o),d=h-this.x,c=g-this.y,a=n?0:Math.cos(e*.01+this.y*.01)*.5,l=n?0:Math.sin(e*.01+this.x*.01)*.5;this.vx+=d*(this.ease*this.easeMultiplier)+a,this.vy+=c*(this.ease*this.easeMultiplier)+l,this.vx*=this.friction,this.vy*=this.friction,this.x+=this.vx,this.y+=this.vy;const u=n?.2:2;this.x+=Math.cos(e*this.floatSpeed+this.floatOffset)*u,this.y+=Math.sin(e*this.floatSpeed+this.floatOffset)*u}draw(e,n="circle",i=0){e.fillStyle=`rgba(${this.baseColor}, ${this.opacity})`;const s=Math.max(.1,this.size*this.sizeMultiplier);if(n==="square")e.fillRect(this.x-s,this.y-s,s*2,s*2);else if(n==="bean"){const m=6+this.size*2*this.sizeMultiplier,r=Math.sin(i*.05+this.x*.01+this.randomSpeed*5),o=.4+.6*((r+1)/2),h=m*.5*o,g=Math.max(.8,s*1.5*(.8+.2*r)),d=this.vx!==0||this.vy!==0?Math.atan2(this.vy,this.vx):0;e.beginPath(),e.ellipse(this.x,this.y,h,g,d,0,Math.PI*2),e.fill()}else e.beginPath(),e.arc(this.x,this.y,s,0,Math.PI*2),e.fill()}}function U(t,e,n){if(e<=0||n<=0)return[];const i=document.createElement("canvas");i.width=e,i.height=n;const s=i.getContext("2d",{willReadFrequently:!0});if(!s)return[];s.clearRect(0,0,e,n);let m=Math.min(e,n)*.65;s.font=`bold ${m}px "Georgia", serif`;const r=s.measureText(t);r.width>e*.9&&(m=m*(e*.9)/r.width,s.font=`bold ${m}px "Georgia", serif`),s.fillStyle="white",s.textAlign="center",s.textBaseline="middle",s.fillText(t,e/2,n/2.05);const h=s.getImageData(0,0,e,n).data,g=[],d=window.innerWidth<600?6:8;for(let c=0;c<n;c+=d)for(let a=0;a<e;a+=d){const l=(c*e+a)*4;h[l+3]>128&&g.push({x:a+(Math.random()-.5)*4,y:c+(Math.random()-.5)*4})}return g}function Q(t,e,n){const i=f.useRef(t);return f.useEffect(()=>{i.current=t},[t]),{getPixelsForText:U,updateTextTargets:(m,r,o)=>{var T,b;const h=r||((T=n.current)==null?void 0:T.offsetWidth)||window.innerWidth,g=o||((b=n.current)==null?void 0:b.offsetHeight)||window.innerHeight;if(!m){e.current.forEach(y=>{const w=50+Math.random()*(h-100),P=50+Math.random()*(g-100);(Math.abs(w-y.x)>20||Math.abs(P-y.y)>20)&&(y.vx+=(Math.random()-.5)*20,y.vy+=(Math.random()-.5)*20),y.targetX=w,y.targetY=P});return}const d=U(m,h,g);if(d.length===0)return;const c=h*.15,a=d.map(C=>({pt:C,key:C.x+(Math.random()-.5)*c}));a.sort((C,y)=>C.key-y.key);const l=a.map(C=>C.pt),u=e.current.map((C,y)=>({i:y,key:C.x+(Math.random()-.5)*c}));u.sort((C,y)=>C.key-y.key);const R=u.map(C=>C.i),E=Math.ceil(Math.sqrt(R.length));for(let C=0;C<R.length;C+=E){const y=Math.min(C+E,R.length),w=R.slice(C,y),P=[];for(let S=C;S<y;S++)P.push(l[S%l.length]);w.sort((S,I)=>e.current[S].y-e.current[I].y),P.sort((S,I)=>S.y-I.y);for(let S=0;S<w.length;S++){const I=w[S],z=e.current[I],M=P[S],D=M.x-z.x,x=M.y-z.y;if(Math.abs(D)>20||Math.abs(x)>20){z.vx+=(Math.random()-.5)*20,z.vy+=(Math.random()-.5)*20;const p=(Math.random()>.5?1:-1)*(Math.random()*10+5);z.vx+=Math.sign(x)*p,z.vy-=Math.sign(D)*p}z.targetX=M.x,z.targetY=M.y}}},textRef:i}}const k=t=>{if(!t||typeof t!="string")return"0, 0, 0";try{let e=0,n=0,i=0;if(t.length===4)e=parseInt(t[1]+t[1],16),n=parseInt(t[2]+t[2],16),i=parseInt(t[3]+t[3],16);else if(t.length===7)e=parseInt(t.substring(1,3),16),n=parseInt(t.substring(3,5),16),i=parseInt(t.substring(5,7),16);else return t;return`${e}, ${n}, ${i}`}catch{return"0, 0, 0"}};function ct({text:t,particleColor:e="255, 255, 255",particleSize:n=1,particleDensity:i=1,particleEase:s=1,isMagnet:m=!0,clickMode:r="none",particleShape:o="circle",backgroundColor:h="#050505"}){const g=f.useRef(null),d=f.useRef(null),c=f.useRef([]),a=f.useRef(0),l=f.useRef(0),u=G(d),R=f.useRef({isMagnet:m,clickMode:r,particleShape:o,backgroundColor:h});R.current={isMagnet:m,clickMode:r,particleShape:o,backgroundColor:h};const{updateTextTargets:E,textRef:T}=Q(t,c,d),b=()=>Array.isArray(e)?e.map(y=>k(y)):k(e),C=(y,w,P=1)=>{const S=window.innerWidth<600?1500:3e3,I=Math.floor(S*P),z=[],M=b();for(let D=0;D<I;D++){const x=new _(y,w,M);x.sizeMultiplier=n,x.easeMultiplier=s,z.push(x)}c.current=z};return f.useEffect(()=>{if(c.current.length>0){const y=b();c.current.forEach(w=>{w.baseColor=Array.isArray(y)?y[Math.floor(Math.random()*y.length)]:y})}},[e]),f.useEffect(()=>{c.current.length>0&&c.current.forEach(y=>{y.sizeMultiplier=n})},[n]),f.useEffect(()=>{c.current.length>0&&c.current.forEach(y=>{y.easeMultiplier=s})},[s]),f.useEffect(()=>{if(c.current.length>0&&g.current&&d.current){const y=window.innerWidth<600?1500:3e3,w=Math.floor(y*i),P=c.current.length;if(w>P){const S=d.current.getBoundingClientRect(),I=b();for(let z=0;z<w-P;z++){const M=new _(S.width,S.height,I);M.sizeMultiplier=n,c.current.push(M)}E(t)}else w<P&&c.current.splice(w)}},[i]),f.useEffect(()=>{const y=d.current,w=g.current;if(!y||!w)return;const P=M=>{for(const D of M){const{width:x,height:p}=D.contentRect,X=window.devicePixelRatio||1;w.width=x*X,w.height=p*X,w.style.width=`${x}px`,w.style.height=`${p}px`;const Y=w.getContext("2d");Y&&Y.scale(X,X),c.current.length===0&&C(x,p,i),E(t,x,p)}},S=new ResizeObserver(P);S.observe(y);const I=w.getContext("2d"),z=()=>{l.current++;const M=y.getBoundingClientRect(),{isMagnet:D,clickMode:x,particleShape:p,backgroundColor:X}=R.current;if(X==="transparent")I.clearRect(0,0,M.width,M.height),I.globalCompositeOperation="source-over";else{const B=k(X);I.fillStyle=`rgba(${B}, 0.25)`,I.fillRect(0,0,M.width,M.height),I.globalCompositeOperation="screen"}const Y=T.current!=="",A=u.current.active?u.current.x:null,F=u.current.active?u.current.y:null,W=u.current.isDown;for(let B=0;B<c.current.length;B++){const $=c.current[B];$.update(l.current,!!Y,A,F,W,D,x),$.draw(I,p,l.current)}I.globalCompositeOperation="source-over",a.current=requestAnimationFrame(z)};return z(),()=>{S.disconnect(),cancelAnimationFrame(a.current)}},[]),f.useEffect(()=>{E(t)},[t]),q.jsx("div",{ref:d,style:{position:"absolute",inset:0,zIndex:0,overflow:"hidden"},children:q.jsx("canvas",{ref:g,style:{display:"block",width:"100%",height:"100%"}})})}L.BackgroundParticleEngine=j,L.JellyfishParticleEngine=J,L.NetParticleEngine=H,L.ParticleCanvas=it,L.TextParticleEngine=ct,L.getMagnetTarget=K,L.useParticleInteraction=G,L.useTextParticles=Q,Object.defineProperty(L,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(B,T){typeof exports=="object"&&typeof module<"u"?T(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],T):(B=typeof globalThis<"u"?globalThis:B||self,T(B.JlParticleInteractive={},B.ReactJsxRuntime,B.React))})(this,(function(B,T,f){"use strict";var ht=Object.defineProperty;var ut=(B,T,f)=>T in B?ht(B,T,{enumerable:!0,configurable:!0,writable:!0,value:f}):B[T]=f;var m=(B,T,f)=>ut(B,typeof T!="symbol"?T+"":T,f);function U(t,e,n,i){let s=e+t.baseX,g=n+t.baseY;s+=Math.sin(i*t.randomSpeed+t.baseY*.05)*15*t.z,g+=Math.cos(i*t.randomSpeed+t.baseX*.05)*15*t.z;const r=s-t.x,o=g-t.y,h=r*.06,v=o*.06;return{forceX:h,forceY:v}}function Q(t,e,n,i,s,g){const r=i,o=s,h=t.x-r,v=t.y-o,d=Math.max(Math.sqrt(h*h+v*v),1);let c=0,a=0;const u=Math.sin(d*.02-g*3)*2.5*t.z;c+=h/d*u,a+=v/d*u;const E=Math.cos(d*.01-g*1+t.randomSpeed)*.8*t.z,q=-v/d,b=h/d;return c+=q*E,a+=b*E,{forceX:c,forceY:a,dxCenter:h,dyCenter:v,distToCenter:d}}function V(t,e){let s=Math.min(e/400,1)*2.5+t.sizeBias*1;s<.4&&(s=0),t.scale+=(s-t.scale)*.15}function Z(t,e,n,i,s,g){let r=0,o=0;s==="horizontal"?(r=1,o=0):s==="diagonal"?(r=-e/i,o=-n/i):(r=-n/i,o=e/i);const h=Math.atan2(o,r),v=t.sizeBias>.3?1:0,d=Math.max(0,Math.sin(g*.5+t.randomSpeed*10)),c=Math.sin(g*3+t.baseX*.1+t.randomSpeed)*.5*d*v;r=Math.cos(h+c),o=Math.sin(h+c);const a=Math.max(1-i/400,.1);s==="horizontal"?(t.dirX=t.dirX*(1-.2)+r*.2,t.dirY=t.dirY*(1-.2)+o*.2):(t.dirX=t.dirX*(1-a*.3)+r*a*.3,t.dirY=t.dirY*(1-a*.3)+o*a*.3);const l=Math.sqrt(t.dirX*t.dirX+t.dirY*t.dirY);l>0&&(t.dirX/=l,t.dirY/=l)}class tt{constructor(e,n,i){m(this,"x");m(this,"y");m(this,"baseX");m(this,"baseY");m(this,"z");m(this,"vx");m(this,"vy");m(this,"color");m(this,"targetColor",null);m(this,"colorDelay",0);m(this,"angleTarget");m(this,"randomSpeed");m(this,"sizeBias");m(this,"scale");m(this,"dirX");m(this,"dirY");m(this,"initialized",!1);this.x=e,this.y=n,this.baseX=e,this.baseY=n,this.z=Math.random()*1.5+.2,this.vx=0,this.vy=0,this.color=i,this.angleTarget=Math.random()*Math.PI*2,this.randomSpeed=Math.random()*2+1,this.sizeBias=Math.random(),this.scale=1,this.dirX=Math.cos(this.angleTarget),this.dirY=Math.sin(this.angleTarget)}update(e,n,i,s,g,r,o,h="vertical"){this.initialized||(this.x=i+this.baseX,this.y=s+this.baseY,this.initialized=!0);const{forceX:v,forceY:d,dxCenter:c,dyCenter:a,distToCenter:l}=Q(this,e,n,i,s,o),{forceX:u,forceY:R}=U(this,i,s,o);this.vx+=v+u,this.vy+=d+R,this.vx*=.75,this.vy*=.75,this.x+=this.vx,this.y+=this.vy,V(this,l),Z(this,c,a,l,h,o),this.targetColor&&(this.colorDelay-=1,this.colorDelay<=0&&(this.color=this.targetColor,this.targetColor=null))}draw(e,n,i="bean"){if(this.scale<=.05)return;e.fillStyle=this.color;const s=Math.sqrt(this.baseX*this.baseX+this.baseY*this.baseY),g=Math.max(0,1-s/350);if(e.globalAlpha=Math.min(1,(.5+this.z*.5)*Math.min(this.scale,1)*g),!(e.globalAlpha<=.01))if(i==="circle"){const r=Math.max(.1,2*this.scale*this.z);e.beginPath(),e.arc(this.x,this.y,r,0,Math.PI*2),e.fill()}else if(i==="square"){const r=Math.max(.1,2*this.scale*this.z);e.fillRect(this.x-r,this.y-r,r*2,r*2)}else{const o=(6+this.sizeBias*6)*this.scale,h=Math.sin(n*3.5+this.baseX*.1+this.randomSpeed*5),v=.4+.6*((h+1)/2),d=o*.5*v,c=Math.max(.8,this.z*1.5*this.scale*(.8+.2*h)),a=Math.atan2(this.dirY,this.dirX);e.beginPath(),e.ellipse(this.x,this.y,d,c,a,0,Math.PI*2),e.fill()}}}function et({config:t,backgroundColor:e}){const n=f.useRef(null),i=f.useRef(null),s=f.useRef([]),g=f.useRef(0),r=f.useRef({x:-1e3,y:-1e3,isDown:!1,active:!1}),o=f.useRef({x:0,y:0,initialized:!1});f.useEffect(()=>{const c=l=>{if(!n.current)return;const u=n.current.getBoundingClientRect();r.current.x=l.clientX-u.left,r.current.y=l.clientY-u.top,r.current.active=!0},a=()=>{r.current.active=!1};return window.addEventListener("pointermove",c),window.addEventListener("pointerleave",a),()=>{window.removeEventListener("pointermove",c),window.removeEventListener("pointerleave",a)}},[]);const h=f.useRef(t),v=f.useRef(null),d=f.useRef(0);return f.useEffect(()=>{h.current=t},[t]),f.useEffect(()=>{if(v.current&&(clearInterval(v.current),v.current=null),!t.colors||t.colors.length===0){const a=t.color||"#8B5CF6";s.current.forEach(l=>{l.targetColor=a,l.colorDelay=Math.random()*20});return}const c=a=>{const l=r.current.active?r.current.x:o.current.x,u=r.current.active?r.current.y:o.current.y;s.current.forEach(R=>{const E=R.x-l,q=R.y-u,b=Math.sqrt(E*E+q*q);R.targetColor=a,R.colorDelay=Math.max(0,b*.15)})};return t.colorMode==="mixed"?s.current.forEach((a,l)=>{a.targetColor=t.colors[l%t.colors.length],a.colorDelay=Math.random()*20}):(d.current=0,c(t.colors[0]),t.colors.length>1&&(v.current=setInterval(()=>{const a=t.colors;d.current=(d.current+1)%a.length,c(a[d.current])},3e3))),()=>{v.current&&clearInterval(v.current)}},[t.colors,t.color,t.colorMode]),f.useEffect(()=>{if(!n.current||!i.current||h.current.name==="NONE")return;const c=i.current,a=n.current,l=b=>{for(const C of b){const{width:y,height:w}=C.contentRect,P=window.devicePixelRatio||1;c.width=y*P,c.height=w*P,c.style.width=`${y}px`,c.style.height=`${w}px`;const S=c.getContext("2d");S&&S.scale(P,P),s.current=[];const z=Math.floor(350*(h.current.density??1)),M=h.current.colors,D=h.current.colorMode||"wave";for(let x=0;x<z;x++){const p=Math.sqrt(Math.random())*350,X=Math.random()*Math.PI*2,Y=Math.cos(X)*p,L=Math.sin(X)*p;let F;if(M&&M.length>0)F=D==="mixed"?M[x%M.length]:M[0];else if(h.current.color)F=h.current.color;else{const A=210+Math.max(0,Math.min(1,(Y+350)/700))*130+(Math.random()*15-7.5),$=75+Math.random()*25,k=60+Math.random()*15;F=`hsl(${A}, ${$}%, ${k}%)`}s.current.push(new tt(Y,L,F))}}},u=new ResizeObserver(l);u.observe(a);const R=c.getContext("2d");let E=0;const q=()=>{const b=a.getBoundingClientRect();if(R.clearRect(0,0,b.width,b.height),e!=="transparent"&&(R.fillStyle=e,R.fillRect(0,0,b.width,b.height)),o.current.initialized||(o.current.x=b.width/2,o.current.y=b.height/2,o.current.initialized=!0),h.current.name==="FOLLOW_POINTER"){let C=b.width/2,y=b.height/2;const w=r.current.active?r.current.x:null,P=r.current.active?r.current.y:null;w!==null&&P!==null&&(C=w,y=P);const S=h.current.pointerTrackingSpeed??.06;o.current.x+=(C-o.current.x)*S,o.current.y+=(y-o.current.y)*S;const I=h.current.particleSpeed??1;E+=.012*I;const z=s.current,M=18,D=M*M;for(let x=0;x<z.length;x++){const p=z[x];for(let X=x+1;X<z.length;X++){const Y=z[X],L=p.x-Y.x,F=p.y-Y.y,W=L*L+F*F;if(W<D&&W>0){const A=Math.sqrt(W),$=(M-A)/M,k=L/A*$*.8,O=F/A*$*.8;p.x+=k,p.y+=O,Y.x-=k,Y.y-=O,p.vx+=k*.1,p.vy+=O*.1,Y.vx-=k*.1,Y.vy-=O*.1}}}for(const x of z){x.update(w,P,o.current.x,o.current.y,b.width,b.height,E,h.current.orientation);const p=h.current.shape||"bean";x.draw(R,E,p)}}g.current=requestAnimationFrame(q)};return q(),()=>{u.disconnect(),cancelAnimationFrame(g.current)}},[e,t.density]),t.name==="NONE"?null:T.jsx("div",{ref:n,style:{position:"absolute",inset:0,zIndex:0,overflow:"hidden"},children:T.jsx("canvas",{ref:i,style:{display:"block",width:"100%",height:"100%"}})})}class nt{constructor(e,n){m(this,"x");m(this,"y");m(this,"vx");m(this,"vy");m(this,"radius");m(this,"currentColor","#8B5CF6");m(this,"targetColor",null);m(this,"colorDelay",0);this.x=e,this.y=n;const i=Math.random()*Math.PI*2,s=Math.random()*.5+.1;this.vx=Math.cos(i)*s,this.vy=Math.sin(i)*s,this.radius=Math.random()*1.5+1}update(e,n,i,s,g=1,r=.06){if(this.x+=this.vx*g,this.y+=this.vy*g,this.x<0?(this.x=0,this.vx*=-1):this.x>e&&(this.x=e,this.vx*=-1),this.y<0?(this.y=0,this.vy*=-1):this.y>n&&(this.y=n,this.vy*=-1),i!==null&&s!==null){const o=i-this.x,h=s-this.y,v=o*o+h*h,d=150,c=d*d;if(v<c){const a=Math.sqrt(v),l=(d-a)/d,u=r/.06;this.x-=o/a*l*2*u,this.y-=h/a*l*2*u}}this.targetColor&&(this.colorDelay-=1*g,this.colorDelay<=0&&(this.currentColor=this.targetColor,this.targetColor=null))}draw(e,n="circle",i=0){if(e.fillStyle=this.currentColor,n==="square")e.fillRect(this.x-this.radius,this.y-this.radius,this.radius*2,this.radius*2);else if(n==="bean"){const s=Math.sin(i*.05+this.x*.01+this.y*.01),g=this.radius*2*(.8+.4*s),r=this.radius*(.8+.2*s),o=this.vx!==0||this.vy!==0?Math.atan2(this.vy,this.vx):0;e.beginPath(),e.ellipse(this.x,this.y,g,r,o,0,Math.PI*2),e.fill()}else e.beginPath(),e.arc(this.x,this.y,this.radius,0,Math.PI*2),e.fill()}}function rt({config:t,backgroundColor:e}){const n=f.useRef(null),i=f.useRef(null),s=f.useRef([]),g=f.useRef(0),r=f.useRef({x:-1e3,y:-1e3,active:!1});f.useEffect(()=>{const d=a=>{if(!n.current)return;const l=n.current.getBoundingClientRect();r.current.x=a.clientX-l.left,r.current.y=a.clientY-l.top,r.current.active=!0},c=()=>{r.current.active=!1};return window.addEventListener("pointermove",d),window.addEventListener("pointerleave",c),()=>{window.removeEventListener("pointermove",d),window.removeEventListener("pointerleave",c)}},[]);const o=f.useRef(t),h=f.useRef(0),v=f.useRef(null);return f.useEffect(()=>{o.current=t},[t]),f.useEffect(()=>{if(v.current&&(clearInterval(v.current),v.current=null),!t.colors||t.colors.length===0){const l=t.color||"#8B5CF6";s.current.forEach(u=>{u.targetColor=l,u.colorDelay=Math.random()*20});return}const d=r.current.active?r.current.x:n.current?n.current.clientWidth/2:0,c=r.current.active?r.current.y:n.current?n.current.clientHeight/2:0,a=l=>{s.current.forEach(u=>{const R=u.x-d,E=u.y-c,q=Math.sqrt(R*R+E*E);u.targetColor=l,u.colorDelay=Math.max(0,q*.2)})};return t.colorMode==="mixed"?s.current.forEach((l,u)=>{l.targetColor=t.colors[u%t.colors.length],l.colorDelay=Math.random()*20}):(h.current=0,a(t.colors[0]),t.colors.length>1&&(v.current=setInterval(()=>{const l=t.colors;h.current=(h.current+1)%l.length,a(l[h.current])},3e3))),()=>{v.current&&clearInterval(v.current)}},[t.colors,t.color,t.colorMode]),f.useEffect(()=>{if(!n.current||!i.current)return;const d=i.current,c=n.current,a=q=>{for(const b of q){const{width:C,height:y}=b.contentRect,w=window.devicePixelRatio||1;d.width=C*w,d.height=y*w,d.style.width=`${C}px`,d.style.height=`${y}px`;const P=d.getContext("2d");P&&P.scale(w,w),s.current=[];const S=C*y,I=o.current.density??1,z=Math.min(Math.floor(300*I),Math.floor(S/6e3*I)),M=o.current.colors,D=o.current.colorMode||"wave";for(let x=0;x<z;x++){const p=new nt(Math.random()*C,Math.random()*y);M&&M.length>0?p.currentColor=D==="mixed"?M[x%M.length]:M[0]:o.current.color&&(p.currentColor=o.current.color),s.current.push(p)}}},l=new ResizeObserver(a);l.observe(c);const u=d.getContext("2d");let R=0;const E=()=>{R+=1;const q=c.getBoundingClientRect();u.clearRect(0,0,q.width,q.height),e!=="transparent"&&(u.fillStyle=e,u.fillRect(0,0,q.width,q.height));const b=r.current.active?r.current.x:null,C=r.current.active?r.current.y:null,y=s.current,w=o.current.shape||"circle",P=120,S=P*P,I=o.current.particleSpeed??1,z=o.current.pointerTrackingSpeed??.06;for(let M=0;M<y.length;M++){const D=y[M];D.update(q.width,q.height,b,C,I,z),u.globalAlpha=1,D.draw(u,w,R);for(let x=M+1;x<y.length;x++){const p=y[x],X=D.x-p.x,Y=D.y-p.y,L=X*X+Y*Y;if(L<S){const F=1-Math.sqrt(L)/P;u.beginPath(),u.moveTo(D.x,D.y),u.lineTo(p.x,p.y),u.strokeStyle=D.currentColor,u.globalAlpha=F*.5,u.lineWidth=1,u.stroke()}}}if(u.globalAlpha=1,b!==null&&C!==null)for(let x=0;x<y.length;x++){const p=y[x],X=p.x-b,Y=p.y-C,L=X*X+Y*Y;if(L<22500){const F=1-Math.sqrt(L)/150;u.beginPath(),u.moveTo(p.x,p.y),u.lineTo(b,C),u.strokeStyle=p.currentColor,u.globalAlpha=F*.8,u.lineWidth=1.5,u.stroke()}}u.globalAlpha=1,g.current=requestAnimationFrame(E)};return E(),()=>{l.disconnect(),cancelAnimationFrame(g.current)}},[e,t.density]),T.jsx("div",{ref:n,style:{position:"absolute",inset:0,zIndex:0,overflow:"hidden"},children:T.jsx("canvas",{ref:i,style:{display:"block",width:"100%",height:"100%"}})})}class st{constructor(e,n,i,s){m(this,"x",0);m(this,"y",0);m(this,"baseX");m(this,"baseY");m(this,"vx",0);m(this,"vy",0);m(this,"color");m(this,"size");m(this,"angle");m(this,"dist");m(this,"spring");m(this,"friction");m(this,"targetColor",null);m(this,"colorDelay",0);this.baseX=e,this.baseY=n,this.color=i,this.size=s,this.angle=Math.atan2(n,e),this.dist=Math.sqrt(e*e+n*n);const g=Math.min(1,this.dist/350);this.spring=.15-g*.13,this.friction=.85+g*.1}update(e,n,i,s){const r=1+Math.sin(this.angle*3+i*1.2)*.05+Math.cos(this.angle*5-i*.6)*.03,o=this.dist*s*r,h=Math.cos(this.angle)*o,v=Math.sin(this.angle)*o,d=this.dist*.1*r,c=Math.sin(i*3+this.dist*.05)*d,a=e+h+Math.cos(this.angle+Math.PI/2)*c,l=n+v+Math.sin(this.angle+Math.PI/2)*c,u=a-this.x,R=l-this.y;this.vx+=u*this.spring,this.vy+=R*this.spring,this.vx*=this.friction,this.vy*=this.friction,this.x+=this.vx,this.y+=this.vy,this.targetColor&&(this.colorDelay-=1,this.colorDelay<=0&&(this.color=this.targetColor,this.targetColor=null))}draw(e,n,i){const s=Math.min(1,this.dist/350),g=1+(1-s)*(i-1)*1.5,r=this.size*g;e.globalAlpha=Math.max(.15,1-s*.7),e.fillStyle=this.color,e.beginPath(),n==="circle"?e.arc(this.x,this.y,r,0,Math.PI*2):n==="square"?e.rect(this.x-r,this.y-r,r*2,r*2):e.ellipse(this.x,this.y,r*1.5,r,0,0,Math.PI*2),e.fill()}}function ot({config:t,backgroundColor:e}){const n=f.useRef(null),i=f.useRef(null),s=f.useRef([]),g=f.useRef(0),r=f.useRef({x:-1e3,y:-1e3,active:!1}),o=f.useRef({x:0,y:0,initialized:!1,angle:-Math.PI/2});f.useEffect(()=>{const c=a=>{if(!n.current)return;const l=n.current.getBoundingClientRect();r.current.x=a.clientX-l.left,r.current.y=a.clientY-l.top,r.current.active=!0};return window.addEventListener("pointermove",c),()=>{window.removeEventListener("pointermove",c)}},[]);const h=f.useRef(t),v=f.useRef(0),d=f.useRef(null);return f.useEffect(()=>{h.current=t},[t]),f.useEffect(()=>{if(d.current&&(clearInterval(d.current),d.current=null),!t.colors||t.colors.length===0){const a=t.color||"#8B5CF6";s.current.forEach(l=>{l.targetColor=a,l.colorDelay=Math.random()*20});return}const c=a=>{s.current.forEach(l=>{l.targetColor=a,l.colorDelay=Math.max(0,l.dist*.2)})};return t.colorMode==="mixed"?s.current.forEach((a,l)=>{a.targetColor=t.colors[l%t.colors.length],a.colorDelay=Math.max(0,a.dist*.2)+Math.random()*10}):(v.current=0,c(t.colors[0]),t.colors.length>1&&(d.current=setInterval(()=>{const a=t.colors;v.current=(v.current+1)%a.length,c(a[v.current])},3e3))),()=>{d.current&&clearInterval(d.current)}},[t.colors,t.color,t.colorMode]),f.useEffect(()=>{if(!n.current||!i.current)return;const c=i.current,a=n.current,l=b=>{for(const C of b){const{width:y,height:w}=C.contentRect,P=window.devicePixelRatio||1;c.width=y*P,c.height=w*P,c.style.width=`${y}px`,c.style.height=`${w}px`;const S=c.getContext("2d");S&&S.scale(P,P),s.current=[];const z=Math.floor(350*(h.current.density??1)),M=h.current.colors,D=h.current.colorMode||"wave";for(let x=0;x<z;x++){const p=Math.random()*Math.PI*2,X=Math.sqrt(Math.random())*350,Y=Math.cos(p)*X,L=Math.sin(p)*X;let F;if(M&&M.length>0)F=D==="mixed"?M[x%M.length]:M[0];else if(h.current.color)F=h.current.color;else{const $=260+Math.random()*60,k=70+Math.random()*30,O=60+Math.random()*20;F=`hsl(${$}, ${k}%, ${O}%)`}let W=2+Math.random()*2;X>200&&(W*=.6),X<80&&(W*=1.5);const A=new st(Y,L,F,W);A.x=y/2,A.y=w/2,s.current.push(A)}}},u=new ResizeObserver(l);u.observe(a);const R=c.getContext("2d");let E=0;const q=()=>{const b=a.getBoundingClientRect();R.globalCompositeOperation="source-over",e==="transparent"?R.clearRect(0,0,b.width,b.height):(R.fillStyle=e,R.fillRect(0,0,b.width,b.height)),o.current.initialized||(o.current.x=b.width/2,o.current.y=b.height/2,o.current.initialized=!0);let C=b.width/2,y=b.height/2;const w=r.current.active?r.current.x:null,P=r.current.active?r.current.y:null;w!==null&&P!==null&&(C=w,y=P);const S=C-o.current.x,I=y-o.current.y,z=Math.sqrt(S*S+I*I);let M=0,D=0;z>1?(M=S/z,D=I/z,o.current.angle=Math.atan2(D,M)):(M=Math.cos(o.current.angle),D=Math.sin(o.current.angle));const x=h.current.particleSpeed??1;E+=.02*x;const p=E%4;let X=1,Y=1,L=0;if(p<1){const O=p;X=1-Math.sin(O*Math.PI)*.3,Y=1+Math.sin(O*Math.PI)*.15,L=Math.sin(O*Math.PI)*12}else{const O=(p-1)/3;X=.7+.3*Math.sin(O*Math.PI/2),Y=1,L=0}const F=h.current.pointerTrackingSpeed??.02;o.current.x+=S*F,o.current.y+=I*F,o.current.x+=M*L*x,o.current.y+=D*L*x;const A=200*(Y+(p<1?p*.15:0)),$=R.createRadialGradient(o.current.x,o.current.y,0,o.current.x,o.current.y,A);$.addColorStop(0,"rgba(80, 150, 255, 0.05)"),$.addColorStop(1,"rgba(80, 150, 255, 0)"),R.fillStyle=$,R.beginPath(),R.arc(o.current.x,o.current.y,A,0,Math.PI*2),R.fill();const k=s.current;R.globalCompositeOperation="source-over";for(const O of k){O.update(o.current.x,o.current.y,E,X);const lt=h.current.shape||"circle";O.draw(R,lt,Y)}g.current=requestAnimationFrame(q)};return q(),()=>{u.disconnect(),cancelAnimationFrame(g.current)}},[e,t.density]),T.jsx("div",{ref:n,style:{position:"absolute",inset:0,zIndex:0,overflow:"hidden",pointerEvents:"none"},children:T.jsx("canvas",{ref:i,style:{display:"block",width:"100%",height:"100%",pointerEvents:"none"}})})}const it={position:"relative",border:"1px solid rgba(255, 255, 255, 0.1)",borderRadius:"1rem",overflow:"hidden",boxShadow:"0 25px 50px -12px rgba(0, 0, 0, 0.25)",transition:"all 300ms ease-out"};function j({children:t,width:e="100%",height:n="60vh",backgroundColor:i="#050505",className:s="",style:g,background:r={name:"NONE"}}){return T.jsxs("div",{className:s,style:{...it,width:e,height:n,backgroundColor:i,...g},children:[r.name==="FOLLOW_POINTER"&&T.jsx(et,{config:r,backgroundColor:i}),r.name==="NET"&&T.jsx(rt,{config:r,backgroundColor:i}),r.name==="JELLYFISH"&&T.jsx(ot,{config:r,backgroundColor:i}),T.jsx("div",{style:{position:"relative",zIndex:10,width:"100%",height:"100%"},children:t})]})}function H(t){const e=f.useRef({x:-1e3,y:-1e3,isDown:!1,active:!1});return f.useEffect(()=>{const n=t.current;if(!n)return;const i=o=>{const h=n.getBoundingClientRect();e.current.x=o.clientX-h.left,e.current.y=o.clientY-h.top,e.current.active=!0},s=()=>{e.current.active=!1},g=()=>{e.current.isDown=!0},r=()=>{e.current.isDown=!1};return n.addEventListener("pointermove",i),n.addEventListener("pointerleave",s),n.addEventListener("pointerdown",g),n.addEventListener("pointerup",r),n.style.touchAction="none",()=>{n.removeEventListener("pointermove",i),n.removeEventListener("pointerleave",s),n.removeEventListener("pointerdown",g),n.removeEventListener("pointerup",r)}},[t]),e}function J(t,e,n,i,s,g,r,o,h){if(s===null||g===null||!o&&h==="none")return{x:n,y:i};let v=n,d=i;const c=s-t,a=g-e,l=c*c+a*a,u=Math.sqrt(l);if(o&&!r&&l<3e4){const E=(3e4-l)/3e4;v+=c*E*.15,d+=a*E*.15}if(r&&h!=="none"){if(h==="attract"){if(l<3e4){const E=(3e4-l)/3e4;v+=c*E*.8,d+=a*E*.8}}else if(h==="repel"&&l<5e4&&u>0){const E=Math.pow(Math.max(0,5e4-l)/5e4,1.2);v-=c/u*E*400,d-=a/u*E*400}}return{x:v,y:d}}class G{constructor(e,n,i="255, 255, 255"){m(this,"x");m(this,"y");m(this,"vx");m(this,"vy");m(this,"targetX");m(this,"targetY");m(this,"baseColor");m(this,"opacity");m(this,"size");m(this,"sizeMultiplier");m(this,"friction");m(this,"ease");m(this,"easeMultiplier");m(this,"floatSpeed");m(this,"floatOffset");m(this,"randomSpeed");this.x=Math.random()*e,this.y=Math.random()*n,this.targetX=this.x,this.targetY=this.y,this.vx=0,this.vy=0,this.size=Math.random()*1.8+.5,this.sizeMultiplier=1,this.baseColor=Array.isArray(i)?i[Math.floor(Math.random()*i.length)]:i,this.opacity=.4+Math.random()*.6,this.friction=.82+Math.random()*.1,this.ease=.03+Math.random()*.05,this.easeMultiplier=1,this.floatSpeed=Math.random()*.02+.005,this.floatOffset=Math.random()*Math.PI*2,this.randomSpeed=Math.random()}update(e,n,i=null,s=null,g=!1,r=!0,o="none"){const{x:h,y:v}=J(this.x,this.y,this.targetX,this.targetY,i,s,g,r,o),d=h-this.x,c=v-this.y,a=n?0:Math.cos(e*.01+this.y*.01)*.5,l=n?0:Math.sin(e*.01+this.x*.01)*.5;this.vx+=d*(this.ease*this.easeMultiplier)+a,this.vy+=c*(this.ease*this.easeMultiplier)+l,this.vx*=this.friction,this.vy*=this.friction,this.x+=this.vx,this.y+=this.vy;const u=n?.2:2;this.x+=Math.cos(e*this.floatSpeed+this.floatOffset)*u,this.y+=Math.sin(e*this.floatSpeed+this.floatOffset)*u}draw(e,n="circle",i=0){e.fillStyle=`rgba(${this.baseColor}, ${this.opacity})`;const s=Math.max(.1,this.size*this.sizeMultiplier);if(n==="square")e.fillRect(this.x-s,this.y-s,s*2,s*2);else if(n==="bean"){const g=6+this.size*2*this.sizeMultiplier,r=Math.sin(i*.05+this.x*.01+this.randomSpeed*5),o=.4+.6*((r+1)/2),h=g*.5*o,v=Math.max(.8,s*1.5*(.8+.2*r)),d=this.vx!==0||this.vy!==0?Math.atan2(this.vy,this.vx):0;e.beginPath(),e.ellipse(this.x,this.y,h,v,d,0,Math.PI*2),e.fill()}else e.beginPath(),e.arc(this.x,this.y,s,0,Math.PI*2),e.fill()}}function K(t,e,n){if(e<=0||n<=0)return[];const i=document.createElement("canvas");i.width=e,i.height=n;const s=i.getContext("2d",{willReadFrequently:!0});if(!s)return[];s.clearRect(0,0,e,n);let g=Math.min(e,n)*.65;s.font=`bold ${g}px "Georgia", serif`;const r=s.measureText(t);r.width>e*.9&&(g=g*(e*.9)/r.width,s.font=`bold ${g}px "Georgia", serif`),s.fillStyle="white",s.textAlign="center",s.textBaseline="middle",s.fillText(t,e/2,n/2.05);const h=s.getImageData(0,0,e,n).data,v=[],d=window.innerWidth<600?6:8;for(let c=0;c<n;c+=d)for(let a=0;a<e;a+=d){const l=(c*e+a)*4;h[l+3]>128&&v.push({x:a+(Math.random()-.5)*4,y:c+(Math.random()-.5)*4})}return v}function _(t,e,n){const i=f.useRef(t);return f.useEffect(()=>{i.current=t},[t]),{getPixelsForText:K,updateTextTargets:(g,r,o)=>{var q,b;const h=r||((q=n.current)==null?void 0:q.offsetWidth)||window.innerWidth,v=o||((b=n.current)==null?void 0:b.offsetHeight)||window.innerHeight;if(!g){e.current.forEach(y=>{const w=50+Math.random()*(h-100),P=50+Math.random()*(v-100);(Math.abs(w-y.x)>20||Math.abs(P-y.y)>20)&&(y.vx+=(Math.random()-.5)*20,y.vy+=(Math.random()-.5)*20),y.targetX=w,y.targetY=P});return}const d=K(g,h,v);if(d.length===0)return;const c=h*.15,a=d.map(C=>({pt:C,key:C.x+(Math.random()-.5)*c}));a.sort((C,y)=>C.key-y.key);const l=a.map(C=>C.pt),u=e.current.map((C,y)=>({i:y,key:C.x+(Math.random()-.5)*c}));u.sort((C,y)=>C.key-y.key);const R=u.map(C=>C.i),E=Math.ceil(Math.sqrt(R.length));for(let C=0;C<R.length;C+=E){const y=Math.min(C+E,R.length),w=R.slice(C,y),P=[];for(let S=C;S<y;S++)P.push(l[S%l.length]);w.sort((S,I)=>e.current[S].y-e.current[I].y),P.sort((S,I)=>S.y-I.y);for(let S=0;S<w.length;S++){const I=w[S],z=e.current[I],M=P[S],D=M.x-z.x,x=M.y-z.y;if(Math.abs(D)>20||Math.abs(x)>20){z.vx+=(Math.random()-.5)*20,z.vy+=(Math.random()-.5)*20;const p=(Math.random()>.5?1:-1)*(Math.random()*10+5);z.vx+=Math.sign(x)*p,z.vy-=Math.sign(D)*p}z.targetX=M.x,z.targetY=M.y}}},textRef:i}}const N=t=>{if(!t||typeof t!="string")return"0, 0, 0";try{let e=0,n=0,i=0;if(t.length===4)e=parseInt(t[1]+t[1],16),n=parseInt(t[2]+t[2],16),i=parseInt(t[3]+t[3],16);else if(t.length===7)e=parseInt(t.substring(1,3),16),n=parseInt(t.substring(3,5),16),i=parseInt(t.substring(5,7),16);else return t;return`${e}, ${n}, ${i}`}catch{return"0, 0, 0"}};function ct({text:t,particleColor:e="255, 255, 255",particleSize:n=1,particleDensity:i=1,particleEase:s=1,isMagnet:g=!0,clickMode:r="none",particleShape:o="circle",backgroundColor:h="#050505"}){const v=f.useRef(null),d=f.useRef(null),c=f.useRef([]),a=f.useRef(0),l=f.useRef(0),u=H(d),R=f.useRef({isMagnet:g,clickMode:r,particleShape:o,backgroundColor:h});R.current={isMagnet:g,clickMode:r,particleShape:o,backgroundColor:h};const{updateTextTargets:E,textRef:q}=_(t,c,d),b=()=>Array.isArray(e)?e.map(y=>N(y)):N(e),C=(y,w,P=1)=>{const S=window.innerWidth<600?1500:3e3,I=Math.floor(S*P),z=[],M=b();for(let D=0;D<I;D++){const x=new G(y,w,M);x.sizeMultiplier=n,x.easeMultiplier=s,z.push(x)}c.current=z};return f.useEffect(()=>{if(c.current.length>0){const y=b();c.current.forEach(w=>{w.baseColor=Array.isArray(y)?y[Math.floor(Math.random()*y.length)]:y})}},[e]),f.useEffect(()=>{c.current.length>0&&c.current.forEach(y=>{y.sizeMultiplier=n})},[n]),f.useEffect(()=>{c.current.length>0&&c.current.forEach(y=>{y.easeMultiplier=s})},[s]),f.useEffect(()=>{if(c.current.length>0&&v.current&&d.current){const y=window.innerWidth<600?1500:3e3,w=Math.floor(y*i),P=c.current.length;if(w>P){const S=d.current.getBoundingClientRect(),I=b();for(let z=0;z<w-P;z++){const M=new G(S.width,S.height,I);M.sizeMultiplier=n,c.current.push(M)}E(t)}else w<P&&c.current.splice(w)}},[i]),f.useEffect(()=>{const y=d.current,w=v.current;if(!y||!w)return;const P=M=>{for(const D of M){const{width:x,height:p}=D.contentRect,X=window.devicePixelRatio||1;w.width=x*X,w.height=p*X,w.style.width=`${x}px`,w.style.height=`${p}px`;const Y=w.getContext("2d");Y&&Y.scale(X,X),c.current.length===0&&C(x,p,i),E(t,x,p)}},S=new ResizeObserver(P);S.observe(y);const I=w.getContext("2d"),z=()=>{l.current++;const M=y.getBoundingClientRect(),{isMagnet:D,clickMode:x,particleShape:p,backgroundColor:X}=R.current;if(X==="transparent")I.clearRect(0,0,M.width,M.height),I.globalCompositeOperation="source-over";else{const A=N(X);I.fillStyle=`rgba(${A}, 0.25)`,I.fillRect(0,0,M.width,M.height),I.globalCompositeOperation="screen"}const Y=q.current!=="",L=u.current.active?u.current.x:null,F=u.current.active?u.current.y:null,W=u.current.isDown;for(let A=0;A<c.current.length;A++){const $=c.current[A];$.update(l.current,!!Y,L,F,W,D,x),$.draw(I,p,l.current)}I.globalCompositeOperation="source-over",a.current=requestAnimationFrame(z)};return z(),()=>{S.disconnect(),cancelAnimationFrame(a.current)}},[]),f.useEffect(()=>{E(t)},[t]),T.jsx("div",{ref:d,style:{position:"absolute",inset:0,zIndex:0,overflow:"hidden"},children:T.jsx("canvas",{ref:v,style:{display:"block",width:"100%",height:"100%"}})})}function at({name:t,config:e,width:n="100%",height:i="60vh",backgroundColor:s="#050505",className:g="",style:r}){const o={name:t,...e};return T.jsx(j,{width:n,height:i,backgroundColor:s,className:g,style:r,background:o})}B.ParticleBackground=at,B.ParticleCanvas=j,B.TextParticleEngine=ct,B.getMagnetTarget=J,B.useParticleInteraction=H,B.useTextParticles=_,Object.defineProperty(B,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jl-particle-interactive",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "private": false,
5
5
  "description": "Canvas-based React library for particle text animations and interactive backgrounds — spring physics, magnetic hover, click attract/repel, NET/JELLYFISH modes. TypeScript. Zero dependencies.",
6
6
  "author": {