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
//! # Cellophane
//!
//! A terminal animation framework for Rust. Implement one trait, get a complete
//! rendering pipeline with frame diffing, resize handling, and input forwarding.
//!
//! ## Core types
//!
//! - [`Animation`] — the trait you implement to define an animation
//! - [`Animator`] — drives your animation with a frame-rate-limited render loop
//! - [`Frame`] — a grid of styled [`Cell`]s representing one frame of output
//! - [`FrameBuilder`] — parses ANSI-escaped text into a `Frame`
//! - [`Cell`] — a single terminal cell with character, colors, and attributes
//! - [`Grapheme`] — a unicode grapheme cluster backed by `SmallVec<[char; 4]>`
//!
//! ## Quick start
//!
//! ```no_run
//! use std::time::Duration;
//! use cellophane::{Animation, Animator, Frame, Cell};
//! use crossterm::style::Color;
//!
//! struct Rainbow {
//! tick: usize,
//! rows: usize,
//! cols: usize,
//! }
//!
//! impl Animation for Rainbow {
//! fn init(&mut self, initial: Frame) {
//! let (rows, cols) = initial.dims().unwrap_or((0, 0));
//! self.rows = rows;
//! self.cols = cols;
//! }
//!
//! fn update(&mut self, _dt: Duration) -> Frame {
//! let mut frame = Frame::with_capacity(self.cols, self.rows);
//! for row in 0..self.rows {
//! for col in 0..self.cols {
//! let hue = ((col + row + self.tick) % 256) as u8;
//! if let Some(cell) = frame.get_cell_mut(row, col) {
//! *cell = Cell::default()
//! .with_bg(Color::Rgb { r: hue, g: 100, b: 255 - hue });
//! }
//! }
//! }
//! self.tick += 1;
//! frame
//! }
//!
//! fn is_done(&self) -> bool { false }
//! fn resize(&mut self, w: usize, h: usize) {
//! self.cols = w;
//! self.rows = h;
//! }
//! }
//!
//! fn main() -> std::io::Result<()> {
//! let anim = Box::new(Rainbow { tick: 0, rows: 0, cols: 0 });
//! let mut animator = Animator::enter_with(anim)?;
//! loop {
//! match animator.tick() {
//! Ok(true) => continue,
//! Ok(false) => break,
//! Err(e) if e.kind() == std::io::ErrorKind::Interrupted => break,
//! Err(e) => return Err(e),
//! }
//! }
//! Ok(())
//! }
//! ```
//!
//! The `Animator` handles entering the alternate screen, enabling raw mode,
//! hiding the cursor, frame-rate limiting, frame diffing (only changed cells
//! are redrawn), terminal resize events, Ctrl+C handling, and terminal
//! restoration on drop.
pub
pub
pub use ;
pub use ;
pub use crossterm;