So I rewrote the viewer for a piece of software I built called Chore Brain. Chore Brain handles the chores and the logic. Chores Kiosk is the screen I actually interact with. The original setup used Go and Chromium, and the Go part was always lightweight. What eventually needed replacing was the part drawing everything on the screen.
This is running on old hardware, a Raspberry Pi 3, connected to a portable touchscreen monitor. You can pick up regular portable monitors for around a hundred dollars, and a touchscreen version costs a little more. The Pi boots straight into the interface. No opening a browser, no finding an app. Turn it on and the board is there.
Naturally, I put a ridiculous amount of red Matrix rain behind it.
Wherever I touch the screen, a wave spreads out through the characters, bending and magnifying them like dropping something into water. It handles multiple touches, so the waves can overlap. It reminds me of the scene in The Matrix where Neo touches the mirror, mixed with the red look I liked from TRON: Ares.
I am really loving how this turned out. Getting here was a lot less straightforward than I expected.
More than a list of chores
The original idea was to put my chores, timed reminders, and project choices somewhere I could see them. Give me a way to finish something without opening an app, finding the right page, and forgetting what I was doing in the first place.
Then I started adding the other things I actually want to know throughout the day.
There is a TomTom traffic widget showing drive times on my usual routes, so I can get an idea of how bad the main roads are before heading out. There is an indicator for the remaining allowance on my Codex plan. The weather widget shows temperature information, including the highs and lows, but the number I care about most is the UV index. That is what drives its color coding.
I also have network beacons deployed around the network. Think of them as little watchdogs checking in from different nodes. The board gives me a place to see the network state instead of having to go check every machine individually.
And some chores trigger other applications. Bedtime is my favorite example.
When I mark Bedtime done, it sends a webhook to another app I wrote called Scene Runner. Scene Runner runs the sequence of API calls, including the calls that control my Wyze power switches. The lights turn off one by one. The bedtime routine also pauses the TV, turns it off, and locks my workstation. In the morning I can use the fingerprint reader to get back in.
I have a lot of low-wattage, warm golden bulbs because I want less blue light in my eyes at night. Walking around switching all of those off gets old. Having one button finish the whole routine is the kind of thing that makes this project useful to me every day.
A chores board that I actually want to look at
Of course, I was not going to leave it looking like a spreadsheet.
I love the red neon, the chamfered edges, and the glass panels. The buttons have that futuristic glass-interface feeling I associate with Star Trek: The Next Generation. The animation runs behind the glass, and you get this softer, diffused version of it coming through the panels. The interface feels like part of the scene instead of a bunch of boxes pasted on top of it.
If this thing is going to sit in my house all day, I want to enjoy looking at it.
Here is what the board actually looks like running on the display. Play the clip to see the latest animation moving behind the interface.
The chores board running on the Raspberry Pi
The Matrix part
The visual inspiration came from Rezmason's open-source Matrix project. Its mirror mode already has click ripples, and that was the reference I wanted to bring to my touchscreen.
My version combines that idea with the red theme, the chores interface, and now a native Rust renderer. What I love about the interaction is that the wave actually distorts the rendered rain. The characters bend, spread out, and change magnification as it passes through them.
The renderer draws the rain into a texture, then runs that texture through another shader for the water effect. It remembers several touch points at once, so you can touch different parts of the screen and get overlapping waves.
That is probably the most interesting visual part of the whole project. I keep going back and touching it just to watch what it does.
Touch ripples bending and magnifying the Matrix rain
The Pi was working overtime
The first version used a Go service and a web interface running in Chromium. Go handled the data and the API. Chromium handled the screen, touch input, and animation.
The kiosk setup was its own little project. I needed the Pi to boot straight into the board without a desktop getting in the way. That meant console autologin, a launcher, and Cage, a Wayland compositor that runs a single application. Originally Cage launched Chromium. Now it launches the native display.
The browser version would run fine for a while, and then I would get a freeze or a black screen. Sometimes I ended up having to power-cycle the Pi. That was getting old real quick.
I wondered whether there was a memory leak somewhere. I never confirmed that as the cause. What the measurements did show was that rendering was putting a lot of pressure on the hardware.
In one early sample, Chromium's GPU process was using about 103 percent of one CPU core, its renderer about 56 percent, and its main process another 27 percent. The Go service was around 0.6 percent. The Pi was over 81 degrees Celsius and reporting throttling in the logs.
Those process percentages can add up to more than 100 because the Pi has multiple cores. Still, that was a lot of CPU time for a chores screen.
That early setup had GPU acceleration disabled. Moving the animation work onto the GPU improved the browser version, but I still wanted to try a different approach. I had this one particular screen to draw, and I kept thinking about how much of a browser I was carrying around to do it.
Why I wanted to try Rust
I had been hearing a lot of good things about Rust, and this seemed like a practical reason to give it a real try.
I still like Go. It is doing a good job in the backend here. But part of what drew me to it was its simplicity and familiar idiomatic design. I am less excited about code full of custom generic abstractions. That is one of the things that puts me off TypeScript too. I can get carried away comparing the two, but the point is that I wanted to try something different and see how it felt to build with it.
This was a specific job for Rust: replace the viewer, keep the backend, and get more out of the hardware I already had.
Initially, it was a disappointment.
I could get a handful of rain columns to render and still use far too much CPU. Other attempts hit graphics-driver errors or gave me a black screen when I deployed them to the Pi. At one point, a trial had a promising-looking CPU number but was only producing about four frames a second. That was not what I had in mind.
I also had versions that technically worked but looked worse. Jagged text, cramped spacing, missing bits of the interface. I wanted the performance improvement, but I wanted my board back too.
The version that made it come together
The version that worked uses Rust, SDL2, and OpenGL ES. SDL handles the window and input. OpenGL ES handles drawing on the Pi's GPU. Cage still provides the kiosk environment.
A lot of the improvement came from being more deliberate about caching and reusing things. The characters are rasterized into a glyph atlas once. Text and glow textures are cached. Network requests happen away from the render loop. The rain and ripple effects use a smaller internal render target instead of doing all of that work at the full display resolution.
There were Pi-specific problems to work through too. The presentation path and VSync settings made a big difference. The Cage launcher needed the right flags. And because I am using a regular screen in a vertical orientation, I had to get the rotated touch coordinates lined up with what was actually being drawn.
Even the mouse cursor took more work than expected. Hiding the application cursor did not necessarily stop the compositor from leaving its own cursor sitting in the middle of the board.
Page changes were another bottleneck. Rebuilding text, glow, and textures could block the animation thread for roughly 385 to 454 milliseconds. After adding shared caches, repeated page changes in the same-device tests took about 5 to 11 milliseconds. The first uncached page could still hitch, but going back and forth through pages stopped rebuilding the same expensive work every time.
The responsiveness is a big part of why I like the result. You touch something and it responds, while the animation keeps moving behind it.
What the measurements showed
With the intended visual effects enabled, one corrected native trial ran at a median of about 27 frames per second and used about 24 percent of one CPU core for the renderer and Cage together. A later production sample was around 25 percent of one core, with frame timing near the 30 FPS target and a temperature around 71 degrees Celsius.
These were different builds and test windows from the early Chromium measurements, so I am not going to turn them into an exact percentage speedup. But I had an animated, usable board running on the same old Pi with much less CPU pressure than the original struggling setup.
And the lightweight Go service stayed right where it was. Chore Brain still handles the chore logic. Rust handles the native viewer.
Naturally, I added more rain
Once it was working well, I looked at it and thought, okay, why not fill it up? How much more of this can we get away with?
The newer renderer has 180 lanes instead of the original 45. Each lane has three independent trails, so that is 540 rain streams. They all choose their own speeds. They overlap and overtake each other. It looks way more alive than a few evenly spaced drops moving together.
That was my latest tweak. The CPU measurements above were taken before this density increase, so they are not a benchmark of the full 540-stream version. The new rendering path gave me room to push the animation further, and I still want to measure each change on the actual hardware.
How I feel about Rust after this
I really like it.
This project gave me a reason to work through graphics, input, memory, and caching on a machine with very limited resources. I am getting much more out of that little Pi than I expected, and the responsiveness of the finished interface is something I am especially happy with.
I have now written a Rust application, and I got there by taking an existing browser-based interface and rebuilding its presentation layer natively. It took more work than serving a page to Chromium. Some of the early versions were honestly pretty rough. But I understand the rendering costs much better now, and I have much more control over what happens every frame.
I can see this experience being useful in future projects or consulting work. There are applications where a native Rust rewrite could make sense, especially on hardware where the existing interface is spending too much of the available resources. Having worked through a real example gives me something concrete to bring to that conversation.
I am also considering cleaning up the native rain renderer and releasing it separately. The click-ripple idea already exists in Rezmason's project, so I would credit that inspiration. What I would be sharing is my implementation and the work that made it useful in this touchscreen kiosk.
And I liked the water effect enough to bring a blue version to my website. Click the background between the cards and you will see what I mean.