Sites and Templates
The site block and the built-in templates webpage / book / presentation / aiskill._
A site block configures one output site — its template, title, theme, and navigation. A document can declare several sites; each page joins one or more via its sites field. A site picks its template with default_template, and a page may override per-page with template.
webpage template
A Hugo-style site header, a sticky top navbar built from menu, and a reading column. Menu items use page = <name> for in-site links (validated against pages in this site) or href = "…" for external or cross-site URLs. Nested items become dropdown groups.
site marketing {
default_template = :webpage
title = "My project"
root = true
theme = :nord
menu {
item "Home" { page = index }
item "Docs" { href = "docs/" }
item "More" {
item "About" { page = about }
item "Contact" { page = contact }
}
item "Source" { href = "https://github.com/example/proj" }
}
}
book template
An mdBook-style fixed left sidebar with nested chapters and current-chapter highlight; reading column on the right. Chapters nest to any depth. A chapter with no page = is a grouping heading. A chapter pointing at an unknown page is a build error.
site docs {
default_template = :book
title = "Project Docs"
theme = :nord
theme_toggle = true
toc {
chapter "Intro" { page = index }
chapter "Guide" {
chapter "Setup" { page = setup }
chapter "First run" { page = first_run }
}
}
}
Search
Set search = true on a site to add client-side full-text search. The build writes a per-page text index to _wdoc/search-index.json and the book and webpage templates render a search box — in the sidebar and the nav respectively.
Served, not opened
The widget fetches the index over HTTP, so search works when the site is hosted (or under wcl wdoc serve), not when a page is opened directly from disk.
presentation template
A reveal.js-style slide deck: the whole site renders into a single index.html, navigated with the keyboard. The deck block lays out the 2-D grid — each section is a column, its slides are rows — and each slide names a page that belongs to this site.
site talk {
default_template = :presentation
title = "My talk"
theme = :catppuccin
deck {
section "Intro" {
slide title
slide agenda
}
section "Main" {
slide topic
}
}
}
Each slide must sit on its own line. Two in-slide blocks are deck-specific: fragment { … } is a step-reveal group (hidden until the presenter advances with Space), and notes { … } holds speaker notes (hidden in the deck, shown in the overlay toggled with s).
page topic {
h2 "Key points"
fragment { p "Revealed on the first Space" }
fragment { p "…then this one" }
notes { p "Reminder: mention the benchmark numbers." }
}
ai_skill template
A fourth built-in: default_template = :ai_skill makes the site a Claude / agent skill folder, built by wcl wdoc skill (not wcl wdoc build). See the skills concept for the skill { } block and file blocks.
Custom templates
The built-ins are not special: a template is just a function from a TemplateCtx to a list of HTML fundamentals. Declare a template <name> { render = fn(c: TemplateCtx) -> list<HtmlFundamental> … } and select it with a site's default_template (e.g. :blog) or a page's template field. The stdlib exposes its chrome as composable parts (wdoc_part_*) plus one wdoc_*_layout per built-in, all resolved by bare name once you import <wdoc.wcl>.
Parts resolve by bare name
Template parts are plain functions reached by name through import <wdoc.wcl> — don't define a let of your own named wdoc_part_* or wdoc_*_layout, or it will shadow the stdlib one.
Related
- Pages
- Styling