Skip to content

Instantly share code, notes, and snippets.

@ostechnix
Last active December 25, 2025 20:22
Show Gist options
  • Select an option

  • Save ostechnix/66cecb6bbb9e35a492bccb9c6ecc5d9d to your computer and use it in GitHub Desktop.

Select an option

Save ostechnix/66cecb6bbb9e35a492bccb9c6ecc5d9d to your computer and use it in GitHub Desktop.
Bashmastree: A Bash Script to Display an Animated Christmas Tree in a Linux Terminal

BashmasTree πŸŽ„

Animated Christmas tree for your terminal!

Versions

πŸŽ„ 2026 Version (RECOMMENDED)

  • Fully responsive to terminal resizing
  • Animated falling snow
  • Enhanced decorations
  • Dynamic scaling
  • File: bashmastree_2026.sh

πŸŽ„ 2025 Version (Legacy)

  • Original simpler version
  • Lighter on resources
  • File: bashmastree_2025.sh
#!/usr/bin/env bash
# ------------------------------------------------------------------
# Script Name: christmas.sh
# Description: A Bash Script to display a
# Christmas tree in Terminal.
# Website: https://gist.github.com/ostechnix
# Version: 1
# Year: 2025
# Usage: chmod +x christmas.sh
# ./christmas.sh
# ------------------------------------------------------------------
# Clear the screen
clear
# Get terminal size
rows=$(tput lines)
cols=$(tput cols)
# Function to print spaces
print_spaces() {
for ((space=0; space<$1; space++)); do
echo -n " "
done
}
# Function to print leaves with occasional blinking lights
print_leaves() {
for ((leaf=0; leaf<$1; leaf++)); do
# Randomly decide to print a leaf or a light
if (( RANDOM % 20 < 2 )); then # Adjust the frequency of lights here
# Randomly choose a color for the blinking light
case $(( RANDOM % 4 )) in
0) echo -n -e "\e[5;35mo\e[0m" ;; # Blinking Pink
1) echo -n -e "\e[5;34mo\e[0m" ;; # Blinking Blue
2) echo -n -e "\e[5;33mo\e[0m" ;; # Blinking Yellow
3) echo -n -e "\e[5;37mo\e[0m" ;; # Blinking White
esac
else
echo -n -e "\e[32m*\e[0m" # Green color for *
fi
done
}
# Function to print the trunk
print_trunk() {
local trunk_width=${#1}
local center=$((size - trunk_width / 2))
print_spaces $center
echo -e "\e[33m$1\e[0m" # Brown color for the trunk
}
# Function to print the tree
print_tree() {
# Size of the tree
size=10
# Calculate the starting row and column
start_row=$(( (rows - size - 10) / 2 ))
start_col=$(( (cols - 2 * size) / 2 ))
# Loop to print the tree
for ((i=1; i<=$size; i++)); do
tput cup $((start_row + i)) $start_col
print_spaces $((size-i))
print_leaves $((2*i-1))
echo
done
# Print the trunk
trunk="HMH"
for ((i=0; i<3; i++)); do
tput cup $((start_row + size + i + 1)) $start_col
print_trunk $trunk
done
}
# Function to print the messages
print_messages() {
local message1="MERRY CHRISTMAS"
local message2="HAPPY NEW YEAR 2025"
local start_row1=$((start_row + size + 5))
local start_row2=$((start_row1 + 1))
local col1=$(( (cols - ${#message1}) / 2 ))
local col2=$(( (cols - ${#message2}) / 2 ))
# Print first message
for ((i=0; i<=${#message1}; i++)); do
tput cup $start_row1 $col1
echo -e "\e[1;36m${message1:0:i}\e[0m"
sleep 0.2
done
# Print second message
for ((i=0; i<=${#message2}; i++)); do
tput cup $start_row2 $col2
echo -e "\e[1;36m${message2:0:i}\e[0m"
sleep 0.2
done
}
# Print exit instructions
print_exit_instructions() {
tput cup $((rows - 2)) 0
echo -e "\e[1;31mPress Ctrl+C to exit\e[0m"
}
# Main loop to keep refreshing the tree and display messages
while true; do
print_tree
print_exit_instructions
print_messages
sleep 0.2 # Pause after the complete messages are shown
done
#!/usr/bin/env bash
# ------------------------------------------------------------------
# Script Name: christmas.sh
# Description: Enhanced Christmas tree with snow and animations
# Fully responsive to terminal resizing!
# Optimized for dark terminal backgrounds!
# Website: https://gist.github.com/ostechnix
# Version: 2 (Responsive)
# Year: 2026
# Usage: chmod +x christmas.sh
# ./christmas.sh
# Note: Recommended minimum terminal size: 80x25
# Tree scales automatically with window size
# Best viewed on dark terminal themes
# ------------------------------------------------------------------
# Hide cursor
tput civis
# Terminal size variables
rows=0
cols=0
start_row=0
start_col=0
size=12
resize_flag=0
# Snow array
declare -a snow_x
declare -a snow_y
snow_count=30
# Function to update terminal size
update_terminal_size() {
rows=$(tput lines)
cols=$(tput cols)
# Adjust tree size based on terminal size - more granular scaling
if (( rows < 25 )); then
size=6
elif (( rows < 30 )); then
size=8
elif (( rows < 35 )); then
size=10
elif (( rows < 40 )); then
size=12
elif (( rows < 50 )); then
size=15
elif (( rows < 60 )); then
size=18
else
size=20 # Maximum size for very large terminals
fi
# Adjust snow count based on terminal size
local new_snow_count=$(( (rows * cols) / 80 ))
if (( new_snow_count < 15 )); then
new_snow_count=15
elif (( new_snow_count > 80 )); then
new_snow_count=80
fi
snow_count=$new_snow_count
# Recalculate positions with new size
start_row=$(( (rows - size - 12) / 2 ))
if (( start_row < 0 )); then
start_row=0
fi
start_col=$(( (cols - 2 * size) / 2 ))
if (( start_col < 0 )); then
start_col=0
fi
}
# Initialize terminal size
update_terminal_size
# Initialize snow with dynamic count
init_snow() {
snow_x=()
snow_y=()
for ((i=0; i<snow_count; i++)); do
snow_x[$i]=$((RANDOM % cols))
snow_y[$i]=$((RANDOM % rows))
done
}
init_snow
# Handle window resize
handle_resize() {
resize_flag=1
}
# Function to print spaces
print_spaces() {
for ((space=0; space<$1; space++)); do
echo -n " "
done
}
# Function to print leaves with ornaments and lights
print_leaves() {
for ((leaf=0; leaf<$1; leaf++)); do
rand=$((RANDOM % 100))
if (( rand < 5 )); then
# Blinking lights - vibrant colors for dark terminals
case $(( RANDOM % 6 )) in
0) echo -n -e "\e[1;91m●\e[0m" ;; # Bright Red
1) echo -n -e "\e[1;93m●\e[0m" ;; # Bright Yellow
2) echo -n -e "\e[1;94m●\e[0m" ;; # Bright Blue
3) echo -n -e "\e[1;95m●\e[0m" ;; # Bright Magenta
4) echo -n -e "\e[1;96m●\e[0m" ;; # Bright Cyan
5) echo -n -e "\e[1;97m●\e[0m" ;; # Bright White
esac
elif (( rand < 8 )); then
# Ornaments
case $(( RANDOM % 4 )) in
0) echo -n -e "\e[1;31mβ—‰\e[0m" ;; # Red ornament
1) echo -n -e "\e[1;33mβ—‰\e[0m" ;; # Gold ornament
2) echo -n -e "\e[1;35mβ—‰\e[0m" ;; # Purple ornament
3) echo -n -e "\e[1;36mβ—‰\e[0m" ;; # Cyan ornament
esac
else
# Green leaves
case $(( RANDOM % 3 )) in
0) echo -n -e "\e[32m*\e[0m" ;; # Medium green
1) echo -n -e "\e[1;32m*\e[0m" ;; # Bright green
2) echo -n -e "\e[2;32m*\e[0m" ;; # Dim green
esac
fi
done
}
# Function to print the trunk
print_trunk() {
local trunk_width=${#1}
# Center trunk under tree: tree base center is at (size-1), trunk center should align
local center=$((size - 1 - trunk_width / 2))
print_spaces $center
echo -e "\e[38;5;94m$1\e[0m" # Brown color for the trunk
}
# Function to update and draw snow
draw_snow() {
# Calculate message area to avoid
local message_start_row=$((start_row + size + 7))
local message_end_row=$((message_start_row + 3))
local exit_row=$((rows - 2))
for ((i=0; i<snow_count; i++)); do
# Clear old position (only if within bounds)
if (( snow_y[$i] >= 0 && snow_y[$i] < rows && snow_x[$i] >= 0 && snow_x[$i] < cols )); then
# Don't clear if in message area or exit instruction area
if (( snow_y[$i] < message_start_row || snow_y[$i] > message_end_row )) && (( snow_y[$i] != exit_row )); then
tput cup ${snow_y[$i]} ${snow_x[$i]} 2>/dev/null
echo -n " "
fi
fi
# Update position
snow_y[$i]=$((snow_y[$i] + 1))
# Reset if out of bounds
if (( snow_y[$i] >= rows - 1 || snow_x[$i] >= cols )); then
snow_y[$i]=0
snow_x[$i]=$((RANDOM % cols))
fi
# Draw new position (avoid tree area, message area, AND exit instruction)
if (( snow_y[$i] >= 0 && snow_y[$i] < rows && snow_x[$i] >= 0 && snow_x[$i] < cols )); then
if (( (snow_y[$i] < start_row || snow_y[$i] > start_row + size + 5) &&
(snow_y[$i] < message_start_row || snow_y[$i] > message_end_row) &&
snow_y[$i] != exit_row )); then
tput cup ${snow_y[$i]} ${snow_x[$i]} 2>/dev/null
# White snow - natural and beautiful on dark terminals
echo -n -e "\e[1;97m❄\e[0m"
fi
fi
done
}
# Function to print the tree
print_tree() {
# Loop to print the tree (removed star on top)
for ((i=1; i<=$size; i++)); do
local row=$((start_row + i))
if (( row >= 0 && row < rows )); then
tput cup $row $start_col 2>/dev/null
print_spaces $((size-i))
print_leaves $((2*i-1))
fi
done
# Print the trunk - scale trunk height with tree size
local trunk_height=4
if (( size > 12 )); then
trunk_height=5
fi
if (( size > 16 )); then
trunk_height=6
fi
trunk="|||"
for ((i=0; i<trunk_height; i++)); do
local row=$((start_row + size + i + 1))
if (( row >= 0 && row < rows )); then
tput cup $row $start_col 2>/dev/null
print_trunk $trunk
fi
done
}
# Function to print the messages with gradient effect
print_messages() {
local message1="πŸŽ„ MERRY CHRISTMAS πŸŽ„"
local message2="✨ HAPPY NEW YEAR 2026 ✨"
local start_row1=$((start_row + size + 7))
local start_row2=$((start_row1 + 2))
# Calculate proper centering (accounting for emoji display width)
# Each emoji typically renders as 2 characters wide
local msg1_text=" MERRY CHRISTMAS "
local msg2_text=" HAPPY NEW YEAR 2026 "
# Only print if within terminal bounds
if (( start_row1 < rows - 3 && cols > 30 )); then
local col1=$(( (cols - ${#msg1_text} - 4) / 2 )) # -4 for emoji width
tput cup $start_row1 $col1 2>/dev/null
echo -e "\e[1;91m$message1\e[0m"
fi
if (( start_row2 < rows - 3 && cols > 30 )); then
local col2=$(( (cols - ${#msg2_text} - 4) / 2 ))
tput cup $start_row2 $col2 2>/dev/null
echo -e "\e[1;96m$message2\e[0m"
fi
}
# Print exit instructions
print_exit_instructions() {
if (( rows > 2 )); then
tput cup $((rows - 2)) 0 2>/dev/null
# Red works well on both backgrounds
echo -e "\e[1;31m❄ Press Ctrl+C to exit ❄\e[0m"
fi
}
# Cleanup function
cleanup() {
tput cnorm # Show cursor
clear
exit 0
}
# Trap Ctrl+C and window resize
trap cleanup INT TERM
trap handle_resize WINCH
# Initial clear and draw
clear
print_tree
print_messages
print_exit_instructions
# Main animation loop
frame=0
while true; do
# Handle terminal resize
if (( resize_flag == 1 )); then
clear
update_terminal_size
init_snow
print_tree
print_messages
print_exit_instructions
resize_flag=0
fi
# Redraw tree periodically for blinking effect
if (( frame % 3 == 0 )); then
print_tree
print_messages
print_exit_instructions
fi
# Update snow
draw_snow
frame=$((frame + 1))
sleep 0.15
done
@ostechnix
Copy link
Author

Display Animated Christmas Tree In Terminal:

Display Animated Christmas Tree In Terminal:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment