Appearance
inkpaper: Introduction and Quick Start
inkpaper is a VitePress blog theme. The visual idea in one line: white paper, black ink, vermillion accents.
The motivation is straightforward — a personal journal doesn't need flashy design. It needs to be quiet, readable, and textured. Most blog themes are either over-engineered or visually noisy. What I wanted was opening a page that feels like unrolling a sheet of rice paper.
Installation
bash
npm install @inkpaper/vitepressThe theme peer-depends on VitePress >= 1.0.0 and Vue >= 3.3.0, which your project likely already has.
Quick Start
The fastest way is the scaffolding tool:
bash
npx @inkpaper/create-for-vitepress my-blog
cd my-blog
npm install
npm run devThis generates a complete project structure under my-blog: VitePress config, theme entry, home/archive/tags pages, content loader, and a sample post. Run it and you'll see the theme in action.
Write articles under docs/posts/. Frontmatter needs at least title, date, and tags:
md
---
title: My First Post
date: 2026-05-11
tags:
- essay
---
Post content goes here.date determines sort order. tags are used for the tags page filter and related-article recommendations. Subdirectories for categorization are supported.
If you already have a VitePress project, read on for manual setup.
Manual Configuration
Four steps, each solving a different problem.
1. Content Loader
VitePress itself doesn't know how to extract a list of posts from your Markdown files — it only renders individual pages. The content loader tells it how to scan the posts directory, extract title, date, and tags from frontmatter, and produce structured post data for theme components to consume.
docs/posts.data.ts:
ts
import { createPostsLoader } from '@inkpaper/vitepress/loader'
export default createPostsLoader()Scans posts/**/*.md by default. For a custom path, pass a glob: createPostsLoader('articles/**/*.md').
2. Theme Entry
The VitePress theme entry wires theme components to data. inkpaper's components (home, archive, tags, etc.) need post data to function — this step injects the data generated by the loader above.
docs/.vitepress/theme/index.ts:
ts
import theme, { themeEnhance } from '@inkpaper/vitepress'
import type { Theme } from 'vitepress'
import { data as posts } from '../../posts.data'
export default {
...theme,
enhanceApp(ctx) {
theme.enhanceApp?.(ctx)
themeEnhance({ posts })(ctx)
}
} satisfies ThemeIf you have a related-articles JSON file, pass it along: themeEnhance({ posts, related: relatedData }). Skipping themeEnhance entirely is fine too — the theme injects empty data by default, so pages render without errors, just without article lists.
3. VitePress Config
This is where you define site metadata and sidebar navigation. title and description are displayed as the home page title and tagline. generateSidebar builds sidebar navigation automatically from the posts directory.
docs/.vitepress/config.mts:
ts
import { defineConfig } from 'vitepress'
import path from 'node:path'
// @ts-ignore — .mjs export
import { generateSidebar } from '@inkpaper/vitepress/config'
const postsDir = path.resolve(import.meta.dirname, '..', 'posts')
export default defineConfig({
title: 'My Blog',
description: 'A personal journal',
themeConfig: {
sidebar: generateSidebar(postsDir),
}
})By default, article pages get a directory tree, archive pages get a date tree, and the tags page gets no sidebar. All configurable — covered in the feature walkthrough.
4. Page Files
VitePress uses file-based routing — no .md file means no URL. The theme provides home, archive, and tags components, but can't register routes automatically. You need to create the corresponding Markdown files to mount them.
docs/index.md:
md
---
layout: doc
title: Home
---
<script setup>
import { HomeLayout } from '@inkpaper/vitepress'
</script>
<HomeLayout />docs/archive/index.md:
md
---
title: Archive
sidebar: true
---
<script setup>
import { ArchivePage } from '@inkpaper/vitepress'
</script>
<ArchivePage />docs/tags.md:
md
---
title: Tags
sidebar: true
---
<script setup>
import { TagsPage } from '@inkpaper/vitepress'
</script>
<TagsPage />That's it. Run npm run dev, open the browser, and you should see your site with the inkpaper theme applied.
Source Code
GitHub: Moonshile/inkpaper-theme