Do you want to know, what it is? What drove me to make this silly effect?
It's nothing grand really. Just thought it would be cool and fit the website! ("rule of cool" is back with a vengeance). I've loved the Matrix movies for a while now, and thought that it was a good balance of cool, corny, and fitting to the whole 90's aesthetic.
Despite other methods that could render it faster and with a bit more flair, I decided to give myself a couple of fun constraints:
So, I started with the boring stuff: prepping the DOM to load the Matrix.
As I write more of this blog, I hope that it comes across how anal I am about making my websites work cross platform. This effect is no exception.
To setup the DOM to render the Matrix effect, a function is ran whenever a screen width update event is fired (either on DOM load or by changing window size). This function splits the width of the screen into 16px intervals, and appends the positions of each interval to a state array. This ensures that when switching back and forth between screen sizes, the correct amount of falling text columns ("Matrix Streams" as I'll call them henceforth) are rendered!
What made React great for this is that I could break each text stream into its own component, and handle its own state independent from the rest of the Matrix effect. While I thought about breaking each character down into it's own element to make the effect more "movie accurate", I reasoned it would be too much of a performance hit on an already expensive effect.
Now, I went on to where the magic happens: the MatrixStream component. From the last step, there exists an array of positions mapped to MatrixStream elements, which is used to position each stream of text across the screen. These streams exist in two states: "alive" and "dead". Initially, all streams are marked as dead, which informs each MatrixStream component to begin its own rendering process. A timeout is set in a bounded random range for each stream to wait out before rendering text to the screen.
Once the initial timeout has passed for a particular stream, the text-rendering function is called. This function runs a loop that picks a random unicode character out of a range, appends it and a newline to a <p> element that contains the stream text, and then waits 25ms before repeating the process. This loop continues to run until the <p> element's height is greater than or equal to the height of the window. Note that the height of the paragraph is increasing with each character of text and newline that is added.
After the loop is complete, the stream is not marked dead immediately. Rather, a 2s "fade-out" animation is played, and afterwards the stream is marked dead again. This was my compromise to make something look "Matrix-like" while still being somewhat performant. Rather than render individual states of animation/coloring for each character of text, one animation is ran per column, saving rendering resources.
Finally, once a stream is marked dead again, a useEffect hook fires on the state change and goes through the same actions as when the stream was initially marked dead: clear all text in the stream, remove all animation classes, and start a bounded random countdown to run the whole function again. Violia, a column of Matrix text!
While I very much love how this effect turned out and its relative simplicity, it is far from flawless. Two primary issues arise:
Regarding the first issue, this is due to every single stream being marked "dead" at once on page load. Despite leaving an initial wait time for each Matrix stream to begin rendering, the ranges are not de-synced enough yet to prevent this from happening. After a couple of render cycles, each stream of the Matrix will start to diverge more and more from the rest, but some more first render calculation is needed to prevent clustering on initial load.
As for the second: a HTML <canvas> element would lead to increased performance due to being optimized for frequent re-draws. In a future version of this effect, I may very well try to rebuild it using <canvas> elements, but using <p> elements proved to be a fun challenge and an interesting proof of concept. Coloring and animations could start to get quite flashy using <canvas>, and I'm curious to see how I could add more to the effect in the future!
While there are other smaller issues (and likely blindspots I haven't caught yet) present, I think that building this text stream effect has been a blast overall. I'm quite pleased with the final result, and I think that it adds some unique visual flair to a website already exploding with color and styling! It's been a fun excersize in using React and Tailwind's strengths to go beyond basic DOM construction for sure.
With that, I'll end my analysis here. Thanks for tumbling down this rabbit hole with me, and stay rad!
Copyright © 2025 Mason Shields
You are free to use any code on this website, but ask if you want to use content!