Publishing something
The exact frontmatter for each of the four content types is in CLAUDE.md,
next to the rest of the reference material. This page is the workflow around
it — what a session of publishing actually looks like.
The loop
npm run dev:blog # or dev:fav, dev:io, dev:home
Write the file, watch it in the browser, then:
That is the whole thing. There is no staging server and no publish button.
Working with an LLM
This repository is built to be driven by conversation rather than by a CMS, so
the useful instruction is usually the content itself:
Add a blog post about the harbour walk. Three photos, they're in
~/Desktop/harbour/. Keep it short.
What makes that work — and what to preserve if you restructure anything:
- Every content type has one obvious location and a schema that fails
loudly with a useful message when a field is missing.
- Components need no imports in
.mdx. <Figure>, <PhotoGrid>,
<Video>, <Bleed> and <Aside> are always in scope, so there is no
relative path to get wrong.
CLAUDE.md is the manual, and it is read automatically at the start of a
session.
Drafts and scheduling
draft: true # never leaves your laptop
pubDate: 2026-09-01 # publishes itself when that date arrives
Both are visible in npm run dev and excluded from npm run build. A
future-dated entry goes live on the next deploy after its date passes — there
is no cron job, so if you want something to appear on a particular morning you
still have to deploy that morning.
Choosing .md or .mdx
Default to .md. Reach for .mdx when you need a component or a piece of
interactivity.
The difference is not cosmetic: .md is rendered to HTML when the site builds,
so the entire post travels in the RSS and JSON feeds. .mdx compiles to a
component, which has no HTML until something renders it, so those entries reach
subscribers as a summary and a link.
For io this does not apply — its feed renders the link list explicitly, so an
issue always arrives complete.
Writing the summary
It is required everywhere and it does more work than it looks like:
- the
<meta name="description">
- the blurb in listings and on the home page
- the text a feed reader shows
- the entire content of the feed item when the body cannot travel
One or two sentences that would make sense to someone who has not read the
post. Not a teaser.
Photographs
Full workflow in docs/05-media.md. The short version: export at full
resolution with location data stripped, drop them in
sites/blog/src/content/photos/<year>/images/, list them in the frontmatter
with alt text. Camera settings are read automatically and rendered under each
frame.
The build refuses to run if any photograph still carries GPS coordinates.
Designing an individual piece
docs/02-design-system.md. Briefly: theme in frontmatter overrides any
design token for that entry alone, and canvas: bare gives you an empty page
with the fonts loaded and nothing else.