Skip to content

A Bash Creativity Showcase by wuseman

Unleash the creativity of your terminal with a unique collection of custom screensavers crafted by Wuseman. This guide features a variety of screensavers, from simple doodles to complex dynamic matrix effects, all designed to transform your command line interface into a canvas of digital art

Dive into the world of Bash scripting with these innovative screensaver examples, and discover how you can bring life, movement, and color to your terminal


One-liner: random colors + random emojis (and less flicker)

trap 'printf "\033[0m\033[?25h\033[2J\033[H\n"; exit' INT TERM; printf '\033[?25l'; while :; do cols=$(tput cols); lines=$(tput lines); printf '\033[2J\033[H'; for ((i=0;i<cols*lines/14;i++)); do x=$((RANDOM%(cols-2)+1)); y=$((RANDOM%lines+1)); r=$((RANDOM%256)); g=$((RANDOM%256)); b=$((RANDOM%256)); em=( "✨" "💫" "⭐" "🌟" "⚡" "🔥" "🌈" "🍄" "👾" "🪐" "🌙" "☄️" "🧿" "🌀" "🔮" "💎" "🦄" "🎲" "🎯" "🧊" "🧠" "🕳️" "🧬" "🧪" "🛰️" ); ch=${em[RANDOM%${#em[@]}]}; printf '\033[%d;%dH\033[38;2;%d;%d;%dm%s\033[0m' "$y" "$x" "$r" "$g" "$b" "$ch"; done; sleep 0.05; done

ASCII Rain

while true; do printf "\033[2J"; for ((i=0;i<($(tput cols)*$(tput lines)/10);i++)); do x=$((RANDOM%$(tput cols))); y=$((RANDOM%$(tput lines))); printf "\033[${y};${x}H|"; done; sleep 0.05; done

Random Numeric Noise Screensaver (Terminal Static Effect)

while true; do printf "\033[2J"; digits=("0" "1" "2" "3" "4" "5" "6" "7" "8" "9"); num_digits=$(($(tput cols)*$(tput lines)/10)); for ((i=0;i<num_digits;i++)); do x=$((RANDOM%$(tput cols))); y=$((RANDOM%$(tput lines))); digit=${digits[$((RANDOM%${#digits[@]}))]} ; printf "\033[${y};${x}H${digit}"; done; sleep 0.05; done

Random Snowfall Screensaver (Unicode Flakes Terminal Storm)

while :; do printf "\033[2J"; a=("❄" "❅" "❆"); n=$(($(tput cols)*$(tput lines)/20)); for ((i=0;i<n;i++)); do x=$((RANDOM%$(tput cols))); y=$((RANDOM%$(tput lines))); printf "\033[${y};${x}H${a[$((RANDOM%${#a[@]}))]}"; done; sleep 0.1; done

Random Blinking Starburst Effect (ANSI Color Sparkles)

while true; do printf "\033[2J"; c=("31" "32" "33" "34" "35" "36" "37"); n=15; for ((i=0;i<n;i++)); do x=$((RANDOM%$(tput cols))); y=$((RANDOM%$(tput lines))); for r in {1..5}; do color=${c[$((RANDOM%${#c[@]}))]} ; printf "\033[${y};${x}H\033[${color}m*\033[0m"; sleep 0.05; printf "\033[${y};${x}H "; sleep 0.05; done; done; done

One-Liner Shrinking Spiral Spinner with Color Cycling and Bouncing Ball Finale

#!/usr/bin/env bash
set -euo pipefail

cleanup() {
  printf '\033[0m\033[?25h\033[2J\033[H'
}
trap cleanup INT TERM EXIT

# Hide cursor + clear
printf '\033[?25l\033[2J\033[H'

spinner=(           )
colors=(31 32 33 34 35 36 37)

n=${#spinner[@]}
m=${#colors[@]}

# Spiral bounds
sx=0; sy=0
ex=$(( $(tput cols)  - 1 ))
ey=$(( $(tput lines) - 1 ))

# Spiral cursor + direction
x=$sx; y=$sy
dx=1; dy=0

# Indices + laps
si=0; ci=0; laps=0

# Bouncing ball state (center)
bx=$((ex/2)); by=$((ey/2))
bdx=-1; bdy=-1

draw_at() { # color row col char  (row/col are 0-based)
  local co="$1" row="$2" col="$3" ch="$4"
  printf '\033[%sm\033[%d;%dH%s\033[0m' "$co" "$((row+1))" "$((col+1))" "$ch"
}

next_spiral_dir() {
  if (( x > ex )); then
    x=$ex; y=$((y+1)); dx=0;  dy=1
  elif (( y > ey )); then
    y=$ey; x=$((x-1)); dx=-1; dy=0
  elif (( x < sx )); then
    x=$sx; y=$((y-1)); dx=0;  dy=-1
  elif (( y < sy )); then
    y=$sy; x=$((x+1)); dx=1;  dy=0
  fi
}

shrink_bounds() {
  ((sx++, sy++, ex--, ey--))
  x=$sx; y=$sy
  dx=1; dy=0
}

bounce_ball() {
  while :; do
    local co="${colors[ci]}"
    draw_at "$co" "$by" "$bx" "●"

    bx=$((bx + bdx))
    by=$((by + bdy))

    (( bx <= sx || bx >= ex )) && bdx=$((-bdx))
    (( by <= sy || by >= ey )) && bdy=$((-bdy))

    sleep 0.01
    ci=$(( (ci+1) % m ))
  done
}

while :; do
  ch="${spinner[si]}"; si=$(( (si+1) % n ))
  co="${colors[ci]}";  ci=$(( (ci+1) % m ))

  draw_at "$co" "$y" "$x" "$ch"

  x=$((x + dx))
  y=$((y + dy))
  next_spiral_dir

  if (( x == sx && y == sy )); then
    laps=$((laps + 1))
    if (( laps == 5 )); then
      bounce_ball
    else
      shrink_bounds
    fi
  fi

  sleep 0.01
done

Doodle Screensaver

HEIGHT=$(tput lines)
WIDTH=$(tput cols)

while true; do
    printf "\033[2J"  # Clear the screen
    for ((i = 0; i < $((HEIGHT - 1)); i++)); do
        for ((j = 0; j < $((WIDTH - 1)); j++)); do
            if ((RANDOM % 10 == 0)); then
                printf "\033[%d;%dH" $i $j
                printf "█"
            fi
        done
    done
    sleep 0.1
done

Matrix Screensaver (run once and stop)

tput setaf 2 setab 0 civis clear
xxd -p -c1 -l $(( $(tput cols)*$(tput lines) )) /dev/urandom \
| awk -v w=$(tput cols) '{printf "%d",strtonum("0x"$1)%2; if(++n%w==0)print""}'
tput cnorm

Matrix Screensaver (forever - random colors)

xxd -p -c1 /dev/urandom \
| awk -v cols="${COLUMNS:-$(tput cols)}" '
BEGIN {
  split("32 36 92 96 37", C)
  for (i=0;i<cols;i++) col[i]=C[int(rand()*length(C))+1]
}
{
  b=strtonum("0x"$1)
  cpos = n % cols
  if (b % 8) printf " "
  else printf "\033[%sm%c\033[0m", col[cpos], 48+(b%10)
  if (++n%cols==0) print ""
}'

Matrix Screensaver (random color)

#!/bin/bash

# Get the terminal size
WIDTH=$(tput cols)
HEIGHT=$(tput lines)

# Generate random binary digits
generate_binary() {
    if ((RANDOM % 2 == 0)); then
        echo -n "0"
    else
        echo -n "1"
    fi
}

generate_color() {
    RED=$((RANDOM % 256))
    GREEN=$((RANDOM % 256))
    BLUE=$((RANDOM % 256))
    echo -ne "\033[38;2;${RED};${GREEN};${BLUE}m"
}

create_matrix_screensaver() {
    while true; do
        color=$(generate_color)
        for ((row = 0; row < HEIGHT; row++)); do
            for ((col = 0; col < WIDTH; col++)); do
                binary=$(generate_binary)
                echo -ne "$color$binary"
            done
            echo ""
        done
        sleep 0.1  # Adjust the sleep duration to control the speed
        tput cup 0 0  # Move the cursor to the top-left corner of the screen
    done
}

tput clear
tput civis

for ((i = 0; i < 10; i++)); do
    create_matrix_screensaver
    tput clear
done

tput cvvis

Full-Screen Colorized Block Matrix Screensaver

#!/bin/bash

WIDTH=$(tput cols)
HEIGHT=$(tput lines)

create_colorized_matrix_screensaver() {
    while true; do
        for ((row = 0; row < HEIGHT; row++)); do
            for ((col = 0; col < WIDTH; col++)); do
                color=$((RANDOM % 8 + 30))
                echo -ne "\033[0;"$color"m\u2588"
            done
            echo ""
        done
        sleep 0.1  # Adjust the sleep duration to control the speed
        tput cup 0 0  # Move the cursor to the top-left corner of the screen
    done
}

tput clear

tput civis

create_colorized_matrix_screensaver

Falling Characters Matrix Screensaver

#!/bin/bash

WIDTH=$(tput cols)
HEIGHT=$(tput lines)

characters=("@" "#" "$" "%" "&" "*")

create_falling_characters_matrix_screensaver() {
    while true; do
        for ((col = 0; col < WIDTH; col++)); do
            for ((row = 0; row < HEIGHT; row++)); do
                character=${characters[$((RANDOM % ${#characters[@]}))]}
                echo -ne "\033[$((row+1));$((col+1))H$character"
                sleep 0.01  
            done
        done
        tput cup 0 0
        sleep 0.5 
        tput clear  
    done
}

tput civis

create_falling_characters_matrix_screensaver

Expanding Square Rectangle Terminal Animation in Bash

#!/bin/bash

WIDTH=$(tput cols)
HEIGHT=$(tput lines)

create_expanding_matrix_screensaver() {
    for ((radius = 0; radius < WIDTH || radius < HEIGHT; radius++)); do
        for ((row = 0; row < HEIGHT; row++)); do
            for ((col = 0; col < WIDTH; col++)); do
                if ((col >= WIDTH/2 - radius && col <= WIDTH/2 + radius && row >= HEIGHT/2 - radius && row <= HEIGHT/2 + radius)); then
                    echo -ne "\u2588"
                else
                    echo -ne " "
                fi
            done
            echo ""
        done
        sleep 0.1 
        tput cup 0 0 
    done
}

tput clear
tput civis
create_expanding_matrix_screensaver

Random Block Matrix Screensaver

#!/bin/bash

WIDTH=$(tput cols)
HEIGHT=$(tput lines)

create_random_block_matrix_screensaver() {
    while true; do
        for ((row = 0; row < HEIGHT; row++)); do
            for ((col = 0; col < WIDTH; col++)); do
                if ((RANDOM % 2 == 0)); then
                    echo -ne "\u2588"
                else
                    echo -ne " "
                fi
            done
            echo ""
        done
        sleep 0.1  
        tput cup 0 0
    done
}

tput clear
tput civis
create_random_block_matrix_screensaver

Create a visually twisted effect by alternating the direction of the "staples" effect vertically.

while :; do for ((i=0;i<$(tput cols);i++));do clear;for ((j=0;j<$(tput lines);j++));do printf \
"\e[48;5;$((RANDOM%256))m%*s\e[0m\n" $(((j+i)%2?$(tput cols)-i:i)) "";done;sleep 0.05;done;done

Wobbly line

while :; do 
    printf "\e[32m%*s\e[0m" $(tput cols) $(shuf -e {0..1} -n $(($(tput lines) * $(tput cols)))); 
    sleep 0.1; 
done
while true; do 
    printf "\e[32m%*s\e[0m" $(tput cols) $(shuf -e {0..1} -n $(tput cols))
    sleep 0.1; 
done

Color filler vertically

while :; do 
    for ((i = 0; i < $(tput cols); i++)); do clear; 
    for ((j = 0; j < $(tput lines); j++)); do 
    printf "\e[48;5;$((RANDOM % 256))m%*s\e[0m\n" $i ""; 
    done; 
    sleep 0.05; 
    done; 
done

Binary screensaver

#!/bin/bash

rows=$(tput lines)
cols=$(tput cols)

while true; do
    clear
    for ((i = 0; i < rows; i++)); do
        tput cup $i $((RANDOM % cols))
        printf "%01d" $((RANDOM % 2))
    done
    sleep 0.05
done

Retro screensaver

color_codes=("31" "32" "33" "34" "35" "36")

while true; do
    clear
    for ((i = 0; i < $(tput lines); i++)); do
        tput cup $i $((RANDOM % $(tput cols)))
        color=${color_codes[$((RANDOM % ${#color_codes[@]}))]}
        printf "\033[${color}m#\033[0m"
    done
    sleep 0.1
done

Starfield screensaver

#!/bin/bash

rows=$(tput lines)
cols=$(tput cols)

while true; do
    clear
    for ((i = 0; i < rows; i++)); do
        tput cup $i $((RANDOM % cols))
        printf "*"
    done
    sleep 0.05
done

Digital clock screensaver

#!/bin/bash

rows=$(tput lines)
cols=$(tput cols)

while true; do
    clear
    tput cup $((rows / 2)) $((cols / 2 - 8))
    printf "%(%H:%M:%S)T"
    sleep 1
done

Snake Screensaver

#!/bin/bash

WIDTH=$(tput cols)
HEIGHT=$(tput lines)

snake_x=$((WIDTH / 2))
snake_y=$((HEIGHT / 2))
dx=1
dy=0

create_snake_matrix_screensaver() {
    while true; do
        tput cup $snake_y $snake_x
        echo -ne "\u2588"  # Print the snake character
        
        snake_x=$((snake_x + dx))
        snake_y=$((snake_y + dy))

        if ((snake_x <= 0 || snake_x >= WIDTH - 1 || snake_y <= 0 || snake_y >= HEIGHT - 1)); then
            snake_x=$((WIDTH / 2))
            snake_y=$((HEIGHT / 2))
        fi

        sleep 0.1
        tput clear 
    done
}

tput civis
create_snake_matrix_screensaver

Snake Screensaver v2

#!/bin/bash

WIDTH=$(tput cols)
HEIGHT=$(tput lines)

snake_x=0
snake_y=$((HEIGHT - 1))
dx=1

create_snake_screensaver() {
    while true; do
        tput clear

        tput cup $snake_y $snake_x
        echo -ne "---->"

        snake_x=$((snake_x + dx))

        # Check for wall collisions
        if ((snake_x >= WIDTH - 5)); then
            snake_x=0
        fi

        sleep 0.1 
    done
}

tput civis

create_snake_screensaver

Fish Screensaver

#!/bin/bash

WIDTH=$(tput cols)
HEIGHT=$(tput lines)

fish_x=$((WIDTH / 2))
fish_y=$((HEIGHT / 2))
dx=1
dy=1

fish_layouts=("><(((°>" "<°)))><" "><(((°>")
num_layouts=${#fish_layouts[@]}
create_fish_screensaver() {
    while true; do
        # Clear the screen
        tput clear

        layout_index=$((fish_x % num_layouts))
        fish_layout=${fish_layouts[$layout_index]}

        tput cup $fish_y $fish_x
        echo -e "$fish_layout"

        fish_x=$((fish_x + dx))
        fish_y=$((fish_y + dy))

        if ((fish_x >= WIDTH - 8)); then
            dx=-1
        elif ((fish_x <= 0)); then
            dx=1
        fi

        if ((fish_y >= HEIGHT - 1)); then
            dy=-1
        elif ((fish_y <= 0)); then
            dy=1
        fi

        sleep 0.1 
    done
}

tput civis
create_fish_screensaver

Shark hunting and eating fish

#!/bin/bash

WIDTH=$(tput cols)
HEIGHT=$(tput lines)

fish_x=$((WIDTH / 2))
fish_y=$((HEIGHT / 2))
dx=1
dy=0

shark_x=$((WIDTH / 2 - 10))
shark_y=$((HEIGHT / 2))
shark_dx=1
shark_dy=0

create_fish_screensaver() {
    while true; do
        tput clear
        tput cup $fish_y $fish_x
        echo -e "><(((°>"

        tput cup $shark_y $shark_x
        echo -e "▄▄▄▄▄▄▄▄▄▄▄▄▄▄"

        fish_x=$((fish_x + dx))
        fish_y=$((fish_y + dy))

        if ((fish_x > shark_x)); then
            shark_dx=1
        elif ((fish_x < shark_x)); then
            shark_dx=-1
        else
            shark_dx=0
        fi

        if ((fish_y > shark_y)); then
            shark_dy=1
        elif ((fish_y < shark_y)); then
            shark_dy=-1
        else
            shark_dy=0
        fi

        shark_x=$((shark_x + shark_dx))
        shark_y=$((shark_y + shark_dy))

        sleep 0.1
    done
}

tput civis
create_fish_screensaver

Shark hunting fish 2, multiple fishes

#!/bin/bash

WIDTH=$(tput cols)
HEIGHT=$(tput lines)

fish_count=5
declare -a fish_x
declare -a fish_y
declare -a fish_dx
declare -a fish_dy
for ((i = 0; i < fish_count; i++)); do
    fish_x[$i]=$((RANDOM % (WIDTH - 9) + 1))
    fish_y[$i]=$((RANDOM % (HEIGHT - 1) + 1))
    fish_dx[$i]=$((RANDOM % 2 * 2 - 1))
    fish_dy[$i]=$((RANDOM % 2 * 2 - 1))
done

shark_x=$((WIDTH / 2 - 20))
shark_y=$((HEIGHT / 2))
shark_dx=1
shark_dy=0

create_fish_screensaver() {
    while true; do
        # Clear the screen
        tput clear

        # Print the fish
        for ((i = 0; i < fish_count; i++)); do
            tput cup ${fish_y[$i]} ${fish_x[$i]}
            echo -e "><(((°>"
        done

        tput cup $shark_y $shark_x
        echo -e "▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄"
        tput cup $((shark_y + 1)) $shark_x
        echo -e "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀"

        for ((i = 0; i < fish_count; i++)); do
            fish_x[$i]=$((fish_x[$i] + fish_dx[$i]))
            fish_y[$i]=$((fish_y[$i] + fish_dy[$i]))
            if ((fish_x[$i] >= WIDTH - 9)) || ((fish_x[$i] <= 0)); then
                fish_dx[$i]=$((fish_dx[$i] * -1))
            fi
            if ((fish_y[$i] >= HEIGHT - 1)) || ((fish_y[$i] <= 0)); then
                fish_dy[$i]=$((fish_dy[$i] * -1))
            fi
        done

        shark_x=$((shark_x + shark_dx))
        shark_y=$((shark_y + shark_dy))
        if ((shark_x >= WIDTH - 10)) || ((shark_x <= 0)); then
            shark_dx=$((shark_dx * -1))
        fi
        if ((shark_y >= HEIGHT - 2)) || ((shark_y <= 0)); then
            shark_dy=$((shark_dy * -1))
        fi

        sleep 0.1 
    done
}

tput civis
create_fish_screensaver

Fishes swim around the boat

#!/bin/bash

# Get the terminal size
WIDTH=$(tput cols)
HEIGHT=$(tput lines)

# Initialize the fish positions and directions
fish_count=5
declare -a fish_x
declare -a fish_y
declare -a fish_dx
declare -a fish_dy
for ((i = 0; i < fish_count; i++)); do
    fish_x[$i]=$((RANDOM % (WIDTH - 9) + 1))
    fish_y[$i]=$((RANDOM % (HEIGHT - 1) + 1))
    fish_dx[$i]=$((RANDOM % 2 * 2 - 1))
    fish_dy[$i]=$((RANDOM % 2 * 2 - 1))
done

# Initialize the boat position and direction
boat_x=$((WIDTH / 2 - 15))
boat_y=$((HEIGHT / 2))
boat_dx=1
boat_dy=0

create_fish_screensaver() {
    while true; do
        # Clear the screen
        tput clear

        # Print the fish
        for ((i = 0; i < fish_count; i++)); do
            tput cup ${fish_y[$i]} ${fish_x[$i]}
            echo -e "><(((°>"
        done

        # Print the boat
        tput cup $boat_y $boat_x
        echo "       ____"
        tput cup $((boat_y + 1)) $boat_x
        echo "              ---|"
        tput cup $((boat_y + 2)) $boat_x
        echo "  \/            /|     \/"
        tput cup $((boat_y + 3)) $boat_x
        echo "               / |\\"
        tput cup $((boat_y + 4)) $boat_x
        echo "              /  | \\        \/"
        tput cup $((boat_y + 5)) $boat_x
        echo "             /   || \\"
        tput cup $((boat_y + 6)) $boat_x
        echo "            /    | | \\"
        tput cup $((boat_y + 7)) $boat_x
        echo "           /     | |  \\"
        tput cup $((boat_y + 8)) $boat_x
        echo "          /      | |   \\"
        tput cup $((boat_y + 9)) $boat_x
        echo "         /       ||     \\"
        tput cup $((boat_y + 10)) $boat_x
        echo "        /        /       \\"
        tput cup $((boat_y + 11)) $boat_x
        echo "       /________/         \\"
        tput cup $((boat_y + 12)) $boat_x
        echo "       ________/__________--/"
        tput cup $((boat_y + 13)) $boat_x
        echo " ~~~   \___________________/"
        tput cup $((boat_y + 14)) $boat_x
        echo "         ~~~~~~~~~~       ~~~~~~~~"
        tput cup $((boat_y + 15)) $boat_x
        echo "~~~~~~~~~~~~~     ~~~~~~~~~"
        tput cup $((boat_y + 16)) $boat_x
        echo "                               ~~~~~~~~~"

        for ((i = 0; i < fish_count; i++)); do
            fish_x[$i]=$((fish_x[$i] + fish_dx[$i]))
            fish_y[$i]=$((fish_y[$i] + fish_dy[$i]))
            if ((fish_x[$i] >= WIDTH - 9)) || ((fish_x[$i] <= 0)); then
                fish_dx[$i]=$((fish_dx[$i] * -1))
            fi
            if ((fish_y[$i] >= HEIGHT - 1)) || ((fish_y[$i] <= 0)); then
                fish_dy[$i]=$((fish_dy[$i] * -1))
            fi
        done

        boat_x=$((boat_x + boat_dx))
        boat_y=$((boat_y + boat_dy))
        if ((boat_x >= WIDTH - 34)) || ((boat_x <= 0)); then
            boat_dx=$((boat_dx * -1))
        fi
        if ((boat_y >= HEIGHT - 17)) || ((boat_y <= 0)); then
            boat_dy=$((boat_dy * -1))
        fi

        sleep 0.1
    done
}

tput civis
create_fish_screensaver

Boat + Airplane

# Get the terminal size
WIDTH=$(tput cols)
HEIGHT=$(tput lines)

# Initialize the fish positions and directions
fish_count=5
declare -a fish_x
declare -a fish_y
declare -a fish_dx
declare -a fish_dy
for ((i = 0; i < fish_count; i++)); do
        fish_x[$i]=$((RANDOM % (WIDTH - 9) + 1))
        fish_y[$i]=$((RANDOM % (HEIGHT - 1) + 1))
        fish_dx[$i]=$((RANDOM % 2 * 2 - 1))
        fish_dy[$i]=$((RANDOM % 2 * 2 - 1))
done

# Initialize the boat position and direction
boat_x=$((WIDTH / 2 - 15))
boat_y=$((HEIGHT / 2))
boat_dx=1
boat_dy=0

# Initialize the airplane position and direction
airplane_x=0
airplane_y=$((HEIGHT / 4))
airplane_dx=1
airplane_dy=0

# Create the fish screensaver
create_fish_screensaver() {
        while true; do
                # Clear the screen
                tput clear

                # Print the fish
                for ((i = 0; i < fish_count; i++)); do
                        tput cup ${fish_y[$i]} ${fish_x[$i]}
                        echo -e "><(((°>"
                done

                # Print the boat
                tput cup $boat_y $boat_x
                echo "       ____"
                tput cup $((boat_y + 1)) $boat_x
                echo "              ---|"
                tput cup $((boat_y + 2)) $boat_x
                echo "  \/            /|     \/"
                tput cup $((boat_y + 3)) $boat_x
                echo "               / |\\"
                tput cup $((boat_y + 4)) $boat_x
                echo "              /  | \\        \/"
                tput cup $((boat_y + 5)) $boat_x
                echo "             /   || \\"
                tput cup $((boat_y + 6)) $boat_x
                echo "            /    | | \\"
                tput cup $((boat_y + 7)) $boat_x
                echo "           /     | |  \\"
                tput cup $((boat_y + 8)) $boat_x
                echo "          /      | |   \\"
                tput cup $((boat_y + 9)) $boat_x
                echo "         /       ||     \\"
                tput cup $((boat_y + 10)) $boat_x
                echo "        /        /       \\"
                tput cup $((boat_y + 11)) $boat_x
                echo "       /________/         \\"
                tput cup $((boat_y + 12)) $boat_x
                echo "       ________/__________--/"
                tput cup $((boat_y + 13)) $boat_x
                echo " ~~~   \___________________/"
                tput cup $((boat_y + 14)) $boat_x
                echo "         ~~~~~~~~~~       ~~~~~~~~"
                tput cup $((boat_y + 15)) $boat_x
                echo "~~~~~~~~~~~~~     ~~~~~~~~~"
                tput cup $((boat_y + 16)) $boat_x
                echo "                               ~~~~~~~~~"

                # Print the airplane
                tput cup $airplane_y $airplane_x
                echo "             ______"
                tput cup $((airplane_y + 1)) $airplane_x
                echo "            _\\ _~-\___"
                tput cup $((airplane_y + 2)) $airplane_x
                echo "   =  = ==(__WUSEMAN__D"
                tput cup $((airplane_y + 3)) $airplane_x
                echo "                \\_____\___________________,-~~~~~~~\`-.._"
                tput cup $((airplane_y + 4)) $airplane_x
                echo "                /     o O o o o o O O o o o o o o O o  |\_"
                tput cup $((airplane_y + 5)) $airplane_x
                echo "                \`~-.__        ___..----..                  )"
                tput cup $((airplane_y + 6)) $airplane_x
                echo "                      \`---~~\\___________/------------\`\`\`\`"
                tput cup $((airplane_y + 7)) $airplane_x
                echo "                      =  ===(_________D"

                # Move the fish
                for ((i = 0; i < fish_count; i++)); do
                        fish_x[$i]=$((fish_x[$i] + fish_dx[$i]))
                        fish_y[$i]=$((fish_y[$i] + fish_dy[$i]))
                        if ((fish_x[$i] >= WIDTH - 9)) || ((fish_x[$i] <= 0)); then
                                fish_dx[$i]=$((fish_dx[$i] * -1))
                        fi
                        if ((fish_y[$i] >= HEIGHT - 1)) || ((fish_y[$i] <= 0)); then
                                fish_dy[$i]=$((fish_dy[$i] * -1))
                        fi
                done

                # Move the boat
                boat_x=$((boat_x + boat_dx))
                boat_y=$((boat_y + boat_dy))
                if ((boat_x >= WIDTH - 34)) || ((boat_x <= 0)); then
                        boat_dx=$((boat_dx * -1))
                fi
                if ((boat_y >= HEIGHT - 17)) || ((boat_y <= 0)); then
                        boat_dy=$((boat_dy * -1))
                fi

                # Move the airplane
                airplane_x=$((airplane_x + airplane_dx))
                airplane_y=$((airplane_y + airplane_dy))
                if ((airplane_x >= WIDTH - 23)) || ((airplane_x <= 0)); then
                        airplane_dx=$((airplane_dx * -1))
                fi
                if ((airplane_y >= HEIGHT / 2 - 7)) || ((airplane_y <= 0)); then
                        airplane_dy=$((airplane_dy * -1))
                fi

                sleep 0.1 # Adjust the sleep duration to control the speed
        done
}

# Hide the cursor
tput civis

# Create the fish screensaver
create_fish_screensaver

Bouncing dvd logo screensaving using tput and bash

set -u

cleanup(){ tput cnorm; tput sgr0; clear; }
trap cleanup EXIT INT TERM

tput civis
clear

logo="DVD"
dx=1; dy=1
x=0; y=0

while :; do
  W=$(tput cols)
  H=$(tput lines)

  # erase previous
  tput cup "$y" "$x"; printf "%*s" "${#logo}" ""

  x=$((x + dx))
  y=$((y + dy))

  (( x <= 0 )) && dx=1
  (( y <= 0 )) && dy=1
  (( x >= W - ${#logo} )) && dx=-1
  (( y >= H - 1 )) && dy=-1

  tput cup "$y" "$x"
  tput setaf $((RANDOM % 7 + 1))
  printf "%s" "$logo"
  tput sgr0

  sleep 0.03
done

ANSI color spiral screensaver in bash

#!/usr/bin/env bash
WIDTH=$(tput cols)
HEIGHT=$(tput lines)

characters=('@' '#' '$' '%' '&' '*')

cleanup(){ tput cnorm; tput sgr0; clear; }
trap cleanup INT TERM EXIT

tput civis
tput clear

while :; do
  top=0; left=0; bottom=$((HEIGHT-1)); right=$((WIDTH-1))

  while (( top <= bottom && left <= right )); do
    # top row: left -> right
    for ((c=left; c<=right; c++)); do
      ch=${characters[RANDOM % ${#characters[@]}]}
      color=$((RANDOM % 256))
      printf '\033[%d;%dH\033[38;5;%dm%s\033[0m' \
        $((top+1)) $((c+1)) "$color" "$ch"
      sleep 0.001
    done
    ((top++))

    # right col: top -> bottom
    for ((r=top; r<=bottom; r++)); do
      ch=${characters[RANDOM % ${#characters[@]}]}
      color=$((RANDOM % 256))
      printf '\033[%d;%dH\033[38;5;%dm%s\033[0m' \
        $((r+1)) $((right+1)) "$color" "$ch"
      sleep 0.001
    done
    ((right--))

    # bottom row: right -> left
    if (( top <= bottom )); then
      for ((c=right; c>=left; c--)); do
        ch=${characters[RANDOM % ${#characters[@]}]}
        color=$((RANDOM % 256))
        printf '\033[%d;%dH\033[38;5;%dm%s\033[0m' \
          $((bottom+1)) $((c+1)) "$color" "$ch"
        sleep 0.001
      done
      ((bottom--))
    fi

    # left col: bottom -> top
    if (( left <= right )); then
      for ((r=bottom; r>=top; r--)); do
        ch=${characters[RANDOM % ${#characters[@]}]}
        color=$((RANDOM % 256))
        printf '\033[%d;%dH\033[38;5;%dm%s\033[0m' \
          $((r+1)) $((left+1)) "$color" "$ch"
        sleep 0.001
      done
      ((left++))
    fi
  done

  # start over (optional)
  sleep 0.2
  tput cup 0 0
done

Animated Terminal Aquarium with Submarine, Fish, UFO, and Particle Effects

cleanup() { tput cnorm; tput sgr0; clear; }
trap cleanup EXIT INT TERM

tput civis
tput sgr0
clear

# ---------- helpers ----------
rand_color() {
  # bright-ish ANSI colors
  local colors=(31 32 33 34 35 36 91 92 93 94 95 96 97)
  printf "\033[%sm" "${colors[RANDOM % ${#colors[@]}]}"
}

draw_art() {
  # draw multi-line art at (y,x)
  local y="$1" x="$2"; shift 2
  local i=0
  for line in "$@"; do
    tput cup $((y+i)) "$x"
    printf "%s" "$line"
    ((i++))
  done
}

clamp() { # clamp val min max
  local v="$1" lo="$2" hi="$3"
  (( v < lo )) && v="$lo"
  (( v > hi )) && v="$hi"
  printf "%s" "$v"
}

# ---------- terminal size ----------
W=$(tput cols)
H=$(tput lines)

# ---------- entities ----------
fish_count=9
declare -a fx fy fdx

# fish glyphs (right/left)
fish_r=("><(((°>" "><>" ">))'>" ">°)))>" ">===>")
fish_l=("<°)))><" "<><" "<'((<" "<)))°<" "<===<")

for ((i=0; i<fish_count; i++)); do
  fx[$i]=$((RANDOM % (W-12) + 1))
  fy[$i]=$((RANDOM % (H-6) + 3))
  fdx[$i]=$(( (RANDOM % 2) ? 1 : -1 ))
done

# submarine
sub_x=$((W/3))
sub_y=$((H*2/3))
sub_dx=1
sub_w=24
sub_h=4

# ufo
ufo_x=$((W/2))
ufo_y=$((H/6))
ufo_dx=-1
ufo_w=19
ufo_h=3
beam_on=1

# bubbles (particle system)
bubble_max=40
declare -a bx by bdy bch bactive
for ((i=0;i<bubble_max;i++)); do bactive[$i]=0; done

spawn_bubble() {
  for ((i=0;i<bubble_max;i++)); do
    if (( bactive[$i] == 0 )); then
      bactive[$i]=1
      bx[$i]="$1"
      by[$i]="$2"
      bdy[$i]=$(( (RANDOM % 2) + 1 ))
      local chars=( "o" "°" "." "•" )
      bch[$i]="${chars[RANDOM % ${#chars[@]}]}"
      return
    fi
  done
}

# lightning timer
flash=0
flash_t=$((RANDOM % 120 + 80))

# ---------- art ----------
# keep lines same widths (avoid terminal jitter)
sub_lines=(
"        |\\"
" _______|_\\______"
"|  __  __  __   _\\__"
"\\__(_)__(_)__(_)____/"
)

ufo_lines=(
"    _.-^-._"
" .-'  ___  '-."
"(_.-'     '-._)"
)

# waves: animate by phase (two patterns)
wave1="~  ~~   ~~~~  ~~   ~  ~~~   ~~~~  ~~  ~ "
wave2=" ~~  ~~~~   ~~  ~  ~~  ~~~~   ~~  ~  ~~"

# ---------- main loop ----------
while :; do
  # refresh size for resize
  W=$(tput cols); H=$(tput lines)

  # background ocean + sky split
  sky_h=$((H/3))
  sea_top=$((sky_h))
  sea_h=$((H - sea_top))

  # lightning flash logic
  ((flash_t--))
  if (( flash_t <= 0 )); then
    flash=1
    flash_t=$((RANDOM % 160 + 120))
  else
    flash=0
  fi

  # clear frame
  tput cup 0 0
  if (( flash )); then
    printf "\033[47m\033[30m"   # white bg, black fg
  else
    printf "\033[0m"
  fi
  tput clear

  # draw stars in sky
  for ((s=0; s< (W/10); s++)); do
    tput cup $((RANDOM % (sky_h>1?sky_h:1))) $((RANDOM % W))
    printf "%s" "*"
  done

  # waves (two moving lines)
  phase=$((RANDOM % 2))
  tput sgr0
  tput setaf 36
  tput cup "$sea_top" 0
  printf "%.*s" "$W" "$wave1$wave2$wave1$wave2"
  tput cup $((sea_top+1)) 0
  printf "%.*s" "$W" "$wave2$wave1$wave2$wave1"
  tput sgr0

  # submarine (colored)
  sub_y=$(clamp "$sub_y" $((sea_top+2)) $((H-sub_h-2)))
  sub_x=$(clamp "$sub_x" 1 $((W-sub_w-2)))

  tput sgr0
  tput setaf 33
  draw_art "$sub_y" "$sub_x" "${sub_lines[@]}"
  tput sgr0

  # bubbles near sub (spawn a few each frame)
  if (( RANDOM % 2 == 0 )); then
    spawn_bubble $((sub_x + 8 + (RANDOM%6))) $((sub_y + 0))
  fi
  if (( RANDOM % 4 == 0 )); then
    spawn_bubble $((sub_x + 14 + (RANDOM%6))) $((sub_y + 1))
  fi

  # fish school
  for ((i=0; i<fish_count; i++)); do
    # pick fish glyph based on direction
    idx=$((RANDOM % ${#fish_r[@]}))
    if (( fdx[$i] > 0 )); then
      glyph="${fish_r[$idx]}"
    else
      glyph="${fish_l[$idx]}"
    fi

    # keep fish in sea
    (( fy[$i] < sea_top+2 )) && fy[$i]=$((sea_top+2))
    (( fy[$i] > H-2 )) && fy[$i]=$((H-2))
    (( fx[$i] < 0 )) && fx[$i]=0
    (( fx[$i] > W-10 )) && fx[$i]=$((W-10))

    tput cup "${fy[$i]}" "${fx[$i]}"
    rand_color
    printf "%s\033[0m" "$glyph"

    # move fish
    fx[$i]=$((fx[$i] + fdx[$i] * ( (RANDOM%2) + 1 )))
    # little vertical drift
    (( RANDOM % 6 == 0 )) && fy[$i]=$((fy[$i] + (RANDOM%3 - 1)))

    # bounce edges
    if (( fx[$i] >= W-10 )); then fdx[$i]=-1; fi
    if (( fx[$i] <= 0 )); then fdx[$i]=1; fi
  done

  # UFO in sky with beam
  ufo_x=$((ufo_x + ufo_dx))
  if (( ufo_x <= 0 )); then ufo_dx=1; fi
  if (( ufo_x >= W-ufo_w )); then ufo_dx=-1; fi
  ufo_y=$(clamp "$ufo_y" 1 $((sky_h-3)))

  # toggle beam sometimes
  (( RANDOM % 25 == 0 )) && beam_on=$((1-beam_on))

  tput sgr0
  tput setaf 35
  draw_art "$ufo_y" "$ufo_x" "${ufo_lines[@]}"
  tput sgr0

  if (( beam_on )); then
    tput setaf 96
    # beam down into sea top
    for ((yy=ufo_y+3; yy<sea_top; yy++)); do
      tput cup "$yy" $((ufo_x + 8))
      printf "|"
    done
    tput sgr0
  fi

  # animate bubbles
  for ((i=0;i<bubble_max;i++)); do
    (( bactive[$i] == 0 )) && continue
    # draw bubble
    if (( by[$i] > 1 )); then
      tput cup "${by[$i]}" "${bx[$i]}"
      tput setaf 97
      printf "%s" "${bch[$i]}"
      tput sgr0
    fi
    # move bubble up with slight horizontal drift
    by[$i]=$((by[$i] - bdy[$i]))
    (( RANDOM % 5 == 0 )) && bx[$i]=$((bx[$i] + (RANDOM%3 - 1)))
    # deactivate if out of screen or into sky
    if (( by[$i] <= sea_top+1 || bx[$i] < 0 || bx[$i] >= W )); then
      bactive[$i]=0
    fi
  done

  # move submarine
  sub_x=$((sub_x + sub_dx))
  if (( sub_x <= 1 )); then sub_dx=1; fi
  if (( sub_x >= W-sub_w-2 )); then sub_dx=-1; fi
  # subtle bobbing
  (( RANDOM % 10 == 0 )) && sub_y=$((sub_y + (RANDOM%3 - 1)))

  # footer hint (optional)
  tput cup $((H-1)) 0
  tput sgr0
  printf "AQUARIUM RAID  |  Ctrl+C to exit  "

  sleep 0.06
done

Colorful Bouncing “W” Screensaver with Bounce Counter in Bash

ROWS=$(tput lines)
COLS=$(tput cols)

tput civis

trap "tput cnorm; exit" SIGINT

symbols=("@" "#" "%" "&" "*" "+" "-" "=" "!" "?" "/" "\\" "|" "(" ")" "[" "]" "{" "}" "<" ">" "^" "~" "," "." ":" ";" " ")

function random_color() {
        local color_code="\e["
        local colors=("31m" "32m" "33m" "34m" "35m" "36m" "91m" "92m" "93m" "94m" "95m" "96m")
        echo -n "${color_code}${colors[$((RANDOM % ${#colors[@]}))]}"
}

function get_w_char() {
        local col=$1
        local middle_col=$((COLS / 2))
        local symbol=${symbols[$((RANDOM % ${#symbols[@]}))]}
        local color_code=${color_codes[$color_index]}

        if [ $col -eq 0 ] || [ $col -eq $((COLS - 1)) ]; then
                echo -ne "\e[0m${symbol}"
        elif [ $col -lt $middle_col ] && [ $col -gt 0 ]; then
                local distance=$((middle_col - col))
                if [ $((distance % 2)) -eq 0 ]; then
                        echo -ne "${color_code}${symbol}"
                else
                        echo -ne "${color_code}${symbol}"
                fi
        elif [ $col -eq $middle_col ]; then
                echo -ne "${color_code}${symbol}"
        else
                local distance=$((col - middle_col))
                if [ $((distance % 2)) -eq 0 ]; then
                        echo -ne "${color_code}${symbol}"
                else
                        echo -ne "${color_code}${symbol}"
                fi
        fi
}

function display_bounce_counter() {
        local counter=$1
        local message="Bounces: $counter"
        local message_length=${#message}
        local center_row=$((ROWS / 2))
        local center_col=$((COLS / 2 - message_length / 2))
        tput cup $center_row $center_col
        echo -n "$message"
}

function clear_screen() {
        tput reset
}

function move_cursor() {
        local row=$1
        local col=$2
        tput cup $row $col
}

function screensaver() {
        local x=0
        local y=0
        local direction_x=1
        local direction_y=1
        local bounce_counter=0

        local stop_x=$((COLS / 2))
        local stop_y=$((ROWS / 2))

        local color_codes=()
        local color_index=0
        local sleep_duration=0.03
        local direction_change_timer=0
        local max_direction_change_time=20

        while true; do
                color_codes+=($(random_color))

                move_cursor $y $x
                echo -n "$(get_w_char $x)"
                sleep $sleep_duration

                x=$((x + direction_x))
                y=$((y + direction_y))

                if [ $x -eq $stop_x ] && [ $y -eq $stop_y ]; then
                        sleep 0.2
                        direction_x=$((direction_x * -1))
                        direction_y=$((direction_y * -1))
                        color_index=$((color_index + 1))
                        sleep_duration=$(awk -v sleep_duration="$sleep_duration" 'BEGIN {print sleep_duration * 0.8}')
                        ((bounce_counter++))
                        display_bounce_counter $bounce_counter

                        ((direction_change_timer++))
                        if [ $direction_change_timer -ge $max_direction_change_time ]; then
                                direction_x=$((RANDOM % 3 - 1))
                                direction_y=$((RANDOM % 3 - 1))
                                direction_change_timer=0
                        fi
                fi

                if [ $x -ge $((COLS - 1)) ] || [ $x -le 0 ]; then
                        direction_x=$((direction_x * -1))
                        color_index=$((color_index + 1))
                        sleep_duration=$(awk -v sleep_duration="$sleep_duration" 'BEGIN {print sleep_duration * 0.8}')
                        ((bounce_counter++))
                        display_bounce_counter $bounce_counter
                fi

                if [ $y -ge $((ROWS - 1)) ] || [ $y -le 0 ]; then
                        direction_y=$((direction_y * -1))
                        color_index=$((color_index + 1))
                        sleep_duration=$(awk -v sleep_duration="$sleep_duration" 'BEGIN {print sleep_duration * 0.8}')
                        ((bounce_counter++))
                        display_bounce_counter $bounce_counter
                fi

                if [ $color_index -ge ${#color_codes[@]} ]; then
                        color_index=0
                fi
        done
}

screensaver

Expanding Rainbow Circle Effect Inside a Unicode Box (Bash + tput)

columns=$(tput cols)
lines=$(tput lines)

clear_screen() {
        tput clear
}

draw_box() {
        local top_left_corner="┌"
        local top_right_corner="┐"
        local bottom_left_corner="└"
        local bottom_right_corner="┘"
        local horizontal_line="─"
        local vertical_line="│"

        local start_x=3
        local start_y=3
        local end_x=$((columns - 1))
        local end_y=$((lines - 1))

        tput cup $start_y $start_x
        echo -n "$top_left_corner"
        tput cup $start_y $end_x
        echo -n "$top_right_corner"
        tput cup $end_y $start_x
        echo -n "$bottom_left_corner"
        tput cup $end_y $end_x
        echo -n "$bottom_right_corner"

        for ((i = $((start_x + 1)); i < end_x; i++)); do
                tput cup $start_y $i
                echo -n "$horizontal_line"
                tput cup $end_y $i
                echo -n "$horizontal_line"
        done

        for ((i = $((start_y + 1)); i < end_y; i++)); do
                tput cup $i $start_x
                echo -n "$vertical_line"
                tput cup $i $end_x
                echo -n "$vertical_line"
        done
}

generate_effect() {
        local colors=("31" "32" "33" "34" "35" "36" "37")
        local num_colors=${#colors[@]}
        local cx=$((columns / 2))
        local cy=$((lines / 2))
        local r=1
        local symbol="●"
        local color_index=0

        while true; do
                local color=${colors[$color_index]}
                color_index=$(((color_index + 1) % num_colors))

                local x=0
                local y=$r
                local d=$((5 - 4 * r))
                while ((x <= y)); do
                        tput cup $((cy - y)) $((cx + x))
                        printf "\033[${color}m${symbol}\033[0m"
                        tput cup $((cy - x)) $((cx + y))
                        printf "\033[${color}m${symbol}\033[0m"
                        tput cup $((cy - x)) $((cx - y))
                        printf "\033[${color}m${symbol}\033[0m"
                        tput cup $((cy - y)) $((cx - x))
                        printf "\033[${color}m${symbol}\033[0m"
                        tput cup $((cy + y)) $((cx - x))
                        printf "\033[${color}m${symbol}\033[0m"
                        tput cup $((cy + x)) $((cx - y))
                        printf "\033[${color}m${symbol}\033[0m"
                        tput cup $((cy + x)) $((cx + y))
                        printf "\033[${color}m${symbol}\033[0m"
                        tput cup $((cy + y)) $((cx + x))
                        printf "\033[${color}m${symbol}\033[0m"

                        if ((d >= 0)); then
                                d=$((d + 8 * (x - y) + 12))
                                y=$((y - 1))
                        else
                                d=$((d + 8 * x + 8))
                        fi
                        x=$((x + 1))
                done

                sleep 0.1

                r=$((r + 1))
                if ((cx - r <= 0 || cx + r >= columns || cy - r <= 0 || cy + r >= lines)); then
                        break
                fi
        done
}

while true; do
        clear_screen
        draw_box
        generate_effect
done

Rainbow Spiral Rectangle Walker Animation (Bash ANSI Cursor Drawing)

clear_screen() {
printf "\033[2J"
}

generate_effect() {
    local colors=("31" "32" "33" "34" "35" "36" "37")
    local num_colors=${#colors[@]}
    local x=$(tput cols)/2
    local y=$(tput lines)/2
    local dx=1 dy=0 step=1 color_index=0 symbol="●"

    while :; do
        local color=${colors[color_index]}
        color_index=$(( (color_index + 1) % num_colors ))

        printf "\033[${color}m\033[${y};${x}H${symbol}\033[0m"

        x=$((x + dx))
        y=$((y + dy))

        if ((x <= 0 || x >= $(tput cols) || y <= 0 || y >= $(tput lines))); then
            break
        fi

        sleep 0.01

        ((step_count++))

        if ((step_count == step)); then
            step_count=0
            case "$dx $dy" in
                "1 0") dx=0; dy=1 ;;
                "0 1") dx=-1; dy=0; ((step++)) ;;
                "-1 0") dx=0; dy=-1 ;;
                "0 -1") dx=1; dy=0; ((step++)) ;;
            esac
        fi
    done
}

while :; do
    clear_screen
    generate_effect
done

Rainbow Spinner Border Animation That Collapses Inward, Then Switches to a Bouncing Ball

# Set terminal dimensions
columns=$(tput cols)
lines=$(tput lines)

# Function to clear the screen
clear_screen() {
    printf "\033[2J"
}

# Function to generate a spinner effect with changing colors
generate_effect() {
    local spinner=("◐" "◓" "◑" "◒" "⣾" "⣽" "⣻" "⢿" "⡿" "⣟" "⣯" "⣷")  # Characters for the spinner
    local colors=("31" "32" "33" "34" "35" "36" "37")  # ANSI escape codes for text colors
    local num_spinner=${#spinner[@]}  # Number of characters in the spinner
    local num_colors=${#colors[@]}  # Number of colors

    local start_x=0
    local start_y=0
    local end_x=$((columns - 1))
    local end_y=$((lines - 1))

    local x=$start_x
    local y=$start_y
    local dx=1
    local dy=0
    local spinner_index=0
    local color_index=0
    local corner_count=0
    local ball_x=$((columns / 2))
    local ball_y=$((lines / 2))
    local ball_dx=-1
    local ball_dy=-1

    while true
    do
        # Get the current character from the spinner
        local char=${spinner[$spinner_index]}
        spinner_index=$(( (spinner_index + 1) % num_spinner ))

        # Get the current color
        local color=${colors[$color_index]}
        color_index=$(( (color_index + 1) % num_colors ))

        # Print the colored character at the current position
        printf "\033[${color}m\033[${y};${x}H${char}\033[0m"

        # Update position
        x=$((x + dx))
        y=$((y + dy))

        # Check for reaching the end of each side and adjust direction accordingly
        if ((x > end_x))
        then
            x=$end_x
            y=$((y + 1))
            dx=0
            dy=1
        elif ((y > end_y))
        then
            x=$((x - 1))
            y=$end_y
            dx=-1
            dy=0
        elif ((x < start_x))
        then
            x=$start_x
            y=$((y - 1))
            dx=0
            dy=-1
        elif ((y < start_y))
        then
            x=$((x + 1))
            y=$start_y
            dx=1
            dy=0
        fi

        # Check for completing the full circle
        if ((x == start_x && y == start_y))
        then
            corner_count=$((corner_count + 1))

            if ((corner_count == 5))
            then
                while true
                do
                    # Print the colored ball at the current position
                    printf "\033[${color}m\033[${ball_y};${ball_x}H●\033[0m"

                    # Update ball position
                    ball_x=$((ball_x + ball_dx))
                    ball_y=$((ball_y + ball_dy))

                    # Check for bouncing off the walls
                    if ((ball_x <= start_x || ball_x >= end_x))
                    then
                        ball_dx=$((ball_dx * -1))
                    fi
                    if ((ball_y <= start_y || ball_y >= end_y))
                    then
                        ball_dy=$((ball_dy * -1))
                    fi

                    sleep 0.01  # Adjust the sleep duration to control the speed of the effect
                done
            else
                start_x=$((start_x + 1))
                start_y=$((start_y + 1))
                end_x=$((end_x - 1))
                end_y=$((end_y - 1))
                x=$((start_x))
                y=$((start_y))
            fi
        fi

        sleep 0.01  # Adjust the sleep duration to control the speed of the effect
    done
}

# Main loop
while true
do
    clear_screen
    generate_effect
done

Multi-Effect Terminal Animation Suite (Spinner + Bouncing Ball + Pulsating Heart)

# Set terminal dimensions
columns=$(tput cols)
lines=$(tput lines)

# Function to clear the screen
clear_screen() {
    printf "\033[2J"
}

# Function to generate a rotating spinner effect with changing colors
generate_spinner_effect() {
    local spinner=("◐" "◓" "◑" "◒")  # Characters for the spinner
    local colors=("31" "32" "33" "34" "35" "36" "37")  # ANSI escape codes for text colors
    local num_spinner=${#spinner[@]}  # Number of characters in the spinner
    local num_colors=${#colors[@]}  # Number of colors

    local x=$((columns / 2))
    local y=$((lines / 2))
    local spinner_index=0
    local color_index=0

    while true
    do
        # Get the current character from the spinner
        local char=${spinner[$spinner_index]}
        spinner_index=$(( (spinner_index + 1) % num_spinner ))

        # Get the current color
        local color=${colors[$color_index]}
        color_index=$(( (color_index + 1) % num_colors ))

        # Print the colored character at the current position
        printf "\033[${color}m\033[${y};${x}H${char}\033[0m"

        sleep 0.1  # Adjust the sleep duration to control the speed of the effect
    done
}

# Function to generate a bouncing ball effect with a changing color
generate_bouncing_ball_effect() {
    local ball=("●")  # Character for the ball
    local colors=("31" "32" "33" "34" "35" "36" "37")  # ANSI escape codes for text colors
    local num_colors=${#colors[@]}  # Number of colors

    local x=$((columns / 2))
    local y=$((lines / 2))
    local dx=1
    local dy=1
    local color_index=0

    while true
    do
        # Get the current color
        local color=${colors[$color_index]}
        color_index=$(( (color_index + 1) % num_colors ))

        # Print the colored ball at the current position
        printf "\033[${color}m\033[${y};${x}H${ball}\033[0m"

        # Update position
        x=$((x + dx))
        y=$((y + dy))

        # Reverse direction if the ball reaches the edge of the screen
        if ((x <= 0 || x >= columns))
        then
            dx=$((dx * -1))
        fi
        if ((y <= 0 || y >= lines))
        then
            dy=$((dy * -1))
        fi

        sleep 0.01  # Adjust the sleep duration to control the speed of the effect
    done
}

# Function to generate a pulsating heart effect with changing colors
generate_pulsating_heart_effect() {
    local heart=("❤")  # Character for the heart
    local colors=("31" "32" "33" "34" "35" "36" "37")  # ANSI escape codes for text colors
    local num_colors=${#colors[@]}  # Number of colors

    local x=$((columns / 2))
    local y=$((lines / 2))
    local scale=10
    local color_index=0

    while true
    do
        # Get the current color
        local color=${colors[$color_index]}
        color_index=$(( (color_index + 1) % num_colors ))

        # Scale the heart based on the current scale value
        local scaled_heart=""
        for ((i = 0; i < scale; i++))
        do
            scaled_heart+=" $heart"
        done

        # Print the colored and scaled heart at the current position
        printf "\033[${color}m\033[${y};${x}H${scaled_heart}\033[0m"

        # Update the scale to create the pulsating effect
        scale=$(( (scale + 1) % 20 + 1 ))

        sleep 0.1  # Adjust the sleep duration to control the speed of the effect
    done
}

# Main loop
while true
do
    clear_screen

    generate_spinner_effect &
    spinner_pid=$!

    generate_bouncing_ball_effect &
    ball_pid=$!

    generate_pulsating_heart_effect &
    heart_pid=$!

    # Wait for user input to stop the animations
    read -n 1 -r

    # Terminate the background processes
    kill $spinner_pid $ball_pid $heart_pid
done

Framed Matrix Rain Hex Wall (Green Digits Inside a Terminal Border)

# Set terminal dimensions
columns=$(tput cols)
lines=$(tput lines)

# Wall dimensions
wall_start_x=10
wall_start_y=5
wall_end_x=$((columns - 10))
wall_end_y=$((lines - 5))

# Array of characters for matrix rain
characters=("0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "A" "B" "C" "D" "E" "F")

# Initialize an array to store the column position of each raindrop
declare -a drops

# Function to clear the screen
clear_screen() {
    printf "\033[2J"
}

# Function to draw the wall
draw_wall() {
    local x
    local y

    # Draw the top level of the wall
    for ((x = wall_start_x; x <= wall_end_x; x++))
    do
        printf "\033[${wall_start_y};${x}H="
    done

    # Draw the bottom level of the wall
    for ((x = wall_start_x; x <= wall_end_x; x++))
    do
        printf "\033[${wall_end_y};${x}H="
    done

    # Draw the left side of the wall
    for ((y = wall_start_y + 1; y < wall_end_y; y++))
    do
        printf "\033[${y};${wall_start_x}H|"
    done

    # Draw the right side of the wall
    for ((y = wall_start_y + 1; y < wall_end_y; y++))
    do
        printf "\033[${y};${wall_end_x}H|"
    done
}

# Function to generate the matrix rain effect inside the wall
generate_effect() {
    local num_drops=$(( (wall_end_x - wall_start_x) / 2 ))  # Number of raindrops to generate

    # Initialize the position of each raindrop randomly inside the wall
    for ((i = 0; i < num_drops; i++))
    do
        drops[$i]=$(( (RANDOM % (wall_end_y - wall_start_y - 2)) + wall_start_y + 1 ))
    done

    while true
    do
        # Update the position of each raindrop and print it
        for ((i = 0; i < num_drops; i++))
        do
            local x=$((i * 2 + wall_start_x + 1))  # Each raindrop occupies two columns inside the wall

            # Print the raindrop in green color
            printf "\033[32m\033[${drops[$i]};${x}H${characters[$((RANDOM % 16))]}"

            # Update the position of the raindrop
            drops[$i]=$((drops[$i] + 1))

            # Reset the raindrop to the top if it reaches the bottom of the wall
            if ((drops[$i] >= wall_end_y))
            then
                drops[$i]=$((wall_start_y + 1))
            fi
        done

        sleep 0.05  # Adjust the sleep duration to control the speed of the effect
    done
}

# Main loop
while true
do
    clear_screen
    draw_wall
    generate_effect
done

Colored Shooting Stars Screensaver (Randomized ANSI Sparkle Trails)

# Clear the screen
clear

# Get the terminal size
rows=$(tput lines)
cols=$(tput cols)

# Define the shooting star characters and colors
SHOOTING_STAR_CHARACTERS=("✦" "✧" "✶" "✴" "✹" "✷")
SHOOTING_STAR_COLORS=("196" "202" "208" "214" "220" "226")

# Define the maximum number of shooting stars
MAX_SHOOTING_STARS=10

# Array to store the shooting stars
shooting_stars=()

# Function to generate a random number within a range
generate_random_number() {
    min=$1
    max=$2
    echo $((RANDOM % (max - min + 1) + min))
}

# Function to generate a random shooting star
generate_random_shooting_star() {
    row=$(generate_random_number 1 $rows)
    col=$(generate_random_number 1 $cols)
    speed=$(generate_random_number 5 10)
    echo "$row:$col:$speed"
}

# Generate initial shooting stars
for ((i=0; i<MAX_SHOOTING_STARS; i++)); do
    shooting_stars[$i]=$(generate_random_shooting_star)
done

# Function to update the shooting stars
update_shooting_stars() {
    updated_stars=()

    for star in "${shooting_stars[@]}"; do
        IFS=':' read -ra star_info <<< "$star"
        row="${star_info[0]}"
        col="${star_info[1]}"
        speed="${star_info[2]}"

        tput cup "$row" "$col"
        echo " "

        new_row=$((row + speed))
        new_col=$((col + (speed / 2)))

        if ((new_row > rows)); then
            updated_stars+=($(generate_random_shooting_star))
        else
            updated_stars+=("$new_row:$new_col:$speed")
        fi
    done

    shooting_stars=("${updated_stars[@]}")
}

while true; do
    update_shooting_stars

    # Print the shooting stars
    for star in "${shooting_stars[@]}"; do
        IFS=':' read -ra star_info <<< "$star"
        row="${star_info[0]}"
        col="${star_info[1]}"
        color="${SHOOTING_STAR_COLORS[$((RANDOM % ${#SHOOTING_STAR_COLORS[@]}))]}"

        # Print the shooting star at its current position with the random color
        tput setaf "$color"
        tput cup "$row" "$col"
        echo -ne "${SHOOTING_STAR_CHARACTERS[$((RANDOM % ${#SHOOTING_STAR_CHARACTERS[@]}))]}"
        tput sgr0
    done

    # Delay between frames (adjust as needed for desired speed)
    sleep 0.1
done

Simple Shooting Star Screensaver (Diagonal Starfall Animation)

#!/bin/bash

# Clear the screen
clear

# Get the terminal size
rows=$(tput lines)
cols=$(tput cols)

# Define the shooting star character
SHOOTING_STAR_CHARACTER="✦"

# Define the maximum number of shooting stars
MAX_SHOOTING_STARS=10

# Array to store the shooting stars
shooting_stars=()

# Function to generate a random number within a range
generate_random_number() {
    min=$1
    max=$2
    echo $((RANDOM % (max - min + 1) + min))
}

# Function to generate a random shooting star
generate_random_shooting_star() {
    row=$(generate_random_number 1 $rows)
    col=$(generate_random_number 1 $cols)
    speed=$(generate_random_number 5 10)
    echo "$row:$col:$speed"
}

# Generate initial shooting stars
for ((i=0; i<MAX_SHOOTING_STARS; i++)); do
    shooting_stars[$i]=$(generate_random_shooting_star)
done

# Function to update the shooting stars
update_shooting_stars() {
    updated_stars=()

    # Update each shooting star's position
    for star in "${shooting_stars[@]}"; do
        IFS=':' read -ra star_info <<< "$star"
        row="${star_info[0]}"
        col="${star_info[1]}"
        speed="${star_info[2]}"

        # Clear the previous shooting star position
        tput cup "$row" "$col"
        echo " "

        # Calculate the new position for the shooting star
        new_row=$((row + speed))
        new_col=$((col + (speed / 2)))

        # Check if the shooting star has reached the bottom of the screen
        if ((new_row > rows)); then
            # Regenerate a new shooting star
            updated_stars+=($(generate_random_shooting_star))
        else
            # Add the updated shooting star position to the updated_stars array
            updated_stars+=("$new_row:$new_col:$speed")
        fi
    done

    # Update the shooting stars array with the new positions
    shooting_stars=("${updated_stars[@]}")
}

# Main loop
while true; do
    # Update the shooting stars
    update_shooting_stars

    # Print the shooting stars
    for star in "${shooting_stars[@]}"; do
        IFS=':' read -ra star_info <<< "$star"
        row="${star_info[0]}"
        col="${star_info[1]}"

        # Print the shooting star at its current position
        tput cup "$row" "$col"
        echo -ne "$SHOOTING_STAR_CHARACTER"
    done

    # Delay between frames (adjust as needed for desired speed)
    sleep 0.1
done

Random Starfield Drift Screensaver (Twinkling Unicode Stars)

#!/bin/bash

# Clear the screen
clear

# Get the terminal size
rows=$(tput lines)
cols=$(tput cols)

# Define the star characters
STAR_CHARACTERS=("✦" "✧" "★" "☆" "✶" "✷" "✸" "✹" "✺" "✻" "✼" "❉" "❋" "❂")

# Define the maximum number of stars
MAX_STARS=50

# Function to generate a random number within a range
generate_random_number() {
    min=$1
    max=$2
    echo $((RANDOM % (max - min + 1) + min))
}

# Function to generate a random star
generate_random_star() {
    row=$(generate_random_number 1 $rows)
    col=$(generate_random_number 1 $cols)
    character=${STAR_CHARACTERS[$((RANDOM % ${#STAR_CHARACTERS[@]}))]}
    echo "$row:$col:$character"
}

# Array to store the stars
stars=()

# Generate initial stars
for ((i=0; i<MAX_STARS; i++)); do
    stars[$i]=$(generate_random_star)
done

# Function to update the stars
update_stars() {
    updated_stars=()

    # Update each star's position
    for star in "${stars[@]}"; do
        IFS=':' read -ra star_info <<< "$star"
        row="${star_info[0]}"
        col="${star_info[1]}"
        character="${star_info[2]}"

        # Clear the previous star position
        tput cup "$row" "$col"
        echo " "

        # Generate new position for the star
        new_row=$((row + $(generate_random_number -1 1)))
        new_col=$((col + $(generate_random_number -1 1)))

        # Wrap the star around if it goes beyond the terminal boundaries
        if ((new_row > rows)); then
            new_row=1
        elif ((new_row < 1)); then
            new_row=$rows
        fi

        if ((new_col > cols)); then
            new_col=1
        elif ((new_col < 1)); then
            new_col=$cols
        fi

        # Add the updated star position to the updated_stars array
        updated_stars+=("$new_row:$new_col:$character")
    done

    # Update the stars array with the new positions
    stars=("${updated_stars[@]}")
}

# Main loop
while true; do
    # Update the stars
    update_stars

    # Print the stars
    for star in "${stars[@]}"; do
        IFS=':' read -ra star_info <<< "$star"
        row="${star_info[0]}"
        col="${star_info[1]}"
        character="${star_info[2]}"

        # Print the star at its current position
        tput cup "$row" "$col"
        echo -ne "$character"
    done

    # Delay between frames (adjust as needed for desired speed)
    sleep 0.1
done

Centered Multi-Style Spinner Animation (Unicode Frame Cycler)

#!/bin/bash

# Clear the screen
clear

# Get the terminal size
rows=$(tput lines)
cols=$(tput cols)

# Calculate the center coordinates of the terminal
center_row=$((rows / 2))
center_col=$((cols / 2))

# Define the animation frames
frames=(
    "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
    "◐◓◑◒"
    "▖▘▝▗"
    "◢◣◤◥"
)

# Calculate the total number of frames
num_frames=${#frames[@]}

# Set the initial frame index
frame_index=0

# Main loop
while true; do
    # Get the current frame
    current_frame="${frames[$frame_index]}"

    start_row=$((center_row - 1))
    start_col=$((center_col - (${#current_frame} / 2)))

    tput clear

    tput cup "$start_row" "$start_col"
    printf "%s" "$current_frame"

    frame_index=$(( (frame_index + 1) % num_frames ))

    sleep 0.1
done

Colorized Waterfall Rain Screensaver (Vertical Unicode Drops)

# Define the characters to be used as water drops
CHARS=("▒" "░" "▓" "█")

# Define the colors for the drops
COLORS=("33" "34" "35" "36" "37")

# Clear the screen
clear

# Get the terminal size
rows=$(tput lines)
cols=$(tput cols)

# Array to store the current position and color of each drop
drops=()

# Initialize the drops at random positions and colors
for ((i=0; i<cols; i++)); do
    drops[$i]="$(($RANDOM % rows)):${COLORS[$(($RANDOM % ${#COLORS[@]}))]}"
done

# Function to update the drops
update_drops() {
    for ((i=0; i<cols; i++)); do
        # Split the drop position and color
        IFS=':' read -ra drop_info <<< "${drops[$i]}"
        drop_pos="${drop_info[0]}"
        drop_color="${drop_info[1]}"

        # Print the drop at the current position and color
        tput setaf "$drop_color"
        tput cup "$drop_pos" "$i"
        printf "${CHARS[$((RANDOM % ${#CHARS[@]}))]}"
        tput sgr0

        # Move the drop down by one row
        drop_pos=$(( (drop_pos + 1) % rows ))

        # Update the drop position and color in the array
        drops[$i]="$drop_pos:${COLORS[$(($RANDOM % ${#COLORS[@]}))]}"
    done
}

# Main loop
while true; do
    # Update the drops
    update_drops

    # Delay between frames (adjust as needed for desired speed)
    sleep 0.05
done

Blue Waterfall Rain Screensaver (Minimal Terminal Drop Effect)

CHARS=("▒" "░" "▓" "█")

clear

rows=$(tput lines)
cols=$(tput cols)

drops=()

# Initialize the drops at random positions
for ((i=0; i<cols; i++)); do
    drops[$i]=$((RANDOM % rows))
done

# Function to update the drops
update_drops() {
    for ((i=0; i<cols; i++)); do
        # Print the drop at the current position with blue color
        tput setaf 4  # Set text color to blue
        tput cup ${drops[$i]} $i
        printf "${CHARS[$((RANDOM % ${#CHARS[@]}))]}"
        tput sgr0  # Reset text color

        # Move the drop down by one row
        drops[$i]=$(( (drops[$i]+1) % rows ))
    done
}

# Main loop
while true; do
    # Update the drops
    update_drops

    # Delay between frames (adjust as needed for desired speed)
    sleep 0.1
done

White and Grey Waterfall Rain Screensaver (Minimal Terminal Drop Effect)

# Define the characters to be used as water drops
CHARS=("▒" "░" "▓" "█")

# Clear the screen
clear

# Get the terminal size
rows=$(tput lines)
cols=$(tput cols)

# Array to store the current position of each drop
drops=()

# Initialize the drops at random positions
for ((i=0; i<cols; i++)); do
    drops[$i]=$((RANDOM % rows))
done

# Function to update the drops
update_drops() {
    for ((i=0; i<cols; i++)); do
        # Print the drop at the current position
        tput cup ${drops[$i]} $i
        printf "${CHARS[$((RANDOM % ${#CHARS[@]}))]}"

        # Move the drop down by one row
        drops[$i]=$(( (drops[$i]+1) % rows ))
    done
}

# Main loop
while true; do
    # Update the drops
    update_drops

    # Delay between frames (adjust as needed for desired speed)
    sleep 0.1
done

Accelerating Corner-Bounce Screensaver with Random Symbols and Color Cycling

# Set the number of rows and columns for the terminal
ROWS=$(tput lines)
COLS=$(tput cols)

# Hide the cursor
tput civis

# Trap the SIGINT (Ctrl+C) signal to exit gracefully
trap "tput cnorm; exit" SIGINT

# Array of symbols to use in the screensaver
symbols=("@" "#" "%" "&" "*" "+" "-" "=" "!" "?" "/" "\\" "|" "(" ")" "[" "]" "{" "}" "<" ">" "^" "~" "," "." ":" ";" " ")

# Function to generate a random color code (ANSI color escape code)
function random_color() {
        local color_code="\e["
        local colors=("31m" "32m" "33m" "34m" "35m" "36m" "91m" "92m" "93m" "94m" "95m" "96m")
        echo -n "${color_code}${colors[$((RANDOM % ${#colors[@]}))]}"
}

# Function to generate the character for the "W" pattern with random symbol and color
function get_w_char() {
        local col=$1
        local middle_col=$((COLS / 2))
        local symbol=${symbols[$((RANDOM % ${#symbols[@]}))]} # Get random symbol
        local color_code=${color_codes[$color_index]}

        if [ $col -eq 0 ] || [ $col -eq $((COLS - 1)) ]; then
                echo -ne "\e[0m${symbol}" # Reset color after each character
        elif [ $col -lt $middle_col ] && [ $col -gt 0 ]; then
                local distance=$((middle_col - col))
                if [ $((distance % 2)) -eq 0 ]; then
                        echo -ne "${color_code}${symbol}"
                else
                        echo -ne "${color_code}${symbol}"
                fi
        elif [ $col -eq $middle_col ]; then
                echo -ne "${color_code}${symbol}"
        else
                local distance=$((col - middle_col))
                if [ $((distance % 2)) -eq 0 ]; then
                        echo -ne "${color_code}${symbol}"
                else
                        echo -ne "${color_code}${symbol}"
                fi
        fi
}

# Function to display the bounce counter in the middle center of the screen
function display_bounce_counter() {
        local counter=$1
        local message="Bounces: $counter"
        local message_length=${#message}
        local center_row=$((ROWS / 2))
        local center_col=$((COLS / 2 - message_length / 2))
        tput cup $center_row $center_col
        echo -n "$message"
}

# Function to clear the screen
function clear_screen() {
        tput reset
}

# Function to move the cursor to a specific position
function move_cursor() {
        local row=$1
        local col=$2
        tput cup $row $col
}

# Function to generate the screensaver animation
function screensaver() {
        local x=0 # Start from the leftmost column
        local y=0 # Start from the top row
        local direction_x=1
        local direction_y=1
        local bounce_counter=0

        # Set the stop positions
        local stop_x=$((COLS / 2))
        local stop_y=$((ROWS / 2))

        local color_codes=()
        local color_index=0
        local sleep_duration=0.03
        local direction_change_timer=0
        local max_direction_change_time=20 # Change direction after 20 bounces (adjust as needed)

        while true; do
                color_codes+=($(random_color))

                move_cursor $y $x
                echo -n "$(get_w_char $x)"
                sleep $sleep_duration

                # Move the position
                x=$((x + direction_x))
                y=$((y + direction_y))

                # Check if the screensaver reached the center
                if [ $x -eq $stop_x ] && [ $y -eq $stop_y ]; then
                        # Pause the animation for a moment
                        sleep 0.2
                        direction_x=$((direction_x * -1)) # Reverse direction
                        direction_y=$((direction_y * -1))
                        color_index=$((color_index + 1))
                        sleep_duration=$(awk -v sleep_duration="$sleep_duration" 'BEGIN {print sleep_duration * 0.8}')
                        ((bounce_counter++))
                        display_bounce_counter $bounce_counter

                        # Check if it's time to change direction randomly
                        ((direction_change_timer++))
                        if [ $direction_change_timer -ge $max_direction_change_time ]; then
                                direction_x=$((RANDOM % 3 - 1)) # Randomly set direction between -1, 0, 1
                                direction_y=$((RANDOM % 3 - 1))
                                direction_change_timer=0
                        fi
                fi

                # Check if the screensaver moved beyond the screen boundaries
                if [ $x -ge $((COLS - 1)) ] || [ $x -le 0 ]; then
                        direction_x=$((direction_x * -1))
                        color_index=$((color_index + 1))
                        sleep_duration=$(awk -v sleep_duration="$sleep_duration" 'BEGIN {print sleep_duration * 0.8}')
                        ((bounce_counter++))
                        display_bounce_counter $bounce_counter
                fi

                if [ $y -ge $((ROWS - 1)) ] || [ $y -le 0 ]; then
                        direction_y=$((direction_y * -1))
                        color_index=$((color_index + 1))
                        sleep_duration=$(awk -v sleep_duration="$sleep_duration" 'BEGIN {print sleep_duration * 0.8}')
                        ((bounce_counter++))
                        display_bounce_counter $bounce_counter
                fi

                if [ $color_index -ge ${#color_codes[@]} ]; then
                        color_index=0
                fi
        done
}

# Start the screensaver
screensaver

Psychedelic Lava Lamp Screensaver (Random ANSI Colors + Unicode Glyph Field)

# Clear the screen
clear

# Get the terminal size
rows=$(tput lines)
cols=$(tput cols)

# Define the lava lamp colors
LAVA_COLORS=("196" "202" "208" "214" "220" "226" "160" "165" "170" "175")

# Define the lava lamp speed
LAVA_SPEED=0.05

# Define the lava lamp symbols
LAVA_SYMBOLS=("☀" "☼" "⚡" "☄" "✨" "✿" "❀" "❂" "❄" "❅" "❆" "❇" "❈" "❉" "❊" "❋" "❌" "❍" "❎" "❏" "❐" "❑" "❒" "❖" "❘" "❙" "❚" "❛" "❜" "❝" "❞" "❡" "❢" "❣" "❤" "❥" "❦" "❧" "❨" "❩" "❪" "❫" "❬" "❭" "❮" "❯" "❰" "❱" "❲" "❳" "❴" "❵" "❶" "❷" "❸" "❹" "❺" "❻" "❼" "❽" "❾" "❿" "➀" "➁" "➂" "➃" "➄" "➅" "➆" "➇" "➈" "➉" "➊" "➋" "➌" "➍" "➎" "➏" "➐" "➑" "➒" "➓")

# Function to generate a random number within a range
generate_random_number() {
  min=$1
  max=$2
  echo $((RANDOM % (max - min + 1) + min))
}

# Function to generate a random color escape sequence
generate_color_sequence() {
  color_code="\e[${1}m"
  echo -e $color_code
}

# Function to move the lava lamps
move_lava_lamps() {
  while true; do
    # Clear the screen
    clear

    for ((i = 1; i <= $rows; i++)); do
      for ((j = 1; j <= $cols; j++)); do
        # Generate a random color for the lava lamp
        color_index=$(generate_random_number 0 $((${#LAVA_COLORS[@]} - 1)))
        color="${LAVA_COLORS[$color_index]}"

        # Calculate the symbol index based on the current row and column
        symbol_index=$((j % ${#LAVA_SYMBOLS[@]}))

        # Get the symbol at the calculated index
        symbol="${LAVA_SYMBOLS[$symbol_index]}"

        # Move the cursor to the current coordinates
        echo -e "\e[${i};${j}H"

        # Set the color and print the symbol
        echo -e "$(generate_color_sequence ${color})${symbol}"
      done
    done

    # Sleep for a short duration to control the speed
    sleep ${LAVA_SPEED}
  done
}

# Hide the cursor
tput civis

# Enable keyboard interrupts
trap "tput cnorm; exit" INT

# Start the lava lamp screensaver
move_lava_lamps

Particle Explosion

# Clear the screen
clear

# Get the terminal size
rows=$(tput lines)
cols=$(tput cols)

# Define the particle ASCII characters
PARTICLE_CHARACTERS=("•" "◦" "∘" "·" "⁕" "∙" "⋆" "⚫" "⚪" "●" "○")

# Define the particle colors
PARTICLE_COLORS=("196" "202" "208" "214" "220" "226" "160" "165" "170" "175")

# Define the number of explosions
NUM_EXPLOSIONS=5

# Define the number of particles per explosion
NUM_PARTICLES=100

# Define the explosion speed
EXPLOSION_SPEED=0.01

# Array to store the particle positions and velocities
explosion_positions=()
explosion_velocities=()

# Function to generate a random number within a range
generate_random_number() {
    local min=$1
    local max=$2
    echo $((RANDOM % (max - min + 1) + min))
}

# Function to initialize the explosion positions and velocities
initialize_explosion_positions() {
    for ((i=0; i<NUM_EXPLOSIONS; i++)); do
        local position_row=$((rows / 2))
        local position_col=$((cols / 2))
        local velocity_row=$(generate_random_number -10 10)
        local velocity_col=$(generate_random_number -20 20)
        explosion_positions[$i]="$position_row:$position_col"
        explosion_velocities[$i]="$velocity_row:$velocity_col"
    done
}

# Function to update the explosion positions
update_explosion_positions() {
    for ((i=0; i<NUM_EXPLOSIONS; i++)); do
        local position="${explosion_positions[$i]}"
        local velocity="${explosion_velocities[$i]}"
        IFS=':' read -ra position_parts <<< "$position"
        IFS=':' read -ra velocity_parts <<< "$velocity"
        local position_row="${position_parts[0]}"
        local position_col="${position_parts[1]}"
        local velocity_row="${velocity_parts[0]}"
        local velocity_col="${velocity_parts[1]}"
        position_row=$((position_row + velocity_row))
        position_col=$((position_col + velocity_col))
        if ((position_row < 1 || position_row >= rows || position_col < 1 || position_col >= cols)); then
            position_row=$((rows / 2))
            position_col=$((cols / 2))
            velocity_row=$(generate_random_number -10 10)
            velocity_col=$(generate_random_number -20 20)
        fi
        explosion_positions[$i]="$position_row:$position_col"
        explosion_velocities[$i]="$velocity_row:$velocity_col"
    done
}

# Function to render the particles on the screen
render_particles() {
    for ((i=0; i<NUM_EXPLOSIONS; i++)); do
        local position="${explosion_positions[$i]}"
        IFS=':' read -ra position_parts <<< "$position"
        local position_row="${position_parts[0]}"
        local position_col="${position_parts[1]}"
        for ((j=0; j<NUM_PARTICLES; j++)); do
            local character=${PARTICLE_CHARACTERS[$((RANDOM % ${#PARTICLE_CHARACTERS[@]}))]}
            local color=${PARTICLE_COLORS[$((RANDOM % ${#PARTICLE_COLORS[@]}))]}
            tput setaf "$color"
            tput cup "$position_row" "$position_col"
            echo -ne "$character"
        done
    done
}

# Main loop
while true; do
    # Update the explosion positions
    update_explosion_positions

    # Render the particles on the screen
    render_particles

    # Delay between frames
    sleep $EXPLOSION_SPEED
done
# Set terminal dimensions
columns=$(tput cols)
lines=$(tput lines)

# Function to clear the screen
clear_screen() {
    printf "\033[2J"
}

# Function to generate the spinning circle effect
generate_effect() {
    local circle=("◐" "◓" "◑" "◒")  # Characters for the spinning circle
    local colors=("31" "32" "33" "34" "35" "36" "37")  # ANSI escape codes for text colors
    local num_circle=${#circle[@]}  # Number of characters in the spinning circle
    local num_colors=${#colors[@]}  # Number of colors

    local x=$((columns / 2))
    local y=$((lines / 2))
    local dx=0
    local dy=0
    local circle_index=0
    local color_index=0
    local step=0

    while true
    do
        # Get the current character from the spinning circle
        local char=${circle[$circle_index]}
        circle_index=$(( (circle_index + 1) % num_circle ))

        # Get the current color
        local color=${colors[$color_index]}
        color_index=$(( (color_index + 1) % num_colors ))

        # Print the colored character at the current position
        printf "\033[${color}m\033[${y};${x}H${char}\033[0m"

        sleep 0.01  # Adjust the sleep duration to control the speed of the effect

        case $step in
            0)
                dx=0
                dy=1
                ((y++))
                if ((y == (lines - 1)))
                then
                    ((step++))
                fi
                ;;
            1)
                dx=1
                dy=-1
                ((x++))
                ((y--))
                if ((x == (columns - 1)))
                then
                    ((step++))
                fi
                ;;
            2)
                dx=0
                dy=-1
                ((y--))
                if ((y == 0))
                then
                    ((step++))
                fi
                ;;
            3)
                dx=1
                dy=1
                ((x++))
                ((y++))
                if ((x == (columns / 2)))
                then
                    ((step++))
                fi
                ;;
            4)
                dx=-1
                dy=-1
                ((x--))
                ((y--))
                if ((x == 0))
                then
                    ((step++))
                fi
                ;;
            5)
                dx=0
                dy=0
                if ((y == (lines / 2)))
                then
                    break
                fi
                ;;
        esac

    done
}

# Main loop
while true
do
    clear_screen
    generate_effect
done

Color-Cycling Spinner Path Animation (Spinning Circle Traversing the Screen)

# Set terminal dimensions
columns=$(tput cols)
lines=$(tput lines)

# Function to clear the screen
clear_screen() {
    printf "\033[2J"
}

# Function to generate the matrix rain effect
generate_effect() {
    local matrix=("0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "A" "B" "C" "D" "E" "F")  # Characters for matrix rain
    local colors=("32" "33" "34" "35" "36")  # ANSI escape codes for text colors
    local num_matrix=${#matrix[@]}  # Number of characters in the matrix rain
    local num_colors=${#colors[@]}  # Number of colors

    local start_x=10
    local start_y=5
    local end_x=$((columns - 11))
    local end_y=$((lines - 6))

    local x=$start_x
    local y=$start_y
    local dx=1
    local dy=0
    local matrix_index=0
    local color_index=0

    while true
    do
        # Get the current character from the matrix rain
        local char=${matrix[$matrix_index]}
        matrix_index=$(( (matrix_index + 1) % num_matrix ))

        # Get the current color
        local color=${colors[$color_index]}
        color_index=$(( (color_index + 1) % num_colors ))

        # Print the colored character at the current position
        printf "\033[${color}m\033[${y};${x}H${char}\033[0m"

        # Update position
        x=$((x + dx))
        y=$((y + dy))

        # Check for reaching the end of each side and adjust direction accordingly
        if ((x > end_x))
        then
            x=$end_x
            y=$((y + 1))
            dx=0
            dy=1
        elif ((y > end_y))
        then
            x=$((x - 1))
            y=$end_y
            dx=-1
            dy=0
        elif ((x < start_x))
        then
            x=$start_x
            y=$((y - 1))
            dx=0
            dy=-1
        elif ((y < start_y))
        then
            x=$((x + 1))
            y=$start_y
            dx=1
            dy=0
        fi

        sleep 0.01  # Adjust the sleep duration to control the speed of the effect
    done
}

# Function to draw the wall
draw_wall() {
    local x
    local y

    local wall_start_x=10
    local wall_start_y=5
    local wall_end_x=$((columns - 11))
    local wall_end_y=$((lines - 6))

    # Draw the top level of the wall
    for ((x = wall_start_x; x <= wall_end_x; x++))
    do
        printf "\033[32m\033[${wall_start_y};${x}H█"
    done

    # Draw the bottom level of the wall
    for ((x = wall_start_x; x <= wall_end_x; x++))
    do
        printf "\033[32m\033[${wall_end_y};${x}H█"
    done

    # Draw the left side of the wall
    for ((y = wall_start_y + 1; y < wall_end_y; y++))
    do
        printf "\033[32m\033[${y};${wall_start_x}H█"
    done

    # Draw the right side of the wall
    for ((y = wall_start_y + 1; y < wall_end_y; y++))
    do
        printf "\033[32m\033[${y};${wall_end_x}H█"
    done

    # Update wall dimensions for the next level
    wall_start_x=$((wall_start_x + 1))
    wall_start_y=$((wall_start_y + 1))
    wall_end_x=$((wall_end_x - 1))
    wall_end_y=$((wall_end_y - 1))
}

# Main loop
while true
do
    clear_screen
    draw_wall
    generate_effect
    draw_wall
done

Psychedelic Lava Lamp Screensaver (Random ANSI Colors + Unicode Glyph Field)

#!/bin/bash

# Set terminal dimensions
columns=$(tput cols)
lines=$(tput lines)

# Function to clear the screen
clear_screen() {
    printf "\033[2J"
}

# Function to generate the spinning circle effect
generate_effect() {
    local circle=("◐" "◓" "◑" "◒")  # Characters for the spinning circle
    local colors=("31" "32" "33" "34" "35" "36" "37")  # ANSI escape codes for text colors
    local num_circle=${#circle[@]}  # Number of characters in the spinning circle
    local num_colors=${#colors[@]}  # Number of colors

    local x=$((columns / 2))
    local y=$((lines / 2))
    local dx=0
    local dy=0
    local circle_index=0
    local color_index=0
    local step=0

    while true
    do
        # Get the current character from the spinning circle
        local char=${circle[$circle_index]}
        circle_index=$(( (circle_index + 1) % num_circle ))

        # Get the current color
        local color=${colors[$color_index]}
        color_index=$(( (color_index + 1) % num_colors ))

        # Print the colored character at the current position
        printf "\033[${color}m\033[${y};${x}H${char}\033[0m"

        sleep 0.01  # Adjust the sleep duration to control the speed of the effect

        case $step in
            0)
                dx=0
                dy=1
                ((y++))
                if ((y == (lines - 1)))
                then
                    ((step++))
                fi
                ;;
            1)
                dx=1
                dy=-1
                ((x++))
                ((y--))
                if ((x == (columns - 1)))
                then
                    ((step++))
                fi
                ;;
            2)
                dx=0
                dy=-1
                ((y--))
                if ((y == 0))
                then
                    ((step++))
                fi
                ;;
            3)
                dx=1
                dy=1
                ((x++))
                ((y++))
                if ((x == (columns / 2)))
                then
                    ((step++))
                fi
                ;;
            4)
                dx=-1
                dy=-1
                ((x--))
                ((y--))
                if ((x == 0))
                then
                    ((step++))
                fi
                ;;
            5)
                dx=0
                dy=0
                if ((y == (lines / 2)))
                then
                    break
                fi
                ;;
        esac

    done
}

# Main loop
while true
do
    clear_screen
    generate_effect
done

Shrinking Spiral Spinner Border That Transitions into a Bouncing Ball

# Set terminal dimensions
columns=$(tput cols)
lines=$(tput lines)

# Function to clear the screen
clear_screen() {
    printf "\033[2J"
}

# Function to generate a spinner effect with changing colors
generate_effect() {
    local spinner=("◐" "◓" "◑" "◒" "⣾" "⣽" "⣻" "⢿" "⡿" "⣟" "⣯" "⣷")  # Characters for the spinner
    local colors=("31" "32" "33" "34" "35" "36" "37")  # ANSI escape codes for text colors
    local num_spinner=${#spinner[@]}  # Number of characters in the spinner
    local num_colors=${#colors[@]}  # Number of colors

    local start_x=0
    local start_y=0
    local end_x=$((columns - 1))
    local end_y=$((lines - 1))

    local x=$start_x
    local y=$start_y
    local dx=1
    local dy=0
    local spinner_index=0
    local color_index=0
    local corner_count=0
    local ball_x=$((columns / 2))
    local ball_y=$((lines / 2))
    local ball_dx=-1
    local ball_dy=-1

    while true
    do
        # Get the current character from the spinner
        local char=${spinner[$spinner_index]}
        spinner_index=$(( (spinner_index + 1) % num_spinner ))

        # Get the current color
        local color=${colors[$color_index]}
        color_index=$(( (color_index + 1) % num_colors ))

        # Print the colored character at the current position
        printf "\033[${color}m\033[${y};${x}H${char}\033[0m"

        # Update position
        x=$((x + dx))
        y=$((y + dy))

        # Check for reaching the end of each side and adjust direction accordingly
        if ((x > end_x))
        then
            x=$end_x
            y=$((y + 1))
            dx=0
            dy=1
        elif ((y > end_y))
        then
            x=$((x - 1))
            y=$end_y
            dx=-1
            dy=0
        elif ((x < start_x))
        then
            x=$start_x
            y=$((y - 1))
            dx=0
            dy=-1
        elif ((y < start_y))
        then
            x=$((x + 1))
            y=$start_y
            dx=1
            dy=0
        fi

        # Check for completing the full circle
        if ((x == start_x && y == start_y))
        then
            corner_count=$((corner_count + 1))

            if ((corner_count == 5))
            then
                while true
                do
                    # Print the colored ball at the current position
                    printf "\033[${color}m\033[${ball_y};${ball_x}H●\033[0m"

                    # Update ball position
                    ball_x=$((ball_x + ball_dx))
                    ball_y=$((ball_y + ball_dy))

                    # Check for bouncing off the walls
                    if ((ball_x <= start_x || ball_x >= end_x))
                    then
                        ball_dx=$((ball_dx * -1))
                    fi
                    if ((ball_y <= start_y || ball_y >= end_y))
                    then
                        ball_dy=$((ball_dy * -1))
                    fi

                    sleep 0.01  # Adjust the sleep duration to control the speed of the effect
                done
            else
                start_x=$((start_x + 1))
                start_y=$((start_y + 1))
                end_x=$((end_x - 1))
                end_y=$((end_y - 1))
                x=$((start_x))
                y=$((start_y))
            fi
        fi

        sleep 0.01  # Adjust the sleep duration to control the speed of the effect
    done
}

# Main loop
while true
do
    clear_screen
    generate_effect
done

Rainbow Spinner Perimeter Loop (Center Start, Edge Trace, Return to Center)

# Set terminal dimensions
columns=$(tput cols)
lines=$(tput lines)

# Function to clear the screen
clear_screen() {
    printf "\033[2J"
}

# Function to generate the spinning circle effect
generate_effect() {
    local circle=("◐" "◓" "◑" "◒")  # Characters for the spinning circle
    local colors=("31" "32" "33" "34" "35" "36" "37")  # ANSI escape codes for text colors
    local num_circle=${#circle[@]}  # Number of characters in the spinning circle
    local num_colors=${#colors[@]}  # Number of colors

    local x=$((columns / 2))
    local y=$((lines / 2))
    local dx=0
    local dy=0
    local circle_index=0
    local color_index=0
    local step=0

    while true
    do
        # Get the current character from the spinning circle
        local char=${circle[$circle_index]}
        circle_index=$(( (circle_index + 1) % num_circle ))

        # Get the current color
        local color=${colors[$color_index]}
        color_index=$(( (color_index + 1) % num_colors ))

        # Print the colored character at the current position
        printf "\033[${color}m\033[${y};${x}H${char}\033[0m"

        sleep 0.01  # Adjust the sleep duration to control the speed of the effect

        case $step in
            0)
                dx=1
                dy=0
                ((x++))
                if ((x == (columns - 1)))
                then
                    ((step++))
                fi
                ;;
            1)
                dx=0
                dy=1
                ((y++))
                if ((y == (lines - 1)))
                then
                    ((step++))
                fi
                ;;
            2)
                dx=-1
                dy=0
                ((x--))
                if ((x == 0))
                then
                    ((step++))
                fi
                ;;
            3)
                dx=0
                dy=-1
                ((y--))
                if ((y == 0))
                then
                    ((step++))
                fi
                ;;
            4)
                dx=0
                dy=0
                if ((x == (columns / 2) && y == (lines / 2)))
                then
                    break
                fi
                ;;
        esac

    done
}

# Main loop
while true
do
    clear_screen
    generate_effect
done

Emoji Confetti Screensaver (Alternate Screen, Smiley Set)

emojis=("🙂" "😀" "😁" "😆" "😅" "😂" "🤣" "😊" "😍" "🥰")

cleanup() {
  tput cnorm 2>/dev/null
  tput sgr0  2>/dev/null
  tput rmcup 2>/dev/null   # leave alternate screen
}
trap cleanup INT TERM EXIT

tput smcup 2>/dev/null     # enter alternate screen (no scrollback junk)
tput civis 2>/dev/null
tput clear 2>/dev/null

while :; do
  cols=$(tput cols)
  lines=$(tput lines)

  for _ in {1..50}; do
    # emojis are often double-width -> avoid last column
    x=$((RANDOM % (cols>1 ? cols-1 : 1)))
    y=$((RANDOM % lines))
    emoji=${emojis[RANDOM % ${#emojis[@]}]}

    tput cup "$y" "$x"
    printf '\e[1m%s\e[0m' "$emoji"
    sleep 0.05
  done

  sleep 0.2
  tput clear
  tput cup 0 0
done

Random Emoji Scatter Screensaver (ANSI Clear, Mixed Symbols)

emojis=("😎" "🤖" "👾" "🎉" "✨" "🔥" "💥" "🌈" "⚡" "🌀" "🚀" "🛸" "🌟" "💫" "👽")

cleanup() {
  tput cnorm
  tput sgr0
  printf '\033[2J\033[H'
}
trap cleanup INT TERM EXIT

tput civis

while true; do
  cols=$(tput cols)
  lines=$(tput lines)

  # clear FIRST
  printf '\033[2J\033[H'

  for _ in {1..50}; do
    x=$((RANDOM % (cols > 1 ? cols-1 : 1))) # avoid last column (emoji width)
    y=$((RANDOM % lines))
    emoji=${emojis[RANDOM % ${#emojis[@]}]}

    tput cup "$y" "$x"
    printf '\e[1m%s\e[0m' "$emoji"
  done

  sleep 0.5
done

Colorful Heart Emoji Confetti Screensaver

emojis=("❤️" "🧡" "💛" "💚" "💙" "💜" "🤎" "🖤" "🤍" "💖" "💗" "💘" "💝" "💞" "💟")

cleanup() {
  tput cnorm
  tput sgr0
  printf '\033[2J\033[H'
}
trap cleanup INT TERM EXIT

tput civis

while true; do
  cols=$(tput cols)
  lines=$(tput lines)

  # clear FIRST
  printf '\033[2J\033[H'

  for _ in {1..50}; do
    x=$((RANDOM % (cols > 1 ? cols-1 : 1))) # avoid last column (emoji width)
    y=$((RANDOM % lines))
    emoji=${emojis[RANDOM % ${#emojis[@]}]}

    tput cup "$y" "$x"
    printf '\e[1m%s\e[0m' "$emoji"
  done

  sleep 0.5
done

Randomized Emoji Confetti Screensaver

emojis=(
  "✨" "🌟" "💫" "⭐" "⚡" "🔥" "💥" "🌈" "🌀" "❄️"
  "☄️" "🌙" "🌕" "🌑" "🪐" "🌍" "🌎" "🌏" "🛸" "🚀"
  "🎆" "🎇" "🎉" "🎊" "🎈" "🧨" "💎" "🔮" "🪄" "🧿"
  "👾" "🤖" "👽" "🧠" "👁️" "🫀" "🫁" "🦾" "🦿" "🧬"
)

cleanup() {
  tput cnorm
  tput sgr0
  printf '\033[2J\033[H'
}
trap cleanup INT TERM EXIT

tput civis

while true; do
  cols=$(tput cols)
  lines=$(tput lines)

  # clear FIRST
  printf '\033[2J\033[H'

  for _ in {1..50}; do
    x=$((RANDOM % (cols > 1 ? cols-1 : 1))) # avoid last column (emoji width)
    y=$((RANDOM % lines))
    emoji=${emojis[RANDOM % ${#emojis[@]}]}

    tput cup "$y" "$x"
    printf '\e[1m%s\e[0m' "$emoji"
  done

  sleep 0.5
done

Snowfall Colorized

# Set terminal dimensions
columns=$(tput cols)
lines=$(tput lines)

# Function to clear the screen
clear_screen() {
        printf "\033[2J"
}

# Function to display the winter scene with colored snowflakes
display_winterscene() {
        local x y
        local colors=("96" "97" "94" "95" "92" "93") # Add more colors if desired
        local snowflakes=("❄" "❅" "❆")
        local num_snowflakes=$((columns * lines / 20)) # Adjust the density of snowflakes

        for ((i = 0; i < num_snowflakes; i++)); do
                x=$((RANDOM % columns))
                y=$((RANDOM % lines))
                color=${colors[$((RANDOM % ${#colors[@]}))]}
                snowflake=${snowflakes[$((RANDOM % ${#snowflakes[@]}))]}
                printf "\033[${y};${x}H\033[${color}m${snowflake}\033[0m"
        done
}

# Main loop
while true; do
        clear_screen
        display_winterscene
        sleep 0.1 # Adjust the sleep duration to control the animation speed
done

Random Emoji Confetti Screensaver (Alternate Screen, Bold Unicode Scatter)

emojis=("🙂" "😀" "😁" "😆" "😅" "😂" "🤣" "😊" "😍" "🥰")

cleanup() {
  tput cnorm 2>/dev/null
  tput sgr0  2>/dev/null
  tput rmcup 2>/dev/null   # leave alternate screen
}
trap cleanup INT TERM EXIT

tput smcup 2>/dev/null     # enter alternate screen (no scrollback junk)
tput civis 2>/dev/null
tput clear 2>/dev/null

while :; do
  cols=$(tput cols)
  lines=$(tput lines)

  for _ in {1..50}; do
    # emojis are often double-width -> avoid last column
    x=$((RANDOM % (cols>1 ? cols-1 : 1)))
    y=$((RANDOM % lines))
    emoji=${emojis[RANDOM % ${#emojis[@]}]}

    tput cup "$y" "$x"
    printf '\e[1m%s\e[0m' "$emoji"
    sleep 0.05
  done

  sleep 0.2
  tput clear
  tput cup 0 0
done

Blinking Starry Night Screensaver (Randomized Twinkling Sky Effect)

# Set terminal dimensions
columns=$(tput cols)
lines=$(tput lines)

# Function to clear the screen
clear_screen() {
        printf "\033[2J"
}

# Function to display the starry night sky
display_starry_night() {
        local x y
        local num_stars=$((columns * lines / 10)) # Adjust the density of stars

        for ((i = 0; i < num_stars; i++)); do
                x=$((RANDOM % columns))
                y=$((RANDOM % lines))
                color=$((RANDOM % 7 + 90)) # Random ANSI escape code for color
                printf "\033[${y};${x}H\033[${color}m*\033[0m"
        done
}

# Function to randomly blink stars
blink_stars() {
        local x y
        local num_blinks=$((columns * lines / 20)) # Adjust the density of blinking stars

        for ((i = 0; i < num_blinks; i++)); do
                x=$((RANDOM % columns))
                y=$((RANDOM % lines))
                color=$((RANDOM % 7 + 90)) # Random ANSI escape code for color
                printf "\033[${y};${x}H\033[${color}m \033[0m"
                sleep 0.1 # Adjust the blink duration
                printf "\033[${y};${x}H\033[${color}m*\033[0m"
                sleep 0.1 # Adjust the blink duration
        done
}

# Main loop
while true; do
        clear_screen
        display_starry_night
        blink_stars
        sleep 0.5 # Adjust the sleep duration to control the animation speed
done

Random-Symbol “W” Bouncer with Color Cycling and Bounce Counter

# Set the number of rows and columns for the terminal
ROWS=$(tput lines)
COLS=$(tput cols)

# Hide the cursor
tput civis

# Trap the SIGINT (Ctrl+C) signal to exit gracefully
trap "tput cnorm; exit" SIGINT

# Array of symbols to use in the screensaver
symbols=("@" "#" "%" "&" "*" "+" "-" "=" "!" "?" "/" "\\" "|" "(" ")" "[" "]" "{" "}" "<" ">" "^" "~" "," "." ":" ";" " ")

# Function to generate a random color code (ANSI color escape code)
function random_color() {
        local color_code="\e["
        local colors=("31m" "32m" "33m" "34m" "35m" "36m" "91m" "92m" "93m" "94m" "95m" "96m")
        echo -n "${color_code}${colors[$((RANDOM % ${#colors[@]}))]}"
}

# Function to generate the character for the "W" pattern with random symbol and color
function get_w_char() {
        local col=$1
        local middle_col=$((COLS / 2))
        local symbol=${symbols[$((RANDOM % ${#symbols[@]}))]} # Get random symbol
        local color_code=${color_codes[$color_index]}

        if [ $col -eq 0 ] || [ $col -eq $((COLS - 1)) ]; then
                echo -ne "\e[0m${symbol}" # Reset color after each character
        elif [ $col -lt $middle_col ] && [ $col -gt 0 ]; then
                local distance=$((middle_col - col))
                if [ $((distance % 2)) -eq 0 ]; then
                        echo -ne "${color_code}${symbol}"
                else
                        echo -ne "${color_code}${symbol}"
                fi
        elif [ $col -eq $middle_col ]; then
                echo -ne "${color_code}${symbol}"
        else
                local distance=$((col - middle_col))
                if [ $((distance % 2)) -eq 0 ]; then
                        echo -ne "${color_code}${symbol}"
                else
                        echo -ne "${color_code}${symbol}"
                fi
        fi
}

# Function to display the bounce counter in the middle center of the screen
function display_bounce_counter() {
        local counter=$1
        local message="Bounces: $counter"
        local message_length=${#message}
        local center_row=$((ROWS / 2))
        local center_col=$((COLS / 2 - message_length / 2))
        tput cup $center_row $center_col
        echo -n "$message"
}

# Function to clear the screen
function clear_screen() {
        tput reset
}

# Function to move the cursor to a specific position
function move_cursor() {
        local row=$1
        local col=$2
        tput cup $row $col
}

# Function to generate the screensaver animation
function screensaver() {
        local x=0 # Start from the leftmost column
        local y=0 # Start from the top row
        local direction_x=1
        local direction_y=1
        local bounce_counter=0

        # Set the stop positions
        local stop_x=$((COLS / 2))
        local stop_y=$((ROWS / 2))

        local color_codes=()
        local color_index=0
        local sleep_duration=0.03
        local direction_change_timer=0
        local max_direction_change_time=20 # Change direction after 20 bounces (adjust as needed)

        while true; do
                color_codes+=($(random_color))

                move_cursor $y $x
                echo -n "$(get_w_char $x)"
                sleep $sleep_duration

                # Move the position
                x=$((x + direction_x))
                y=$((y + direction_y))

                # Check if the screensaver reached the center
                if [ $x -eq $stop_x ] && [ $y -eq $stop_y ]; then
                        # Pause the animation for a moment
                        sleep 0.2
                        direction_x=$((direction_x * -1)) # Reverse direction
                        direction_y=$((direction_y * -1))
                        color_index=$((color_index + 1))
                        sleep_duration=$(awk -v sleep_duration="$sleep_duration" 'BEGIN {print sleep_duration * 0.8}')
                        ((bounce_counter++))
                        display_bounce_counter $bounce_counter

                        # Check if it's time to change direction randomly
                        ((direction_change_timer++))
                        if [ $direction_change_timer -ge $max_direction_change_time ]; then
                                direction_x=$((RANDOM % 3 - 1)) # Randomly set direction between -1, 0, 1
                                direction_y=$((RANDOM % 3 - 1))
                                direction_change_timer=0
                        fi
                fi

                # Check if the screensaver moved beyond the screen boundaries
                if [ $x -ge $((COLS - 1)) ] || [ $x -le 0 ]; then
                        direction_x=$((direction_x * -1))
                        color_index=$((color_index + 1))
                        sleep_duration=$(awk -v sleep_duration="$sleep_duration" 'BEGIN {print sleep_duration * 0.8}')
                        ((bounce_counter++))
                        display_bounce_counter $bounce_counter
                fi

                if [ $y -ge $((ROWS - 1)) ] || [ $y -le 0 ]; then
                        direction_y=$((direction_y * -1))
                        color_index=$((color_index + 1))
                        sleep_duration=$(awk -v sleep_duration="$sleep_duration" 'BEGIN {print sleep_duration * 0.8}')
                        ((bounce_counter++))
                        display_bounce_counter $bounce_counter
                fi

                if [ $color_index -ge ${#color_codes[@]} ]; then
                        color_index=0
                fi
        done
}

# Start the screensaver
screensaver

Accelerating Random-Symbol “W” Screensaver with Color Cycling

#!/usr/bin/env bash

# Set the number of rows and columns for the terminal
ROWS=$(tput lines)
COLS=$(tput cols)

# Use alternate screen so the terminal content (your pasted script) is hidden
tput smcup

# Hide cursor + clear screen before starting
tput civis
tput clear
tput cup 0 0

# Trap signals to exit gracefully and restore terminal
cleanup() {
  tput cnorm
  printf '\e[0m'
  tput rmcup
  exit
}
trap cleanup INT TERM

# Array of symbols to use in the screensaver
symbols=("@" "#" "%" "&" "*" "+" "-" "=" "!" "?" "/" "\\" "|" "(" ")" "[" "]" "{" "}" "<" ">" "^" "~" "," "." ":" ";" " ")

# Function to generate a random color code (ANSI color escape code)
random_color() {
  local colors=("31m" "32m" "33m" "34m" "35m" "36m" "91m" "92m" "93m" "94m" "95m" "96m")
  printf '\e[%s' "${colors[RANDOM % ${#colors[@]}]}"
}

# Function to move the cursor to a specific position
move_cursor() {
  tput cup "$1" "$2"
}

# Function to generate the character for the "W" pattern with random symbol and color
# NOTE: We pass color_code in so we don't depend on a local array from another scope.
get_w_char() {
  local col=$1
  local color_code=$2
  local middle_col=$((COLS / 2))
  local symbol=${symbols[RANDOM % ${#symbols[@]}]}

  if [ "$col" -eq 0 ] || [ "$col" -eq $((COLS - 1)) ]; then
    printf '\e[0m%s' "$symbol"
  elif [ "$col" -le "$middle_col" ]; then
    printf '%b%s' "$color_code" "$symbol"
  else
    printf '%b%s' "$color_code" "$symbol"
  fi
}

screensaver() {
  local x=0 y=0
  local direction_x=1 direction_y=1

  local stop_x=$((COLS / 2))
  local stop_y=$((ROWS / 2))

  local color_code
  local sleep_duration=0.03

  # Make sure we start drawing from a clean frame
  tput clear
  tput cup 0 0

  while true; do
    color_code="$(random_color)"

    move_cursor "$y" "$x"
    get_w_char "$x" "$color_code"

    sleep "$sleep_duration"

    x=$((x + direction_x))
    y=$((y + direction_y))

    if [ "$x" -eq "$stop_x" ] && [ "$y" -eq "$stop_y" ]; then
      sleep 0.2
      direction_x=$((direction_x * -1))
      direction_y=$((direction_y * -1))
      sleep_duration=$(awk -v s="$sleep_duration" 'BEGIN {print s * 0.8}')
    fi

    if [ "$x" -ge $((COLS - 1)) ] || [ "$x" -le 0 ]; then
      direction_x=$((direction_x * -1))
      sleep_duration=$(awk -v s="$sleep_duration" 'BEGIN {print s * 0.8}')
    fi

    if [ "$y" -ge $((ROWS - 1)) ] || [ "$y" -le 0 ]; then
      direction_y=$((direction_y * -1))
      sleep_duration=$(awk -v s="$sleep_duration" 'BEGIN {print s * 0.8}')
    fi
  done
}

screensaver

African Flag Spiral Border Animation with Color Cycling and Bouncing Ball Finale

# Define the array of African flags
flags=(
  "🇦🇴" "🇧🇯" "🇧🇼" "🇧🇫" "🇧🇮" "🇨🇻" "🇨🇲" "🇨🇫" "🇹🇩" "🇰🇲"
  "🇨🇬" "🇨🇩" "🇨🇮" "🇩🇯" "🇪🇬" "🇬🇶" "🇪🇷" "🇸🇿" "🇪🇹" "🇬🇦"
  "🇬🇲" "🇬🇭" "🇬🇳" "🇬🇼" "🇰🇪" "🇱🇸" "🇱🇷" "🇱🇾" "🇲🇬" "🇲🇼"
  "🇲🇱" "🇲🇷" "🇲🇺" "🇲🇦" "🇲🇿" "🇳🇦" "🇳🇪" "🇳🇬" "🇷🇼" "🇸🇹"
  "🇸🇳" "🇸🇨" "🇸🇱" "🇸🇴" "🇿🇦" "🇸🇸" "🇸🇩" "🇹🇿" "🇹🇬" "🇹🇳"
  "🇺🇬" "🇿🇲" "🇿🇼"
)

# Define colors (ANSI color codes)
colors=("36" "32" "33" "34" "35" "36" "37")

# Get terminal dimensions
columns=$(tput cols)
lines=$(tput lines)

# Initialize variables for movement
start_x=0
start_y=0
end_x=$((columns - 1))
end_y=$((lines - 1))

x=$start_x
y=$start_y
dx=1
dy=0

spinner_index=0
color_index=0
corner_count=0

ball_x=$((columns / 2))
ball_y=$((lines / 2))
ball_dx=-1
ball_dy=-1

# Function to clear the screen
clear_screen() {
        printf "\033c"
}

# Function to generate the spiraling effect with flags
generate_effect() {
        local num_flags=${#flags[@]}   # Number of flags
        local num_colors=${#colors[@]} # Number of colors

        while true; do
                # Get the current flag
                local flag=${flags[$spinner_index]}
                spinner_index=$(((spinner_index + 1) % num_flags))

                # Get the current color
                local color=${colors[$color_index]}
                color_index=$(((color_index + 1) % num_colors))

                # Print the colored flag at the current position
                printf "\033[${color}m\033[${y};${x}H${flag}\033[0m"

                # Update position
                x=$((x + dx))
                y=$((y + dy))

                # Check for reaching the end of each side and adjust direction accordingly
                if ((x > end_x)); then
                        x=$end_x
                        y=$((y + 1))
                        dx=0
                        dy=1
                elif ((y > end_y)); then
                        x=$((x - 1))
                        y=$end_y
                        dx=-1
                        dy=0
                elif ((x < start_x)); then
                        x=$start_x
                        y=$((y - 1))
                        dx=0
                        dy=-1
                elif ((y < start_y)); then
                        x=$((x + 1))
                        y=$start_y
                        dx=1
                        dy=0
                fi

                # Check for completing the full circle
                if ((x == start_x && y == start_y)); then
                        corner_count=$((corner_count + 1))

                        if ((corner_count == 5)); then
                                # Switch to bouncing ball effect after 5 complete circles
                                while true; do
                                        # Print the colored ball at the current position
                                        printf "\033[${color}m\033[${ball_y};${ball_x}H●\033[0m"

                                        # Update ball position
                                        ball_x=$((ball_x + ball_dx))
                                        ball_y=$((ball_y + ball_dy))

                                        # Check for bouncing off the walls
                                        if ((ball_x <= start_x || ball_x >= end_x)); then
                                                ball_dx=$((ball_dx * -1))
                                        fi
                                        if ((ball_y <= start_y || ball_y >= end_y)); then
                                                ball_dy=$((ball_dy * -1))
                                        fi

                                        sleep 0.01 # Adjust the sleep duration to control the speed of the effect
                                done
                        else
                                # Reduce the bounding box for the next circle
                                start_x=$((start_x + 1))
                                start_y=$((start_y + 1))
                                end_x=$((end_x - 1))
                                end_y=$((end_y - 1))
                                x=$((start_x))
                                y=$((start_y))
                        fi
                fi

                sleep 0.01 # Adjust the sleep duration to control the speed of the effect
        done
}

# Main loop
while true; do
        clear_screen
        generate_effect
done

Euorpes Flag Spiral Border Animation with Color Cycling and Bouncing Ball Finale

# Define the array of African flags
flags=(
  "🇦🇱" "🇦🇩" "🇦🇹" "🇧🇪" "🇧🇦" "🇧🇬" "🇭🇷" "🇨🇾" "🇨🇿" "🇩🇰"
  "🇪🇪" "🇫🇮" "🇫🇷" "🇩🇪" "🇬🇷" "🇭🇺" "🇮🇸" "🇮🇪" "🇮🇹" "🇱🇻"
  "🇱🇮" "🇱🇹" "🇱🇺" "🇲🇹" "🇲🇩" "🇲🇨" "🇲🇪" "🇳🇱" "🇲🇰" "🇳🇴"
  "🇵🇱" "🇵🇹" "🇷🇴" "🇷🇸" "🇸🇲" "🇸🇰" "🇸🇮" "🇪🇸" "🇸🇪" "🇨🇭"
  "🇺🇦" "🇬🇧" "🇻🇦"
)

# Define colors (ANSI color codes)
colors=("36" "32" "33" "34" "35" "36" "37")

# Get terminal dimensions
columns=$(tput cols)
lines=$(tput lines)

# Initialize variables for movement
start_x=0
start_y=0
end_x=$((columns - 1))
end_y=$((lines - 1))

x=$start_x
y=$start_y
dx=1
dy=0

spinner_index=0
color_index=0
corner_count=0

ball_x=$((columns / 2))
ball_y=$((lines / 2))
ball_dx=-1
ball_dy=-1

# Function to clear the screen
clear_screen() {
        printf "\033c"
}

# Function to generate the spiraling effect with flags
generate_effect() {
        local num_flags=${#flags[@]}   # Number of flags
        local num_colors=${#colors[@]} # Number of colors

        while true; do
                # Get the current flag
                local flag=${flags[$spinner_index]}
                spinner_index=$(((spinner_index + 1) % num_flags))

                # Get the current color
                local color=${colors[$color_index]}
                color_index=$(((color_index + 1) % num_colors))

                # Print the colored flag at the current position
                printf "\033[${color}m\033[${y};${x}H${flag}\033[0m"

                # Update position
                x=$((x + dx))
                y=$((y + dy))

                # Check for reaching the end of each side and adjust direction accordingly
                if ((x > end_x)); then
                        x=$end_x
                        y=$((y + 1))
                        dx=0
                        dy=1
                elif ((y > end_y)); then
                        x=$((x - 1))
                        y=$end_y
                        dx=-1
                        dy=0
                elif ((x < start_x)); then
                        x=$start_x
                        y=$((y - 1))
                        dx=0
                        dy=-1
                elif ((y < start_y)); then
                        x=$((x + 1))
                        y=$start_y
                        dx=1
                        dy=0
                fi

                # Check for completing the full circle
                if ((x == start_x && y == start_y)); then
                        corner_count=$((corner_count + 1))

                        if ((corner_count == 5)); then
                                # Switch to bouncing ball effect after 5 complete circles
                                while true; do
                                        # Print the colored ball at the current position
                                        printf "\033[${color}m\033[${ball_y};${ball_x}H●\033[0m"

                                        # Update ball position
                                        ball_x=$((ball_x + ball_dx))
                                        ball_y=$((ball_y + ball_dy))

                                        # Check for bouncing off the walls
                                        if ((ball_x <= start_x || ball_x >= end_x)); then
                                                ball_dx=$((ball_dx * -1))
                                        fi
                                        if ((ball_y <= start_y || ball_y >= end_y)); then
                                                ball_dy=$((ball_dy * -1))
                                        fi

                                        sleep 0.01 # Adjust the sleep duration to control the speed of the effect
                                done
                        else
                                # Reduce the bounding box for the next circle
                                start_x=$((start_x + 1))
                                start_y=$((start_y + 1))
                                end_x=$((end_x - 1))
                                end_y=$((end_y - 1))
                                x=$((start_x))
                                y=$((start_y))
                        fi
                fi

                sleep 0.01 # Adjust the sleep duration to control the speed of the effect
        done
}

# Main loop
while true; do
        clear_screen
        generate_effect
done