diff options
| author | Sadeep Madurange <sadeep@asciimx.com> | 2025-12-21 01:10:18 +0800 |
|---|---|---|
| committer | Sadeep Madurange <sadeep@asciimx.com> | 2025-12-21 01:21:00 +0800 |
| commit | aad38bc831c8bba90688df2cc28c46a46cac1112 (patch) | |
| tree | 7ccd19e374254b52502a9cf1d9a0e5f8347a4cf6 /_site/log/matrix-digital-rain | |
| parent | e15f1076b59e997108914f6a5b9b28652d323268 (diff) | |
| download | www-aad38bc831c8bba90688df2cc28c46a46cac1112.tar.gz | |
Matrix post as a journal entry.
Diffstat (limited to '_site/log/matrix-digital-rain')
| -rw-r--r-- | _site/log/matrix-digital-rain/index.html | 100 |
1 files changed, 34 insertions, 66 deletions
diff --git a/_site/log/matrix-digital-rain/index.html b/_site/log/matrix-digital-rain/index.html index 26244b3..ac4a536 100644 --- a/_site/log/matrix-digital-rain/index.html +++ b/_site/log/matrix-digital-rain/index.html @@ -2,12 +2,12 @@ <html> <head> <meta charset="utf-8"> - <title>The Matrix digital rain</title> + <title>Recreating the Matrix rain with ANSI escape sequences</title> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>The Matrix digital rain</title> + <title>Recreating the Matrix rain with ANSI escape sequences</title> <link rel="stylesheet" href="/assets/css/main.css"> <link rel="stylesheet" href="/assets/css/skeleton.css"> </head> @@ -41,61 +41,30 @@ <main> <div class="container"> <div class="container-2"> - <h2 class="center" id="title">THE MATRIX DIGITAL RAIN</h2> + <h2 class="center" id="title">RECREATING THE MATRIX RAIN WITH ANSI ESCAPE SEQUENCES</h2> <h6 class="center">22 AUGUST 2022</h5> <br> - <div class="twocol justify"><p>“All I see is blonde, brunette, red head.” The iconic digital rain from The -Matrix in C, with zero dependencies—not even ncurses.</p> + <div class="twocol justify"><p>Over the weekend, I came across Domsson’s <a href="https://github.com/domsson/fakesteak" class="external" target="_blank" rel="noopener noreferrer">Fakesteak</a>: a beautifully lean rendition of the +Matrix rain in raw C using ANSI escape sequences—zero dependencies, not even +ncurses.</p> + +<p>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.</p> + +<p>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:</p> <video style="max-width:100%;" controls="" poster="poster.png"> <source src="matrix.mp4" type="video/mp4" /> </video> -<h2 id="overview">Overview</h2> - -<p>This is my fork of Domsson’s beautiful <a href="https://github.com/domsson/fakesteak" class="external" target="_blank" rel="noopener noreferrer">Fakesteak</a>. 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.</p> - -<p>My implementation supports:</p> - -<ul> - <li>Unicode characters.</li> - <li>24-bit RGB colors (truecolor).</li> - <li>Glitches in the matrix.</li> - <li>Ghosting effect of old monochrome CRT displays.</li> - <li>Closely resembles the Matrix seen in the background during Neo and Cypher’s -conversation.</li> -</ul> - -<p>With no dependencies, compilation is trivial:</p> - -<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cc -O3 main.c -o matrix -$ ./matrix -</code></pre></div></div> - -<h2 id="how-does-it-work">How does it work?</h2> - -<p>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:</p> - -<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>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]); -} -</code></pre></div></div> - -<p>The ghosting effect is achieved by carefully scaling the RGB -channels before mixing them:</p> +<p>Adding Unicode support via <code class="language-plaintext highlighter-rouge">wchar_t</code> and <code class="language-plaintext highlighter-rouge">wprintf()</code> 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:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>static void mat_shade(matrix *mat, size_t row, size_t col) { @@ -107,26 +76,25 @@ channels before mixing them:</p> } </code></pre></div></div> -<p>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.</p> - -<h2 id="customization">Customization</h2> +<p>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.</p> -<p>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.</p> +<p>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.</p> -<p>There are three color settings: head, tail, and background. You can configure -them using <code class="language-plaintext highlighter-rouge">COLOR_*_RED</code>, <code class="language-plaintext highlighter-rouge">COLOR_*_GRN</code>, and <code class="language-plaintext highlighter-rouge">COLOR_*_BLU</code> definitions found in -main.c.</p> +<p>Lastly, to compile and run:</p> -<p>The <code class="language-plaintext highlighter-rouge">UNICODE_MIN</code> and <code class="language-plaintext highlighter-rouge">UNICODE_MAX</code> values control the Unicode block used. For -example, setting them to <code class="language-plaintext highlighter-rouge">0x30A1</code> and <code class="language-plaintext highlighter-rouge">0x30F6</code> rains Katakana, if a font that -supports Katakana is present on the system:</p> +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cc -O3 main.c -o matrix +$ ./matrix +</code></pre></div></div> -<p><img style="width: 100%;" src="katakana.png" /></p> +<p>“All I see is blonde, brunette, red head.”</p> <p>Files: <a href="source.tar.gz">source.tar.gz</a></p> </div> |
