61 lines
1.7 KiB
Rust
61 lines
1.7 KiB
Rust
use crate::theme;
|
|
use rand::Rng;
|
|
use ratatui::buffer::Buffer;
|
|
use ratatui::layout::Rect;
|
|
use ratatui::style::{Color, Style};
|
|
use ratatui::widgets::Widget;
|
|
|
|
const CHARS: &[char] = &['·', '✦', '✧', '°', '•', '+', '⋆', '*'];
|
|
|
|
struct Sparkle {
|
|
x: u16,
|
|
y: u16,
|
|
char_idx: usize,
|
|
life: u8,
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct Sparkles {
|
|
sparkles: Vec<Sparkle>,
|
|
}
|
|
|
|
impl Sparkles {
|
|
pub fn tick(&mut self, area: Rect) {
|
|
let mut rng = rand::thread_rng();
|
|
for _ in 0..3 {
|
|
if rng.gen_bool(0.6) {
|
|
self.sparkles.push(Sparkle {
|
|
x: rng.gen_range(0..area.width),
|
|
y: rng.gen_range(0..area.height),
|
|
char_idx: rng.gen_range(0..CHARS.len()),
|
|
life: rng.gen_range(15..40),
|
|
});
|
|
}
|
|
}
|
|
self.sparkles
|
|
.iter_mut()
|
|
.for_each(|s| s.life = s.life.saturating_sub(1));
|
|
self.sparkles.retain(|s| s.life > 0);
|
|
}
|
|
}
|
|
|
|
impl Widget for &Sparkles {
|
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
let colors = theme::get().sparkle.colors;
|
|
for sp in &self.sparkles {
|
|
let color = colors[sp.char_idx % colors.len()];
|
|
let intensity = (sp.life as f32 / 30.0).min(1.0);
|
|
let r = (color.0 as f32 * intensity) as u8;
|
|
let g = (color.1 as f32 * intensity) as u8;
|
|
let b = (color.2 as f32 * intensity) as u8;
|
|
|
|
if sp.x < area.width && sp.y < area.height {
|
|
let x = area.x + sp.x;
|
|
let y = area.y + sp.y;
|
|
let ch = CHARS[sp.char_idx];
|
|
buf[(x, y)].set_char(ch).set_style(Style::new().fg(Color::Rgb(r, g, b)));
|
|
}
|
|
}
|
|
}
|
|
}
|