summaryrefslogtreecommitdiffstats
path: root/_site/log/matrix-digital-rain/index.html
blob: 6007da53816c2b286955f0839bbc0e58638570e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <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>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>



  </head>
  <body>

    <div id="nav-container" class="container">
  <ul id="navlist" class="left">
    
    <li >
      <a href="/" class="link-decor-none">hme</a>
    </li>
    <li class="active">
      <a href="/log/" class="link-decor-none">log</a>
    </li>
    <li >
      <a href="/projects/" class="link-decor-none">poc</a>
    </li>
    <li >
      <a href="/about/" class="link-decor-none">abt</a>
    </li>
    <li><a href="/feed.xml" class="link-decor-none">rss</a></li>
  </ul>
</div>



    <main>
      <div class="container">
        <div class="container-2">
          <h2 class="center" id="title">RECREATING THE MATRIX RAIN WITH ANSI ESCAPE SEQUENCES</h2>
          <h6 class="center">21 DECEMBER 2025</h5>
          <br>
          <div class="twocol justify"><p>The Matrix digital rain implemented in raw C using ANSI escape sequences with
zero dependencies—not even ncurses.</p>

<video style="max-width:100%;" controls="" poster="poster.png">
  <source src="matrix.mp4" type="video/mp4" />
</video>

<p>This is a fork of Domsson’s unique rendition of the Matrix rain: <a href="https://github.com/domsson/fakesteak" class="external" target="_blank" rel="noopener noreferrer">Fakesteak</a>. 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.</p>

<h2 id="unicode-support">Unicode support</h2>

<p>Unicode support in the 2022 version lacked flexibility. The charset used in the
rain had to be a single contiguous block defined by <code class="language-plaintext highlighter-rouge">UNICODE_MIN</code> and
<code class="language-plaintext highlighter-rouge">UNICODE_MAX</code> settings:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#define UNICODE_MIN 0x0021
#define UNICODE_MAX 0x007E

static inline void insert_code(matrix *mat,
    size_t row, size_t col) 
{
    mat-&gt;code[index(mat, row, col)] = rand()
        % (UNICODE_MAX - UNICODE_MIN)
        + UNICODE_MIN;
}
</code></pre></div></div>

<p>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 <code class="language-plaintext highlighter-rouge">glyphs</code> array. In fact, the default rain now includes
both ASCII and half-width Katakana characters:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#define UNICODE(min, max)  (((uint64_t)max &lt;&lt; 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 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 &gt;&gt; 32);

    mat-&gt;code[index(mat, row, col)] = rand()
        % (unicode_max - unicode_min)
        + unicode_min;
}
</code></pre></div></div>

<p>Entries in the <code class="language-plaintext highlighter-rouge">glyphs</code> 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.</p>

<h2 id="phosphor-decay">Phosphor decay</h2>

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

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#define DECAY_MPLIER  2

static inline void blend(matrix *mat,
    size_t row, size_t col)
{
    unsigned char *color;

    color = mat-&gt;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;
}
</code></pre></div></div>

<p>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.</p>

<h2 id="the-algorithm">The algorithm</h2>

<p>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.</p>

<p>Lastly, to compile and run:</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>“All I see is blonde, brunette, red head.”</p>

<p>Files: <a href="source.tar.gz">source.tar.gz</a></p>
</div>
          <p class="post-author right">by W. D. Sadeep Madurange</p>
        </div>
      </div>
    </main>

    <div class="footer">
  <div class="container">
    <div class="twelve columns right container-2">
      <p id="footer-text">&copy; ASCIIMX - 2025</p>
    </div>
  </div>
</div>


  </body>
</html>