Why this site is no longer a canvas
This site used to be a Compose Multiplatform app compiled to WebAssembly. It was a scrollable column of category rows, each one a horizontal strip of cards that resized when you clicked them. It looked good. It was also the wrong tool, and it took me a while to see why.
The canvas problem
Compose Multiplatform for Web doesn’t render HTML. It renders into a single
<canvas> element via Skia. Everything you see is pixels the runtime painted.
That one architectural fact cascades:
- Search engines find nothing to index. There is no text in the document.
- Screen readers get almost nothing, because there are no semantics to read.
- Ctrl+F doesn’t work. Neither does selecting a paragraph to quote it.
- The first paint waits on a multi-megabyte runtime download.
None of that matters for an internal dashboard behind a login. All of it matters for a personal site whose entire purpose is being found and read.
The test I should have applied earlier
Is the thing a document or an application?
Documents want the DOM — text, links, semantics, indexability. Applications can justify a canvas. A blog is a document. Figma is an application. Most things people build are documents wearing an application costume, and this site was one of them.
The theme argued against it too
I wanted a heavily styled terminal aesthetic — green phosphor, scanlines, the whole Weyland-Yutani look. My instinct was that a custom visual identity needed a canvas to draw on.
That’s backwards. Scanlines are a repeating-linear-gradient. Phosphor glow is
a text-shadow. The terminal look is typography and colour, which is what CSS
does natively:
.crt::after {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
background: repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0.22) 0 1px,
rgba(0, 0, 0, 0) 1px 3px
);
}
Fifteen lines, and it renders on top of real text. The aesthetic became a layer over the content instead of a replacement for it.
What Kotlin/Wasm is actually good at
Worth saying clearly, because the conclusion isn’t “the technology is bad.”
Kotlin/Wasm targets WasmGC, so it reuses the browser’s garbage collector rather than shipping its own. That makes it a genuinely good way to run Kotlin logic in a browser — a parser, a solver, a simulation, a domain layer shared with an Android app. Compute, not UI.
The narrower thing is Compose for Web specifically: it exists so that a team with an existing Compose app can ship a web build cheaply. That’s a real and valuable use case. It just isn’t a blog.
What carried over
Less was wasted than I expected. The GitHub Pages deploy pipeline transferred almost unchanged — same Actions workflow shape, same custom domain, same DNS. The theming work turned into CSS custom properties. And the writing I’d been putting off is now a markdown file instead of a Kotlin data class, which is probably the change that matters most.