hugo new site example-docs
cd example-docs
git init
hugo mod init example.com/example-docs
npm init -y
npm install --save-dev @tailwindcss/cli@^4.1.0
hugo new site creates hugo.toml, content/, layouts/, static/ and other
standard Hugo directories. hugo mod init creates go.mod, which records the
theme dependency.
Hugo now reads the local checkout without downloading the module. Do not commit a
machine-specific replace line in a production site; remove it and run
hugo mod tidy before releasing.
Copy the complete commented configuration from
Configuration into the
site’s root hugo.toml—the file created by hugo new site. The output-format
blocks enable search, print views, page Markdown and llms.txt; the markup block
enables class-based syntax highlighting, heading tables of contents and math.
Open the URL printed by Hugo. Check the sidebar, search, language and appearance
menus, code colours and keyboard focus. A production build is hugo --minify.
Set params.build.tailwind = false to serve the theme’s tokens and component CSS
without Tailwind utilities. Site-authored Tailwind utility classes will then not be
generated.
Site-wide configuration
Configure Hugo, outputs, Markdown, menus, languages and theme parameters.
Configure the theme in layers. Start with Hugo’s site configuration, add theme
parameters for presentation and integrations, then use front matter for page-level
choices. Do not edit theme templates for settings that already have a parameter.
Site URL, module, languages, menus, outputs, Markdown and theme parameters
Site owner
go.mod
Hugo Module dependency and selected theme version
Site owner
package.json / lockfile
Tailwind CLI and browser-test tools
Site owner
data/cdn.yaml
Exact KaTeX, Mermaid and asciinema runtime versions
Theme maintainer
i18n/*.toml
Translated interface labels
Theme maintainer or translator
Page front matter
Title, order, description and per-page capabilities
Content author
The example at src/content/hugo.toml is executable test material. The copyable
equivalent is included below so a site creator does not need to browse the theme
repository.
Paste this into the site-root hugo.toml created by hugo new site, then replace
the example identity and repository values. Comments mark optional settings.
hugo.toml
baseURL="https://docs.example.com/"# Canonical URL, including any path prefix.title="Example documentation"# Site name used in metadata and the header.defaultContentLanguage="en"# English is served when no language is specified.defaultContentLanguageInSubdir=false# Keep the default language at the site root.enableRobotsTXT=true# Ask Hugo to generate the theme's robots.txt.[module]# Install the theme as a versioned Hugo Module.[[module.imports]]path="github.com/projectious-work/brand-theme-hugo-vanilla"# Theme module.[build.buildStats]# Let Tailwind discover classes emitted by Hugo templates.enable=true[outputFormats.SearchIndex]# Local full-text search data at /index.json.mediaType="application/json"# JSON response type.baseName="index"# Output filename without extension.isPlainText=true# Do not wrap the generated JSON in HTML.notAlternative=true# Keep this out of alternate-format metadata.[outputFormats.Print]# Printable aggregate for each section.mediaType="text/html"# Browser-renderable output.baseName="print"# Produces print.html.isHTML=true# Enable Hugo's HTML processing.notAlternative=true# Do not advertise it as an alternate page.permalinkable=true# Give the output a stable URL.[outputFormats.LLMS]# Machine-readable discovery document at /llms.txt.mediaType="text/plain"# Plain UTF-8 text.baseName="llms"# Output filename without extension.isPlainText=true# Do not apply an HTML wrapper.notAlternative=true# Keep it out of alternate-format metadata.[outputFormats.Markdown]# Clean Markdown representation of pages and sections.mediaType="text/markdown"# Standard Markdown response type.isPlainText=true# Do not apply an HTML wrapper.permalinkable=true# Give every representation a stable URL.[outputs]# Select the formats generated for each Hugo page kind.home=["HTML","RSS","SearchIndex","LLMS"]# Site-level discovery outputs.section=["HTML","RSS","Print","Markdown"]# Section aggregates and copies.page=["HTML","Markdown"]# Reader page plus clean Markdown.[markup.goldmark.renderer]# Markdown-to-HTML safety policy.unsafe=false# Reject raw HTML from content files.[markup.goldmark.extensions.passthrough]# Preserve formulas for KaTeX.enable=true[markup.goldmark.extensions.passthrough.delimiters]# Accepted LaTeX delimiters.block=[["\\[","\\]"],["$$","$$"]]# Display formulas.inline=[["\\(","\\)"]]# Formulas inside prose.[markup.highlight]# Hugo Chroma syntax highlighting.noClasses=false# Emit semantic classes so the theme controls colours.guessSyntax=true# Highlight an unlabelled fence when detection succeeds.[markup.tableOfContents]# Headings used by the right-hand navigation.startLevel=2# Begin with H2.endLevel=3# Include H3, but not deeper headings.[[menus.main]]# Add a link to the primary header navigation.name="Documentation"# Reader-facing label.pageRef="/docs"# Hugo page reference; checked during the build.weight=10# Lower weights appear first.[params]# Public theme settings; defaults are documented below.description="Documentation for the example product."# Site metadata summary.github="https://github.com/example/example-docs"# Repository header link.editURL="https://github.com/example/example-docs/edit/main/content/"# Edit base URL.version="v1.0"# Current label in the version menu.codeTheme="adaptive"# Adapt code panels to light and dark modes.sidebarSections=["docs"]# Top-level sections that receive the docs rail.sidebarOpenDepth=1# Initially expanded sidebar levels.[[params.versions]]# One published documentation version.label="v1.0"# Menu label.url="/"# Deployment-relative root for this version.note="latest"# Optional status annotation.
HTML works without custom outputs. The integrated search, printing, Markdown copy
and llms.txt features require the [outputFormats] and [outputs] blocks from
the example configuration.
Format
What the theme produces
Why enable it
SearchIndex
/index.json with pages and H2/H3 headings
Header search and command palette
Print
print.html for an entire section
Printable handbook/PDF workflow
Markdown
index.md beside each page
Copy/View Markdown actions and agent consumption
LLMS
/llms.txt with language-aware page links
A compact discovery file for LLM tools
RSS
XML feeds styled by feed.xsl
Release-note subscriptions
Add SearchIndex and LLMS to outputs.home; add Print and Markdown to
sections; add Markdown to pages. The example configuration shows the exact media
types and filenames.
The table is the complete public parameter set. Scalar parameters are assigned
below [params]; tables and arrays use the TOML shapes shown in their detailed
pages.
Define primary links under menus.main; use pageRef for local pages. Define each
language under [languages.<code>] with label and weight. See
Header and navigation and
Internationalization for complete examples.
See Editing and feedback for repository URL
mapping, the request payload, the browser’s one-vote-per-page behavior and the
security requirements for an optional receiving service.
It writes shared Markdown below content/_notebooks/ and images below
static/notebooks/. The shortcode checks a page resource first, then the shared
path. Notebook basenames must be unique.
robots.txt gives compliant web crawlers crawl instructions. Set
enableRobotsTXT = true; Hugo then asks the theme to publish /robots.txt. The
theme allows canonical content while excluding generated search indexes and print
variants that duplicate it. For example:
llms.txt is a discovery document, not a crawler rule. Enable it by defining the
LLMS output format and adding "LLMS" to outputs.home, as in the copyable
configuration. It contains page titles, descriptions and links to clean Markdown
representations, without repeated header, sidebar and footer controls:
text
# Example documentation
## Documentation
- [Getting started](https://docs.example.com/docs/getting-started/index.md): Create a site.
Neither file is access control. Private information must not be published; use
authentication at the hosting layer when content requires access restrictions.
Run ./scripts/verify.sh. It builds twice, compares artifacts, rejects project-base
URL escapes and runs desktop/mobile browser tests. A configuration change is not
complete until that command passes without warnings.
Versioned documentation
Publish separate documentation builds and connect them with the version menu.
Each documentation version is a separate Hugo build. Publish the newest release at
the stable site root and older builds below prefixes such as /v0.2/. Never add a
version-menu entry until that URL exists.
Check out the source tag for the older documentation, for example v0.2.0.
Build that checkout with a base URL ending in /v0.2/:
sh
hugo --baseURL https://docs.example.com/v0.2/ --destination public/v0.2
Publish the entire generated public/v0.2/ tree. It contains that release’s
index.html, section/page directories, CSS, JavaScript, fonts, search index and
other static assets—not Markdown source files copied by hand.
Verify https://docs.example.com/v0.2/ and representative child pages.
Return to the current source and add the selector entry shown below.
Deploy current documentation without deleting the already-published v0.2/
directory.
The menu normally appends the current page path so readers stay on the same topic.
Set params.versionProbe = false, or probe = false on one entry, when versions
have different structures. Older builds display a banner linking to the first
configured version.
The repository’s release script deploys the current release only. A consumer that
retains multiple versions needs a deployment step that copies the new root while
preserving each archived generated tree.
Page configuration (front matter)
Control navigation, cards, tables of contents and optional page capabilities.
Front matter is the TOML block between +++ delimiters at the beginning of a
Markdown file. These values affect only that page or section.
toml
+++title="API reference"# Required page title.linkTitle="API"# Optional shorter navigation label.description="HTTP API."# Summary, metadata and search excerpt.weight=20# Navigation and previous/next order.icon="code"# Icon on a generated child-page card.toc=true# Show the right-hand table of contents.cards=true# Generate cards for child pages on a section.hidden=false# Include this child in generated cards.math=false# Load KaTeX only when this page needs it.private=false# Include the page in search and sitemap.cover="/img/api.png"# Optional blog cover image.coverAlt="API response"# Required alternative text for the cover.+++
Use quotes for strings, plain integers for weights, and true or false for
booleans. The values shown in the type column are defaults, not placeholders.
Template authoring guide
Move from Markdown authoring to your first upgrade-safe Hugo shortcode and layout, step by step.
This guide starts with the knowledge needed to create ordinary Markdown pages.
You do not need to know Go, HTML templating or Tailwind beforehand. By the end,
you will have created a reusable status-panel component and will understand
when and how to change a complete page layout.
1. Understand what changes when Markdown is not enough#
A Markdown file supplies content: headings, paragraphs, lists, images and front
matter. A template supplies the HTML around that content. Hugo combines the
two when it builds the site.
For example, this Markdown:
md
+++
title = "Service status"
+++
The service is available.
becomes a complete HTML page because the theme supplies the header, sidebar,
main content area and footer. You only need to author a template when you want
reusable presentation that Markdown and the theme’s existing shortcodes do not
already provide.
Hugo has three relevant building blocks:
Building block
What it does
Who invokes it
Shortcode
Embeds a reusable component inside Markdown
Content author
Partial
Reuses HTML inside another template
Template author
Layout
Defines the structure of a complete page or section
Hugo
Start with a shortcode for a component used in content. It is the smallest and
safest first customization. Do not copy a complete theme layout merely to add a
box to one page.
All paths in this guide are relative to my-site/, the directory containing
your site’s hugo.toml. Create assets/ or layouts/ if they do not exist.
Do not edit the downloaded theme in Hugo’s module cache. Hugo checks your local
site first, so a local file can add to or override the theme without changing
the dependency.
Before changing templates, make sure the ordinary site still builds:
This is a paired shortcode because it accepts content between an opening and a
closing tag. .Page.RenderString tells Hugo to render Markdown such as emphasis
and links inside that content.
Use the shortcode in any Markdown page:
md
{{< status-panel title="Release status" >}}
The **documentation build** passed all checks.
{{< /status-panel >}}
Run the development server and open the page containing the shortcode:
sh
hugo server
At this stage the component is intentionally plain. Confirm that its heading and
bold text render before adding styling. If Hugo reports failed to extract shortcode, check the filename, paired closing tag and quotation marks.
Tailwind turns utility names in class="..." attributes into CSS. The theme
already owns the stylesheet and exposes a documented set of semantic utilities.
Your site must let Hugo record the class names found in your local templates.
In the site-root hugo.toml, add or merge this setting:
toml
[build.buildStats]enable=true
Do not create a second [build.buildStats] table if one already exists; add
enable = true to the existing table.
If you build the theme CSS in the consuming project, install the same major
Tailwind CLI version and commit package.json and the generated lockfile:
sh
npm install --save-dev @tailwindcss/cli@^4.1.0
The theme reads Hugo’s generated hugo_stats.json. This is how utility classes
used by local templates become visible to Tailwind. Run the repository’s normal
build command after adding a class; hugo server alone may not rebuild CSS in a
custom build setup.
{{< status-panel title="Release status" kind="important" >}}
The documentation build passed all checks.
{{< /status-panel >}}
Read it from top to bottom:
$kind reads an optional argument and falls back to info.
$classes maps the two supported values to complete class strings.
index selects one class string for the <aside> element.
.Get "title" writes the heading supplied by the author.
.Inner | .Page.RenderString renders the enclosed Markdown.
Use complete, literal class names in the map. Do not construct a class such as
bg-{{ .Get "colour" }}. Tailwind cannot reliably discover dynamically assembled
names, and allowing arbitrary presentation values makes the component harder to
maintain.
7. Choose theme-safe colours, spacing and typography#
Use the documented utilities—font-display, font-sans, font-mono,
bg-page, bg-surface, bg-subtle, bg-terminal, text-hi, text-lo,
text-accent, border-default and border-accent. For custom CSS, prefer
semantic variables such as --color-surface, --color-text-primary,
--color-border, --space-5 and --radius-lg.
See Tailwind and design tokens for the complete mapped
surface. Avoid depending directly on internal component selectors or raw palette
steps when a semantic token exists.
The semantic names adapt to light mode, dark mode and accessibility settings. A
hard-coded class such as bg-black may look correct in one mode but remain black
in all modes. Test semantic utilities before adding custom CSS.
8. Add an icon only when it conveys useful information#
Place an additional Tabler outline SVG at assets/icons/<name>.svg; Hugo’s merged
asset filesystem makes it available to the theme partial and shortcode:
Decorative icons omit label and become aria-hidden. Icon-only controls need an
accessible name on the control itself. See Icons and Tabler.
If the icon is purely decorative, omit label. If it communicates meaning that
is not already present in nearby text, provide a short label. Do not use an icon
as the only way to communicate status or severity.
The shortcode above adds a component inside .Content; it does not move the
sidebar, breadcrumbs or page title. A layout is appropriate only when the HTML
structure of a whole page type must change.
Before overriding one, identify the exact upstream file:
Find the layout that renders the page in the theme’s layouts/ directory.
Copy that one file into the identical path below your site’s layouts/.
Make the smallest possible change.
Keep a note of the theme version from which it was copied.
Copy the relevant theme layout into the same path in the consuming site, for
example layouts/docs/single.html. Preserve the base template contract:
Start from the exact version of the upstream file you consume. Record the source
tag in a comment or commit message so future maintainers can compare it.
The line {{ define "main" }} fills a named area supplied by the theme’s base
template. The dot passed to a partial, as in {{ partial "sidebar.html" . }},
is the current page context. .Title comes from front matter and .Content is
the rendered Markdown body.
If all you need is a component inside Markdown, stop at the shortcode. A copied
layout follows the theme less automatically and therefore needs upgrade review.
Use layouts/shortcodes/<name>.html in the site root
The shortcode text appears literally
Escaped example syntax was copied
Use real {{< ... >}} delimiters without the documentation escapes
.Inner is unavailable
Closing tag is missing
Add {{< /status-panel >}}
New classes have no effect
CSS was not rebuilt or the class is dynamic
Enable build stats, use literal classes and run the full build
Colours work only in one mode
Raw colour values were used
Choose semantic theme utilities or variables
A copied layout loses theme features
The base-template contract changed
Start from the exact layout in your installed theme version
Hugo error messages normally include the template path and line number. Start at
the first reported error; later errors can be consequences of the first one.
Run a production build and the consuming site’s tests:
sh
hugo --minify
Check light and both dark surfaces, 200% text size, keyboard focus, reduced motion,
mobile layout, print output and every supported language. Confirm that links keep
the deployment base path and that the generated CSS contains the new utilities.
For the status-panel, verify at least:
the default form and kind="important";
Markdown links and emphasis inside the panel;
light and dark colour modes;
keyboard navigation when the content contains a link;
Read release notes for template and token changes.
Diff every local override against the same upstream path in the new tag.
Remove an override when upstream now provides the required extension point.
Re-run visual and accessibility tests before committing go.mod and go.sum.
Local overrides are intentionally your responsibility; keeping them small and
tested is the best protection against upgrade drift.
The safest progression is therefore: Markdown first, an existing theme shortcode
second, a small local shortcode third, and a complete layout override only when
the page structure truly has to change.
Tokens and public API
Inspect the stable semantic CSS tokens and Tailwind namespaces generated from the theme source.
The tables below are generated from the theme’s CSS during the Hugo build. Use
semantic tokens and documented Tailwind namespaces in site-owned templates;
palette steps, component selectors and internal behavior attributes may change.
The root API.md defines the complete compatibility contract. For practical
authoring examples, see Tailwind and design tokens.
Terminal recordings
Record and embed copyable terminal sessions with asciinema.
asciinema records terminal text and timing data rather
than video. Recordings stay sharp, remain copyable, and are usually much smaller
than screen video.
Install the recorder, run asciinema rec theme-tour.cast, and put the resulting
file in a page bundle or under static/casts/.
Autoplay is off by default. The player version is pinned in data/cdn.yaml; see
Dependencies for CDN and self-hosting options.
Tailwind and design tokens
Use the theme's Tailwind integration and stable projectious.work design tokens.
Content authors normally use Markdown and shortcodes; they do not need Tailwind.
Template developers may use Tailwind utilities in site-owned layouts and
shortcodes. Hugo’s build statistics tell Tailwind which classes were actually
emitted, so [build.buildStats] enable = true is required.
Use CSS custom properties when a utility is not appropriate. The complete source
of truth is assets/css/brand-tokens.css; it defines the 12-step Midnight, Orange
and Slate scales, semantic success/warning/danger/info colours, typography,
spacing, radii, shadows, motion, breakpoints, layout measurements, terminal ANSI
slots and light/dark syntax roles. Prefer semantic tokens such as
--color-text-primary, --color-surface, --color-border, --space-5,
--radius-lg and --type-body-size over raw palette steps.
The implementation follows the projectious.work brand design system.
Set params.build.tailwind = false only when site templates contain no Tailwind
utilities; the theme’s component CSS and tokens still render.
Shortcodes
Every component the theme ships, with the Markdown that produces it.
Each section shows the rendered component, then the exact Markdown. Nothing here
needs raw HTML — the theme ships with unsafe = false.
Markdown first
Prose, lists, links, images, tables and code fences are ordinary Markdown. A fenced
block already gets a filename bar, language label and copy button; an image already
becomes a captioned, lazy-loaded figure that opens in a lightbox. Reach for a
shortcode only where a component needs structured children.
Hugo decides which form to use from the template. A shortcode whose template
reads .Inner requires a closing tag; one that has no inner content must not have
one or use an XML-style trailing slash.
A section’s overview cards are generated from its child pages’ front matter —
title, description, icon, weight — so you never hand-maintain a card list
that drifts as pages come and go. Set cards = false in a section’s front matter to
suppress the grid, or hidden = true on a child to leave it out.
Write cards by hand only for a set that is not a page list:
cols is 2, 3 (default) or 4, so an incomplete last row keeps its width.
card also takes image and alt for an image card. subtitle is rendered as
Markdown, so links and code spans work inside it.
Use the minimum version listed in the theme’s README.
Configure the module
Add the theme import and required output formats.
Run
Start the local server and review the generated pages.
A step is not limited to plain text. Its body is Markdown and may contain lists,
code, images, callouts, or nested shortcodes such as cards. Use % delimiters
for step so Hugo renders that mixed body before the step template receives it.
md
{{< steps >}}
{{% step title="Install Hugo" %}}
Use the supported version.
{{% /step %}}
{{% step title="Configure the module" %}}
Add the theme import.
{{% /step %}}
{{< /steps >}}
Numbering is CSS counters — steps renumber themselves when you reorder them.
Title, description, breadcrumb, tags, every H2 and H3 heading, and the first 2000
characters of plain text per page — generated by the SearchIndex output format.
md
{{< details title="What does the search index contain?" >}}
Title, description, breadcrumb, tags and headings.
{{< /details >}}
$ hugo server --disableFastRender
Watching for changes in content and layouts
Built in 284 ms
Web Server is available at http://localhost:1313/
md
{{< terminal title="deploy" >}}
$ hugo server --disableFastRender
Watching for changes in content and layouts
Built in 284 ms
Web Server is available at http://localhost:1313/
{{< /terminal >}}
For a plain code listing use a fenced block — the filename bar, language label and
copy button come free, and fence options work:
Markdown images become figures automatically — the title becomes the caption:
md

Prefer a page bundle: put navigation.png next to the page’s index.md and
reference it by name. Hugo then knows its dimensions, so the figure carries intrinsic
width and height and the page does not shift as images load. A sibling
navigation-dark.png is picked up and swapped by colour mode. To be explicit, or to
caption with Markdown:
Record with asciinema rec deploy.cast and keep the file in the page bundle, or
under static/casts/. cols, rows, speed, idleTimeLimit, autoplay and
loop are all supported — autoplay is off by default, per the brand rule on motion.
Run scripts/notebooks.sh first. The shortcode looks for a page resource named
analysis.md in the page bundle, then content/_notebooks/analysis.md — both exact,
so duplicate basenames are an error rather than a coin flip.
Tags
Use Hugo taxonomies for related-content and release-note metadata.
Tags are ordinary Hugo taxonomy terms. Add them to front matter:
toml
tags=["release","accessibility"]
The theme renders tags in page metadata and generates Hugo’s term and taxonomy
pages. Tags are also included in the search index. The example site deliberately
does not place a Tags link in the primary header; link to a curated term from your
content when it helps readers, or add /tags/ to your own menu.
Configure a different taxonomy through Hugo’s [taxonomies] table and provide the
corresponding templates if its presentation differs from tags.
Developer guide
Adapt the theme, swap bundled assets, run tests and contribute changes safely.
Theme consumers should override files through Hugo Modules or their project layout
instead of editing a cached module. Contributors to this repository work below
src/; release and deployment scripts intentionally remain outside that tree.
src/assets/ CSS, JavaScript and inline SVG icons
src/layouts/ Hugo templates, partials, render hooks and shortcodes
src/i18n/ interface translations
src/data/ glossary and pinned runtime metadata
src/static/ fonts, logos and licences
src/content/ executable multilingual example site
scripts/ local build, verification, release and deployment commands
tests/browser/ Playwright behavior and visual baselines
Hugo’s lookup order gives the consuming site’s layouts/ precedence over module
templates. Copy only the partial or template you need to change and preserve its
public parameters. This limits the merge work required during upgrades.
CSS variables in brand-tokens.css are the stable styling surface. Put site-level
overrides in a later stylesheet rather than changing component selectors whenever
possible.
The fallback source files are in
src/assets/icons/fallback/.
Use a name with {{< icon "search" >}} or front-matter icon = "search".
The resolver checks a site override, the mounted Tabler outline library and then
the bundled fallback. Install the pinned library and mount it in hugo.toml:
Every Tabler outline icon is then available by its
filename without .svg. A site can still override or add a glyph at
assets/icons/<name>.svg. See the root ICONS.md for resolution order, naming and
MIT attribution.
This icon is resolved from the mounted full library rather than the fallback set:
md
{{< icon name="rocket" class="ico--lg" label="Rocket from Tabler Icons" >}}
Content Markdown should not contain presentation classes. Site-owned layouts and
shortcodes may use the theme’s Tailwind namespaces and CSS tokens. See
Tailwind and design tokens for the complete mapped utility
surface, token categories and a working component example.
Font faces live in src/static/fonts/; declarations live in fonts.css. Replace
both files and licence documents together, then test layout at 200% text size.
KaTeX, Mermaid and asciinema pins live in src/data/cdn.yaml. For offline hosting,
mirror the exact file structure below static/vendor/ and enable
params.selfHostAssets. See Dependencies and SBOM.
build.sh performs two Hugo passes because Tailwind consumes Hugo’s generated
class inventory. verify.sh compares two output trees, validates base-path links
and runs Playwright at desktop and mobile sizes.
When an intentional visual change fails a snapshot, inspect the actual and diff
images first. Only then run npx playwright test --update-snapshots and review the
new files.
Create a short-lived branch from main, use Conventional Commits, add tests for
behavior changes, run verification locally and open a pull request referencing its
work item. Do not add GitHub Actions: this repository’s release policy is explicitly
local-only. See the root CONTRIBUTING.md for the complete workflow.
Search
How the generated search index, header search and command palette work.
Search is local and requires no hosted service. Hugo writes /index.json; the
browser loads the bundled FlexSearch runtime only on pages where search is enabled.
Each page contributes its title, description, breadcrumb, tags, content and H2/H3
headings, so a heading result links directly to its anchor.
Copy the SearchIndex output format and add it to outputs.home, as shown in
Configuration. Create content/search.md
with layout = "search". Set params.search = false to remove the header field,
index and search page integration.
Set private = true on a page to omit it from search and the sitemap. This is
publication control, not access control: do not put secrets in a static site.
Maintenance and upgrades
Keep the theme, runtime pins, content and published documentation current.
Treat theme upgrades as reviewed application changes. They can affect templates,
generated URLs, accessibility, search records and screenshots even when content is
unchanged.
Copy scripts/check-theme-update.sh from the theme release into the consuming
site’s scripts/ directory and make it executable. It reads the installed version
from Hugo’s module graph and compares it with upstream SemVer tags:
It is check-only by default and exits with status 10 when an update is available,
which makes it suitable for a scheduled local task. After reading the release
notes and committing or stashing site changes, apply the update explicitly:
sh
./scripts/check-theme-update.sh --update
The update mode runs hugo mod get and hugo mod tidy; it deliberately does not
rewrite configuration, overwrite local templates or publish. Review the resulting
go.mod/go.sum, compare configuration examples, then run the consuming site’s
build, link, accessibility and visual tests.
Publish a version URL before adding it to params.versions. Keep canonical current
documentation at the stable root. When removing an old version, remove its selector
entry and configure redirects where links may remain in the wild.
This repository uses local scripts rather than GitHub workflows. From a clean,
synchronized main after review:
sh
./scripts/release.sh vX.Y.Z
The script verifies deterministic output and browser baselines, packages the theme,
creates the annotated tag and GitHub release, then deploys that tagged commit to
GitHub Pages. Never deploy an unreviewed working tree.
Published tags and GitHub release archives are immutable recovery points. Report
security issues through SECURITY.md; use GitHub issues for reproducible defects
and discussions for usage questions when enabled.
Mathematics
Render inline and display mathematics with KaTeX.
KaTeX renders LaTeX notation. Set math = true in the page front matter first.
Inline mathematics such as \( t_{build} < 1s \) stays in a sentence; display
mathematics gets its own block:
npm development dependency mounted into Hugo assets
Complete outline icon catalogue
MIT
IBM Plex Mono font package
5.3.0 locked
npm development source for bundled WOFF2 cuts
Code and syntax typography
SIL OFL 1.1
FlexSearch
0.8.143
Bundled browser asset
Local full-text search
Apache-2.0
KaTeX
0.18.4
Pinned CDN or self-hosted
Mathematics rendering
MIT
Mermaid
11.16.1
Pinned CDN or self-hosted
Diagram rendering
MIT
asciinema-player
3.17.0
Pinned CDN or self-hosted
Terminal recording playback
Apache-2.0
nbconvert
7.16.6
Optional pinned Python tool
Convert Jupyter notebooks to Markdown
BSD-3-Clause
Bundled fallback icons
38 theme glyphs
Bundled assets
Offline interface fallback
MIT
Exact browser-runtime URLs are maintained in src/data/cdn.yaml; exact npm
transitives and integrity values are in package-lock.json; Python conversion pins
are in scripts/requirements.txt.
Plus Jakarta Sans, Source Sans 3 and IBM Plex Mono are bundled as WOFF2 under the
SIL Open Font License 1.1. IBM Plex Mono includes normal and italic cuts at 400,
500, 600 and 700 so syntax roles use real faces rather than browser-synthesized
weight or oblique. Licence texts ship under src/static/fonts/licenses/.
The theme’s fallback SVG set follows Tabler geometry. The exact Tabler dependency
is mounted from node_modules during the example build; consuming sites may use
the same mount or rely on the fallback set. See
Icons and Tabler. FlexSearch’s licence ships
under src/static/licenses/flexsearch/.
This page is the human-readable software bill of materials for v0.3.x. Before each
release, maintainers must compare it with package-lock.json, requirements.txt,
data/cdn.yaml, bundled asset directories and Hugo/Go declarations. Generated
CycloneDX or SPDX output may supplement this page, but must not replace checked-in
licence files or the exact lockfiles.
Run npm audit --json for the Node graph. CDN and bundled assets require separate
release-note and advisory review because npm audit cannot see them.
Jupyter notebooks
Convert and publish reproducible notebook output.
Jupyter notebooks combine prose, executable code, and
output in .ipynb JSON files. The theme converts them before Hugo builds, so the
published page contains ordinary Markdown and images rather than executable code.
This preview represents Markdown produced by the pinned nbconvert workflow. A
real notebook can include narrative cells, highlighted input and tabular output.
The pinned nbconvert environment makes conversion reproducible and keeps the
tools outside the system Python installation. Embed the converted result with
{{< notebook "theme-demo" >}}. The shortcode accepts a converted file; it
cannot execute or contain an inline notebook. See
Notebook conversion for lookup paths.
Internationalization
Configure translated content, language navigation, metadata and RTL layout.
Use Hugo’s multilingual configuration and place translated content below language
directories. The example site contains complete English, German and French trees.
The language menu links to the current page’s translation when available and falls
back to that language’s home page. Search indexes, edit links, RSS, canonical URLs,
sitemaps, hreflang and llms.txt remain language-aware.
Translate interface strings in i18n/<lang>.toml. For right-to-left languages set
languagedirection = "rtl"; structural rails, chevrons and menus mirror.
Keep filenames and translation keys stable across languages. Hugo then associates
translations without custom template logic.
Header and navigation
Configure primary links, repository actions, search and header controls.
The header contains the brand link, primary menu, search, version and language
menus, accessibility and colour controls, and an optional repository link. On wide
screens it aligns with the documentation shell; on narrow screens documentation
navigation moves into a drawer.
params.github adds the bundled GitHub icon with an accessible label. For another
service, add an icon SVG below assets/icons/ and extend partials/header.html
with an .iconbtn link using partials/icon.html. Keep the link at least 44 by 44
CSS pixels and provide an aria-label.
params.editURL is the repository URL prefix containing the site’s Markdown
files. For a page at content/docs/install.md, this configuration creates a link
to https://github.com/org/repo/edit/main/content/docs/install.md:
The Yes/No control works locally by remembering one vote per page in browser
storage. Set params.feedback = false to hide it. To collect votes centrally,
set params.feedbackEndpoint to an HTTPS endpoint. The browser sends:
The browser avoids repeated submissions from the same browser—at most one network
request per page per hour and ten per tab session. This is only interface behavior:
a caller can bypass JavaScript and send arbitrary requests. The receiving service
must therefore reject unexpected origins and paths, validate the JSON fields,
limit request rates by an appropriate server-side identity, cap body size and
avoid logging sensitive headers. CONTRACT-feedback.md contains the endpoint
contract and a reference Worker implementation.
Diagrams
Render responsive Mermaid diagrams from Markdown.
Mermaid turns text definitions into diagrams. A mermaid fence or the paired
shortcode loads the pinned runtime only on pages that need it and redraws the
diagram after a colour-mode change.
flowchart LR
M[Markdown] --> H[Hugo]
H --> S[Search index]
H --> P[HTML and print]
md
```mermaid
flowchart LR
M[Markdown] --> H[Hugo]
H --> P[HTML and print]
```
The versions and delivery options are documented under
Dependencies.
Code blocks
Configure syntax highlighting, filenames, line numbers, highlighted lines and linkable anchors.
The theme renders fenced Markdown code through Hugo’s Chroma syntax highlighter
and adds a header with the language or optional filename plus a copy button.
Put the language after the opening fence. Add the theme-specific filename
attribute inside braces when readers should know which file the example belongs
to:
Fence attributes override these values for one block. noClasses = false is
important for this theme because it lets the theme stylesheet control colours in
light and dark mode instead of inserting fixed inline colours.
Use per-block options to explain a particular example; use site-wide defaults
only for conventions that should apply to nearly every code sample. Hugo’s
syntax-highlighting reference
documents the complete Chroma configuration.
Specify the real language so Chroma can tokenize it correctly.
Use filename when the code belongs to a named file.
Highlight only the lines discussed by the surrounding prose.
Prefer linenos=table when readers will copy code.
Do not use a terminal fence for source code; use the terminal shortcode for
command sessions and their output.
Accessibility
Keyboard behavior, reader preferences and author responsibilities.
The theme provides semantic landmarks, a skip link, visible keyboard focus,
44-pixel primary targets, accessible menus and dialogs, reduced-motion support,
scalable type and non-text contrast for interactive controls.
The accessibility menu stores preferences locally:
text sizes from 112% to 200%;
high contrast;
a deliberately prominent three-pixel Strong focus ring;
underlined prose links;
reduced motion; and
expanded text spacing.
These controls supplement operating-system preferences. They do not replace the
browser’s own zoom or accessibility tools.
High contrast strengthens foreground roles and interactive boundaries. It
does not underline links. Underlined links is an independent preference so
readers can enable either treatment or combine both.
To see Strong focus ring, enable it, then press Tab rather than clicking.
Keyboard focus around the search field, menu buttons, links and form controls
changes to a three-pixel orange outline with a three-pixel gap. Browsers normally
hide :focus-visible for pointer clicks, so clicking a control is not a reliable
demonstration. The preference persists in local storage for this site origin.
Supply meaningful image alternatives, use headings in order, label icon-only
shortcodes, avoid autoplay, and do not communicate status through colour alone.
Run the keyboard and axe checks documented in TESTING.md after changing layouts.
Set params.accessibilityMenu = false only if the host product supplies equivalent
controls elsewhere.