This is the multi-page printable view of this section. .

Return to the regular view of this page.

Oink Blog

OINK announcements, engineering stories, and implementation notes

1 - Introducing the OINK implementation preview

OINK turns a directly customized Docsy codebase into a local-first, Hugo-only documentation theme with multilingual infrastructure and reusable content components.

Today we are publishing the OINK implementation preview: a directly evolved Docsy theme with one canonical product shell, a Hugo-only consumer build, local-first browser dependencies, a general multilingual framework, and a set of reusable content components drawn from PGSTY documentation sites.

This is an implementation and documentation milestone, not a public versioned release. The final public brand, module and package identities, first version, and production Cloudflare Pages deployment remain explicit release gates.

Why OINK exists

Several mature documentation sites had independently copied the same Docsy layouts, navigation, search code, SCSS, JavaScript, and shortcodes. A common fix had to be repeated across repositories, while each site also carried a frontend toolchain and implicit network dependencies that made isolated builds harder than they needed to be.

OINK consolidates the genuinely reusable layer. Product matrices, portals, pricing pages, and other business-specific behavior stay in their own sites. The shared theme owns the documentation shell, browser runtimes, multilingual routing, accessibility behavior, and content-component contracts.

What changes

One product instead of a mode

OINK is not an optional skin. There is no oink.enabled flag, params.oink.* namespace, or parallel upstream-versus-brand template tree. The implementation in theme/ is the product.

That decision avoids two visual systems and two test matrices. Native Hugo settings and compatible Docsy parameters keep their established meanings.

Hugo-only consumer builds

A complete consuming site builds with:

BASH
hugo --gc --minify

Bootstrap, Font Awesome, fonts, search, diagrams, API documentation runtimes, and OINK components are committed with the theme. Node.js, npm, PostCSS, Autoprefixer, and CDN downloads are not consumer requirements.

Repository maintainers still use Node-based tools for tests and vendor refreshes. That maintenance toolchain is deliberately outside the public site-build contract.

Local-first browser behavior

The default starter serves its shell, fonts, icons, search, Mermaid, KaTeX, Markmap, Swagger UI, Redoc, Asciinema, ECharts, and Infographic dependencies from the generated site. Optional runtimes are selected per page and loaded at most once.

PlantUML and Diagrams.net do not receive public service defaults. A site must configure a controlled endpoint, use a pre-rendered result, or make an explicit remote-service choice.

Multilingual infrastructure

Language routing comes from Hugo’s language and translation objects. One configured language hides the selector. With two or more languages, a click advances by configured weight, while a short hover or keyboard focus opens the complete menu. If the current page lacks a translation, the selector goes to the target-language home page instead of a dead path.

The starter and documentation site use English as the primary language and Simplified Chinese as the second. Every page in the core docs and blog scope has a colocated .zh.md translation with stable explicit heading IDs.

Reusable components

OINK adds theme-owned Asciinema, ECharts, Infographic, document carousel, details, tabs, cards, navigation cards, document cards, and parameter components. They generate unique instance IDs and load their local assets only when used.

ECharts accepts structured JSON or YAML plus optional JavaScript callbacks referenced as $fn:name. Callback code runs only on pages that declare it.

What stays familiar

OINK retains Docsy’s content organization, front matter, documentation and blog sections, menus, taxonomies, print output, repository links, common shortcodes, diagrams, API reference features, and extension hooks. Existing sites can remove duplicated common implementations without rewriting ordinary Markdown.

The project also preserves Docsy’s Apache-2.0 history and attribution. A vendor manifest records pinned third-party sources, licenses, artifacts, and checksums.

Try the starter

Install Hugo Extended 0.160.1 or newer, then run from this checkout:

BASH
hugo --source starter --gc --minify

The current validation baseline is Hugo Extended 0.164.0. Open the generated English and Chinese pages, switch languages, search locally, change color mode, and visit the component examples.

For a network-isolated transfer, maintainers can create a complete archive:

BASH
scripts/package-offline.sh /absolute/path/oink-preview.tar.gz preview

The archive includes the theme, starter, licenses, upstream record, migration guide, vendor manifest, and a sidecar checksum.

Current validation

The implementation includes automated coverage for:

  • minimum-version and current Hugo Extended builds;
  • forbidden consumer Node/npm/PostCSS/Autoprefixer paths;
  • LTR, RTL, subpath, print, color-mode, and production assets;
  • hidden, click-to-cycle, hover-menu, translation-fallback, and RTL language behavior;
  • local per-page runtimes and repeated component instances;
  • ECharts structured options and callback integration;
  • an offline bilingual starter and offline release archive;
  • vendor licenses and checksums;
  • non-mutating migration rehearsals for SILO, PGSTY, SOW, and Pigsty.

