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:
npm run build && npm run preview npx lighthouse http://localhost:4321 --view03
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
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
body: { provider: 'google', family: 'Newsreader', weights: [400, 500], styles: ['normal', 'italic'], display: 'optional' } // Adobe: { provider: 'adobe', family: 'Freight Text' } + ADOBE_FONTS_KIT_ID in .envdisplay: '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
{ "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
--- 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
<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
npm run freshRemoves 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
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:
git fetch upstream && git merge upstream/main && npm install