All writing

Everything you can write in this theme

A reference post that exercises every markdown feature and component the site supports. Keep it, or delete it once you've stopped needing the cheat sheet.

This post exists as a working cheat sheet. Every feature below is enabled in astro.config.ts and styled in src/styles/global.css. If something here looks wrong, the styling is wrong — not your post.

Text and inline marks

Standard emphasis works: italic, bold, both, struck through, and inline code. Smart punctuation is on, so “straight quotes” curl, — becomes an en dash, --- an em dash, and … an ellipsis.

Superscript and subscript are enabled: 10^6^ and H2O.

Links get a highlighter sweep on hover — like this one.

Keyboard keys aren’t markdown, but the styling exists if you write the HTML: + K.

Headings and anchors

Every h2h4 gets a slugified id automatically, plus a # anchor that appears on hover — both at build time, via rehype-heading-ids and rehype-autolink-headings.

Fourth-level headings

These render as small uppercase labels rather than another serif size — useful for breaking up a long section without implying a new topic.

Lists

Unordered lists use a small peach diamond:

  • First item
  • Second item, with a nested list
    • Nested one
    • Nested two
  • Third item

Ordered lists use monospace numerals:

  1. Do the first thing
  2. Then the second
  3. Then the third

Task lists work (GFM):

  • Ship the site
  • Write the reference post
  • Delete the reference post

Quotes

Blockquotes get a marker-yellow rule and italic text. Good for a pull quote or someone else’s sentence you’re arguing with.

Code

Plain fenced code with a language gets syntax highlighting in both themes:

def reading_time(words: int, wpm: int = 220) -> int:
    return max(1, round(words / wpm))

Add title="…" for a filename header, showLineNumbers for a numbered gutter, and {} to highlight specific lines:

src/lib/example.ts
export function slugify(input: string): string {
  return input
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-|-$/g, '');
}

Inline notation comments give you diffs, focus, and error levels:

Notation demo
const config = {
  retries: 3, 
  retries: 5, 
  timeout: 30_000, 
  endpoint: undefined, 
  cache: 'maybe', 
};

Focus dims everything else until you hover:

setup();
const result = doTheImportantThing();
teardown();

Tables

Wide tables scroll inside their own box rather than widening the page:

FeatureEnabled byWhere to change it
GFM tables, footnotes, task listsunified({ gfm: true })astro.config.ts
Smart punctuationunified({ smartypants: true })astro.config.ts
Mathsremark-math + rehype-katexastro.config.ts
Heading ids and anchorsrehype-heading-ids + rehype-autolink-headingsastro.config.ts
Code themes and notationShiki + transformersastro.config.ts
Filename tabs, line numberstransformerCodeTitlesrc/lib/shiki-code-title.ts
Callouts, figures, asidesMDX componentssrc/components/mdx/

Components

These four are available in any .mdx post with no import needed — they’re passed in by src/pages/blog/[...slug].astro.

<Aside> puts a margin note in the right gutter on wide screens and folds it inline on narrow ones.

For images, use <Figure> with an imported asset so Astro optimises it:

import diagram from './diagram.png';

<Figure src={diagram} alt="How the pipeline fans out" caption="Fan-out, then merge." width="wide" />

alt is required by the component’s props, and heroAlt is required by the content schema whenever a post sets hero — both enforced at build time, so an unlabelled image fails the build rather than shipping.

For video and embeds, <Embed> keeps a fixed aspect box so nothing jumps:

<Embed src="https://www.youtube-nocookie.com/embed/VIDEO_ID" title="Demo walkthrough" />

Maths

Inline maths with single dollars: the pp-mean welfare interpolates between social welfare at p=1p = 1 and egalitarian welfare as pp \to -\infty.

Display maths with double dollars:

NSW(x)=(i=1nvi(xi))1/n\mathrm{NSW}(x) = \left(\prod_{i=1}^{n} v_i(x_i)\right)^{1/n}

Long expressions scroll inside their own box rather than widening the page:

O~(kT12p)for p1,O~(k1.5T12)for 1<p<0\tilde{O}\left(\sqrt{\frac{k}{T^{\frac{1}{2|p|}}}}\right) \quad \text{for } p \leq -1, \qquad \tilde{O}\left(\sqrt{\frac{k^{1.5}}{T^{\frac{1}{2}}}}\right) \quad \text{for } -1 < p < 0

Rendered by KaTeX at build time, so there’s no maths JavaScript in the page. MathML is emitted alongside the visual output, which means screen readers get real equations rather than a pile of glyphs.

Footnotes

Footnotes collect at the bottom with a return link.1 You can reference the same one twice,1 and they’re numbered automatically.2

Frontmatter reference

Everything the schema accepts, with the required fields first:

---
title: Required, max 120 chars
description: Required, max 300 chars — used in meta tags, lists, RSS, and the OG image
pubDate: 2026-08-14
# Optional from here down:
updatedDate: 2026-08-20
tags: ['one', 'two']
draft: false        # true = visible in dev, excluded from the production build
featured: false     # true = surfaces on the homepage
series: Building Poiro
toc: true           # false = no outline rail
hero: ./cover.jpg   # relative to the post file; requires heroAlt
heroAlt: Description of the cover image
---

Validation runs at build time via Zod, so a typo in a field name or a missing heroAlt fails the build with a pointer to the file.

Footnotes

  1. This is a footnote. GFM footnote syntax, handled natively by Sätteri. 2

  2. A second one, to show the ordering.