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
|
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>The Matrix digital rain</title>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>The Matrix digital rain</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 >
<a href="/blog/" class="link-decor-none">blg</a>
</li>
<li class="active">
<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">THE MATRIX DIGITAL RAIN</h2>
<h6 class="center">12 JANUARY 2024</h5>
<br>
<div class="twocol justify"><p>“All I see is blonde, brunette, red head.” The iconic digital rain from The
Matrix, implemented in C, without dependencies (not even ncurses).</p>
<video style="max-width:100%;" controls="" poster="thumb.png">
<source src="matrix.mp4" type="video/mp4" />
</video>
<p>This project is a fork of Domsson’s beautiful <a href="https://github.com/domsson/fakesteak" class="external" target="_blank" rel="noopener noreferrer">Fakesteak</a>. Use the following commands to compile
and run the program:</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>While I loved Domsson’s take on the
digital rain, what blew my mind was the minimalistic elegance of his code. As I
carefully examined it, I thought about what it might take to recreate the
original digital rain from the first Matrix movie with it. The challenge is
adding these features without destroying fakesteak’s elegance.</p>
<h2 id="how-does-it-work">How does it work?</h2>
<p>The <code class="language-plaintext highlighter-rouge">matrix</code> struct makes use of three 2D arrays to encode the Matrix: the
<code class="language-plaintext highlighter-rouge">code</code> array for 32-bit Unicode characters, the <code class="language-plaintext highlighter-rouge">rgb</code> array for 24-bit RGB
values of the character (foreground color), and the <code class="language-plaintext highlighter-rouge">shade</code> array for the
degree of transparency of the character to simulate the ghosting effect of old
monochrome displays. The dimensions of these arrays depend on the size of the
terminal screen. Each slot in the array corresponds to a cursor position on the
screen.</p>
<p>The ghosting effect, which is arguably the crowning feature of my version, is
implemented by carefully scaling and mixing the RGB channels:</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)
{
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;
}
</code></pre></div></div>
<p>The above algorithm achieves transparency by iteratively bringing the
foreground color closer to the background color with each pass of the rain.
This approach offers multiple advantages, such as simpler and more natural
color configuration (background, foreground, and the color of the first drop)
that lends itself well to Unix ricing, and of course, recreates The Matrix rain
with high fidelity.</p>
<p>Rather than heavy-weight graphics tool kits, we use ANSI escape codes to
control the terminal screen. It’s the effective use of the ANSI escape codes
that greatly contributes to the minimalism of the solution:</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>Finally, the glitch effect is controlled by the following code:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if (mat.row[i] > 0 && rand() % 6 == 0) {
j = rand() % mat.row[i];
if (mat.code[mat_idx(&mat, j, mat.col[i])] != ' ') {
mat_put_code(&mat, j, mat.col[i]);
term_print(&mat, j, mat.col[i]);
}
}
</code></pre></div></div>
<p>The above code causes glitches in the Matrix with a probablity of 1/6.</p>
<h2 id="customizing-the-rain">Customizing the rain</h2>
<p>While you can customize almost any aspect of the rain including its speed,
glitch frequency, and the density of the rain, the most useful settings for
ricing are the color scheme and the character set used for the rain.</p>
<p>There are three color settings: the head, the tail, and the background. They
are configured by setting the <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 in main.c. 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 instance, setting them to <code class="language-plaintext highlighter-rouge">0x30A1</code> and <code class="language-plaintext highlighter-rouge">0x30F6</code> rains
Katakana code points:</p>
<p><img style="width: 100%;" src="katakana.png" /></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">© ASCIIMX - 2025</p>
</div>
</div>
</div>
</body>
</html>
|