diff --git a/profile.d/rain.sh b/profile.d/rain.sh index 1833afc..4541151 100644 --- a/profile.d/rain.sh +++ b/profile.d/rain.sh @@ -92,6 +92,24 @@ _rain_build_chars() return 0 } +_rain_normalize_speed() +{ + local raw_speed="$1" + + # Accept integer/floating values. UI scale is centiseconds by default: + # 5 -> 0.05s, 2.5 -> 0.025s. Values < 1 are treated as direct seconds + # for backward compatibility (e.g. 0.03). + if [[ ! "$raw_speed" =~ ^[0-9]+([.][0-9]+)?$ ]]; then + return 1 + fi + + if awk -v s="$raw_speed" 'BEGIN { exit !(s < 1) }'; then + printf "%s" "$raw_speed" + else + awk -v s="$raw_speed" 'BEGIN { printf "%.3f", s / 100 }' + fi +} + _rain_engine() { local step_duration="$1" @@ -111,6 +129,7 @@ _rain_engine() local rain_chars=("${RAIN_ENGINE_CHARS[@]}") local rain_color_tab=${#rain_colors[@]} local rain_tab=${#rain_chars[@]} + local matrix_head_color=$'\e[1;97m' local exit_st=0 local num_rain_metadata=5 @@ -118,27 +137,42 @@ _rain_engine() local X=0 Y=0 drop_length=0 rain_drop=0 local max_rain_width=0 max_rain_height=0 local new_rain_odd=0 falling_odd=0 + local term_area=0 + local frame_sleep="$step_duration" sigwinch() { term_width=$(tput cols) term_height=$(tput lines) + ((term_area = term_width * term_height)) case "$mode" in matrix) - ((max_rain_width = term_width * term_height / 3)) + ((max_rain_width = term_area / 3)) ((max_rain_height = term_height < 8 ? 1 : term_height / 6)) ((new_rain_odd = term_height > 50 ? 100 : term_height * 2)) ((new_rain_odd = new_rain_odd * 85 / 100)) ((falling_odd = 100)) + + # Adapt cadence and density to terminal size for smoother rendering. + if ((term_area < 1200)); then + ((max_rain_width = term_area / 4)) + frame_sleep=$(awk -v s="$step_duration" 'BEGIN { printf "%.3f", s * 1.15 }') + elif ((term_area > 5000)); then + ((max_rain_width = term_area / 2)) + frame_sleep=$(awk -v s="$step_duration" 'BEGIN { printf "%.3f", s * 0.85 }') + else + frame_sleep="$step_duration" + fi ;; *) - ((max_rain_width = term_width * term_height / 4)) + ((max_rain_width = term_area / 4)) ((max_rain_height = term_height < 10 ? 1 : term_height / 10)) ((new_rain_odd = term_height > 50 ? 100 : term_height * 2)) ((new_rain_odd = new_rain_odd * 75 / 100)) ((falling_odd = term_height > 25 ? 100 : term_height * 4)) ((falling_odd = falling_odd * 90 / 100)) + frame_sleep="$step_duration" ;; esac } @@ -150,7 +184,7 @@ _rain_engine() do_render() { - local idx=0 y=0 drop_color="" + local idx=0 y=0 drop_color="" current_char="" render_color="" for ((idx = 0; idx < num_rains * num_rain_metadata; idx += num_rain_metadata)); do X=${rains[idx]} @@ -179,7 +213,18 @@ _rain_engine() for ((y = Y; y < Y + drop_length; y++)); do ((y < 1 || y > term_height)) && continue - printf "\e[%d;%dH%s%s" "$y" "$X" "$drop_color" "$rain_drop" + if [[ "$mode" == "matrix" ]]; then + current_char="${rain_chars[rain_tab * RANDOM / 32768]}" + if ((y == Y + drop_length - 1)); then + render_color="$matrix_head_color" + else + render_color="$drop_color" + fi + else + current_char="$rain_drop" + render_color="$drop_color" + fi + printf "\e[%d;%dH%b%s" "$y" "$X" "$render_color" "$current_char" done done } @@ -196,7 +241,7 @@ _rain_engine() sigwinch while ((exit_st <= 0)); do - read -r -n 1 -t "$step_duration" ch + read -r -n 1 -t "$frame_sleep" ch case "$ch" in q|Q) do_exit @@ -232,8 +277,9 @@ rain() { printf "Usage: rain [OPTIONS]\n" printf "Options:\n" - printf "\t-s, --speed NUM Set the drop delay in seconds (default: 0.050).\n" - printf "\t Lower values = faster rain.\n" + printf "\t-s, --speed NUM Set speed value (default: 5 => 0.050s).\n" + printf "\t Values >=1 use a /100 scale (5 => 0.05s).\n" + printf "\t Values <1 are interpreted as raw seconds.\n" printf "\t-c, --color COLOR Set the color theme (default: white).\n" printf "\t-h, --help Display this help message and exit.\n\n" printf "Available Colors:\n" @@ -243,7 +289,7 @@ rain() printf "\t\e[33myellow\e[0m\t: Amber and gold tones\n" printf "\t\e[36mcyan\e[0m\t: Electric cyan/turquoise\n" printf "\twhite\t: Greyscale and white (original style)\n\n" - printf "Example: rain --color green --speed 0.03\n" + printf "Example: rain --color green --speed 3\n" } local step_duration=0.050 @@ -253,7 +299,11 @@ rain() case $1 in -s|--speed) if [[ -n "$2" && ! "$2" =~ ^- ]]; then - step_duration="$2" + step_duration=$(_rain_normalize_speed "$2") || { + disp E "--speed requires a numeric value." + _rain_show_usage + return 1 + } shift else disp E "--speed requires a numeric value." @@ -301,12 +351,13 @@ matrix() { printf "Usage: matrix [OPTIONS]\n" printf "Options:\n" - printf "\t-s, --speed NUM Set the drop delay in seconds (default: 0.035).\n" - printf "\t Lower values = faster stream.\n" + printf "\t-s, --speed NUM Set speed value (default: 3.5 => 0.035s).\n" + printf "\t Values >=1 use a /100 scale (3.5 => 0.035s).\n" + printf "\t Values <1 are interpreted as raw seconds.\n" printf "\t-c, --color COLOR Set color theme (default: green).\n" - printf "\t-t, --charset SET Character set: binary, kana, ascii (default: binary).\n" + printf "\t-C, --charset SET Character set: binary, kana, ascii (default: binary).\n" printf "\t-h, --help Display this help message and exit.\n\n" - printf "Example: matrix --charset kana --speed 0.02\n" + printf "Example: matrix -C kana -c green --speed 2\n" } local step_duration=0.035 @@ -317,7 +368,11 @@ matrix() case $1 in -s|--speed) if [[ -n "$2" && ! "$2" =~ ^- ]]; then - step_duration="$2" + step_duration=$(_rain_normalize_speed "$2") || { + disp E "--speed requires a numeric value." + _matrix_show_usage + return 1 + } shift else disp E "--speed requires a numeric value." @@ -327,7 +382,15 @@ matrix() ;; -c|--color) if [[ -n "$2" && ! "$2" =~ ^- ]]; then - base_color="$2" + case "${2,,}" in + binary|kana|kanji|ascii) + disp W "'${2}' looks like a charset value. Use -C/--charset for clarity." + charset="${2,,}" + ;; + *) + base_color="$2" + ;; + esac shift else disp E "--color requires a color name." @@ -335,7 +398,7 @@ matrix() return 1 fi ;; - -t|--charset) + -C|--charset) if [[ -n "$2" && ! "$2" =~ ^- ]]; then charset="${2,,}" shift