The latest four-site rehearsal built temporary copies successfully. It did not modify or deploy those production repositories.

What remains before release

The public identity and first version must be approved and applied consistently to the module, package, source tags, nested theme tag, archive, and documentation. The target Cloudflare Pages project must then be connected to the source branch, built with the pinned Hugo version, published, and verified at its hosted URL.

Until those gates close, use the preview for evaluation and migration rehearsal, not as an unversioned production dependency.

2 - OINK implementation diary: from copied shells to one theme

A technical diary of the decisions, migrations, safety boundaries, tests, and documentation work behind the OINK implementation preview.

OINK began with an awkward observation: several production documentation sites looked related because they were related, but their common implementation lived as copied files. The visible result was consistent enough; the maintenance model was not.

This diary records how the project moved from repeated site overrides to one directly evolved theme. It focuses on decisions and evidence rather than a commit-by-commit transcript.

Locking the contract

The first useful work was subtraction. We wrote down what the product must be before choosing how to implement it:

  • an independent theme derived directly from Docsy;
  • one canonical shell, not a switchable skin;
  • Hugo Extended as the only consumer build dependency;
  • local-first delivery for every theme-owned browser asset;
  • multilingual behavior derived from Hugo rather than PGSTY domains;
  • reusable components in the theme, business semantics in the site;
  • preserved Docsy history, licenses, and upstream traceability.

This ruled out an attractive but costly shortcut: adding params.oink.enabled and leaving the old shell in place. A mode switch would have made every layout change, accessibility fix, and test support two products. Direct evolution made the intended design the only design.

Replacing the shell

The documentation, blog, and API-reference layouts were rebuilt around shared, small partials. The resulting shell includes:

  • global navigation and responsive sub-navigation;
  • a resizable, foldable sidebar;
  • local search and quick links;
  • language and color-mode controls;
  • breadcrumbs, table of contents, page metadata, and feedback;
  • a consistent footer and print layout.

The hard part was not drawing a navbar. It was preserving existing Docsy extension points while removing copied baseof.html files. Narrow hooks remain; site-wide shell duplication no longer has to be the normal customization path.

Removing the consumer toolchain

The original dependency chain assumed npm-provided Bootstrap and Font Awesome, and some paths invoked PostCSS. OINK moved the required sources and compiled artifacts into the theme and kept SCSS inside Hugo’s own asset pipeline.

Tests do more than check that hugo succeeds. Fixture traps fail if a consumer build tries to run Node.js, npm, PostCSS, or Autoprefixer, or if a template uses resources.GetRemote. LTR and RTL pages go through the same constraint.

This distinction matters: the repository still uses Node for its maintainer test harness. “Hugo-only” describes what a consuming site needs after it has a complete theme, not a ban on development tooling inside the theme repository.

Vendoring browser runtimes

The next layer was every dependency the browser might otherwise fetch: Bootstrap, Font Awesome, fonts, jQuery, Lunr, Mermaid, KaTeX, Markmap, Swagger UI, Redoc, Asciinema, ECharts, Infographic, and their supporting libraries.

Each selected artifact received a source, fixed version, license path, checksum, and update procedure in theme/VENDOR.json. Licenses live beside the vendored material. The manifest is validated against the actual files rather than treated as an aspirational inventory.

PlantUML and Diagrams.net forced a useful distinction. They are service-backed features, not merely JavaScript libraries. OINK refuses to invent a public endpoint: enabling one without a configured service fails the build.

Building the multilingual core

The previous language behavior was scattered across navigation and site-specific assumptions. The new core starts with Hugo’s configured languages, .Translations, and .AllTranslations.

The presentation is deliberately stable: one language hides the selector; two or more use the same icon button. Clicking advances by configured weight, while a short hover or keyboard focus opens the complete language menu.

A missing translation falls back to the target-language home page. Language labels use each language’s own name. The same objects drive lang, direction, canonical, hreflang, and Open Graph locale metadata, so the visible selector cannot drift from SEO output.

The tests construct every state with an RTL current language as well as normal LTR cases. Native links and disclosure controls keep keyboard behavior predictable.

Promoting components

Asciinema, ECharts, Infographic, document carousel, details, tabs, cards, and parameter rendering had already proved valuable in PGSTY sites. The work was to turn them from copies into product APIs:

  • normalize parameter names and defaults;
  • generate unique IDs from page identity and shortcode ordinal;
  • load each runtime once per page and omit it from unused pages;
  • preserve subpath URLs;
  • support repeated identical instances;
  • provide print, dark-mode, mobile, keyboard, and reduced-motion behavior;
  • retain compatible aliases for imported content.

