Mara Voss

Everything KoPlain ships with.

A tour of the theme — and, behind each feature, exactly how to configure it. This page lives in your copy of the theme, so the docs are always where your code is.

01

One column, done properly

KoPlain is the prose-site archetype: a single readable column, large body type, and links as the interface. No grids to fight, no sections to fill — your words carry the design.

Setup & config

The column lives in src/layouts/PageLayout.astro(42rem). The intro and contact paragraphs are markdown you edit insrc/content/pages/.

02

Fast — measured, not promised

Every KoPlain release is audited with Lighthouse before it ships. These are the real numbers from v1.0.0; they ship with the theme so you can re-run them yourself.

Mobile

99

Performance

95

Accessibility

100

Best practices

100

SEO

Desktop

100

Performance

95

Accessibility

100

Best practices

100

SEO

mobile: FCP 1.2 s · LCP 1.8 s · TBT 0 ms · CLS 0 — Lighthouse 13.4.0, median of 3 runs, 2026-06-10

Setup & config

Why it's fast: one text serif, subset and self-hosted at build time, loading withfont-display: optional so it never blocks paint, and there's one small JS file. Verify it yourself:

terminal
npm run build && npm run preview npx lighthouse http://localhost:4321 --view

03

Every setting in one file

Colors, fonts, name, meta tags, social links and navigation live in theme.config.ts — typed, validated, and impossible to typo silently.

Setup & config
theme.config.ts
logo: { type: 'text', value: 'Your Name' }, colors: { accent1: '#2222dd', /* link color */ }, nav: { links: [{ label: 'Notes', href: '/notes' }] }

Invalid values fail the build with a readable error pointing at the exact field.

Light, dark and system color schemes are built in: the grey ramp inverts automatically in dark mode, colors.dark overrides any accent, and the toggle in the nav cycles auto → light → dark (persisted, no flash on load). Set dark: false to ship light-only.

04

Google Fonts, Adobe Fonts, local files, or system stacks

KoPlain is set entirely in Newsreader — a text serif made for reading, with true italics — self-hosted at build time and never blocking the first paint. Swap in any family with one config change.

Setup & config
theme.config.ts
body: { provider: 'google', family: 'Newsreader', weights: [400, 500], styles: ['normal', 'italic'], display: 'optional' } // Adobe: { provider: 'adobe', family: 'Freight Text' } + ADOBE_FONTS_KIT_ID in .env

display: 'optional' means a slow first visit shows the metric-matched fallback instead of waiting; repeat visits get the serif from cache. Switch to 'swap' if you prefer the serif always.

05

Projects as a list you actually maintain

Eight lines of JSON per project — title, line of description, optional link, year. No images to art-direct, no case studies to write. The format you'll keep updated.

Setup & config
src/content/projects.json
{ "id": "ledger", "title": "Ledger", "description": "A personal finance app that treats budgeting as journaling.", "url": "https://example.com", "year": 2026, "order": 1 }

06

Notes — writing without a blog's ceremony

Markdown files become /notes/your-slug. Dated, listed newest-first on the home page and the notes index. Set draft: true to keep one private.

Setup & config
src/content/notes/on-defaults.md
--- title: On defaults description: Why the default state of a tool is its real interface. date: 2026-04-18 draft: false --- Your text.

07

The underline that notices you

KoPlain's one moment of motion: the line under your name thickens as the pointer approaches. Pointer-only, reduced-motion-safe, and it never delays the page.

Setup & config

Lives in src/scripts/wordmark-underline.ts. The attraction radius is the function's argument; remove the call insrc/scripts/motion.ts to disable it entirely.

08

SEO without a plugin

Canonical URLs, Open Graph and Twitter cards, sitemap, robots.txt — fed by your config and per-page frontmatter.

Setup & config
any page
<PageLayout title="Page title" description="…" ogImage="/og-custom.png">

09

Demo content — keep it or strip it

The theme arrives as Mara Voss's site so every page has something to show. One command makes it yours.

Setup & config
terminal
npm run fresh

Removes demo projects, notes and placeholder copy; structure and styles stay.

10

Updates that respect your changes

Theme updates arrive as git pulls. Your config, content, styles and overrides live in safe zones updates never touch.

Setup & config
update-safe
theme.config.ts src/styles/custom.css src/content/ src/components/overrides/ public/

Don't edit src/_core/ — copy a component intosrc/components/overrides/ and change its import instead. Updating:

terminal
git fetch upstream && git merge upstream/main && npm install