Getting started
Neither the paper nor the engine is published to npm — both are zero-build and export raw TS/CSS source. A site vendors the two repos as git submodules, imports three stylesheets, and wires one function into astro.config. Everything on this site is built that way.
§1.1A pair of submodules
Vendor the two repos and point file: dependencies at them:
git submodule add https://github.com/ventusff/astro-inkstone.git packages/astro-inkstone
git submodule add https://github.com/ventusff/astro-inkbrush.git packages/astro-inkbrush{
"dependencies": {
"@astrojs/mdx": "^7.0.5",
"astro": "^7.1.6",
"astro-inkstone": "file:packages/astro-inkstone",
"astro-inkbrush": "file:packages/astro-inkbrush"
}
}§1.2Styles
In your global stylesheet: tokens first, then the content layer, then — for a site with browse pages — the shelf, then only your own chrome:
@import 'astro-inkstone/styles/tokens.css';
@import 'astro-inkstone/styles/base.css';
@import 'astro-inkstone/styles/browse.css'; /* landing / facet pages, on body.wb-root */
/* identity: override the tier-one pigments; both semantic contexts and the component layer follow */
:root {
--p-shi: #b03a48; /* your reading accent */
--p-zhu: #3b4a7a; /* your shelf accent and mark */
--p-shi-n: #e0919b; /* the night twins: the dark theme reads --p-*-n */
--p-zhu-n: #9fb0e4;
}The shelf's serif is --font-display (Source Serif 4 + Noto Serif SC); self-host it as this demo does and the masthead looks exactly like this one:
@import '@fontsource-variable/source-serif-4/opsz.css';
@import '@fontsource-variable/source-serif-4/opsz-italic.css';
@import '@fontsource-variable/inter/index.css';
@import '@fontsource/noto-serif-sc/400.css';
@import '@fontsource/noto-serif-sc/600.css';Math sites add one line for KaTeX's stylesheet in the layout (without it, formula layout falls apart):
import 'katex/dist/katex.min.css';§2.1The Markdown pipeline, one line
A minimal configuration in this site's shape — chapter numbering, math, callouts, diagrams, and [[wikilinks]] resolved against the note collection (the full version, with every hook this site wires, is astro.config.mjs in the repository):
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import { normalizeBase } from 'astro-inkstone';
import { siteMarkdown } from 'astro-inkstone/markdown-preset';
import { buildWikilinkResolver, cachedScan } from 'astro-inkbrush/wikilinks';
const WIKI_MODE = process.env.WIKI === '1';
const inkbrush = WIKI_MODE ? (await import('astro-inkbrush')).inkbrush : null;
const BASE = normalizeBase(process.env.DEMO_BASE || '/'); // '/docs' and '/docs/' both work
export default defineConfig({
site: 'https://example.com',
base: BASE || '/',
integrations: [mdx(), ...(inkbrush ? [inkbrush()] : [])],
markdown: siteMarkdown({
numbering: 'chapters', // part/chapter numbers + ToC via remarkPluginFrontmatter
math: true, // remark-math + KaTeX
codeFrame: true, // code frames: title bar / copy / collapse / annotations
mermaid: true, // mermaid fences render client-side
callouts: true, // Obsidian-style > [!note] syntax
wikiBlocks: WIKI_MODE, // editing mode: block ↔ source-line mapping, always last
guard: { autoNumberedHeadings: true }, // content guard: reject hand-typed numbers
wikilinks: {
resolve: buildWikilinkResolver({
notes: cachedScan('src/content/notes'),
urlFor: (id) => `${BASE}/${id}/`,
locales: [{ code: 'en', prefix: '' }, { code: 'zh', prefix: 'zh/' }],
}),
},
}),
});siteMarkdown sits on the engine's dialect (GFM, CJK-friendly emphasis, the content guard); the preset itself only assembles and orders the site-side plugins — the pipeline order is the contract, so your site never worries about who runs before whom. Every switch is demonstrated on the kitchen sink page, and the reasoning behind the package split lives in boundaries. Chinese-labelled callouts? Pass calloutLabels — the defaults are English.
§2.2Run it
The scripts, as this demo's package.json defines them (build runs the engine's check-dist as postbuild; wiki is WIKI=1 astro dev):
npm install
npm run dev # the garden
npm run build # static build + the engine's check-dist (postbuild)
npm run wiki # WIKI=1 astro dev — CMS editing modeThe static build carries zero engine bytes: outside WIKI mode the engine's integration code is never even imported (dynamic import), and no editing metadata is emitted. What remains CMS-shaped in the output is the site's own inert docking markup — the empty data-inkbrush-slot spans in the nav bar and their CSS — which does nothing until the CMS docks into it.