Skip to content
The Marginalia.

Design showcase · build notes

The margin is the product.

The Marginalia is a literary magazine whose one idea — readers writing back — is also its one interface idea. These are the build notes: what carries the site, why Astro, and the exact mechanics of the live margin notes.

The idea

Most magazine sites treat the margin as leftover space. This one treats it as the editorial voice: every essay is set in a text column with a wide outer margin, and the margin holds real annotations — the author second-guessing herself, the editor checking a fact. As you read, the note beside the paragraph you’re on wakes up; the rest sit faded, waiting their turn. The homepage repeats the trick everywhere it can: the masthead has its own margin note, the table of contents previews each essay’s opening line in the margin, even the subscribe form keeps its fine print out there.

The stack — why Astro content collections

Five essays, one layout, zero client-side framework: this is exactly the shape Astro is for. The essays live as markdown in src/content/essays/ with a zod schema (src/content.config.ts) that types every field the design depends on — title, dek, section, reading time, the opening line the TOC previews, and the notes themselves:

notes: z.record(
  z.object({
    kind: z.enum(['author', 'editor']),
    text: z.string(),
  })
)

In the essay body, [[noteId]] anchors a note to the sentence it annotates. A ~50-line renderer (src/lib/essay.ts) splits the body into paragraphs and expands each anchor into a reference mark — the classical compositor’s sequence * † ‡ § ‖ ¶ — while collecting that paragraph’s notes. Adding an essay is adding a markdown file; the TOC, pager, folios and margin all follow from the collection.

Signature technique — scroll-synced margin notes

The layout does the hard part. Each paragraph renders as its own two-column grid row, so a note is born beside its paragraph — no JavaScript positioning, no absolute offsets to keep in sync:

.pg {
  display: grid;
  grid-template-columns: minmax(0, var(--measure)) var(--marg);
  column-gap: clamp(2.5rem, 5vw, 4.5rem);
}
.pg > p     { grid-column: 1; }
.pg > .mnote { grid-column: 2; grid-row: 1; }

Notes rest at opacity: .38, nudged 10px into the margin. One IntersectionObserver watches only the paragraphs that carry notes, using a root margin that describes the reading band of the viewport — roughly where your eyes are:

const io = new IntersectionObserver((entries) => {
  for (const e of entries)
    e.target.classList.toggle('live', e.isIntersecting);
}, { rootMargin: '-18% 0px -46% 0px' });

flow.querySelectorAll('.pg.has-note')
    .forEach((pg) => io.observe(pg));
.js .can-sync .pg.live .mnote {
  opacity: 1;
  transform: none;
  border-color: var(--oxblood);   /* the hairline turns oxblood */
}

Below 880px the margin folds in. The same markup becomes a footnote system: notes hide behind their reference marks (display:none, gated on the .js class so nothing is ever lost without scripts), and the mark becomes a tap target that toggles the note open beneath its paragraph with correct aria-expanded/aria-controls wiring. With prefers-reduced-motion, all of it stands down: notes are simply always visible, fully opaque, static — the print experience.

Details that matter

Ship it

Astro builds straight into docs/ so GitHub Pages can serve from the main branch — no Actions, no second branch:

// astro.config.mjs
export default defineConfig({
  site: 'https://bswxyz.github.io',
  base: '/the-marginalia',
  outDir: './docs',
});
npm run build
gh repo create bswxyz/the-marginalia --public --source . --push
gh api --method POST /repos/bswxyz/the-marginalia/pages \
  -f 'source[branch]=main' -f 'source[path]=/docs'

A .nojekyll in public/ rides along into the build. Internal links go through import.meta.env.BASE_URL, which is the difference between a site that works at /the-marginalia/ and one that only worked on localhost.


The Marginalia is a design-showcase concept — the essays, authors and letters are fictional. The README maps what’s demo and what a production magazine would still need.

← Back to the issue