use std::{io, time::Duration};
use crossterm::event::{self, Event, KeyCode, KeyEventKind};
use scrin::{
Color, Terminal,
layout::{Constraint, Direction, Layout},
style::Style,
widgets::{
Paragraph, Widget,
block::{Block, BorderStyle},
},
};
use scrin_widgets::{AislingExt, AislingPalette, GlyphRain, NebulaGauge, SignalPanel};
fn main() -> io::Result<()> {
let mut terminal = Terminal::init()?;
let result = run(&mut terminal);
terminal.restore()?;
result
}
fn run(terminal: &mut Terminal) -> io::Result<()> {
let orchard = AislingPalette {
low: Color::rgb(80, 255, 176),
mid: Color::rgb(129, 96, 255),
high: Color::rgb(245, 255, 173),
pulse: Color::rgb(255, 93, 217),
shadow: Color::rgb(10, 11, 26),
};
let ember = AislingPalette {
low: Color::rgb(255, 120, 72),
mid: Color::rgb(255, 54, 138),
high: Color::rgb(255, 236, 181),
pulse: Color::rgb(93, 226, 255),
shadow: Color::rgb(34, 12, 18),
};
let mut tick = 0_u64;
loop {
terminal.draw(|frame| {
let root = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(5),
Constraint::Min(12),
Constraint::Length(7),
])
.split(frame.area());
let buffer = frame.buffer();
let title = color_block("void orchard", orchard.pulse);
let title_inner = title.inner(root[0]);
title.render(buffer, root[0]);
Paragraph::new("bioluminescent packet-fruit blooming in a black terminal grove")
.with_style(Style::default().fg(orchard.high).bold())
.with_word_wrap(true)
.aisling()
.tick(tick)
.palette(orchard)
.intensity(8)
.render(buffer, title_inner);
let middle = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Percentage(42),
Constraint::Percentage(33),
Constraint::Percentage(25),
])
.split(root[1]);
GlyphRain::new(tick)
.density(54)
.glyphs("✶✦✧✺✹✸✷✳")
.palette(orchard)
.block(color_block("spore fall", orchard.low))
.render(buffer, middle[0]);
let charge = ((tick % 120) as f64 / 120.0 - 0.5).abs();
NebulaGauge::new(1.0 - charge * 2.0)
.tick(tick)
.label("mycelial uplink")
.palette(ember)
.block(color_block("root pulse", ember.pulse))
.render(buffer, middle[1]);
SignalPanel::new("orchid daemon")
.line("sap: neon")
.line("hive: listening")
.line("gate: half-open")
.line("fruit: encrypted")
.tick(tick)
.palette(orchard)
.render(buffer, middle[2]);
let lower = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(38), Constraint::Percentage(62)])
.split(root[2]);
NebulaGauge::new(((tick % 88) as f64 / 88.0).sin().abs())
.tick(tick + 31)
.label("moon-sugar pressure")
.palette(orchard)
.block(color_block("vessel", orchard.high))
.render(buffer, lower[0]);
let note = color_block("field note", ember.mid);
let note_inner = note.inner(lower[1]);
note.render(buffer, lower[1]);
Paragraph::new("Every panel is Scrin-native: colored borders, live gauges, signal bars, glyph fields, and Aisling shimmer share one buffer.")
.with_word_wrap(true)
.with_style(Style::default().fg(ember.high))
.aisling()
.tick(tick + 9)
.palette(ember)
.intensity(6)
.render(buffer, note_inner);
})?;
if event::poll(Duration::from_millis(45))? {
if let Event::Key(key) = event::read()? {
if key.kind == KeyEventKind::Press
&& matches!(key.code, KeyCode::Char('q') | KeyCode::Esc)
{
break;
}
}
}
tick = tick.wrapping_add(1);
}
Ok(())
}
fn color_block(title: &str, color: Color) -> Block<'_> {
Block::new(title)
.with_borders(BorderStyle::Plain)
.with_border_color(color)
.with_inner_margin(scrin::Rect::ZERO)
}