# Ttyrec
A ttyrec is a recording of a terminal. For example, you can play a game of NetHack in a text-mode terminal, and record everything that NetHack shows. nethack.alt.org and hardfought.org record all games.
ttyrec files can be played back with several programs:

Name
Can rewind
Can play compressed (e.g. .gz)
Supports logarithmic time compression
Notes

IPBT
Yes (including frame by frame control)
No
Yes
May have issues emitting ncurses output, and is very slow to read ttyrecs

playttyrec.c (also see https://www.stack.nl/~jilles/games/)
No
No
No
Supports "fake" timing, where ttyrecs don't contain time information

ttyplay and ttyrec
No
No
No
Part of the original ttyrec package.

termplay
Yes (time based control, not frame by frame)
Yes
No
Note that the bundled termcat package may mangle timing

Jettyplay
Yes (full timing and frame by frame control)
Yes
Yes
Uses a GUI, but has significantly more features including a timeline and online URL loading.

A game may be split into many ttyrec files. There are multiple approaches for merging them into a single game:

Name
Notes

cat *.ttyrec &gt; path/to/out.ttyrec
Just by using built in Unix commands. Note that large time differences are maintained, so a player with logarithmic compression may be required.

termcat
Timing may be mangled. See details.

ttytie
Playback may break after the first concatenated file.

ttyrec format
A ttyrec consists of many frames. Each frame is made up of a twelve-byte header and an arbitrarily long data block. The twelve-byte header contains two pieces of information: how much data is in this frame and a timestamp. The timestamp is very precise; it has microsecond precision. The header bytes are aligned like so:

1 2 3 4 5 6 7 8 9 A B C
\-----/ \-----/ \-----/
  sec     usec    len

The bytes are in little-endian order (meaning least significant bytes first). You can portably read and process frames like this, in C:

while (fread(header, 1, 12, stdin) == 12)
{
  sec  = (((((header[ 3] &lt;&lt; 8) | header[ 2]) &lt;&lt; 8) | header[1]) &lt;&lt; 8) | header[0];
  usec = (((((header[ 7] &lt;&lt; 8) | header[ 6]) &lt;&lt; 8) | header[5]) &lt;&lt; 8) | header[4];
  len  = (((((header[11] &lt;&lt; 8) | header[10]) &lt;&lt; 8) | header[9]) &lt;&lt; 8) | header[8];

  received = fread(data, 1, len, stdin)
  if (len&nbsp;!= received)
    break;

  /* process data */
}

/* either the ttyrec is done or we had an error */

This page is a stub. Should you wish to do so, you can contribute by expanding this page.