Open. Indexed. Navigable. Knowledge.
A local-first Hugo theme for engineering documentation.
OINK gives engineering teams a complete documentation system without making consumer sites maintain a frontend toolchain. The theme bundles its assets and feature runtimes locally; Hugo Extended turns Markdown into a deployable static site with no Node.js, npm, PostCSS, or CDN dependency.
- Local-first delivery. One Hugo build produces an auditable, portable site whose core assets work without third-party networks.
- Documentation at scale. Responsive docs and blog shells, navigation, full-text search, table of contents, dark mode, RSS, SEO, and print views are built in.
- Multilingual by design. Language-aware routing, translated-page fallback, RTL support, and alternate-language metadata support serious international documentation.
- Engineering-native content. Diagrams, formulae, API references, terminal recordings, charts, file trees, galleries, cards, and tabs load only when a page needs them.
- Proven foundation. OINK evolves Docsy's mature content model with a focused interface and site-owned extension points.
Requires Git, Go, and Hugo Extended 0.160.1 or newer.
hugo mod init github.com/example/docs
hugo mod get github.com/pgsty/oink@latestAdd OINK to hugo.yaml. Hugo leaves output selection to the consuming site, so
enable the formats and interactive features you want explicitly:
module:
imports:
- path: github.com/pgsty/oink
outputs:
home: [HTML, RSS, markdown, LLMS]
page: [HTML, markdown]
section: [HTML, RSS, print, markdown]
# Hugo does not merge a theme module's Goldmark configuration into the site.
# These three settings are required by OINK's native component forms.
markup:
goldmark:
renderer:
unsafe: true # `%` container shortcodes emit HTML that Goldmark must keep
parser:
wrapStandAloneImageWithinParagraph: false # block images carry attributes
attribute:
block: true # {.steps}, {.fields}, captions, numbered Book targets
params:
# Book reading measure: slim | normal | wide (default: normal).
reading_width: normal
copyright:
authors: '[Example Documentation](https://example.org/)'
from_year: 2026
# footer_center_info defaults to Powered by Oink and accepts inline Markdown.
offline_search: true
# `hugo server` builds the search index too (default); set false to skip it.
offline_search_on_serve: true
ui:
dark_mode:
show_menu: true
# Hide the 50px navbar until a mouse reaches the top edge; touch stays visible.
navbar_autohide: false
# Optional one-click docs feedback; records structured gtag events only.
feedback:
enable: false
reasons: true
image_zoom: trueBefore migrating content, verify the consuming site's resolved configuration:
python3 path/to/oink/bin/check-site-markup.py --site .markdown enables Copy text and View source, LLMS emits llms.txt, and
print enables section print views. Offline search, assistant handoff links,
the theme menu, and native image previews are opt-in; the theme supplies their
implementation but does not silently enable site policy. A page can override
Image Zoom with the front matter key image_zoom — every params.ui.* switch
that a page may override uses the site key without its ui. prefix. Book pages
can likewise override reading_width; this controls the inner reading measure
while page_width continues to control the surrounding shell.
Set params.ui.navbar_autohide: true to tuck the navbar above the viewport on
mouse-driven devices at the md breakpoint (768px) and above and reveal it
from the center of the top edge. The two 64px corners stay inactive for
collapsed-rail controls, while touch pointers and every drawer-width viewport
keep the sticky navbar visible. The home page is exempt: a landing page shows
its navbar even when the site-wide setting is on (its own front matter can
still set navbar_autohide: true). A section cascade or page can override the
policy with the top-level navbar_autohide front-matter key. This differs from
navbar_enabled: false, which omits the navbar completely.
params.ui.feedback.enable: true adds a “Yes / No” prompt. A click
immediately emits a docs_feedback event through an existing gtag function;
an optional reason emits a refining event with refinement: true. OINK does
not send free text and needs no endpoint. When Giscus comments are active, the
result also links readers to the comments section for a detailed report. Use a
Docs/Book/Swagger section cascade to enable it only where it is useful.
When upgrading an older feedback configuration, remove yes, no,
max_value, endpoint, and max_length; the one-click model does not use a
Worker or a submission endpoint.
Then preview the site. Local search is omitted from hugo server so large-site
content edits stay fast; set the Hugo parameter environment override when the
preview specifically needs to exercise search (the x is Hugo's alternate
key delimiter, needed because the key itself contains underscores):
hugo server
HUGOxPARAMSxOFFLINE_SEARCH_ON_SERVE=true hugo serverOINK renders fenced math code blocks out of the box. To author inline
\( ... \) or block \[ ... \] / $$ ... $$ formulae, the consuming site
must also enable Hugo's Goldmark passthrough extension:
markup:
goldmark:
extensions:
passthrough:
enable: true
delimiters:
block: [['\[', '\]'], ['$$', '$$']]
inline: [['\(', '\)']]Hugo does not merge a theme module's markup configuration into the consumer,
so OINK cannot enable this on a site's behalf. A passthrough configuration with
no matching render hook silently leaves delimiter text such as $$ in the
page; OINK supplies that hook and renders KaTeX locally at build time. The
legacy Hextra front matter key math: true has no meaning in OINK and is not a
substitute for the Goldmark configuration above.
For an isolated display formula on a site that cannot enable passthrough yet,
use {{< eq >}}E = mc^2{{< /eq >}}. This parameter-free escape hatch is
unnumbered; the Book form adds an explicit num.
For production, pin a release tag in go.mod. See the
getting-started guide for site
structure, configuration, and deployment.
The shell defaults to content whose Hugo type is docs, book, blog, or swagger.
Sites with a different docs path can set params.ui.docs_section (for example,
guide) and use a front matter cascade with type: docs; additional types can
be added through params.ui.shell_types.
OINK keeps font choices behind semantic CSS custom properties. The default
technical preset preserves the OINK display and monospace faces. A site that
wants the platform font stack, with no OINK brand-font requests, can select:
params:
ui:
typography: systemBoth presets are compiled by Hugo into the same static stylesheet. They add no
JavaScript, package-manager step, remote font service, or runtime stylesheet.
Sites can locally host their own faces and override the documented
--td-*-font-family roles in assets/scss/_styles_project.scss; see the
architecture contract.
- oink.pgsty.com — source — the bilingual documentation, feature showcase, and regression site.
exampleSite/— a bilingual example site: a composable landing page plus a flat component reference under/docs/, running directly from this checkout withcd exampleSite && hugo server.
Configuration · Components · Examples · Deployment · Contributing
Theme maintainer notes: index · architecture · components · shell, navigation, and actions · Landing · 0.4 to 0.5 migration.
English, Simplified Chinese (zh-cn and generic zh), and Traditional Chinese
(zh-tw) have complete reviewed OINK interface text. Every other bundled locale
has the same key schema and keeps its inherited Docsy translations; new
OINK-only labels currently use explicit English fallback text pending community
translation.
OINK is licensed under the Apache License 2.0 and derived from Docsy. See NOTICE for upstream attribution and VENDOR.json for bundled third-party components.