Build a documentation site with the static stack
Start state: nothing. End state: a full documentation site — sidebar, live search, per-page table of contents, prev/next pager, breadcrumbs, copy buttons on every code block — as plain HTML files you can host anywhere for free. The static stack has no build tool and no framework: content lives in JSON, a generator turns it into pages.
1. Scaffold the static shape
pnpm new fielddocs --title "Field Docs" --stack static --type website-blog-docs \
--design editorial --accent teal --mode light
Expected: apps/fielddocs scaffolded from _template/static-site — index.html, css/, js/main.js, and content/blog.json + content/docs.json. There is no package.json in the app and no install step: --stack static means plain HTML+JS+BEM, website types only, deploy = files as-is.
--features does not apply here — features belong to --type webapp. The static stack's feature set is the site itself: website, blog, and docs pages driven by the two JSON files.
2. Understand the content schema
Open apps/fielddocs/content/docs.json. It is an array of sections; each section has a title and pages; each page is a slug, a title, and a body of typed blocks:
[
{
"title": "Getting started",
"pages": [
{
"slug": "introduction",
"title": "Introduction",
"body": [
{ "kind": "p", "text": "Welcome to the Field Docs documentation." },
{ "kind": "h2", "text": "Structure" },
{ "kind": "list", "items": ["Sections group related pages", "Each page is a slug + title + blocks", "The sidebar renders itself"] }
]
}
]
}
]
Block kinds: p, h2, h3, list, code, and quote. The sidebar, search index, and pager are all derived from this one file — you never edit navigation by hand.
3. Write your docs
Replace the sample sections with your own. A useful starting shape: one "Getting started" section (introduction, install, quickstart), one "Guides" section (a page per task), one "Reference" section (a page per command or API). Keep slugs lowercase-with-dashes — each slug becomes <slug>.html.
4. Regenerate the pages
pnpm regen-blog fielddocs # regenerates blog AND docs from the JSON files
Expected: the generator emits one HTML file per docs page plus search-index.json. Each page gets, for free:
- Live search — the docs search box lazy-fetches search-index.json on focus and filters as you type, with keyboard navigation over the hits
- "On this page" — a table-of-contents box generated from the page's h2 blocks (appears on any page with 2+ h2s)
- Prev/next pager cards across the whole docs order, plus breadcrumbs
- A copy button on every code block
Edit content/docs.json, not the generated HTML — the next regen overwrites generated output. The JSON is the source of truth and versions cleanly with your site.
5. Preview locally
open apps/fielddocs/index.html # or: npx serve apps/fielddocs
Static files need no dev server, though search's fetch of search-index.json is disabled on file:// — use a local server to try search.
6. Deploy
pnpm deploy fielddocs --to github-pages
Expected: deploy.mjs detects "kind: static files" (index.html present, no package.json), skips the build entirely, and pushes the directory as-is. Any of the 6 providers works; GitHub Pages and Surge are the classic free homes for docs. The choice is remembered in apps/fielddocs/.deploy.json.
What you built
- A documentation site with search, TOC, pager, breadcrumbs, and copy buttons — zero JavaScript written by you
- A content pipeline: edit content/docs.json → pnpm regen-blog fielddocs → deploy
- A site with no dependencies to update, ever — plain HTML, CSS, and one small JS file