Colophon
This is my personal website, version 7, built on top of atproto. I wrote about why I took this approach, in My Atmospheric personal website.
Data
The AT Protocol is an open protocol for building decentralised social websites and applications. A key concept is the Personal Data Server (PDS) where applications store your data in a server you control1. Your data is freely accessible and owned by you.
My PDS is this website’s back-end. The following services store data in my PDS using their own lexicons: predefined record types designed for interoperability. Here are the records they store visualised by PDSls:
- Bluesky - notes, replies and simple photos.
- Grain - photo galleries.
- BookHive - books I’m reading and those I’ve finished.
- Popfeed - films I’ve watched and reviewed.
- Rocksky - songs and albums I’ve scrobbled.
- Sifa - my professional work profile.
- Standard Site - subscriptions to publications.
Check-ins use a custom lexicon for my Foursquare Swarm data. A small service running on Val Town polls for new check-ins via the Foursquare API and creates matching records in my PDS.
Articles are (currently) the exception. I wanted control over layout, performance and URLs, and I write all articles and weeknotes in Markdown. Copies are published as Standard Site records on my PDS for reading services to use. My 2000-2001 Travelblog is also here, written in Markdown with one file per month.
My atproto handle and identity is barryfrost.com which maps to my DID: did:plc:j5ksi3y4tdtbp7vpsxsfyask.
Build
Astro 7 is the website generator, outputting static HTML without dynamic pages or a database. Data is fetched from my PDS at build time using content loaders working in parallel, along with Markdown files for articles and weeknotes.
Cloudflare Workers builds and hosts. For code and article changes, an on-demand rebuild is triggered via any push to the GitHub repo. But for updates in my PDS, a small Worker polls the API every minute via cron, and fires a deploy hook if there has been a change in its watched collections. There is also a belt-and-braces hourly rebuild.
Disclosure: Claude writes the Worker and Astro code that I review and deploy.
Images aren’t served from my PDS or hot-linked from an external origin2. Any full-size photos, film posters, Bluesky images, and so on, are resized at build time using sharp, stored in a Cloudflare R2 bucket in webp format using a content-addressable key filename. Images are processed just once, and served via Cloudflare’s CDN.
Pagefind is used for static full-text search. At build time, pages built as HTML by Astro are then processed and indexed, ready for the client-side search page.
Even with the hourly rebuilds, image transformations and storage, everything fits comfortably within Cloudflare’s free tier.
Front-end
Performance is a feature, and I’ve tried to optimise download speed. Pages are static and delivered by Cloudflare’s global CDN. There is very little JavaScript: Leaflet.js for maps, Pagefind on the search page, and Umami3 for analytics. Fonts are self-hosted4 and preloaded. Images are pre-sized and optimised in efficient webp format, and pages preconnect to the images host.
Content on pages, articles, and weeknotes is authored in Markdown, and MDX to use components like icons. Templates include Microformats 2 markup - h-feed, h-card and h-entry - with relevant classes for Post-Type Discovery. There are rel=me links to my profiles on GitHub, Mastodon and Bluesky.
I’ve split content into two channels that you can follow: one for just my writing (articles and weeknotes) at /feed.*, or a firehose/everything feed at /stream.*. Feeds are available as MF2, RSS, and JSON Feed.
Articles and weeknotes are published as Standard Site documents in separate publications with <link> tags for discovery.
Cool URIs don’t change. Content from my previous website is 301-redirected to its new home. Any legacy URLs for content I no longer maintain, like bookmarks, are redirected to a static copy at archive.barryfrost.com.
With accessibility in mind, there is screen-reader friendly markup throughout, a skip link, machine-readable <time> values with every relative date, high-contrast AAA styles, and a dark mode that needs no JavaScript.
No cookies are used. For security, headers define HSTS, nosniff, a Referrer-Policy, and a Permissions-Policy denying camera, microphone, geolocation and payment.
Design
This website is deliberately lo-fi. It uses spacing, not lines, to separate sections. Colour is used sparingly.
Tailwind 4 is used for styles.
I discovered Work Sans and love its slightly-wide, Grotesque look. It’s used for all non-code text, with body-sized headings that use the semi-bold weight for emphasis. ui-monospace is the default for code.
The Asterism (⁂) symbol is used as a dinkus for section breaks instead of horizontal rules. It’s a traditional typographic ornament, which I think complements Work Sans nicely. It’s also a fun nod towards federation and the social web.
Icons are SVGs sourced from atmologos for the atproto services, and Heroicons for generic symbols.
An inverted dark scheme is used when specified by the operating system via prefers-color-scheme.
Next
There are currently no comments, no Webmentions and no likes. These are future improvements I’m considering.
Source
The website source code is available on GitHub under the MIT licence.
All content and original images are licensed under Creative Commons Attribution 4.0 International.
Footnotes
-
I’m using Bluesky’s shared PDS today, but my DID and data are fully portable. ↩
-
With two small exceptions: Blogroll favicons fall back to google.com/s2/favicons when a subscription has no avatar, and the check-ins map pulls tile images from CARTO. ↩
-
Umami is a cookieless, privacy-respecting analytics service, but it’s worth pointing out that anonymous usage data is sent to its cloud service. ↩
-
Astro downloads Work Sans from Google Fonts at build time, so there’s no runtime request to Google. This is as much for privacy as for performance. ↩