From aad38bc831c8bba90688df2cc28c46a46cac1112 Mon Sep 17 00:00:00 2001 From: Sadeep Madurange Date: Sun, 21 Dec 2025 01:10:18 +0800 Subject: Matrix post as a journal entry. --- _log/matrix-digital-rain.md | 101 +++++++++++++++----------------------------- 1 file changed, 35 insertions(+), 66 deletions(-) (limited to '_log') diff --git a/_log/matrix-digital-rain.md b/_log/matrix-digital-rain.md index d8e2543..0a3d30d 100644 --- a/_log/matrix-digital-rain.md +++ b/_log/matrix-digital-rain.md @@ -1,65 +1,34 @@ --- -title: The Matrix digital rain +title: Recreating the Matrix rain with ANSI escape sequences date: 2022-08-22 layout: post project: true thumbnail: thumb_sm.png --- -"All I see is blonde, brunette, red head." The iconic digital rain from The -Matrix in C, with zero dependencies—not even ncurses. - - - -## Overview - -This is my fork of Domsson's beautiful Fakesteak. While going through his code, I -wondered what it would take to faithfully recreate the original Matrix from the -first movie without sacrificing its minimalism. - -My implementation supports: - - - Unicode characters. - - 24-bit RGB colors (truecolor). - - Glitches in the matrix. - - Ghosting effect of old monochrome CRT displays. - - Closely resembles the Matrix seen in the background during Neo and Cypher's - conversation. - -With no dependencies, compilation is trivial: - -``` -$ cc -O3 main.c -o matrix -$ ./matrix -``` +rel="noopener noreferrer">Fakesteak: a beautifully lean rendition of the +Matrix rain in raw C using ANSI escape sequences—zero dependencies, not even +ncurses. -## How does it work? +The project's README noted that it 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. -The program tracks the state of the terminal, such as code points, background -and foreground colors, and cursor position, using multiple internal data -buffers. On each frame, it updates these buffers and repaints the screen using -ANSI escape codes: +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: -``` -static void term_print(const matrix *mat, size_t row, size_t col) -{ - size_t idx; - idx = mat_idx(mat, row, col); - wprintf(L"\x1b[%d;%dH\x1b[38;2;%d;%d;%dm%lc", - row, col, - mat->rgb[idx].color[R], - mat->rgb[idx].color[G], - mat->rgb[idx].color[B], - mat->code[idx]); -} -``` + -The ghosting effect is achieved by carefully scaling the RGB -channels before mixing them: +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, allowing me to emulate a dim afterglow by gradually +transitioning each raindrop's RGB values towards the background color: ``` static void mat_shade(matrix *mat, size_t row, size_t col) @@ -72,25 +41,25 @@ static void mat_shade(matrix *mat, size_t row, size_t col) } ``` -The ghosting function emulates the dim after glow by gradually transitioning -each raindrop's color towards the background color. This approach provides two -key benefits: straightforward color configuration that integrates naturally -with (Unix) ricing and high-fidelity recreation of the Matrix aesthetic. - -## Customization +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, really should flash white as well. -While you can alter almost every aspect, including speed, glitch frequency, and -rain density, the most common customizations are the color scheme and character -set. +Nonetheless, the rain closely resembles the original, is highly customizable, +and is gentle on the CPU. Not too bad for a weekend project. I tested the +program 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. -There are three color settings: head, tail, and background. You can configure -them using `COLOR_*_RED`, `COLOR_*_GRN`, and `COLOR_*_BLU` definitions found in -main.c. +Lastly, to compile and run: -The `UNICODE_MIN` and `UNICODE_MAX` values control the Unicode block used. For -example, setting them to `0x30A1` and `0x30F6` rains Katakana, if a font that -supports Katakana is present on the system: +``` +$ cc -O3 main.c -o matrix +$ ./matrix +``` - +"All I see is blonde, brunette, red head." Files: [source.tar.gz](source.tar.gz) -- cgit v1.2.3