Skip to content

Commit

Permalink
Add new rainbow setting (#105)
Browse files Browse the repository at this point in the history
Resolves #102

Use `--rainbow` to set the new setting, the number is the hue in degrees to shift each pipe. Only applies to RGB mode, defaults to None/0, which means no change in hue.
  • Loading branch information
lhvy committed Jul 27, 2022
1 parent 20ab84e commit 35a5408
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 49 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ The following is an example file with the default settings:
bold = true
color_mode = "ansi" # ansi, rgb or none
palette = "default" # default, darker, pastel or matrix
rainbow = 0 # 0-255
delay_ms = 20
inherit_style = false
kinds = ["heavy"] # heavy, light, curved, knobby, emoji, outline, dots, blocks, sus
Expand Down Expand Up @@ -94,17 +95,18 @@ _Due to emojis having a different character width, using the emoji pipe kind alo

There are also command line options that can be used to override parts of the configuration file:

| Option | Usage | Example |
| :---------- | :-------------------------------------------------------------- | :----------------- |
| `-b` | toggles bold text | `-b true` |
| `-c` | sets the color mode | `-c rgb` |
| `-d` | sets the delay in ms | `-d 15` |
| `-i` | toggles if pipes inherit style when hitting the edge | `-i false` |
| `-k` | sets the kinds of pipes, each kind separated by commas | `-k heavy,curved` |
| `-p` | sets the number of pipes on screen | `-p 5` |
| `-r` | sets the percentage of the screen to be filled before resetting | `-r 0.75` |
| `-t` | chance of a pipe turning each frame | `-t 0.15` |
| `--palette` | sets the color palette, RGB mode only | `--palette pastel` |
| Option | Usage | Example |
| :---------- | :-------------------------------------------------------------------------------- | :----------------- |
| `-b` | toggles bold text | `-b true` |
| `-c` | sets the color mode | `-c rgb` |
| `-d` | sets the delay in ms | `-d 15` |
| `-i` | toggles if pipes inherit style when hitting the edge | `-i false` |
| `-k` | sets the kinds of pipes, each kind separated by commas | `-k heavy,curved` |
| `-p` | sets the number of pipes on screen | `-p 5` |
| `-r` | sets the percentage of the screen to be filled before resetting | `-r 0.75` |
| `-t` | chance of a pipe turning each frame | `-t 0.15` |
| `--palette` | sets the color palette, RGB mode only | `--palette pastel` |
| `--rainbow` | sets the number of degrees per frame to shift the hue of each pipe, RGB mode only | `--rainbow 5` |

## Credits

Expand Down
2 changes: 1 addition & 1 deletion crates/model/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ anyhow = "1.0"
rng = {path = "../rng"}
serde = {version = "1.0", features = ["derive"]}
terminal = {path = "../terminal"}
tincture = "0.5.0"
tincture = "1.0.0"
9 changes: 7 additions & 2 deletions crates/model/src/pipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ pub use color::{ColorMode, Palette};
use history_keeper::HistoryKeeper;
pub use kind::{Kind, KindSet};

use self::color::Color;
use crate::direction::Direction;
use crate::position::{InScreenBounds, Position};

pub struct Pipe {
dir: HistoryKeeper<Direction>,
pub pos: Position,
pub color: Option<terminal::Color>,
pub color: Option<Color>,
kind: Kind,
}

Expand Down Expand Up @@ -40,9 +41,13 @@ impl Pipe {
}
}

