1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! Classic "Matrix digital rain" effect for terminals, packaged as both a
//! [ratatui](https://ratatui.rs/) [`StatefulWidget`](ratatui::widgets::StatefulWidget)
//! library and a standalone `matrix` binary.
//!
//! The crate is published as `matrix-rain` on crates.io because the bare `matrix`
//! name is taken; the installed binary is still called `matrix`.
//!
//! # Quick start
//!
//! Drop the widget into any ratatui layout. `MatrixRainState` carries the
//! per-frame animation state (column streams, RNG, timing, cached color tier)
//! across renders.
//!
//! ```
//! use matrix_rain::{MatrixConfig, MatrixRain, MatrixRainState};
//! use ratatui::buffer::Buffer;
//! use ratatui::layout::Rect;
//! use ratatui::widgets::StatefulWidget;
//!
//! let cfg = MatrixConfig::builder().fps(30).density(0.5).build().unwrap();
//! let mut state = MatrixRainState::with_seed(42);
//! let area = Rect::new(0, 0, 80, 24);
//! let mut buf = Buffer::empty(area);
//!
//! MatrixRain::new(&cfg).render(area, &mut buf, &mut state);
//! assert_eq!(state.streams_len(), 80);
//! ```
//!
//! For a full embed inside a [`ratatui::Terminal`] event loop, see
//! `examples/embedded.rs` in the source repo. For the standalone full-screen
//! demo, see `examples/standalone.rs`.
//!
//! # Driving frames
//!
//! There are two ways to advance the animation:
//!
//! - **Wall-clock (default).** Each call to
//! [`MatrixRain::render`](ratatui::widgets::StatefulWidget::render) reads
//! `Instant::now()` internally and applies as many ticks as the elapsed time
//! buys (capped at `MAX_CATCHUP_TICKS=4` so a process resumed from suspend
//! doesn't render hundreds of frames at once). This is what `terminal.draw(…)`
//! does naturally and what the bundled binary uses.
//! - **Manual via [`MatrixRainState::tick`].** Each call advances exactly one
//! frame regardless of wall-clock time. Useful for deterministic snapshot
//! tests and external tick-loop apps.
//!
//! Mixing both modes in the same session produces visible drift; the snapshot
//! suite suppresses wall-clock advance by setting `fps=1` together with a tiny
//! `speed` (e.g. `0.001`) so the elapsed-time conversion floors to zero ticks
//! per render. See [`MatrixRainState::set_color_count`] if you also need to
//! lock the rendering tier for reproducibility.
//!
//! # Backends
//!
//! The library is backend-agnostic — `MatrixRain` renders into a ratatui
//! [`Buffer`](ratatui::buffer::Buffer), so any ratatui backend works. Pick
//! one via a feature flag:
//!
//! - `crossterm` (default; enabled by the `binary` feature)
//! - `termion`
//! - `termwiz`
//!
//! Each feature simply forwards to ratatui's same-named feature, so a single
//! line in `Cargo.toml` covers both crates:
//!
//! ```toml
//! matrix-rain = { version = "0.1", default-features = false, features = ["termion"] }
//! ```
//!
//! The default `binary` feature pulls in `crossterm` (plus `clap`, `anyhow`,
//! and `signal-hook`) for the standalone `matrix` binary. Library-only users
//! who don't need the binary should opt out with `default-features = false`
//! and pick exactly one backend feature.
//!
//! # Color tiers
//!
//! Color depth is detected once per state on the first render via an env-var
//! sniff: `COLORTERM=truecolor|24bit` (de-facto standard for advertising
//! 24-bit support) wins; otherwise `TERM` is checked for `*256color*`.
//! The result is cached on the state and drives one of three rendering paths:
//!
//! - **Truecolor**: linear RGB interpolation between the 5 stops in
//! [`ColorRamp`]. Smoothest gradient.
//! - **256-color**: nearest-of-5-stops; the terminal handles any further
//! RGB→256 quantization.
//! - **16-color**: 3-zone collapse (head, then `bright`/`mid`/`fade` zones)
//! with each stop mapped to the nearest of the 16 named [`Color`] variants
//! by euclidean RGB distance. Detection failure or any value the widget
//! doesn't recognize also falls back to this path rather than panicking.
//!
//! Force a specific tier with [`MatrixRainState::set_color_count`]: pass `16`
//! for accessibility, `256` for the quantized middle tier, or `u16::MAX` for
//! the smooth-interpolation path.
//!
//! [`Color`]: ratatui::style::Color
//!
//! # Caveats
//!
//! - **Full-width and combining characters in [`CharSet::Custom`] are not
//! detected.** Each glyph must occupy exactly one terminal cell or the
//! column layout misaligns. CJK ideographs, emoji with variation selectors,
//! and zero-width combiners are all single `char`s in Rust but multi-cell
//! in the terminal. Display width cannot reliably be detected across
//! terminals; verifying single-cell-ness is the caller's responsibility.
//! - **Mixing [`MatrixRainState::tick`] with wall-clock rendering** produces
//! visible drift over time. Tick driving is exact (each call advances
//! exactly one frame); wall-clock driving advances based on elapsed
//! [`Instant`](std::time::Instant)s. Pick one mode per session.
//! - **16-color fallback is a 3-zone collapse**, not the original 5-stop
//! gradient. If your theme has stops that map to the same named color
//! (common with monochrome themes on 16-color), zones will visually merge.
//! Use [`MatrixRainState::set_color_count`] to force a higher tier if your
//! terminal actually supports it, or supply a [`Theme::Custom`] ramp whose
//! stops are already in the named-color palette.
//! - **Non-TTY refusal (binary only).** The standalone `matrix` binary exits
//! with code 2 when stdout isn't a terminal so it doesn't garble logs when
//! accidentally run under a pipe, in a CI runner, or as a systemd service.
//! `--help` and `--version` still work in non-TTY contexts (they run before
//! the check).
pub use CharSet;
pub use ;
pub use MatrixError;
pub use MatrixRainState;
pub use ;
pub use MatrixRain;