From 08e594268ed20c5c2355a249ac691c007e38aed9 Mon Sep 17 00:00:00 2001 From: Sadeep Madurange Date: Mon, 22 Dec 2025 23:38:06 +0800 Subject: Matrix post. --- _site/log/matrix-digital-rain/index.html | 105 +++++++++++++++++++++------- _site/log/matrix-digital-rain/matrix.mp4 | Bin 930430 -> 696574 bytes _site/log/matrix-digital-rain/poster.png | Bin 70901 -> 233077 bytes _site/log/matrix-digital-rain/source.tar.gz | Bin 2075 -> 3602 bytes _site/log/matrix-digital-rain/thumb_sm.png | Bin 22764 -> 52762 bytes 5 files changed, 78 insertions(+), 27 deletions(-) (limited to '_site/log/matrix-digital-rain') diff --git a/_site/log/matrix-digital-rain/index.html b/_site/log/matrix-digital-rain/index.html index cf04bde..6007da5 100644 --- a/_site/log/matrix-digital-rain/index.html +++ b/_site/log/matrix-digital-rain/index.html @@ -42,45 +42,96 @@

RECREATING THE MATRIX RAIN WITH ANSI ESCAPE SEQUENCES

-
22 AUGUST 2022
+
21 DECEMBER 2025

-

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:

+

The Matrix digital rain implemented in raw C using ANSI escape sequences with +zero dependencies—not even ncurses.

-

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:

+

This is a fork of Domsson’s unique rendition of the Matrix rain: Fakesteak. Three years ago, I forked his project +and added truecolor and Unicode support. I also drastically modified the +algorithm to produce a rain that resembled the original aesthetic with high +visual fidelity.

+ +

Unicode support

+ +

Unicode support in the 2022 version lacked flexibility. The charset used in the +rain had to be a single contiguous block defined by UNICODE_MIN and +UNICODE_MAX settings:

+ +
#define UNICODE_MIN 0x0021
+#define UNICODE_MAX 0x007E
+
+static inline void insert_code(matrix *mat,
+    size_t row, size_t col) 
+{
+    mat->code[index(mat, row, col)] = rand()
+        % (UNICODE_MAX - UNICODE_MIN)
+        + UNICODE_MIN;
+}
+
+ +

There was no way, for instance, to use both ASCII and Katakana at the same +time. The user had to pick one. In the new version, the user can use any number +of Unicode blocks using glyphs array. In fact, the default rain now includes +both ASCII and half-width Katakana characters:

+ +
#define UNICODE(min, max)  (((uint64_t)max << 32) | min)
+
+static uint64_t glyphs[] = {
+    UNICODE(0x0021, 0x007E), /* ASCII */
+    UNICODE(0xFF65, 0xFF9F), /* Half-width Katakana */
+};
+
+static uint8_t glyphlen = (sizeof glyphs) / (sizeof glyphs[0]);
 
-
static void mat_shade(matrix *mat, size_t row, size_t col) 
+static inline void insert_code(matrix *mat,
+    size_t row, size_t col) 
+{
+    uint64_t block;
+    uint32_t unicode_min, unicode_max;
+
+    block = glyphs[(rand() % glyphlen)];
+    unicode_min = (uint32_t)block;
+    unicode_max = (uint32_t)(block >> 32);
+
+    mat->code[index(mat, row, col)] = rand()
+        % (unicode_max - unicode_min)
+        + unicode_min;
+}
+
+ +

Entries in the glyphs array are Unicode blocks bit-packed in an 8-byte +container: the four low bytes forms the first codepoint and the four high bytes +the last.

+ +

Phosphor decay

+ +

The dim afterglow of monochrome CRT displays is achieved by carefully scaling +the RGB channels individually and mixing them:

+ +
#define DECAY_MPLIER  2
+
+static inline void blend(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;
+
+    color = mat->rgb[index(mat, row, col)].color;
+    color[R] = color[R] - (color[R] - RGB_BG_RED) / DECAY_MPLIER;
+    color[G] = color[G] - (color[G] - RGB_BG_GRN) / DECAY_MPLIER;
+    color[B] = color[B] - (color[B] - RGB_BG_BLU) / DECAY_MPLIER;
 }
 
-

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.

+

The blending function emulates the phosphor decay by gradually transitioning +each raindrop’s color towards the background color. The multiplier is the +number of passes over the rain track needed before the afterglow disappears.

+ +

The algorithm

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 diff --git a/_site/log/matrix-digital-rain/matrix.mp4 b/_site/log/matrix-digital-rain/matrix.mp4 index 84a9839..7edf5d6 100644 Binary files a/_site/log/matrix-digital-rain/matrix.mp4 and b/_site/log/matrix-digital-rain/matrix.mp4 differ diff --git a/_site/log/matrix-digital-rain/poster.png b/_site/log/matrix-digital-rain/poster.png index 0321ad3..1f68ca4 100644 Binary files a/_site/log/matrix-digital-rain/poster.png and b/_site/log/matrix-digital-rain/poster.png differ diff --git a/_site/log/matrix-digital-rain/source.tar.gz b/_site/log/matrix-digital-rain/source.tar.gz index fead280..5a69236 100644 Binary files a/_site/log/matrix-digital-rain/source.tar.gz and b/_site/log/matrix-digital-rain/source.tar.gz differ diff --git a/_site/log/matrix-digital-rain/thumb_sm.png b/_site/log/matrix-digital-rain/thumb_sm.png index d3f06c9..940965a 100644 Binary files a/_site/log/matrix-digital-rain/thumb_sm.png and b/_site/log/matrix-digital-rain/thumb_sm.png differ -- cgit v1.2.3