/tui-rain

TUI Rain Effect

Primary LanguageRustMIT LicenseMIT

tui-rain

crate docs license

tui-rain is a simple widget to generate various rain effects for ratatui.

matrix rain effect

Features:

  • Highly configurable
  • Practically stateless
  • Backend-agnostic
  • Transparent background

Examples

Matrix rain

A classic matrix rain of green half-width kana characters. Press q to quit, and f to show/hide the FPS tracker.

cargo run --example matrix
matrix rain effect

Normal rain

Drops of fast blue | characters. Press q to quit, and f to show/hide the FPS tracker.

cargo run --example rain
normal rain effect

Snow

Slow-falling white * characters. Press q to quit, and f to show/hide the FPS tracker.

cargo run --example snow
snow effect

Emoji soup

A chaotic flood of emojis. Terminals that use Unicode version 9+ widths may experience jitter. Press q to quit, and f to show/hide the FPS tracker.

cargo run --example emoji
emoji rain effect

Simple

A demonstration of fairly minimal code to render this widget. Does not listen for key events, and will automatically exit after ~10 seconds.

Usage

The Rain struct is a simple stateless ratatui widget. It can be initially constructed from a few helper functions with defaults, and further configured from there.

Construction requires only an elapsed duration to determine what frame to render. This can be provided by just tracking the time the animation was started, and computing start_time.elapsed() at render-time. See simple.rs for a minimal example.

Construction functions:

  • new_matrix builds a classic matrix rain of green half-width kana characters
  • new_rain builds drops of fast blue | characters
  • new_snow builds slow-falling white * characters
  • new_emoji_soup builds a chaotic flood of emojis (may jitter on some terminals)

Configuration

There are a variety of configuration options available, and they can be sequentially chained:

use std::time::Duration;
use tui_rain::{CharacterSet, Rain, RainDensity, RainSpeed};

let elapsed = Duration::from_secs(5);

let rain = Rain::new_rain(elapsed)
    .with_character_set(CharacterSet::UnicodeRange {
        start: 0x61,
        len: 26,
    })
    .with_rain_density(RainDensity::Relative {
        sparseness: 50,
    })
    .with_rain_speed(RainSpeed::Absolute {
        speed: 10.0,
    })
    .with_rain_speed_variance(0.1)
    .with_tail_lifespan(Duration::from_secs(5))
    .with_color(ratatui::style::Color::LightGreen)
    .with_noise_interval(Duration::from_secs(10))
    .with_seed(1234);

Character set

The simplest option is to provide an explicit set of characters to choose from:

use std::time::Duration;
use tui_rain::{CharacterSet, Rain};

let elapsed = Duration::from_secs(5);

Rain::new_matrix(elapsed)
    .with_character_set(CharacterSet::Explicit {
        options: vec!['a', 'b', 'c'],
    });

More performant is to provide a unicode range:

use std::time::Duration;
use tui_rain::{CharacterSet, Rain};

let elapsed = Duration::from_secs(5);

Rain::new_matrix(elapsed)
    .with_character_set(CharacterSet::UnicodeRange {
        start: 0x61,
        len: 26,
    });

Preset unicode ranges include:

  • CharacterSet::HalfKana is the half-width Japanese kana character set (used in the classic matrix rain)
  • CharacterSet::Lowercase is the lowercase English character set

Density

This can be configured as an absolute number of drops:

use std::time::Duration;
use tui_rain::{Rain, RainDensity};

let elapsed = Duration::from_secs(5);

Rain::new_matrix(elapsed)
    .with_rain_density(RainDensity::Absolute {
        num_drops: 100,
    });

Or a ratio of screen pixels to drops (lower is more dense):

use std::time::Duration;
use tui_rain::{Rain, RainDensity};

let elapsed = Duration::from_secs(5);

Rain::new_matrix(elapsed)
    .with_rain_density(RainDensity::Relative {
        sparseness: 50,
    });

The actual number of drops on the screen at any time is randomly distributed between 0 and twice the target.

Preset relative options include:

  • RainDensity::Sparse
  • RainDensity::Normal
  • RainDensity::Dense

Speed

Speed can be configured as an absolute value of pixels per second, or as a preset.

For an absolute speed in pixels per second:

use std::time::Duration;
use tui_rain::{Rain, RainSpeed};

let elapsed = Duration::from_secs(5);

Rain::new_matrix(elapsed)
    .with_rain_speed(RainSpeed::Absolute {
        speed: 10.0,
    });

Preset options include:

  • RainSpeed::Slow
  • RainSpeed::Normal
  • RainSpeed::Fast

Speed Variance

To avoid perfectly consistent patterns, you can configure some variance in the speed of each drop. This can also give an impression of parallax (depth).

For example, a value of 0.1 will cause each drop's speed to be uniformly distrbuted within ±10% of the target speed:

use std::time::Duration;
use tui_rain::Rain;

let elapsed = Duration::from_secs(5);

Rain::new_matrix(elapsed)
    .with_rain_speed_variance(0.1);

The speed of an individual drop will never go below 0.001 pixels / second, but can vary arbitrarily high.

Tail lifespan

You can make the rain drop tails appear shorter / longer by configuring how long the tail effect lasts:

use std::time::Duration;
use tui_rain::Rain;

let elapsed = Duration::from_secs(5);

Rain::new_matrix(elapsed)
    .with_tail_lifespan(Duration::from_secs(5));

The drop length is capped at the screen height to avoid strange wraparound effects.

Color

You can change the tail color for each drop:

use std::time::Duration;
use tui_rain::Rain;

let elapsed = Duration::from_secs(5);

Rain::new_matrix(elapsed)
    .with_color(ratatui::style::Color::LightGreen);

The color of the head is independently configured. The bold / dim effects that automatically get applied over a drop's length may tweak the color inadvertently, but this can be disabled.

Head Color

You can change the head color for each drop:

use std::time::Duration;
use tui_rain::Rain;

let elapsed = Duration::from_secs(5);

Rain::new_matrix(elapsed)
    .with_head_color(ratatui::style::Color::Green);

The color of the tail is independently configured. The bold / dim effects that automatically get applied over a drop's length may tweak the color inadvertently, but this can be disabled.

Bold/Dim Effect

By default, the lower third of each drop has the bold effect applied, and the upper third has the dim effect applied. This produces an impression of the drop fading instead of abruptly ending.

This may tweak the color of glyphs away from the base color on some terminals, so it can be disabled if desired:

use std::time::Duration;
use tui_rain::Rain;

let elapsed = Duration::from_secs(5);

Rain::new_matrix(elapsed)
    .with_bold_dim_effect(false);

Noise Interval

A more subtle effect is that glyphs already rendered in a drop occasionally switch characters before dissapearing. The time interval between each character switch is per-glyph, and can be adjusted:

use std::time::Duration;
use tui_rain::Rain;

let elapsed = Duration::from_secs(5);

Rain::new_matrix(elapsed)
    .with_noise_interval(Duration::from_secs(10));

Random seed

The random seed can be configured. Given a constant screen size, results should be reproducible across executions, operating systems, and architectures.

use std::time::Duration;
use tui_rain::Rain;

let elapsed = Duration::from_secs(5);

Rain::new_matrix(elapsed)
    .with_seed(1234);

License

tui-rain is distributed under The MIT License.