<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <title>remy sharp's b:log</title>
    <atom:link href="https://remysharp.com/feed.xml" rel="self" type="application/rss+xml"></atom:link>
    <link>https://remysharp.com</link>
    <description>About [code] and all that jazz</description>
    <image>
      <title>remy sharp's b:log</title>
      <link>https://remysharp.com</link>
      <url>https://remysharp.com/images/avatar-125.jpg</url>
      <width>125</width>
      <height>125</height>
    </image>
    <lastBuildDate>Mon, 22 Jun 2026 22:00:49 +0000</lastBuildDate>
    <managingEditor>remy@remysharp.com (Remy Sharp)</managingEditor>
    <webMaster>remy@remysharp.com (Remy Sharp)</webMaster>
    <language>en</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <generator>Honestly, I don't know what most of these tags do, I copied a lot of them from other people's web site ¯\_(ツ)_/¯</generator>
    <item>
      <title>Accessible (I Think) Split-Cell Table Headers by Eric Archived Thoughts [link]</title>
      <guid isPermaLink="false">2026-06-22-4f7168d2</guid>
      <link>https://remysharp.com/links/2026-06-22-4f7168d2</link>
      <pubDate>Mon, 22 Jun 2026 16:24:15 +0000</pubDate>
      <description><![CDATA[This really isn't the intended take away from Eric's post (which is worth reading), but I needed a CSS rule that targetting Safari (because their support is weird):
/* this is gross and I hate it but it works to fix 
   Safari’s layout of the table’s top headers */
@supports (font: -apple-system-body)

Gross, and horrible, but 🙏
Source: meyerweb.com]]></description>
      <content:encoded><![CDATA[
<p>This really isn't the intended take away from Eric's post (which is worth reading), but I needed a CSS rule that targetting Safari (because their support is weird):</p>
<pre><code class="language-css"><span class="token comment">/* this is gross and I hate it but it works to fix 
   Safari’s layout of the table’s top headers */</span>
@supports <span class="token punctuation">(</span><span class="token property">font</span><span class="token punctuation">:</span> -apple-system-body<span class="token punctuation">)</span>
</code></pre>
<p>Gross, and horrible, but 🙏</p>
<p><em>Source: <a href="https://meyerweb.com/eric/thoughts/2026/05/28/accessible-i-think-split-cell-table-headers/">meyerweb.com</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-06-22-4f7168d2">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>FFConf 2026 is live: Things I Learnt [blog]</title>
      <guid isPermaLink="false">ffconf-2026-is-live-things-i-learnt</guid>
      <link>https://remysharp.com/2026/06/22/ffconf-2026-is-live-things-i-learnt</link>
      <pubDate>Mon, 22 Jun 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[As with each year for the FFConf web site, I have a distinct idea of the visual style I want. It has zero to do with the content we're presenting each year, but I do love how FFConf's site can be creative.
It was like that from the very first web site - the logo was designed in early 2009 in 12 variations (which you can see from years 2009, 2010 and 2011 before they were really redesigned).
Before I (inevitably) forget, it made sense for me to write up some of the things I learnt along the way now that the 2026 web site is live.]]></description>
      <content:encoded><![CDATA[
<p>As with each year for the FFConf web site, I have a distinct idea of the visual style I want. It has zero to do with the content we're presenting each year, but I do love how FFConf's site can be creative.</p>
<p>It was like that from the very first web site - the logo was designed in early 2009 in 12 variations (which you can see from years 2009, 2010 and 2011 before they were <em>really</em> redesigned).</p>
<p>Before I (inevitably) forget, it made sense for me to write up some of the things I learnt along the way now that the <a href="https://2026.ffconf.org/">2026 web site is live</a>.</p>
<p>I think <a href="https://chrismahon.com/">Chris Mahon's</a> did an excellent job with his translation of my mood board into Figma pages.</p>
<p>The spec this year was a fanzine style, which is a very tactile paper based medium, which doesn't always translate well to digital. The actual visual impetuous came from the (very fun) Running Man remake, the credits in particular:</p>
<figure><img src="https://remysharp.com/images/2026-mood-board.avif" alt="Screenshots of the credits of Running Man that look like the credits are pages from a physical fanzine, hand copied and pasted and then photocopied over and over" decoding="async"><figcaption>A series of screenshots from the credits of Running Man 2025 which I used as my mood board</figcaption></figure>
<h2>The CSS</h2>
<p>It's very likely a lot of this (<code>clip-path</code> for instance) have been around for ages. But my client work has been almost exclusively on API backend design for the last 4 years or so, which means FFConf is usually the only time I get to work in the front end to a specification.</p>
<h3>Vertical text</h3>
<p>I had been wrestling with transform rotates and origins, and had the text sliding all over the place.</p>
<p><a href="https://bsky.app/profile/anatudor.bsky.social/post/3mok3w3ihhk2q">Ana Tudor came to my rescue</a> and took away all the pain in a simple single line: <code>writing-mode: vertical-lr</code>. An absolute slam dunk for getting text along the side.</p>
<figure><img src="https://remysharp.com/images/ffconf2026-vertical.avif" alt="The word &quot;schedule&quot; vertically aligned perfectly against the actual schedule" decoding="async"></figure>
<h3>Ana's other tips</h3>
<ul>
<li><code>inset: 1</code> can be used as a shortcut instead of <code>top/left/right/bottom: 0</code> when stretching across the page.</li>
<li>I don't need to do <code>transition: rotate(180deg)</code>, <code>rotate</code> (and others) are first class now, so <code>rotate: 180deg</code> works (less bytes too).</li>
</ul>
<h3>Polygons</h3>
<p>I'd not used polygons in CSS yet (didn't have the use case), but due to the cutout nature of the speaker photos, and the proximity to the talk titles, I quickly realised (after failing with margins) this was the way to go.</p>
<ul>
<li><code>shape-outside</code> floating the element and having the text shape around the element, in particular the cutout of the speaker photos</li>
<li><code>clip-path</code> letting me create the sharp angle shape on the footer</li>
<li>Firefox interactive polygon devtools</li>
</ul>
<p>I would primarily develop in Chrome Devtools directly using <a href="https://developer.chrome.com/docs/devtools/automatic-workspaces">workspaces</a>, but Firefox offers interactive polygon editing which was immensely useful.</p>
<figure><img src="https://remysharp.com/images/ffconf2026-polygons.avif" alt="The polygon editor in Firefox with nodes to reshape" decoding="async"></figure>
<h3>Contrast issues</h3>
<p>Due to the effect of the &quot;paper&quot;, I didn't want to make all the text partly opaque, so instead I lay the paper (which is mostly transparent) over the entire page (with <code>pointer-events: none</code>).</p>
<p>This did mean that there was some grey flecks of colour over black text which definitely caused contrast issues.</p>
<p>In skimming the rendering options in Chrome's devtools I found the &quot;Prefers Contrast&quot; (I'm not sure if I knew about it already or not).</p>
<p>Using <code>@media (prefers-contrast: more)</code> allowed me to remove the paper effect and keep a striking black and white design.</p>
<p>But what if the user wanted control? I added a labelled checkbox and found that instead of using the <code>@media</code> query I could use <code>@container style(--high-contrast: 1)</code>. All the modification styles are nested inside of the <code>@container</code> query.</p>
<p>Then the <code>--high-contrast</code> is toggled using:</p>
<pre><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--high-contrast</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-contrast</span><span class="token punctuation">:</span> more<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">:root</span> <span class="token punctuation">{</span>
    <span class="token property">--high-contrast</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token selector">body:has(#high_contrast:checked)</span> <span class="token punctuation">{</span>
  <span class="token property">--high-contrast</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<h3>Bonus bits</h3>
<p>I hadn't realised I could style the <code>::placeholder</code> pseudo element (not sure why I thought I couldn't).</p>
<p>Lastly, a lovely win for me, I discovered <code>nth-child(odd of &lt;selector&gt;)</code> 🤯. I was trying to set the speaker blocks with alternating position of their photo (which I'd select with <code>odd</code> and <code>even</code>), but there was an extra element between each speaker.</p>
<p>In reviewing the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:nth-child#the_of_selector_syntax">MDN page</a> I discover the <code>of</code> syntax, and it let me target exactly the way I need using: <code>&amp;:nth-child(odd of .speaker-card)</code>.</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/06/22/ffconf-2026-is-live-things-i-learnt">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>prop-for-that: CSS reacts, JS just listens [link]</title>
      <guid isPermaLink="false">2026-06-19-e5b6847a</guid>
      <link>https://remysharp.com/links/2026-06-19-e5b6847a</link>
      <pubDate>Fri, 19 Jun 2026 15:51:12 +0000</pubDate>
      <description><![CDATA[This is neat. Effectively injecting a tonne of JavaScript based sensors into the elements that ask for the particular category via data-props-for, such as:
&lt;div id="meter" data-props-for="range">
  &lt;input type="range" min="0" max="100" value="42">
&lt;/div>

With CSS like:
@container style(--live-value: 100) {
  .gauge__num { color: var(--max-tint); }
  .gauge__flag::after { content: 'max'; }
}

Lots of useful categories too.
Source: prop-for-that.netlify.app]]></description>
      <content:encoded><![CDATA[
<p>This is neat. Effectively injecting a tonne of JavaScript based sensors into the elements that ask for the particular category via <code>data-props-for</code>, such as:</p>
<pre><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>meter<span class="token punctuation">"</span></span> <span class="token attr-name">data-props-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>range<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>range<span class="token punctuation">"</span></span> <span class="token attr-name">min</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0<span class="token punctuation">"</span></span> <span class="token attr-name">max</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>100<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>42<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
</code></pre>
<p>With CSS like:</p>
<pre><code class="language-css"><span class="token atrule"><span class="token rule">@container</span> <span class="token function">style</span><span class="token punctuation">(</span><span class="token property">--live-value</span><span class="token punctuation">:</span> 100<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">.gauge__num</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--max-tint<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
  <span class="token selector">.gauge__flag::after</span> <span class="token punctuation">{</span> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">'max'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Lots of useful categories too.</p>
<p><em>Source: <a href="https://prop-for-that.netlify.app/">prop-for-that.netlify.app</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-06-19-e5b6847a">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>A bouncer in your pocket by Sacha Judd [link]</title>
      <guid isPermaLink="false">2026-06-19-efb870ce</guid>
      <link>https://remysharp.com/links/2026-06-19-efb870ce</link>
      <pubDate>Fri, 19 Jun 2026 10:29:59 +0000</pubDate>
      <description><![CDATA[Sacha has an in depth analysis of the UK's recent announcements around social media websites and children's access to them.
I wanted to pull a few quotes:

The Internet Watch Foundation reported that child sexual extortion cases in the UK rose 72% in a single year — criminals tricking young people into sending nude images, then blackmailing them. In 97% of those cases, the victims are boys.

Sacha also spots this:

Buried in the coverage is the acknowledgement that all adults will need to verify their age if they want to take or view nude images on their own devices. [...] You’ll have to prove you’re an adult to own and use a phone.

On one hand, to own a phone requires (since the availability of mobile phones) proof of being an adult, because to get a contract of any sort you had to have a bank account. This obviously changes with &quot;burner&quot; phones (a £10 job from ASDA) and a PAYG sim.
On the other hand, who am I proving I'm an adult to - which walks a weird line of privacy invasion.
Quoted within Sacha's article is Signal's response, and exactly what I was thinking when I saw the announcement too: isn't this at odds with the UK wanting to take some kind of lead in international AI?

Child safety looks like well-funded education, robust social services, and meaningful guardrails on the very AI technologies and platforms the current government is eagerly courting.

An excellent post well worth the review, regardless of parent status, it's going to affect us all.
Source: newsletter.sachajudd.com]]></description>
      <content:encoded><![CDATA[
<p>Sacha has an in depth analysis of the UK's recent announcements around social media websites and children's access to them.</p>
<p>I wanted to pull a few quotes:</p>
<blockquote>
<p>The Internet Watch Foundation reported that child sexual extortion cases in the UK rose 72% in a single year — criminals tricking young people into sending nude images, then blackmailing them. In 97% of those cases, the victims are boys.</p>
</blockquote>
<p>Sacha also spots this:</p>
<blockquote>
<p>Buried in the coverage is the acknowledgement that all adults will need to verify their age if they want to take or view nude images on their own devices. [...] You’ll have to prove you’re an adult to own and use a phone.</p>
</blockquote>
<p>On one hand, to own a phone requires (since the availability of mobile phones) proof of being an adult, because to get a contract of any sort you had to have a bank account. This obviously changes with &quot;burner&quot; phones (a £10 job from ASDA) and a PAYG sim.</p>
<p>On the other hand, <em>who</em> am I proving I'm an adult to - which walks a weird line of privacy invasion.</p>
<p>Quoted within Sacha's article is Signal's response, and exactly what I was thinking when I saw the announcement too: isn't this at odds with the UK wanting to take some kind of lead in international AI?</p>
<blockquote>
<p>Child safety looks like well-funded education, robust social services, and meaningful guardrails on the very AI technologies and platforms the current government is eagerly courting.</p>
</blockquote>
<p>An excellent post well worth the review, regardless of parent status, it's going to affect us all.</p>
<p><em>Source: <a href="https://newsletter.sachajudd.com/archive/a-bouncer-in-your-pocket/">newsletter.sachajudd.com</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-06-19-efb870ce">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>20 Years of Blogging [blog]</title>
      <guid isPermaLink="false">20-years-of-blogging</guid>
      <link>https://remysharp.com/2026/06/17/20-years-of-blogging</link>
      <pubDate>Wed, 17 Jun 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[Today is the anniversary of the first blog post on this website from two decades ago. It was about client side JavaScript to automatically (albeit blindly) select the &quot;active&quot; navigation. Ironically, I'd probably do this on the server side these days.
Admittedly, it's imported from my prior blog and the first time I posted on on this domain was in September, but the post in June counts! But then, my domain was registered a full year before on 13 June 2005 (which neither myself, nor the Internet Archive can remember what was on it!).]]></description>
      <content:encoded><![CDATA[<p>Today is the anniversary of the <a href="https://remysharp.com/2006/06/17/auto-selecting-navigation">first blog post</a> on this website from two decades ago. It was about client side JavaScript to automatically (albeit blindly) select the &quot;active&quot; navigation. Ironically, I'd probably do this on the server side these days.</p>
<p>Admittedly, it's imported from my prior blog and the first time I posted on on this domain was in September, but the post in June counts! But then, my domain was registered a full year before on 13 June 2005 (which neither myself, nor the Internet Archive can remember what was on it!).</p>
<p>I could probably pull up the best hits based on traffic (though my Google analytics were stripped years ago, so I'm not sure how I'd work it out). But I'm not sure the highest traffic really represents the hits to me.</p>
<p>Instead, I'm going to reflect on the last two decades of posts and comment on how what I wrote about has changed.</p>
<p>In the first couple of years of my blog, I was posting regularly throughout the month. <a href="https://remysharp.com/2007#march">Even publishing twice a day</a>.</p>
<p>The posts were a mix of movies I had seen and my excitement in sharing jQuery with non-devs (ie. designers, who back in the mid-2000s didn't have the same exposure to front end code as they do now...I think).</p>
<p>I'm not if it was that the mid-2000s the front end for logic wasn't considered serious enough or... something else, but I always feel like the atmosphere has changed a lot over that time. React has somehow let the trolls out from under the rocks and there's a constant tension around the front end.</p>
<p>Still, my posts in those first 5 years wanted to share technical solutions as simply as possible to newbies and non-devs to show there was a way that didn't require starting your JavaScript journey in 1994.</p>
<h2>A personal place</h2>
<p>In 2010 Julie and I lost Tia to stillbirth. After a full disconnect from the internet, I tentatively re-entered using my blog as the way to share what had happened and to share our thanks to the overwhelming love we had had from both friends and the community.</p>
<p>Since then I've always used my blog to reflect on another year passing without our girl on, or near, her birth date.</p>
<p>From 2008, I would also write a round up of <a href="https://remysharp.com/my-years">my year</a>. Something that's celebrated throughout the web blogging community each year around New year (not <em>my</em> blog post! All of yours! Silly thing).</p>
<p>This would also serve as an opportunity to share how our family has grown. Over the years a lot of us (you and I my dear reader) have gotten to chat in person, so it's also fun to hear comments on how our kids have grown. They're a hugely important part of my life, so those comments make me happy.</p>
<h2>Ch-ch-changes</h2>
<p>Just like a house you've no intention of ever leaving, my blog has had various renovations.</p>
<p>I added my <a href="https://remysharp.com/books">reading records</a>, making an effort to (attempt to) review the books.</p>
<p>I added a short lived <a href="https://remysharp.com/til">Things I Learnt</a>. And a newsletter section, which lasted around a year. <em>And</em> a <a href="https://remysharp.com/tif">Things I Fixed</a> (as my experience in hardware grew).</p>
<p>The links section still lives, and probably inspired by <a href="https://adactio.com/links/">Jeremy's links</a> section.</p>
<p>I also added an <a href="https://remysharp.com/attic/">attic</a> (really, it's a loft, but it sounded more impressive as an &quot;attic&quot;) of designs and my <a href="https://remysharp.com/ethos">ethos</a> page, which is like lifting the lid on my brain and seeing the ideas I try to live by.</p>
<p>In the last 5 years the momentum has proven difficult. The pandemic lockdown cut off a lot of my community connection (through events in particular), and as the years rolled on I've found less and less interest in the web.</p>
<p>Obviously there's AI playing into this. I've written a little about it, and have strong opinions (not all obvious) and I've enjoyed making a lot of personal, offline, projects.</p>
<p>But I don't feel like I've anything to add to the discourse on the web. Maybe I will again one day. I'd love to have the excitement I used to have, but these days, it's just not there.</p>
<p>So my blogging slowed down. It's evident in my archive, and you can see the topics drift away from anything practical and as I got older it's more idea and opinion based. Lol. Like <em>this</em> post!</p>
<h2>Your contributions</h2>
<p>From day one, I had comments on my site. Those posts that attracted more visitors tended to draw more discussion, which, I <a href="https://remysharp.com/house-rules">mostly</a> approved of.</p>
<p>I had ported the comments from WordPress to Disqus, <a href="https://remysharp.com/2019/06/11/ejecting-disqus">ejected Disqus</a> when I found they were adding Facebook tracking and landed on <a href="http://commento.io">commento.io</a>.</p>
<p>At some point during this year (2026), Commento just dropped off the web. First it was hanging requests (which is how I spotted it) and now it's just a 404 holding page. Along with dropping off the web, <em>all</em> the comments you've all left over the years went with it.</p>
<p>A constant side effect of the web: entropy. The lesson there: own your stack if you want to last.</p>
<h2>Stick around for some more?</h2>
<p>Honestly, the idea of blogging for another 20 years really doesn't sound realistic to me at all! I'll be in my late 60s and frankly, I find it hard to see that far.</p>
<p>That said, in the 20 years behind me, I've published 674 blog posts (excluding this one), 252 links and 188 book reviews. Annoyingly I've got 75 blog posts in draft, some dating back to 2019 (I really need to tidy these up).</p>
<p>My blog is also entirely all <a href="https://github.com/remy/remysharp.com/tree/86e78a054977819ad2b1294fd4f2561784cdf5d6/lib">my own code</a> - for better or worse.</p>
<p>I'll keep publishing here. I do love my little corner of the web. A mix of musings and code and goodness knows what. Thanks for reading and hanging out online with me for all these long days 💞</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/06/17/20-years-of-blogging">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Enhancing with CSS Grid Lanes [link]</title>
      <guid isPermaLink="false">2026-06-16-e496d97b</guid>
      <link>https://remysharp.com/links/2026-06-16-e496d97b</link>
      <pubDate>Tue, 16 Jun 2026 14:46:39 +0000</pubDate>
      <description><![CDATA[I've been catching CSS Grid Lanes in the socials this week, but somehow had it in my head that it was to do with the gaps (the lanes) between the grid.
It's not, it's masonry (which, why not display: masonry 🤷
There's a also a decent (albeit stiff) video on how it works.
TL;DR: mostly you can swap display: grid for display: grid-lanes (but Jeremy goes further to actually add the CSS support check first).
Source: adactio.com]]></description>
      <content:encoded><![CDATA[
<p>I've been catching CSS Grid Lanes in the socials this week, but somehow had it in my head that it was to do with the gaps (the lanes) between the grid.</p>
<p>It's not, it's masonry (which, why not <code>display: masonry</code> 🤷</p>
<p>There's a also a <a href="https://www.youtube.com/watch?v=NDwoB2PpwgY">decent (albeit stiff) video</a> on how it works.</p>
<p>TL;DR: mostly you can swap <code>display: grid</code> for <code>display: grid-lanes</code> (but Jeremy goes further to actually add the CSS support check first).</p>
<p><em>Source: <a href="https://adactio.com/journal/22613">adactio.com</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-06-16-e496d97b">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Social media to be banned for under-16s in landmark government move to give kids their childhood back - GOV.UK [link]</title>
      <guid isPermaLink="false">2026-06-15-e715aced</guid>
      <link>https://remysharp.com/links/2026-06-15-e715aced</link>
      <pubDate>Mon, 15 Jun 2026 09:08:31 +0000</pubDate>
      <description><![CDATA[The UK government has announced they're going ahead with a social media ban for 16 year old and under.
In our household we've already had this restriction in place (at a network/DNS level) so it doesn't impact our kids experiences at all, but I do know from talking to the kids that the do wish their friends had it too. I would add that I'm in no doubt that kids will find work arounds, but the larger effect of this, I think, is important.
A few quotes that interest me from the GOV.UK news post:

The ban will therefore include platforms like Snapchat, TikTok, YouTube, Instagram, Facebook and X. We do not intend for messaging services like WhatsApp and Signal to be included in the social media ban

I'm assuming that &quot;like&quot; refers to the user-to-user definition, and I'd expect or hope to see pretty clear definitions (though the government doesn't particularly have a track record on clear definitions).

The government will also be looking in more detail at overnight curfews and breaks in infinite scrolling for under-18-year-olds and will set out more detail in July.

In particular the breaks in infinite scrolling - though I've been personally arguing that it could be banned altogether - the only function it serves from a UX perspective is &quot;stickiness&quot; aka - addition.
I'm sceptical about the implementation rules and I'm particularly worried about how the government goes about setting the definitions of what products will need to do.
Source: www.gov.uk]]></description>
      <content:encoded><![CDATA[
<p>The UK government has announced they're going ahead with a social media ban for 16 year old and under.</p>
<p>In our household we've already had this restriction in place (at a network/DNS level) so it doesn't impact our kids experiences at all, but I do know from talking to the kids that the do wish their friends had it too. I would add that I'm in no doubt that kids will find work arounds, but the larger effect of this, I think, is important.</p>
<p>A few quotes that interest me from the <a href="http://GOV.UK">GOV.UK</a> news post:</p>
<blockquote>
<p>The ban will therefore include platforms like Snapchat, TikTok, YouTube, Instagram, Facebook and X. We do not intend for messaging services like WhatsApp and Signal to be included in the social media ban</p>
</blockquote>
<p>I'm assuming that <em>&quot;like&quot;</em> refers to the user-to-user definition, and I'd expect or hope to see pretty clear definitions (though the government doesn't particularly have a track record on clear definitions).</p>
<blockquote>
<p>The government will also be looking in more detail at overnight curfews and breaks in infinite scrolling for under-18-year-olds and will set out more detail in July.</p>
</blockquote>
<p>In particular the breaks in infinite scrolling - though I've been personally arguing that it could be banned altogether - the only function it serves from a UX perspective is &quot;stickiness&quot; aka - addition.</p>
<p>I'm sceptical about the implementation rules and I'm particularly worried about how the government goes about setting the definitions of what products will need to do.</p>
<p><em>Source: <a href="https://www.gov.uk/government/news/social-media-to-be-banned-for-under-16s-in-landmark-government-move-to-givekids-their-childhood-back">www.gov.uk</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-06-15-e715aced">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>AI designed pages and prompts [link]</title>
      <guid isPermaLink="false">2026-06-12-eb25c11f</guid>
      <link>https://remysharp.com/links/2026-06-12-eb25c11f</link>
      <pubDate>Fri, 12 Jun 2026 17:02:07 +0000</pubDate>
      <description><![CDATA[Based on the output of this article the author has styled their project with different AI prompts.
I think what I find interesting here is after the jQuery mobile themes and especially Bootstrap you come to just visually adapt the most common style.
What this author has done is asked for the design systems of existing software to be adopted into the code.
What frustrates me a little bit is that I actually like the &quot;Original&quot; style, which is what AI is pumping out at the moment, as what I see all the time, which just says that I'm not very original…
Source: envs.net]]></description>
      <content:encoded><![CDATA[
<p>Based on the output of <a href="https://envs.net/~volpe/blog/posts/reduce-slop.html">this article</a> the author has styled their project with different AI prompts.</p>
<p>I think what I find interesting here is after the jQuery mobile themes and especially Bootstrap you come to just visually adapt the most common style.</p>
<p>What this author has done is asked for the design systems of existing software to be adopted into the code.</p>
<p>What frustrates me a little bit is that I actually like the &quot;Original&quot; style, which is what AI is pumping out at the moment, as what I see all the time, which just says that I'm not very original…</p>
<p><em>Source: <a href="https://envs.net/~volpe/projects/ai-design.html">envs.net</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-06-12-eb25c11f">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>The “Nude” Ultimatum: Privacy Is Dead - The Unknown Universe [link]</title>
      <guid isPermaLink="false">2026-06-12-74cd263b</guid>
      <link>https://remysharp.com/links/2026-06-12-74cd263b</link>
      <pubDate>Fri, 12 Jun 2026 15:13:51 +0000</pubDate>
      <description><![CDATA[The UK government's ultimatum to Apple and Google is a blueprint for mass surveillance. A warning on why &quot;nothing to hide&quot; won't protect your digital freedom.
...
We're being steered toward a future where &quot;safety&quot; is just a euphemism for &quot;unrestricted access.&quot;

If I had read this a few years ago, I'd assume it was the plot for some dystopian novel, but no, it's reality today under (what was supposed to be) the progressive government - not even the Tories.
As per the author, I don't expect any of the Big Tech to do anything about it if it means it affects their share of the gold.
I guess I'll be looking around for alternatives soon enough too (and then for the kids, and the extended family). Yay.
Source: the.unknown-universe.co.uk]]></description>
      <content:encoded><![CDATA[
<blockquote>
<p>The UK government's ultimatum to Apple and Google is a blueprint for mass surveillance. A warning on why &quot;nothing to hide&quot; won't protect your digital freedom.</p>
<p>...</p>
<p>We're being steered toward a future where &quot;safety&quot; is just a euphemism for &quot;unrestricted access.&quot;</p>
</blockquote>
<p>If I had read this a few years ago, I'd assume it was the plot for some dystopian novel, but no, it's reality today under (what was supposed to be) the progressive government - not even the Tories.</p>
<p>As per the author, I don't expect any of the Big Tech to do anything about it if it means it affects their share of the gold.</p>
<p>I guess I'll be looking around for alternatives soon enough too (and then for the kids, and the extended family). Yay.</p>
<p><em>Source: <a href="https://the.unknown-universe.co.uk/privacy-security/the-ultimatum/">the.unknown-universe.co.uk</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-06-12-74cd263b">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>More molly guards [link]</title>
      <guid isPermaLink="false">2026-06-10-9c0e1c9b</guid>
      <link>https://remysharp.com/links/2026-06-10-9c0e1c9b</link>
      <pubDate>Wed, 10 Jun 2026 20:12:49 +0000</pubDate>
      <description><![CDATA[I love these little deep dives into bits of UX that we take for granted. Admittedly I think extending the idea of a Molly Guard to a &quot;Are you sure&quot; prompt is a bit of stretch, but it's a cute story either way.
This is the extension of a previous post, Molly Guard in reverse which introduces the molly guard with:

…the little plastic safety cover you have to move out of the way before you press some button of significance.
Anecdotally, this is named after Molly, an engineer’s daughter who was invited to a datacenter and promptly pressed a big red button, as one would.
Then she did it again later the same day.

Love it.
But what's more to love about this particular post, is that Marcin found the actual Molly with her dad!
Source: unsung.aresluna.org]]></description>
      <content:encoded><![CDATA[
<p>I love these little deep dives into bits of UX that we take for granted. Admittedly I think extending the idea of a Molly Guard to a &quot;Are you sure&quot; prompt is a bit of stretch, but it's a cute story either way.</p>
<p>This is the extension of a previous post, <a href="https://unsung.aresluna.org/molly-guard-in-reverse/">Molly Guard in reverse</a> which introduces the molly guard with:</p>
<blockquote>
<p>…the little plastic safety cover you have to move out of the way before you press some button of significance.</p>
<p>Anecdotally, this is named after Molly, an engineer’s daughter who was invited to a datacenter and promptly pressed a big red button, as one would.</p>
<p>Then she did it again later the same day.</p>
</blockquote>
<p>Love it.</p>
<p>But what's more to love about this particular post, is that Marcin found the <em>actual</em> Molly with her dad!</p>
<p><em>Source: <a href="https://unsung.aresluna.org/more-molly-guards/">unsung.aresluna.org</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-06-10-9c0e1c9b">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Landmark German ruling declares Google's AI Overviews are Google's own words and makes it liable for false answers [link]</title>
      <guid isPermaLink="false">2026-06-10-f4446f0b</guid>
      <link>https://remysharp.com/links/2026-06-10-f4446f0b</link>
      <pubDate>Wed, 10 Jun 2026 10:34:26 +0000</pubDate>
      <description><![CDATA[The &quot;AI overview&quot; is its own content, not just a list of search results.

This is really interesting and I would love to see this set the tone for other countries (::cough UK::).

If enough of that wrong content defames companies or individuals, it could become a serious legal problem not just for Google but for other providers of similar services like ChatGPT, Claude, or Perplexity.

Big Tech helped themselves to our content. The content bloggers put out on the web was always intended to be consumed freely, but it we didn't agree that you (Big Tech) could use it for massive profits without the least bit of credit (let alone royalties for the content being used).
The big AI companies have harvested and thrown the web into their models without moderation causing all kinds of real-world harm, so this looks to be a positive step to forcing them to take some real responsibility.
Source: the-decoder.com]]></description>
      <content:encoded><![CDATA[
<blockquote>
<p>The &quot;AI overview&quot; is its own content, not just a list of search results.</p>
</blockquote>
<p>This is really interesting and I would love to see this set the tone for other countries (::cough UK::).</p>
<blockquote>
<p>If enough of that wrong content defames companies or individuals, it could become a serious legal problem not just for Google but for other providers of similar services like ChatGPT, Claude, or Perplexity.</p>
</blockquote>
<p>Big Tech helped themselves to our content. The content bloggers put out on the web was always intended to be consumed freely, but it we didn't agree that you (Big Tech) could use it for massive profits without the least bit of credit (let alone royalties for the content being used).</p>
<p>The big AI companies have harvested and thrown the web into their models without moderation causing all kinds of real-world harm, so this looks to be a positive step to forcing them to take some real responsibility.</p>
<p><em>Source: <a href="https://the-decoder.com/landmark-german-ruling-declares-googles-ai-overviews-are-googles-own-words-and-makes-it-liable-for-false-answers/">the-decoder.com</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-06-10-f4446f0b">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>No, Artificial Intelligence Is Not Conscious - Ted Chiang [link]</title>
      <guid isPermaLink="false">2026-06-05-ee9041b8</guid>
      <link>https://remysharp.com/links/2026-06-05-ee9041b8</link>
      <pubDate>Fri, 05 Jun 2026 14:52:31 +0000</pubDate>
      <description><![CDATA[I didn't really need to read much past the title or subtitle, but it's still an excellent essay that does a good job of drawing comparisons to concepts we already understand, for example:

The term deepfake traditionally refers to photos, audio, and video, but when it comes to discussions of consciousness, we need to regard text as a deepfake medium as well.

This does remind me of the story of ELIZA and Joseph Weizenbaum, which people quickly attributed intelligence to the bot. With 6 months of ELIZA's debut (in 1966), he warned loudly and publicly about the perils of anthropomorphism. He continued this campaign until his death in 2008. Yet, here we are again.
Source: www.theatlantic.com]]></description>
      <content:encoded><![CDATA[
<p>I didn't really need to read much past the title or subtitle, but it's still an excellent essay that does a good job of drawing comparisons to concepts we already understand, for example:</p>
<blockquote>
<p>The term deepfake traditionally refers to photos, audio, and video, but when it comes to discussions of consciousness, we need to regard text as a deepfake medium as well.</p>
</blockquote>
<p>This does remind me of the story of ELIZA and Joseph Weizenbaum, which people quickly attributed intelligence to the bot. With 6 months of ELIZA's debut (in 1966), he warned loudly and publicly about the perils of anthropomorphism. He continued this campaign until his death in 2008. Yet, here we are again.</p>
<p><em>Source: <a href="https://www.theatlantic.com/philosophy/2026/06/no-artificial-intelligence-is-not-conscious/687378/?gift=R2zbWGNBDp_xHqoa7Q8ZRp-EV6jGaHiamQBxQQlMJqI">www.theatlantic.com</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-06-05-ee9041b8">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Are you standard.site? [link]</title>
      <guid isPermaLink="false">2026-06-05-a88bc26b</guid>
      <link>https://remysharp.com/links/2026-06-05-a88bc26b</link>
      <pubDate>Fri, 05 Jun 2026 14:45:23 +0000</pubDate>
      <description><![CDATA[Another (shorter) entry in how how devs are adding Standard.site to their web sites to enrich the social cards.I suspect we'll start to gravitat towards tools to help us to add these - which is what it looks like David is doing.Though I'm a little wary of how BIG the card image is on top of the extra UI that shows the dates, buttons and so on. Given how large I have my font these days, it could easily become a wall just a couple of these.
Source: dbushell.com]]></description>
      <content:encoded><![CDATA[
<p>Another (shorter) entry in how how devs are adding Standard.site to their web sites to enrich the social cards.I suspect we'll start to gravitat towards tools to help us to add these - which is what it looks like David is doing.Though I'm a little wary of how BIG the card image is on top of the extra UI that shows the dates, buttons and so on. Given how large I have my font these days, it could easily become a wall just a couple of these.</p>
<p><em>Source: <a href="https://dbushell.com/2026/06/05/are-you-standard-site/">dbushell.com</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-06-05-a88bc26b">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>How I foot-gunned our newsletter this week [blog]</title>
      <guid isPermaLink="false">how-i-foot-gunned-our-newsletter-this-week</guid>
      <link>https://remysharp.com/2026/06/05/how-i-foot-gunned-our-newsletter-this-week</link>
      <pubDate>Fri, 05 Jun 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[For the second year running, as part of our &quot;stay sane&quot; strategy for FFConf, Julie and I write and send a weekly newsletter. It's structured the same way so it means we have a much better line of sight as to what we have to say.
The open rate is usually around 40% (though I know some email systems synthetically do this), but our click rates are also usually pretty good.
This week however, open rate was 3% and click rate was just 8 clicks. Something was definitely…afoot.]]></description>
      <content:encoded><![CDATA[
<p>For the second year running, as part of our &quot;stay sane&quot; strategy for FFConf, Julie and I write and send a weekly newsletter. It's structured the same way so it means we have a much better line of sight as to what we have to say.</p>
<p>The open rate is usually around 40% (though I know some email systems synthetically do this), but our click rates are also usually pretty good.</p>
<p>This week however, open rate was 3% and click rate was just 8 clicks. Something was definitely…afoot.</p>
<h2>Spam scores</h2>
<p>I had a report from a friend of the event that last week's newsletter landed in their spam folder. From this, I decided to integrate <a href="https://spamassassin.apache.org/">spamassassin</a> to try to score the content (which it almost always comes back clean).</p>
<p>As belt and braces, I also paid for some credit for <a href="https://mail-tester.com/">Mail Tester</a> which gives me an email address that I can send to and it'll run all manner of tests, including stuff outside of the actual markup.</p>
<p>I had a score of 9.8/10 - so I dipped into what could be improved, and suggested &quot;check <abbr title="Domain-based Message Authentication">DMARC</abbr> policy state&quot;.</p>
<h2><abbr title="Domain-based Message Authentication">DMARC</abbr></h2>
<p>The page suggested:</p>
<figure><img src="https://remysharp.com/images/dmarc.avif" alt="A screenshot of the recommendation to add a DMARC record where p=reject" decoding="async"></figure>
<p>Not being that versed in email security set up, and like many of us, having to wear <em>many</em> hats, I just copied what I needed and trotted along adding this record.</p>
<p>What I didn't appreciate was that this change translates to:</p>
<blockquote>
<p>If the email didn't come from Left Logic, just <strong>reject</strong> it.</p>
</blockquote>
<p>The problem being is that the email <em>doesn't</em> come from Left Logic, it comes from AWS because I use SES for sending the newsletters. So even though our newsletter <a href="https://www.mailcoach.app/">product</a> said they were all sent. AWS also said they were all sent. Only a handful of people had the email.</p>
<p>The <em>only</em> reason I figured it out was because I hadn't received the email to my personal email.</p>
<p>The temporary fix was to add this to the <code>_dmarc.leftlogic.com</code> as a TXT:</p>
<pre><code>&quot;v=DMARC1; p=none; rua=mailto:dmarc@leftlogic.com&quot;
</code></pre>
<p>I do need to sort out proper <abbr title="Sender Policy Framework">SPF</abbr> records and <abbr title="DomainKeys Identified Mail">DKIM</abbr> and &quot;Easy <abbr title="Domain-based Message Authentication">DMARC</abbr>&quot; (whatever that is), but next time around I might be a little more careful with what I copy and paste…</p>
<p>(though, who am I kidding!)</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/06/05/how-i-foot-gunned-our-newsletter-this-week">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>The 30 year game [blog]</title>
      <guid isPermaLink="false">the-30-year-game</guid>
      <link>https://remysharp.com/2026/05/17/the-30-year-game</link>
      <pubDate>Sun, 17 May 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[Today I'm releasing my Game Boy game called Marbles² (or Marbles Squared). It's a port of a game that I originally wrote back in 2002, but is a game that started in my life in (or around) 1996.
The development this iteration of the game, the one in 2026, took me about a week and I haven't written a single line of code. Here's how things have changed.]]></description>
      <content:encoded><![CDATA[
<p>Today I'm releasing my Game Boy game called Marbles² (or Marbles Squared). It's a port of a game that I originally wrote back in 2002, but is a game that started in my life in (or around) 1996.</p>
<p>The development this iteration of the game, the one in 2026, took me about a week and I haven't written a single line of code. Here's how things have changed.</p>
<h2>TL;DR</h2>
<p>I get it, this is a stupidly long blog post. There's no real value buried inside of it, it's pretty much entirely a story of how technology has progressed over 30 years (not really a spoiler) and my journey to evolve a game that I found in 1996.</p>
<p>The latest edition of this game was coded entirely by Claude Code with one strict rule: keep inside of the 32K boundary limit. There was a huge saving that Claude never suggested (1bpp font tiles instead of 2bpp) which bought me 3K - which was enough to add a full tutorial in the game along with additional small features.</p>
<p>I also tried to vibe code another game using the same process only to fail - the key take away for me was that my experience and knowledge was still the guiding light. With the other game, it failed because my knowledge was shallow, so the output was shallow. Sort of obvious on paper, but a useful exercise for me.</p>
<p>Oh, and if you scroll to the end, there's a link to the game download page.</p>
<h2>1996</h2>
<p>At some point during my days during Sixth Form (college to some, basically aged 16-18), a close friend had (some) machine (that neither of us can remember) and they let me play a game on it.</p>
<figure><img src="https://remysharp.com/images/remy-6th-form-days.avif" alt="A picture of Remy and Julie when they were just babies, both looking dreamily into the camera" decoding="async"><figcaption>Remy &amp; Julie from their Sixth form days in the 90s</figcaption></figure>
<p>I remember really enjoying the game. It was technically a very simple puzzle game: a bunch of balls that you would tap the matching colour groups of balls and they would collapse down into the corner. The goal being to clear the screen.</p>
<p>I never caught the name of the game but my dad had a <a href="https://en.wikipedia.org/wiki/Psion_Series_3">Psion</a> and remembered that in the instruction manual (long gone are those times) it mentioned you could write your own software.</p>
<p>I'd been making little <a href="https://en.wikipedia.org/wiki/Visual_Basic_(classic)">Visual Basic</a> <a href="https://tweets.remysharp.com/1181605537571655681/">programs for friends</a> for a few years by then, so I decided that since I had access to the internet (of sorts) through bulletin boards I would try and build my version of game so I could play it all the time!</p>
<p>When I finally managed to download <em>and</em> printed out the <a href="https://archive.org/details/psion-sibo-c-sdk">documentation</a> (I remember it just kept printing and printing and printing), the very first is what hit the hardest.</p>
<p>SDK. This was foreshadowing. I had no idea what an <em>SDK</em> was. Nor any of the other mass of acronyms. And software development being gate-kept by the usual nerds meant there wasn't going to be any help with the &quot;basic stuff&quot;.</p>
<p>(In truth is might have been any kind of acronym, I just remember being bewildered).</p>
<p>Google doesn't exist yet so I tried thumbing through the documentation and spent probably weeks just going back and forth just looking for any clue that would help me get a footing so I'd have something to start with.</p>
<p>In the end, I got absolutely nowhere. I park the idea and put it down to lack of knowledge, and lack of experience. This was not for someone like me. This was for people who had the inside knowledge. Plus, at that age, I had plenty of other (better) distractions.</p>
<h2>2002</h2>
<p>In 1999 I started my work placement for a year as part of my Computer Information Systems Design sandwich course degree (a mouthful!). In the end, I'd never return to finish my degree and stayed on for a decade.</p>
<figure><img src="https://remysharp.com/images/remy-dl-days.avif" alt="Remy, just about, wearing god knows what: large Elvis sunglasses, fake elf ears, a set of flowers around his neck, a fake HEAD (of all things) and a nurses hairband - it's not pretty" decoding="async"><figcaption>Certainly a lot less dreamy that the 90s</figcaption></figure>
<p>But back to '99 and the start of the new century. The company was a web agency with the boss and two students (myself being one). Along with client work, the agency also had it's own side projects, one of which was <a href="https://web.archive.org/web/20011225185437/http://www.eurocool.com/palm/apps/latest/index.html">Eurocool</a> - a website dedicated to software for the Palm Pilot (they even made <a href="https://web.archive.org/web/20011212081559/http://news.bbc.co.uk/hi/english/events/the_launch_of_emu/the_uk_and_emu/newsid_222000/222808.stm">BBC news</a>).</p>
<p>So I eventually bought myself one and through Eurocool I started notice that some of the games and some of the utilities came with source code and the source code was not huge and by this point I had learnt a lot more programming.</p>
<p>By that time I had tinkered with some C, worked with Java. I was writing JavaScript (JScript and VBScript). I was writing Perl and I could start to understand the functions of the source code and I went about making my first utility for the Palm pilot for me.</p>
<p>I started with a couple of smaller bits of software for the Palm Pilot, before I realised I could (and should) make a game</p>
<p>As it turns out that I'm not a very good graphic designer, so when it came to drawing circles for the Palm Pilot it was…very, very bad. The best I could do was draw squares and colour them in. So this is where the name Marbles Squared comes from (<em>&quot;it's a feature, not a bug!&quot;</em>).</p>
<p>It took me until the mid 2020 so realise that the original game from the 90s was actually <a href="https://en.wikipedia.org/wiki/SameGame">SameGame</a> that I had unwittingly cloned (though only the game play mechanic, the Wiki page details the scoring system which I was never aware of).</p>
<p>One of the key mechanics of my version of the game was that the the random function would have a <a href="https://en.wikipedia.org/wiki/Random_seed">seed</a>, and that seed would make the grids being played repeatable and shareable.</p>
<p>My game even <a href="https://remysharp.com/2007/03/23/the-day-i-appeared-in-scientific-american">turned up in American Scientific</a> (though the original article has been long disappeared sadly). After a few years, the game had been downloaded over 1/4 million times.</p>
<p>More importantly though, the coding part took me (probably) 3 months to go from scratch to the first version of a workable game, mostly coding late into the night because I had a full-time job (running in start-up days of getting home at 8pm and later). I'd continue to iterate on it for a further 6 months and the <a href="https://ihatemusic.com/">last release was in 2003</a>. If you want to try the game on a (pretty faithful) web port of the Palm Pilot, I'm hosting the <a href="https://marbles2.com/palm/">Palm version on the Marbles</a> website.</p>
<h2>2008</h2>
<p>By the mid-late 2000s, I had move away from London and I joined the web scene down in Brighton. Coincidentally the iPhone had launched in 2007.</p>
<figure><img src="https://remysharp.com/images/remy-2008-cats.avif" alt="Remy awkwardly holding his three cats, one black and white, one tabby and one long haired" decoding="async"><figcaption>I remember using this as an excuse for not going out and meeting Brighton webbies</figcaption></figure>
<p>Eventually I caved and got myself an iPhone and Steve Jobs <a href="https://m.youtube.com/watch?v=p1nwLilQy64">original vision</a> was for developers to use the web and the power of the browser (sidebar: that wasn't really his vision, he just <a href="https://www.theguardian.com/technology/appsblog/2011/oct/24/steve-jobs-apps-iphone">didn't want 3rd party apps</a>).</p>
<p>So that's what I did. I took my knowledge of Marbles Squared and the only code that was directly ported was the random function so that I could continue supporting the seed mechanic.</p>
<p>I also add a timer bar across the bottom of the screen (to let me play with CSS transitions), but functional it did nothing, so watching friends play the game and panicking about the timer running out was a real delight!</p>
<p>Developing the core of the mobile version was a matter weeks (if that) because I was breathing JavaScript daily, and that I was so familiar with how the game would play.</p>
<p>As with all these projects, it really wasn't the core gameplay that took the time, it was the UX around the game. The damn button in particular with the &quot;new&quot; <code>border-image</code> (vendor prefixed to kingdom come!) probably proved to be the trickiest parts.</p>
<p>A it probably took me a few weeks to finish the <a href="https://marbles2.com/mobile">mobile version</a>.</p>
<h2>2020</h2>
<p>In 2020, the <a href="https://www.kickstarter.com/projects/spectrumnext/zx-spectrum-next">ZX Spectrum Next Kickstarter</a> project was delivered (after quite a few long years of waiting) and with the pandemic lockdown in full swing, it was time to tinker.</p>
<figure><img src="https://remysharp.com/images/remy-zxnext.avif" alt="Remy with his head resting awkwardly on a desk, with a spectrum, a modern keyboard, some kind of phone and various figurines from lego Batman characters to super mini Jokers" decoding="async"><figcaption>This was the vibe of tinkering on tech during lockdown!</figcaption></figure>
<p>The Next came with an upgraded (and much more capable) NextBASIC (plus the crystal boost to 28Mhz made a big difference). So I set about making myself a game.</p>
<p>I wrote a clone of <a href="https://remysharp.itch.io/go-mummy">Oh Mummy</a> that I used to play on the my friends' Commodore C64 but after that was done I turn my hand to recreating my Marbles game.</p>
<p>The challenge here was that even though the Next was faster than an original ZX Spectrum, NextBASIC still wasn't fast enough to do the grid traversing to workout available moves - or certainly not in a way that felt responsive.</p>
<p>So this meant turning my hand to Z80 assembly. I'd tinkered with the language but never had a real project to solve with it. This was perfect for dipping my toe into. Plus, there was 40+ years of experience on the web to learn from.</p>
<p>The bulk of the game would still be in NextBASIC but it would call out to a library that I wrote in assembly for <em>hard</em> tasks.</p>
<p>That project probably took me over 3 months because it was a brand new language. It was also much harder to debug. The development cycle is a lot longer compared to something like JavaScript.</p>
<p>But as I reach the end of that piece of work, I realised that I wanted to add a high score table.</p>
<p>The Spectrum Next (most times) included a Wi-Fi module, but it didn't have any native HTP protocol support so was another side quest.</p>
<p>I built an <a href="https://github.com/remy/next-http">HTTP client</a> in assembly for the spectrum and one of my more prouder moments that my <code>.http</code> is now part of the <a href="https://gitlab.com/thesmog358/tbblue/-/blob/master/docs/dotcommands/http.md">Spectrum Next distro</a>, part of the default library of tools.</p>
<p>This would let players see a <a href="https://marbles2.com/spectrum">global leaderboard</a> on the spectrum <em>and</em> share their own high scores directly from the retro hardware.</p>
<p>The http part was probably another three or more months, but absolutely worth it.</p>
<h2>2026</h2>
<p>In the intervening years AI has exploded as we're all well aware.</p>
<p>In the last few months I have taken to using LLMs to create small personal projects that serve a single purpose, a tool to calculate the distance between a and b, but also to add how long it would take me to walk or run and so on. Or maybe it would be a small song game that I would share with my friends.</p>
<p>About a month ago, I decided that I would take my experience of vibe coding and see if I could build the Game Boy game that I've been wanting the Game Boy version of Marles Squared (ironically I discovered, literally today, that Samegame was available on the Game Boy in 1997 - though it's very different from the game I wanted to enjoy).</p>
<figure><img src="https://remysharp.com/images/remy-2026-gameboy.avif" alt="Remy standing in front of his arcade build with his Marbles Game Boy game running" decoding="async"><figcaption>30 years later, Remy's able to play the game he wanted from 1996</figcaption></figure>
<p>I was able to describe in detail exactly what I wanted and I was able to iterate over and over <em>and over</em> to get all the details kind of fine-tuned. It certainly wasn't just a <em>one shot</em> build me a Game Boy game.</p>
<p>As with all the previous iterations, the real work was in the UI.</p>
<p>I did however, set myself the constraint that the game <strong>had to</strong> fit into a 32K rom (this means it works on a cart that doesn't have an MBC - memory bank controller - chip - which is what allowed games to grow up to 8MB large).</p>
<p>The LLM (Claude Code in my case) was also vital to really quickly turning around tooling that helped me in the development process. Tools to slice my <a href="https://tools.remysharp.com/gb-tile-converter/">graphics into tiles</a> or to <a href="https://tools.remysharp.com/gb-tile-visualizer/">visualise tile data</a> inline to code, or to <a href="https://tools.remysharp.com/gb-font-extractor/">convert fonts</a> (for variable width fonts which I didn't use in the end due to byte size limits).</p>
<p>I was also able to take an existing rust implementation of a Game Boy emulator and layered on an MCP server so that that Claude Code could test, screenshot and probe the memory of the game to see if it was doing what I needed to do.</p>
<p>But the whole process was me just talking back and forth to Claude code in particular to get this game built and the vast majority of it took about a week.</p>
<p>After a couple of rounds of testing, I did notice that the couple of people who tried the game didn't <em>quite</em> know what the goal was. A &quot;how to play&quot; section was needed in the game, but given the constraints of 32K, lumping in a load of text copy wasn't going to work.</p>
<p>One of the biggest wins I had in optimising the codebase was <em>not</em> from Claude. I could see all the text tiles (the tiles that make up the font) were two colours. Whereas a Game Boy tile stores 4 bits of colour in a &quot;pixel&quot;, I could see I was wasting a lot of space. GBDK even includes a native function <code>set_bkg_1bpp_data</code> that will make use of 1bpp tile data. From this single change (I had to update my tools to generate 1bpp) I was able to unlock over 3K. This space was then used for the tutorial and a number of other small changes (including increasing the pool of &quot;easy game seeds&quot;).</p>
<hr>
<p>So in the 30 years that's passed I've gone from taking weeks and weeks looking at documentation and getting nowhere to taking a week to build a fully working piece of software that suits all of my requirements.</p>
<p>But the reality isn't as straightforward to say you can just magic up anything you want. My advantage I have is that I've got decades worth of experience in software development. I also have an intimate understanding as to how this game is supposed to work.</p>
<p>As an experiment I tried to vibe code another game. Our family was playing <a href="https://100jumps.org">100 Jumps</a> and I thought it'd be a good candidate for a Game Boy game.</p>
<p>The source code is online, and on the surface it seemed pretty straightforward to me to re-use the techniques that I was using to develop Marble Squared.</p>
<p>Except what happened is I kept iterating on something that was awful. The physics were wrong. The movement was wrong. The graphics were bad. No matter how many times I tried to iterate and even reset, it just didn't come out feeling like a decent experience.</p>
<p>I've come to realise that the reason for this, is because of where my experience lies, and in particular my intimate understanding of how my <em>own</em> game works. This knowledge allowed me to carefully plan out the development, to know where all the pitfalls were ahead of time, which I simply didn't have for 100 Jumps.</p>
<p>I think we're starting to see in the tech industry that the pitch that AI is here to replace our jobs isn't entirely true. In fact, a lot of us have known for decades that the real skill isn't in producing code, but actually understanding functionality and translating it to the real world.</p>
<hr>
<p>If you made it this far, thank you for reading. If you simply skipped from the top to find the download link, I appreciate you too 😄</p>
<p>You can download the game over on itch, and if you fancy your chances, you can submit your high score via the <a href="https://marbles2.com/gameboy">Marbles website</a>.</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/05/17/the-30-year-game">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>When the Cranes Fly South [book]</title>
      <guid isPermaLink="false">when-the-cranes-fly-south</guid>
      <link>https://remysharp.com/books/2026/when-the-cranes-fly-south</link>
      <pubDate>Fri, 15 May 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[Took me a minute to get into, but then…I cried. The good kind.
It took me until around 20% of the book to get on with it properly. I was struggling to even want to pick up the book. It's well written, but the subject, end of life, was so unappealing that I found myself wanting to avoid reading the book.
At some point around 1/5 of the way in, this feeling settled and I was swept along by the narrative that the main character, Bo, gives us.
I think reading this there's going to be different aspects that hit different people hardest. I'm not a dog person, so the thread about Sixten, his dog, though sad (the dog doesn't die!) it didn't gut punch me.
I did however relate hard to the inner monologue not linking up to what's actually said. Something I suspect most people can relate to - which I suspect is the reason this book is well recommended.
The book is told almost exclusively from the thoughts of Bo, the elderly 89 year old man (which took me quite a few pages to actually work out). From his thoughts we travel back and forth in his memory which worked really well. I didn't feel lost at all, maybe because Bo's memories felt like they flowed naturally back and forth.
The story really does feel like it's being faithful to the human flaws many of us share.
It also, for me, did an excellent job of building up my relationship with Bo and gently brought me to tears right at the end in a way that made me message my kids to tell them I love them.]]></description>
      <content:encoded><![CDATA[<p>Took me a minute to get into, but then…I cried. The good kind.</p>
<p>It took me until around 20% of the book to get on with it properly. I was struggling to even want to pick up the book. It's well written, but the subject, <em>end of life</em>, was so unappealing that I found myself wanting to avoid reading the book.</p>
<p>At some point around 1/5 of the way in, this feeling settled and I was swept along by the narrative that the main character, Bo, gives us.</p>
<p>I think reading this there's going to be different aspects that hit different people hardest. I'm not a dog person, so the thread about Sixten, his dog, though sad (the dog doesn't die!) it didn't gut punch me.</p>
<p>I did however relate hard to the inner monologue not linking up to what's actually said. Something I suspect most people can relate to - which I suspect is the reason this book is well recommended.</p>
<p>The book is told almost exclusively from the thoughts of Bo, the elderly 89 year old man (which took me quite a few pages to actually work out). From his thoughts we travel back and forth in his memory which worked really well. I didn't feel lost at all, maybe because Bo's memories felt like they flowed naturally back and forth.</p>
<p>The story really does feel like it's being faithful to the human flaws many of us share.</p>
<p>It also, for me, did an excellent job of building up my relationship with Bo and gently brought me to tears right at the end in a way that made me message my kids to tell them I love them.</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2026/when-the-cranes-fly-south">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>NES Programming in 6502 Assembly [link]</title>
      <guid isPermaLink="false">2026-05-13-7746ef1b</guid>
      <link>https://remysharp.com/links/2026-05-13-7746ef1b</link>
      <pubDate>Wed, 13 May 2026 09:44:25 +0000</pubDate>
      <description><![CDATA[Source: pikuma.com]]></description>
      <content:encoded><![CDATA[
<p><em>Source: <a href="https://pikuma.com/courses/nes-game-programming-tutorial">pikuma.com</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-05-13-7746ef1b">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>A popover backdrop anti-pattern [blog]</title>
      <guid isPermaLink="false">popover-backdrop-anti-pattern</guid>
      <link>https://remysharp.com/2026/05/08/popover-backdrop-anti-pattern</link>
      <pubDate>Fri, 08 May 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[After attending recent conferences and learning that I can swap out buckets of JavaScript for the HTML native popover property, I've been using it liberally throughout my own projects.
For little pop out menus it's perfect. Then I also started using it for modal boxes (yes, you might be thinking ahead of me: dialog, still, let's find out what happened).
The popover property was really easy for this, and the ::backdrop selector was perfect for adding a little backdrop blur to tell my user &quot;this is the thing you're dealing with&quot;.
I especially love that all the UX around dismissing is handled for me. I can hit the escape key, or click outside the popover and it's dismissed.
Except, I kept noticing that when I dismissed my popover it would sometimes vanish then immediately pop back to life…]]></description>
      <content:encoded><![CDATA[
<p>After attending recent conferences and learning that I can swap out buckets of JavaScript for the HTML native <code>popover</code> property, I've been using it liberally throughout my own projects.</p>
<p>For little pop out menus it's perfect. Then I also started using it for modal boxes (yes, you might be thinking ahead of me: <code>dialog</code>, still, let's find out what happened).</p>
<p>The popover property was really easy for this, and the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/::backdrop"><code>::backdrop</code></a> selector was perfect for adding a little backdrop blur to tell my user &quot;this is the thing you're dealing with&quot;.</p>
<p>I especially love that all the UX around dismissing is handled for me. I can hit the escape key, or click outside the popover and it's dismissed.</p>
<p>Except, I kept noticing that when I dismissed my popover it would sometimes vanish then immediately pop back to life…</p>
<h2>On using the wrong tool</h2>
<p>It was through a chat with <a href="https://www.bram.us/">Bramus</a> during a <a href="https://beyondtellerrand.com/">BTConf</a> lunch that it was pointed out that I should be using a <code>dialog</code> for a modal.</p>
<p>I think the reason I didn't think of this earlier is down to the age old problem of naming. I have a mental model that a modal is a different thing from a dialog box. Specifically a dialog lets me set it aside whilst I carry on with what I'm doing.</p>
<p>For example, in many native desktop apps, a preference dialog can be opened, but I can still interact with the software.</p>
<p>Whereas a modal is &quot;you need to do this and we'll lock out the app until you do&quot;. Although dismissing the modal is also valid as an action.</p>
<p>Anyway, that was my thinking as to why I hadn't used a dialog for modal actions.</p>
<p>I also didn't know I could use the <code>::backdrop</code> selector with <code>dialog</code> - mostly because I'd heard of it in the context of the popover.</p>
<h2>So what's the anti-pattern?</h2>
<p>A popover doesn't trap focus (which is the whole point of a <code>dialog</code>). But I wasn't looking at keyboard focus, I was looking at mouse focus.</p>
<p>When I used the popover for a modal (looking) element, and used a blur on the <code>backdrop</code> selector, I didn't realise that clicking on the backdrop would let the click carry through to whatever was underneath it.</p>
<p>So visually the UX is saying the modal is the thing that you need to do, and clicking anywhere else will dismiss it. Technically, I could have a solid colour hiding everything under the modal and you'd have no idea what you were clicking through to.</p>
<p>Let's look at the two buttons below. The &quot;click jack&quot; one will show an alert box. If you click the &quot;modal&quot; button, you'll get my modal, and under the solid backdrop, I'm going to position the &quot;click jack&quot; button across the entire screen, so when you click away to dismiss the modal, you should get the alert.</p>
<div id="demo-popover" popover class="popover-demo">
  <p>This is my modal. I don't have a button to dismiss this, but you can click anywhere on the page to dismiss it, and … see what happens.</p>
</div>
<button type="button" class="button inline" onclick="alert('click jack button got clicked')" id="demo-clickjack">click jack</button>
<button type="button" class="button inline" popovertarget="demo-popover">modal</button>
<style>
#demo-popover::backdrop {
  /* note that I've used this semi-opaque color due to a bug in Firefox
     https://bugzilla.mozilla.org/show_bug.cgi?id=2038260
  */
  background-color: rgba(255, 19, 240, 0.99);
}

#demo-popover:popover-open + #demo-clickjack {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  cursor: auto;
}
</style>
<p>Besides the JavaScript click handler for the click jack alert, this is all done with CSS:</p>
<pre><code class="language-css"><span class="token comment">/* put a solid colour over the page */</span>
<span class="token selector">#demo-popover::backdrop</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> hotpink<span class="token punctuation">;</span>
  <span class="token comment">/*
    note there's a bug that I've filed in FF that
    doesn't like solid backgrounds.
    https://bugzilla.mozilla.org/2038260
  */</span>
<span class="token punctuation">}</span>

<span class="token comment">/* expand the "bad" button under the page */</span>
<span class="token selector">#demo-popover:popover-open + #demo-clickjack</span> <span class="token punctuation">{</span>
  <span class="token property">position</span><span class="token punctuation">:</span> fixed<span class="token punctuation">;</span>
  <span class="token property">top</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
  <span class="token property">left</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
  <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
  <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>This isn't really a demo of click jacking (I've not fully thought though whether it's a real world issue or not), but it shows how I had managed to click to dismiss my modal and then accidentally hit a &quot;live&quot; target in my blurred background.</p>
<h2>Now with a dialog</h2>
<dialog id="demo-dialog" class="popover-demo" closedby="any">
  <p>This is my modal. I don't have a button to dismiss this, but you can click anywhere on the page to dismiss it, and … see what happens.</p>
</dialog>
<button type="button" class="button inline" onclick="alert('click jack button got clicked')" id="demo-modal-clickjack">click jack</button>
<button type="button" class="button inline" command="show-modal" commandfor="demo-dialog">modal</button>
<p>In this example, when the <code>::backdrop</code> is active, it does still have a giant &quot;click jack&quot; button under it (you'll need to inspect the DOM to validate this), but the backdrop <em>also</em> traps the clicks and it doesn't go through.</p>
<p>That said, you can swap this same code to use <code>popovertarget</code> and the same problem occurs (because it's not modal, and won't trap the click).</p>
<p><em>Side note: oddly, if you happen to click on the button that opened the popover, it doesn't re-open the popover. You can see this in the <a href="https://developer.mozilla.org/en-US/play?uuid=e989dbaddcdee714679e010fe188787cc8126a7b&amp;state=hVBBCgIxDPxKyFndu9S9%2BAAvHnup29BWum3ZZhUR%2F26gK7ggeMokzEwmeaLnMeIe1WVmzglKLvlGE5vJER80jo%2BtDSZmp7E%2FFUrQOtU1fq%2BTTqrNINi14GMmJABV%2BrMPddHD3VTI4kcW5hqSA7NebQYOEscwT0FW0U51pfn8D%2FrLSRg%2BWJIrjjFX%2BsqvuqYTiBscapVvCLgulT2NJDAG5xlfbw%3D%3D&amp;srcPrefix=%2Fen-US%2Fdocs%2FWeb%2FHTML%2FReference%2FElements%2Fdialog%2F">MDN demo of dialog with popover</a></em>.</p>
<style>
#demo-dialog::backdrop {
  background-color: rgba(255, 19, 240, 0.99);
}

#demo-dialog[open] + #demo-modal-clickjack {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  cursor: auto;
}
</style>
<h2>I think ::backdrop might be the problem</h2>
<p>For me to fall so quickly into this pattern of using a <code>popover</code> with the <code>::backdrop</code>, and not realise I was taking the wrong approach <em>feels</em> like it might be something others will fall into quickly too - especially if you work in an environment where generated code isn't scrutinised.</p>
<p>I could even see developers trying to use <code>pointer-events</code> to prevent clicking through the <code>::backdrop</code> whilst using <code>popover</code> which would really be committing to the wrong approach.</p>
<p>Another question is: what is the <code>::backdrop</code> pseudo element for, if not obscuring the background? Therefore, if the background is obscured, then surely we're looking at a modal element (because the background is now visually out of focus)?</p>
<p>Which all leads me to wonder if <code>popover</code> should even have support for <code>::backdrop</code>.</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/05/08/popover-backdrop-anti-pattern">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>devtools: how to query through the shadow DOM [blog]</title>
      <guid isPermaLink="false">devtools-how-to-query-through-the-shadow-dom</guid>
      <link>https://remysharp.com/2026/05/01/devtools-how-to-query-through-the-shadow-dom</link>
      <pubDate>Fri, 01 May 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[This is a literal TIL but was so handy I had to put it my blog so that I wouldn't forget it later.
Thanks to Big Brain Keith Cirkel for sharing this.
As (hopefully) you know, there's the $ and $$ functions in devtools. For querySelector and querySelectorAll respectively.
Well there's also $$$ to query through the shadow DOM. This means the query will cut through and into the nested DOM inside of the shadow DOM making it much easier to navigate and search for elements when debugging or styling.
It's worth also adding that, just like $ and $$, this third function also takes a second argument for context, so it means this is valid (where $0 is the currently selected DOM node in the devtools inspector):
$$$('ha-card', $0)

Begs the question: what's going to be lurking inside of $$$$ in 5 years time!]]></description>
      <content:encoded><![CDATA[
<p>This is a literal <abbr title="Today I learnt">TIL</abbr> but was so handy I had to put it my blog so that I wouldn't forget it later.</p>
<p><a href="https://bsky.app/profile/keithamus.social/post/3mkqqbxnnys27">Thanks to</a> Big Brain Keith Cirkel for sharing this.</p>
<p>As (hopefully) you know, there's the <code>$</code> and <code>$$</code> functions in devtools. For <code>querySelector</code> and <code>querySelectorAll</code> respectively.</p>
<p>Well there's <em>also</em> <code>$$$</code> to query <em>through</em> the shadow DOM. This means the query will cut through and into the nested DOM inside of the shadow DOM making it <em>much</em> easier to navigate and search for elements when debugging or styling.</p>
<p>It's worth also adding that, just like <code>$</code> and <code>$$</code>, this third function <em>also</em> takes a second argument for context, so it means this is valid (where <code>$0</code> is the currently selected DOM node in the devtools inspector):</p>
<pre><code>$$$('ha-card', $0)
</code></pre>
<p>Begs the question: what's going to be lurking inside of <code>$$$$</code> in 5 years time!</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/05/01/devtools-how-to-query-through-the-shadow-dom">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Apps I use, that you might not know [blog]</title>
      <guid isPermaLink="false">apps-i-use-that-you-might-not-know</guid>
      <link>https://remysharp.com/2026/04/27/apps-i-use-that-you-might-not-know</link>
      <pubDate>Mon, 27 Apr 2026 09:00:00 +0000</pubDate>
      <description><![CDATA[This is a cheap post to share some of the apps (macos, sorry Windows users) that I use on a fairly regular basis and think some of you might not have heard of before (whilst still being useful).]]></description>
      <content:encoded><![CDATA[<p>This is a cheap post to share some of the apps (macos, sorry Windows users) that I use on a fairly regular basis <em>and</em> think some of you might not have heard of before (whilst still being useful).</p>
<h2>Aliento</h2>
<p>For some reason macos, for quite a number of versions has made it really hard to dismiss notifications (heaven forbid you repeatedly flash a raspberry pi pico). The hot target is horrible and there's many notifications that don't bundle together (the unmounted drive springs to mind).</p>
<p>Aliento give me a single key binding that swiped all notifications away. A daily use for me.</p>
<p><a href="https://inchman.gumroad.com/l/Aliento">Aliento</a></p>
<h2>Muzzle</h2>
<p>Speaking of notifications, if you've ever given or seen a talk or video call when a distracting notification appears then this the app to solve it.</p>
<p>It's a toggle that <em>muzzles</em> your notifications. Once turned off, they'll all pile in - and you can review or use Aliento.</p>
<p><a href="https://muzzleapp.com/help/">Muzzle</a></p>
<h2>Shottr</h2>
<p>I'm sure most of us have our goto screenshot tool. I've been using Shottr for quite a few years now. The base functionality is good, but what it adds is a quick way to draw, point, annotate and even OCR screenshots.</p>
<p>One extra little feature I like is that I can then drag the screenshot to where I want to share and then the file is never saved (my screenshot folder is 'uuuge already!).</p>
<p><a href="https://shottr.cc/">Shottr</a></p>
<h2>VoiceInk</h2>
<p>As big as my phone is, I find myself dictating more and more (somewhere last year the voice recognition had a massive step change improvement).</p>
<p>Lately I'd been looking for a suitable voice to text on my desktop and laptop but ideally with the processing done on machine (rather than needing to wait for the roundtrip to some random server).</p>
<p>I use VoiceInk multiple times a day. Both for push-to-talk and for much longer sentences.</p>
<p>There's options to download different models, but I've found the Apple native STT to be suitable and usually the quickest (even though one machine is on Somona and the other is running Tahoe).</p>
<p><a href="https://github.com/Beingpax/VoiceInk">VoiceInk</a></p>
<h2>KeyboardCleanTool</h2>
<p>It helps you do the thing it says. Though it doesn't clean your keyboard, it does trap all key presses so you're not randomly posting emails containing keyboard mashing.</p>
<p><a href="https://folivora.ai/keyboardcleantool">KeyboardCleanTool</a></p>
<h2>Karabiner-Elements</h2>
<p>This one has been installed on my machine(s) for years. It's one of those apps that sit in the background, do the work, and make things just a little bit more to your liking.</p>
<p>Primarily it's a key binding app. In my case, I wanted to swap my ctrl and alt keys, but only when using a specific keyboard. This does the job.</p>
<p>It also allows me to add much more complicated bindings (which historically have been tricky, but LLMs are pretty good at generating these if you need them too).</p>
<p><a href="https://karabiner-elements.pqrs.org/">Karabiner-Elements</a></p>
<h2>Better mouse</h2>
<p>I've got a Logi MX (something) mouse. It's very fancy, and has more buttons than camo trousers have pockets.</p>
<p>Earlier this year, Logitech pushed a server change that somehow (I really don't understand how or why) borked the Logi mice/mouses(?!).</p>
<p>With that I immediately sourced an alternative that didn't bind my physical device to a cloud server 🤦</p>
<p>BetterMouse is that for me. Tonnes of configuration, specifically I can bind the buttons to perform custom tasks depending on the focused application.</p>
<p>What also stood out for me, the UI for finding the right button (that I wanted to bind) was much easier than the existing Logitech software.</p>
<p><a href="https://better-mouse.com/">BetterMouse</a></p>
<h2>Sim Daltonism</h2>
<p>I can't remember quite when I first installed this app, but it's got to be at least a decade.</p>
<p>It's a window that sits above all else, and let's me quickly cycle through different types of colour blindness.</p>
<p>I know that some of the browser dev tools included this, but I found a standalone app the simplest (since it can also see beyond the browser, such as mock ups in Photoshop or Sketch and the likes).</p>
<p>It's an app they I always reach for once the colour system is in place for the website I'm working on.</p>
<p><a href="https://michelf.ca/projects/sim-daltonism/">Sim Daltonism</a></p>
<h2>Tahoe Electron Detector</h2>
<p>Let me say this first: do not, if possible, upgrade to Tahoe. It's a total mess.</p>
<p>Still, if you unwittingly upgraded like I did, you might find that software becomes somewhat sluggish. For me I noticed hover effects in Firefox was firing log after I had left that target.</p>
<p>The issue is related (from what I understand) to some private libraries being used by Electron apps. A full reboot would resolve the issue until it raised its ugly head again.</p>
<p>So Tahoe Electron Detector checks your installed apps, and tells you which haven't been upgraded away from this particular bug.</p>
<p>Once I know what the list looked like it was easy for me to stop using those apps (Dropbox and Discord at the time, and I could use the web alternatives), and the sluggish problem went away.</p>
<p><a href="https://furbo.org/2025/10/06/tahoe-electron-detector/">Tahoe Electron Detector</a></p>
<h2>Bartender</h2>
<p>This is probably one of the most popular apps I'm listing, so I suspect many of you have already heard of it. Hopefully it helps a few of you though.</p>
<p>Bartender let's me pick and choose which menubar icons are visible, and which are tucked away. There's also a rule system that lets you show particular menubar icons depending on conditions (such as battery level or WiFi connection).</p>
<p>There are a few issues that I have with the latest edition (but are primarily due to macos rather than Bartender itself): there's a couple of system menubar icons you can't hide (like the notification centre), and I've found that some menubar apps don't open and <em>stay</em> open when Bartender is running (NordVPN being one of those apps).</p>
<p><a href="https://www.macbartender.com/">Bartender</a></p>
<hr>
<p>There's many other apps I use, but they're much more common place. There's also apps that are very cool (notist) that I just can't make into a habit.</p>
<p>On that note, I'd love to read your favourites that might be hidden gems.</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/04/27/apps-i-use-that-you-might-not-know">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Lost Lambs [book]</title>
      <guid isPermaLink="false">lost-lambs</guid>
      <link>https://remysharp.com/books/2026/lost-lambs</link>
      <pubDate>Sun, 26 Apr 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[Enjoyable, well drawn characters, a pleasure to read.
I really enjoyed reading this book. The story floats like a butterfly from one character to the next and it works without losing the reader.
The story, I think, follows the Flynn family and though they're painted as somewhat dysfunctional, they're all spirited in their own journey.
There's a line towards the end that reflects on the mother's character not having given up on her art career, but having chosen to be a mother. The book definitely left me with this sense: that we're okay.
There is a strong religious thread in the book (not being religious myself) but it wasn't an agenda being pushed, but rather something for some of the characters to hang on to.
Easily enjoyable. I loved the characters and would definitely recommend.]]></description>
      <content:encoded><![CDATA[<p>Enjoyable, well drawn characters, a pleasure to read.</p>
<p>I really enjoyed reading this book. The story floats like a butterfly from one character to the next and it works without losing the reader.</p>
<p>The story, I think, follows the Flynn family and though they're painted as somewhat dysfunctional, they're all spirited in their own journey.</p>
<p>There's a line towards the end that reflects on the mother's character not having <em>given up</em> on her art career, but having chosen to be a mother. The book definitely left me with this sense: that we're okay.</p>
<p>There is a strong religious thread in the book (not being religious myself) but it wasn't an agenda being pushed, but rather something for some of the characters to hang on to.</p>
<p>Easily enjoyable. I loved the characters and would definitely recommend.</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2026/lost-lambs">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Another England: How to Reclaim Our National Story [book]</title>
      <guid isPermaLink="false">another-england-how-to-reclaim-our-national-story</guid>
      <link>https://remysharp.com/books/2026/another-england-how-to-reclaim-our-national-story</link>
      <pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[&quot;Our diverse literary heritage reveals that we do not need a single national story&quot;
I bought and read this book after seeing Caroline Lucas speaking with Zack Polanski during a live session of Bold Politics. It's a book that tries to reclaim &quot;Englishness&quot; from the weaponising that the Far Right have been using it for.
Overall, it's an interesting read, lots of history, both good and bad, lots of literature and how stories and poetry has been used over the centuries to act as a force for political change for good.
Solidarity and standing up for what's right is the theme the ran through for me.
From a technical perspective, I didn't enjoy that nearly every single page also came with a long paragraph of footnotes - which normally I skip (because it goes off to the end of the book and back, but these were inline on the same page), and completely broke the flow of what I was reading. I wish that these had simply been part of the written content rather than regular sidebars.
Then as I read, I felt like perhaps I wasn't quite the audience to fully appreciate the book. There's certainly a good chunk that is accessible, but it often felt like if I worked in politics this content would make more sense.

I did come away with 23 highlights and wanted to highlight more, partly to remember what I had read, partly as a &quot;wow, I did not know&quot;.
I think if you enjoy your history and commentary and literature, then you'll enjoy this book. I struggle to read non-fiction in any reasonable amount of time, so I often find by the time I get to the end of a book, I forget the important things from the start!]]></description>
      <content:encoded><![CDATA[<p>&quot;Our diverse literary heritage reveals that we do not <em>need</em> a single national story&quot;</p>
<p>I bought and read this book after seeing Caroline Lucas speaking with Zack Polanski during a live session of Bold Politics. It's a book that tries to reclaim &quot;Englishness&quot; from the weaponising that the Far Right have been using it for.</p>
<p>Overall, it's an interesting read, lots of history, both good and bad, lots of literature and how stories and poetry has been used over the centuries to act as a force for political change for good.</p>
<p>Solidarity and standing up for what's right is the theme the ran through for me.</p>
<p>From a technical perspective, I didn't enjoy that nearly every single page also came with a long paragraph of footnotes - which normally I skip (because it goes off to the end of the book and back, but these were inline on the same page), and completely broke the flow of what I was reading. I wish that these had simply been part of the written content rather than regular sidebars.</p>
<p>Then as I read, I felt like perhaps I wasn't quite the audience to fully appreciate the book. There's certainly a good chunk that is accessible, but it often felt like if I worked in politics this content would make more sense.</p>
<hr>
<p>I did come away with 23 highlights and wanted to highlight more, partly to remember what I had read, partly as a &quot;wow, I did not know&quot;.</p>
<p>I think if you enjoy your history and commentary <em>and</em> literature, then you'll enjoy this book. I struggle to read non-fiction in any reasonable amount of time, so I often find by the time I get to the end of a book, I forget the important things from the start!</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2026/another-england-how-to-reclaim-our-national-story">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Fixing my slow Mac network speeds [blog]</title>
      <guid isPermaLink="false">fixing-my-slow-mac-network-speeds</guid>
      <link>https://remysharp.com/2026/03/26/fixing-my-slow-mac-network-speeds</link>
      <pubDate>Thu, 26 Mar 2026 09:00:00 +0000</pubDate>
      <description><![CDATA[For a while now both my desktop Mac (running Sonoma) and my laptop (running Tahoe - do not recommend) have had sub-optimal network speeds.
My Android phone, on our network, on the same SSID, speed tests at 1.1Gbps. My laptop gets around 160Mbps and my desktop pulls in around 80Mbps.
That's quite a difference, and even though I don't need the gigabit speeds - sometimes I can tell when the desktop is being slow (web site be getting big).
What was weird is that the network speeds get much faster if I add something like NordVPN to my connection…which doesn't make sense…]]></description>
      <content:encoded><![CDATA[
<p>For a while now both my desktop Mac (running Sonoma) and my laptop (running Tahoe - do not recommend) have had sub-optimal network speeds.</p>
<p>My Android phone, on our network, on the same SSID, speed tests at 1.1Gbps. My laptop gets around 160Mbps and my desktop pulls in around 80Mbps.</p>
<p>That's quite a difference, and even though I don't <em>need</em> the gigabit speeds - sometimes I can tell when the desktop is being slow (web site be getting big).</p>
<p>What was weird is that the network speeds get much faster if I add something like NordVPN to my connection…which doesn't make sense…</p>
<h2>TL;DR - AWDL</h2>
<p>It's a &quot;magic&quot; non standard enhancement (Apple Wireless Direct Link) to WiFi that Apple use that can seriously hamper your network connectivity. It's hard to kill, so the &quot;simpler&quot; approach is to ensure the Wifi channels you use are 44 (for 5Ghz in Europe, or 36 outside).</p>
<h2>Slightly longer</h2>
<p>My router, for it's 5Ghz channel, uses 160Mhz using (something called) DFS (apparently nothing to do with sofas…sorry, British joke): Dynamic Frequency Selection.</p>
<p>This seems to throw Apple a curve ball when it comes to their AWDL (honestly, screw Apple for having more tech that we can't control and ends up getting in the way).</p>
<p>AWDL is part of the system that's (from what I understood) responsible for things like AirDrop (which I don't use). Of course, turning it off doesn't really work - it's an easter process: it keeps respawning. It sort of stayed disabled on my laptop running Tahoe, but on my desktop running Somona it wouldn't stay down regardless of what I did.</p>
<p>Even though this problem is exclusively an Apple problem, the only way I could resurrect my network connectivity (and even though I caught it at 60Mbps, I'd seen it much, much slower) was by switching the 5Ghz to 80Mhz (all the hertz) and selecting 44 as my channel.</p>
<p>Night and day difference:</p>
<figure><img src="https://remysharp.com/images/speed-test.avif" alt="On the left, with AWDL, 60Mbps, on the right, without and getting around 1.2Gbps" decoding="async"></figure>
<p>Ultimately my plan is to set the Wifi booster/mesh/thingy to have a Mac specific 5Ghz connection point, which is then hard wired through our house into the router, then I can have 5Ghz at 160Mhz band (so nice for all other devices, like our TV) and - hopefully - the pesky Apple devices can pull data at a decent speed too.</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/03/26/fixing-my-slow-mac-network-speeds">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Web of State of the Browser Day Out [blog]</title>
      <guid isPermaLink="false">web-of-state-of-the-browser-day-out</guid>
      <link>https://remysharp.com/2026/03/18/web-of-state-of-the-browser-day-out</link>
      <pubDate>Wed, 18 Mar 2026 09:00:00 +0000</pubDate>
      <description><![CDATA[Okay, that's a stupidly obscure title. It's meant to represent the combined events: State of the Browser and Web Day Out - two events I attended in the last month.
The short version is: if you get the chance to attend these events or even anything similar, I'd highly recommend that you grab that ticket and let the event wash over you.
For those that didn't attend (or maybe you did and wanted to read my perspective) then here's my thoughts on the separate events and then the round up of my own experience.]]></description>
      <content:encoded><![CDATA[
<p>Okay, that's a stupidly obscure title. It's meant to represent the combined events: <a href="https://2026.stateofthebrowser.com/">State of the Browser</a> and <a href="https://webdayout.com/">Web Day Out</a> - two events I attended in the last month.</p>
<p>The short version is: if you get the chance to attend these events or even <em>anything</em> similar, I'd highly recommend that you grab that ticket and let the event wash over you.</p>
<p>For those that didn't attend (or maybe you did and wanted to read my perspective) then here's my thoughts on the separate events and then the round up of my own experience.</p>
<h2>State of the Browser</h2>
<p>London based and fronted by the lovable <a href="https://letorey.co.uk/">Dave Letorey</a>, always has a strong accessibility story - both from a practical (&quot;how to make the web accessible&quot;) but also universal access - in that all are welcome and an open web is championed through the talks and the heart of the event.</p>
<p>I tried to take a few notes for myself during the day, but this quickly fell to the wayside by midday (I find if I'm taking notes I'm slowly losing track of the talk, so it was more important at the time to stay in the moment).</p>
<p>The day did start with <a href="https://www.bram.us/">Bramus Van Damme</a> with an excellent dive into CSS anchor position, an exciting new feature of CSS that's landing throughout browsers that means we can move a lot of complex JavaScript into the bin. The CSS spec itself it's wholly simple, and there's a blind spot specifically around recreating call out arrows (usually done using rotated weird border magic).</p>
<p>I do question the ease of testing - though I think a talk on how to test CSS (with launching a browser and diffing the screenshot) would be extremely valuable.</p>
<p>Another talk by <a href="https://www.linkedin.com/in/fionasafari/">Fiona Safari</a> on how they learnt to work with their introvertness(?) left me feeling very &quot;seen&quot;, though <a href="https://www.kryogenix.org/days/">Stuart</a> did raise the valid point that this felt a little like the <a href="https://en.wikipedia.org/wiki/Barnum_effect">Barnum effect</a> - where you're able to recognise yourself in most things (we're human after all, and patterns and self interest is programmed deep in us).</p>
<p>This quote really meant a lot to me, and I think about kids who don't push themselves to the front of the class - this is one to remember:</p>
<figure><img src="https://remysharp.com/images/introvert.avif" alt="Being an introvert &amp; extrovert had nothing to do with confidence, social skills or personality flaws - Carl Jung" decoding="async"></figure>
<p><a href="https://www.zachleat.com/">Zach Leatherman's</a> talk looking at how a common picture compare component would and could be developed from the day the first <code>img</code> element was released to today. Especially drawing attention to the &quot;dead zone&quot; where code has landed in the browser yet the interactivity isn't at all ready.</p>
<p>The time to interactivity is a metric I think (I hope), we're thinking of all the time, but to see it articulated and in the context of a relatively contained context really helped - especially considering that webbies have to go back to work and argue the case.</p>
<p>Then <a href="https://jason-williams.co.uk/">Jason Williams</a> gave a wonderful context to how <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal">Temporal</a> came about and the sheer scale of the work.</p>
<p>I've spent my fair share of bemoaning the JavaScript date object (since '99, so yeah, I've been at the sharp end of <code>Date</code> suckage!), so learning about the mammoth effort that went into bringing a completely new date structure was a real treat.</p>
<p>I've been using Temporal for a good few years via a polyfill, but to learn there's so much more <em>and</em> it's arriving cross browser (and server-side) is valuable.</p>
<p><a href="https://www.linkedin.com/posts/kitation_the-plateau-of-accessibility-compliance-activity-7434924356574752768-Szon/">Chad Gowler's accessibility talk</a> was absolutely superb and I do hope they have the opportunity to give the talk again at more events - so many people can learn from these experiences.</p>
<p>Likewise with <a href="https://bsky.app/profile/mikehall314.bsky.social">Mike Hall's</a> story of battling for every single byte for performance in a time when it really, <strong>really</strong> mattered (and in some senses, still does). Mike's always a pleasure to listen to (both as a speaker but also his podcast).</p>
<p>I'll be there for next year's <a href="https://2026.stateofthebrowser.com/2027/">State of the Browser</a></p>
<figure><img src="https://remysharp.com/images/dave-sotb.avif" alt="Dave sharing the news of State of the Browser 2027" decoding="async"></figure>
<h2>Web Day Out</h2>
<p>My general feeling from (the first) Web Day Out was that there was a strong sense of practical takeaway from the talks.</p>
<p>I'm hoping the slides will be available (if they're not already) because there's lots of little details in many of the talks that I definitely felt like I could apply today.</p>
<p>All of the talks from Web Day Out were ace quality, reflecting the wonderful speaker line up.</p>
<p><a href="https://www.jemimaabu.com/">Jemima Abu</a> very much set the starting tone for the day. A taste of new and exciting CSS features (touching on some of the items from Bramus at State of the Browser), and speaking to the solid idea that there's technology that's moved out of the JavaScript cycle deeper into the platform, either available in CSS or event HTML itself (such as <code>popup</code>). Giving me even more reason to <a href="https://remysharp.com/2026/01/13/bytes-i-can-delete-after-all-this-time">eject bytes</a> from my code.</p>
<p>The original Lady of CSS, <a href="https://rachelandrew.co.uk/">Rachel Andrew</a> talked about what <a href="https://web.dev/baseline">Baseline</a> means to development and talked about the very practical nature of support.</p>
<p>One incredibly interesting item that I've not heard others mention: Rachel points out that given the nature of the data collected on Baseline support, it's now possible to accurately predict browser support by a given amount of time. Specifically, if a feature moves to &quot;newly available&quot; today, it will land in &quot;widely available&quot; in 30 months. This might sound like a long time, but Rachel makes the excellent point that developers working on a year-long+ project can use features that may not have wide support from the outset, but they'll be able to pick features based on expected support at the time they go live.</p>
<p>Rachel did also talk about how the Baseline project, in an early form, did consider whether to include <a href="https://remysharp.com/2010/10/08/what-is-a-polyfill">polyfills</a> as part of the support timelines, but the search for a &quot;gold standard&quot; of polyfill was…elusive. For my part, personally, I wouldn't want or expect to see polyfills being stamped with approval by browsers. As Rachel said herself, the requirements for polyfills (and what's considered Baseline) is entirely dependant on your own projects and products.</p>
<figure><img src="https://remysharp.com/images/rachel_polyfill.avif" alt="Rachel stands in front of a slide that reads: The search for gold standard polyfills - the perfect polyfill is hard to find" decoding="async"></figure>
<p>Next was <a href="https://alethgueguen.com/">Aleth Gueguen</a> who shared their story of development and testing directly from the trenches - figuratively <em>and</em> literally. In the post-social a good number of people shared how much they appreciated the insights saying how they'd love to hear more real-life stories, as often it's the real development and challenges overcome that make an interesting story (echo'ing Mike Hall's story from State of the Browser).</p>
<p>Then <a href="https://csswizardry.com/">Harry Roberts</a> took the stage to talk outside of his usual stomping ground. That's to say, instead of performance and measurements he instead spoke to the impact of <em>not</em> building for the web. He shared practical examples of where (anonymised) clients had brought Harry in to work on their performance issues whilst they grappled with framework upgrades. It's a strange web-world we live in when the typical path development path is to reach for Next/Nuxt/Fux/Whux/evar because everyone is does and laden the users with bloat.</p>
<p>Harry had many excellent points during his talk, one that comes to mind as I write today was how optimising for 2nd page load with a coach load of JavaScript, when the bounce rate is so high is premature optimisation (pause for feigned shock) - which ultimately costs negatively.</p>
<p>This wasn't Harry's normal wheelhouse of talk - by his own admission - but an excellent one, and I hope he gets to repeat it for others.</p>
<p>Post lunch, was <a href="https://matuzo.at/">Manuel Matuzovič</a> sharing his newly gained knowledge from questioning if what he knew 3 years ago still stands, and modifying and improving the tech he was using - squarely in CSS land. He used his own pet project <a href="https://olicss.com/">oli.css</a> as a place to experiment (I <strong>strongly</strong> approve - always find a safe place to play), and in particular shared his really interesting take on a CSS &quot;reset&quot; (not a reset per se, because browsers have managed to converge on a solid starting point, but a great starter CSS) and how he layers and reuses throughout the project.</p>
<p>Keeping in this space, which <a href="https://adactio.com/">Jeremy</a> made clear he had curated the talks and order into these excellent pairings, <a href="https://clagnut.com/">Richard Rutter</a> talked us through what had changed in (web) font typography in the last 9 years since he published <a href="https://book.webtypography.net/"><em>The</em> Web Typography book</a>.</p>
<p>I'll be honest, I really didn't think the web type scene was either interesting or even moving. But by gosh there was a LOT. Tonnes of interesting tweaks that we can be making here and today, lots of features that were in Baseline, others that were coming. Of all the talks, Richard's had the most &quot;oooh - I really need to pinch this for my website&quot; slides. I'm hoping they'll be available (and I remember to find it) because it really was a treasure trove.</p>
<p>In the final straight was <a href="https://jakearchibald.com/">Jake Archibald</a> taking a zoomed in view on the customisable <code>select</code> element that is landing (or <em>landed</em>). A (typically) hilarious talk where he went all the way back to 1993 and went through all the events that needed to take place before developers (finally) laid their hands on a stylable select - whilst also showing us <em>how</em> to style the select today.</p>
<p>Highly enjoyable and difficult to ignore the contents of his slides! 😂</p>
<figure><img src="https://remysharp.com/images/jake_select.avif" alt="Jake's slide reads &quot;Look, this is just some placeholder text. You should be listening to whatever I'm saying rather than reading this. Seriously, stop! I might say something interesting. I mean, I hope I say something interesting. Oh god what if no one finds what I'm saying interesting? I'm going to have a panic attack.&quot;" decoding="async"></figure>
<p>Finally <a href="https://lolaslab.co/">Lola Odelola</a> talked about their experience approaching and implementing a missing browser feature - a fallout from their talk at State of the Browser in 2024 asking the question: <em>should there be a <code>prefers-alt-text</code> CSS feature?</em>. Very much from the land of how-the-sausage-is-made and makes me twitch to want to have a crack myself (lol - if I ever had time).</p>
<h2>What I came away with</h2>
<p>Look, if you've been to even a handful you'll already know it's the people between the talks that makes it all worthwhile. It's always lovely when there's talks that give me a little shove towards tinkering with code, doubly so if it's a friend up on stage (new or old) giving the talk.</p>
<p>For the first time in a long while I attended the post-event parties (I tend to miss out on Brighton or London event parties because home calls). In doing so I had some really, really lovely conversations with different people (though landing myself chats finishing at 3am and 1am respectively 🤦).</p>
<hr>
<p>As I sit in these events, I'm thinking about what I want from FFConf. A conundrum I face is that as I increasingly follow politics, the more I want to share what I learn about the world.</p>
<p>At some point during the last of the talks I realised actually what this web community is, is a microcosm of exactly the kind of progressive community that I identify with. A community that cares about representation, dignity for others, equality and sharing.</p>
<p>I've always known I was happier in (what I called) the hippy nation of webbies, but it makes me realise actually what we're doing in the corner of the world can be applied to how we conduct ourselves in the broader sense - and actually the politics I follow these days are very much aligned with the politics that I care about inside of the web community.</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/03/18/web-of-state-of-the-browser-day-out">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Rivers of London (Rivers of London, #1) [book]</title>
      <guid isPermaLink="false">rivers-of-london</guid>
      <link>https://remysharp.com/books/2026/rivers-of-london</link>
      <pubDate>Tue, 24 Feb 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[Vivid voice, fun and dark and original.
I wasn't sure what I was getting in to reading Rivers of London (recommended multiple times on socials), especially as I kept finding the teens/young adult book cover for it (reminding me of the multiple covers the Harry Potter books had) - but I decided to jump in.
I quickly got sucked into the book and the narrative style that Aaronovitch used. For some reason I had Millie Bobby Brown as the voice which caused me a little confusion when I learn that the protagonist and narrator is called Peter Grant (I really didn't read the blurb) - but decided that she could still run the inner monologue.
The Rivers of London is a very London and British book (which I always especially enjoy because I can vividly see the places, hear the accents and usually feel the weather) that's a mix of modern copper plod story with fantastical (and certainly for me: original) characters from gods to vampires to ghosts and wizards.
There's a good balance of funny and witting against the (some times) gruesome and frankly pretty terribly bad things that make for the primary investigation for the protagonist, Grant, to work through.
Really fun stuff - I can definitely see myself returning for more in this series.]]></description>
      <content:encoded><![CDATA[<p>Vivid voice, fun and dark and original.</p>
<p>I wasn't sure what I was getting in to reading Rivers of London (recommended multiple times on socials), especially as I kept finding the teens/young adult book cover for it (reminding me of the multiple covers the Harry Potter books had) - but I decided to jump in.</p>
<p>I quickly got sucked into the book and the narrative style that Aaronovitch used. For some reason I had Millie Bobby Brown as the voice which caused me a little confusion when I learn that the protagonist and narrator is called Peter Grant (I really didn't read the blurb) - but decided that she could still run the inner monologue.</p>
<p>The Rivers of London is a very London and British book (which I always especially enjoy because I can vividly see the places, hear the accents and usually feel the weather) that's a mix of modern copper plod story with fantastical (and certainly for me: original) characters from gods to vampires to ghosts and wizards.</p>
<p>There's a good balance of funny and witting against the (some times) gruesome and frankly pretty terribly bad things that make for the primary investigation for the protagonist, Grant, to work through.</p>
<p>Really fun stuff - I can definitely see myself returning for more in this series.</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2026/rivers-of-london">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>git recent: what branch did I work on? [blog]</title>
      <guid isPermaLink="false">git-recent</guid>
      <link>https://remysharp.com/2026/02/12/git-recent</link>
      <pubDate>Thu, 12 Feb 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[Mega short blog post, mostly for me to remember, but also might be useful to you.
In a project I'll often work on and move around different branches throughout the day, and as the years wear on it's rather dulled my memory - that's to say, I quickly forget what branch I was working on!]]></description>
      <content:encoded><![CDATA[
<p>Mega short blog post, mostly for me to remember, but also might be useful to you.</p>
<p>In a project I'll often work on and move around different branches throughout the day, and as the years wear on it's rather dulled my memory - that's to say, I quickly forget what branch I was working on!</p>
<h2><code>git recent</code></h2>
<p>I created a <code>git</code> command line alias that helps my failing memory. What it does is list all the local branches, oldest to newest with the relative time and the name:</p>
<pre><code>[alias]
  recent = !git for-each-ref --sort=committerdate --format='%(committerdate:relative) %(refname:short)' refs/heads/ | tail -10
</code></pre>
<p>It's a bit cumbersome with the <code>!git</code> part at the start, but it's because I want to limit it the most recent 10 results <em>and</em> I want it with the newest at the bottom.</p>
<pre><code>$ git recent
3 weeks ago fix/ai-gen-docs
2 weeks ago feat/not-available-not-404
2 weeks ago fix/bulk-download-timeout
8 days ago fix/real-null-in-bulk
8 days ago fix/real-404
2 days ago feat/bulk-schema
2 days ago fix/transcript-endpoint-potential-null
2 days ago fix/sanitise-sql-input
21 hours ago main
20 hours ago feat/api-analytics
</code></pre>
<p>Memory win for me. Neato.</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/02/12/git-recent">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Try text scaling support [link]</title>
      <guid isPermaLink="false">2026-02-03-d5be6744</guid>
      <link>https://remysharp.com/links/2026-02-03-d5be6744</link>
      <pubDate>Tue, 03 Feb 2026 11:01:24 +0000</pubDate>
      <description><![CDATA[I've had a larger phone because I got fed up with squinting at my screen, but because of that I also have the OS level font bumped to 115% (and I know Jule, my wife, has it bumped to 125%). This meta tag will use the system font size to adjust the font. Importantly, Josh also points out that the default font size shouldn't be touched: Source: www.joshtumath.uk#heading-tip-1:-don't-override-the-initial-font-size /By Josh Tumath, via Jeremy Keith]]></description>
      <content:encoded><![CDATA[
<p>I've had a larger phone because I got fed up with squinting at my screen, but because of that I also have the OS level font bumped to 115% (and I know Jule, my wife, has it bumped to 125%). This meta tag will use the system font size to adjust the font. Importantly, Josh also points out that the default font size shouldn't be touched: <em>Source: <a href="https://www.joshtumath.uk/posts/2026-01-27-try-text-scaling-support-in-chrome-canary/">www.joshtumath.uk</a></em>#heading-tip-1:-don't-override-the-initial-font-size /By Josh Tumath, via Jeremy Keith</p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-02-03-d5be6744">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Bear Head (Dogs of War, #2) [book]</title>
      <guid isPermaLink="false">bear-head</guid>
      <link>https://remysharp.com/books/2026/bear-head</link>
      <pubDate>Mon, 02 Feb 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[Really enjoyed this follow up to Dogs of War.
I accidentally read Dogs of War in 2018 - I never went looking for it and loved it. Equally, I can't remember when I found out about Bear Head but I knew I wanted to read it if it existed in the same universe. So finally I get around to it.
Overall well written, well drawn characters with distinctive voices in a universe that's really not that hard to conceive. I've read a few of Tchaikovsky's books now and as much as I enjoy them, for some reason it does take me quite a stretch to read the books (this one being just ~315 pages and took me a month) - not sure what's up with that.
The story is told from three protagonist's perspective: Honey, the bear from Dogs of War - once soldier, now an academic arguing for rights for others. Jimmy, the &quot;grunt worker&quot; placed on Mars to prepare it for the colonies that plan to settle and Carole (Springer…I want to say), the PA and &quot;collared&quot; assistant to the antagonist Warner S. Thompson.
Similarly with Dogs of War, Bear Head discusses self and identity (can a person be entirely digital?), freedom and slavery, and the untouchable super rich and their power.
There's some pretty horrible scenes around human slavery where people are compelled to perform, both involuntary physically but also compelled to think in certain ways (i.e. being submissive by design).
With a lot of what I'm reading lately, I can't help but associate it with today's real life events (in 2025-2026), and thinking of the corruption throughout politics we're seeing today - though I can see how this book being published in 2021 aligns fairly well with Trump's first regime from '17-21. Perhaps it's that backdrop that makes me a slow reader!]]></description>
      <content:encoded><![CDATA[<p>Really enjoyed this follow up to Dogs of War.</p>
<p>I <em>accidentally</em> read <a href="https://remysharp.com/books/2018/dogs...">Dogs of War</a> in 2018 - I never went looking for it and loved it. Equally, I can't remember when I found out about Bear Head but I knew I wanted to read it if it existed in the same universe. So finally I get around to it.</p>
<p>Overall well written, well drawn characters with distinctive voices in a universe that's really not that hard to conceive. I've read a few of Tchaikovsky's books now and as much as I enjoy them, for some reason it does take me quite a stretch to read the books (this one being just ~315 pages and took me a month) - not sure what's up with that.</p>
<p>The story is told from three protagonist's perspective: Honey, the bear from Dogs of War - once soldier, now an academic arguing for rights for others. Jimmy, the &quot;grunt worker&quot; placed on Mars to prepare it for the colonies that plan to settle and Carole (Springer…I want to say), the PA and &quot;collared&quot; assistant to the antagonist Warner S. Thompson.</p>
<p>Similarly with Dogs of War, Bear Head discusses self and identity (can a person be entirely digital?), freedom and slavery, and the untouchable super rich and their power.</p>
<p>There's some pretty horrible scenes around human slavery where people are compelled to perform, both involuntary physically but also compelled to <em>think</em> in certain ways (i.e. being submissive by design).</p>
<p>With a lot of what I'm reading lately, I can't help but associate it with today's real life events (in 2025-2026), and thinking of the corruption throughout politics we're seeing today - though I can see how this book being published in 2021 aligns fairly well with Trump's first regime from '17-21. Perhaps it's that backdrop that makes me a slow reader!</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2026/bear-head">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>JS Bin down in 2026 [blog]</title>
      <guid isPermaLink="false">js-bin-down-in-2026</guid>
      <link>https://remysharp.com/2026/02/02/js-bin-down-in-2026</link>
      <pubDate>Mon, 02 Feb 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[January 27th I got an email notification saying that JS Bin had become unavailable. Then next day real life human beings were asking what's going on. By 11pm on the 30th the last of the issues were resolved.
Earlier today Jake asked me: what went wrong?
Fucking, everything.]]></description>
      <content:encoded><![CDATA[
<p>January 27th I got an email notification saying that JS Bin had become unavailable. Then next day real life human beings were asking what's going on. By <a href="https://github.com/jsbin/jsbin/issues/3583#issuecomment-3826171066">11pm on the 30th</a> the last of the issues were resolved.</p>
<p>Earlier today <a href="https://jakearchibald.com/">Jake</a> asked me: <em>what went wrong?</em></p>
<p><strong>Fucking, everything.</strong></p>
<h2>TL;DR</h2>
<p>I get it, this is a big wordy blog post. I got carried away and enjoyed telling the story.</p>
<p>The short version is: CloudFlare, probably best to upgrade everything to latest software (which I couldn't do), 520 status can actually be a mismatched TLS exchange between CloudFlare and the origin. Oh, and don't lean on LLMs too hard when the shit is really hitting the fan - try to take a big step back and make sure you take stock.</p>
<p>Otherwise, here's the too-long, do-read version -</p>
<h2>On being in maintenance mode</h2>
<p>For the last 5 ish/maybe quite a few years or more, JS Bin has run in a fairly automated maintenance mode. There's usually little flurries of wobbles that need my attention every 3/6 months. JS Bin is coming on to 18 years old, which is geriatric by web standards.</p>
<p>Typically it's <a href="https://remysharp.com/2015/09/15/jsbin-toxic-part-2">dodgy content</a> on the site that I need to put banning in place, sometimes it's take down requests that come through from Amazon (where JS Bin is hosted), sometimes it's a memory exception that takes me a little longer to recover from.</p>
<p>You can see from the last 11 years of status checks, there's been outages but nothing quite like what happened this time around (ignoring that big one on the far left…):</p>
<figure><img src="https://remysharp.com/images/jsbin-status-chart.avif" alt="A chart starting from 2014 with spots throughout showing when JS Bin was down" decoding="async"><figcaption>In 2017 the entire server fell over and need to be replaced entirely. Then this were quiet-ish, then…we have the red wall</figcaption></figure>
<p>The larger hours when the server goes down (as I found out recently) is memory running out on the machine, and the machine will respond by pretty much collapsing. The result of which is that I can't connect to the machine via ssh to attempt restore it. It usually requires a forced reboot via the AWS console.</p>
<p>Then there's the odd occasion that even reboots from the AWS console, a literal &quot;turn it on and off again&quot;, doesn't fly…</p>
<h2>It wouldn't come back from a reboot</h2>
<p>This latest outage just wouldn't come back from a reboot. I would trigger the reboot and then wait on the console attempting to connect over SSH so I could get some eyes on the situation but even then I couldn't get it.</p>
<p>JS Bin was rebooting and immediately locking up. So this tells me there's some external pressure on the machine that is not easing up.</p>
<p>The only option I have to hand is to shutdown the machine entirely for an hour or so, to let whatever is clawing at the door to go away for a bit.</p>
<p>When I eventually looked at the Cloud Watch logs, it was clear there was something absolutely smashing at the walls (and door, yes, I mix my metaphors). The amount of inbound network traffic is unprecedented for jsbin. From the chart below, it shows normal usage in the days prior, a trickle of network inbound traffic by comparison to what I was now seeing.</p>
<p>The dips that happen after the cliff edge of monitoring is the machine giving up and being unresponsive. From the chart, I can see that even the short outage wasn't enough to get this beast off jsbin's back.</p>
<figure><img src="https://remysharp.com/images/cloud-watch-chart.avif" alt="The Cloud Watch network traffic logs showing a huge increase of network inbound traffic, going from a typical 1mb to 100mb" decoding="async"><figcaption>The 100mb peak <em>incoming</em> traffic was the real problem.</figcaption></figure>
<h2>Killing the appropriate process</h2>
<p>When I finally managed to get into the machine, the first stop was <code>syslog</code> to find out what was responsible for the crash (or rather the symptom, not the cause, not yet).</p>
<p>I quickly found the garbage collection dump and stacktrace of node running out of memory. First thing's first: let's kill the offending process rather than having a full shit-the-bed approach.</p>
<pre><code># /etc/sysctl.conf and reload with `sudo sysctl -p`
vm.oom_kill_allocating_task=1
</code></pre>
<p>That would mean node (which was saturating all the memory) would be killed rather than anything the system could get it's hands on - which usually meant I couldn't ssh into the machine.</p>
<p>This change wouldn't stop things getting sluggish on the machine but it would mean that I could continue to diagnose even whilst the traffic was bombarding the server (albeit with a very slow terminal responding).</p>
<p>I could see the CPU usage was very, very high, and I could see node steadily increasing it's memory footprint (I use <code>htop</code>).</p>
<p>CPU usage of 100% is…okay because it means I'm using all the available process, but it leaves zero headroom and rather conspicuous that it wasn't dipping at any point.</p>
<p>Then chatgpt suggested upgrading node, which was weird because I'd never told Chatgpt what version of node I was running…</p>
<h2>Side quest: node is <em>really</em> old</h2>
<p>As with running in maintenance and things being in a status quo, I hadn't really touched node…at all.</p>
<p>As it happens, jsbin had been running on node 7 (not even &quot;stable&quot; node 8) for, I imagine, well over a decade.</p>
<p>To me, out of the blue, Chatgpt suggested I could upgrade node. This is a decent suggestion but at no point did I tell Chatgpt what version of node I was running.</p>
<p>On me querying, Chatgpt told me that <em>I had told the AI</em> which was a straight up lie.</p>
<p>After more prodding than I'd like, eventually it turned out that the version of node was in my terminal and at some point during the nginx tuning (in the next section), Chatgpt had helped itself to what was on the screen.</p>
<p>I've no idea if it has access to the scroll back history - I've got to assume it doesn't, but still pretty uncool.</p>
<p>I don't tend to use the &quot;application&quot; thing that Chatgpt has (I normally use the browser interface) but this definitely taught me a lesson: if there's sensitive data <em>anywhere</em> on the screen (ie. I had just <code>cat</code> an <code>.env</code> file) then it's entirely likely an LLM can see it too.</p>
<p>Anyway, I bumped from node 7 to node 22 and by some kind miracle it actually worked without any incident. It turned out that back in 2024 I had done some fairly significant work on the codebase so that I could run it on my local machine (which understandably didn't want to run node 7), so I had modernised the requisite parts.</p>
<p>Phew. At least the event loop is improved and going to be kinder on my CPU.</p>
<p>Except, it's still fucked and the adventure is far from over. Next I considered whether nginx (the proxy layer) could do with some optimisation.</p>
<h2>Fine tuning on zip-all resources</h2>
<p>Until now I've not shared what jsbin's main server runs on. It's a t2.micro AWS instance. Single CPU and 1GB of RAM. I'm often surprised it's managed so long on what I consider so little resources.</p>
<p>And yes, standing a beefier machine up (aka: throwing money at the problem) might help, but the time to reconfigure a new machine wasn't quick - I don't have an instant &quot;build a new jsbin&quot; script (remember, this server has been in maintenance for a long time and just happily running). It's also worth adding that although jsbin does has a &quot;pro&quot; offering, there's very little actual monetary resources. That's all to say: what can I do right now before creating a new machine (spoiler: I did make a new machine, and double-spoiler: it was terminated the following day as I didn't need it).</p>
<p>With the help of Chatgpt, Gemini <em>and</em> Claude (because somehow I have access to all of them, and I really don't have the full skills to know the ins and outs of nginx config) I looked at what could be tuned. I used multiple LLMs so that I could attempt to cross verify the advice (though I wasn't as diligent as I'd have liked).</p>
<p>The adjustments fell into these categories:</p>
<ul>
<li>workers spawned</li>
<li>proxy timeout</li>
<li>increase file descriptors</li>
<li>keep alive timings</li>
<li>remove http2 - to help with memory</li>
</ul>
<p>Here's some of the actual config:</p>
<pre><code class="language-yaml">worker_connections 1024;
worker_processes auto;

keepalive_timeout 10;
keepalive_requests 100;
</code></pre>
<p>With the kicking I was getting from the inbound network traffic, this made little tangible difference. I'm sure it helps in the long run, but not when the machine is struggling with over 1000 requests a second and many more trying to squeeze in.</p>
<p>And then there was this:</p>
<blockquote>
<p>Remy, have you considered CloudFlare?</p>
</blockquote>
<p>I'd thought about add CloudFlare a few times in the past, but I was worried that the configuration adjustment and changes I'd need would be either complicated or would cause some other issue.</p>
<p>Except, nothing was working, so now was the time to get CloudFlare involved.</p>
<p>And so begin new problems…</p>
<h2>Adding CloudFlare</h2>
<p>Props where due, putting CloudFlare in front of JS Bin was relatively easy. CloudFlare detected <em>most</em> of the domains and where they pointed (the important ones at least) and it was a matter of swapping over the name servers from pointing to AWS's Route 53 to CloudFlare's own name servers.</p>
<p>Close to midnight on 29-Jan, I started to see <a href="http://jsbin.com">jsbin.com</a> load in the browser.</p>
<p>I thought there might be a few snags around, but quickly I got replies on github and via email that people were still (mostly) seeing errors.</p>
<p>In particular <a href="https://developers.cloudflare.com/support/troubleshooting/http-status-codes/cloudflare-5xx-errors/error-520/">CloudFlare's 520</a> error page, which, as it turns out can be any number of issues.</p>
<h2>Requests cutting through CloudFlare</h2>
<p>Although I did have some success in loading, I could also see traffic still hammering through on the server.</p>
<p>With some help from our LLM overlords (i.e. I would have google'd it…&quot;<a href="https://kagi.com/">kagied</a> it&quot;?), I got the <a href="https://www.cloudflare.com/en-gb/ips/">list of IP ranges</a> that meant the traffic was from CloudFlare.</p>
<p>There was still a lot of traffic that didn't match those IP ranges. So the next step was to drop non-CloudFlare traffic.</p>
<p>This is where using the LLM cost me time via newly introduced problems (which wouldn't surface until the next day). I think I was too buried in the thick of things otherwise I might have caught it earlier (and not at the end of the process).</p>
<p>The first method to blocking non-CloudFlare was to use an nginx rule and variable, and to drop all traffic that wasn't tagged.</p>
<p>This would mean adding this line to each <code>server {}</code> block - this would say <em>&quot;If the request doesn't have the CloudFlare header, then don't let it through&quot;</em>:</p>
<pre><code>if ($http_cf_ray = &quot;&quot;) {
    return 444;
}
</code></pre>
<p>Importantly there was more config directions that I followed (which I've tucked away, but you can read if you want), specifically <code>set_real_ip_from 173.245.48.0/20;</code> - this would trip me up later on.</p>
<details class="aside"><summary>The http_cf_ray config</summary>
<p>Via Captain GPT:</p>
<h4>The correct nginx-level approach (safe + reversible)</h4>
<h5>1. Tell nginx which IPs belong to Cloudflare</h5>
<p>Create a file:</p>
<pre><code>/etc/nginx/cloudflare.conf
</code></pre>
<p>Put exactly this in it (current CF IPv4 ranges):</p>
<pre><code>set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;

real_ip_header CF-Connecting-IP;
real_ip_recursive on;
</code></pre>
<p>Include it near the top of <code>http {}</code>:</p>
<pre><code>http {
    include /etc/nginx/cloudflare.conf;
    ...
}
</code></pre>
<p>This ensures $remote_addr becomes the real client IP, not Cloudflare.</p>
<h5>2. Block non-Cloudflare traffic (this is the key)</h5>
<p>In each public <code>server {}</code> block (ports 80 and 443), add this at the very top:</p>
<pre><code>if ($http_cf_ray = &quot;&quot;) {
    return 444;
}
</code></pre>
<p>What this does:</p>
<ul>
<li>Cloudflare always sends CF-Ray</li>
<li>Direct clients never do</li>
<li>444 silently drops the connection (no response, no load)</li>
</ul>
<p>This is extremely effective.</p>
</details>
<p>This config was all well and good, but traffic was still coming in. This change would mean that nginx would have to process the traffic than ignoring (or &quot;dropping&quot;) it entirely (<em>#foreshadowing</em>).</p>
<p>When I ran command below, it would list the connections, and I could <em>still</em> see non-CloudFlare requests being able to complete request (at this specific point in time, I was in a frantic cycle of &quot;try a change - fail - worry a bit - ask LLM - repeat&quot;):</p>
<pre><code>ss -tan state established '( sport = :443 )'
</code></pre>
<p>The next change that I put in place was to drop the request if the IP didn't match the ones in the CloudFlare IP range (whereas before the change was looking for a CloudFlare specific header). Looking back as I write this, I'm not sure why the header method didn't work, but I was sure to add more petrol onto the fire:</p>
<pre><code>geo $is_cloudflare {
    default 0;

    173.245.48.0/20    1;
    103.21.244.0/22    1;
    # etc
}
</code></pre>
<p>This flags if the remote address is a CloudFlare IP, set the <code>$is_cloudflare=1</code>. Then in my server blocks:</p>
<pre><code>server {
    listen 443 ssl http2 default_server;
    if ($is_cloudflare = 0) { return 444; }
    if ($cf_valid = 0) { return 444; }

    # rest of config unchanged
}
</code></pre>
<p>What I didn't realise at this point, and took another 24 hours to figure out, is that the first CloudFlare nginx based change would say <em>&quot;if the IP is CloudFlare, then set the $remote_addr to the original request&quot;</em>. Then this code says <em>&quot;if the IP is NOT CloudFlare don't let them through&quot;</em>.</p>
<p>It's a mess. Now I've got reports from people on github telling me they're still seeing <em>mostly</em> 520 errors, and finally I realise I can replicate by using a VPN because for some reason it was still working for me.</p>
<p>There's two problems at this point:</p>
<ol>
<li>Traffic still coming in that isn't through CloudFlare that's causing a drain on resources</li>
<li>Real users coming through CloudFlare are, mostly, not getting the site</li>
</ol>
<p>Pretty much the worst of both worlds.</p>
<p>Finally, firewall rules spring to mind. Better late than never.</p>
<h2>Dropping traffic</h2>
<p>This was done on two fronts - just for <em>belt-and-braces</em> approach:</p>
<ol>
<li><code>ufw</code> (or as I knew it &quot;iptables&quot;) rules one the server to <code>DROP</code> or <code>ALLOW</code> traffic based on IP range</li>
<li>AWS security policy to do the same.</li>
</ol>
<p>Running the rules for <code>ufw</code> was relatively simple. A matter of allowing all the known IP ranges, then denying everything else:</p>
<pre><code class="language-shell">$ ufw allow from <span class="token number">173.245</span>.48.0/20 to any port <span class="token number">443</span>
$ ufw allow from <span class="token number">103.21</span>.244.0/22 to any port <span class="token number">443</span>
$ <span class="token comment"># etc</span>
$ ufw deny <span class="token number">443</span>
</code></pre>
<p>Then repeated for port 80. I did get tripped up during testing when I wanted to allow my IP through, but that was solved with <code>ufw status numbered</code> and then <code>ufw delete N</code>.</p>
<p>Adding all the IP ranges on AWS was not so simple. The web UI just doesn't allow for large changes - it's very, very clunky.</p>
<p>Thankfully I could automate some of it from the <a href="https://aws.amazon.com/cli/">command line</a> and script the work. The annoying thing was that the AWS command line doesn't let me bulk modify (or at least I didn't find it) and each command takes a good few seconds to run <em>and</em> requires me to press enter after the response comes back saying it had worked.</p>
<p>This was the command:</p>
<pre><code class="language-sh"><span class="token keyword">for</span> <span class="token for-or-select variable">CIDR</span> <span class="token keyword">in</span> <span class="token punctuation">\</span>
   <span class="token number">103.21</span>.244.0/22 <span class="token punctuation">\</span>
   <span class="token number">103.22</span>.200.0/22 <span class="token punctuation">\</span>
   <span class="token number">103.31</span>.4.0/22 <span class="token punctuation">\</span>
   <span class="token comment"># etc</span>
<span class="token keyword">do</span>
   aws ec2 authorize-security-group-ingress --group-id <span class="token variable">$SG_ID</span> <span class="token parameter variable">--protocol</span> tcp <span class="token parameter variable">--port</span> <span class="token number">80</span>  <span class="token parameter variable">--cidr</span> <span class="token variable">$CIDR</span> <span class="token parameter variable">--region</span> us-east-1
   aws ec2 authorize-security-group-ingress --group-id <span class="token variable">$SG_ID</span> <span class="token parameter variable">--protocol</span> tcp <span class="token parameter variable">--port</span> <span class="token number">443</span> <span class="token parameter variable">--cidr</span> <span class="token variable">$CIDR</span> <span class="token parameter variable">--region</span> us-east-1
<span class="token keyword">done</span>
</code></pre>
<p>With those in place, finally the server was breathing again. However, those pesky CloudFlare 520s were still preventing people from visiting <a href="http://jsbin.com">jsbin.com</a> (except me…somehow…).</p>
<h2>CloudFlare's 520</h2>
<p>I naively thought 520 was like a 503 (the entire server is failing to respond to CloudFlare) or a 504 (gateway timeout - usually when node doesn't come back to nginx or CloudFlare), but it's not. It's more like <em>&quot;CloudFlare made a request and the response is incompatible&quot;</em>.</p>
<p>The only real clue I had was that port 80, plain http wasn't affected. A <a href="https://github.com/jsbin/jsbin/issues/3583#issuecomment-3823361117">helpful comment from @robobuljan</a> showed that it was only the https version causing issues:</p>
<pre><code class="language-sh">$ <span class="token function">curl</span> jsbin.com             <span class="token comment"># (works!)</span>
$ <span class="token function">curl</span> http://jsbin.com      <span class="token comment"># (works!)</span>
$ <span class="token function">curl</span> https://jsbin.com     <span class="token comment"># "error code: 520"</span>
</code></pre>
<p>Although this digging took most of the day, it was the part that the LLMs really couldn't help with (and I had thankfully set them aside whilst I chewed on the meat of this problem).</p>
<p>As I looked for any clues. In the CloudFlare SSL/TLS page a section called &quot;Traffic Served Over TLS&quot; showed that there was a split in the supported TLS versions (I didn't capture a screenshot, but these numbers are from their API):</p>
<ul>
<li>TLSv1: 36 requests</li>
<li>TLSv1.1: 56 requests</li>
<li>TLSv1.2: 1,922,523 requests</li>
<li><strong>TLSv1.3: 5,216,795 requests</strong></li>
</ul>
<p>That's a lot on TLSv1.3, but I wondered how old (or actually new) v1.3 was given how old my rickety machine was. So I went back to my nginx config and found this line, repeated against each server block that ran SSL:</p>
<pre><code>ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
</code></pre>
<p>A conspicuous lack of TLSv1.3, and I wondered what would happen if the user asked for 1.3, CloudFlare tottered off wanting 1.3 and then got back 1.2… or perhaps nothing at all.</p>
<p>I first tried to add <code>TLSv1.3</code> to the list only for the <code>nginx -t</code> test to fail (the module wasn't installed and I couldn't get it without doing major upgrade work). So let's see if it can be turned off in CloudFlare.</p>
<p>The short answer is yes, but I struggled to find it.</p>
<p>The first place to confirm what's being support is the section under &quot;Speed, Settings&quot;. But to completely turn it off, it's located in &quot;SSL/TLS&quot; then &quot;Edge Certificates&quot; and towards the end of the page.</p>
<p>Disabling this unlocked a lot more genuine traffic and we were cooking again. Almost, nearly. Again, for some, now the static assets weren't loading nor was the frame that actually live runs the authored code (the <code>null.jsbin.com</code> domain).</p>
<h2>JS Bin was dropping some users</h2>
<p>It took me a few more hours to solve this last step, and I'm still not entirely sure how it all hung together. But if you recall, earlier in my nginx config, I had told nginx that if the IP of the request was from CloudFlare that we should use <code>set_real_ip_from</code>.</p>
<p>This specific command was writing the original IP of the requesting user into the <code>$remote_addr</code>, which is what nginx was now using to drop requests with the <code>return 444</code>. Somehow this wasn't in the main server block (the part that returns the index page), but was somehow in the <code>static.jsbin.com</code> and <code>null.jsbin.com</code>.</p>
<p>This kind of confusion is the result of working late hours, and working in crisis mode. I should have known better and I'm great at dolling out advice but sometimes don't tend to heed it myself.</p>
<p>After I finally removed the janky checks, IP swapping and quite a bit of the cruft that I had introduced with my pal ChatGPT, this let the last of the traffic come through correctly.</p>
<p>JS Bin was back. Entirely.</p>
<h2>The aftermath</h2>
<p>Now that CloudFlare is in front of the server, life is surprisingly chill on this 1GB single CPU machine. Way more calm than a normal day of traffic. Look at that CPU usage!</p>
<figure><img src="https://remysharp.com/images/jsbin-htop-2026.avif" alt="A screenshot of the &quot;htop&quot; program showing that the CPU is around 5% and memory usage is about 30% consumed" decoding="async"><figcaption>Just chilling out at an easy 4.6% CPU usage</figcaption></figure>
<p>I suspect if I hadn't leant on the LLMs so much during the scream-face-the-server-is-down moments, I might have caught the complexity that I was adding. Though equally I should have put CloudFlare in front of JS Bin years ago - and not at a time of crisis.</p>
<p>I definitely learnt a few gotchas, the TLS and 520 status codes are that for me.</p>
<p>The traffic has eased out from the AWS CloudWatch logs and I believe CloudFlare is now bouncing a lot of that away from me - and it seems like a lot of that is coming from Hong Kong (which I've set to have a JavaScript based check to get through CloudFlare):</p>
<figure><img src="https://remysharp.com/images/jsbin-hong-kong.avif" alt="" decoding="async"><figcaption>Hong Kong is so small in this map, you can't even see the deep blue of the chart</figcaption></figure>
<p>Since I took that screenshot, Hong Kong has 10 million requests in the last 24 hours.</p>
<p>Even though I don't think I'll ever really know what caused the amount of traffic that caused everything to fall over, my gut suspects scrapers for AI and LLMs just slurping up as much of the web it can. The only evidence I have <em>against</em> that theory is that the traffic didn't come from a single IP.</p>
<p>Whereas, weirdly, I saw a <a href="https://bsky.app/profile/remysharp.com/post/3mb55uwp3vk2j">single IP bot scraping this blog</a>, accounting for over 3GB of data and over 325,000 requests in a matter of hours. Thankfully this was running on Netlify and is entirely static, and not running on node 7 🤦.</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/02/02/js-bin-down-in-2026">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Bytes I can delete after all this time [blog]</title>
      <guid isPermaLink="false">bytes-i-can-delete-after-all-this-time</guid>
      <link>https://remysharp.com/2026/01/13/bytes-i-can-delete-after-all-this-time</link>
      <pubDate>Tue, 13 Jan 2026 10:00:00 +0000</pubDate>
      <description><![CDATA[For the last few years my work-work has mostly focused on back end software (particularly around APIs). This meant that any front end work I was doing was for myself.
Being an long-in-the-tooth old dog, I tend to learn and trick, and roll it out again and again typically without taking the time to find whether I still need the trick. Case and point, I learnt about the JavaScript performance trick of ~~1.4 === 1 to floor a value (and the same float | 0) but really these days it's not &quot;faster&quot; than doing it the legible way (i.e. Math.floor(1.4)).
Given I've had a bit of time away from the backend, here's an unorganised list of things I've found I can use, and thusly remove extra code that I no longer need.]]></description>
      <content:encoded><![CDATA[
<p>For the last few years my work-work has mostly focused on back end software (particularly around APIs). This meant that any front end work I was doing was for myself.</p>
<p>Being an long-in-the-tooth old dog, I tend to learn and trick, and roll it out again and again typically without taking the time to find whether I still need the trick. Case and point, I learnt about the JavaScript performance trick of <code>~~1.4 === 1</code> to floor a value (and the same <code>float | 0</code>) but really these days it's not &quot;faster&quot; than doing it the legible way (i.e. <code>Math.floor(1.4)</code>).</p>
<p>Given I've had a bit of time away from the backend, here's an unorganised list of things I've found I can use, and thusly remove extra code that I no longer need.</p>
<h2>The list</h2>
<ol>
<li>CSS: <code>text-underline-offset</code> - the distance I can set the <span style="text-decoration: underline; font-family: 'Ubuntu Mono'; text-underline-offset: 12px">text-underline-offset: 12px</span></li>
<li>CSS: <code>gap</code> - no more faffing with margins in flexbox.</li>
<li>CSS: nested media queries on selectors (and nesting general):</li>
</ol>
<pre><code class="language-css"><span class="token selector">h1</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 600px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<ol start="4">
<li>CSS: <code>clamp(min, variable, max)</code> - I used this extensively on FFConf 2025's <a href="https://github.com/leftlogic/ffconf2025/blob/fdb687636450058afbfb67c846a32667bdbe6c8e/style.css#L62">css</a>, the process of finding the right values is very much</li>
<li>CSS: <code>content: open-quote</code> can localised quotes <em>and</em> the <code>q</code> tag does this by default, <a href="https://www.stefanjudis.com/today-i-learned/how-to-use-language-dependent-quotes-in-css/">via this neat insight from Stefan Judis</a></li>
<li>JS: <code>catch</code> without catching the variable, let's me get past the <code>'error' is defined but never used</code>:</li>
</ol>
<pre><code class="language-js"><span class="token keyword">try</span> <span class="token punctuation">{</span>
  <span class="token function">doTheDodgyStuff</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
  <span class="token comment">// nothing, it's fine</span>
<span class="token punctuation">}</span>
</code></pre>
<ol start="7">
<li>JS: pointer events have improved (though still from experience they're not 100% perfect) but are to replace the old double click &amp; touch handlers nonsense as seen in <a href="https://www.w3.org/TR/pointerevents/#example_1">the W3C spec</a></li>
<li>AVIF images are fully supported - I benefited from a train ride with <a href="https://jakearchibald.com/">Jake Archibald</a> and in chatting I discovered AVIF are very well supported. This means <a href="https://github.com/remy/remysharp.com/commit/19a32efcb719d1b125017577e48330606ef20ef7#diff-43c10c1d3f992c362c956760385e6ad7397a2345f90c0709e2d4da765ab2d255">easily getting 50% file size savings on JPEGs</a>. I'm regularly running the <a href="https://github.com/AOMediaCodec/libavif/">avidenc</a> command in directories:</li>
</ol>
<pre><code class="language-sh"><span class="token function">ls</span> *.jpg <span class="token operator">|</span> <span class="token function">xargs</span> <span class="token parameter variable">-P</span> <span class="token number">8</span> <span class="token parameter variable">-I</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> avifenc <span class="token parameter variable">-q</span> <span class="token number">50</span> <span class="token string">"{}"</span> <span class="token string">"{}"</span>.avif
</code></pre>
<p>So that's my little list.</p>
<p>Not even 10 things. I guess I've not learnt much yet, but even though I return to the server side of APIs in 2026, I'm sure I'll be kicking the tyres in the front again soon enough and adding to my measly list.</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/01/13/bytes-i-can-delete-after-all-this-time">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>A Very Merry Murder (Malvern Farm Mystery, #6) [book]</title>
      <guid isPermaLink="false">a-very-merry-murder-malvern-farm-mystery-6</guid>
      <link>https://remysharp.com/books/2026/a-very-merry-murder-malvern-farm-mystery-6</link>
      <pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[Fine. Easy read. Guessed the murdered though 🤷
Grabbed it for the Christmas period (slightly annoyed I finished it on Jan 2nd). It's decently written, apparently part of a series (this being book 6) but stands fine on it's own. There's a few references to something that happened before, but doesn't affect the story.
It does read like a Columbo or Murder She Wrote, where there's people killing other people like it's just another Wednesday. All ends are fully tied up without anything left to the reader by the end.
I did figure out the killer around 1/3rd of the way in - or at least I keep asking the protagonist &quot;What about X?!&quot;.
Not terribly Christmasy, but the very last chapter was very sweet.]]></description>
      <content:encoded><![CDATA[<p>Fine. Easy read. Guessed the murdered though 🤷</p>
<p>Grabbed it for the Christmas period (slightly annoyed I finished it on Jan 2nd). It's decently written, apparently part of a series (this being book 6) but stands fine on it's own. There's a few references to something that happened before, but doesn't affect the story.</p>
<p>It does read like a Columbo or Murder She Wrote, where there's people killing other people like it's just another Wednesday. All ends are fully tied up without anything left to the reader by the end.</p>
<p>I did figure out the killer around 1/3rd of the way in - or at least I keep asking the protagonist &quot;What about X?!&quot;.</p>
<p>Not terribly Christmasy, but the very last chapter was very sweet.</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2026/a-very-merry-murder-malvern-farm-mystery-6">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Books I read in 2025 [blog]</title>
      <guid isPermaLink="false">books-i-read-in-2025</guid>
      <link>https://remysharp.com/2026/01/01/books-i-read-in-2025</link>
      <pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[This post is mostly data driven (from my own web site's data) to give me a sense of the quality of the books I've read, otherwise individual reviews are all linked in this post or available on my books page.
Longest book: Empire of AI: Dreams and Nightmares in Sam Altman's OpenAI - 496 pages
Shortest book: The Time Machine - 107 pages
Quickest read: 3 days - The Radleys by Matt Haig (341 pages)
Longest read: 2 months, 2 days - Butter by Asako Yuzuki (464 pages)
Diversity of authors:

Women: 9
Men: 5

Rated books
5 stars

Minority Rule: Adventures in the Culture War - 319 pages

4 stars

Empire of AI: Dreams and Nightmares in Sam Altman's OpenAI - 496 pages
In Bloom (Sweetpea, #2) - 432 pages
Sweetpea (Sweetpea, #1) - 480 pages
The Radleys - 341 pages
The Man Who Died Twice (Thursday Murder Club, #2) - 422 pages
The Echo Wife - 347 pages

Books by decade
1890

1895: The Time Machine by H.G. Wells

1960

1969: The Left Hand of Darkness by Ursula K. Le Guin

2010

2010: The Radleys by Matt Haig
2013: Spike Milligan: Man of Letters by Spike Milligan
2017: Butter by Asako Yuzuki
2017: Sweetpea (Sweetpea, #1) by C.J. Skuse
2018: In Bloom (Sweetpea, #2) by C.J. Skuse
2019: Reasons to Be Cheerful by Nina Stibbe

2020

2021: The Man Who Died Twice (Thursday Murder Club, #2) by Richard Osman
2021: The Echo Wife by Sarah Gailey
2022: The Satsuma Complex (Gary Thorn, #1) by Bob Mortimer
2025: Empire of AI: Dreams and Nightmares in Sam Altman's OpenAI by Karen Hao
2025: Minority Rule: Adventures in the Culture War by Ash Sarkar
2025: Making a Killing (DI Fawley #7) by Cara Hunter]]></description>
      <content:encoded><![CDATA[
<p>This post is mostly data driven (from my own web site's data) to give me a sense of the quality of the books I've read, otherwise individual reviews are all linked in this post or available on my books page.</p>
<p><strong>Longest book</strong>: <a href="https://remysharp.com/books/2025/empire-of-ai-dreams-and-nightmares-in-sam-altmans-openai">Empire of AI: Dreams and Nightmares in Sam Altman's OpenAI</a> - 496 pages</p>
<p><strong>Shortest book</strong>: <a href="https://remysharp.com/books/2025/the-time-machine">The Time Machine</a> - 107 pages</p>
<p><strong>Quickest read</strong>: 3 days - <a href="https://remysharp.com/books/2025/the-radleys">The Radleys</a> <em>by Matt Haig</em> (341 pages)</p>
<p><strong>Longest read</strong>: 2 months, 2 days - <a href="https://remysharp.com/books/2025/butter">Butter</a> <em>by Asako Yuzuki</em> (464 pages)</p>
<p><strong>Diversity of authors</strong>:</p>
<ul>
<li>Women: 9</li>
<li>Men: 5</li>
</ul>
<h2>Rated books</h2>
<h3>5 stars</h3>
<ul>
<li><a href="https://remysharp.com/books/2025/minority-rule-adventures-in-the-culture-war">Minority Rule: Adventures in the Culture War</a> - 319 pages</li>
</ul>
<h3>4 stars</h3>
<ul>
<li><a href="https://remysharp.com/books/2025/empire-of-ai-dreams-and-nightmares-in-sam-altmans-openai">Empire of AI: Dreams and Nightmares in Sam Altman's OpenAI</a> - 496 pages</li>
<li><a href="https://remysharp.com/books/2025/in-bloom-sweetpea-2">In Bloom (Sweetpea, #2)</a> - 432 pages</li>
<li><a href="https://remysharp.com/books/2025/sweetpea-sweetpea-1">Sweetpea (Sweetpea, #1)</a> - 480 pages</li>
<li><a href="https://remysharp.com/books/2025/the-radleys">The Radleys</a> - 341 pages</li>
<li><a href="https://remysharp.com/books/2025/the-man-who-died-twice-thursday-murder-club-2">The Man Who Died Twice (Thursday Murder Club, #2)</a> - 422 pages</li>
<li><a href="https://remysharp.com/books/2025/the-echo-wife">The Echo Wife</a> - 347 pages</li>
</ul>
<h2>Books by decade</h2>
<p><strong>1890</strong></p>
<ul>
<li>1895: <a href="https://remysharp.com/books/2025/the-time-machine">The Time Machine</a> <em>by H.G. Wells</em></li>
</ul>
<p><strong>1960</strong></p>
<ul>
<li>1969: <a href="https://remysharp.com/books/2025/the-left-hand-of-darkness">The Left Hand of Darkness</a> <em>by Ursula K. Le Guin</em></li>
</ul>
<p><strong>2010</strong></p>
<ul>
<li>2010: <a href="https://remysharp.com/books/2025/the-radleys">The Radleys</a> <em>by Matt Haig</em></li>
<li>2013: <a href="https://remysharp.com/books/2025/spike-milligan-man-of-letters">Spike Milligan: Man of Letters</a> <em>by Spike Milligan</em></li>
<li>2017: <a href="https://remysharp.com/books/2025/butter">Butter</a> <em>by Asako Yuzuki</em></li>
<li>2017: <a href="https://remysharp.com/books/2025/sweetpea-sweetpea-1">Sweetpea (Sweetpea, #1)</a> <em>by C.J. Skuse</em></li>
<li>2018: <a href="https://remysharp.com/books/2025/in-bloom-sweetpea-2">In Bloom (Sweetpea, #2)</a> <em>by C.J. Skuse</em></li>
<li>2019: <a href="https://remysharp.com/books/2025/reasons-to-be-cheerful">Reasons to Be Cheerful</a> <em>by Nina Stibbe</em></li>
</ul>
<p><strong>2020</strong></p>
<ul>
<li>2021: <a href="https://remysharp.com/books/2025/the-man-who-died-twice-thursday-murder-club-2">The Man Who Died Twice (Thursday Murder Club, #2)</a> <em>by Richard Osman</em></li>
<li>2021: <a href="https://remysharp.com/books/2025/the-echo-wife">The Echo Wife</a> <em>by Sarah Gailey</em></li>
<li>2022: <a href="https://remysharp.com/books/2025/the-satsuma-complex-gary-thorn-1">The Satsuma Complex (Gary Thorn, #1)</a> <em>by Bob Mortimer</em></li>
<li>2025: <a href="https://remysharp.com/books/2025/empire-of-ai-dreams-and-nightmares-in-sam-altmans-openai">Empire of AI: Dreams and Nightmares in Sam Altman's OpenAI</a> <em>by Karen Hao</em></li>
<li>2025: <a href="https://remysharp.com/books/2025/minority-rule-adventures-in-the-culture-war">Minority Rule: Adventures in the Culture War</a> <em>by Ash Sarkar</em></li>
<li>2025: <a href="https://remysharp.com/books/2025/making-a-killing-di-fawley-7">Making a Killing (DI Fawley #7)</a> <em>by Cara Hunter</em></li>
</ul>
<p><em>Originally published on <a href="https://remysharp.com/2026/01/01/books-i-read-in-2025">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>My 2025 [blog]</title>
      <guid isPermaLink="false">my-2025</guid>
      <link>https://remysharp.com/2025/12/31/my-2025</link>
      <pubDate>Wed, 31 Dec 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[I've been doing these posts ending my years, aiming to publish on the 31st, so I'm pleased that I've managed to get this post out the door. Mostly for my own reading, but perhaps yours too.]]></description>
      <content:encoded><![CDATA[
<p>I've been doing these posts ending <a href="https://remysharp.com/my-years">my years</a>, aiming to publish on the 31st, so I'm pleased that I've managed to get this post out the door. Mostly for my own reading, but perhaps yours too.</p>
<h2>Reflecting and comparing</h2>
<p>I've just read through my opening to the <a href="https://remysharp.com/2024/12/31/my-2024">end of 2024</a> and wow, it doesn't feel better (to me). Though I do appreciate two things that factor into this: 1. I'm a glass half empty fella, 2. the coverage (I follow) of events doesn't often highlight the positive things happening.</p>
<p>The world is on fire. Still.</p>
<p>With this particular phrase in mind, I saw The Holdovers last week for the first time, and <a href="https://www.imdb.com/title/tt14849194/quotes/?item=qt7172147">this quote</a> struck me, for a movie set in 1970:</p>
<blockquote>
<p>the world doesn't make sense anymore. I mean, it's on fire. The rich don't give a shit. Poor kids are cannon fodder. Integrity is a punch line. Trust is just a name on a bank.</p>
</blockquote>
<p>The response to which is:</p>
<blockquote>
<p>…if that's all true, then now is when they most need someone like you.</p>
</blockquote>
<p>I think that's why we need to still feel like it's burning so that we can find that fire and help as do what we/I can.</p>
<p>Two particular legal cases that I'm trying to follow (though struggling because I suspect these legal things are <em>slow</em>):</p>
<ul>
<li>Palatine Action having been <a href="https://en.wikipedia.org/wiki/Palestine_Action#Proscription">proscribed</a>, and the <a href="https://en.wikipedia.org/wiki/Palestine_Action#Legal_challenge">legal challenge</a>, at time of writing, <a href="https://gcnchambers.co.uk/final-submissions-made-before-judgment-in-high-court-challenge-to-proscription-of-palestine-action/">&quot;Judgment is awaited&quot;</a>.</li>
<li>The ECHR &quot;interim guidance&quot; (quoted due to the lack-thereof) on &quot;woman&quot; and &quot;sex&quot; refer to the biological sex - and the resulting <a href="https://goodlawproject.org/case/were-challenging-the-ehrcs-interim-guidance/">challenge</a> showing that it's transphobic and legally wrong.</li>
</ul>
<p>A few other highlights being Labour did not swoop in and do what I had hoped (i.e. do right by people) and instead has spent a lot of their time trying to out-Reform Reform. The Giant Cheese Puff across the pond is tearing apart democracy, <a href="https://youtu.be/dergOG7vpJg?si=Oq5VTYDcVAhs3laO&amp;t=105">literally and figuratively</a> and the <a href="https://www.aljazeera.com/search/genocide?sort=date">genocide continues</a> even after a &quot;ceasefire&quot; and the <a href="https://www.theguardian.com/uk-news/2025/dec/29/number-people-britons-must-be-born-in-uk-rising-study">far right continue to raise it's ugly head</a> in the UK. Oh, an AI eating the world and people <em>actually</em> <a href="https://wapo.st/49uy2q1">dying from the companies pushing engagement</a> (<abbr title="Content warning">CW</abbr>: suicide).</p>
<p>So… with that floating around in the background, I have found it hard to muster the motivation to care about the web, about bits of code and about writing on my blog.</p>
<p>I will say that I've found a little light in the political sphere. I regularly watch <a href="https://crooked.com/podcast-series/pod-save-the-uk/">Pod Save the UK</a> on YouTube, and found Zack Polanski's campaign to lead the greens - and <em>a lot</em> of what I believed. I've joined the Greens specifically to cast a vote and not only did he win, but the Greens have seen a huge surge adding over 120,000 new members (me included).</p>
<p>In a similar vein to doom scrolling, I found myself watching Polanski's videos and interviews online to drop a pipette's worth of hope back into my system. This was a <a href="https://www.youtube.com/shorts/4nNJYpHk6Co">particular highlight</a> for me earlier this year.</p>
<p>With that out of the way, what have I been up to?</p>
<h2>Work</h2>
<p>Work-work (or as most people know it: <em>paid work</em>) has really been two main items: working with <a href="https://www.thenational.academy/">Oak National</a> and working on FFConf 2025.</p>
<p>I first started working for Oak in early 2021 and have worked with them for just over 3 years in total. Ranging from rebuilding their question and answer system, to designing and building their public facing content API (where you, Jo Public, can access any part of their curriculum).</p>
<p>I really like working with the people at Oak, and it's the first place I encountered the concept of working in squads (which I see as like mini movie production crews - ask me in person what I mean!).</p>
<p>My last contract ended in mid-August this year, but I'm looking forward to returning to work with them at the start of 2026.</p>
<p>Then onto FFConf, and with my Oak contract ending, allowed me much more time to focus on the event, planning and new software.</p>
<h3>FFConf</h3>
<p>This year's lead up to FFconf was very, very different to 2024's lead up.</p>
<p>In 2024, the stress of trying to sell tickets, trying to find sponsors, and feeling like we were spinning our tyres and getting no-where was bad. Very, very bad. Like &quot;I want to throw this all in&quot;-bad.</p>
<p>When Julie and I returned to FFConf's planning for 2025 we knew this wasn't the last one, but we also knew we needed to do something different at the very least for my own mental health (and so Julie wasn't worried about me the whole year).</p>
<p>The relatively small and simple change we made was that we decided we would send a newsletter every week. The same structure, but weekly on Thursday.</p>
<p>This seemingly obvious change, completely changed the experience for me. There was none of the stress and terror that I experienced in 2024.</p>
<p>Weirdly, tickets sold <em>mostly</em> similarly to 2024, but it <em>felt</em> completely different.</p>
<p>As for the day. It was wonderful. I had a smile throughout the day, and I felt full of love from the people who attended. The talks were amazing and inspiring and fun. I <a href="https://remysharp.com/2025/11/22/ffconf-2025">wrote about the day</a> too.</p>
<h2>Projects</h2>
<p>As I mentioned earlier, I've gone through a lot of the year not entirely excited about web stuff. I want to be, but… I'm just not right now.</p>
<p>A side effect of that feeling is that I've not really put much out into the world. I know I don't have to, but I also know that it's my creative outlet, and it's a nice thing for me to do (for me).</p>
<p>AI has been a dominant feature of the tech industries in 2025 - <a href="https://bsky.app/profile/remysharp.com/post/3mavgppf5bc2k">unavoidable</a> in a lot of cases - but I have been dabbling in lots of little personal tools and toys using (effectively) vibe coding.</p>
<p>I find myself using this vibe coding method to create personal items that make something really specific to me, like: a tracker to help me and Julie to remember who chose the movie last week <em>and</em> what the hell we watched, or, a command line tool to scan my network and try to work out where my <a href="https://esphome.io/">esphome</a> devices are, or, a percentage calculate (because I <em>keep</em> forgetting how it works), or, a tool to modify subtitle files to offset the timing, or, a stupid toy that let's me upload a photo, cut out a mouth, then it uses speech API to sing whatever you type in.</p>
<p><a href="https://remysharp.com/2025/07/18/vibe-coding-and-robocop">But these are personal toys</a>. Prototypes. Things that are not meant for more than one user.</p>
<p>I'd like to list and screenshot some of these in the future to preserve them a little better.</p>
<h3>Donations</h3>
<p>Each year, since 2021, I've been trying to look at donating <em>at least</em> 10% of the business profits to charities.</p>
<p>I put a call out on socials for anyone's lived experience with any trans support charities and the replies grew and grew (as much as I wanted to give to them all, I simply couldn't).</p>
<p>When reviewing which charities to donate to, we always check their income and want to see that they're also using their funds.</p>
<ul>
<li><a href="https://www.choirwithnoname.org/">Choir with No Name</a> - homelessness and marginalised groups</li>
<li><a href="https://www.forwardfacing.co.uk/">Forward Facing</a> - support for families with critical illness or complex disabilities</li>
<li><a href="https://clareproject.org.uk/">The Clare Project</a> - support for trans, non-binary and intersex adults</li>
</ul>
<p>Separately, I also donated to these companies (which aren't charities) from my personal donations:</p>
<ul>
<li><a href="https://transkidsdeservebetter.org/">Trans Kids Deserve Better</a></li>
<li><a href="https://transactual.org.uk/">TransActual</a></li>
<li><a href="https://goodlawproject.org/">The Good Law Project</a></li>
</ul>
<p>I hope to continue this &quot;tradition&quot; while I can.</p>
<h2>Personal</h2>
<p>Having touched on it already in the opening of this post, a lot of my personal headspace is in politics right now.</p>
<p>Outside of that particular stress, I've got my <a href="https://retrobyrem.uk/">Gameboy and retro hardware that I restore</a> (though much less often these days).</p>
<p>I also regularly tinker with my Home Assistant set up (something I've been meaning to write a little more about - there's some fun and dumb automations I have set up). A few of my favourites are: when I go to the gym, the bathroom radiator starts heating up (whereby my undies start getting warm in lieu of my shower when I return), or perhaps the increasingly <a href="https://www.collinsdictionary.com/dictionary/english/aggro">aggro</a> announcement to remind me to empty the washing machine.</p>
<p>The family keep growing (physically, thankfully the numbers have levelled off now!). The pets (3 cats and 1 dog) are happy, and the kids (one teenager and one pre-teen) keep sprouting and amazing (and <em>testing</em> us) each day.</p>
<p>The best books I read this year were both non-fiction (and thusly took me ages to read), but I highly recommend both:</p>
<ol>
<li><a href="https://remysharp.com/books/2025/empire-of-ai-dreams-and-nightmares-in-sam-altmans-openai">Empire of AI: Dreams and Nightmares in Sam Altman's OpenAI</a></li>
<li><a href="https://remysharp.com/books/2025/minority-rule-adventures-in-the-culture-war">Minority Rule: Adventures in the Culture War</a></li>
</ol>
<p>I'll see if I can rustle up my reading summary in the new year - though at 14 books, it's rather brief!</p>
<h3>Next bits - the retrospective</h3>
<p><a href="https://remysharp.com/2024/12/31/my-2024">Last year</a> I said I wanted to:</p>
<ul>
<li><strong>Increase my reading</strong> ✅ - in 2024 I read 13 books, this year I've read 14 (highly unlikely I'll finish the 15th in time!)</li>
<li><strong>Find the motivation to blog some more</strong> ❌ - I didn't find the motivation, though I did actually manage to blog more than 2024 (though still not my target of twice a month, every month)</li>
<li><strong>Hopefully some journalling will help</strong> 🤔 - I started strong, then slowed down to when I needed to put thoughts somewhere, to now… I can't remember the last time I wrote (and writing by pen is a slow process ofr me, my fingers can't keep up with the thoughts) - this one is a semi-fail</li>
<li><strong>Keep an eye on my health</strong> ✅ - this is a mixed bag really. The <abbr title="Multiple Sclerosis">MS</abbr> support here in Brighton is really good, so they regularly meet me to check things are okay (<abbr title="Magnetic resonance imaging">MRI</abbr> scans, drugs, etc). I <em>have</em> managed to return to the gym on a 2/3 times a week schedule. I had some physio that actually helped with some of my finger tip nerve issues (from <abbr title="Multiple Sclerosis">MS</abbr>) and it's improved the sensitivity for the first time in probably a decade. My diet…isn't terrible, but it's a far cry from dry chicken every day - I just think age is a reality I can't just ignore. On the other hand, my <a href="https://remysharp.com/2024/07/05/say-what-on-tinnitus-and-hearing">hearing aids</a> are superb and I love them.</li>
</ul>
<p>But hell, like I read somewhere on the web in the last week: 2026 is probably going to be a shitshow too, so don't be too hard on yourself.</p>
<p>This year, I'd like it if I found some way to get myself to write some more. I do wonder what software development is going to look like for me (particularly after how little code I've written from the ground up in the last 3 months). I'd like to keep up the reading and gym'ing. I'd like to get to bed earlier, and perhaps be a bit kinder inside my own head (to myself primarily). I want to ask &quot;can I help&quot; a lot more (if only to Julie) - it seems like a good mantra. I want to have fun with some stupid home assistant things. I want to design and build more PCBs and electronics projects (and perhaps improve my understanding).</p>
<p>And I'd really like to go to the cinema more. I miss the cinema. Maybe that'll be my thing in 2026 🤔</p>
<p>If you made it this far, thanks. If you're Remy reading this from the future - I hope things are looking up.</p>
<p>I'm now looking forward to reading your year-in-review blog posts, and I'll see you in The Future / 2026 💜</p>
<figure><img src="https://remysharp.com/images/family-2025.avif" alt="The family, growing up(wards)!" decoding="async"></figure>
<p><em>Originally published on <a href="https://remysharp.com/2025/12/31/my-2025">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>The Satsuma Complex (Gary Thorn, #1) [book]</title>
      <guid isPermaLink="false">the-satsuma-complex-gary-thorn-1</guid>
      <link>https://remysharp.com/books/2025/the-satsuma-complex-gary-thorn-1</link>
      <pubDate>Thu, 18 Dec 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[Light on the brain.
Just the kind of read I wanted after a few longer books. Not 100% even throughout the book - but I'll come to that.
The squirrel from the cover features a nice silly-ish part of the story where the main character will often run into a local squirrel and add his own voice in a back and forth between him and the squirrel. The sort of thing I'd expect from a Bob Mortimer book.
I'm not 100% sure where the book's tone is supposed to sit. Some parts are particularly dark - police corruption, police harassment and modern day slavery. Juxtaposed next to funny little things like socks, squeaky shoes, a cranky neighbour and dog who's constantly disappointed with our main character.
The pages did turn quickly though, and it was easy reading. Nothing particularly to shout about, but not bad either.]]></description>
      <content:encoded><![CDATA[<p>Light on the brain.</p>
<p>Just the kind of read I wanted after a few longer books. Not 100% even throughout the book - but I'll come to that.</p>
<p>The squirrel from the cover features a nice silly-ish part of the story where the main character will often run into a local squirrel and add his own voice in a back and forth between him and the squirrel. The sort of thing I'd expect from a Bob Mortimer book.</p>
<p>I'm not 100% sure where the book's tone is supposed to sit. Some parts are particularly dark - police corruption, police harassment and modern day slavery. Juxtaposed next to funny little things like socks, squeaky shoes, a cranky neighbour and dog who's constantly disappointed with our main character.</p>
<p>The pages did turn quickly though, and it was easy reading. Nothing particularly to shout about, but not bad either.</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2025/the-satsuma-complex-gary-thorn-1">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Butter [book]</title>
      <guid isPermaLink="false">butter</guid>
      <link>https://remysharp.com/books/2025/butter</link>
      <pubDate>Sat, 06 Dec 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[Made me hungry and could even smell the foods, but took me a long time to read which made it feel extremely stretched and disconnected.
I really don't know why this book took me nearly 60 days to read, but it did which makes the events at the start of the book feel so utterly far away from the end.
I'm not sure what drew me to the book but I picked it up with zero expectations.
It discusses feminism, the pressure society puts on women to behave and appear certain ways (though this is Japanese culture, I do think a lot of this applies/is experienced by western white women too).
There's a strong feature of food and butter in particular (as you'd expect from the title) - and the author (and translator) does an excellent job of writing in a way that left me reading late at night and really wanting to taste the food (and I'm not a foodie).
There's also a story of friendship and support through those connections. This part of the book was really lovely to read, but seemed to all be crammed in at the end.
The story also includes a very manipulative character, Kajii, and whilst I read I felt sorry (and frustrated) for the protagonist, Rika, that she couldn't see the obvious manipulation (but perhaps that's the point, when we're close up to manipulation, we can't see the wood for the trees).
There really is a lot (of meaty subjects) in this book, and perhaps this contributed to my slow reading but it did leave me struggling to carry all the ideas through to the end of the book.
I've written about urgency in writing, and that's what helps me turn the page. This book doesn't have that, which isn't bad, but doesn't help me.
I suspect I would have enjoyed this more had I been able to digest it a little faster than two months.]]></description>
      <content:encoded><![CDATA[<p>Made me hungry and could even smell the foods, but took me a long time to read which made it feel extremely stretched and disconnected.</p>
<p>I really don't know why this book took me nearly 60 days to read, but it did which makes the events at the start of the book feel so utterly far away from the end.</p>
<p>I'm not sure what drew me to the book but I picked it up with zero expectations.</p>
<p>It discusses feminism, the pressure society puts on women to behave and <em>appear</em> certain ways (though this is Japanese culture, I do think a lot of this applies/is experienced by western white women too).</p>
<p>There's a <strong>strong</strong> feature of food and butter in particular (as you'd expect from the title) - and the author (and translator) does an excellent job of writing in a way that left me reading late at night and <em>really</em> wanting to taste the food (and I'm not a foodie).</p>
<p>There's also a story of friendship and support through those connections. This part of the book was really lovely to read, but seemed to all be crammed in at the end.</p>
<p>The story also includes a very manipulative character, Kajii, and whilst I read I felt sorry (and frustrated) for the protagonist, Rika, that she couldn't see the obvious manipulation (but perhaps that's the point, when we're close up to manipulation, we can't see the wood for the trees).</p>
<p>There really is a lot (of meaty subjects) in this book, and perhaps this contributed to my slow reading but it did leave me struggling to carry all the ideas through to the end of the book.</p>
<p>I've written about <em>urgency</em> in writing, and that's what helps me turn the page. This book doesn't have that, which isn't bad, but doesn't help me.</p>
<p>I suspect I would have enjoyed this more had I been able to digest it a little faster than two months.</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2025/butter">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>An opportunity to learn: Advent of Code [blog]</title>
      <guid isPermaLink="false">an-opportunity-to-learn-advent-of-code</guid>
      <link>https://remysharp.com/2025/12/03/an-opportunity-to-learn-advent-of-code</link>
      <pubDate>Wed, 03 Dec 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[I've written about Advent of Code in the past, but that was 5 years ago, so this warrants a new post, and there's an extra opportunity, I think.]]></description>
      <content:encoded><![CDATA[<p>I've written about Advent of Code in <a href="https://remysharp.com/2020/12/01/the-advent-of-code">the past</a>, but that was 5 years ago, so this warrants a new post, and there's an extra opportunity, I think.</p>
<h2>The code calendar</h2>
<p>The advent of code is a daily code challenge, comprising of two parts based around the same problem, with increasing complexity. There's a wonderful little story that's weaved through the days, usually relating to Christmas and rouge elves that you can help.</p>
<p>I use it as a yearly chance to try to bend the <a href="https://jqlang.org/">jq language</a> into shapes it definitely wasn't intended for. It's another way of clearing out some of the cobwebs that gather in my head (<a href="https://github.com/remy/advent-of-code-solved/tree/main/2025">these are my attempts so far</a>).</p>
<p>Perhaps you're new to software development or a particular language, then this is a great way of having real problems to solve where there's an absolute answer. There's also a wealth of solutions posted up on the <a href="https://www.reddit.com/r/adventofcode/">Reddit channel</a> if you (or I) get stuck and need inspiration.</p>
<h2>Changes to the programme</h2>
<p>As of this year, there's now only 12 challenge days (previously it was 24 - one for each day until Christmas eve). For me this is welcomed, partly because I'd usually break by day 16, but also, I'm not sure I want to spend hours tinkering on a hard problem on Christmas eve (having never gotten past 16, I hadn't yet!).</p>
<p>The global leaderboard has also been removed. I personally never made it anywhere near the leaderboard, but some people would obsess over it. Sadly, with the rise and ease of access of AI tools, it meant quickly the time from challenge release to posting a correct answer started turning up in seconds long. That's single digit seconds to solve the problem - which really isn't in the spirit at all.</p>
<p>AI was banned/asked to not join in with the leaderboard, but completely removing the global leaderboard completely takes the pressure off (and that idea that &quot;why can't I solve it that fast&quot;).</p>
<p>You <em>can</em> still create a leaderboard for your friends or team - which makes sense.</p>
<h2>Speaking of AI</h2>
<p>Here's where my final suggestion might be controversial: why not try to solve using AI?</p>
<p>By that, I mean, if you're in a similar camp as me and have been sceptical of AI and a little wary, this might be a good opportunity to dip your toe in. I don't mean to paste in the challenge and have AI spit out the answer - that doesn't help anyone.</p>
<p>It could be seen as a chance to practise controlling the context and the problem space with AI doing the work. Perhaps testing different models from providers, but perhaps trying out local LLM models to see if they can do the work (so perhaps we could be a little more in control of the power usage).</p>
<p>As for me, I'm having to <em>actively</em> disable copilot in VS Code when solving the advent of code, because it's so desperate to help me!</p>
<p><em>Originally published on <a href="https://remysharp.com/2025/12/03/an-opportunity-to-learn-advent-of-code">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Handing over to the AI for a day [blog]</title>
      <guid isPermaLink="false">handing-over-to-the-ai-for-a-day</guid>
      <link>https://remysharp.com/2025/11/29/handing-over-to-the-ai-for-a-day</link>
      <pubDate>Sat, 29 Nov 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[Context: back in March 2025 I decided to put aside my scepticism and try AI driven development for the day. I appreciate that in 8 months, the AI landscape, particularly around agentic software dev has moved along, and perhaps this should have been posted originally back in March. All the same, maybe this is useful to some degree, if only to capture what it was like in time.

Whilst I sit squarely in my AI-sceptic seat, I was recently prompted to try a different tact by two post I read a few weeks back.
The first was Bruce's colonoscopy post, yes, that one. It was in fact that he was using a local LLM to create a generative image to commemorate his visit. I'd been using chatgpt (for code and electronics, basically a NLP version of a search engine), and hadn't considered that perhaps I could host myself to take some responsibility for one of the two problematic aspects of LLMs today (first being power consumption, second being the global theft).
The second post was Simon Willison's post on how he created a mini tool (the post is much broader than that, a useful read). It wasn't the post so much but the tool he was using: Claude Code. So far with chatgpt I'd copy back and forth errors and tweaks when it was helping me. Although I also have copilot enabled in VS Code it really holds down to autocomplete at a pretty junior level.
I'll often have typescript errors (for work) that copilot claims it can help fix, only resulting in even more typescript errors - so as a rule, I tend to avoid generating code fixes with copilot.
But what Simon showed with a shared transcript between himself and Claude Code was the software making the changes and offering diffs.
So that was what prompted a mini journey, and here's how it went.
Offline LLMs
Previously I had installed command line tools and even Ollama on my Mac without having the faintest idea how to use them effectively - so they sat idle and unused.
I'm not sure how, but I came across Msty, a tool that purported to make using local LLMs very easy. For a change, that seems to be true.
Since I still had Ollama running (though I should have probably ejected it), Msty quickly linked up to this and discovered (though I'd forgotten) that the DeepSeek R1 model was loaded already.
I figured since I was primarily using LLMs for software development, it made sense to find a model that suited those requirements.
Not quite that simple, or certainly not if you (ie. me) doesn't have the LLM lingo and terminology down.
I did some searching online, found a few articles, which themselves read as if they had been generated by AI, offering feature reviews of LLM models, but I couldn't find anything that said &quot;model X is excellent for Y software development&quot;.
Additionally, I found some models on huggingface.io, and figured that 7B was going to be easier/more viable to run than a 70B (big numbers need big machines? I was guessing…). However putting the name of the model into Myst yielded a lot of results and I couldn't really tell you what the difference was. More importantly, I couldn't quite be sure of the provenance (and whether that even matters…I'd assume it did).
I ended up installing the following models:

llama 3.2 (2gb)
deepseek coder v2 (which blew up)
codellama (3.8gb)
codellama 13b
WizardCoder (I think the 3gb one?) (it just didn't reply on the query)
Wavecoder-ultra-6.7b (literally never worked for me)

I tried a number of technical problems without much success and did capture the output for a number of these models to try to solve a Home Assistant automation process (which you can see here).
It's entirely likely there's better models out there for what I wanted to do. I did know I didn't need a model to know everything, so some focus (and thus: reduced size) would make sense.
However, not one of these gave useful replies to my questions.
My favourite (fail) was giving code-llama a question that read: this query gets all the lessons matching these lesson slugs (I gave it the actual SQL query), how do I get a list of all the slugs that didn't match?.
The LLM happily reported that I was trying to learn Spanish:

The provided code contains a list of sentences that are written in Spanish, and the goal is to translate them into English. However, there are some errors in the provided code that need to be fixed before it can function properly. Here are some issues with the current code:
Missing curly braces around the translate function definition: The translate function should be defined as a separate named function expression, like this: { translate } = require(&quot;google-translate&quot;);. This will ensure that the function is properly closed and can be used in other parts of the code.

For some reason it was using the slugs in the query as the most important part and completely ignoring the technical query.
For the most part, the responses I got were fairly hand wavy, text heavy (which I didn't want since I was asking about code), and in most cases irrelevant to my task.
I think em0ry42 on BlueSky sums up what I was seeing:

Smaller self hosted models will always under perform the larger ones. I think your experience and those of the other commenters are consistent with the current reality of these technologies. They can't do what people are promising. Yet.

I'm sure there are people who can tune the hell out of their setup, but sadly, running any decent LLM locally as a useful code assistant, is just not here for the rest of us.
So I parked that for a while, and turned my attention to Claude Code.
Coding without touching code
I've no clue how new Claude Code was at the time, though I've gathered it's fairly new. It's a solid product from my experience (where I even managed to lose track as to which company owns which weirdly named AI thingy).
Setup and interface is entirely on the command line, so already we're speaking my language.
I'd seen demos of developers who've been able to join up their entire codebase to the LLM but each time I'd dabbling, I would quickly get lost and give up.
Claude Code does exactly this without the walls I'd experienced in the past.
I am however, acutely wary that Claude is running on a remote machine, and likely to be chonking through so much power that we're just throwing away water to keep machines from burning up. Let's stick a pin in that (and gosh, I loath myself already for that).
The very first problem I wanted it to solve was where I was trying to download 1,000s of videos and they all needed to be added to one massive tarball (context: this is for work, to allow users to bulk download our assets).
I'd hit a problem where the tar process kept throwing an unhelpful exception the evening before and no amount of documentation on the library I was using helped me.
Overnight I had a suspicion as to the cause and it gave me an idea to try - but I thought I'd let Claude try first, see what it does.
Without any specific direction (ie. my idea for the fix), and only the name of the file and the function the problem happened, Claude Code suggested the same solution I had in my head.
The UI then offered a syntax highlighted diff of the change it wanted to commit to disk. I was able to review it (very much how I'd approach a code review) and all I then needed to do was hit enter to accept.
I tested the code in a separate terminal and indeed the change worked.
Given this positive start, I then spent most of the working time split between the Claude Code UI and in the terminal to run the main program (which was sequencing a very large dataset).
The code changes for the most part were always good and code that I accepted.
The experience was…weird. I'd heard of LLMs being referred to as junior developers but when I was going back and forth between chatgpt and vscode (again, for me, copilot never really came in useful), because of the amount of interaction that was required from me, it felt even less than working with a junior.
But this was a much closer experience. I'd describe the change and logic, sometimes pointing to filenames that would offer useful context, and Claude would spend some time (and money) thinking, then it would ask me to check a diff.
Weirdly I spent more time sitting and staring out the window waiting for code to come back than I did looking at code. It was a weirdly hands off experience. I can't tell where I sit on that.
The main criticism that I had is that, because we use specific rules for typescript (no any and types are defined, which I think seems okay), Claude wouldn't really follow those strict rules, so I needed to go in at the end to clean that part up.
The secondary criticism is more a matter of taste. The code (and logging) was verbose to my taste. Additionally, being outside the code for the majority of the work period felt really strange. Sort of like a self-driving car took me the majority of my journey, deciding itself the navigation, for me only to be needed for the final arrival through some tight country lanes. Or something!
A cost
Since I was freestyling my way on Claude Code, I did manage to rattle through $5 of credit. I did think this was (somehow) linked to my Google business account, but I'm now suspecting it was free credit to introduce me to their API.
After running through this credit now twice (I switched to my personal account for a second run) I've discovered there's tools to help manage that sprawling cost (such as /compact and /clear to reduce how much context the LLM is fed before giving me a result). I'd like to play with this more to get an idea of how much I'm really prepared to pay.
Also after writing (most of) this post, I came across an interesting project that takes the Claude UI and lets you connect up your own backend. I've not tried it yet, but I'd be interested to see if I can connect to a local LLM and try out results (though going by the current experience, it's going to have a hard time competing).
Since it was conversational...
I decided to hack together a simple keyboard keycap (I had spare) with an ESP32 board to emulate a keyboard.
Then this would send a (fairly) unique keycode that then launched a python command which started a whisper based script that let me talk, then pasted the text into whatever was focused.
This meant I had: press button, say the thing, press the button, wait for it to be done.
It wasn't great because it was a little clunky, but it definitely felt futuristic!
How I felt afterwards
(I'm now writing this 8 months late, but I remember how it felt on the day).
Even though I was surprised at the progress of the work, both for how terrible the local code solving was and how impressed I was with Claude Code - it did leave me with a feeling of disconnect.
There's certainly the issue with the maintainability of pure vibe-coded software, but this was something more.
There's a creative input that I put into my coding process. A sense of purpose and achievement in solving some complicated problem, or writing a line of code that I'm particularly pleased with. There wasn't really of that feeling of connection with the output.
Having written this retrospectively I know that my perspective has changed somewhat, but I do remember have this weird dissonance between the outcome and the experience of getting there.]]></description>
      <content:encoded><![CDATA[
<p><em><strong>Context</strong>: back in March 2025 I decided to put aside my scepticism and try AI driven development for the day. I appreciate that in 8 months, the AI landscape, particularly around agentic software dev has moved along, and perhaps this should have been posted originally back in March. All the same, maybe this is useful to some degree, if only to capture what it was like in time.</em></p>
<hr>
<p>Whilst I sit squarely in my AI-sceptic seat, I was recently prompted to try a different tact by two post I read a few weeks back.</p>
<p>The first was Bruce's <a href="https://brucelawson.co.uk/2025/colonoscopy-fun/">colonoscopy post</a>, yes, that one. It was in fact that he was using a <em>local</em> LLM to create a generative image to commemorate his visit. I'd been using chatgpt (for code and electronics, basically a NLP version of a search engine), and hadn't considered that perhaps I could host myself to take some responsibility for one of the two problematic aspects of LLMs today (first being power consumption, second being the global theft).</p>
<p>The second post was Simon Willison's post on <a href="https://simonwillison.net/2025/Mar/11/using-llms-for-code/#a-detailed-example">how he created a mini tool</a> (the post is much broader than that, a useful read). It wasn't the post so much but the tool he was using: Claude Code. So far with chatgpt I'd copy back and forth errors and tweaks when it was helping me. Although I also have copilot enabled in VS Code it really holds down to autocomplete at a pretty junior level.</p>
<p>I'll often have typescript errors (for work) that copilot claims it can help fix, only resulting in even more typescript errors - so as a rule, I tend to avoid generating code fixes with copilot.</p>
<p>But what Simon showed with a shared transcript between himself and Claude Code was the software making the changes and offering diffs.</p>
<p>So that was what prompted a mini journey, and here's how it went.</p>
<h2>Offline LLMs</h2>
<p>Previously I had installed command line tools and even Ollama on my Mac without having the faintest idea how to use them effectively - so they sat idle and unused.</p>
<p>I'm not sure how, but I came across <a href="https://msty.app/">Msty</a>, a tool that purported to make using local LLMs very easy. For a change, that seems to be true.</p>
<p>Since I still had Ollama running (though I should have probably ejected it), Msty quickly linked up to this and discovered (though I'd forgotten) that the DeepSeek R1 model was loaded already.</p>
<p>I figured since I was primarily using LLMs for software development, it made sense to find a model that suited those requirements.</p>
<p>Not quite that simple, or certainly not if you (ie. me) doesn't have the LLM lingo and terminology down.</p>
<p>I did some searching online, found a few articles, which themselves read as if they had been generated by AI, offering feature reviews of LLM models, but I couldn't find anything that said &quot;model X is excellent for Y software development&quot;.</p>
<p>Additionally, I found some models on <a href="http://huggingface.io">huggingface.io</a>, and figured that 7B was going to be easier/more viable to run than a 70B (big numbers need big machines? I was guessing…). However putting the name of the model into Myst yielded <em>a lot</em> of results and I couldn't really tell you what the difference was. More importantly, I couldn't quite be sure of the provenance (and whether that even matters…I'd assume it did).</p>
<p>I ended up installing the following models:</p>
<ol>
<li>llama 3.2 (2gb)</li>
<li>deepseek coder v2 (which blew up)</li>
<li>codellama (3.8gb)</li>
<li>codellama 13b</li>
<li>WizardCoder (I think the 3gb one?) (it just didn't reply on the query)</li>
<li>Wavecoder-ultra-6.7b (literally never worked for me)</li>
</ol>
<p>I tried a number of technical problems without much success and did capture the output for a number of these models to try to solve a Home Assistant automation process (which <a href="https://gist.github.com/remy/76d5761b57a5d42f781b74c072d22139">you can see here</a>).</p>
<p>It's entirely likely there's better models out there for what I wanted to do. I did know I didn't need a model to know everything, so some focus (and thus: reduced size) would make sense.</p>
<p>However, not one of these gave useful replies to my questions.</p>
<p>My favourite (fail) was giving code-llama a question that read: this query gets all the lessons matching these lesson slugs (I gave it the actual SQL query), how do I get a list of all the slugs that <strong>didn't</strong> match?.</p>
<p>The LLM happily reported that I was trying to learn Spanish:</p>
<blockquote>
<p>The provided code contains a list of sentences that are written in Spanish, and the goal is to translate them into English. However, there are some errors in the provided code that need to be fixed before it can function properly. Here are some issues with the current code:</p>
<p>Missing curly braces around the translate function definition: The translate function should be defined as a separate named function expression, like this: { translate } = require(&quot;google-translate&quot;);. This will ensure that the function is properly closed and can be used in other parts of the code.</p>
</blockquote>
<p>For some reason it was using the slugs in the query as the most important part and completely ignoring the technical query.</p>
<p>For the most part, the responses I got were fairly hand wavy, text heavy (which I didn't want since I was asking about code), and in most cases irrelevant to my task.</p>
<p>I think <a href="https://bsky.app/profile/em0ry42.penney-family.net/post/3lkdpqaouc22h">em0ry42 on BlueSky</a> sums up what I was seeing:</p>
<blockquote>
<p>Smaller self hosted models will always under perform the larger ones. I think your experience and those of the other commenters are consistent with the current reality of these technologies. They can't do what people are promising. Yet.</p>
</blockquote>
<p>I'm sure there are people who can tune the hell out of their setup, but sadly, running any decent LLM locally as a useful code assistant, is just not here for the rest of us.</p>
<p>So I parked that for a while, and turned my attention to <a href="https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview">Claude Code</a>.</p>
<h2>Coding without touching code</h2>
<p>I've no clue how new Claude Code was at the time, though I've gathered it's <em>fairly</em> new. It's a solid product from my experience (where I even managed to lose track as to which company owns which weirdly named AI thingy).</p>
<p>Setup and interface is entirely on the command line, so already we're speaking my language.</p>
<p>I'd seen demos of developers who've been able to join up their entire codebase to the LLM but each time I'd dabbling, I would quickly get lost and give up.</p>
<p>Claude Code does exactly this without the walls I'd experienced in the past.</p>
<p>I am however, acutely wary that Claude <em>is</em> running on a remote machine, and likely to be chonking through so much power that we're just <a href="https://m.youtube.com/shorts/PSe6GSwJ0cI">throwing away water</a> to keep machines from burning up. Let's stick a pin in that (and gosh, I loath myself already for that).</p>
<p>The very first problem I wanted it to solve was where I was trying to download 1,000s of videos and they all needed to be added to one massive tarball (context: this is for work, to allow users to bulk download our assets).</p>
<p>I'd hit a problem where the tar process kept throwing an unhelpful exception the evening before and no amount of documentation on the library I was using helped me.</p>
<p>Overnight I had a suspicion as to the cause and it gave me an idea to try - but I thought I'd let Claude try first, see what it does.</p>
<p>Without any specific direction (ie. my idea for the fix), and only the name of the file and the function the problem happened, Claude Code suggested the same solution I had in my head.</p>
<p>The UI then offered a syntax highlighted diff of the change it wanted to commit to disk. I was able to review it (very much how I'd approach a code review) and all I then needed to do was hit enter to accept.</p>
<p>I tested the code in a separate terminal and indeed the change worked.</p>
<p>Given this positive start, I then spent most of the working time split between the Claude Code UI and in the terminal to run the main program (which was sequencing a very large dataset).</p>
<p>The code changes for the most part were always good and code that I accepted.</p>
<p>The experience was…weird. I'd heard of LLMs being referred to as junior developers but when I was going back and forth between chatgpt and vscode (again, for me, copilot never really came in useful), because of the amount of interaction that was required from me, it felt even less than working with a junior.</p>
<p>But this was a much closer experience. I'd describe the change and logic, sometimes pointing to filenames that would offer useful context, and Claude would spend some time (and money) thinking, then it would ask me to check a diff.</p>
<p>Weirdly I spent more time sitting and staring out the window waiting for code to come back than I did looking at code. It was a weirdly hands off experience. I can't tell where I sit on that.</p>
<p>The main criticism that I had is that, because we use specific rules for typescript (no <code>any</code> and types are defined, which I think seems okay), Claude wouldn't really follow those strict rules, so I needed to go in at the end to clean that part up.</p>
<p>The secondary criticism is more a matter of taste. The code (and logging) was verbose to my taste. Additionally, being outside the code for the majority of the work period felt really strange. Sort of like a self-driving car took me the majority of my journey, deciding itself the navigation, for me only to be needed for the final arrival through some tight country lanes. Or something!</p>
<h2>A cost</h2>
<p>Since I was freestyling my way on Claude Code, I did manage to rattle through $5 of credit. I did think this was (somehow) linked to my Google business account, but I'm now suspecting it was free credit to introduce me to their API.</p>
<p>After running through this credit now twice (I switched to my personal account for a second run) I've discovered there's tools to help manage that sprawling cost (such as <code>/compact</code> and <code>/clear</code> to reduce how much context the LLM is fed before giving me a result). I'd like to play with this more to get an idea of how much I'm <em>really</em> prepared to pay.</p>
<p>Also after writing (most of) this post, I came across an interesting project that takes the <a href="https://github.com/dnakov/anon-kode">Claude UI and lets you connect up your own backend</a>. I've not tried it yet, but I'd be interested to see if I can connect to a local LLM and try out results (though going by the current experience, it's going to have a hard time competing).</p>
<h2>Since it was conversational...</h2>
<p>I decided to hack together a simple keyboard keycap (I had spare) with an ESP32 board to emulate a keyboard.</p>
<p>Then this would send a (fairly) unique keycode that then launched a python command which started a whisper based script that let me talk, then pasted the text into whatever was focused.</p>
<p>This meant I had: press button, say the thing, press the button, wait for it to be done.</p>
<p>It wasn't great because it was a little clunky, but it definitely felt futuristic!</p>
<h2>How I felt afterwards</h2>
<p>(I'm now writing this 8 months late, but I remember how it felt on the day).</p>
<p>Even though I was surprised at the progress of the work, both for how terrible the local code solving was and how impressed I was with Claude Code - it did leave me with a feeling of disconnect.</p>
<p>There's certainly the issue with the <a href="https://remysharp.com/2025/07/18/vibe-coding-and-robocop">maintainability of pure vibe-coded software</a>, but this was something more.</p>
<p>There's a creative input that I put into my coding process. A sense of purpose and achievement in solving some complicated problem, or writing a line of code that I'm particularly pleased with. There wasn't really of that feeling of connection with the output.</p>
<p>Having written this retrospectively I know that my perspective has changed somewhat, but I do remember have this weird dissonance between the outcome and the experience of getting there.</p>
<p><em>Originally published on <a href="https://remysharp.com/2025/11/29/handing-over-to-the-ai-for-a-day">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>FFConf 2025 [blog]</title>
      <guid isPermaLink="false">ffconf-2025</guid>
      <link>https://remysharp.com/2025/11/22/ffconf-2025</link>
      <pubDate>Sat, 22 Nov 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[I've been wanting to write and share my experience of this year's event but a number of things have slowed me down - not least of all that it was Julie's birthday the following Tuesday (the first year her birthday was entirely swallowed by the event).
So now as I sit writing this a full eight days later - sat on the side of the swimming pool as many kids, including my own, do their swimming lessons - I'm trying to collect my thoughts on the day.]]></description>
      <content:encoded><![CDATA[
<p>I've been wanting to write and share my experience of this year's event but a number of things have slowed me down - not least of all that it was Julie's birthday the following Tuesday (the first year her birthday was entirely swallowed by the event).</p>
<p>So now as I sit writing this a full eight days later - sat on the side of the swimming pool as many kids, including my own, do their swimming lessons - I'm trying to collect my thoughts on the day.</p>
<h2>The talks</h2>
<p>Every year it's always an amazing experience, hearing the stories of speakers from across different walks of life.</p>
<p>The videos of the talks will be released in the coming weeks and <a href="https://ffconf.org/news">our newsletter</a> will highlight each in turn.</p>
<p>I curated the talks so that up front we had the heavier subjects: diversity from <a href="https://2025.ffconf.org/hellen">Hellen</a> and data privacy from <a href="https://2025.ffconf.org/chetan">Chetan</a>.</p>
<p>From the evening before we were talking about JavaScript, React, standards and new developers coming to the industry. We were talking specifically about whether the lessons had been learnt from the past or needed to be repeated.</p>
<p>I'm of the belief (though only in the last decade) that we need to repeat the learnings over and over and over. There's no point when the teaching is done. A fun example of this is seeing the CSS creative coders having their hay-day whilst hearing from the sidelines that the Flash developers have already done a lot of this. It's not new. But if you don't continue to pass down your lessons, the next generations will make the same mistakes and have to learn from scratch.</p>
<p>That's a very long way to say that we've covered the subjects of diversity and privacy before, but new perspectives and different experiences keep the subjects fresh and not a &quot;done&quot; task in the world of the web worker.</p>
<p>The next segment talked about web components from <a href="https://2025.ffconf.org/hannah">Hannah</a> and about cults from <a href="https://2025.ffconf.org/serges">Sèrges</a>.</p>
<p>Hannah talked about her experience bringing web components to a React based team and the process integration both from the software side but also from the team adoption perspective.</p>
<p>Unsurprisingly (see previous notes on curation 😉) Sèrges brilliant (fun and funny) talk about cults dovetailed perfectly into Hannah's talk. She argued that we're all in a cult (to some degree) and touched on the gatekeeping that was also touched on in Helen's talk about team diversity.</p>
<p>Post lunch was time to discuss AI. When friends of mine who know me from outside the web, as about the conference, they understandably assume it's all about AI. It's all we hear about these days.</p>
<p>The two talks were very different perspectives on AI. <a href="https://2025.ffconf.org/asim">Asim</a> gave a talk (obscurely but made sense in the end) entitled Don't be an Idiot on how AI can, and is, being used to democratise big decisions, putting much more nuance in the decisions offered to people.</p>
<p>The following was <a href="https://2025.ffconf.org/jessica-eda">Jess and Eda</a> on AI coding tools and skills. Told from the perspective of a senior and junior and what are the lasting impacts on relying (or being pushed into) AI tools. Very much the argument of shallow learning versus deep (human) learning through experience.</p>
<p>Finally to close the event two talks from the vast spread of experience starting with <a href="https://2025.ffconf.org/surya">Surya</a> on the journey of 6 to 16 years old and coding. As our industry continues to exist, it's the young people who will breathe life into it, so I wanted to hear about Surya's experience (even if he is a bit of a black swan - making many of us old hats feel rather like underachievers!).</p>
<p>Then to close, we (FFConf) were lucky to have <a href="https://2025.ffconf.org/sacha">Sacha Judd</a> (because she resides in New Zealand and it's a long old journey) filling our hearts with the joy of what the Good Internet is. Not just a nostalgic memory but alive today and just as weird as always.</p>
<p>Here are all <a href="https://www.flickr.com/photos/remysharp/albums/72177720330509685/">the photos from FFConf 2025</a> if you'd like to see the lovely time people had.</p>
<figure><img src="https://remysharp.com/images/ffconf-2025.avif" alt="The people attending FFConf waving for the camera" decoding="async"></figure>
<h2>Looking for meaning</h2>
<p>The last few years of FFconf have been hard for me to put into context in a world that honestly frightens me. War. Genocide. Famine. Racism. Fascism. Hate. They're alive and well.</p>
<p>Sometimes I think it's ridiculous to put on a web event when things outside are so hard on people. In part it feels like a horrible privilege to be able to sink my head down and listen to these amazing speakers.</p>
<p>On reflection though, I do believe we need to recharge. That we need a little self care if we're going to continue fighting for a fair and equal world, however we achieve it. So maybe that's important for FFConf.</p>
<p>At the top of the event, I asked everyone to try to find one thing that you'll take away. There's so much in a day of talks - it's hard to remember what got you excited in the earlier talks let alone make sweeping changes.</p>
<p>So the (first) one thing I decided to do, relatively simple, was to move to more paid services (I've switched to <a href="https://kagi.com/">Kagi</a> already). I've already started paying for my news (<a href="https://www.404media.co/">404 Media</a>, <a href="https://novaramedia.com/">Novara Media</a>, Guardian and a few others) so I'm continuing to look for these. I also know that this works if you have the funds. For me, it's part of my work, so my business pays for it. I get that it's not as simple for others (that's to say: this is <em>my</em> one thing!).</p>
<p>In my back pocket I'm going to make myself some either silly or partially useful little toys. I may or may not share these; I like that these can be for me and family/friends: low pressure nonsense.</p>
<h2>Next</h2>
<p>FFConf will return next year, Friday 13 November. I've already got a couple of speakers in mind so I need to approach them with my proposals.</p>
<p>I'll be attending more events myself next year too, including <a href="https://2026.stateofthebrowser.com/">State of the Browser</a>, <a href="https://webdayout.com/">Web Day Out</a>, (the final) <a href="https://heypresents.com/conferences/2026">All Day Hey</a>, <a href="https://beyondtellerrand.com/events/dusseldorf-2026">Beyond Tellerand</a> and <a href="https://webdevconf.com/events/">WDC</a> (tickets aren't live yet). I'm on the lookout for more events and meet ups in particular (though I have a stinking record of staying at home).</p>
<p>I know this might read as a hopeful note, and I do want it to be, but I also know that I don't 100% buy my written down optimism (I should!). Still, I hope to see you out there.</p>
<p><em>Originally published on <a href="https://remysharp.com/2025/11/22/ffconf-2025">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Building an AI Sandbox with Docker [link]</title>
      <guid isPermaLink="false">2025-11-12-dac6ad4b</guid>
      <link>https://remysharp.com/links/2025-11-12-dac6ad4b</link>
      <pubDate>Wed, 12 Nov 2025 14:08:00 +0000</pubDate>
      <description><![CDATA[As I think about how command line AI tools can be used, I know it's already a bit of the wild west not disimilar to the way we install npm modules. I've seen a bit of writing about how these tools should be run in a controlled sandbox (because they can mess with the surroudning environment), and this is a nice digestable post with working examplse of Dockerfiles.
Source: thingsithinkithink.blog]]></description>
      <content:encoded><![CDATA[
<p>As I think about how command line AI tools can be used, I know it's already a bit of the wild west not disimilar to the way we install npm modules. I've seen a bit of writing about how these tools should be run in a controlled sandbox (because they can mess with the surroudning environment), and this is a nice digestable post with working examplse of Dockerfiles.</p>
<p><em>Source: <a href="https://thingsithinkithink.blog/posts/2025/11-11-building-an-ai-sandbox-with-docker/">thingsithinkithink.blog</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2025-11-12-dac6ad4b">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Syntax Highlighting in Web Component Templates [blog]</title>
      <guid isPermaLink="false">syntax-highlighting-in-web-component-templates</guid>
      <link>https://remysharp.com/2025/11/12/syntax-highlighting-in-web-component-templates</link>
      <pubDate>Wed, 12 Nov 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[A simple but effective fix to working with web components and VS Code. I wanted to get syntax highlighting and prettier support (to auto fix indenting, quotes, etc) in my component's templates.
The extremely quick read is, add /* HTML */ to the front of the template. Case sensitive and space sensitive (though hopefully one day it won't be so strict). Now highlighting and prettier (with save and fix) works.
Note that you need the es6-string-html VS Code extension for this to highlight correct (something I had forgotten I had installed).]]></description>
      <content:encoded><![CDATA[
<p>A simple but effective fix to working with web components and VS Code. I wanted to get syntax highlighting <em>and</em> prettier support (to auto fix indenting, quotes, etc) in my component's templates.</p>
<p>The extremely quick read is, add <code>/* HTML */</code> to the front of the template. Case sensitive <em>and</em> space sensitive (though hopefully one day it won't be so strict). Now highlighting and prettier (with save and fix) works.</p>
<p>Note that you need the <a href="https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html">es6-string-html</a> VS Code extension for this to highlight correct (something I had forgotten I had installed).</p>
<h2>The slightly longer read</h2>
<p>What I wanted to achieve was that I could include my template in the source of the web component (or at least in the same directory - i.e. physically near to the application logic).</p>
<p>The problem is that unless I use a build function (or tools), the markup for the template is a string.</p>
<p>Here's the starting point:</p>
<pre><code class="language-js">customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span>
  <span class="token string">'hello-world'</span><span class="token punctuation">,</span>
  <span class="token keyword">class</span> <span class="token class-name">extends</span> HTMLElement <span class="token punctuation">{</span>
    <span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> n <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">'name'</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token string">'World'</span><span class="token punctuation">;</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">attachShadow</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'open'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
      &lt;style>:host{font:600 16px system-ui;color:#222}&lt;/style>
      &lt;div>Hello, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>n<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> 👋&lt;/div></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Seen here with VS Code's syntax highlighting - note that the template itself is just green, plain text:</p>
<figure><img src="https://remysharp.com/images/template-highlight-0.png.avif" alt="Although the JavaScript is highlighted, the string of markup applied to the innerHTML is all in green" decoding="async"></figure>
<p>Using a tag function solves the main issue, but requires extra code or a <em>magic</em> build process which I really don't want or need - and look at that nasty red snake telling me I need to write more code:</p>
<figure><img src="https://remysharp.com/images/template-highlight-2.png.avif" alt="The syntax is nice and tidy now using a tag function, but my linting is highlighted that the html function is missing" decoding="async"></figure>
<p>VS Code does support highlighting if you give it a hint using a comment: <code>/*html*/</code>, but prettier doesn't format it - close, but still no dice:</p>
<figure><img src="https://remysharp.com/images/template-highlight-1.png.avif" alt="The syntax is now fully colourised, but not structured in a way that's nice and easy to read" decoding="async"></figure>
<p>Finally, if you get the comment syntax <em>exactly</em> right, that's uppercase and with spaces around the text, <code>/* HTML */</code>, then you'll get both highlighting and syntax tidy support without the need for build tools:</p>
<figure><img src="https://remysharp.com/images/template-highlight-3.png.avif" alt="The syntax is now fully colourised and it's tidy" decoding="async"></figure>
<p>I do have the VS Code option <code>&quot;prettier.embeddedLanguageFormatting&quot;: &quot;auto&quot;</code> in my settings, but if I've understood correctly, this should be the default for prettier and not required.</p>
<p>A large hat tip to <a href="https://front-end.social/@zzzzBov/115535106033886819">Timothy Leverett on Mastodon</a> for helping me.</p>
<p><em>Originally published on <a href="https://remysharp.com/2025/11/12/syntax-highlighting-in-web-component-templates">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Automerge [link]</title>
      <guid isPermaLink="false">2025-11-04-aeb3d7b3</guid>
      <link>https://remysharp.com/links/2025-11-04-aeb3d7b3</link>
      <pubDate>Tue, 04 Nov 2025 12:47:22 +0000</pubDate>
      <description><![CDATA[Version control for your data: Automerge is a local-first sync engine for multiplayer apps that works offline, prevents conflicts, and runs fast. Interesting project, possibly for mini personal projects that want to share some data (possibly without a database? unsure). But also in some kind of collaborative code editor, ala codecasting from JS Bin old days. Beautifully designed landing page though.
Source: automerge.org]]></description>
      <content:encoded><![CDATA[
<p>Version control for your data: Automerge is a local-first sync engine for multiplayer apps that works offline, prevents conflicts, and runs fast. Interesting project, possibly for mini personal projects that want to share some data (possibly without a database? unsure). But also in some kind of collaborative code editor, ala codecasting from JS Bin old days. Beautifully designed landing page though.</p>
<p><em>Source: <a href="https://automerge.org/">automerge.org</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2025-11-04-aeb3d7b3">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>How has FFConf changed since it was known as Full Frontal? [blog]</title>
      <guid isPermaLink="false">how-has-ffconf-changed-since-it-was-known-as-full-frontal</guid>
      <link>https://remysharp.com/2025/10/27/how-has-ffconf-changed-since-it-was-known-as-full-frontal</link>
      <pubDate>Mon, 27 Oct 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[Besides the name, the entire core foundation has changed.
This question came up recently by someone who had either attended back in the early days or that knew of our event, but they (understandably) saw us as it was in 2009.
I think the vibes you came away with in the 2009 and 2010 events would be recognised, but content and the core messaging has changed quite significantly.]]></description>
      <content:encoded><![CDATA[
<p>Besides the <a href="https://remysharp.com/2016/07/22/whats-in-a-name">name</a>, the entire core foundation has changed.</p>
<p>This question came up recently by someone who had either attended back in the early days or that knew of our event, but they (understandably) saw us as it was in 2009.</p>
<p>I think the vibes you came away with in the 2009 and 2010 events would be recognised, but content and the core messaging has changed quite significantly.</p>
<p>The event was founded on the premise that there weren’t any (dedicated) JavaScript conferences in the UK at the time, and I wanted <em>something</em> to fulfil my own desire to see that change. I wanted an event that I would want to attend.</p>
<p>The first line up in 2009 was mostly brought about by asking the question: who do I know or could reach that talk about JavaScript things? I can’t say for certain, but I suspect the outreach was &quot;can you speak&quot; rather than &quot;can you speak about…&quot;.</p>
<p>Immediately I knew I wanted a rule that prevented speakers from repeating (this was a preventative measure to get me to reach outside of my circles).</p>
<p>The follow 2010 event still had a JavaScript flavour but was already showing signs of morphing into something different (albeit I wouldn’t start working on the diversity until 2012).</p>
<p>I remember Dan Webb (who spoke in 2010) saying that he realised at the end of the event he was the only speaker to show code in his slides.</p>
<p>By 2018, the 10th conference, I think the entire shape had changed. Talks like <a href="https://ffconf.org/talks/mentoring/">&quot;Mentoring: Being the help you wish you'd had&quot;</a>, <a href="https://ffconf.org/talks/dear-developer/">&quot;Dear Developer, the Web Isn't About You&quot;</a> and <a href="https://ffconf.org/talks/weird-web">&quot;Weird Web &amp; Curious Creation&quot;</a> were all based in the idea of helping others and ourselves to become better Web Citizens.</p>
<p>People who had attended told me that the talks they saw at FFConf were talks they never expected to see - in a positive way. <a href="https://ffconf.org/talks/2022_heydonworks_talk/">&quot;Capitalism, The Web, And You&quot;</a> was an excellent example of that in 2019 along with <a href="https://ffconf.org/talks/2022_lil_natw_talk/">&quot;Working towards a greener world from behind the keyboard&quot;</a> or <a href="https://ffconf.org/talks/2022_lily_2point0_talk/">&quot;Programming with Yarn&quot;</a> (although I've only included 3 talks, they're all superb, or certainly to me).</p>
<p>The talks at FFConf continue along this line of thinking. How can we learn to be better versions of ourselves - and so that we can help others.</p>
<p>From the talks on the day, you won't learn how to add aria roles to a tabbing system, but you will learn how your junior developers are being affected by learning from LLMs spouting code at them. You won't learn what the latest additions to JavaScript syntax is, but you will learn how the latest technology has been used to exploit your privacy and the ethics of how developers' decisions landed them there.</p>
<p>You won't learn what a blog post, a tiktok or chatgpt can give you. You'll come away inspired and fired up and (hopefully, usually!) excited to work. It's a hard one to measure, and hard to explain to a business &quot;what's the ROI?&quot;, but if we are happy, keen or even excited to work, then the ROI is <em>always</em> a net positive.</p>
<p>So that's what FFConf is in 2025. It's an event chooses people over technology, that aims to inspire and motivate, and that champions a better web.</p>
<figure><img src="https://remysharp.com/images/combined-ffconf-group.avif" alt="The audience over the years, looking happy with their hands raised high" decoding="async"></figure>
<p><em>Originally published on <a href="https://remysharp.com/2025/10/27/how-has-ffconf-changed-since-it-was-known-as-full-frontal">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>What Happened to Apple's Legendary Attention to Detail? [link]</title>
      <guid isPermaLink="false">2025-10-23-d9bf3277</guid>
      <link>https://remysharp.com/links/2025-10-23-d9bf3277</link>
      <pubDate>Thu, 23 Oct 2025 10:33:22 +0000</pubDate>
      <description><![CDATA[I accidentally upgraded to Tahoe (I didn't know it existed and thought I was moving to Sequoia and the UI design is all over the place, and it's constantly reminding me how bad it is. This excellent article takes what was an attention to detail that we took for granted (because tech is supposed to &quot;just work&quot;), and calls out just a handful of the failings that Apple's OS now ships with (including on iOS, that I thankfully don't have to suffer). My fear, based on experience with bad Apple UI - (like the notifications that couldn't be quickly dismissed forcing us to click EXACTLY in the right place, and with the &quot;suitable&quot; amount of delay) - is that it simply won't be fixed or even improved. /via venerable Bruce Lawson
Source: blog.johnozbay.com]]></description>
      <content:encoded><![CDATA[
<p>I accidentally upgraded to Tahoe (I didn't know it existed and thought I was moving to Sequoia and the UI design is all over the place, and it's constantly reminding me how bad it is. This excellent article takes what was an attention to detail that we took for granted (because tech is supposed to &quot;just work&quot;), and calls out just a handful of the failings that Apple's OS now ships with (including on iOS, that I thankfully don't have to suffer). My fear, based on experience with bad Apple UI - (like the notifications that couldn't be quickly dismissed forcing us to click <em>EXACTLY</em> in the right place, and with the &quot;suitable&quot; amount of delay) - is that it simply won't be fixed or even improved. /via venerable <a href="https://brucelawson.co.uk/">Bruce Lawson</a></p>
<p><em>Source: <a href="https://blog.johnozbay.com/what-happened-to-apples-attention-to-detail.html">blog.johnozbay.com</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2025-10-23-d9bf3277">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Empire of AI: Dreams and Nightmares in Sam Altman's OpenAI [book]</title>
      <guid isPermaLink="false">empire-of-ai-dreams-and-nightmares-in-sam-altmans-openai</guid>
      <link>https://remysharp.com/books/2025/empire-of-ai-dreams-and-nightmares-in-sam-altmans-openai</link>
      <pubDate>Mon, 06 Oct 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[I'd recommend anyone who wants to understand the emergence of AI and OpenAI in particular to read this book.
I do struggle reading non-fiction, and this book was no different. It took me nearly 2 months to finish reading (in my evening snippets) - but it was definitely worthwhile. It was this 90 minute interview by Novara Media with Karen Hao that made me immediately purchase the book.
I don't think I can fully review this book and do it justice, but I can share what I learnt from the book where my original assumptions were wrong about AI and AI companies.
The book is focused primarily around OpenAI and Sam Altman, and in particular how his ousting in November 2023 came to be, through hundreds of interviews and documents, and paints a very insightful picture of the messiah complex (though not in her words) that Altman has.
Here's a short summary of things I didn't know but learnt through reading this:

Altman and friends started conversations (and business, albeit initially as a non-profit, though that didn't last) in 2015 because they were going to build AGI and that it was inevitable.
The company was formed with scientific researchers originally, again as an open company with the intent of sharing, though spoiler alert: this all changed
I had always assumed it was cowboy bro developers working on the code, but it was, originally, academic based engineering
AI safety was constantly there and initially significant - but as we all know now, eventually lost a battle to make an impact, left &quot;hobbled&quot; and thrown rather to the wayside.
The training data was, after GPT-2, ingested wholesale and attempt to clean/sanitise would happen on the results coming from prompts - i.e. the inputs were not cleaned, which means applying dizzying array of filters to catch on the output and edge cases.
Common Crawl was introduced at GPT-3 - which is also where the input filtering stopped happening
AI, or Western AI companies including OpenAI (but also Google and Microsoft) put their data centres in the Global South, additionally sourcing their data annotators from the poorest countries allowing them to pay (via third parties) literal pennies per hour for the work (which could also come with terrible mental health side effects as the worker would read and view the generative content that AI could come up with based on the unfiltered dark corners of the web)
Sam Altman lies. Little lies, but from a great deal of documentation, a lot and often to tell people what they want to hear whilst (we guess?!) having some ulterior motive
The path that OpenAI decided to take to head towards what they believe will be AGI, effectively requires unlimited compute power, when in reality, there are lots of different applications of AI that don't need that level of power, Stable Diffusion being one such example trained using 256 GPUs (still not a desktop computer, but not hundreds of thousand GPUs either)
OpenAI's approach, to close off it's scientific findings, close it's source and refusing to share methods means that there's no way to verify any of their progress, but more importantly is stripping the academic scientific community of it's researchers (as someone who has visited CERN on two occassions, seeing science being shared is incredible and incredible for society)

My only complaint about the book (and it's likely to be my own fault) is I had trouble with the jumping backwards and forwards in time - I'd often be unsure where we were in the timeline.
If you work in tech, I'd absolutely recommend this book. If it's not possible, then definitely the interview I linked above.]]></description>
      <content:encoded><![CDATA[<p>I'd recommend anyone who wants to understand the emergence of AI and OpenAI in particular to read this book.</p>
<p>I do struggle reading non-fiction, and this book was no different. It took me nearly 2 months to finish reading (in my evening snippets) - but it was definitely worthwhile. It was <a href="https://www.youtube.com/watch?v=8enXR...">this 90 minute interview</a> by Novara Media with Karen Hao that made me immediately purchase the book.</p>
<p>I don't think I can fully review this book and do it justice, but I can share what I learnt from the book where my original assumptions were wrong about AI and AI companies.</p>
<p>The book is focused primarily around OpenAI and Sam Altman, and in <a href="https://www.bbc.co.uk/news/business-6...">particular how his ousting in November 2023</a> came to be, through hundreds of interviews and documents, and paints a very insightful picture of the messiah complex (though not in her words) that Altman has.</p>
<p>Here's a short summary of things I didn't know but learnt through reading this:</p>
<ol>
<li>Altman and friends started conversations (and business, albeit initially as a non-profit, though that didn't last) in 2015 because they were <em>going</em> to build AGI and that it was inevitable.</li>
<li>The company was formed with scientific researchers originally, again as an open company with the intent of sharing, though spoiler alert: this all changed</li>
<li>I had always assumed it was cowboy bro developers working on the code, but it was, originally, academic based engineering</li>
<li>AI safety was constantly there and initially significant - but as we all know now, eventually lost a battle to make an impact, left &quot;hobbled&quot; and thrown rather to the wayside.</li>
<li>The training data was, after GPT-2, ingested wholesale and attempt to clean/sanitise would happen on the results coming from prompts - i.e. the inputs were not cleaned, which means applying dizzying array of filters to catch on the output and edge cases.</li>
<li>Common Crawl was introduced at GPT-3 - which is also where the input filtering stopped happening</li>
<li>AI, or Western AI companies including OpenAI (but also Google and Microsoft) put their data centres in the Global South, additionally sourcing their data annotators from the poorest countries allowing them to pay (via third parties) literal pennies per hour for the work (which could also come with terrible mental health side effects as the worker would read and view the generative content that AI could come up with based on the unfiltered dark corners of the web)</li>
<li>Sam Altman lies. Little lies, but from a great deal of documentation, <em>a lot</em> and often to tell people what they want to hear whilst (we guess?!) having some ulterior motive</li>
<li>The path that OpenAI decided to take to head towards what they believe will be AGI, effectively requires unlimited compute power, when in reality, there are lots of different applications of AI that don't need that level of power, Stable Diffusion being one such example trained using 256 GPUs (still not a desktop computer, but not hundreds of thousand GPUs either)</li>
<li>OpenAI's approach, to close off it's scientific findings, close it's source and refusing to share methods means that there's no way to verify any of their progress, but more importantly is stripping the academic scientific community of it's researchers (as someone who has visited CERN on two occassions, seeing science being shared is incredible and incredible for society)</li>
</ol>
<p>My only complaint about the book (and it's likely to be my own fault) is I had trouble with the jumping backwards and forwards in time - I'd often be unsure where we were in the timeline.</p>
<p>If you work in tech, I'd absolutely recommend this book. If it's not possible, then definitely the interview I linked above.</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2025/empire-of-ai-dreams-and-nightmares-in-sam-altmans-openai">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Making a low-budget conference look high-budget using an ATEM video mixer and a long USB cable [link]</title>
      <guid isPermaLink="false">2025-10-05-22673538</guid>
      <link>https://remysharp.com/links/2025-10-05-22673538</link>
      <pubDate>Sun, 05 Oct 2025 21:28:52 +0000</pubDate>
      <description><![CDATA[Niels Leenheer goes through a detailed setup on how to take a single HDMI to projection into a mini event setup with holding screens. The technical detail is superb too, specifically considering power draw you would need but also, importantly, the length of cables and types to handle data rates. Definitely one for the back pocket read when wanting to upgrade the meetup game to something that has a lot more polish.
Source: nielsleenheer.com]]></description>
      <content:encoded><![CDATA[
<p>Niels Leenheer goes through a detailed setup on how to take a single HDMI to projection into a mini event setup with holding screens. The technical detail is superb too, specifically considering power draw you would need but also, importantly, the length of cables and types to handle data rates. Definitely one for the back pocket read when wanting to upgrade the meetup game to something that has a lot more polish.</p>
<p><em>Source: <a href="https://nielsleenheer.com/articles/2025/making-a-low-budget-conference-look-high-budget-using-an-atem-video-mixer-and-a-long-usb-cable/">nielsleenheer.com</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2025-10-05-22673538">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>CSS HDR Gradients [link]</title>
      <guid isPermaLink="false">2025-10-03-8c6febb9</guid>
      <link>https://remysharp.com/links/2025-10-03-8c6febb9</link>
      <pubDate>Fri, 03 Oct 2025 06:36:20 +0000</pubDate>
      <description><![CDATA[Very cool CSS gradient tooling by Adam Argyle.It's so pretty all I want to do is play with UI forgetting that it'll actually give me CSS.I also like that the URL is sharable and savable (perhaps through a bookmark or in a markdown doc).His latest changes include:- better import design- more resilient parser (understands more syntax)- supports multi-layered gradient imports
Source: gradient.style]]></description>
      <content:encoded><![CDATA[
<p>Very cool CSS gradient tooling by Adam <a href="http://Argyle.It">Argyle.It</a>'s so pretty all I want to do is play with UI forgetting that it'll actually give me CSS.I also like that the URL is sharable and savable (perhaps through a bookmark or in a markdown doc).His latest changes include:- better import design- more resilient parser (understands more syntax)- supports multi-layered gradient imports</p>
<p><em>Source: <a href="https://gradient.style/">gradient.style</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2025-10-03-8c6febb9">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Signal Pollution [blog]</title>
      <guid isPermaLink="false">signal-pollution</guid>
      <link>https://remysharp.com/2025/09/25/signal-pollution</link>
      <pubDate>Thu, 25 Sep 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[Very recently I was forced to sign up to Meta due to a product purchase (don't at-me!) and I had forgotten what it was like to be part of the algorithms. Our entire family browse the internet (the web and internet) from behind a DNS proxy that blocks a lot of social media including Facebook/Meta/Insta/whatever it's actually called.]]></description>
      <content:encoded><![CDATA[
<p>Very recently I was forced to sign up to Meta due to a product purchase (don't at-me!) and I had forgotten what it was like to be part of the algorithms. Our entire family browse the internet (the web <em>and</em> internet) from behind a DNS proxy that blocks a lot of social media including Facebook/Meta/Insta/whatever it's actually called.</p>
<p>Unblocking these different services just to get a physical product to work (naively I thought it worked mostly offline) felt like I was exposing myself to a pretty gross network.</p>
<p>Then had to make an account for my child, whom if there were over the age of 10 and under the age of 13, could be managed under my account. Once they turned 13 (in the eyes of Meta) they were completely unrestricted (which I've got A LOT to say about, but I digress).</p>
<p>This combined with having already having to lift the protection I had in place was too much. I quickly deleted both accounts and parked the problem for the day.</p>
<p>After some reflection, I decided that I would create a single account, that we'd all share that way at least I could monitor all activity <em>and</em> the data Meta collected would be (hopefully) extremely mixed due to different people using the account.</p>
<hr>
<p>Which reminded me of a story I heard about <em>years</em> ago where villagers in some areas of Africa (and likely other places in the Global South) were sharing a single device to visit Facebook and the like, which made it nigh impossible for algorithms to profile the user and made targetting and ads effectively useless.</p>
<p><strong>Why don't we do this now?</strong> Why don't we share accounts to large social media sites to pollute the signal we're putting out?</p>
<p>I understand if you want to create an account so you can build your brand or post what you're up to, this doesn't really work. But if you're visiting these sites to keep in touch with your communities and post short comments or questions - then it seems to me that this is a viable solution.</p>
<p>If I were to propose implementing this, it would be that each shared-user would have 10-20 real people using the account, I can see how it might be chaotic with more people - plus there's an aspect of trust required in your group. If someone decides to change the password you're all of a sudden blown up.</p>
<p>Funnily enough, I've written about this same thought some <a href="https://remysharp.com/2019/06/27/a-thought-privacy-pollution">6 years ago</a>, prompted by this fun <a href="https://trackthis.link/">pollution tool</a>.</p>
<p>What do you think? What downsides am I missing here?</p>
<p><em>Originally published on <a href="https://remysharp.com/2025/09/25/signal-pollution">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Fifteen [blog]</title>
      <guid isPermaLink="false">fifteen</guid>
      <link>https://remysharp.com/2025/08/30/fifteen</link>
      <pubDate>Sat, 30 Aug 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[I'd been waiting for the grief to find me. I wasn't actively looking for it, I know which memories to poke to feel real pain, but I wanted to create space for it to find me, and throughout the month of August, this year, it couldn't find me. Until today. 30th August. This day is the knife edge. The day, 15 years ago, that Tia still had a heartbeat, still kicked, was on her way. Julie was in (long) labour. On this same day, at some point, her heart gave out, she died before she could take her first breath and the midwives had to tell us that they couldn't find that heartbeat any more. Julie was in labour, so  Tia was coming. Except that her delivery at 3am on 31st August would be the other side of our lives. The side we live on today: our derailed and rebuilt lives that exist in now.]]></description>
      <content:encoded><![CDATA[<p>I'd been waiting for the grief to find me. I wasn't actively looking for it, I know which memories to poke to feel real pain, but I wanted to create space for it to find me, and throughout the month of August, this year, it couldn't find me. Until today. 30th August. This day is the knife edge. The day, 15 years ago, that <a href="https://remysharp.com/search?q=tia">Tia</a> still had a heartbeat, still kicked, was on her way. Julie was in (long) labour. On this same day, at some point, her heart gave out, she died before she could take her first breath and the midwives had to tell us that they couldn't find that heartbeat any more. Julie was in labour, so  Tia was coming. Except that her delivery at 3am on 31st August would be the other side of our lives. The side we live on today: our derailed and rebuilt lives that exist in now.</p>
<p>So today, the 30th of August, grief wakes me up in the morning. It presses hard downwards on me. And I need it, even if it's just for a day.</p>
<p>15 years didn't fix us, or heal us, <a href="https://remysharp.com/2014/08/11/time-doesnt-heal">time doesn't do that</a>, but it does allow for new memories. For more memories. For life to fill in the space. It's that time, and that life, and our amazing two children who create the life and family we needed. It keeps us busy and it keeps us alive.</p>
<p>We only got one day with Tia, to hold her. Then we had to leave her. Alone in the hospital. That's my memory that's fraught with pain and longing, and all kinds of complicated feelings. For a long time, in those early years, it was a dark memory, a memory I hated myself for, for leaving her. It took a year of therapy to put light into that room again, to not cast judgement on myself, to leave the memory as it is. Just that one day. The one day that she was real.</p>
<p>But that's why I write these post each year. It's why I write this for myself, and in part to share with you. Tia is a memory to me, but she was real. I have to write about that to bring her existence into reality, into the world I still inhabit.</p>
<hr>
<p>I was worried this year I wouldn't find the words, that the grief wouldn't find me. I know that there's an instinct in me to shove the grief away, to busy myself, but I also know that every other day of the year can do that with no effort at all. The little one starting secondary, the big one starting his options, new achievements, new problems, new arguments, new memories. So, I'll try my best to sit in the grief today. Share it with Julie, and try to be gentle on ourselves.</p>
<p>And I'll remember Tia today.</p>
<p><em>Originally published on <a href="https://remysharp.com/2025/08/30/fifteen">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>In Bloom (Sweetpea, #2) [book]</title>
      <guid isPermaLink="false">in-bloom-sweetpea-2</guid>
      <link>https://remysharp.com/books/2025/in-bloom-sweetpea-2</link>
      <pubDate>Tue, 12 Aug 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[No quite the same murderfest from Sweetpea 1, but still enjoyably angry at the world.
I think I expected the same kind of murder spree from the first book, and it's not that at all (although Rhiannon, the protagonist, desperately wants that). It's actually written on the tin, In Bloom is Rhiannon's experience of being pregnant - which, for a change, rolls up all the shitty experiences into one.
I enjoyed, and laughed at, the cutting turn of phrases - the kind of brutal honesty that you might reserve for the closest of friends knowing that it's for the &quot;inside voice&quot;.
I can see myself reading the next instalment in the book (though perhaps not so soon) and I'm not entirely sure where the character can go given the way the book ends, so that's definitely intriguing.
But just for the the record (my record!), Rhiannon is a terrible person!]]></description>
      <content:encoded><![CDATA[<p>No quite the same murderfest from Sweetpea 1, but still enjoyably angry at the world.</p>
<p>I think I expected the same kind of murder spree from the first book, and it's not that at all (although Rhiannon, the protagonist, desperately wants that). It's actually written on the tin, In Bloom is Rhiannon's experience of being pregnant - which, for a change, rolls up all the shitty experiences into one.</p>
<p>I enjoyed, and laughed at, the cutting turn of phrases - the kind of brutal honesty that you might reserve for the closest of friends knowing that it's for the &quot;inside voice&quot;.</p>
<p>I can see myself reading the next instalment in the book (though perhaps not so soon) and I'm not entirely sure where the character can go given the way the book ends, so that's definitely intriguing.</p>
<p>But just for the the record (my record!), Rhiannon is a terrible person!</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2025/in-bloom-sweetpea-2">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Getting my highlights &amp; notes from KOReader [blog]</title>
      <guid isPermaLink="false">getting-my-highlights-and-notes-from-koreader</guid>
      <link>https://remysharp.com/2025/07/22/getting-my-highlights-and-notes-from-koreader</link>
      <pubDate>Tue, 22 Jul 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[It's not an intuitive process and requires a few speciality commands to work, so it made sense that I write up the process so I can duck myself later on.]]></description>
      <content:encoded><![CDATA[
<p>It's not an intuitive process and requires a few speciality commands to work, so it made sense that I write up the process so I can <a href="https://duckduckgo.com/?q=site%3Aremysharp.com+kindle&amp;t=newext">duck myself</a> later on.</p>
<p>Since I'm getting my <a href="https://remysharp.com/2025/05/01/showing-book-clippings-on-my-blog">Amazon Kindle book highlights</a> already but am also actively trying to buy books from <a href="https://remysharp.com/2025/06/29/unhooking-from-amazon-ebooks">anywhere that isn't Amazon</a> it means my highlights are in KOReader.</p>
<p>There's a multi-step process that requires special command line tools <em>and</em> navigating KOReader into the &quot;right&quot; state to allow for syncing (I'm certain there's other ways to do this process, but I've not found it yet myself).</p>
<h2>1. Export the highlights</h2>
<p>Probably the simplest part, and if you're happy to connect the Kindle via a USB port, probably a lot easier to get the exported notes off (but I'm taking the wireless route, so it's trickier!).</p>
<p>Whilst the current book is open, open the &quot;tools&quot; menu (the spanner and screwdriver icon), then <em>Export highlights</em> and <em>Export all notes in current book</em>.</p>
<p>I've already selected the format as JSON and selected my export folder (arbitrarily my exports are going to <code>/mnt/us/koreader/clipboard</code>).</p>
<p>Now the file is waiting to be lifted to my computer.</p>
<h2>2. WebDAV</h2>
<p>From the machine I want to upload the JSON file to, I need to run a WebDAV server (a technology I've always known about but never really had an need or use for until now).</p>
<p>There's quite a few options for WebDAV servers, but I wanted something very lightweight and that I could run on the command line. I ended up using a <a href="https://github.com/hacdias/webdav">Go based server</a>, via <code>brew install webdav</code>.</p>
<p>Which ever server you use, you'll need to make sure it has write permissions. To run this go version in write, in the directory I want the JSON file uploaded to, I run:</p>
<pre><code class="language-sh"><span class="token assign-left variable">WD_PERMISSIONS</span><span class="token operator">=</span>CRUD webdav <span class="token parameter variable">-p</span> <span class="token number">8181</span>
</code></pre>
<p>This says:</p>
<ol>
<li>Run on port 8181</li>
<li>Run with create, read, update and delete permissions</li>
</ol>
<p>Once I'm done with the process, I then terminate the WebDAV server.</p>
<p>However, before I shut the server down, I need to upload my JSON notes from the Kindle.</p>
<h2>3. Uploading to WebDAV from KOReader</h2>
<p>This is where KOReader's UI gets clunky again. You need to use the &quot;Cloud Storage&quot; option.</p>
<p>Cloud Storage is <em>only</em> visible in the tools menu when you're in the file browser (not in the book reading mode).</p>
<p>Once the Cloud Storage is open, tap the plus icon on the top right, then fill out the details. Assuming the Kindle is on the same network as the computer (because it needs to be), the URL/host is <code>http://{IP}:8181</code> and the folder is just <code>/</code>.</p>
<p>Once this is saved, tap on the connection name. If the directory is empty, you'll see a new screen with no files. If there's any <code>.pub</code> ebooks, then those will be listed (and could be downloaded).</p>
<p>From this new screen, tap the top left plus icon to upload a file. Navigate to the file, and long press on the file to &quot;choose&quot; the file to be uploaded.</p>
<p>If all is successful, KOReader should say so. If it fails, it could be related to permissions. I had earlier luck with a <a href="https://wsgidav.readthedocs.io/en/latest/">python WebDAV server</a>.</p>
<h2>4. Transform</h2>
<p>The JSON structure is fairly simplistic, but I have this specific <a href="https://jqterm.com">jq transform</a> to get into the format I use:</p>
<pre><code class="language-jq"><span class="token keyword">def</span> <span class="token function">slug</span><span class="token punctuation">:</span>
  <span class="token keyword">ascii_downcase</span>
  <span class="token operator pipe">|</span> <span class="token keyword">gsub</span><span class="token punctuation">(</span><span class="token string">"[^a-z0-9]+"</span><span class="token punctuation">;</span> <span class="token string">"-"</span><span class="token punctuation">)</span>
  <span class="token operator pipe">|</span> <span class="token keyword">gsub</span><span class="token punctuation">(</span><span class="token string">"(^-|-$)"</span><span class="token punctuation">;</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token dot important">.</span> <span class="token operator">+</span>  <span class="token punctuation">{</span> <span class="token property-literal property">slug</span><span class="token punctuation">:</span> <span class="token punctuation">.</span>title <span class="token operator pipe">|</span> slug <span class="token punctuation">}</span> <span class="token operator pipe">|</span> <span class="token punctuation">{</span>
  <span class="token property">"<span class="token interpolation"><span class="token punctuation">\(</span><span class="token content"><span class="token punctuation">.</span>slug</span><span class="token punctuation">)</span></span>"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    title<span class="token punctuation">,</span>
    author<span class="token punctuation">,</span>
    <span class="token property-literal property">highlights</span><span class="token punctuation">:</span> <span class="token punctuation">.</span>entries <span class="token operator pipe">|</span> <span class="token keyword">map</span><span class="token punctuation">(</span><span class="token punctuation">{</span> text<span class="token punctuation">,</span> page<span class="token punctuation">,</span> note <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Alternatively, if I'm lifting the annotations (highlights) directly from Calibre, this works:</p>
<pre><code class="language-jq"><span class="token keyword">def</span> <span class="token function">clean</span><span class="token punctuation">:</span> <span class="token keyword">tostring</span> <span class="token operator pipe">|</span> <span class="token keyword">gsub</span><span class="token punctuation">(</span><span class="token string">"\\\\\\n"</span><span class="token punctuation">;</span> <span class="token string">"\n\n"</span><span class="token punctuation">)</span> <span class="token operator pipe">|</span> <span class="token keyword">gsub</span><span class="token punctuation">(</span><span class="token string">"[’‘]"</span><span class="token punctuation">;</span> <span class="token string">"'"</span><span class="token punctuation">;</span> <span class="token string">"g"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">def</span> <span class="token function">percent</span><span class="token punctuation">(</span><span class="token variable">$total</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token dot important">.</span> <span class="token operator">/</span> <span class="token variable">$total</span> <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">;</span>

<span class="token keyword">def</span> <span class="token function">slug</span><span class="token punctuation">:</span>
  <span class="token keyword">ascii_downcase</span>
  <span class="token operator pipe">|</span> <span class="token keyword">gsub</span><span class="token punctuation">(</span><span class="token string">"[^a-z0-9]+"</span><span class="token punctuation">;</span> <span class="token string">"-"</span><span class="token punctuation">)</span>
  <span class="token operator pipe">|</span> <span class="token keyword">gsub</span><span class="token punctuation">(</span><span class="token string">"(^-|-$)"</span><span class="token punctuation">;</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token dot important">.</span> <span class="token keyword">as</span> <span class="token variable">$_</span> <span class="token operator pipe">|</span> <span class="token punctuation">{</span> <span class="token property-literal property">slug</span><span class="token punctuation">:</span> <span class="token punctuation">.</span>stats<span class="token punctuation">.</span>title <span class="token operator pipe">|</span> slug <span class="token punctuation">}</span> <span class="token operator pipe">|</span> <span class="token punctuation">{</span>
  <span class="token property">"<span class="token interpolation"><span class="token punctuation">\(</span><span class="token content"><span class="token punctuation">.</span>slug</span><span class="token punctuation">)</span></span>"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token property-literal property">title</span><span class="token punctuation">:</span> <span class="token variable">$_</span><span class="token punctuation">.</span>stats<span class="token punctuation">.</span>title<span class="token punctuation">,</span>
    <span class="token property-literal property">author</span><span class="token punctuation">:</span> <span class="token variable">$_</span><span class="token punctuation">.</span>stats<span class="token punctuation">.</span>authors<span class="token punctuation">,</span>
    <span class="token property-literal property">highlights</span><span class="token punctuation">:</span> <span class="token variable">$_</span><span class="token punctuation">.</span>annotations <span class="token operator pipe">|</span> <span class="token keyword">to_entries</span> <span class="token operator pipe">|</span> <span class="token keyword">map</span><span class="token punctuation">(</span><span class="token punctuation">.</span>value <span class="token operator pipe">|</span> <span class="token punctuation">{</span> <span class="token property-literal property">text</span><span class="token punctuation">:</span> <span class="token punctuation">.</span>text <span class="token operator pipe">|</span> clean<span class="token punctuation">,</span> <span class="token property-literal property">page</span><span class="token punctuation">:</span> <span class="token string">"<span class="token interpolation"><span class="token punctuation">\(</span><span class="token content"><span class="token punctuation">.</span>pageno</span><span class="token punctuation">)</span></span>/<span class="token interpolation"><span class="token punctuation">\(</span><span class="token content"><span class="token variable">$_</span><span class="token punctuation">.</span>stats<span class="token punctuation">.</span>pages</span><span class="token punctuation">)</span></span>"</span><span class="token punctuation">,</span> <span class="token property-literal property">note</span><span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">.</span>note <span class="token operator pipe">|</span> clean<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<hr>
<p>That's how I get my notes from non-Amazon bought books into my own blog.</p>
<p><em>Originally published on <a href="https://remysharp.com/2025/07/22/getting-my-highlights-and-notes-from-koreader">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
  </channel>
</rss>