Series seed

By hand, in VS Code

Six collections, eighteen components, and nothing in the editor that knew about any of it.

5 min read

Every post on this site started the same way for years. New file, .mdx, and then a pause at the top of an empty document while I tried to remember what goes in the frontmatter this time.

This time, because it depends where the file is.

A note wants title, description, pubDate, heroImage, tags, featured, maturity, publish. A live note wants Month and OneLiner, with capitals, alone among every collection on the site. A work post wants fourteen keys including company and duration and the two store URLs. A series part wants seriesOrder and an excerpt. Six collections, six shapes, and the only thing that told me I’d got one wrong was the build.

You can see the copying in the files, actually. Four of the live notes open with a blank line before the ---. August, September, October, November. Four consecutive months, which looks a lot like pasting the block from the previous month and catching a stray newline on the way in, four times, without ever noticing. Nothing renders frontmatter, and nothing complains about a leading blank line.

The components were worse

The site has eighteen components you can use inside a post. Callout, SideNote, Quote, ImagesLeft, SideBySide, VideoBreakout, WorkSection, References, and so on.

They’re registered centrally, which is a nice piece of design and the reason MDX files here import nothing. You just write <SideNote> and it works. The cost of that is there’s nothing to autocomplete against. VS Code sees an angle bracket and a capital letter, shrugs, and lets me type whatever I want. The name is either exactly right or it silently isn’t a component any more.

Same with props. ImagesLeft takes imageSrc. Image takes src. Get that one backwards and nothing shouts at you; you find it later, on a page where an image should be. [? Did that actually happen to you, or am I projecting? It’s the kind of specific that would earn its place if it’s true.]

The CODM essay is 3,800 words and carries about sixty component tags. Twenty nine <Image>, ten <Link>, eight <SideNote>, eight <ImagesLeft>. Every one of them typed by hand, with the props remembered, in a file that looked like prose interrupted by JSX and never like the thing a reader would see.

And to see the thing a reader would see, I’d save, switch to the browser, wait for the reload, scroll back to where I was, and then go back to VS Code to fix the spacing.

The part I’d stopped noticing

None of this was hard. That’s what took me so long to do anything about it.

Writing the post was never the slow part. The slow part was the frame around the writing: remembering the shape, typing the ceremony, checking the render, coming back. Each one costs a few seconds and none of them are worth complaining about, and together they’re the reason a half-formed idea often stayed half-formed. If getting a thought onto the site costs a context switch, some thoughts don’t make it.

Markdown was supposed to be the thing that got out of the way. It does, right up until the post needs an image with a caption, or a side note, or two images side by side, and then I’m writing markup in a text editor that has no idea what any of it means.

[GAP: was there a particular post or evening where this tipped over, or did it just accumulate? A specific one would make this section land much harder than “it accumulated” does, but I’d rather have nothing here than something I made up.]

Why not just install one

The obvious move is to use something that exists. Ghost, Tina, Keystatic, Obsidian with a publish step.

[GAP: I don’t know which of these you actually looked at, or what put you off. This is your call to make and I’m not going to guess at it. What follows is only the constraint I can see in the repo.]

What I can say from the outside is what the content already is. Forty files in git, validated by Zod schemas that the site itself uses, rendered by components that live in the same repo, with a build that fails if the frontmatter is wrong. The content isn’t in a database waiting to be fetched. It’s the source.

Most hosted editors want to own that. They want the content in their store, with their schema, and the site pulls from an API. Which is a perfectly good trade if you’re a team, and a strange one for a personal site where the whole point is that the posts are files I can grep.

So the thing I wanted wasn’t a CMS in front of the site. It was an editor that sat directly on top of the files, knew the same schemas the site knows, and rendered the same components the site renders. Nothing in between.

Which sounds reasonable right up until you write it down, because the first question it raises is the one that turned out to matter most.

If the editor opens a post and saves it, do I get the same file back?

That’s where the 19th of September starts.

seed maturity Seed — this note will change as the strip does