A practical guide to using this template — install Quarto, build the site, add chapters, and switch between full and selective publishing.
- A Quarto website project (3-level collapsible sidebar) configured for long-form books.
- Two render profiles:
full(entire book) andselection(subset for previews / drafts). - A custom Lua filter (
opencode-prompt.lua) that turns special code blocks (opencode,agent,skill,bash) into styled cards with a copy button. - Companion CSS (
styles.css) with light/dark variants for the semantic blocks. - Two style guides under
docs/style-guides/covering Quarto callouts and content modules.
The template is structure-only — you bring the chapters.
Quarto runs on macOS, Linux, and Windows.
- Download from https://quarto.org/docs/get-started/, or
- Install via package manager:
# macOS
brew install --cask quarto
# Linux (deb/rpm available on the download page)
# Windows: use the installer from quarto.orgVerify:
quarto --versionIf you intend to render PDFs, also install a TeX distribution. The simplest way is:
quarto install tinytexFor Chinese / CJK PDF output you will additionally need LuaLaTeX and CJK fonts (e.g. Noto Serif CJK SC, Noto Sans CJK SC). HTML output has no such requirement.
your-book/
├── _quarto.yml # main config (shared settings, format, filters)
├── _quarto-full.yml # profile: render the whole book
├── _quarto-selection.yml # profile: render a subset
├── opencode-prompt.lua # Lua filter for semantic code blocks
├── styles.css # custom CSS (callouts, code block styling, dark mode)
├── index.md # landing page
├── images/ # shared images, including book-logo.png
├── chapters/
│ └── chapter-template/ # one folder per chapter
│ ├── index.md # chapter cover (title, learning goals, intro)
│ ├── section-1.md # one file per section
│ ├── section-2.md
│ └── summary.md # chapter summary
├── docs/
│ ├── quarto-quickstart.md # this file
│ ├── semantic-code-blocks.md # how the Lua filter works
│ └── style-guides/
│ ├── callout-style-guide.md
│ └── content-module-guide.md
└── scripts/
└── new-chapter.sh # scaffold a new chapter (see §7)_quarto.yml holds settings that apply to every build (theme, fonts, filters, crossref labels, language). The two profile files supply the bits that change between builds: which files are rendered (project.render) and what shows in the sidebar (website.sidebar.contents).
The two commands you will use most:
# Live preview with auto-reload — best for writing
quarto preview
# One-shot build into _book/
quarto renderPreview opens a local server and rebuilds whenever you save a .md. Render produces static HTML in the output directory.
Other useful invocations:
# Render only HTML
quarto render --to html
# Build with a specific profile (see §5)
quarto render --profile selection
# Render a single file (fast iteration)
quarto render chapters/chapter-template/section-1.md
# Preview without opening a browser, on a fixed port
quarto preview --no-browser --port 5455Output goes to _book/ by default (configured via project.output-dir in _quarto.yml). To serve the built site locally without quarto preview:
npx serve _book -p 8080
# or
python -m http.server 8080 -d _bookThis template uses Quarto's profile system to keep one source tree producing different outputs.
| Profile | File | Use when |
|---|---|---|
full |
_quarto-full.yml |
Default. Render the entire book. |
selection |
_quarto-selection.yml |
Preview a subset, share a sample, draft mode. |
_quarto.yml declares the default profile:
profile:
default: fullSo quarto render and quarto preview use full unless you override:
quarto render --profile selection
quarto preview --profile selectionEach profile must define two things:
project.render— the list (or globs) of source files to compile.website.sidebar.contents— the sidebar tree for those files.
Everything else (theme, CSS, filters, crossref labels) stays in _quarto.yml and is shared.
Open _quarto-selection.yml and replace the chapter-template entries with the files you actually want in the preview. Anything not listed in project.render is skipped, and anything not listed in sidebar.contents is hidden from navigation.
Tip: keep the lists in the two files in sync conceptually — if a chapter exists in project.render but not in sidebar.contents, it builds but is unreachable from the sidebar.
Every .md starts with YAML frontmatter that supplies the title:
---
title: "Chapter 1: Getting Started"
---For sections:
---
title: "1.1 First Section"
---Do not add a leading # Heading after the frontmatter — Quarto already renders the title. Adding one creates a duplicate H1.
Inside a chapter folder, the typical files are:
index.md— chapter cover: title, learning objectives, short intro.section-1.md,section-2.md, … — one per section.summary.md— wrap-up.
You can also add experiment.md, exercises.md, cases.md, etc. — there is nothing magical about the names; what matters is that they appear in the active profile.
Put chapter-specific images under chapters/chapter-N/images/ and reference them with relative paths:
{#fig-diagram}
See @fig-diagram.Shared assets (book logo, cover) live in the top-level images/ folder.
The bundled helper script makes scaffolding a chapter quick:
./scripts/new-chapter.sh 2 "Chapter Title"The first argument is just the chapter number — the script prefixes it with chapter- to produce the directory name (e.g. chapters/chapter-2/).
It will:
- Create
chapters/chapter-2/by copying the entirechapters/chapter-template/directory, which includes a starterindex.md,section-1.md,section-2.md, andsummary.md(plus an emptyimages/folder). Delete or rename any files you don't need. - Print the YAML snippets you need to paste into
_quarto-full.yml(and optionally_quarto-selection.yml).
Manual workflow — equivalent if you do not use the script:
-
mkdir -p chapters/chapter-2/images -
Create
index.md,section-1.md,section-2.md,summary.mdwith frontmatter as shown above. -
In
_quarto-full.yml, append toproject.render:- chapters/chapter-2/index.md - chapters/chapter-2/section-*.md - chapters/chapter-2/summary.md
-
In the same file, extend
website.sidebar.contents:- section: chapters/chapter-2/index.md contents: - chapters/chapter-2/section-1.md - chapters/chapter-2/section-2.md - chapters/chapter-2/summary.md
-
Run
quarto previewto verify it shows up in the sidebar.
The template ships with two reference documents under docs/style-guides/:
callout-style-guide.md— when to use which callout (note,tip,warning,important,caution), syntax, and conversion rules from older blockquote styles.content-module-guide.md— patterns for concept definitions, file paths, structural diagrams (directory trees, tables, configs), step-by-step instructions, and worked examples.
These were written for a Chinese-language book and use Chinese examples, but the patterns translate directly. Use them as a checklist when drafting or reviewing chapters.
For the custom code blocks (opencode, agent, skill, bash), see semantic-code-blocks.md.
Manual numbering in titles (第 1 章, 1.1 …, Chapter 1, 1.2 …) collides with Quarto's auto-numbering. The template ships with number-sections: false. If you prefer Quarto-driven numbers, flip it on and remove the manual prefixes from your title: fields.
_quarto.yml localizes crossref prefixes:
crossref:
fig-prefix: "图"
tbl-prefix: "表"
eq-prefix: "公式"
sec-prefix: "节"Change these to English (Figure, Table, Equation, Section) for English-language books.
Inside .md source files, use the plain ```mermaid fence — Quarto will render it to an SVG diagram on the client side:
```mermaid
flowchart LR
A --> B --> C
```If you need a numbered/captioned figure for cross-referencing, wrap the fence in a labeled div:
::: {#fig-flow}
```mermaid
flowchart LR
A --> B --> C
```
Diagram caption goes here.
:::
See @fig-flow.Note: the executable
```{mermaid}form (with curly braces) only works inside.qmdsource files, because Quarto requires.qmdfor files containing executable code. This template uses plain.mdfiles.
The template ships with a starter PDF profile, _quarto-pdf.yml, alongside the HTML profiles. To build a PDF:
quarto render --profile pdfOutput is written under _book/ (a .pdf file alongside the HTML — Quarto picks an output name based on the project title).
Required tools:
- A TeX distribution. The simplest is TinyTeX, which Quarto can install for you:
quarto install tinytex
- LuaLaTeX (provided by TinyTeX and full TeX Live distributions).
If you already have TinyTeX from a prior year, run
quarto install tinytex --update(or~/Library/TinyTeX/bin/.../tlmgr update --self --all) to refresh — cross-yeartlmgroperations fail with a "remote repository has newer release" error.
CJK font caveat. Because _quarto.yml defaults to lang: zh, the PDF profile uses documentclass: ctexbook and references CJKmainfont: "PingFang SC". You will need a Chinese-capable font installed on the build machine:
- macOS:
PingFang SC,Songti SC, andHeiti SCare pre-installed. - Linux / CI: install
Noto Serif CJK SCandNoto Sans CJK SC(e.g.apt install fonts-noto-cjk) and setCJKmainfont: "Noto Serif CJK SC".
For an English-only book, switch documentclass to scrreport and remove the CJK font keys (the profile contains a commented block showing how).
Lua filter caveat. The shipped opencode-prompt.lua filter emits RawBlock html only — those custom block types (opencode, agent, skill, bash) will appear as plain code in PDF output until the filter grows a LaTeX/PDF code path. For pure HTML books this does not matter; if you need styled blocks in PDF too, plan to extend the filter or strip those filters when rendering PDF.
Practical advice. Treat HTML as the primary deliverable and PDF as secondary: nail down chapter structure, sidebar, callouts, and code-block styling against quarto preview, and only stress-test PDF once content has stabilized. PDF iteration is much slower (LaTeX typesetting, font discovery, page-break tuning).
If you prefer everything in one file, you can fold a format.pdf: block into _quarto.yml instead of using a separate profile. The dedicated _quarto-pdf.yml is recommended because it keeps PDF-only options (engine, font names, document class) out of the HTML build path.
- Preview not refreshing. Stop and restart
quarto preview, or use--no-browser --port <new-port>to dodge a stuck cache. - Missing pages in sidebar. Check that the file is listed in both
project.renderandwebsite.sidebar.contentsof the active profile. - Duplicate titles in output. Remove leading
# Headinglines from.mdfiles; the YAMLtitle:already provides the heading. opencode/agent/skill/bashblocks render as plain code. The Lua filter is missing from_quarto.yml. Confirm thefilters: - opencode-prompt.luablock is present and the.luafile is at the project root.
- Skim
docs/style-guides/callout-style-guide.mdanddocs/style-guides/content-module-guide.mdbefore drafting your first chapter. - Read
docs/semantic-code-blocks.mdto understand the four custom block types. - Browse
chapters/chapter-template/for a working layout you can copy. - Quarto's full reference: https://quarto.org/docs/guide/.