VT100 Animations

This is a fun exercise in retro-computing.

There is a cool website called textfiles.com, which has almost every "viral" text file archived from the 80s onward. Browsing this website is a great way to spend an afternoon relaxing and geeking out.

Of course, there is an entire subsection dedicated to VT100 animations. These are text files that contain special escape sequences that "smart" terminals (such as the VT100 and derivatives) recognize. These escape sequences can manipulate the cursor position and change font properties.

The animation "text" files were designed to be printed directly to a VT100 terminal. Unfortunately, I don't own a hardware VT100 terminal. (Although if you have a working unit that you wish to sell/donate, please let me know.)

However, all desktop Linux distributions come with a program that emulates VT100 terminals: xterm.

There is one problem though. xterm runs extremely fast, and the animation only takes a fraction of a second to run. We need to slow down terminal emulation somehow.

Perl comes to the rescue! The following quick-and-dirty script inserts two artificial delays while printing a text file.

Both parameters can be customized using flags.

#!/usr/bin/env perl
#
# scat 
#
# sleepy-cat - like cat, except delay a little bit to emulate the
# behavior of an old terminal
#
# By default a delay is inserted after every line feed (to emulate
# screen refresh), and a smaller delay is inserted between every
# character (to emulate slow baud rate).
#
# -nXX sets the newline output rate in frames per second (default is 60)
# -cXX sets the character output rate in frames per second (default 12800)
#      (set either option to 0 to disable)
#
# There are no spaces between the letter option and its number value
# (i.e. "-c15" is valid, but "-c 15" is not)

use strict;
use warnings;
use Time::HiRes qw(time usleep);
use List::Util qw(max);

my $linewait = 1e6 / 60;
my $charwait = 1e6 / 12800;

# Parse parameters
while (defined($ARGV[0]) && $ARGV[0] =~ /^-/) {
    $_ = shift @ARGV;
    if (/^-n(\d+)/) {$linewait = $1 == 0? 0: 1e6 / $1;}
    elsif (/^-c(\d+)/) {$charwait = $1 == 0 ? 0 : 1e6 / $1;}
    elsif (/^-$/) {unshift @ARGV, $_; last}
    elsif (/^--$/) {last;}
    else {die "Unknown parameter $_";}
}

if ($charwait > 0) {
    $| = 1;
    while (<>) {
	my $t0 = time();
	foreach (split //, $_) {
	    print;
	    usleep($charwait);
	}
	my $elapsed = (time() - $t0) * 1e6;
	usleep(max(0, $linewait - $elapsed));
    }
}
# If charwait is disabled, we can skip many extra steps.
else {
    while (<>) {
	print;
	usleep($linewait);
    }
}

The results are amazing, and watching these animations is another great way to spend a geeky afternoon.

bambi_godzilla.png

Source files

Suggestions? Comments?

Please contact me.