Back when I first created this blog, I had little to basically no web designing experience or knowledge. I was just writing raw HTML and CSS by hand, the best way I could manage to figure out. I knew that Web Frameworks were a thing, but I just had the impression those would be far too clunky and overkill for a simple blog. I thought that web frameworks were solely to blame for one of my biggest gripes when navigating websites, that is buttons and content moving around as the page loads, and in many aspects that is true. I did not want to manage many different files of many different types in many different languages in many different organization patterns in many different configuration settings to make text appear in a minimally designed layout. I also embarrassingly did not know that the ideas I had for this site is called a “static content site”. My entire Computer Science frustrations are defined by not having the vocabulary built up to express what I want and know to be good, although it certainly exists in some generally accepted industry vocabulary.

I have since learned after traversing the vertically inclined learning curve of having a real-world software engineering job for a software company that the diversity of web application architecture is vast and infinitely expanding. There are pros, cons, and tradeoffs for all, and all should be carefully considered for the use case. Carefully thinking about your goals of the application, or site, is the first and most important step to making what you want performant, maintainable, and enjoyable for yourself as a developer and most importantly the user.

That being said, I set out to do an overhauling redesign of this blog with the following goals:

Redesign Goals

  1. All changes must motivate writing.
  2. Minimize requests and transferred bytes.
  3. Keep the design minimal, yet modern.

Those three goals were motivated by my own enjoyment of various blogs and my experience writing this one. The first spark to really make me start brainstorming my desires was Xe Iaso’s migration to a static site generator. Specifically, they chose Lume. Moreover, it was my first realization that Markdown could be used to generate web content. That immediately made me swoon and passionate to blog again. I always had tons of ideas and aspirations for many articles, but the idea of handwriting my HTML and CSS made me want to puke and any use of a modern heavy handed web framework made me sick moreso.

For a long time, I was attempting to use Lume as well. I love Lume and think it is pretty great. I was mostly trying to do this a couple of years ago though when Lume was still fairly early days and the modern LLMs just didn’t know much about it. I admittedly didn’t have the patience to manually architect all that I wanted with it and started looking for an alternative that modern LLMs can crutch me with ease. Astro seemed like the best alternative, and that is what I have stuck with.

How do I motivate writing?

The idea that I could write my articles in Markdown was plenty motivation enough to keep me writing fairly frequently going forward. I needed to keep it that way. However, since I want this blog to be heavily travel-photography and terse mathy/CS article forward, I always had ideas for elegant reusable “chunks”, for say images or proofs, that I could reuse across all articles. Again, lacking vocabulary, I came to learn these are accepted as “components”.

Components are exciting, but again, since motivating writing was priority number one, it was imperative my writing was almost entirely Markdown. I needed to figure out how to extend Markdown to support components, but I needed to make the number of components I support to myself minimal to keep me sane. I found that MDX does exactly that. Here are the few in-article components I am supporting for myself:

ArticleDate and ArticleChangelog

Gwern’s blog is a massive inspiration for this blog. It is beyond beautiful. Like it is done there, I wanted to support viewing older versions of articles (through ArticleDate) if I have revisions and show a changelog (through ArticleChangelog) of what has changed.

Figure

The Figure component is the canonical way to embed images in an article. It handles placement (left / right / center), custom width as a percentage, captions, eager vs. lazy loading, responsive AVIF/WebP variants, and a lightbox for image galleries.

figure.mdx astro
<Figure
  src="/assets/images/selfie.jpg"
  alt="Trey Manuszak"
  placement="center"
  width={60}
  loading="eager"
  fetchpriority="high"
/>

Video

The Video component embeds a local video with an optimized H.264 MP4 source, a poster frame, and a caption.

video.mdx astro
<Video
  src="/assets/videos/karaoke.mp4"
  caption="Karaoke from the basement of the Yanggakdo International Hotel."
/>
Karaoke from the basement of the Yanggakdo International Hotel.

ManimAnimation

Inspired by the 3blue1brown YouTube channel, I knew I wanted educational animations to the technical topics I talk about. The ManimAnimation component renders a Manim-generated video as a timed slideshow. Each slide is bound to a timestamp with its own caption (KaTeX-aware), and the viewer can step through slides inline or open a full lightbox.

manim.mdx astro
<ManimAnimation
  src="/assets/videos/yao-minimax-bipartite-query.mp4"
  title="Bipartiteness query lower-bound animation"
  caption="Breakpoint animation of the hard distribution for the bipartiteness query lower bound."
  slides={[
    { time: 0, caption: "The vertex set is split into two halves $L$ and $R$." },
    { time: 3.5, caption: "Edges are queried between the halves." },
    { time: 7.0, caption: "The hard distribution hides a single contradiction." },
  ]}
/>
1 / 3
The vertex set is split into two halves and .

Code