Product matrices and other business widgets did not move. Reuse is not measured by the number of repositories containing a copy; it requires a stable, business-neutral contract.

Supporting ECharts callbacks

ECharts callbacks are legitimate chart options that JSON and YAML cannot express. Existing pages use them for tooltip formatting, label formatting, and data-dependent colors. Treating those callbacks as a separate migration exception added configuration without creating a sandbox.

The shortcode therefore keeps one direct contract:

  1. content supplies JSON or YAML, which Hugo parses and safely serializes;
  2. an optional fenced JavaScript block declares callbacks;
  3. $fn:name values reconnect those callbacks after the options are parsed;
  4. authors review executable code under the same trust model as inline HTML and other custom integrations.

Tests cover repeated identical charts, invalid CSS lengths, structured options, and callback registration.

Creating the starter and archive

A contract is easier to trust when the smallest example demonstrates it. The starter contains bilingual home, docs, blog, and component pages; local search; dark mode; diagrams; API documentation; and the new components. It has no package.json and no site workflow.

The offline packager combines theme/, starter/, licenses, the upstream record, and migration guidance, excluding generated output and dependency caches. It writes a sidecar SHA-256 file and refuses to overwrite an existing artifact.

The acceptance test copies the starter and theme to a temporary directory, empties caches, blocks HTTP/HTTPS and Go proxies, builds with Hugo, and examines HTML and CSS for third-party subresources.

Rehearsing four migrations

SILO, PGSTY, SOW, and Pigsty provided the reality check. The rehearsal tool copies each workspace instead of modifying it, removes only classified common overrides, applies a local theme replacement, forbids network and frontend tools, and runs the production build.

The latest rehearsal removed 20 common overrides from SILO, PGSTY, and SOW and 24 from Pigsty. Pigsty retained its three business matrix shortcodes and existing ECharts callbacks. All temporary copies built, producing 1,095, 16, 128, and 2,473 HTML files respectively.

Those numbers prove the rehearsal at the recorded commits. They do not prove that any production repository was changed or any hosted site was deployed.

Turning the sample into OINK docs

The inherited docsy.dev site was valuable as a regression corpus, but it described only Docsy. The documentation phase did four things:

  1. made English primary and Simplified Chinese second; a later shell review removed French from the demonstration site;
  2. translated every core documentation and blog source into a colocated .zh.md page;
  3. preserved English heading IDs explicitly in every Chinese heading;
  4. added the OINK product guide, announcement, and this implementation diary.

Before translation, we established a terminology and typography guide. A checker then verifies source/translation pairs, heading counts, explicit Chinese IDs, and rendered English/Chinese heading-ID equality.

Historical Docsy release posts remain faithful translations. Their npm-era instructions are historical context, while the OINK architecture and migration guides state the current Hugo-only product contract.

What testing changed

Several tests changed the design rather than merely blessing it:

  • subpath fixtures forced every local component URL through Hugo URL handling;
  • repeated-instance tests replaced content hashes with page-and-ordinal IDs;
  • offline browser checks exposed implicit runtime requests;
  • RTL language matrices prevented a selector implementation that only worked for the starter’s two LTR languages;
  • ECharts callback fixtures kept callback registration and structured options interoperable;
  • migration rehearsals preserved site-specific partials that a blanket layouts/ deletion would have removed.

The strongest test suite is one that constrains the product boundary, not just the current HTML snapshot.

Remaining work

Two release gates remain intentionally open. The public brand, repository, module and package identities, and first version need approval. A real Cloudflare Pages project then needs to build from the source branch and pass hosted verification.

Production migrations should proceed one site at a time, with dedicated branches, preview deployments, visual regression, and rollback artifacts. The temporary four-site rehearsal is a foundation for that work, not a substitute.

Lessons

  • Write the product boundary before moving files.
  • A local-first promise needs both build-time and browser-time evidence.
  • Configuration is healthier when it expresses user choices, not internal implementation branches.
  • Translation quality includes stable links, code fidelity, typography, and rendered structure—not prose alone.
  • Reuse should remove maintenance copies without absorbing business semantics.
  • “Built,” “packaged,” “published,” “deployed,” and “migrated” are different claims and need different evidence.

The result is less dramatic than a rewrite and more useful: one theme that can be understood, built, tested, translated, and migrated as a coherent product.