Hello, new site
I had a single-page HTML portfolio for a couple of years. It did its job — told people what I make, gave them a way to reach me. But it had no room for the thing I actually wanted to do: write.
Why now
Most of what I figure out — patterns that worked, things that didn’t, small techniques worth keeping — ends up in scratch files and DMs. I want a place to put it down, both for me and for anyone who might find it useful later.
What this is
- Work — selected projects, shipped and otherwise.
- Notes — short pieces on whatever I’m currently building.
- Contact — boring but necessary.
That’s it. No newsletter. No “subscribe” modals. No tracking.
How it’s built
The site is Astro, generating static files. Each note
is a Markdown file in src/content/notes/. Push to git, the deploy fires,
the new post is live a minute later. No CMS, no database, no auth, no
backend.
The interesting parts:
- Search runs entirely in the browser via Pagefind. At build time it indexes every page; at runtime it loads a tiny WASM blob and returns instant local results. No server, no API key, no quota. Tags in any note are clickable and pre-fill the search.
- Code blocks go through Shiki with dual
light/dark themes baked into the HTML. Adding
{2,4-6}after the language tag highlights those lines; adiffblock colors removed and added lines red and green. Line numbers come from a CSS counter. No client JS. - OG images are rendered per post at build time using Satori — JSX in, PNG out. Every post gets a unique preview card when shared.
- Markdown extensions — GitHub-style callouts (
> [!NOTE]), footnotes, anchor links on headings, external-link favicons and arrows, a reading-progress bar, a sticky table of contents on long posts. A few small plugins, none of them aware of the others. - Type and color — Geist and Geist Mono,
one sans-and-mono pair for everything. The mono carries dates, code, and
small labels; the sans does the rest. Warm stone neutrals with a single
lime accent. Both themes defined as CSS variables; toggling flips a
data-themeattribute on the root — no JS theme library, no flash on load. - Hover-preview on any internal note link — pulls a one-paragraph excerpt from a JSON map built alongside the index. Wikipedia-style, but with the site’s typography.
- Schema-checked content via Zod — a typo in a frontmatter field fails the build before it can break a page.
The palette:
:root {
--bg: hsl(60 9% 98%);
--fg: hsl(24 10% 10%);
--accent: hsl(82 78% 34%);
}
:root[data-theme='dark'] {
--bg: hsl(20 14% 4%);
--fg: hsl(60 9% 98%);
--accent: hsl(79 76% 56%);
}
The publishing flow:
src/content/notes/this-post.md # write
git push # → live
That’s the whole loop. Source is on GitHub.
More soon.