04 May 2026
I've been slowly making my website more and more Atmospheric. Services like offprint.app, pckt.blog, leaflet.pub, and others have all began to use the standard.site lexicon to give a consistent lexicon for referencing these documents.
But each of the apps supports different content blocks and different rendering tasks. There is no shared schema for rendering of documents. The central lexicon is primarily for making posts referenceable across the Atmosphere.
I really wanted to use one of these services (or maybe several of these services) as a CMS of sorts. Where I could post on Offprint and have it be mirrored on my website.
So, I built a small package called at-astro-loader. We can just build things, I guess!
On my website, I have a projects section, which looks like this:
To make my website more Atmospheric, I wanted these projects to be referenced from my PDS. So, I defined a custom lexicon, com.chrisvanderloo.project, with a simple schema that you can find here on PDSLS. There's a great guide on atproto.com that helps with the basics of publishing your first schema.
After publishing that, I used lex to install my new lexicon. I used npx -p @atproto/lex lex install com.chrisvanderloo.project . Then, I generated a src/lexicons folder using lex build . Finally, I had a type-safe schema to reference.
In Astro, you define a content.config.ts file to create content collections. I wanted my projects to be loaded as a content collection so I could reference it at build. Using my at-astro-loader package, it's pretty easy to set up a content collection based on an installed schema. I'm having it pull straight from my PDS, and repo references my username.
import { defineCollection } from "astro:content";
import * as com from "./lexicons/com";
import { atLoader } from "at-astro-loader";
const projects = defineCollection({
loader: atLoader(com.chrisvanderloo.project, {
endpoint: "https://bsky.chrisvanderloo.com",
repo: "chrisvanderloo.com",
}),
});
export const collections = {
projects,
};The above configuration pulls my projects at build time, easy peasy.
But now, how do I do this with Offprint posts? I have articles I've written in Markdown, and those are turned into pages at build time. I'd like it to pull Offprint posts as well.
With 1.2.1 of at-astro-loader, I added support for Offprint documents. The loader is used as follows:
import { defineCollection } from "astro:content";
import { atLoader, defineStandardSiteDocumentRenderer } from "at-astro-loader";
import { site } from "at-astro-loader/lexicons";
const atprotoBlogCollection = defineCollection({
loader: atLoader(site.standard.document, {
endpoint: "https://bsky.chrisvanderloo.com",
repo: "chrisvanderloo.com",
renderer: defineStandardSiteDocumentRenderer({
shikiConfig: {
themes: {
light: "catppuccin-latte",
dark: "catppuccin-mocha",
},
},
}),
}),
});You'll note that the lexicon is pulled straight from the package, and we didn't have to install it. Also, there's a "renderer" option. In this case, I've defined a renderer to turn site.standard.document records into HTML. You could define a renderer for any kind of record if desired - I felt this one was important enough to publish with the package.
And, the post you're reading right now was published on Offprint. Looks pretty good, right?
Let me know if you give my package a shot! I hope I could help to make your Astro site a bit more Atmospheric.