Published: 30. 8. 2012   Category: GNU/Linux

Nyan Cat, the BASH version

       ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄
      █  ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄  █
      █ █      ▄    ▄       █ █
      █ █   ▄        ▄▀▀▄   █ █▄▀▀▄
▄▀▀▄  █ █        ▄   █   ▀▄▄█▄▀   █
▀▄  ▀▀█ █     ▄      █            █
  ▀▀▄▄█ █  ▄        █   ▄█   ▄ ▄█  █
      █ █        ▄  █ ██ ▄  ▄  ▄ ███
     ▄█  ▀▄▄▄▄▄▄▄▄▄▄▄▀▄  ▀▀▀▀▀▀▀ ▄▀
   ▄▀ ▄▀▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▀▀▀▀▀▀▀▀▀▀
   █▄▄▀  █▄▄▀        █▄▄▀ ▀▄▄█

Here is it! Another version of this Internet meme. This time produced as ANSI art picture and some Bourne-Again Shell driven animation.

In comparison with another ANSI art version this version use finer graphics. Instead of big pixels from char ██ (or double space with color background) I use chars ▀ and ▄. So I can put two "pixels" into one char and combine them with background and foreground color. The standard ANSI color palette supports only 8 colors for background and 8 colors for foreground (with 2 levels of brightness), because brightness of background cannot be changed the picture of cat and trail uses only 8 colors, for bubbles the bright is on. (There is also xterm extension for 256 colors, but it not very supported in another terminal emulators.)

It works nice with standard 80x25 Linux console, PuTTY, gnome-terminal and xterm (but it depends on its current configuration), I did not try another terminal emulators.

Download

nyan_cat.sh

Known errors

Source code, with few comments

#!/bin/bash
#  --------------------------------------------------------------------------
#  (c) 2012 BruXy            Version: 1.0             http://bruxy.regnet.cz/
#  --------------------------------------------------------------------------
# switch off cursor, set blue background, clear screen
echo -e "\E[?25l\E[44m\E[2J"

# Play music
M=/tmp/cat_orig.mp3
[ ! -f $M ] && wget http://nyan.cat/music/original.mp3 -O $M >/dev/null 2>&1
while true; do mplayer $M > /dev/null 2>&1; done &

# easy way to reset terminal and exit subprocesses
trap "reset;killall nyan_cat.sh" 2

## Nyan cat ANSI picture data, my own creation :P, size 38 x 11
# Compressed version of picture
D="H4sIAHUNPlAAA22Q2w7CIAyG730rC1IGEs3itoS7cYlLvFGf37YcPMQvo5DxpT+pMYLb/8OVSxNv
Aiq1Db9sSmG1TgKqdhXqktKtsyBW6F08gB/EcgAUG2eAeRxbryqi1hq89yvQgfrFZ6If8E7sVoet
aVqWlNjqgYGlA5ckG5r4EGqvHmgtGeWzlqwLc6dJHD8Sr/IMQadMiTxR0IDrN/RUUjDnLJOghYn9
UgtyzvTcNvvdCw/8WhWjAQAA"

# decompress it to $C
C=`echo "$D" | base64 -d | zcat`

# hash field with 'pixel' atributes
declare -A B

B=([A]=43\;30m▀ [a]=43\;30m▄ [B]=47\;30m▀ [b]=47\;30m▄ [C]=43m\  [D]='47m '
[E]=1\;40\;37m▀\\E[0m [F]=44m\  [G]=40m\  [H]=1\;31m█\\E[0m [I]=0\;35m█
[J]=44\;30m▄ [j]=44\;30m▀ [K]=45\;30m▄ [k]=45\;30m▀ [L]=43\;35m▀
[l]=43\;35m▄ [M]=45\;31m▄ [O]=31m█ [o]=44\;31m▄ [P]=33m█ 
[R]=42\;33m▀ [S]=42\;32m█ [s]=46\;32m▀ [T]=46\;36m█ [t]=46\;30m▄
[U]=45\;35m█ [u]=46\;35m▀ [V]=43\;30m▄ [v]=42\;30m▀ [W]=45\;30m▀
[X]=43\;32m▄ [x]=32m█ [c]=44\;36m▀ [d]=42\;35m▄ [e]=41\;33m▄ [Z]=44m\\n)

# get size of terminal window
read X Y <<< `tput cols; tput lines`

# some terminals have problem with background color change
# this fills screen with spaces and fill my signature to bottom left
printf "%*s" $[X*Y] BruXy

##################
### Draw Nyan Cat
##################

# set position to the center
xp=$[(X-37)/2]
yp=$[(Y-11)/2]

# go through image data and draw them to specified position

j=1 #row    ... y
k=1 #column ... x
for i in {0..417} #38*11-1 image size
do
    p=${C:$i:1} # get pixel
    # put pixel to given position \E[y;xH
    echo -en "\E[$[j+yp];$[k+xp]H\E[${B[$p]}"
    # if pixel Z is found go to next row (pixel count worked strange)
    k=$[k++,k%38]; [ $p = 'Z' ] && : $[j++]
done

###################
### Star animation
###################

# Field with stars animation
S=("       " "      " "       " "       "
"       " "  ▄▀▄  " "      " "       "
"      " "      " "▀▀  ▀▀" "      "
"      " "     " "     " "    "
"      " "       " "     " "      ")

# function for star drawing
# $1 .. column, $2 .. row position
s () {
    echo -en "\E[1;37m" # set bright white
    for j in {0..4} # for each line
    do
        # draw one star frame of animation
        for i in {0..3}
        do
            echo -en "\E[$[i+$1];$[$2+m]H\E[1;37m${S[$[i+4*j]]}\E[0;44m"
        done

        sleep 0.2

        # erase star
        for i in {0..3}
        do
            echo -en "\E[$[i+$1];$[$2+m]H\E[44m${S[0]}"
        done
        : $[m-=5] # move the next frame 5 columns to the left
    done
}

# count star positions according to nyan cat position 
# -3,+3 best constant, I've played with those numbers
# to get best position of stars and do not destroy the cat :)
my=$[(Y-11)/2 - 3]
My=$[my+11 + 3]

while true
do
    for i in $(eval echo {1..$my..4}) # each position 4 rows difference
    do
        # draw top star, animation has 20 columns length, so generated
        # for lowest start position columns is 0+20
        (s $i $[20 + $RANDOM % (X - 20)]) &
        # draw bottom star 
        (s $[i+My] $[20 + $RANDOM % (X - 20)]) &
    done
    sleep 0.5
done &

######################
### Draw rainbow flag
######################

# oOPXxUuT .. top wave, OePxdUTc bottom wave
A="oOPXxUuTOePxdUTc";

# Flag waving:
# $c .. flip flop when counter $i modulo 5 is zero,
#       then it adress top or bottom wave
while true
do
    : $[c^=1]
    for x in `eval echo {1..$[xp]}`
    do
        if [ $[i++ % 5] -eq 4 ]; then : $[c^=1]; fi;
        for y in {0..7}
        do
            echo -en "\E["$[yp+y+2]";${x}H\E[${B[${A:$[y+(c*8)]:1}]}\E[0m"
        done
    done
    sleep 0.5
done