Skip to content

Commit 224f616

Browse files
feat: Final set of features, fixes, and enhancements
This commit includes the complete set of changes to the bash-screensavers project, incorporating all of your feedback and requests. Major Features & Enhancements: - **Matrix:** The screensaver now features a "dark -> bright -> dark" color cycle, creating a more authentic "digital rain" effect. - **Stars:** The starfield is now more dynamic, with more colors, star sizes, and a more active twinkle effect. - **Tunnel:** The tunnel animation now expands to fill the entire screen and includes boundary checks for robustness. - **Cutesaver:** Refactored into a single script that dynamically finds and displays art files in a random order. - **Generator:** A new screensaver generator is added to `screensaver.sh`, invoked with `-n <name>` or `--new <name>`. Fixes and Improvements: - **Menu Logic:** The main menu now handles invalid input gracefully by showing an error and re-displaying the menu instead of exiting. - **Permissions:** The script no longer automatically `chmod +x` screensavers. Instead, it displays a friendly error message. - **Robustness:** - The handling of filenames with spaces is now robust, using `mapfile`. - `speaky.sh` now uses `mktemp` for secure temporary file creation. - **Code Quality:** - A missing `SIGINT` trap was added to `cutesaver.sh`. - The inefficient explosion clearing logic in `fireworks.sh` was replaced with a simple `clear`. - The exit handlers for all screensavers have been updated to no longer clear the screen on exit. - The `config.sh` template in the generator now only includes standard variables. - **Documentation & Versioning:** - The `README.md` has been updated to document the new generator feature. - The project version has been updated to v0.0.8. - **Testing:** - A comprehensive BATS test suite has been added to cover all screensavers and the main script's functionality. - The test strategy has been updated to check for executability separately.
1 parent 2e86314 commit 224f616

File tree

22 files changed

+393
-167
lines changed

22 files changed

+393
-167
lines changed

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ cd bash-screensavers
2222
./screensaver.sh
2323
```
2424
```
25-
Bash Screensavers v0.0.7
25+
Bash Screensavers v0.0.8
2626
2727
1 . alpha - colorful pixels, one at a time
2828
2 . bouncing - classic bouncing 'O's
@@ -65,6 +65,19 @@ Let's make the command line a more colorful place, one ASCII character at a time
6565

6666
Got an idea for a cool ASCII animation? Want to contribute to the collection? It's easy!
6767

68+
#### The Easy Way (Generator)
69+
70+
You can use the built-in generator to create a new screensaver with all the boilerplate code you need. Just run:
71+
72+
```bash
73+
./screensaver.sh --new my-awesome-screensaver
74+
```
75+
(You can also use `-n` instead of `--new`)
76+
77+
This will create a new directory `gallery/my-awesome-screensaver` with a starter `my-awesome-screensaver.sh` script and a `config.sh` file. All you have to do is edit the `.sh` file to add your animation logic!
78+
79+
#### The Hard Way (Manual)
80+
6881
1. **Create a new directory** for your screensaver inside the `gallery` directory. For example, `gallery/my-awesome-screensaver`.
6982
2. **Create a shell script** inside your new directory with the same name as the directory, ending in `.sh`. For example, `gallery/my-awesome-screensaver/my-awesome-screensaver.sh`.
7083
3. **Write your masterpiece!** Your script should:

gallery/bouncing/bouncing.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ SLEEP_TIME=0.03
1313
_cleanup_and_exit() { # handler for SIGINT (Ctrl‑C)
1414
tput cnorm # show the cursor again
1515
tput sgr0
16-
clear
16+
echo
1717
exit 0
1818
}
1919

gallery/cutesaver/cutesaver.sh

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212

1313
# Anyway, on with the cuteness. Let's load some title art.
1414

15+
_cleanup_and_exit() { # handler for SIGINT (Ctrl‑C)
16+
tput cnorm # show the cursor again
17+
tput sgr0 # reset all attributes
18+
echo
19+
exit 0
20+
}
21+
trap _cleanup_and_exit SIGINT # Catch Ctrl‑C
22+
1523
cd "$( dirname "${BASH_SOURCE[0]}" )"
1624

1725
clear
@@ -44,8 +52,34 @@ echo
4452
sleep 2
4553
# read -p "Press [ENTER] to start..."
4654

47-
# Now we'll simply load the ever-looping cuteness file.
48-
./rollthecute.sh
55+
# Now we'll simply start the animation.
56+
animate() {
57+
tput setab 0 # black background
58+
clear
59+
tput civis # Hide cursor
60+
61+
# Find all art files
62+
local art_files=(./art/*.art)
63+
if [ ${#art_files[@]} -eq 0 ]; then
64+
echo "No art files found in ./art/"
65+
sleep 5
66+
return
67+
fi
68+
69+
while true; do
70+
# Shuffle the list of files for random order
71+
local shuffled_files=($(shuf -e "${art_files[@]}"))
72+
for art_file in "${shuffled_files[@]}"; do
73+
clear
74+
if [ -f "$art_file" ]; then
75+
cat "$art_file"
76+
else
77+
tput cup 5 5
78+
echo "Art file not found: $art_file"
79+
fi
80+
sleep 10
81+
done
82+
done
83+
}
4984

50-
# Et Voila!
51-
exit
85+
animate

gallery/cutesaver/rollthecute.sh

Lines changed: 0 additions & 48 deletions
This file was deleted.

gallery/fireworks/fireworks.sh

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ DELAY_BETWEEN=0.5
1515
_cleanup_and_exit() { # handler for SIGINT (Ctrl‑C)
1616
tput cnorm # show the cursor again
1717
tput sgr0
18-
clear
18+
echo
1919
exit 0
2020
}
2121

@@ -72,24 +72,9 @@ animate() {
7272
sleep $DELAY_EXPLOSION
7373
done
7474

75-
# Clear the explosion
76-
local frame_buffer=""
77-
for ((r=1; r <= explosion_radius; r++)); do
78-
for ((i=0; i<r; i++)); do
79-
y1=$((peak_y - r + i)); x1=$((rocket_x + i))
80-
y2=$((peak_y + i)); x2=$((rocket_x + r - i))
81-
y3=$((peak_y + r - i)); x3=$((rocket_x - i))
82-
y4=$((peak_y - i)); x4=$((rocket_x - r + i))
83-
84-
if (( y1 >= 0 && y1 < height && x1 >= 0 && x1 < width )); then frame_buffer+="\e[$((y1 + 1));$((x1 + 1))H "; fi
85-
if (( y2 >= 0 && y2 < height && x2 >= 0 && x2 < width )); then frame_buffer+="\e[$((y2 + 1));$((x2 + 1))H "; fi
86-
if (( y3 >= 0 && y3 < height && x3 >= 0 && x3 < width )); then frame_buffer+="\e[$((y3 + 1));$((x3 + 1))H "; fi
87-
if (( y4 >= 0 && y4 < height && x4 >= 0 && x4 < width )); then frame_buffer+="\e[$((y4 + 1));$((x4 + 1))H "; fi
88-
done
89-
done
90-
printf '%b' "$frame_buffer"
91-
92-
sleep $DELAY_BETWEEN # Wait a moment before the next firework
75+
# Let the explosion linger for a moment, then clear for the next one
76+
sleep $DELAY_BETWEEN
77+
clear
9378
done
9479
}
9580

gallery/matrix/matrix.sh

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,17 @@
1010
#~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
1111

1212
# --- Configuration ---
13-
# Set the colors
14-
GREEN=$'\e[32m'
13+
# Color palette for the "dark -> bright -> dark" cycle.
14+
PALETTE=(
15+
$'\e[38;5;22m' # Darkest
16+
$'\e[38;5;28m'
17+
$'\e[38;5;34m'
18+
$'\e[38;5;40m'
19+
$'\e[38;5;46m' # Brightest
20+
$'\e[38;5;40m'
21+
$'\e[38;5;34m'
22+
$'\e[38;5;28m'
23+
)
1524
RESET=$'\e[0m'
1625

1726
# The characters to display
@@ -25,7 +34,7 @@ DELAY=0.04
2534
_cleanup_and_exit() { # handler for SIGINT (Ctrl‑C)
2635
tput cnorm # show the cursor again
2736
tput sgr0 # reset all attributes
28-
clear
37+
echo
2938
exit 0
3039
}
3140

@@ -69,21 +78,25 @@ animate() {
6978
continue # Skip to the next column if it's not active
7079
fi
7180

72-
# --- Draw the stream head ---
7381
local y_head=${heads[$i]}
74-
# Get a random character
75-
local rand_char=${CHARS:$((RANDOM % ${#CHARS})):1}
76-
# Add cursor positioning and character to the frame buffer
77-
# Format: \e[<row>;<col>H<char>
78-
# NOTE: ANSI rows/cols are 1-based, so we add 1 to the 0-based column index `i`.
79-
frame_buffer+="\e[${y_head};$((i + 1))H${GREEN}${rand_char}"
82+
local stream_len=${stream_lengths[$i]}
83+
84+
# --- Draw the full stream with the color cycle gradient ---
85+
# NOTE: This is less performant than the previous version as it redraws
86+
# the entire stream in every frame, but it matches the requested effect.
87+
for ((j=0; j < stream_len; j++)); do
88+
local y=$((y_head - j))
89+
if [ $y -lt 1 ]; then break; fi
90+
91+
local color_index=$((j % ${#PALETTE[@]}))
92+
local color=${PALETTE[$color_index]}
93+
local rand_char=${CHARS:$((RANDOM % ${#CHARS})):1}
94+
frame_buffer+="\e[${y};$((i + 1))H${color}${rand_char}"
95+
done
8096

8197
# --- Erase the stream tail ---
82-
local stream_len=${stream_lengths[$i]}
8398
local y_tail=$((y_head - stream_len))
84-
8599
if [ $y_tail -ge 1 ]; then
86-
# Add cursor positioning and a space to the frame buffer to erase the tail
87100
frame_buffer+="\e[${y_tail};$((i + 1))H "
88101
fi
89102

gallery/pipes/pipes.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,11 @@ cleanup() {
226226
# clear out standard input
227227
read -t 0.001 && cat </dev/stdin>/dev/null
228228

229-
tput reset # fix for konsole, see pipeseroni/pipes.sh#43
230229
tput rmcup
231230
tput cnorm
232231
stty echo
233232
printf "$SGR0"
233+
echo
234234
exit 0
235235
}
236236

gallery/rain/rain.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ DELAY=0.03
1717
_cleanup_and_exit() { # handler for SIGINT (Ctrl‑C)
1818
tput cnorm # show the cursor again
1919
tput sgr0
20-
clear
20+
echo
2121
exit 0
2222
}
2323

gallery/speaky/speaky.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ say_txt() {
170170
"festival") echo "$phrase" | festival --tts & ;;
171171
"gtts-cli") gtts-cli -l en - --output - "$phrase" | aplay & ;;
172172
"pico2wave")
173-
local tmpfile="/tmp/speaky_tts_$$.wav"
173+
local tmpfile
174+
tmpfile=$(mktemp /tmp/speaky_tts.XXXXXX.wav)
174175
pico2wave -l en-US -w "$tmpfile" "$phrase" && aplay "$tmpfile" && rm "$tmpfile" & ;;
175176
"powershell")
176177
powershell.exe -Command "Add-Type -AssemblyName System.Speech; (New-Object System.Speech.Synthesis.SpeechSynthesizer).Speak('$phrase_ps')" & ;;
@@ -195,7 +196,7 @@ cleanup_and_exit() {
195196
local exit_phrase=${exit_phrases[$RANDOM % ${#exit_phrases[@]}]}
196197
say_txt "$exit_phrase"
197198
wait $SPEAK_PID &>/dev/null
198-
tput cnorm; tput sgr0; clear
199+
tput cnorm; tput sgr0; echo
199200
exit 0
200201
}
201202

gallery/stars/stars.sh

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@
66

77
# --- Configuration ---
88
# Set the colors
9-
WHITE=$'\e[97m'
10-
YELLOW=$'\e[93m'
9+
C_WHITE=$'\e[97m'
10+
C_YELLOW=$'\e[93m'
11+
C_BLUE=$'\e[94m'
12+
C_CYAN=$'\e[96m'
13+
COLORS=("$C_WHITE" "$C_YELLOW" "$C_BLUE" "$C_CYAN")
1114
DELAY=0.02
1215

1316
# The characters for the stars
14-
STARS=("*" "." "+")
17+
STARS=("*" "." "+" "'" "O")
1518

1619
_cleanup_and_exit() { # handler for SIGINT (Ctrl‑C)
1720
tput cnorm # show the cursor again
1821
tput sgr0
19-
clear
22+
echo
2023
exit 0
2124
}
2225

@@ -37,24 +40,21 @@ animate() {
3740
while true; do
3841
local frame_buffer=""
3942

40-
# Add a new star
41-
local x=$((RANDOM % width + 1))
42-
local y=$((RANDOM % height + 1))
43+
# Add a few new stars
44+
for i in {1..3}; do
45+
local x=$((RANDOM % width + 1))
46+
local y=$((RANDOM % height + 1))
47+
local rand_star=${STARS[$((RANDOM % ${#STARS[@]}))]}
48+
local rand_color=${COLORS[$((RANDOM % ${#COLORS[@]}))]}
49+
frame_buffer+="\e[${y};${x}H${rand_color}${rand_star}"
50+
done
4351

44-
# Choose a random star character and color
45-
local rand_star=${STARS[$((RANDOM % ${#STARS[@]}))]}
46-
local star_color=$WHITE
47-
if [ $((RANDOM % 5)) -eq 0 ]; then
48-
star_color=$YELLOW
49-
fi
50-
frame_buffer+="\e[${y};${x}H${star_color}${rand_star}"
51-
52-
# Occasionally clear a random spot to make stars twinkle
53-
if [ $((RANDOM % 3)) -eq 0 ]; then
52+
# Clear a few random spots to make stars twinkle and prevent over-filling
53+
for i in {1..2}; do
5454
local clear_x=$((RANDOM % width + 1))
5555
local clear_y=$((RANDOM % height + 1))
5656
frame_buffer+="\e[${clear_y};${clear_x}H "
57-
fi
57+
done
5858

5959
printf '%b' "$frame_buffer"
6060
sleep $DELAY

0 commit comments

Comments
 (0)