Three Passes to a Static Site
I started with one practical question: could a C-first website stay fast without becoming hard to maintain?
Pass 1: Clay UI
Clay UI made the first pass feel possible. Its rendering model fit the C-to-WebAssembly experiment, so I used it for the header, page layout, and navigation. It felt fast, but responsive content polish turned into too much hand-tuning.
Clay UI proved the C-first browser shell could work.
Pass 2: LVGL + Emscripten
LVGL + Emscripten brought a fuller embedded GUI toolkit into the browser. SDL GPU acceleration got the prototype down to 16 ms frame times, but the result still felt more like a portable app surface than an accessible, content-heavy website.
LVGL proved the rendering path could be fast.
Pass 3: SvelteKit
SvelteKit became the keeper because it let the site be simple again: static pages and mdsvex for the blog, easy to read and easy to change. The heavier WebAssembly game path stays lazy-loaded, so public pages stay quick to revise. That split is what keeps every game page fast once a prototype ships.
SvelteKit kept the fast path while making the public site easier to write for.
Comparison
| System | Implementation model | Performance | UI/UX quality and maintainability | Outcome |
|---|---|---|---|---|
| Clay UI | Immediate-mode C UI in WebAssembly | Lean and fast | Fun to prototype; fragile for polished responsive content | Moved on |
| LVGL + Emscripten | Embedded GUI toolkit in the browser | SDL GPU path hit 16 ms frames | Strong runtime; wrong fit for a public content site | Moved on |
| SvelteKit | Static Svelte pages with TypeScript, CSS, and mdsvex | Prerendered pages; lazy game WASM | Accessible, responsive, content-friendly | Kept |
Clay and LVGL proved the performance instinct was valid. SvelteKit was fast enough, easier to polish, and easier to keep writing for.