Essay

Rebuilding DivineForge: From Hugo to Next.js App Router

Fri Feb 27
next-jstypescripttailwindmdxdesign-systemaws-lightsailcontent-strategy

Context

DivineForge started as a Hugo/Blowfish site on Cloudflare Pages — a minimal work log for documenting software decisions. The original intent was right: structure over prose, context and outcome over narrative. But the scope evolved. The site needed to document building in public across multiple concerns — a build log, satire on enterprise software culture, consultation context, and an honest about page — each with different content shapes and a distinct visual identity that Hugo themes couldn't support without significant workaround.

Constraint / Problem

Hugo is well-suited for static content. It is not suited for a custom component system, design tokens, or React components embedded in content. The Blowfish theme handled layout but couldn't accommodate a dark/light mode built on CSS custom properties, a custom type system, or interactive React components inside MDX posts. Adding those things would mean maintaining patches against the theme — a maintenance position that compounds over time.

The content model had also outgrown a single work log. Satire, build entries, and consultation context each have different frontmatter shapes and rendering logic. Hugo's taxonomy system handles tagging well but is awkward for section-specific logic — bot cards on satire posts, status badges on build entries, SVG diagram components embedded in build content.

Deploying to AWS Lightsail (Docker, standalone output) was also not a workflow Hugo or Cloudflare Pages was set up for.

Action Taken

Rebuilt the site on Next.js 16 App Router with TypeScript and Tailwind v4. Content is MDX rendered via next-mdx-remote/rsc, which keeps content in flat Markdown files while allowing React components to be passed in per-section — the SmartHomeDiagram SVG in a build post being the first use of that pattern.

Designed a token-based design system using CSS custom properties under @theme and :root. Seven tokens cover the full palette for both dark (default) and light modes. No hardcoded colors anywhere in the codebase — all UI uses var(--color-forge-*). Glow effects are hover-only, never ambient.

Content is organised into five sections with distinct frontmatter contracts:

  • Worklog — structured four-part entries (Context, Constraint, Action, Outcome)
  • Build — system documentation with status (concept / in-progress / shipped), diagram components, cover image extraction from content or frontmatter
  • Satire — bot-assigned commentary cards, split rendering for builder response blockquote
  • Consult — static, WhatsApp contact with QR
  • About — narrative + track record + stack

Navigation restructured to reflect those sections. /lab removed — build content absorbed into /build. Home page entry cards updated accordingly.

Standalone output is enabled for Docker compatibility. Google AdSense added via next/script with afterInteractive strategy. Logo, favicon (src/app/icon.png), and Apple touch icon (src/app/apple-icon.png) generated from a 1024×1024 source PNG using macOS sips. Open Graph and Twitter card metadata configured.

Mobile layout was audited specifically for Safari iOS. Navigation restructured to two rows on mobile — logo and theme toggle on row 1, nav links on row 2 — to prevent overflow on ~390px viewports. Responsive gutters (px-4 sm:px-6), overflow-wrap: break-word in prose, and min-w-0 on flex title spans applied across all pages.

Outcome / Result

The site runs on a stack that matches the work being documented. Next.js App Router handles section routing, per-section MDX component injection, and static generation cleanly. The design system is portable — adding a new section means new frontmatter fields and a new route, not a theme fork.

Content model is stable enough to publish into. Satire has ten entries. Build has one documented system. Worklog has entries spanning 2020–2026. The sections are distinct but share the same token system, navigation, and footer.

The rebuild also forced clarity on what the site is not: it is not a blog, not a portfolio, and not a consultant brochure. It is a forge that documents its own building — and the stack now matches that intent.