Colophon
Framework & Language
The site is built with Astro, a modern static-site generator. Content is authored in TypeScript and Astro components. The output is a fully static site — no client-side JavaScript framework, no runtime server. You can find the full source code and CI/CD setup at https://github.com/shaftoe/personal-website.
Styling
Theme forked from zaggonaut. All styling uses Tailwind CSS v4, processed through the @tailwindcss/vite plugin. Typography is handled by @tailwindcss/typography. Icons provided by @lucide/astro. Dark mode respects the user’s system preference and can be toggled manually, the choice is persisted in localStorage.
Fonts
- IBM Plex Mono — the primary body font, loaded from Fontsource CDN.
- Press Start 2P — the display/heading font (pixel art style), loaded from Fontsource CDN.
- Literata Variable — a variable serif font for reading, also from Fontsource.
Content
Blog posts live as Markdown files with YAML frontmatter, managed through Astro’s content collections. The changelog is parsed directly from the project’s CHANGELOG.md file at build time using marked.
Tooling
- Bun — JavaScript runtime and package manager.
- Biome — fast linter and formatter, replacing ESLint + Prettier.
- Astro · Check — static type analysis for
.astrofiles. - Vitest — unit tests and integration tests.
- Nu HTML Validator (vnu-jar) — validates all generated HTML pages against the W3C spec.
- Netlify — hosting and continuous deployment.
Infrastructure
Versioning and deploys are fully automated. Every push to master triggers a release workflow powered by semantic-release, which analyzes conventional commit messages, bumps package.json version, updates CHANGELOG.md, and publishes a GitHub Release.
When a new version tag is created, a deploy workflow triggers a Netlify build that runs bun run build and publishes the resulting dist/ directory to their CDN. The same workflow also runs on a schedule every four hours to keep the homepage’s Mastodon posts and blog content up to date without manual intervention.
Analytics
Web analytics are powered by Umami, a simple, fast, privacy-focused, open-source alternative to Google Analytics. It gives total control over the data and does not violate the privacy of visitors. The tracking script is built from source and served self-hosted — see the Privacy Policy for details. It is loaded conditionally and skipped on the expenses page when the user is authenticated.
HTML Validation
Generated HTML is validated against the W3C Markup Validator (vnu-jar) to ensure standards compliance. Every page produced by the build is checked automatically as part of the test suite. Known framework-level exceptions (Astro module script placement after </html>, astro-island inline styles, heading hierarchy in blog snippet cards) are suppressed with documented justifications.
Social Images
Open Graph and Twitter Card images are generated at build time as PNGs using Sharp (which leverages librsvg for SVG rendering). Each image is a 1200×630 terminal-style banner using the Press Start 2P pixel font, with a dark background, traffic-light window chrome, and green accent colors matching the site’s theme. Three variants are generated: a default banner for the homepage and general pages, a blog-specific banner, and a 404 page banner. The images are referenced via og:image and twitter:image meta tags in the <head> of every page.
IndieWeb Compatibility
This site tries to follows IndieWeb principles and be a good citizen of the independent web:
- Microformats2 — Blog posts and article snippets are marked up with microformats2 classes (
h-entry,h-card,p-name,e-content,p-summary,dt-published,u-url,p-uid,p-category,p-author). This makes the content machine-readable and consumable by IndieWeb tools, readers, and search engines. rel="me"links — Profile links to Mastodon and GitHub includerel="me", enabling IndieAuth identity verification and cross-site identity proof.- RSS feed — A full blog feed at /rss.xml ensures content is syndication-friendly and subscribable from any RSS reader.
- Blogroll — The /blogroll page follows the tradition of linking to other personal websites and independent blogs.
- Postroll — The /postroll page curates link recommendations, a pattern aligned with the IndieWeb ethos of sharing discovery.
- TIL — The /til page collects short “Today I Learned” entries from Mastodon posts tagged
#til, acting as a microblog-style knowledge log — a form of personal wiki native to the IndieWeb. - Canonical URLs — Every page includes a
<link rel="canonical">tag for unambiguous permalink identity. - Semantic HTML — Proper use of
<article>,<nav>,<main>,<time>(withdatetimeattributes), and other semantic elements ensures structural clarity for parsers and assistive technology. - Open Graph & Twitter Cards — Rich
og:*andtwitter:*meta tags provide accurate social previews when content is shared.
Other Bits
- Sitemap generated by @astrojs/sitemap. A
301redirect from /sitemap points to the sitemap index XML. - /expenses — a private, password-protected expense tracker backed by a serverless API. Built as a Svelte 5 SPA island embedded in the Astro page via
client:load.