pub fn tick(&mut self, size: (u16, u16), turn_chance: f32) -> InScreenBounds {
pub fn tick(&mut self, size: (u16, u16), turn_chance: f32, hue_shift: u8) -> InScreenBounds {
let InScreenBounds(in_screen_bounds) = self.pos.move_in(self.dir.current(), size);

if let Some(color) = &mut self.color {
color.update(hue_shift.into());
}

if !in_screen_bounds {
return InScreenBounds(false);
}
Expand Down
87 changes: 59 additions & 28 deletions crates/model/src/pipe/color.rs
Original file line number Diff line number Diff line change
@@ -1,53 +1,84 @@
use std::ops::Range;
use std::str::FromStr;
use tincture::ColorSpace;

pub(super) fn gen_random_color(color_mode: ColorMode, palette: Palette) -> Option<terminal::Color> {
#[derive(Clone, Copy)]
pub struct Color {
pub terminal: terminal::Color,
pub(crate) oklch: Option<tincture::Oklch>,
}

impl Color {
pub(crate) fn update(&mut self, hue_shift: f32) {
if let Some(oklch) = &mut self.oklch {
oklch.h += hue_shift.to_radians();
let oklab = tincture::oklch_to_oklab(*oklch);
let lrgb = tincture::oklab_to_linear_srgb(oklab);
let srgb = tincture::linear_srgb_to_srgb(lrgb);
self.terminal = terminal::Color::Rgb {
r: (srgb.r * 255.0) as u8,
g: (srgb.g * 255.0) as u8,
b: (srgb.b * 255.0) as u8,
};
}
}
}

pub(super) fn gen_random_color(color_mode: ColorMode, palette: Palette) -> Option<Color> {
match color_mode {
ColorMode::Ansi => Some(gen_random_ansi_color()),
ColorMode::Rgb => Some(gen_random_rgb_color(palette)),
ColorMode::None => None,
}
}

fn gen_random_ansi_color() -> terminal::Color {
fn gen_random_ansi_color() -> Color {
let num = rng::gen_range(0..12);

match num {
0 => terminal::Color::Red,
1 => terminal::Color::DarkRed,
2 => terminal::Color::Green,
3 => terminal::Color::DarkGreen,
4 => terminal::Color::Yellow,
5 => terminal::Color::DarkYellow,
6 => terminal::Color::Blue,
7 => terminal::Color::DarkBlue,
8 => terminal::Color::Magenta,
9 => terminal::Color::DarkMagenta,
10 => terminal::Color::Cyan,
11 => terminal::Color::DarkCyan,
_ => unreachable!(),
Color {
terminal: match num {
0 => terminal::Color::Red,
1 => terminal::Color::DarkRed,
2 => terminal::Color::Green,
3 => terminal::Color::DarkGreen,
4 => terminal::Color::Yellow,
5 => terminal::Color::DarkYellow,
6 => terminal::Color::Blue,
7 => terminal::Color::DarkBlue,
8 => terminal::Color::Magenta,
9 => terminal::Color::DarkMagenta,
10 => terminal::Color::Cyan,
11 => terminal::Color::DarkCyan,
_ => unreachable!(),
},
oklch: None,
}
}

fn gen_random_rgb_color(palette: Palette) -> terminal::Color {
fn gen_random_rgb_color(palette: Palette) -> Color {
let hue = rng::gen_range_float(palette.get_hue_range());
let lightness = rng::gen_range_float(palette.get_lightness_range());

let oklch = tincture::Oklch {
l: lightness,
c: palette.get_chroma(),
h: tincture::Hue::from_degrees(hue).unwrap(),
h: hue.to_radians(),
};
let oklab = tincture::Oklab::from(oklch);
let lrgb: tincture::LinearRgb = tincture::convert(oklab);
let srgb = tincture::Srgb::from(lrgb);
debug_assert!(srgb.in_bounds());

terminal::Color::Rgb {
r: (srgb.r * 255.0) as u8,
g: (srgb.g * 255.0) as u8,
b: (srgb.b * 255.0) as u8,
let oklab = tincture::oklch_to_oklab(oklch);
let lrgb = tincture::oklab_to_linear_srgb(oklab);
let srgb = tincture::linear_srgb_to_srgb(lrgb);
debug_assert!(
(0.0..=1.0).contains(&srgb.r)
&& (0.0..=1.0).contains(&srgb.g)
&& (0.0..=1.0).contains(&srgb.b)
);

Color {
terminal: terminal::Color::Rgb {
r: (srgb.r * 255.0) as u8,
g: (srgb.g * 255.0) as u8,
b: (srgb.b * 255.0) as u8,
},
oklch: Some(oklch),
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/pipes-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
edition = "2021"
license = "MIT OR Apache-2.0"
name = "pipes-rs"
version = "1.5.0"
version = "1.6.0"

[dependencies]
anyhow = "1.0"
Expand Down
9 changes: 9 additions & 0 deletions crates/pipes-rs/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ pub struct Config {
#[clap(long, possible_values = ["default", "darker", "pastel", "matrix"])]
pub palette: Option<Palette>,

/// cycle hue of pipes
#[clap(long, value_name = "DEGREES")]
pub rainbow: Option<u8>,

/// delay between frames in milliseconds
#[clap(short, long = "delay")]
pub delay_ms: Option<u64>,
Expand Down Expand Up @@ -102,6 +106,10 @@ impl Config {
self.palette.unwrap_or(Palette::Default)
}

pub fn rainbow(&self) -> u8 {
self.rainbow.unwrap_or(0)
}

pub fn delay(&self) -> Duration {
Duration::from_millis(self.delay_ms.unwrap_or(20))
}
Expand Down Expand Up @@ -140,6 +148,7 @@ impl Config {
Self {
color_mode: other.color_mode.or(self.color_mode),
palette: other.palette.or(self.palette),
rainbow: other.rainbow.or(self.rainbow),
delay_ms: other.delay_ms.or(self.delay_ms),
reset_threshold: other.reset_threshold.or(self.reset_threshold),
kinds: other.kinds.or(self.kinds),
Expand Down
9 changes: 6 additions & 3 deletions crates/pipes-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,11 @@ impl<B: Backend> App<B> {
}

fn tick_pipe(&mut self, pipe: &mut Pipe) {
let InScreenBounds(stayed_onscreen) =
pipe.tick(self.terminal.size(), self.config.turn_chance());
let InScreenBounds(stayed_onscreen) = pipe.tick(
self.terminal.size(),
self.config.turn_chance(),
self.config.rainbow(),
);

if !stayed_onscreen {
*pipe = if self.config.inherit_style() {
Expand All @@ -102,7 +105,7 @@ impl<B: Backend> App<B> {
self.terminal.move_cursor_to(pipe.pos.x, pipe.pos.y)?;

if let Some(color) = pipe.color {
self.terminal.set_text_color(color)?;
self.terminal.set_text_color(color.terminal)?;
}

self.terminal.print(if rng::gen_bool(0.99999) {
Expand Down

0 comments on commit 35a5408

Please sign in to comment.