The Code component is the canonical way to display code blocks in my blog posts. It handles syntax highlighting at build time via Shiki (GitHub Dark Dimmed), margin line numbers, a language badge, and a copy button. No client-side highlighting runtime is shipped (goal #2!).

code.mdx astro
<Code
  lang="rust"
  filename="registry.rs"
  code={rustRegistryCode}
/>
registry.rs rust
use std::collections::HashMap;
use std::sync::Arc;

pub struct Registry<T: Clone + Default> {
    inner: Arc<HashMap<&'static str, T>>,
    capacity: usize,
}

impl<T: Clone + Default> Registry<T> {
    pub fn new(capacity: usize) -> Self {
        Self {
            inner: Arc::new(HashMap::with_capacity(capacity)),
            capacity,
        }
    }

    pub fn get(&self, key: &'static str) -> Option<&T> {
        self.inner.get(key)
    }
}

References

The References component renders a styled references section at the end of an article.

references.mdx astro
<References>

Bonanno, G. (2018). _Game Theory: Volume 1: Basic Concepts_. North Charleston, SC: Createspace Independent Publishing Platform.

Motwani, R., & Raghavan, P. (1995). _Randomized Algorithms_. Cambridge, England: Cambridge University Press.

</References>

Statement and Focus

The Statement component renders a named mathematical statement (Theorem, Corollary, Lemma, Proposition, or Problem) with a label tab. The remarkStatementReferences remark plugin auto-numbers statements by kind and resolves <Ref to="..." /> cross-references at build time. The Focus component is a lightweight variant for highlighting important asides.

statement.mdx astro
<Statement kind="Theorem" id="von-neumann-minimax" title="von Neumann's Minimax Theorem">

For any two-person zero-sum game specified by a payoff matrix $P$,

$$
\max_{\boldsymbol{p}} \min_{\boldsymbol{q}} \boldsymbol{p}^T P \boldsymbol{q} =
\min_{\boldsymbol{q}} \max_{\boldsymbol{p}} \boldsymbol{p}^T P \boldsymbol{q}.
$$

</Statement>

Theorem 1 von Neumann's Minimax Theorem

For any two-person zero-sum game specified by a payoff matrix PP,

max⁡pmin⁡qpTPq=min⁡qmax⁡ppTPq.\max_{\boldsymbol{p}} \min_{\boldsymbol{q}} \boldsymbol{p}^T P \boldsymbol{q} = \min_{\boldsymbol{q}} \max_{\boldsymbol{p}} \boldsymbol{p}^T P \boldsymbol{q}.
focus.mdx astro
<Focus title="Current Interests">
  Rust, FPGA development, Zero-knowledge Proofs, Category Theory applied to programming.
</Focus>

Current Interests

Rust, FPGA development, Zero-knowledge Proofs, Category Theory applied to programming.

Cross-references are resolved automatically:

ref.mdx astro
Following <Ref to="von-neumann-minimax" /> and <Ref to="loomis-minimax" /> above, we get the lower-bound form of Yao's minimax principle.

Proof

The Proof component renders a proof block with a floating “Proof” label tab and an animated Q.E.D. cube.

proof.mdx astro
<Proof>

To use Yao's minimax principle, we want to construct an input distribution over $n$-vertex graphs such that any deterministic algorithm asks, on average, $\Omega(n^2)$ questions to determine if the input graph is bipartite.

</Proof>

Proof.

To use Yao’s minimax principle, we want to construct an input distribution over nn-vertex graphs such that any deterministic algorithm asks, on average, Ω(n2)\Omega(n^2) questions to determine if the input graph is bipartite.

How do I deliver the blog content efficiently?

Given that this is just intended to be a blog, there is no reason to not serve as many assets as possible through a CDN and avoid having any kind of backend server to maintain. Astro builds three packages for my blog,

  1. A local build I can view in-the-works posts served on my Tailscale network,
  2. A Web2 build which can host all assets served from treymanuszak.com,
  3. A Web3 build which hosts HTML/CSS/font/script files over IPFS, accessed through decentralized.treymanuszak.com. Cloudflare serves cached content or, on a cache miss, fetches it through the eth.limo gateway.

As explained in my first post, the viewer can browse my blog and its content on either Web2 or Web3. If the user is browsing on Web3, the media assets are served from Web2. That choice is made to keep IPFS pinning services costs to a bare minimum, while trying to still benefit from some decentralization and security of the overall textual content that Web3 hopes to ensure.

In either case, I wanted it to be made sure that I was also serving content minimally and efficiently for the best experience and bandwidth savings. To do that every image as a responsive set of AVIF and WebP files, with a JPEG or PNG fallback. The browser can then choose the smallest useful image for the reader’s screen instead of downloading the original photograph. Videos are reduced to a broadly supported H.264/AAC MP4 with a small poster image, and normal article videos do not begin loading until the reader asks for them. Every generated media filename contains a hash of its source and encoding settings. Those URLs can be cached for a very long time without becoming stale.

Three paths from build to reader.

Design motivations

The original Reutersvärd triangle logo and color scheme (#E8E288, #7DCE82, and #FF8360) remain central to the redesign. The typography also carries over: JetBrains Mono for inline text and Source Serif 4 for prose. The former comes from it being my favorite terminal and editor font to use, while the latter was inspired by how much I enjoy reading Gwern Branwen’s blog, as mentioned earlier.

Before even making the first version of the site, I wanted to draw inspiration from Tao Tajima’s homepage, which uses short animated videos in a fluid slideshow. Recreating something like that was well beyond my abilities at the time, given my limited computer science experience. But, I still wanted something fun to put in the background of the homepage.

Over the years, following shader developers such as XorDev introduced me to shaders and WebGL libraries. The shader code golf these developers produced was astonishing. That eventually led me to Shadertoy, a showcasing of handcrafted shaders. I was particularly fond of an aurora borealis shader by “nimitz”. After removing the reflection and stars, narrowing the view, and fixing the camera, it became the foundation of the current homepage background.

Almost…

The remaining influence came from the dithering used by Nous Research illustrator John Galt. “The Art of Dithering and Retro Shading for the Web” also offers a superb overview of what those techniques can achieve. Combining dithering with the aurora shader and snapping its illumination to the site’s paper-white and muted-black palette produced the final homepage background effect.

The boxed logo-and-name hero takes inspiration from the graphic design work of Kyle Anthony Miller, whose style I would describe as an “industrial micrographic flight console.”