jl-particle-interactive 0.1.0 → 0.2.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 +236 -0
- package/dist/components/ParticleCanvas.d.ts +3 -1
- package/dist/components/background/BackgroundParticleEngine.d.ts +6 -0
- package/dist/components/background/FollowPointerParticle.d.ts +23 -0
- package/dist/components/background/JellyfishParticleEngine.d.ts +6 -0
- package/dist/components/background/NetParticleEngine.d.ts +6 -0
- package/dist/components/{Particle.d.ts → text/Particle.d.ts} +4 -2
- package/dist/components/{TextParticleEngine.d.ts → text/TextParticleEngine.d.ts} +3 -3
- package/dist/hooks/background/useParticleMovement.d.ts +5 -0
- package/dist/hooks/background/useParticleOrientation.d.ts +3 -0
- package/dist/hooks/background/useParticleScaling.d.ts +2 -0
- package/dist/hooks/background/usePointerTracking.d.ts +8 -0
- package/dist/hooks/{useTextParticles.d.ts → text/useTextParticles.d.ts} +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/jl-particle-interactive.js +700 -208
- package/dist/jl-particle-interactive.umd.cjs +1 -1
- package/dist/types/background.d.ts +16 -0
- package/dist/types.d.ts +1 -1
- package/package.json +31 -5
package/README.md
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# jl-particle-interactive — React Canvas Particle Animations
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/jl-particle-interactive)
|
|
4
|
+
[](https://www.npmjs.com/package/jl-particle-interactive)
|
|
5
|
+
[](https://bundlephobia.com/package/jl-particle-interactive)
|
|
6
|
+
[](https://github.com/cjorgeluis122333/jl-particles-interactive/blob/main/LICENSE)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
|
|
9
|
+
A canvas-based React library for rendering text and backgrounds as thousands of animated particles. Letters form from particle swarms, respond to magnetic hover, attract or repel on click, and backgrounds come alive with NET graphs, JELLYFISH glows, or pointer-following swarms. Built with zero runtime dependencies, full TypeScript support, and DPR-aware rendering for sharp output on retina displays.
|
|
10
|
+
|
|
11
|
+
> Requires React 18+. No global CSS. Zero runtime dependencies.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Why jl-particle-interactive?
|
|
16
|
+
|
|
17
|
+
| Feature | jl-particle-interactive | tsparticles | particles.js |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| **Text that forms from particles** | ✓ (native, spatial coherence) | Plugin only (complex setup) | ✗ |
|
|
20
|
+
| **Spring physics + float noise** | ✓ | ✗ | ✗ |
|
|
21
|
+
| **Magnetic hover / click interact** | ✓ (attract & repel) | ✗ | ✗ |
|
|
22
|
+
| **Ready-made background presets** | ✓ NET, JELLYFISH, FOLLOW_POINTER | General engine (DIY) | General engine (DIY) |
|
|
23
|
+
| **Runtime dependencies** | **Zero** | 14+ packages | 0 (vanilla JS only) |
|
|
24
|
+
| **React integration** | Native React hooks | Wrapper package needed | Manual integration |
|
|
25
|
+
| **TypeScript** | Strict mode | Partial | ✗ |
|
|
26
|
+
| **DPR-aware (retina)** | ✓ | ✗ | ✗ |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Use cases
|
|
31
|
+
|
|
32
|
+
- **Hero section animated titles** — Text materializes from particle chaos on page load
|
|
33
|
+
- **Loading screens** — Words form and dissolve while content loads
|
|
34
|
+
- **Interactive word carousels** — Cycle through words; particles re-form smoothly
|
|
35
|
+
- **Animated backgrounds** — NET graph, JELLYFISH glow, or pointer-following swarm behind any content
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install jl-particle-interactive
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Framework compatibility
|
|
48
|
+
|
|
49
|
+
| Framework | Supported |
|
|
50
|
+
|---|---|
|
|
51
|
+
| Vite + React | ✓ |
|
|
52
|
+
| Next.js (App Router & Pages) | ✓ (client components only — add `'use client'`) |
|
|
53
|
+
| Create React App | ✓ |
|
|
54
|
+
| Remix | ✓ (client-side only) |
|
|
55
|
+
| Astro | ✓ (inside `client:only` components) |
|
|
56
|
+
| TypeScript | ✓ (strict mode, declarations included) |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## What it offers
|
|
61
|
+
|
|
62
|
+
| Feature | Description |
|
|
63
|
+
|---|---|
|
|
64
|
+
| **Text particles** | Thousands of canvas particles that form any text string using pixel-sampling with spatial coherence — letters look sharp at any size |
|
|
65
|
+
| **Magnetic hover** | Particles are attracted to the cursor on hover (~173px radius spring force) |
|
|
66
|
+
| **Click interactions** | Attract or repel particles on click/tap — particles flee or swarm toward the pointer |
|
|
67
|
+
| **Animated backgrounds** | NET (connected node graph), JELLYFISH (organic glow rings), and FOLLOW_POINTER (swarm) modes |
|
|
68
|
+
| **Spring physics** | Each particle uses spring + friction + float-noise physics — movement feels natural, never robotic |
|
|
69
|
+
| **Customizable** | Colors (hex or RGB palettes), shapes (circle, square, bean), density, speed, ease, and more |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Quick start
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
import { ParticleCanvas, TextParticleEngine } from 'jl-particle-interactive';
|
|
77
|
+
|
|
78
|
+
export default function App() {
|
|
79
|
+
return (
|
|
80
|
+
<ParticleCanvas height="60vh">
|
|
81
|
+
<TextParticleEngine text="Hello" />
|
|
82
|
+
</ParticleCanvas>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Examples
|
|
90
|
+
|
|
91
|
+
### Text with a color palette
|
|
92
|
+
|
|
93
|
+
Assign multiple colors and each particle picks one at random.
|
|
94
|
+
|
|
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.
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
<ParticleCanvas height="60vh">
|
|
113
|
+
<TextParticleEngine
|
|
114
|
+
text="Boom"
|
|
115
|
+
clickMode="repel"
|
|
116
|
+
particleEase={2}
|
|
117
|
+
/>
|
|
118
|
+
</ParticleCanvas>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### Attract on click
|
|
124
|
+
|
|
125
|
+
The opposite — particles swarm toward the cursor on press.
|
|
126
|
+
|
|
127
|
+
```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.
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
<ParticleCanvas
|
|
145
|
+
height="80vh"
|
|
146
|
+
background={{
|
|
147
|
+
name: 'NET',
|
|
148
|
+
color: '#4ecdc4',
|
|
149
|
+
lineDistance: 120,
|
|
150
|
+
density: 0.8,
|
|
151
|
+
}}
|
|
152
|
+
>
|
|
153
|
+
<TextParticleEngine text="Network" particleColor="#ffffff" />
|
|
154
|
+
</ParticleCanvas>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
### Jellyfish background
|
|
160
|
+
|
|
161
|
+
Smooth, organic blobs that drift across the canvas.
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
<ParticleCanvas
|
|
165
|
+
height="80vh"
|
|
166
|
+
background={{
|
|
167
|
+
name: 'JELLYFISH',
|
|
168
|
+
colors: ['#ff6b6b', '#a29bfe', '#00cec9'],
|
|
169
|
+
colorMode: 'wave',
|
|
170
|
+
}}
|
|
171
|
+
>
|
|
172
|
+
<TextParticleEngine text="Fluid" particleColor="#ffffff" />
|
|
173
|
+
</ParticleCanvas>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
### Dynamic text
|
|
179
|
+
|
|
180
|
+
Change the `text` prop and the particles re-form automatically.
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
const words = ['Hello', 'World', 'React'];
|
|
184
|
+
|
|
185
|
+
export default function Carousel() {
|
|
186
|
+
const [index, setIndex] = useState(0);
|
|
187
|
+
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
const id = setInterval(() => setIndex(i => (i + 1) % words.length), 2000);
|
|
190
|
+
return () => clearInterval(id);
|
|
191
|
+
}, []);
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<ParticleCanvas height="60vh">
|
|
195
|
+
<TextParticleEngine text={words[index]} />
|
|
196
|
+
</ParticleCanvas>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## API reference
|
|
204
|
+
|
|
205
|
+
### `<ParticleCanvas>`
|
|
206
|
+
|
|
207
|
+
| Prop | Type | Default | Description |
|
|
208
|
+
|---|---|---|---|
|
|
209
|
+
| `width` | `string \| number` | `'100%'` | Container width |
|
|
210
|
+
| `height` | `string \| number` | `'60vh'` | Container height |
|
|
211
|
+
| `backgroundColor` | `string` | `'#050505'` | Background color |
|
|
212
|
+
| `background` | `BackgroundCanvas` | `{ name: 'NONE' }` | Animated background config |
|
|
213
|
+
| `className` | `string` | `''` | Additional CSS class |
|
|
214
|
+
| `style` | `CSSProperties` | — | Inline style overrides |
|
|
215
|
+
|
|
216
|
+
### `<TextParticleEngine>`
|
|
217
|
+
|
|
218
|
+
| Prop | Type | Default | Description |
|
|
219
|
+
|---|---|---|---|
|
|
220
|
+
| `text` | `string` | **required** | Text the particles form |
|
|
221
|
+
| `particleColor` | `string \| string[]` | `'255, 255, 255'` | RGB string or array of hex colors |
|
|
222
|
+
| `particleSize` | `number` | `1` | Size multiplier |
|
|
223
|
+
| `particleDensity` | `number` | `1` | Particle count multiplier |
|
|
224
|
+
| `particleEase` | `number` | `1` | Return speed multiplier |
|
|
225
|
+
| `isMagnet` | `boolean` | `true` | Hover attraction effect |
|
|
226
|
+
| `clickMode` | `'none' \| 'attract' \| 'repel'` | `'none'` | Click/tap interaction |
|
|
227
|
+
| `particleShape` | `'circle' \| 'square' \| 'bean'` | `'circle'` | Particle shape |
|
|
228
|
+
| `backgroundColor` | `string` | `'#050505'` | Canvas background (hex) |
|
|
229
|
+
|
|
230
|
+
> **Color note:** `particleColor` accepts `'R, G, B'` strings (e.g. `'255, 100, 50'`) or hex strings in an array (e.g. `['#ff0000', '#00ff00']`). Alpha is handled internally.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## License
|
|
235
|
+
|
|
236
|
+
MIT
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ReactNode, CSSProperties } from 'react';
|
|
2
|
+
import { BackgroundCanvas } from '../types/background';
|
|
2
3
|
export interface ParticleCanvasProps {
|
|
3
4
|
children?: ReactNode;
|
|
4
5
|
width?: string | number;
|
|
@@ -6,5 +7,6 @@ export interface ParticleCanvasProps {
|
|
|
6
7
|
backgroundColor?: string;
|
|
7
8
|
className?: string;
|
|
8
9
|
style?: CSSProperties;
|
|
10
|
+
background?: BackgroundCanvas;
|
|
9
11
|
}
|
|
10
|
-
export default function ParticleCanvas({ children, width, height, backgroundColor, className, style, }: ParticleCanvasProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export default function ParticleCanvas({ children, width, height, backgroundColor, className, style, background, }: ParticleCanvasProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { BackgroundCanvas } from '../../types/background';
|
|
2
|
+
export interface BackgroundParticleEngineProps {
|
|
3
|
+
config: BackgroundCanvas;
|
|
4
|
+
backgroundColor: string;
|
|
5
|
+
}
|
|
6
|
+
export default function BackgroundParticleEngine({ config, backgroundColor }: BackgroundParticleEngineProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ParticleOrientation } from '../../types/background';
|
|
2
|
+
export declare class FollowPointerParticle {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
baseX: number;
|
|
6
|
+
baseY: number;
|
|
7
|
+
z: number;
|
|
8
|
+
vx: number;
|
|
9
|
+
vy: number;
|
|
10
|
+
color: string;
|
|
11
|
+
targetColor: string | null;
|
|
12
|
+
colorDelay: number;
|
|
13
|
+
angleTarget: number;
|
|
14
|
+
randomSpeed: number;
|
|
15
|
+
sizeBias: number;
|
|
16
|
+
scale: number;
|
|
17
|
+
dirX: number;
|
|
18
|
+
dirY: number;
|
|
19
|
+
initialized: boolean;
|
|
20
|
+
constructor(relX: number, relY: number, color: string);
|
|
21
|
+
update(mouseX: number | null, mouseY: number | null, swarmX: number, swarmY: number, screenW: number, screenH: number, time: number, orientation?: ParticleOrientation): void;
|
|
22
|
+
draw(ctx: CanvasRenderingContext2D, time: number, shape?: 'circle' | 'square' | 'bean'): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { BackgroundCanvas } from '../../types/background';
|
|
2
|
+
export interface JellyfishParticleEngineProps {
|
|
3
|
+
config: BackgroundCanvas;
|
|
4
|
+
backgroundColor: string;
|
|
5
|
+
}
|
|
6
|
+
export default function JellyfishParticleEngine({ config, backgroundColor }: JellyfishParticleEngineProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { BackgroundCanvas } from '../../types/background';
|
|
2
|
+
export interface NetParticleEngineProps {
|
|
3
|
+
config: BackgroundCanvas;
|
|
4
|
+
backgroundColor: string;
|
|
5
|
+
}
|
|
6
|
+
export default function NetParticleEngine({ config, backgroundColor }: NetParticleEngineProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ClickMode } from '
|
|
1
|
+
import { ClickMode } from '../../hooks/useParticleInteraction';
|
|
2
|
+
import { ParticleShape } from '../../types';
|
|
2
3
|
export declare class Particle {
|
|
3
4
|
x: number;
|
|
4
5
|
y: number;
|
|
@@ -15,7 +16,8 @@ export declare class Particle {
|
|
|
15
16
|
easeMultiplier: number;
|
|
16
17
|
floatSpeed: number;
|
|
17
18
|
floatOffset: number;
|
|
19
|
+
randomSpeed: number;
|
|
18
20
|
constructor(w: number, h: number, color?: string | string[]);
|
|
19
21
|
update(time: number, isActive: boolean, mx?: number | null, my?: number | null, isMouseDown?: boolean, isMagnet?: boolean, clickMode?: ClickMode): void;
|
|
20
|
-
draw(ctx: CanvasRenderingContext2D, shape?:
|
|
22
|
+
draw(ctx: CanvasRenderingContext2D, shape?: ParticleShape, time?: number): void;
|
|
21
23
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ClickMode } from '
|
|
2
|
-
import { ParticleShape } from '
|
|
1
|
+
import { ClickMode } from '../../hooks/useParticleInteraction';
|
|
2
|
+
import { ParticleShape } from '../../types';
|
|
3
3
|
export interface TextParticleEngineProps {
|
|
4
4
|
text: string;
|
|
5
5
|
particleColor?: string | string[];
|
|
@@ -11,4 +11,4 @@ export interface TextParticleEngineProps {
|
|
|
11
11
|
particleShape?: ParticleShape;
|
|
12
12
|
backgroundColor?: string;
|
|
13
13
|
}
|
|
14
|
-
export default function TextParticleEngine({ text, particleColor, particleSize, particleDensity, particleEase, isMagnet, clickMode, particleShape, backgroundColor }: TextParticleEngineProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export default function TextParticleEngine({ text, particleColor, particleSize, particleDensity, particleEase, isMagnet, clickMode, particleShape, backgroundColor, }: TextParticleEngineProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { FollowPointerParticle } from '../../components/background/FollowPointerParticle';
|
|
2
|
+
import { ParticleOrientation } from '../../types/background';
|
|
3
|
+
export declare function useParticleOrientation(particle: FollowPointerParticle, dxCenter: number, dyCenter: number, distToCenter: number, orientation: ParticleOrientation, time: number): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FollowPointerParticle } from '../../components/background/FollowPointerParticle';
|
|
2
|
+
export declare function usePointerTracking(particle: FollowPointerParticle, mouseX: number | null, mouseY: number | null, swarmX: number, swarmY: number, time: number): {
|
|
3
|
+
forceX: number;
|
|
4
|
+
forceY: number;
|
|
5
|
+
dxCenter: number;
|
|
6
|
+
dyCenter: number;
|
|
7
|
+
distToCenter: number;
|
|
8
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { default as ParticleCanvas } from './components/ParticleCanvas';
|
|
2
2
|
export type { ParticleCanvasProps } from './components/ParticleCanvas';
|
|
3
|
-
export { default as TextParticleEngine } from './components/TextParticleEngine';
|
|
4
|
-
export type { TextParticleEngineProps } from './components/TextParticleEngine';
|
|
3
|
+
export { default as TextParticleEngine } from './components/text/TextParticleEngine';
|
|
4
|
+
export type { TextParticleEngineProps } from './components/text/TextParticleEngine';
|
|
5
5
|
export { useParticleInteraction, getMagnetTarget } from './hooks/useParticleInteraction';
|
|
6
6
|
export type { ClickMode } from './hooks/useParticleInteraction';
|
|
7
|
-
export { useTextParticles } from './hooks/useTextParticles';
|
|
7
|
+
export { useTextParticles } from './hooks/text/useTextParticles';
|
|
8
8
|
export type { ParticleShape, ColorMode } from './types';
|
|
9
|
+
export type { BackgroundModeName, BackgroundCanvas, ParticleOrientation } from './types/background';
|