Rewriting My Site in Rust

zig

Introduction

Previously, more than a year now I had written a blog post where I moved my site from Reactjs to Astro. While that kept me happy for a while, I eventually got bored of it and wanted to go to an even simpler form of existence as a way of learning. Wanted to get out of the coziness that Astro gave me by setting up markdown, parsing frontmatter, codeblocks and all that. This also turned out to be a great way to learn a language that I usually have some disdain for, Rust.

Now I have worked with Rust before in a small project, but I never really got into the language. It had too many things for me to handle and felt quiet overwhelming. But for some very random reason I decided to give it another shot, a new shot to make my website blazingly fast

Now I will be quiet frank, but I did use a lot of llm sessions to get this done. Thank you grok and claude.

Basic Setup

The server is with actix as it was the only one I had heard of. I used tera for templating which is just very much like jinja2. For styling I, ofcourse, used tailwind because there is no way I am going back to writing CSS in a primal way in 2025.

What Is New // Better?

Here are a list of changes that have been made into the site

Codeblocks

Previously I was using expressive-code for codeblocks, but I was not able to add my own theme to it. Now, I am using inkjet rs to generate html for the code for me, which I modified by adding line numbers, titles, adding a copy button and line highlighting.

math.zig
01// example code block
02fn calculateCardCorners(x: f32, y: f32, theta: f32, width: f32, height: f32, padding: f32) struct { top_left: rl.Vector2, bottom_right: rl.Vector2 } {
03    const half_width = (width - 2 * padding) / 2;
04    const half_height = (height - 2 * padding) / 2;
05
06    const cos_theta = @cos(theta);
07    const sin_theta = @sin(theta);
08
09    const top_left = rl.Vector2{ .x = (x + -half_width * cos_theta + half_height * sin_theta), .y = (y + -half_width * sin_theta - half_height * cos_theta) };
10
11    const bottom_right = rl.Vector2{ .x = (x + half_width * cos_theta - half_height * sin_theta), .y = (y + half_width * sin_theta + half_height * cos_theta) };
12
13    return .{ .top_left = top_left, .bottom_right = bottom_right };
14}

Generating OG Images

Before this I was using a fixed image for the og image, but now I am using imageproc to generate a custom og image for each post and page. For example you can see it in action here

og

It also fetches my github pfp and caches it, and is refreshed after every 10 minutes using actix_rt.

pfp-refreshing
01    actix_rt::spawn(async move {
02        let fetch_avatar = || async {
03            if let Ok(response) = reqwest::get("https://github.com/namishh.png").await {
04                if response.status().is_success() {
05                    if let Ok(bytes) = response.bytes().await {
06                        if let Ok(img) = load_from_memory(&bytes) {
07                            return Some(img);
08                        }
09                    }
10                }
11            }
12            None
13        };
14
15        if let Some(img) = fetch_avatar().await {
16            let mut avatar_lock = avatar_for_closure.write().await;
17            *avatar_lock = Some(img);
18        }
19
20        // update my avatar every 10 minutes
21        let mut interval = time::interval(Duration::from_secs(600));
22        loop {
23            interval.tick().await;
24            if let Some(img) = fetch_avatar().await {
25                let mut avatar_lock = avatar_for_closure.write().await;
26                *avatar_lock = Some(img);
27            }
28        }
29    });

Here is another example:

og

Tweet Embeds

With mdx, I had the leverage of using components to embed tweets, but now I am back to using plain old markdown. So the very obvious solution was to use the imageproc library from before to generate a screenshot of the tweet and then use it as a image.

image

Each tweet has an id for example 1897239052862276089 and using vercel's react-tweet api I can get the tweet in a json format. The background gradient is unique to each tweet and is generated by hashing the id of the tweet.

Smaller Changes

  1. Dynamic file tree, So now I can have subdirectories and arrange my writings better instead of dumping them in a single folder.
  2. Added conways game of life all pages except the pages that are blogs / poems / notes.
  3. Added a minimal table of contents minimap to the right of the page.
  4. Added a search bar to the left sidebar

The Experience

img

Fun and frustrating. At the same time. I had to learn a lot of new things, like macros, mutexes, rwlocks and lazy_static. I will admit I still do not grasp rust very well, but well it is a step up from the last time. I am still very much into zig, because it is very much simpler and it is easier to translate my thoughts into code. And when I only get a very limited time to code stuff, I really want to make progress and not get stuck understanding the language.

I get why rust is objectively better, and I REALLY do want to continue learning it. I have a lot of projects in zig that are planned to be done, so maybe I can do a couple of them in rust. I was really dependent on llms to get this project done, which I really do not like doing.

But, atleast my code seems to be blazingly fast.

5 March 2025
By Namish