<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Jason Jamieson — Log Entries</title><description>Engineering notes and write-ups.</description><link>https://jasonjamieson.me/</link><item><title>Why this site is no longer a canvas</title><link>https://jasonjamieson.me/log/moving-off-kotlin-wasm/</link><guid isPermaLink="true">https://jasonjamieson.me/log/moving-off-kotlin-wasm/</guid><description>Compose Multiplatform for Web renders into a canvas element. That&apos;s a fine choice for an app and the wrong one for a blog. Notes from the rebuild.</description><pubDate>Tue, 28 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;the-canvas-problem&quot;&gt;The canvas problem&lt;/h2&gt;
&lt;p&gt;Compose Multiplatform for Web doesn’t render HTML. It renders into a single
&lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element via Skia. Everything you see is pixels the runtime painted.&lt;/p&gt;
&lt;p&gt;That one architectural fact cascades:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Search engines find nothing to index. There is no text in the document.&lt;/li&gt;
&lt;li&gt;Screen readers get almost nothing, because there are no semantics to read.&lt;/li&gt;
&lt;li&gt;Ctrl+F doesn’t work. Neither does selecting a paragraph to quote it.&lt;/li&gt;
&lt;li&gt;The first paint waits on a multi-megabyte runtime download.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;the-test-i-should-have-applied-earlier&quot;&gt;The test I should have applied earlier&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Is the thing a document or an application?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;the-theme-argued-against-it-too&quot;&gt;The theme argued against it too&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;That’s backwards. Scanlines are a &lt;code&gt;repeating-linear-gradient&lt;/code&gt;. Phosphor glow is
a &lt;code&gt;text-shadow&lt;/code&gt;. The terminal look is &lt;em&gt;typography and colour&lt;/em&gt;, which is what CSS
does natively:&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-background);color:var(--astro-code-foreground); overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;.crt::after&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  content&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  position&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; fixed&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  inset&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  pointer-events&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; none&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  background&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt; repeating-linear-gradient&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;    0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;deg&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    rgba&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0.22) 0 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-function)&quot;&gt;    rgba&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;(0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 0) 1&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;px&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-constant)&quot;&gt;  )&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fifteen lines, and it renders &lt;em&gt;on top of real text&lt;/em&gt;. The aesthetic became a
layer over the content instead of a replacement for it.&lt;/p&gt;
&lt;h2 id=&quot;what-kotlinwasm-is-actually-good-at&quot;&gt;What Kotlin/Wasm is actually good at&lt;/h2&gt;
&lt;p&gt;Worth saying clearly, because the conclusion isn’t “the technology is bad.”&lt;/p&gt;
&lt;p&gt;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 &lt;em&gt;logic&lt;/em&gt;
in a browser — a parser, a solver, a simulation, a domain layer shared with an
Android app. Compute, not UI.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;what-carried-over&quot;&gt;What carried over&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
</content:encoded><category>kotlin</category><category>wasm</category><category>web</category><category>astro</category></item><item><title>First entry</title><link>https://jasonjamieson.me/log/first-entry/</link><guid isPermaLink="true">https://jasonjamieson.me/log/first-entry/</guid><description>Setting up shop — what this log is for and what to expect here.</description><pubDate>Mon, 20 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is where I’ll keep working notes: things I’ve debugged, decisions I’ve
made and later regretted, and the occasional write-up of something I shipped.&lt;/p&gt;
&lt;p&gt;Posts are markdown files in &lt;code&gt;src/content/log/&lt;/code&gt;. Adding one means creating a
file with frontmatter and writing — no build config to touch, no component to
register.&lt;/p&gt;
&lt;pre class=&quot;astro-code css-variables&quot; style=&quot;background-color:var(--astro-code-background);color:var(--astro-code-foreground); overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;md&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &quot;A new entry&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt; &quot;One sentence that shows up in the index and in link previews.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;pubDate&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt; 2026-07-28&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;tags&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-token-string-expression)&quot;&gt;&quot;kotlin&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--astro-code-foreground)&quot;&gt;Body text starts here.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;description&lt;/code&gt; isn’t decoration — it’s what appears in the log index, in the
RSS feed, and in the preview card when someone shares the link. Worth writing
properly.&lt;/p&gt;
&lt;p&gt;Set &lt;code&gt;draft: true&lt;/code&gt; in the frontmatter to keep something out of the index and the
feed while you work on it.&lt;/p&gt;
</content:encoded><category>meta</category></item></channel></rss>