RECREATING THE MATRIX RAIN WITH ANSI ESCAPE SEQUENCES
22 AUGUST 2022
Over the weekend, I came across Domsson’s Fakesteak: a beautifully lean rendition of the
Matrix rain in raw C using ANSI escape sequences—zero dependencies, not even
ncurses.
To keep things simple, Fakesteak didn’t support Japanese characters and that it
used 8-bit color mode. The latter meant that the ghosting effect has to rely on
different foreground colors rather than shades of the same color. As a tip of
the hat to Domsson’s impressive work, I decided to add Unicode and 24-bit
truecolor support to it, aiming to faithfully recreate the original Matrix from
the first movie during Neo and Cypher’s conversation:
Adding Unicode support via wchar_t and wprintf() was easy enough.
Implementing the ghosting effect with truecolor support, however, turned out
harder than expected. To achieve the ghosting effect, I treated phosphor decay
as a multiplier, which allowed me to emulate the dim afterglow by gradually
transitioning each raindrop’s color towards the background color:
static void mat_shade(matrix *mat, size_t row, size_t col)
{
unsigned char *color;
color = mat->rgb[mat_idx(mat, row, col)].color;
color[R] = color[R] - (color[R] - COLOR_BG_RED) / 2;
color[G] = color[G] - (color[G] - COLOR_BG_GRN) / 2;
color[B] = color[B] - (color[B] - COLOR_BG_BLU) / 2;
}
Looking back at the implementation, there are still a few improvements to be
made. Instead of using a dedicated buffer, I should have bit-packed the
phosphor decay into the RGB data buffer to save memory. I’m not entirely
satisfied with the Unicode support as it’s restricted to contiguous code
points. The glitch effect, which I implemented with characters unexpectedly
changing, would have been closer to the original if flashed white as well.
Nonetheless, the rain resembles the original with high visual fidelity. It’s
highly customizable and gentle on the CPU. On my 14” ThinkPad T490, which has a
resolution of 1920x1080 and 4GHz CPU, it uses 2-3% of the CPU with occasional
jumps of up to about 8%. Not too bad for a weekend project. The program has
been tested with xterm and urxvt terminal emulators on OpenBSD and Arch Linux
systems. Someone has managed to get it moving on a Raspberry Pi as well.
Lastly, to compile and run:
$ cc -O3 main.c -o matrix
$ ./matrix
“All I see is blonde, brunette, red head.”
Files: source.tar.gz
Over the weekend, I came across Domsson’s Fakesteak: a beautifully lean rendition of the Matrix rain in raw C using ANSI escape sequences—zero dependencies, not even ncurses.
To keep things simple, Fakesteak didn’t support Japanese characters and that it used 8-bit color mode. The latter meant that the ghosting effect has to rely on different foreground colors rather than shades of the same color. As a tip of the hat to Domsson’s impressive work, I decided to add Unicode and 24-bit truecolor support to it, aiming to faithfully recreate the original Matrix from the first movie during Neo and Cypher’s conversation:
Adding Unicode support via wchar_t and wprintf() was easy enough.
Implementing the ghosting effect with truecolor support, however, turned out
harder than expected. To achieve the ghosting effect, I treated phosphor decay
as a multiplier, which allowed me to emulate the dim afterglow by gradually
transitioning each raindrop’s color towards the background color:
static void mat_shade(matrix *mat, size_t row, size_t col)
{
unsigned char *color;
color = mat->rgb[mat_idx(mat, row, col)].color;
color[R] = color[R] - (color[R] - COLOR_BG_RED) / 2;
color[G] = color[G] - (color[G] - COLOR_BG_GRN) / 2;
color[B] = color[B] - (color[B] - COLOR_BG_BLU) / 2;
}
Looking back at the implementation, there are still a few improvements to be made. Instead of using a dedicated buffer, I should have bit-packed the phosphor decay into the RGB data buffer to save memory. I’m not entirely satisfied with the Unicode support as it’s restricted to contiguous code points. The glitch effect, which I implemented with characters unexpectedly changing, would have been closer to the original if flashed white as well.
Nonetheless, the rain resembles the original with high visual fidelity. It’s highly customizable and gentle on the CPU. On my 14” ThinkPad T490, which has a resolution of 1920x1080 and 4GHz CPU, it uses 2-3% of the CPU with occasional jumps of up to about 8%. Not too bad for a weekend project. The program has been tested with xterm and urxvt terminal emulators on OpenBSD and Arch Linux systems. Someone has managed to get it moving on a Raspberry Pi as well.
Lastly, to compile and run:
$ cc -O3 main.c -o matrix
$ ./matrix
“All I see is blonde, brunette, red head.”
Files: source.tar.gz