Building this blog

I’ve always loved Benji Taylor’s personal site. My old minimal page was based on his, before he had a blog. And then when he added to it, I wanted to rebuild everything from scratch.

You probably don’t need a blog — I’m not sure anyone does.1 People don’t even finish YouTube videos anymore. But if you’re going to have one, it may as well look like this.

Where the idea came from

This site is based on two others.

The design is from Benji Taylor’s site. I don’t really know anything about design, and he knows everything. And I couldn’t afford a designer,2 but I certainly can follow a spec.

The architecture comes from Guillermo Rauch’s blog. Everything about how this is set up comes from his blog: the open source GitHub repo, the MDX files that are their own routes, and the one line in a JSON registry driving the index. No CMS, no database, no frontmatter parser.

So the site is a combo of the two: Benji’s aesthetic on Guillermo’s skeleton.

How it works

Each post lives at app/(articles)/<slug>/page.mdx and ships at the root path (this one is just /building-this-blog). There’s no CMS and no frontmatter parser, because a post is a file and the file is the route:

import { Counter } from "./counter";
 
export const metadata = { title: "Hello" };
 
This is a whole post. The button below is a React component,
imported one line up and dropped straight into the prose:
<Counter />

A single posts.json registry holds each post’s slug, title, and date; the homepage index and the shared article layout both read from it, so the index and the page header can never drift out of sync. Code is highlighted at build time with rehype-pretty-code, every element a post might reach for is already styled, and the whole thing prerenders to static HTML.

Posts that do things

Because a post is a real React route, the component it imports is really running. Here’s the one from the file above, live:

You haven’t clicked yet
A Framer Motion counter, imported at the top of this very file.

That’s kind of the main trick.3 A post about a gesture can contain the gesture. A post about an animation can play the animation. There’s no CMS to decide what I can and can’t use. So the whole thing is an escape hatch.

The fun parts

I tried to get as many of the details right from Benji’s site, because they’re what make it feel nice.

For instance, the margin notes are my actual handwriting. I used Calligraphr to make a custom font from a photo in my notebook, and loaded it in with next/font.

A spiral notebook page filled with a grid of hand-drawn letters, one glyph per cellHow I created my own font for the margin notes.

The bracket used in the margin notes is drawn with rough.js and rough-notation. It sketches a slightly wobbly line, and redraws it a bit differently each time. And it waits until the note scrolls into view to run the animation.

To get a nice highlighter effect, I combine a few randomized gradients, paddings, and tilts. And they’re all seeded by the text itself. That way, it pools at the edges naturally and never changes between renders.

And finally, there’s a very nice .

A note on the source

This blog was originally supposed to be open source. I wanted anyone to be able to fork the repo and make it theirs.

But the design is fully Benji’s, and I followed it exactly. He asked me to close the source, so I did. Thank you to Benji for letting me keep this site up.

Footnotes

  1. Except maybe Sam Altman and Paul Graham.

  2. The Consumer Price Index is up about a fifth since 2020. Designer rates are up even more.

  3. The counter above is an ordinary client component co-located in this post’s folder. You don’t need a plugin or shortcode. It animates with Framer Motion.