jl-particle-interactive
v0.2.2
Published
Canvas-based React library for particle text animations and interactive backgrounds — spring physics, magnetic hover, click attract/repel, NET/JELLYFISH modes. TypeScript. Zero dependencies.
Maintainers
Readme
jl-particle-interactive — React Canvas Particle Animations
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.
Requires React 18+. No global CSS. Zero runtime dependencies.
Why jl-particle-interactive?
| Feature | jl-particle-interactive | tsparticles | particles.js | |---|---|---|---| | Text that forms from particles | ✓ (native, spatial coherence) | Plugin only (complex setup) | ✗ | | Spring physics + float noise | ✓ | ✗ | ✗ | | Magnetic hover / click interact | ✓ (attract & repel) | ✗ | ✗ | | Ready-made background presets | ✓ NET, JELLYFISH, FOLLOW_POINTER | General engine (DIY) | General engine (DIY) | | Runtime dependencies | Zero | 14+ packages | 0 (vanilla JS only) | | React integration | Native React hooks | Wrapper package needed | Manual integration | | TypeScript | Strict mode | Partial | ✗ | | DPR-aware (retina) | ✓ | ✗ | ✗ |
Use cases
- Hero section animated titles — Text materializes from particle chaos on page load
- Loading screens — Words form and dissolve while content loads
- Interactive word carousels — Cycle through words; particles re-form smoothly
- Animated backgrounds — NET graph, JELLYFISH glow, or pointer-following swarm behind any content
Installation
npm install jl-particle-interactiveFramework compatibility
| Framework | Supported |
|---|---|
| Vite + React | ✓ |
| Next.js (App Router & Pages) | ✓ (client components only — add 'use client') |
| Create React App | ✓ |
| Remix | ✓ (client-side only) |
| Astro | ✓ (inside client:only components) |
| TypeScript | ✓ (strict mode, declarations included) |
What it offers
| Feature | Description | |---|---| | Text particles | Thousands of canvas particles that form any text string using pixel-sampling with spatial coherence — letters look sharp at any size | | Magnetic hover | Particles are attracted to the cursor on hover (~173px radius spring force) | | Click interactions | Attract or repel particles on click/tap — particles flee or swarm toward the pointer | | Animated backgrounds | NET (connected node graph), JELLYFISH (organic glow rings), and FOLLOW_POINTER (swarm) modes | | Spring physics | Each particle uses spring + friction + float-noise physics — movement feels natural, never robotic | | Customizable | Colors (hex or RGB palettes), shapes (circle, square, bean), density, speed, ease, and more |
Quick start
import { ParticleCanvas, TextParticleEngine } from 'jl-particle-interactive';
export default function App() {
return (
<ParticleCanvas height="60vh">
<TextParticleEngine text="Hello" />
</ParticleCanvas>
);
}Examples
Text with a color palette
Assign multiple colors and each particle picks one at random.
<ParticleCanvas height="60vh">
<TextParticleEngine
text="React"
particleColor={['#ff6b6b', '#feca57', '#48dbfb']}
particleSize={1.5}
/>
</ParticleCanvas>Repel on click
Particles flee from the cursor while the mouse button is held down.
<ParticleCanvas height="60vh">
<TextParticleEngine
text="Boom"
clickMode="repel"
particleEase={2}
/>
</ParticleCanvas>Attract on click
The opposite — particles swarm toward the cursor on press.
<ParticleCanvas height="60vh">
<TextParticleEngine
text="Pull"
clickMode="attract"
isMagnet={false}
/>
</ParticleCanvas>Animated NET background
A connected particle network moves behind your content.
<ParticleCanvas
height="80vh"
background={{
name: 'NET',
color: '#4ecdc4',
density: 0.8,
}}
>
<TextParticleEngine text="Network" particleColor="#ffffff" />
</ParticleCanvas>Jellyfish background
Smooth, organic blobs that drift across the canvas.
<ParticleCanvas
height="80vh"
background={{
name: 'JELLYFISH',
colors: ['#ff6b6b', '#a29bfe', '#00cec9'],
colorMode: 'wave',
}}
>
<TextParticleEngine text="Fluid" particleColor="#ffffff" />
</ParticleCanvas>Dynamic text
Change the text prop and the particles re-form automatically.
const words = ['Hello', 'World', 'React'];
export default function Carousel() {
const [index, setIndex] = useState(0);
useEffect(() => {
const id = setInterval(() => setIndex(i => (i + 1) % words.length), 2000);
return () => clearInterval(id);
}, []);
return (
<ParticleCanvas height="60vh">
<TextParticleEngine text={words[index]} />
</ParticleCanvas>
);
}Background guide
The background prop on ParticleCanvas supports four usage patterns:
- No animated background
FOLLOW_POINTERswarm backgroundNETnode-link graph backgroundJELLYFISHorganic glow/swim background
1) No background engine
Use this when you only want text particles.
<ParticleCanvas background={{ name: 'NONE' }}>
<TextParticleEngine text="Only Text" />
</ParticleCanvas>2) FOLLOW_POINTER background
Particles form a swarm that follows the cursor smoothly.
<ParticleCanvas
background={{
name: 'FOLLOW_POINTER',
orientation: 'diagonal',
density: 1,
shape: 'bean',
colors: ['#00d4ff', '#6ee7b7', '#facc15'],
colorMode: 'wave',
particleSpeed: 1,
pointerTrackingSpeed: 0.06,
}}
>
<TextParticleEngine text="Follow" particleColor="255, 255, 255" />
</ParticleCanvas>3) NET background
Moving nodes connect with lines. Great for tech-style hero sections.
<ParticleCanvas
background={{
name: 'NET',
density: 0.9,
shape: 'circle',
colors: ['#7dd3fc', '#60a5fa'],
colorMode: 'mixed',
particleSpeed: 1,
pointerTrackingSpeed: 0.08,
}}
>
<TextParticleEngine text="Network" particleColor="255, 255, 255" />
</ParticleCanvas>4) JELLYFISH background
Soft organic particle body with pulse/swimming motion.
<ParticleCanvas
background={{
name: 'JELLYFISH',
density: 1.1,
shape: 'bean',
colors: ['#f472b6', '#a78bfa', '#22d3ee'],
colorMode: 'wave',
particleSpeed: 1,
pointerTrackingSpeed: 0.02,
}}
>
<TextParticleEngine text="Jelly" particleColor="255, 255, 255" />
</ParticleCanvas>Background with transparent stage
Use backgroundColor="transparent" to place particles over your own image/gradient layer.
<div style={{ background: 'linear-gradient(135deg, #0f172a, #111827)' }}>
<ParticleCanvas
height="70vh"
backgroundColor="transparent"
background={{ name: 'NET', density: 0.7, color: '#67e8f9' }}
>
<TextParticleEngine text="Overlay" backgroundColor="transparent" />
</ParticleCanvas>
</div>Full BackgroundCanvas type
type BackgroundModeName = 'NONE' | 'FOLLOW_POINTER' | 'NET' | 'JELLYFISH';
type ParticleOrientation = 'vertical' | 'horizontal' | 'diagonal';
interface BackgroundCanvas {
name: BackgroundModeName;
orientation?: ParticleOrientation;
density?: number;
color?: string;
colors?: string[];
colorMode?: 'wave' | 'mixed';
interactionRadius?: number;
lineDistance?: number;
shape?: 'circle' | 'square' | 'bean';
particleSpeed?: number;
pointerTrackingSpeed?: number;
}Option matrix (what applies to each mode)
| Option | FOLLOW_POINTER | NET | JELLYFISH | Notes |
|---|---|---|---|---|
| name | ✓ | ✓ | ✓ | Mode selector |
| density | ✓ | ✓ | ✓ | Particle count multiplier |
| color | ✓ | ✓ | ✓ | Single hex/HSL/CSS color |
| colors | ✓ | ✓ | ✓ | Palette override |
| colorMode | ✓ | ✓ | ✓ | wave (default) or mixed |
| shape | ✓ | ✓ | ✓ | bean default in FOLLOW_POINTER, circle in NET/JELLYFISH |
| particleSpeed | ✓ | ✓ | ✓ | Animation speed multiplier |
| pointerTrackingSpeed | ✓ | ✓ | ✓ | Cursor-follow/response smoothness |
| orientation | ✓ | — | — | Only FOLLOW_POINTER (vertical default) |
| interactionRadius | — | — | — | Declared in type, currently not applied in v0.2.1 |
| lineDistance | — | — | — | Declared in type, currently not applied in v0.2.1 |
Practical presets
| Goal | Suggested config |
|---|---|
| Calm ambient hero | JELLYFISH, density: 0.8, pointerTrackingSpeed: 0.015 |
| High-energy interactive background | FOLLOW_POINTER, density: 1.2, particleSpeed: 1.3, shape: 'bean' |
| Tech/network look | NET, density: 0.9, colorMode: 'mixed', cool blue palette |
API reference
<ParticleCanvas>
| Prop | Type | Default | Description |
|---|---|---|---|
| width | string \| number | '100%' | Container width |
| height | string \| number | '60vh' | Container height |
| backgroundColor | string | '#050505' | Background color |
| background | BackgroundCanvas | { name: 'NONE' } | Animated background config |
| className | string | '' | Additional CSS class |
| style | CSSProperties | — | Inline style overrides |
BackgroundCanvas
| Prop | Type | Description |
|---|---|---|
| name | 'NONE' \| 'FOLLOW_POINTER' \| 'NET' \| 'JELLYFISH' | Background mode |
| orientation | 'vertical' \| 'horizontal' \| 'diagonal' | Direction style for FOLLOW_POINTER |
| density | number | Particle amount multiplier |
| color | string | Single background particle color |
| colors | string[] | Background particle palette |
| colorMode | 'wave' \| 'mixed' | Palette propagation mode |
| shape | 'circle' \| 'square' \| 'bean' | Particle drawing shape |
| particleSpeed | number | Background animation speed multiplier |
| pointerTrackingSpeed | number | Cursor tracking interpolation factor |
| interactionRadius | number | Reserved in type (not applied in v0.2.1) |
| lineDistance | number | Reserved in type (not applied in v0.2.1) |
<TextParticleEngine>
| Prop | Type | Default | Description |
|---|---|---|---|
| text | string | required | Text the particles form |
| particleColor | string \| string[] | '255, 255, 255' | RGB string or array of hex colors |
| particleSize | number | 1 | Size multiplier |
| particleDensity | number | 1 | Particle count multiplier |
| particleEase | number | 1 | Return speed multiplier |
| isMagnet | boolean | true | Hover attraction effect |
| clickMode | 'none' \| 'attract' \| 'repel' | 'none' | Click/tap interaction |
| particleShape | 'circle' \| 'square' \| 'bean' | 'circle' | Particle shape |
| backgroundColor | string | '#050505' | Canvas background (hex) |
Color note:
particleColoraccepts'R, G, B'strings (e.g.'255, 100, 50') or hex strings in an array (e.g.['#ff0000', '#00ff00']). Alpha is handled internally.
License
MIT
