Aisling
Embeddable terminal text effects and loader animations for Rust TUI applications.
Aisling renders animated text effects, spinners, and progress loaders as plain Rust data. It does not own your terminal, start an event loop, sleep, or print unless you run the included examples. Your app drives the iterator or asks for the current loader frame and maps each styled Frame into Ratatui, Crossterm, ANSI output, tests, logs, or any custom renderer.
The effect catalog is ported from the Python terminaltexteffects project shape and includes every built-in reference effect exposed by the current snapshot.
Install
After publishing:
Or in Cargo.toml:
[]
= "0.1"
For local development from this repository:
[]
= { = "../aisling" }
Quick Start
use ;
let config = default
.with_duration
.with_seed;
let effect = with_config;
for frame in effect.iter
Progress loaders are also frame-based:
use ;
let loader = with_config;
let downloaded = 42;
let total = 100;
let frame = loader.frame;
let line = loader.line;
TUI Integration
Effect::iter() yields Frame values. A Frame is a fixed-size grid with row-major Cell data.
Important types:
| Type | Purpose |
|---|---|
Effect |
Owns the effect kind, input text, and config. |
EffectKind |
Selects one of the built-in effects. |
EffectConfig |
Controls duration, seed, gradient, canvas size, color handling, and more. |
Loader |
Owns a loader kind and config; render with the current tick and progress. |
LoaderKind |
Selects a built-in spinner/progress/download animation. |
LoaderConfig |
Controls loader width, height, label, units, colors, and duration. |
LoaderProgress |
Carries a progress fraction or current/total counters. |
Frame |
Rendered 2D grid for a single animation tick. |
Cell |
Character plus foreground/background colors and simple styles. |
Color, Gradient, Easing |
Color and timing helpers. |
Minimal renderer loop shape:
use ;
let effect = new;
for frame in effect.iter
Loaders
Loaders are for status lines, downloads, installs, background tasks, and tqdm-style progress indicators. Unlike text effects, real app progress usually comes from your own IO loop, so call Loader::frame(tick, progress) whenever your UI redraws.
use ;
let loader = new;
let tick = 12;
let frame = loader.frame;
Built-in loaders:
bar, tqdm, blocks, meter, battery, gauge, dots, pulse, line, bounce,
scanner, snake, pong, marquee, steps, download, upload, equalizer,
wave, matrix, spark, orbit, brackets, crawl, braided, burn, decrypt,
rain, thunderstorm, laseretch, vhstape, blackhole, fireworks, pour,
synthgrid, beams, smoke, binarypath, bouncyballs, bubbles, colorshift,
crumble, errorcorrect, expand, highlight, middleout, orbittingvolley,
overflow, print, randomsequence, rings, scattered, slice, slide,
spotlights, spray, swarm, sweep, unstable, waves, wipe
The effect-inspired loaders use the same Frame/Cell model but are designed for long-running tasks: burn smolders across the progress line, decrypt cascades cipher characters downward into the status, laseretch scans a hot beam, rings orbits around the transfer cursor, swarm throws particles around the active edge, and thunderstorm layers rain with lightning.
For quick plain-line output, use Loader::line(tick, progress). For TUI rendering, use Loader::frame(tick, progress) and map its cells into your buffer.
Effects
All built-in effects are available through EffectKind and EffectKind::all().
| Command | Enum |
|---|---|
beams |
EffectKind::Beams |
binarypath |
EffectKind::BinaryPath |
blackhole |
EffectKind::Blackhole |
bouncyballs |
EffectKind::BouncyBalls |
bubbles |
EffectKind::Bubbles |
burn |
EffectKind::Burn |
colorshift |
EffectKind::ColorShift |
crumble |
EffectKind::Crumble |
decrypt |
EffectKind::Decrypt |
errorcorrect |
EffectKind::ErrorCorrect |
expand |
EffectKind::Expand |
fireworks |
EffectKind::Fireworks |
highlight |
EffectKind::Highlight |
laseretch |
EffectKind::LaserEtch |
matrix |
EffectKind::Matrix |
middleout |
EffectKind::MiddleOut |
orbittingvolley |
EffectKind::OrbittingVolley |
overflow |
EffectKind::Overflow |
pour |
EffectKind::Pour |
print |
EffectKind::Print |
rain |
EffectKind::Rain |
randomsequence |
EffectKind::RandomSequence |
rings |
EffectKind::Rings |
scattered |
EffectKind::Scattered |
slice |
EffectKind::Slice |
slide |
EffectKind::Slide |
smoke |
EffectKind::Smoke |
spotlights |
EffectKind::Spotlights |
spray |
EffectKind::Spray |
swarm |
EffectKind::Swarm |
sweep |
EffectKind::Sweep |
synthgrid |
EffectKind::SynthGrid |
thunderstorm |
EffectKind::Thunderstorm |
unstable |
EffectKind::Unstable |
vhstape |
EffectKind::VhsTape |
waves |
EffectKind::Waves |
wipe |
EffectKind::Wipe |
String parsing is supported:
use FromStr;
use EffectKind;
let kind = from_str.unwrap;
assert_eq!;
Configuration
use ;
let config = default
.with_duration
.with_seed
.with_canvas_size
.with_gradient;
Notable EffectConfig fields:
| Field | Meaning |
|---|---|
duration |
Number of animation frames. |
hold_final_frames |
Extra frames that hold the final text. |
seed |
Deterministic random seed for repeatable playback. |
gradient |
Final/effect color gradient. |
gradient_direction |
Horizontal, vertical, diagonal, or radial mapping. |
easing |
Global easing used by many effect renderers. |
existing_color_handling |
Preserve or ignore parsed ANSI input colors. |
no_color |
Disable color output. |
canvas_width, canvas_height |
Optional fixed frame dimensions. |
tab_width |
Spaces per tab when parsing input text. |
ANSI Input
Aisling parses common ANSI SGR sequences in input text, including foreground/background 3-bit, bright 3-bit, 8-bit xterm, and 24-bit RGB colors. Parsed styling is kept in each final Cell when the color-handling mode allows it.
use ;
let effect = new;
let final_frame = effect.final_frame;
assert_eq!;
Examples
Run a single effect in the terminal:
Use the helper script while developing locally:
Run the multi-pane all-effects showcase:
The showcase defaults to a curated high-contrast palette and a masonry pane layout. Wider/taller effects such as matrix, blackhole, rain, thunderstorm, and vhstape receive larger panes when the terminal has room. Use --rainbow for the original full-spectrum theme or --industrial for a steel/amber palette.
test.sh launches the showcase with a longer embedded text sample:
./run.sh loaders and ./test.sh -loaders show the full loader catalog in a grid so the loader styles can be compared at once. The test.sh -loaders path defaults to slower playback.
loaders.sh runs the full loader command deck. It keeps every loader visible in a catalog strip, gives one loader a large story-style focus pane, keeps six surrounding live mock transfer lanes running at different speeds, and supports arrow-key focus changes in a real terminal.
story.sh runs a full TUI-style Knott Dynamics narrative demo. It uses the embedded text from test.sh, then composes matrix, burn, thunderstorm, laser etch, rings, swarm, fireworks, fake downloads, and exotic loaders into one animated dashboard.
Package Verification
Before publishing:
Publish when ready:
License
MIT