particle_text 0.0.2
particle_text: ^0.0.2 copied to clipboard
Interactive particle text and image effect for Flutter. Particles form text or image shapes and scatter on touch/hover, with spring-based physics and full customization.
particle_text #
Interactive particle text and image effect for Flutter. Particles form text or image shapes and scatter on touch/hover, with spring-based physics and full customization.
🔴 Live Demo #
Move your cursor or touch to scatter the particles!
Preview #
Features #
- Touch & hover interaction — particles scatter away from your finger/cursor
- Spring physics — smooth, natural particle reformation
- Image to particle — render any image as colored interactive particles
- Fully customizable — colors, particle count, physics, font, and more
- Built-in presets — cosmic, fire, matrix, pastel, minimal
- Zero dependencies — pure Flutter, no external packages
- Cross-platform — works on iOS, Android, Web, macOS, Windows, Linux
Getting started #
dependencies:
particle_text: ^0.0.2
Usage #
Basic #
import 'package:particle_text/particle_text.dart';
ParticleText(text:'Hello')
With configuration #
ParticleText(
text: 'Flutter',
config: ParticleConfig(
particleDensity: 2000,
particleColor: Color(0xFF8CAADE),
displacedColor: Color(0xFFDCE5FF),
backgroundColor: Color(0xFF020308),
mouseRadius: 80,
repelForce: 8.0,
returnSpeed: 0.04,
),
)
Using presets #
// Cosmic blue dust
ParticleText(text: 'Cosmic', config: ParticleConfig.cosmic())
// Fiery warm particles
ParticleText(text: 'Fire', config: ParticleConfig.fire())
// Neon green matrix
ParticleText(text: 'Matrix', config: ParticleConfig.matrix())
// Soft pastel glow
ParticleText(text: 'Pastel', config: ParticleConfig.pastel())
// Fewer, larger particles
ParticleText(text: 'Clean', config: ParticleConfig.minimal())
Dynamic text #
Simply update the text parameter and the particles will morph:
ParticleText(
text: _currentText, // change this and particles re-target
onTextChanged: () => print('Morphing!'),
)
Fixed size (non-expanding) #
By default, ParticleText expands to fill its parent. To use a fixed size:
SizedBox(
width: 400,
height: 300,
child: ParticleText(
text: 'Sized',
expand: false,
),
)
Inside Expanded #
Use ParticleText alongside other widgets in a Column or Row:
Column(
children: [
AppBar(title: Text('My App')),
Expanded(
child: ParticleText(text: 'Hello'),
),
BottomNavigationBar(...),
],
)
Image to Particles #
Convert & Render any image into interactive particles with per-pixel colors using ParticleImage:
// From a pre-loaded ui.Image
ParticleImage(
image: myUiImage,
config: ParticleConfig(particleDensity: 2500),
)
// From an asset
ParticleImage.asset(
'assets/logo.png',
config: ParticleConfig.cosmic(),
)
Each particle takes the color of its source pixel, creating a full-color particle representation that scatters on touch and reforms.
ParticleConfig options #
| Parameter | Type | Default | Description |
|---|---|---|---|
particleDensity |
double |
2000 |
Particles per 100k px² of screen area (responsive) |
particleCount |
int? |
null |
Fixed count — overrides density when set |
maxParticleCount |
int |
50000 |
Upper cap for density scaling |
minParticleCount |
int |
1000 |
Lower floor for density scaling |
mouseRadius |
double |
80.0 |
Pointer repulsion radius |
returnSpeed |
double |
0.04 |
Spring return speed (0.01–0.1) |
friction |
double |
0.88 |
Velocity damping (0.8–0.95) |
repelForce |
double |
8.0 |
Pointer repulsion strength |
backgroundColor |
Color |
#020308 |
Canvas background |
particleColor |
Color |
#8CAADE |
Particle color at rest |
displacedColor |
Color |
#DCE5FF |
Particle color when scattered |
pointerGlowColor |
Color |
#C8D2F0 |
Glow orb color |
minParticleSize |
double |
0.4 |
Min particle radius |
maxParticleSize |
double |
2.2 |
Max particle radius |
minAlpha |
double |
0.5 |
Min particle opacity |
maxAlpha |
double |
1.0 |
Max particle opacity |
sampleGap |
int |
2 |
Text pixel sampling density |
fontWeight |
FontWeight |
bold |
Text rendering weight |
fontFamily |
String? |
null |
Custom font family |
showPointerGlow |
bool |
true |
Show pointer glow orb |
pointerDotRadius |
double |
4.0 |
Center dot radius |
Responsive particle count #
By default, particle count scales automatically with screen size:
Mobile (360×800) → ~5,760 particles
Tablet (768×1024) → ~15,729 particles
Desktop (1920×1080) → ~41,472 particles
4K (3840×2160) → ~50,000 particles (capped)
To force a fixed count (ignores screen size):
ParticleConfig(particleCount: 6000) // always exactly 6000
How it works #
- Text is rendered off-screen using
TextPainterat device physical resolution - Opaque pixels are sampled to create target positions
- Particles are spawned and spring toward their targets
- Touch/hover applies a repulsion force that scatters particles
- Friction and spring forces bring particles back to form the text
- All particles rendered in a single GPU draw call via
drawRawAtlasfor maximum performance
Performance #
particle_text renders all particles in a single GPU draw call using Canvas.drawRawAtlas. This means 10,000+ particles run smoothly at 60fps — compared to traditional drawCircle-per-particle approaches that start lagging at 1,000.
Other optimizations include pre-allocated Float32List/Int32List render buffers (zero GC pressure), squared-distance checks (avoids sqrt in hot loops), ChangeNotifier-driven repainting (no setState, no widget tree rebuilds), and RepaintBoundary isolation.
License #
MIT License. See LICENSE for details.