For years, my blog was powered by Wyam, a fantastic .NET static site generator. However, technology moves fast, and Wyam became legacy, bound to older .NET Framework runtimes and dependencies.
Recently, I decided to upgrade my blog's engine to Statiq Web, the modern, performance-oriented successor to Wyam built on top of .NET 8. Along the way, I didn't just migrate files—I gave the site a complete visual, functional, and developer-experience facelift.
The twist? This entire migration was performed in partnership with agentic AI coding assistants.
Instead of manually modifying 300+ HTML/Markdown files and fighting compiler warnings for days, I paired with AI coding assistants to handle the bulk of the refactoring work.
My workflow was split across two powerful models:
Here is a breakdown of what the AI agents helped me build:
.NET 8 console project structure (MySite.csproj and Program.cs) from scratch._Layout.cshtml, and mapped page metadata variables correctly.localStorage memory.ArrowUp/ArrowDown/Enter/Escape), and custom <mark> keyword query highlighting.Wyam served me well, but it had several issues:
Statiq Web compiles pages in a fraction of the time, offers C# console-first configuration, and supports modern Razor templating out-of-the-box.
Unlike Wyam, which relies on a global CLI tool, Statiq sites are compiled using a standard .NET Console Application.
We created a new project and added the Statiq.Web NuGet package:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Statiq.Web" Version="1.0.0-beta.60" />
</ItemGroup>
</Project>
Then, we defined the entry point in Program.cs:
using Statiq.App;
using Statiq.Web;
return await Bootstrapper
.Factory
.CreateWeb(args)
.AddSetting(Keys.Host, "matthewregis.dev")
.AddSetting(Keys.LinksUseHttps, true)
.AddSetting(WebKeys.SiteTitle, "Matthew Regis")
.AddSetting(WebKeys.GenerateSitemap, true)
.AddSetting(WebKeys.GenerateSearchIndex, true)
.AddSetting("ZipSearchResultsFile", false)
.AddSetting("AdditionalSearchResultFields", new[] { "tags" })
.RunAsync();
The blog's theme is based on the HTML5 UP SolidState theme—a futuristic dark layout. To improve accessibility and user choice, we implemented a custom theme switcher supporting a brand-new, premium light mode.
To avoid the annoying "dark-mode flash" on loading the light theme, the layout utilizes an inline script in <head> that applies the theme class before the browser paints the body:
<script>
(function() {
var theme = localStorage.getItem('theme') || 'dark';
if (theme === 'light') {
document.documentElement.classList.add('light-theme');
window.addEventListener('DOMContentLoaded', function() {
document.body.classList.add('light-theme');
});
}
})();
</script>
The light theme features:
#f8fafc).backdrop-filter: blur(8px)) with fine slate dividers.linear-gradient(135deg, #e0e7ff 0%, #fae8ff 100%)).To prevent page elements from animating their colors on initial load (which looks jittery), we added a .no-transition class to <body> on load, removing it 100ms later via JS:
body.no-transition, body.no-transition * {
transition: none !important;
}
Adding a client-side search indexing system is easy with Statiq's SearchIndex pipeline.
By adding "AdditionalSearchResultFields": ["tags"] to Program.cs, Statiq compiles a search.results.json mapping that includes each post's URL, Title, and Tags list.
We built a custom real-time search interface in search.cshtml:
ArrowUp/ArrowDown, selecting with Enter to navigate to the post, or closing the overlay with Escape.<mark> tag wrapper to highlight matched keywords in a soft indigo tint rather than default browser yellow.We also added two client-side scripts to improve code sharing and site speed:
<pre> code block now displays a copy icon on hover. Clicking it utilizes the browser's clipboard API and flashes a green checkmark success state.loading="lazy" to all post images dynamically, accelerating page load speeds.Previously, deployment was managed via an Azure DevOps pipeline zipping the output directory and pushing it via a curl request.
We replaced this with a clean, modern GitHub Actions Workflow (.github/workflows/deploy.yml):
name: Build and Deploy to Netlify
on:
push:
branches: [master]
pull_request:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Build Site
run: dotnet run
- name: Deploy to Netlify
uses: nwtgck/actions-netlify@v3.0
with:
publish-dir: './output'
production-branch: 'master'
github-token: ${{ secrets.GITHUB_TOKEN }}
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
This setup compiles the Statiq project on a Linux runner and deploys it directly to Netlify. It even supports automatic Deploy Previews on Pull Requests!
Migrating to Statiq Web brought my developer blog into the modern era. The build pipeline is fast, the templates use the latest Razor engine features, the light theme provides a great alternative for readers, and code snippets are easy to copy.
Doing it side-by-side with agentic AI coding tools showed how powerful collaborative development can be—starting the foundational structure with Claude Opus, and polishing and completing it with Gemini 3.5 Flash.