animated_text_effects
A Flutter package for text with 45 composable animation effects and 4 animated counter widgets. Combine effects freely, control playback, and persist state across scroll off-screen.
✨ Features
- 45 effects — fade, wave, typewriter, fire, smoke, matrix rain, glitch, scramble, shake, tracking, glow reveal, kinetic type, split reveal, ink drops, and more
- Composable — apply multiple effects simultaneously (opacity multiplies, translation sums, last color wins)
- Loop modes — forward, ping-pong, or finite repeat counts
- External controller —
TextEffectControllerfor play/pause/stop/seek - Scroll persistence — animations survive scrolling off-screen via
keepAlive(defaulttrue) - Counter widgets —
AnimatedCounter,AnimatedPercentage,AnimatedCurrency,AnimatedStatCard,RollingDigitCounter - Sequence widgets —
AnimatedTextSequencefor sequential multi-text playback,AnimatedRichTextfor mixing static & animated text inline - Interactive demos — included in example app with real-time parameter controls
📋 Effects
📂 Entry & Reveal
Fade
AnimatedText(
'Hello World',
effects: const [FadeEffect()],
style: TextStyle(fontSize: 32),
)
Slide
AnimatedText(
'Hello World',
effects: const [SlideEffect()],
style: TextStyle(fontSize: 32),
)
Blur
AnimatedText(
'Hello World',
effects: const [BlurEffect()],
style: TextStyle(fontSize: 32),
)
Typewriter
AnimatedText(
'Hello World',
effects: const [TypewriterEffect()],
style: TextStyle(fontSize: 32),
)
Scatter
AnimatedText(
'Hello World',
effects: const [ScatterEffect()],
style: TextStyle(fontSize: 32),
)
Staggered Appear
AnimatedText(
'Hello World',
effects: const [StaggeredAppearEffect()],
style: TextStyle(fontSize: 32),
)
Random Reveal
AnimatedText(
'Hello World',
effects: const [RandomRevealEffect()],
style: TextStyle(fontSize: 32),
)
Reveal
AnimatedText(
'Hello World',
effects: const [RevealEffect()],
style: TextStyle(fontSize: 32),
)
Scramble
AnimatedText(
'Hello World',
effects: const [ScrambleEffect()],
style: TextStyle(fontSize: 32),
)
Pop In
AnimatedText(
'Hello World',
effects: const [PopInEffect()],
style: TextStyle(fontSize: 32),
)
Ripple
AnimatedText(
'Hello World',
effects: const [RippleEffect()],
style: TextStyle(fontSize: 32),
)
Elastic
AnimatedText(
'Hello World',
effects: const [ElasticEffect()],
style: TextStyle(fontSize: 32),
)
🎯 Motion & Energy
Wave
AnimatedText(
'Hello World',
effects: const [WaveEffect()],
style: TextStyle(fontSize: 32),
)
Bounce
AnimatedText(
'Hello World',
effects: const [BounceEffect()],
style: TextStyle(fontSize: 32),
)
Wiggle
AnimatedText(
'Hello World',
effects: const [WiggleEffect()],
style: TextStyle(fontSize: 32),
)
Shake
AnimatedText(
'Hello World',
effects: const [ShakeEffect()],
style: TextStyle(fontSize: 32),
)
Pulse
AnimatedText(
'Hello World',
effects: const [PulseEffect()],
style: TextStyle(fontSize: 32),
)
Spin
AnimatedText(
'Hello World',
effects: const [SpinEffect()],
style: TextStyle(fontSize: 32),
)
Flip
AnimatedText(
'Hello World',
effects: const [FlipEffect()],
style: TextStyle(fontSize: 32),
)
Flag Wave
AnimatedText(
'Hello World',
effects: const [FlagWaveEffect()],
style: TextStyle(fontSize: 32),
)
Liquid
AnimatedText(
'Hello World',
effects: const [LiquidEffect()],
style: TextStyle(fontSize: 32),
)
Conveyor Belt
AnimatedText(
'Hello World',
effects: const [ConveyorBeltEffect()],
style: TextStyle(fontSize: 32),
)
🌈 Color & Light
Gradient
AnimatedText(
'Hello World',
effects: const [GradientEffect()],
style: TextStyle(fontSize: 32),
)
Rainbow
AnimatedText(
'Hello World',
effects: const [RainbowEffect()],
style: TextStyle(fontSize: 32),
)
Glow
AnimatedText(
'Hello World',
effects: const [GlowEffect()],
style: TextStyle(fontSize: 32),
)
Shimmer
AnimatedText(
'Hello World',
effects: const [ShimmerEffect()],
style: TextStyle(fontSize: 32),
)
Wave Color
AnimatedText(
'Hello World',
effects: const [WaveColorEffect()],
style: TextStyle(fontSize: 32),
)
Breathing Opacity
AnimatedText(
'Hello World',
effects: const [BreathingOpacityEffect()],
style: TextStyle(fontSize: 32),
)
Glow Reveal
AnimatedText(
'Hello World',
effects: const [GlowRevealEffect()],
style: TextStyle(fontSize: 32),
)
Neon Flicker
AnimatedText(
'Hello World',
effects: const [NeonFlickerEffect()],
style: TextStyle(fontSize: 32),
)
Highlight
AnimatedText(
'Hello World',
effects: const [HighlightEffect()],
style: TextStyle(fontSize: 32),
)
Sparkle Twinkle
AnimatedText(
'Hello World',
effects: const [SparkleTwinkleEffect()],
style: TextStyle(fontSize: 32),
)
Scanner
AnimatedText(
'Hello World',
effects: const [ScannerEffect()],
style: TextStyle(fontSize: 32),
)
💥 VFX & Distortion
Fire
AnimatedText(
'Hello World',
effects: const [FireEffect()],
style: TextStyle(fontSize: 32),
)
Smoke
AnimatedText(
'Hello World',
effects: const [SmokeEffect()],
style: TextStyle(fontSize: 32),
)
VHS Glitch
AnimatedText(
'Hello World',
effects: const [VHSGlitchEffect()],
style: TextStyle(fontSize: 32),
)
Glitch Split
AnimatedText(
'Hello World',
effects: const [GlitchSplitEffect()],
style: TextStyle(fontSize: 32),
)
Matrix Rain
AnimatedText(
'Hello World',
effects: const [MatrixRainEffect()],
style: TextStyle(fontSize: 32),
)
Melt Drip
AnimatedText(
'Hello World',
effects: const [MeltDripEffect()],
style: TextStyle(fontSize: 32),
)
Kinetic Type
AnimatedText(
'Hello World',
effects: const [KineticTypeEffect()],
style: TextStyle(fontSize: 32),
)
Split Reveal
AnimatedText(
'Hello World',
effects: const [SplitRevealEffect()],
style: TextStyle(fontSize: 32),
)
Ink Drops
AnimatedText(
'Hello World',
effects: const [InkDropsEffect()],
style: TextStyle(fontSize: 32),
)
📏 Utility
Progress Text
AnimatedText(
'Hello World',
effects: const [ProgressTextEffect()],
style: TextStyle(fontSize: 32),
)
Tracking
AnimatedText(
'Hello World',
effects: const [TrackingEffect()],
style: TextStyle(fontSize: 32),
)
Underline
AnimatedText(
'Hello World',
effects: const [UnderlineEffect()],
style: TextStyle(fontSize: 32),
)
🔗 Sequence & Rich Text
AnimatedTextSequence
AnimatedTextSequence(
texts: [
SequenceText('Hello', effects: const [FadeEffect()]),
SequenceText('World', effects: const [WaveEffect()]),
SequenceText('!', effects: const [BounceEffect()]),
],
repeat: true,
displayDuration: Duration(seconds: 2),
transitionDuration: Duration(milliseconds: 600),
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
)
AnimatedRichText
AnimatedRichText(
segments: [
TextSegment.static('Static '),
TextSegment.animated('Animated!', effects: const [FadeEffect(), WaveEffect()]),
TextSegment.static(' suffix'),
],
repeat: true,
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
)
AnimatedCounter
AnimatedCounter(
value: 99999,
duration: Duration(seconds: 3),
style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
)
AnimatedPercentage
AnimatedPercentage(
value: 87.5,
decimals: 1,
style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
)
AnimatedCurrency
AnimatedCurrency(
value: 123456.78,
decimals: 2,
symbol: r'$',
style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
)
RollingDigitCounter
RollingDigitCounter(
value: 2026,
style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
)
AnimatedStatCard
AnimatedStatCard(
value: 8472,
label: 'Users',
icon: Icons.people,
activeColor: Colors.blue,
)
🚀 Getting started
Import
import 'package:animated_text_effects/animated_text_effects.dart';
📟 Counter widgets reference
AnimatedCounter
AnimatedCounter({
required num value,
Duration duration = 1000ms,
Curve curve = easeOut,
TextStyle? style,
int decimals = 0,
Color? activeColor,
bool scalePulse = false,
bool autoplay = true,
bool keepAlive = true,
String Function(num)? format,
})
AnimatedPercentage
AnimatedPercentage({
required num value,
int decimals = 1,
Duration duration = 1000ms,
Curve curve = easeOut,
TextStyle? style,
bool autoplay = true,
bool keepAlive = true,
Color? activeColor,
bool scalePulse = false,
bool showPercentSign = true,
})
AnimatedCurrency
AnimatedCurrency({
required num value,
int decimals = 2,
String symbol = r'$',
Duration duration = 1000ms,
Curve curve = easeOut,
TextStyle? style,
bool autoplay = true,
bool keepAlive = true,
Color? activeColor,
bool scalePulse = false,
bool showPlusSign = false,
})
AnimatedStatCard
AnimatedStatCard({
required num value,
required String label,
IconData? icon,
int decimals = 0,
Duration duration = 1000ms,
Curve curve = easeOut,
TextStyle? valueStyle,
TextStyle? labelStyle,
Color? activeColor,
bool scalePulse = false,
Color? cardColor,
double elevation = 2,
EdgeInsetsGeometry padding = EdgeInsets.all(20),
bool autoplay = true,
String Function(num)? format,
})
RollingDigitCounter
RollingDigitCounter({
required num value,
int decimals = 0,
Duration duration = 1000ms,
TextStyle? style,
bool autoplay = true,
bool keepAlive = true,
double digitWidth = 28,
double digitHeight = 40,
Color? backgroundColor,
})
🧩 AnimatedText widget API
| Parameter | Type | Default | Description |
|---|---|---|---|
text |
String |
— | Text to animate |
effects |
List<TextEffect> |
[] |
Effects to apply (order matters for color) |
controller |
TextEffectController? |
null |
External playback control |
style |
TextStyle? |
inherits | Text styling |
autoplay |
bool |
true |
Start animation automatically |
repeat |
bool |
false |
Loop infinitely |
reverse |
bool |
false |
Ping-pong (requires repeat: true) |
textAlign |
TextAlign |
start |
Text alignment |
textDirection |
TextDirection |
ltr |
Text direction |
keepAlive |
bool |
true |
Persist animation in scroll views |
🧩 CharacterAnimation properties
| Property | Type | Combined as | Description |
|---|---|---|---|
opacity |
double |
Multiplied | Character opacity |
translation |
Offset |
Summed | Displacement from origin |
scale |
double |
Multiplied | Uniform scale |
scaleX |
double |
Multiplied | Horizontal scale |
scaleY |
double |
Multiplied | Vertical scale |
color |
Color? |
Last non-null wins | Text color |
backgroundColor |
Color? |
Last non-null wins | Background behind character |
blurSigma |
double |
Summed | Gaussian blur |
rotation |
double |
Summed | 2D rotation (radians) |
rotationX |
double |
Summed | 3D X rotation (radians) |
rotationY |
double |
Summed | 3D Y rotation (radians) |
underlineProgress |
double |
Summed | Underline fill (0–1) |
clipProgress |
double |
Multiplied | Visible portion (0–1) |
🧪 Composing effects
| Property | Combination rule |
|---|---|
opacity |
Multiplied across effects |
translation |
Summed across effects |
scale, scaleX, scaleY |
Multiplied across effects |
color, backgroundColor |
Last non-null wins |
blurSigma, rotation, rotationX, rotationY, underlineProgress |
Summed across effects |
clipProgress |
Multiplied across effects |
🧩 Sequence widgets API
AnimatedTextSequence
| Parameter | Type | Default | Description |
|---|---|---|---|
texts |
List<SequenceText> |
— | Ordered list of text items to cycle through |
controller |
TextEffectController? |
null |
External playback control |
style |
TextStyle? |
inherits | Text styling (applied to all texts) |
autoplay |
bool |
true |
Start animation automatically |
repeat |
bool |
true |
Loop infinitely through the sequence |
displayDuration |
Duration |
3s |
How long each text is displayed |
transitionDuration |
Duration |
500ms |
Duration of the cross-fade between texts |
transitionEffect |
TextEffect? |
null |
Effect applied during transitions (null = plain cross-fade) |
textAlign |
TextAlign |
start |
Text alignment |
textDirection |
TextDirection |
ltr |
Text direction |
keepAlive |
bool |
true |
Persist animation in scroll views |
SequenceText
| Parameter | Type | Default | Description |
|---|---|---|---|
text |
String |
— | Text content for this item |
effects |
List<TextEffect> |
[] |
Effects to apply when this text is displayed |
style |
TextStyle? |
null |
Per-item text style override |
segments |
List<TextSegment>? |
null |
Fine-grained segment control (for mixed static/animated within one item) |
AnimatedRichText
| Parameter | Type | Default | Description |
|---|---|---|---|
segments |
List<TextSegment> |
— | Ordered list of static or animated text segments |
controller |
TextEffectController? |
null |
External playback control |
style |
TextStyle? |
inherits | Base text styling |
autoplay |
bool |
true |
Start animation automatically |
repeat |
bool |
false |
Loop infinitely |
reverse |
bool |
false |
Ping-pong (requires repeat: true) |
textAlign |
TextAlign |
start |
Text alignment |
textDirection |
TextDirection |
ltr |
Text direction |
keepAlive |
bool |
true |
Persist animation in scroll views |
TextSegment
| Constructor | Parameters | Description |
|---|---|---|
TextSegment.static(text) |
text |
Non-animated text segment |
TextSegment.animated(text, {effects}) |
text, effects |
Animated text segment with optional effects |
📐 Effect contract
All effects guarantee f(0) == f(1) — at progress=0 and progress=1 every character returns to its base state. This ensures seamless looping and predictable end states.
Noise-based effects (FireEffect, NeonFlickerEffect, VHSGlitchEffect, WiggleEffect, SparkleTwinkleEffect) wrap their output to enforce this contract.
Use noise(int index, [int offset]) on TextEffect for deterministic pseudo-random values per character:
final value = noise(index); // 0.0–1.0 per character
final value = noise(index, 42); // with offset for different noise streams
🔄 Scroll persistence
Animations survive scrolling off-screen by default (keepAlive: true). This uses AutomaticKeepAliveClientMixin under the hood.
For more advanced persistence across widget mount/unmount (e.g., conditional rendering), use TextEffectController which saves its progress internally on detach and restores on attach:
class MyWidget extends StatefulWidget {
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> with SingleTickerProviderStateMixin {
final controller = TextEffectController();
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
if (showText)
AnimatedText(
'Persistent text',
effects: const [FadeEffect(), WaveEffect()],
controller: controller,
),
],
);
}
}
🎮 Interactive demos
The example app includes two interactive demos reachable from the AppBar:
- Text — multi-effect checkboxes with per-effect parameter sliders (all 45 effects)
- Counters — all 5 counter types with global controls (value, decimals, duration, curve, color, scale pulse) and a reset button that recreates all widgets from scratch
- Sequence — interactive
AnimatedTextSequencewith per-text effect selection and transition effect picker - Comprehensive — tabbed demo (Static Text, Sequence, Mixed) with gap support, per-text effects, color, curve, and font size controls
- Cmp Counters — tabbed counter demo (Single, Dashboard, Mixed) with inline prefix/suffix text mixing
cd example
flutter run
🏗️ Architecture
lib/
├── animated_text_effects.dart # Barrel exports
├── core/
│ ├── text_effect.dart # Abstract base with noise() helper
│ ├── text_effect_controller.dart # Playback controller with attach/detach
│ ├── character_animation.dart # Per-character animation data
│ ├── animated_text.dart # Main AnimatedText widget
│ ├── text_segment.dart # Static or animated segment for AnimatedRichText
│ ├── sequence_text.dart # Text item with effects for AnimatedTextSequence
│ ├── animated_rich_text.dart # Inline static + animated text segments
│ ├── animated_text_sequence.dart # Sequential multi-text playback with transitions
│ └── animated_counter.dart # AnimatedCounter base widget
├── effects/ # 45 effect implementations
│ ├── fade_effect.dart
│ ├── gradient_effect.dart
│ ├── wave_effect.dart
│ ├── typewriter_effect.dart
│ ├── bounce_effect.dart
│ ├── shimmer_effect.dart
│ ├── slide_effect.dart
│ ├── blur_effect.dart
│ ├── rainbow_effect.dart
│ ├── glow_effect.dart
│ ├── ripple_effect.dart
│ ├── spin_effect.dart
│ ├── flip_effect.dart
│ ├── wiggle_effect.dart
│ ├── pulse_effect.dart
│ ├── scatter_effect.dart
│ ├── neon_flicker_effect.dart
│ ├── elastic_effect.dart
│ ├── highlight_effect.dart
│ ├── underline_effect.dart
│ ├── progress_text_effect.dart
│ ├── staggered_appear_effect.dart
│ ├── fire_effect.dart
│ ├── smoke_effect.dart
│ ├── vhs_glitch_effect.dart
│ ├── reveal_effect.dart
│ ├── liquid_effect.dart
│ ├── scanner_effect.dart
│ ├── wave_color_effect.dart
│ ├── breathing_opacity_effect.dart
│ ├── conveyor_belt_effect.dart
│ ├── melt_drip_effect.dart
│ ├── sparkle_twinkle_effect.dart
│ ├── matrix_rain_effect.dart
│ ├── scramble_effect.dart
│ ├── pop_in_effect.dart
│ ├── shake_effect.dart
│ ├── flag_wave_effect.dart
│ ├── tracking_effect.dart
│ ├── glow_reveal_effect.dart
│ ├── kinetic_type_effect.dart
│ ├── split_reveal_effect.dart
│ ├── ink_drops_effect.dart
│ └── random_reveal_effect.dart
│ └── glitch_split_effect.dart
└── counters/ # Counter widgets
├── animated_percentage.dart
├── animated_currency.dart
├── animated_stat_card.dart
└── rolling_digit_counter.dart
📄 License
MIT
Libraries
- animated_text_effects
- core/animated_counter
- core/animated_rich_text
- core/animated_text
- core/animated_text_sequence
- core/character_animation
- core/sequence_text
- core/text_effect
- core/text_effect_controller
- core/text_renderer
- core/text_segment
- counters/animated_currency
- counters/animated_percentage
- counters/animated_stat_card
- counters/rolling_digit_counter
- effects/blur_effect
- effects/bounce_effect
- effects/breathing_opacity_effect
- effects/conveyor_belt_effect
- effects/elastic_effect
- effects/fade_effect
- effects/fire_effect
- effects/flag_wave_effect
- effects/flip_effect
- effects/glitch_split_effect
- effects/glow_effect
- effects/glow_reveal_effect
- effects/gradient_effect
- effects/highlight_effect
- effects/ink_drops_effect
- effects/kinetic_type_effect
- effects/liquid_effect
- effects/matrix_rain_effect
- effects/melt_drip_effect
- effects/neon_flicker_effect
- effects/pop_in_effect
- effects/progress_text_effect
- effects/pulse_effect
- effects/rainbow_effect
- effects/random_reveal_effect
- effects/reveal_effect
- effects/ripple_effect
- effects/scanner_effect
- effects/scatter_effect
- effects/scramble_effect
- effects/shake_effect
- effects/shimmer_effect
- effects/slide_effect
- effects/smoke_effect
- effects/sparkle_twinkle_effect
- effects/spin_effect
- effects/split_reveal_effect
- effects/staggered_appear_effect
- effects/tracking_effect
- effects/typewriter_effect
- effects/underline_effect
- effects/vhs_glitch_effect
- effects/wave_color_effect
- effects/wave_effect
- effects/wiggle_effect