<?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>Sun, 02 Aug 2026 20:00:40 +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>A Firefox-only minimap [link]</title>
      <guid isPermaLink="false">2026-07-31-010186f7</guid>
      <link>https://remysharp.com/links/2026-07-31-010186f7</link>
      <pubDate>Fri, 31 Jul 2026 13:54:12 +0000</pubDate>
      <description><![CDATA[This is very cute, a web site minimap in only a few lines of CSS that paints the entire web page into a canvas (background) using the element() CSS function.
Original link: www.stefanjudis.com/a-firefox-only-minimap]]></description>
      <content:encoded><![CDATA[
<p>This is very cute, a web site minimap in only a few lines of CSS that paints the entire web page into a canvas (background) using the <code>element()</code> CSS function.</p>
<p><em>Original link: <a href="https://www.stefanjudis.com/a-firefox-only-minimap/">www.stefanjudis.com/a-firefox-only-minimap</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-07-31-010186f7">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Pokémon Emerald [tif]</title>
      <guid isPermaLink="false">2026-07-30-pokemon-emerald</guid>
      <link>https://remysharp.com/tif/2026-07-30-pokemon-emerald</link>
      <pubDate>Thu, 30 Jul 2026 12:00:00 +0000</pubDate>
      <description><![CDATA[Similar to the Pokemon Yellow recently, I had a GBA Emerald Green sent in for repair.
Just 24 hours ago, this was going to be a post on how I had failed to repair it, but in a last minute ditch, I managed to save it.
Loading up the game resulted in nothing, and opening the shell explained why. There was a lot of corrosion around the PCB, but more importantly, two of the legs on the ROM had completely dissolved:
It doesn't photograph well, but the crud at the top left is where the chip legs had turned to mush
The first task is to remove the main chips (the ROM and the RAM) and examine and then clean up the damage under the chips. The black around the vias (the holes) aren't a great sign either.
Initially looked like the pads had been lost too, but thankfully they were under there
Whilst the chips are off, this is a good time to (try to) check the traces for continuity throughout the board.
Once the chips were replaced, I then have to repair the lost legs. To do this, I use a small Dremel-like hand tool that can burr into the epoxy (the black part of the chip that you would handle) until I'm able to expose the internal part of the leg before it was lost.
From there, very carefully, I'm soldering a 30 AWG (hair-thin at 0.1mm) to the inside of the chip to the pad it originally connected to.
Drilling into the epoxy is always nerve wracking stuff
Then using the same 30 AWG jumper wire, I proceeded to jump all the locations that I knew the trace was bad. It ended up a bit of a spaghetti board:
Lots of tiny wires snake across the board
At this point, it was time to test.
And…it wouldn't boot. I debugged a lot more, but decided the PCB itself had suffered too much damage, and managed to order a new bare PCB for £6.50 - which came reasonably quickly.
I then proceeded to move all the components across from the old PCB to the new. The larger components are pretty straightforward, but the passives, such as the resistors and capacitors are harder, especially without a template.
I also decided to use my own new passives for the resistors, and at the time I didn't have any new capacitors, so I carried these across assuming, since I had always considered them to be pretty robust (spoiler: they aren't).
The new PCB definitely got me out of a corner
When I was finally done soldering down all the individual components and checking and re-checking the pads on the chips, I finally tried to boot it up to… another fail.
I was going to email the customer and tell them it was a dead end, when I decided I might splash out on Amazon (booo) for some 0402 SMD capacitors - at least I'd have some more for future.
As it turned out, this was the last of the issues. The caps had somehow gone bad on the original board and replacing them brought the whole cart back to life!
It lives!!!
Another one saved. Quite a challenge, and I know if I were a real electronics shop I would have cut the losses much earlier. But I'm not a real shop, this is a distraction hobby and this one was certainly a challenge!]]></description>
      <content:encoded><![CDATA[<p>Similar to the Pokemon Yellow recently, I had a GBA Emerald Green sent in for repair.</p>
<p>Just 24 hours ago, this was going to be a post on how I had <em>failed</em> to repair it, but in a last minute ditch, I managed to save it.</p>
<p>Loading up the game resulted in nothing, and opening the shell explained why. There was a lot of corrosion around the PCB, but more importantly, two of the legs on the ROM had completely dissolved:</p>
<figure><img src="https://remysharp.com/images/tif/2026-07-30-gba-pe-1.jpg.avif" alt="Extreme close-up of a corroded green printed circuit board showing oxidized metal contacts, vias, and labeled solder pads." decoding="async"><figcaption>It doesn't photograph well, but the crud at the top left is where the chip legs had turned to mush</figcaption></figure>
<p>The first task is to remove the main chips (the ROM and the RAM) and examine and then clean up the damage under the chips. The black around the vias (the holes) aren't a great sign either.</p>
<figure><img src="https://remysharp.com/images/tif/2026-07-30-gba-pe-2.jpg.avif" alt="Close-up of a the circuit board showing severe corrosion, damaged traces, and flux residue around small surface-mount component pads and vias." decoding="async"><figcaption>Initially looked like the pads had been lost too, but thankfully they were under there</figcaption></figure>
<p>Whilst the chips are off, this is a good time to (try to) check the traces for continuity throughout the board.</p>
<p>Once the chips were replaced, I then have to repair the lost legs. To do this, I use a small Dremel-like hand tool that can burr into the epoxy (the black part of the chip that you would handle) until I'm able to expose the internal part of the leg before it was lost.</p>
<p>From there, very carefully, I'm soldering a 30 AWG (hair-thin at 0.1mm) to the inside of the chip to the pad it originally connected to.</p>
<figure><img src="https://remysharp.com/images/tif/2026-07-30-gba-pe-3.jpg.avif" alt="Extreme macro photo of an integrated circuit chip on a circuit board, where thin enamel jumper wires have been soldered directly into scraped-open chip package leads for repair." decoding="async"><figcaption>Drilling into the epoxy is always nerve wracking stuff</figcaption></figure>
<p>Then using the same 30 AWG jumper wire, I proceeded to jump all the locations that I knew the trace was bad. It ended up a bit of a spaghetti board:</p>
<figure><img src="https://remysharp.com/images/tif/2026-07-30-gba-pe-4.jpg.avif" alt="Top-down view of a modified 2002 Nintendo Game Boy Advance cartridge circuit board featuring multiple bodge wires routed across broken traces." decoding="async"><figcaption>Lots of tiny wires snake across the board</figcaption></figure>
<p>At this point, it was time to test.</p>
<p>And…it wouldn't boot. I debugged a lot more, but decided the PCB itself had suffered too much damage, and managed to order a new bare PCB for £6.50 - which came reasonably quickly.</p>
<p>I then proceeded to move all the components across from the old PCB to the new. The larger components are pretty straightforward, but the passives, such as the resistors and capacitors are harder, especially without a template.</p>
<p>I also decided to use my own new passives for the resistors, and at the time I didn't have any new capacitors, so I carried these across assuming, since I had always considered them to be pretty robust (spoiler: they aren't).</p>
<figure><img src="https://remysharp.com/images/tif/2026-07-30-gba-pe-5.jpg.avif" alt="Two Game Boy Advance cartridge circuit boards held in clamps side-by-side on a workbench, one fully harvested down to bare pads and the other populated with the transferred chips and components." decoding="async"><figcaption>The new PCB definitely got me out of a corner</figcaption></figure>
<p>When I was finally done soldering down all the individual components and checking and <em>re-checking</em> the pads on the chips, I finally tried to boot it up to… another fail.</p>
<p>I was going to email the customer and tell them it was a dead end, when I decided I might splash out on Amazon (booo) for some 0402 SMD capacitors - at least I'd have some more for future.</p>
<p>As it turned out, <em>this</em> was the last of the issues. The caps had somehow gone bad on the original board and replacing them brought the whole cart back to life!</p>
<figure><img src="https://remysharp.com/images/tif/2026-07-30-gba-pe-6.jpg.avif" alt="Clear shell Game Boy Advance with a backlit screen displaying the title screen of Pokémon Emerald fully loading" decoding="async"><figcaption>It lives!!!</figcaption></figure>
<p>Another one saved. Quite a challenge, and I know if I were a real electronics shop I would have cut the losses much earlier. But I'm not a <em>real</em> shop, this is a distraction hobby and this one was certainly a challenge!</p>
<p><em>Originally published on <a href="https://remysharp.com/tif/2026-07-30-pokemon-emerald">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Human Software [book]</title>
      <guid isPermaLink="false">human-software</guid>
      <link>https://remysharp.com/books/2026/human-software</link>
      <pubDate>Thu, 30 Jul 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[A book about work, felt like work.
I suspect this is very specific to me, but I found the majority of the story pretty triggering - specifically, I felt pissed off a lot of the time I was reading. After reading the About the Author section at the end of the book, it looks like I've had a similar timeline of a technical career to them (which perhaps is why the story got under my skin).
This is because I spent a decade in a company (over a decade ago) that treated it's employees a lot like the characters in the book and it was doing my in that the story seemed to centre around people who made their company the be-all of their lives.
Though the story (sort of) follows two main characters, you really don't meet anyone outside of the company, Gerbach, and there's a scene in the book where it seems pretty clear they all live in each other's pockets.
I didn't really have a good sense of timings until the very end (4 months). The story opens with outages the devs are firefighting, and I couldn't tell if they were still dealing with issues across the timeline or… if they'd just accepted it was all terrible and the characters swan off and pull sickies when their infrastructure is on fire 🤷.
Then there's the AI aspect that's sort of supposed to be looming, but, sort of not really… Around 2/3rds of the way into the story there's a development (not quite a plot twist) which I managed to guess how it related to the AI.
I think if you work in the technology industry, and you are (or have been) a dev, then this book might be worth a read. I'm not sure it's quite that accessible outside of the tech industry, specifically around some of the terminology (which, though I knew, I didn't realise there was a full appendix at the end, &quot;log4j&quot; might throw some people).
Read through a recommendation (later realising that the person who recommended it was listed in the author thanks!), I think I'd struggle to recommend it myself.]]></description>
      <content:encoded><![CDATA[<p>A book about work, felt like work.</p>
<p>I suspect this is very specific to me, but I found the majority of the story pretty triggering - specifically, I felt pissed off a lot of the time I was reading. After reading the About the Author section at the end of the book, it looks like I've had a similar timeline of a technical career to them (which perhaps is why the story got under my skin).</p>
<p>This is because I spent a decade in a company (over a decade ago) that treated it's employees a lot like the characters in the book and it was doing my in that the story seemed to centre around people who made their company the be-all of their lives.</p>
<p>Though the story (sort of) follows two main characters, you really don't meet anyone outside of the company, Gerbach, and there's a scene in the book where it seems pretty clear they all live in each other's pockets.</p>
<p>I didn't really have a good sense of timings until the very end (4 months). The story opens with outages the devs are firefighting, and I couldn't tell if they were still dealing with issues across the timeline or… if they'd just accepted it was all terrible and the characters swan off and pull sickies when their infrastructure is on fire 🤷.</p>
<p>Then there's the AI aspect that's sort of supposed to be looming, but, sort of not really… Around 2/3rds of the way into the story there's a development (not quite a plot twist) which I managed to guess how it related to the AI.</p>
<p>I think if you work in the technology industry, and you are (or have been) a dev, then this book might be worth a read. I'm not sure it's quite that accessible outside of the tech industry, specifically around some of the terminology (which, though I knew, I didn't realise there was a full appendix at the end, &quot;log4j&quot; might throw some people).</p>
<p>Read through a recommendation (later realising that the person who recommended it was listed in the author thanks!), I think I'd struggle to recommend it myself.</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2026/human-software">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Rescued Pokémon Yellow [tif]</title>
      <guid isPermaLink="false">2026-07-24-rescued-pokemon-yellow</guid>
      <link>https://remysharp.com/tif/2026-07-24-rescued-pokemon-yellow</link>
      <pubDate>Fri, 24 Jul 2026 12:00:00 +0000</pubDate>
      <description><![CDATA[I guess I just want bragging rights, but here's the short story of rescuing Pokémon Yellow.
I run &quot;fix your gameboy game for £10&quot; which occasionally I get orders for. This one was a challenge.]]></description>
      <content:encoded><![CDATA[
<p>I guess I just want bragging rights, but here's the short story of rescuing Pokémon Yellow.</p>
<p>I run &quot;fix your gameboy game for £10&quot; which occasionally I get orders for. This one was a challenge.</p>
<p>First it had a battery swap attempt (I spotted on the melted shell), but it had also suffered A LOT of flux and grim inside and initially I couldn't see any corrosion.</p>
<p>There were solder bridges on the ROM and eventually I spotted that the VCC vias to the ROM were corroded, so I got a jumper in place from the rear to the VCC pin on the ROM and it started booting.</p>
<p>But…not all was well…</p>
<figure><img src="https://remysharp.com/images/gameboy/pokemon-yellow-1.avif" alt="The Pokémon Yellow title screen running on a Game Boy" decoding="async"><figcaption>Yellow boots, but …</figcaption></figure>
<figure><img src="https://remysharp.com/images/gameboy/pokemon-yellow-2.avif" alt="The game running in-game with the large sprites visibly broken" decoding="async"><figcaption>Although sprites work, large sprites did not…</figcaption></figure>
<p>My guess it was related to the RAM chip (assuming the sprites are built in RAM when they're big) and <a href="https://www.reddit.com/r/Gameboy/comments/veqaz1/pok%C3%A9mon_yellow_game_and_everything_works_fine_but/">other reddit posts confirmed this</a>.</p>
<p>The old multimeter is my friend, I could see the power monitor/reset chip wasn't getting power. In fact, the trace was fudged where it joins up to a 10K resistor.</p>
<p>I completely removed and rehomed the resistor, found even more vias that were corroded and using this <a href="https://www.reddit.com/r/Gameboy/comments/v5n5ab/not_completely_complete_but_it_already_helps_a/">excellent post</a> to trace out from the reset chip to the RAM, I was able to add two more jumpers and only then did it come back to life:</p>
<figure><img src="https://remysharp.com/images/gameboy/pokemon-yellow-3.avif" alt="The Pokémon Yellow board with the rehomed resistor and jumper wires added" decoding="async"><figcaption>In the top left you can see the rehomed resistor and the trace that had been completely removed.</figcaption></figure>
<p>I usually use the hair-thin wires, but I figured if someone was going to replace the battery on this in 5 or more years, hopefully the big blue and yellow wires were shouting I'M HERE ON PURPOSE!</p>
<figure><img src="https://remysharp.com/images/gameboy/pokemon-yellow-4.avif" alt="Pokémon Yellow running properly with a battle scene and full size sprites" decoding="async"><figcaption>All good again, and Yellow can battle those pokemon.</figcaption></figure>
<p>I love getting these challenges - and definitely couldn't do what I do without the wealth of info on the web and reddit on the gameboy.</p>
<p>Another game saved from landfill 💪</p>
<p><em>Originally published on <a href="https://remysharp.com/tif/2026-07-24-rescued-pokemon-yellow">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>when-do web component [blog]</title>
      <guid isPermaLink="false">when-do-web-component</guid>
      <link>https://remysharp.com/2026/07/24/when-do-web-component</link>
      <pubDate>Fri, 24 Jul 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[I saw recently saw a blog post (which annoyingly I can't find any more, but I'll link it if I do), showing off a web component that if I recall correctly, would show (or hide) it's contents depending on a browser feature (I'd guess using the @supports query).
That reminded me that I wrote a web component that I use quite a bit (particularly with FFConf), which should really be called do-when, but it's not, it's (stupidly) called when-do (the dash, I guess, being a comma in my head).
The component says: when a time occurs or passes, do a what: show, hide or scroll-to.
You can get the code from github - which also includes an interactive demo that lets you try the settings.]]></description>
      <content:encoded><![CDATA[<p>I saw recently saw a blog post (which annoyingly I can't find any more, but I'll link it if I do), showing off a web component that if I recall correctly, would show (or hide) it's contents depending on a browser feature (I'd guess using the <code>@supports</code> query).</p>
<p>That reminded me that I wrote a web component that I use quite a bit (particularly with <a href="https://2026.ffconf.org">FFConf</a>), which should really be called <code>do-when</code>, but it's not, it's (stupidly) called <code>when-do</code> (the dash, I guess, being a comma in my head).</p>
<p>The component says: <code>when</code> a time occurs or passes, <code>do</code> a <code>what</code>: show, hide or scroll-to.</p>
<p>You can get the code <a href="https://github.com/remy/web-components/tree/main/when-do">from github</a> - which also includes an <a href="https://github.com/remy/web-components/blob/main/when-do/example/index.html">interactive demo</a> that lets you try the settings.</p>
<h2>What it is</h2>
<p>A small web component to toggle on or off depending on wall clock (date) time without affecting the visual layout (with it's own element).</p>
<h2>Use case</h2>
<p>I've been using this web component on the FFConf event pages for a number of years to reveal the ticket button if a visitor is sitting on the page (though I appreciate that's unlikely!).</p>
<pre><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>when-do</span> <span class="token attr-name">what</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hide<span class="token punctuation">"</span></span> <span class="token attr-name">datetime</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{ticket-live}<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>p</span><span class="token punctuation">></span></span>Tickets live at {nice-ticket-live}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>when-do</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>when-do</span> <span class="token attr-name">what</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>show<span class="token punctuation">"</span></span> <span class="token attr-name">datetime</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{ticket-live}<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>p</span><span class="token punctuation">></span></span>Buy <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>…<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>now<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>when-do</span><span class="token punctuation">></span></span>
</code></pre>
<p>I've also used the <code>what=&quot;scroll&quot;</code> for our schedule page, to automatically scroll to the current speaker.</p>
<p>Though I do appreciate my &quot;battle testing&quot; has been rather limited, so if you use this and spot bugs, please let me know!</p>
<h2>API</h2>
<ul>
<li><code>what=&quot;show|hide|scroll&quot;</code> - the component also throws an exception if a non valid string is used</li>
<li><code>datetime=&quot;isodate&quot;</code> - recommended that you include the timezone, ie. &quot;2026-09-13T10:00Z&quot; is 10am on 13th September on UTC</li>
<li><code>apply=&quot;classname&quot;</code> optional class name to apply to the <code>when-do</code> element when it activates, useful if you wanted to transition your contents into view, or highlight the newly scrolled element</li>
</ul>
<h2>How it works/styling</h2>
<p>The web component makes use of <code>display: contents</code> to prevent itself from modifying the visual layout.</p>
<p>Due to this display method, it means you can't style the element directly, in that styling has no effect.</p>
<p>If you want to style the contents when the element is active, such as when it has been scrolled into view, it's recommended you wrap the child elements it a parent element, such as a <code>div</code>.</p>
<p>You can also use the <code>apply</code> property to indicate the current <code>when-do</code> has activated.</p>
<hr>
<p>AI wasn't used in any part of this web component (which is also why the demo page is so ugly).</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/07/24/when-do-web-component">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>'VPNs are lawful technical tools,' says EU Court in landmark copyright ruling [link]</title>
      <guid isPermaLink="false">2026-07-23-35890312</guid>
      <link>https://remysharp.com/links/2026-07-23-35890312</link>
      <pubDate>Thu, 23 Jul 2026 10:39:26 +0000</pubDate>
      <description><![CDATA[I've been following the stories around the &quot;child protection&quot; because on one hand it does afford children some protection, but it also hammers down on the privacy of everyone - i.e. adults who give up their privacy to prove they're not a child.
VPNs in particular have been tossed around as something that the UK government would like to ban (citation needed/lacking!), which is why this article is particularly interesting:
The Court of Justice of the European Union has ruled that publishers and VPN providers aren't liable for copyright infringement

Geo-blocking is the copyright holder's problem, not the VPN's. Providers are not liable for users bypassing restrictions

Hopefully this draws a simple line in the sand for the UK government, and yet, who really knows what's going through their head at any one time!
Original link: www.techradar.com/[…]/vpns-are-lawful-technical-tools-says-eu-court-in-landmark-anne-frank-copyright-ruling]]></description>
      <content:encoded><![CDATA[
<p>I've been following the stories around the &quot;child protection&quot; because on one hand it does afford children some protection, but it also hammers down on the privacy of everyone - i.e. adults who give up their privacy to prove they're not a child.</p>
<p>VPNs in particular have been tossed around as something that the UK government would like to ban (citation needed/lacking!), which is why this article is particularly interesting:</p>
<p>The Court of Justice of the European Union has ruled that publishers and VPN providers aren't liable for copyright infringement</p>
<blockquote>
<p>Geo-blocking is the copyright holder's problem, not the VPN's. Providers are not liable for users bypassing restrictions</p>
</blockquote>
<p>Hopefully this draws a simple line in the sand for the UK government, and yet, who really knows what's going through their head at any one time!</p>
<p><em>Original link: <a href="https://www.techradar.com/vpn/vpn-privacy-security/vpns-are-lawful-technical-tools-says-eu-court-in-landmark-anne-frank-copyright-ruling">www.techradar.com/[…]/vpns-are-lawful-technical-tools-says-eu-court-in-landmark-anne-frank-copyright-ruling</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-07-23-35890312">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Image to text [link]</title>
      <guid isPermaLink="false">2026-07-17-8797d866</guid>
      <link>https://remysharp.com/links/2026-07-17-8797d866</link>
      <pubDate>Fri, 17 Jul 2026 11:25:43 +0000</pubDate>
      <description><![CDATA[Really appreciate Jeremy's post on the way he used generative AI to solve a problem.
Specifically he considers the options carefully and was able to make use of local hardware (i.e. his laptop) and &quot;ethically&quot; trained model (from Flickr and creative commons licensed images).
Closing with a quote from Scott Jenson, that I can absolutely relate to:

While the utility is there, the current landscape of these frontier corporate models comes with massive ethical and environmental baggage. This is not a long term solution!

Original link: adactio.com/[…]/22657]]></description>
      <content:encoded><![CDATA[
<p>Really appreciate Jeremy's post on the way he used generative AI to solve a problem.</p>
<p>Specifically he considers the options carefully and was able to make use of local hardware (i.e. his laptop) and &quot;ethically&quot; trained model (from Flickr and creative commons licensed images).</p>
<p>Closing with a quote from Scott Jenson, that I can absolutely relate to:</p>
<blockquote>
<p>While the utility is there, the current landscape of these frontier corporate models comes with massive ethical and environmental baggage. This is not a long term solution!</p>
</blockquote>
<p><em>Original link: <a href="https://adactio.com/journal/22657">adactio.com/[…]/22657</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-07-17-8797d866">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>The Air Raid Book Club [book]</title>
      <guid isPermaLink="false">the-air-raid-book-club</guid>
      <link>https://remysharp.com/books/2026/the-air-raid-book-club</link>
      <pubDate>Wed, 15 Jul 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[Quick easy read. Little repetitive, but shines a nice light.
The story starts in 1938 and we follow Gertie as she plans to retire as a widow having run a bookshop and successful book clubs for many years.
That's put on hold when she agrees to take in a child from the Kindertransport - which I'd know about but hadn't read a great deal of detail.
As a parent myself, this is the first part that breaks my brain a little, and indeed this part is entirely based in history. An amazing effort and so terrible too.
The story then follows Gertie as she takes care of Hedy, a 15 year old German Jew who also longs to be reunited with her family.
The story takes us through The Blitz, the air raid shelters, rolling blackouts and rationing that took place over the years as Hitler and the Nazis spread through Europe.
I've not read any wartime books, so this was an experience. Obviously: harrowing. The story does also do a good job of making me believe the life that tries to march on.]]></description>
      <content:encoded><![CDATA[<p>Quick easy read. Little repetitive, but shines a nice light.</p>
<p>The story starts in 1938 and we follow Gertie as she plans to retire as a widow having run a bookshop and successful book clubs for many years.</p>
<p>That's put on hold when she agrees to take in a child from the Kindertransport - which I'd know about but hadn't read a great deal of detail.</p>
<p>As a parent myself, this is the first part that breaks my brain a little, and indeed this part is entirely based in history. An amazing effort and so terrible too.</p>
<p>The story then follows Gertie as she takes care of Hedy, a 15 year old German Jew who also longs to be reunited with her family.</p>
<p>The story takes us through The Blitz, the air raid shelters, rolling blackouts and rationing that took place over the years as Hitler and the Nazis spread through Europe.</p>
<p>I've not read any wartime books, so this was an experience. Obviously: harrowing. The story does also do a good job of making me believe the life that tries to march on.</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2026/the-air-raid-book-club">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>The infinite scroll may become endangered if controversial Calif. law passes [link]</title>
      <guid isPermaLink="false">2026-07-14-c60c39d6</guid>
      <link>https://remysharp.com/links/2026-07-14-c60c39d6</link>
      <pubDate>Tue, 14 Jul 2026 19:12:57 +0000</pubDate>
      <description><![CDATA[I've been banging on about this for a while now and I absolutely welcome the prospect of this being a reality, and hopefully not just for children. Adults desperately need it too:
Under Assembly Bill 1709 by Democratic Assemblyman Josh Lowenthal, social media companies might soon be forced to remove addictive features.

infinite scroll, auto play, recommended algorithms, and push notifications are product features. They are not speech.

Original link: www.sfgate.com/[…]/meta-social-media-teenagers-22337724.php]]></description>
      <content:encoded><![CDATA[
<p>I've been banging on about this for a while now and I absolutely welcome the prospect of this being a reality, and hopefully not <em>just</em> for children. Adults desperately need it too:</p>
<p>Under Assembly Bill 1709 by Democratic Assemblyman Josh Lowenthal, social media companies might soon be forced to remove addictive features.</p>
<blockquote>
<p>infinite scroll, auto play, recommended algorithms, and push notifications are product features. They are not speech.</p>
</blockquote>
<p><em>Original link: <a href="https://www.sfgate.com/politics/article/meta-social-media-teenagers-22337724.php">www.sfgate.com/[…]/meta-social-media-teenagers-22337724.php</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-07-14-c60c39d6">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>In defense of polyfills • Lea Verou [link]</title>
      <guid isPermaLink="false">2026-07-14-6ee288d7</guid>
      <link>https://remysharp.com/links/2026-07-14-6ee288d7</link>
      <pubDate>Tue, 14 Jul 2026 12:24:16 +0000</pubDate>
      <description><![CDATA[An excellent post on polyfills, talking through their impact, what issues people (mostly in the standards world) face.
Chock full of quotable lines, way too many to include to do the post any justice, save perhaps Lea's last headline:

Polyfills make the Web faster, inclusive, and more robust

Highly recommend reading for a greater understanding of the role of polyfills on the web.
Original link: lea.verou.me/[…]/polyfills]]></description>
      <content:encoded><![CDATA[
<p>An excellent post on polyfills, talking through their impact, what issues people (mostly in the standards world) face.</p>
<p>Chock full of quotable lines, way too many to include to do the post any justice, save perhaps Lea's last headline:</p>
<blockquote>
<p>Polyfills make the Web faster, inclusive, and more robust</p>
</blockquote>
<p>Highly recommend reading for a greater understanding of the role of polyfills on the web.</p>
<p><em>Original link: <a href="https://lea.verou.me/blog/2026/polyfills/">lea.verou.me/[…]/polyfills</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-07-14-6ee288d7">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>This was the first commit via an LLM to git [link]</title>
      <guid isPermaLink="false">2026-07-12-4e9c9652</guid>
      <link>https://remysharp.com/links/2026-07-12-4e9c9652</link>
      <pubDate>Sun, 12 Jul 2026 15:44:27 +0000</pubDate>
      <description><![CDATA[TIL: git (the command line tool) now contains LLM generated code (I'm still unsure, we're calling this generative AI, right?). Landed in Jan 2026.
I appreciate there's some folks out there that don't want to touch LLM generated content or have it in your tool chains, I'm just going to assume that's going to be very hard as time goes on.
Though I do also appreciate there are projects working thanklessly to achieve just that.
Original link: github.com/[…]/d7971544fe17378f44f49983010dbfc1834f7bef]]></description>
      <content:encoded><![CDATA[
<p>TIL: git (the command line tool) now contains LLM generated code (I'm still unsure, we're calling this generative AI, right?). Landed in Jan 2026.</p>
<p>I appreciate there's some folks out there that don't want to touch LLM generated content or have it in your tool chains, I'm just going to assume that's going to be very hard as time goes on.</p>
<p>Though I do also appreciate there are projects working thanklessly to achieve <a href="https://git-annex.branchable.com/no_llm_code/">just that</a>.</p>
<p><em>Original link: <a href="https://github.com/git/git/commit/d7971544fe17378f44f49983010dbfc1834f7bef">github.com/[…]/d7971544fe17378f44f49983010dbfc1834f7bef</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-07-12-4e9c9652">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Wildcards In CSS [blog]</title>
      <guid isPermaLink="false">wildcards-in-css</guid>
      <link>https://remysharp.com/2026/07/11/wildcards-in-css</link>
      <pubDate>Sat, 11 Jul 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[Just a brainfart here, but it's odd that even though we have wildcard selectors throughout CSS, and even partial selectors (I'll explain in a bit) we don't have partial wildcard selectors on top level elements.
I'm not talking about the &quot;star&quot; rule, but what I imagine would be a wildcard on elements selector.]]></description>
      <content:encoded><![CDATA[
<p>Just a brainfart here, but it's odd that even though we have wildcard selectors throughout CSS, and even partial selectors (I'll explain in a bit) we don't have partial wildcard selectors on top level elements.</p>
<p>I'm not talking about the &quot;star&quot; rule, but what I imagine would be a wildcard on elements selector.</p>
<h2>Existing methods</h2>
<p>If I want to select and style all the <code>.btn-*</code> classes using <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/Attribute_selectors">attribute selector</a>, I'd do this:</p>
<pre><code class="language-css"><span class="token selector">[class^="btn-" i]</span> <span class="token punctuation">{</span>
  …
<span class="token punctuation">}</span>
</code></pre>
<p>This selector says: find all the elements with the class attribute that starts with &quot;btn-&quot; - case insensitive.</p>
<p>It's rather brittle, because it requires that the HTML class attribute starts exactly with <code>btn-</code>. Though it works, it does tie the HTML closely to the CSS - which I'd argue you'd want to be very sure you need to do.</p>
<p>But it is possible.</p>
<p>Equally, and a lot more robust, is the wildcard that says &quot;anywhere in the attribute&quot;, so:</p>
<pre><code class="language-css"><span class="token selector">[class*="btn"]</span> <span class="token punctuation">{</span>
  …
<span class="token punctuation">}</span>
</code></pre>
<p>It's fine, but it's a bit sledgehammery. However, if you want to do the same thing for a web component, for instance, you can't.</p>
<p>If I want to target all the <code>rem-xxx</code> custom components using <code>rem-* { … }</code>, I can't.</p>
<p>Obviously I'm not the first to think of this, and <em>of course</em> the venerable <a href="https://lea.verou.me/">Lea Verou</a> has thought about this and <a href="https://github.com/w3c/csswg-drafts/issues/10001">filed the issue</a> over two years ago, though there doesn't seem to be much interest in supporting it.</p>
<p>The reason it crossed my mind is that I was thinking about how you would initialise web components on a page, and currently it requires searching every single element in the DOM, rather than targetting to the nodes you want ahead of time.</p>
<p>From this <a href="https://developer.mozilla.org/en-US/blog/mdn-front-end-deep-dive/">MDN article</a> they included a code snippet that (I thought) was a clever way to initialise the components:</p>
<pre><code class="language-js"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> element <span class="token keyword">of</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">"*"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> tag <span class="token operator">=</span> element<span class="token punctuation">.</span>tagName<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>tag<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">"mdn-"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> component <span class="token operator">=</span> tag<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">"mdn-"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">../components/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>component<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/element.js</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>
</code></pre>
<p>But really, it should be:</p>
<pre><code class="language-js"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> element <span class="token keyword">of</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">"mdn-*"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> component <span class="token operator">=</span> element<span class="token punctuation">.</span>tagName<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">"mdn-"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">../components/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>component<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/element.js</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>This feels like a relatively cheap change to add support for wildcards, and gives the <code>querySelectorAll</code> a nice little boost, along with the benefits Lea already outlined in the github issue she raised.</p>
<h2>Would it be valid?</h2>
<p>I swear I found the documentation that read that the <code>*</code> asterisk was reserved for the universal selector (i.e. match all things), but I can't find it any more.</p>
<p>However, the from my memory, the parser only allows an asterisk <em>after</em> a space, to indicate it's a universal selector, so <code>foo*</code> or <code>foo-*</code> would not match in the parser.</p>
<p>Equally, it's allowed in the attribute selector, but <a href="https://www.w3.org/TR/selectors-4/#attribute-substrings">only when followed</a> by <code>=</code>, but attribute selector already has wildcard support. But maybe this would be extended to cover &quot;glob&quot; like support, so I could do <code>.foo*bar</code> to match <code>.foo-dont-do-it-bar</code>. Again, the current parser doesn't allow for this, so that means it's available for use.</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/07/11/wildcards-in-css">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>AI Content Is Everywhere on Social Media, Especially LinkedIn [link]</title>
      <guid isPermaLink="false">2026-07-09-9fd775a9</guid>
      <link>https://remysharp.com/links/2026-07-09-9fd775a9</link>
      <pubDate>Thu, 09 Jul 2026 16:54:07 +0000</pubDate>
      <description><![CDATA[When I think of AI slop, as a developer working on or around the web, I tend to think of dev-centric content, such as blog posts or even software (a lot of the community I'm connected to will call software slop).
Still, it's useful to be reminded that AI generated content is much, much farther reaching.
This project used a Chrome extension (with paid users, from what I could test) and collected a tonne of data and shows for products like LinkedIn, Medium and Twitter, it's anything from 30-50% of AI slop.
Lots of easy to scan charts.
I tend to only use LinkedIn to post about FFConf, then I immediately leave, and I use Reddit for either Gameboy or Home Assistant content, so I'm not really coming across this kind of content myself (or that I've noticed).
Original link: www.pangram.com/[…]/ai-in-your-feed]]></description>
      <content:encoded><![CDATA[
<p>When I think of AI slop, as a developer working on or around the web, I tend to think of dev-centric content, such as blog posts or even software (a lot of the community I'm connected to will call software slop).</p>
<p>Still, it's useful to be reminded that AI generated content is much, much farther reaching.</p>
<p>This project used a Chrome extension (with paid users, from what I could test) and collected a tonne of data and shows for products like LinkedIn, Medium and Twitter, it's anything from 30-50% of AI slop.</p>
<p>Lots of easy to scan charts.</p>
<p>I tend to only use LinkedIn to post about FFConf, then I immediately leave, and I use Reddit for either Gameboy or Home Assistant content, so I'm not really coming across this kind of content myself (or that I've noticed).</p>
<p><em>Original link: <a href="https://www.pangram.com/blog/ai-in-your-feed">www.pangram.com/[…]/ai-in-your-feed</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-07-09-9fd775a9">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Web Platform Wishlist on Vale.Rocks [link]</title>
      <guid isPermaLink="false">2026-07-09-221b1dd2</guid>
      <link>https://remysharp.com/links/2026-07-09-221b1dd2</link>
      <pubDate>Thu, 09 Jul 2026 08:41:02 +0000</pubDate>
      <description><![CDATA[I remember the days I was hungry for features on the web…it was…a long time ago! So it's refreshing to read that others still have ideas and want more.
I especially like these two from the post:

Text overflow truncation from centre…

And:

More pseudo-classes. :sticky for if an element is currently sticky, :overflow for if overflowing, etc

Which falls consistently into the category of &quot;JavaScript is used to do this, it shouldn't need to&quot;.
Original link: vale.rocks/[…]/web-platform-wishlist]]></description>
      <content:encoded><![CDATA[
<p>I remember the days I was hungry for features on the web…it was…a long time ago! So it's refreshing to read that others still have ideas and want more.</p>
<p>I especially like these two from the post:</p>
<blockquote>
<p>Text overflow truncation from centre…</p>
</blockquote>
<p>And:</p>
<blockquote>
<p>More pseudo-classes. :sticky for if an element is currently sticky, :overflow for if overflowing, etc</p>
</blockquote>
<p>Which falls consistently into the category of &quot;JavaScript is used to do this, it shouldn't need to&quot;.</p>
<p><em>Original link: <a href="https://vale.rocks/posts/web-platform-wishlist">vale.rocks/[…]/web-platform-wishlist</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-07-09-221b1dd2">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>querySelector immediate children with :scope [link]</title>
      <guid isPermaLink="false">2026-07-08-05cd4aed</guid>
      <link>https://remysharp.com/links/2026-07-08-05cd4aed</link>
      <pubDate>Wed, 08 Jul 2026 20:23:59 +0000</pubDate>
      <description><![CDATA[Came across this nice little TIL in the qSA API:

parentNode.querySelectorAll('&gt; *') you get an error: '&gt; *' is not a valid selector.. That doesn't work...

Using :scope first fixes the &quot;missing scope&quot;.
Original link: siderite.dev/[…]/queryselector-immediate-children-with-scope]]></description>
      <content:encoded><![CDATA[
<p>Came across this nice little TIL in the qSA API:</p>
<blockquote>
<p>parentNode.querySelectorAll('&gt; *') you get an error: '&gt; *' is not a valid selector.. That doesn't work...</p>
</blockquote>
<p>Using <code>:scope</code> first fixes the &quot;missing scope&quot;.</p>
<p><em>Original link: <a href="https://siderite.dev/blog/queryselector-immediate-children-with-scope/">siderite.dev/[…]/queryselector-immediate-children-with-scope</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-07-08-05cd4aed">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Fundamentally [book]</title>
      <guid isPermaLink="false">fundamentally</guid>
      <link>https://remysharp.com/books/2026/fundamentally</link>
      <pubDate>Mon, 06 Jul 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[Loved it. Intelligent and genuinely made me laugh.
This book was recommended in our work Slack, and just pull quote for the book description, I found myself instantly buying it:

By normal, you mean like you? A slag with a saviour complex?

The story follows Nadia, an academic who is pulled into a job with the UN to apply her proposal to rehabilitate ISIS brides so they can leave the camps and return home.
What I really enjoyed about this book was the exposure to completely different backgrounds to my own. So for an example, Nadia is Muslim. She has turned her back on her faith. She's gone into academia, and she's now offered a job in the UN to help these ISIS brides.
Most of the characters are completely different to the people in my real life, but the writing is steeped in reality (the author's note at the end explains that she, Younis, was a humanitarian worker known for her expertise on contemporary Iraq, and that though fictionalised, there's a lot of real experience in the story).
Nadia's character is witty, flawed, pissed off, broken and I found myself actually laughing out loud at some of the lines from the book. The book's blurb includes the following line, which I absolutely felt was accurate:

A bitingly original, wildly funny and razor-sharp exploration of love, family, religion, radicalism[…]

I really enjoyed the book, and found it hard to put down - as seen in my 10 day read of what normally takes me a month.
For a first novel, from someone that on paper is very academic and doing very serious work, this is A*. Love it.]]></description>
      <content:encoded><![CDATA[<p>Loved it. Intelligent and genuinely made me laugh.</p>
<p>This book was recommended in our work Slack, and <em>just</em> pull quote for the book description, I found myself instantly buying it:</p>
<blockquote>
<p>By normal, you mean like you? A slag with a saviour complex?</p>
</blockquote>
<p>The story follows Nadia, an academic who is pulled into a job with the UN to apply her proposal to rehabilitate ISIS brides so they can leave the camps and return home.</p>
<p>What I really enjoyed about this book was the exposure to completely different backgrounds to my own. So for an example, Nadia is Muslim. She has turned her back on her faith. She's gone into academia, and she's now offered a job in the UN to help these ISIS brides.</p>
<p>Most of the characters are completely different to the people in my real life, but the writing is steeped in reality (the author's note at the end explains that she, Younis, was a humanitarian worker known for her expertise on contemporary Iraq, and that though fictionalised, there's a lot of real experience in the story).</p>
<p>Nadia's character is witty, flawed, pissed off, broken and I found myself actually laughing out loud at some of the lines from the book. The book's blurb includes the following line, which I absolutely felt was accurate:</p>
<blockquote>
<p>A bitingly original, wildly funny and razor-sharp exploration of love, family, religion, radicalism[…]</p>
</blockquote>
<p>I really enjoyed the book, and found it hard to put down - as seen in my 10 day read of what normally takes me a month.</p>
<p>For a first novel, from someone that on paper is very academic and doing <em>very</em> serious work, this is A*. Love it.</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2026/fundamentally">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Why we moved our Bluesky data to Eurosky [link]</title>
      <guid isPermaLink="false">2026-07-01-8272e198</guid>
      <link>https://remysharp.com/links/2026-07-01-8272e198</link>
      <pubDate>Wed, 01 Jul 2026 20:15:32 +0000</pubDate>
      <description><![CDATA[As I've been seeing more and more posts about PDS and things like &quot;lexicons&quot; such as standard.site, I've been thinking more about how Bluesky is the main hub of all our our social data (for those left twitter and of course putting aside Mastodon for a moment).
This post gives a good high level overview of my own concerns about Bluesky being that hub, and though the post doesn't explain how they moved to Eurosky (and funnily enough then link to follow them on Bluesky) - it tries to demonstrate that it is possible to move data around.
I wonder how far we are from being able to self host and connect into the network to disseminate (I think this is the &quot;relay&quot; and I'm fairly sure this is far from trivial for a self-host job).
Still, one I'm keeping my eye on.
Source: waag.org]]></description>
      <content:encoded><![CDATA[
<p>As I've been seeing more and more posts about PDS and things like &quot;lexicons&quot; such as standard.site, I've been thinking more about how Bluesky is the main hub of all our our social data (for those left twitter and of course putting aside Mastodon for a moment).</p>
<p>This post gives a good high level overview of my own concerns about Bluesky being that hub, and though the post doesn't explain <em>how</em> they moved to Eurosky (and funnily enough then link to follow them on Bluesky) - it tries to demonstrate that it <em>is</em> possible to move data around.</p>
<p>I wonder how far we are from being able to self host and connect into the network to disseminate (I <em>think</em> this is the &quot;relay&quot; and I'm fairly sure this is far from trivial for a self-host job).</p>
<p>Still, one I'm keeping my eye on.</p>
<p><em>Source: <a href="https://waag.org/en/article/why-we-moved-our-bluesky-data-eurosky/">waag.org</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-07-01-8272e198">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Under the hood of MDN's new frontend [link]</title>
      <guid isPermaLink="false">2026-06-30-99723827</guid>
      <link>https://remysharp.com/links/2026-06-30-99723827</link>
      <pubDate>Tue, 30 Jun 2026 14:04:43 +0000</pubDate>
      <description><![CDATA[A long article (23 min read!) on the rebuild of MDN away from React and into Web Components.
There's lots in there, but I particularly like the section starting Web Components that writes about how they're progressively enhancing and how there's thought to the components (such as their mdn-dropdown styles).
I also really like this pattern where modules are auto-loaded and it's easy to switch JS enabled modules off for testing:
for (const element of document.querySelectorAll(&quot;*&quot;)) {
  const tag = element.tagName.toLowerCase();
  if (tag.startsWith(&quot;mdn-&quot;)) {
    const component = tag.replace(&quot;mdn-&quot;, &quot;&quot;);
    import(`../components/${component}/element.js`);
  }
}

Source: developer.mozilla.org]]></description>
      <content:encoded><![CDATA[
<p>A long article (23 min read!) on the rebuild of MDN away from React and into Web Components.</p>
<p>There's lots in there, but I particularly like the section starting Web Components that writes about how they're progressively enhancing and how there's thought to the components (such as their <code>mdn-dropdown</code> styles).</p>
<p>I also really like this pattern where modules are auto-loaded and it's easy to switch JS enabled modules off for testing:</p>
<pre><code>for (const element of document.querySelectorAll(&quot;*&quot;)) {
  const tag = element.tagName.toLowerCase();
  if (tag.startsWith(&quot;mdn-&quot;)) {
    const component = tag.replace(&quot;mdn-&quot;, &quot;&quot;);
    import(`../components/${component}/element.js`);
  }
}
</code></pre>
<p><em>Source: <a href="https://developer.mozilla.org/en-US/blog/mdn-front-end-deep-dive/">developer.mozilla.org</a></em></p>
<p><em>Originally published on <a href="https://remysharp.com/links/2026-06-30-99723827">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Decompressing 33 signal bytes [blog]</title>
      <guid isPermaLink="false">decompressing-33-signal-bytes</guid>
      <link>https://remysharp.com/2026/06/29/decompressing-33-signal-bytes</link>
      <pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[In my RSS reader, I stumbled upon this code-golfed (i.e. minimised to death) snippet that's fairly clever, but from the code, utterly opaque.
I couldn't immediately see how it worked, and since Copilot autocompletes most of my code for me - whether I want to or not, I figured it was a good bit of practice to decompress and understand.
First things first: snooze the little copilot bastard for an hour!]]></description>
      <content:encoded><![CDATA[<p>In my RSS reader, I stumbled upon this code-golfed (i.e. minimised to death) <a href="https://gist.github.com/GulgDev/7b113b5e971682a6512d96c9c0fdf6da">snippet</a> that's fairly clever, but from the code, utterly opaque.</p>
<p>I couldn't immediately see how it worked, and since Copilot autocompletes most of my code for me - whether I want to or not, I figured it was a good bit of practice to decompress and understand.</p>
<p>First things first: snooze the little copilot bastard for an hour!</p>
<p><em>Side note: because I got this post through my reader, I didn't happen to clock the link right after (<a href="https://javascriptweekly.com/issues/791">in the newsletter</a>) that read &quot;a Redditor breaks down exactly what's going on&quot;. So…um…yeah, I guess wasted energy, but probably good for my brain.</em></p>
<p>Here's the original author's code:</p>
<pre><code class="language-js"><span class="token comment">// 33 bytes</span>
<span class="token keyword">const</span> <span class="token function-variable function">signal</span> <span class="token operator">=</span> <span class="token parameter"><span class="token constant">F</span></span><span class="token operator">=></span><span class="token punctuation">(</span><span class="token parameter">f<span class="token punctuation">,</span><span class="token constant">G</span><span class="token operator">=</span><span class="token constant">F</span></span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token constant">F</span><span class="token operator">=</span>f<span class="token operator">?</span><span class="token parameter">_</span><span class="token operator">=></span><span class="token function">f</span><span class="token punctuation">(</span><span class="token constant">G</span><span class="token operator">?.</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">:</span><span class="token constant">F</span><span class="token operator">?.</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>The crux is that it creates a wrapped stack of callbacks. Effectively recursion through locally defined (and overwritten) variables (<code>G</code> in this case).</p>
<p>I started by unpacking the implicit returns so I could see more of what was going on (and renamed <code>F</code> to <code>callback</code>)</p>
<pre><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">__signal</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">callback</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token parameter">f<span class="token punctuation">,</span> <span class="token constant">G</span><span class="token operator">=</span>callback</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> callback <span class="token operator">=</span> f <span class="token operator">?</span> <span class="token parameter">_</span> <span class="token operator">=></span> <span class="token function">f</span><span class="token punctuation">(</span><span class="token constant">G</span><span class="token operator">?.</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">:</span> callback<span class="token operator">?.</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>From there, I &quot;simplified&quot; everything as far as I could so that that all the neat tricks could be seen. This certainly isn't <em>better</em> code (probably a version of the one above with nicer names would work).</p>
<pre><code class="language-js"><span class="token comment">/**
 * The function stores local variables that are
 * overwritten * with a call stack of passed in
 * functions. When the argument is falsy, then
 * the stack is unwound.
 *
 * Call stack looks like: four(three(two(one())))
 */</span>
<span class="token keyword">function</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token comment">/*F*/</span> callbackStack<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token comment">/*f*/</span> callback<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token comment">// Each new time the signal singleton is called, it</span>
    <span class="token comment">// creates a new copy of the `callbackStack`,</span>
    <span class="token comment">// originally as an argument which saves on the</span>
    <span class="token comment">// `const` part.</span>

    <span class="token keyword">const</span> localCopy <span class="token operator">=</span> callbackStack<span class="token punctuation">;</span> <span class="token comment">/*G=F*/</span>

    <span class="token comment">// if we're passed a callback, then redefine</span>
    <span class="token comment">// `callbackStack` with where the local copy is</span>
    <span class="token comment">// called first, then we run the callback.</span>
    <span class="token comment">// Calling this singleton multiple times creates</span>
    <span class="token comment">// a stack of functions like:</span>
    <span class="token comment">//</span>
    <span class="token comment">// four(three(two(one())))</span>
    <span class="token comment">//</span>
    <span class="token comment">// there's also the initial protection with `?.()`</span>
    <span class="token comment">// to allow for `callbackStack` to be `undefined`.</span>
    <span class="token comment">// In the example below, I've just unrolled the code.</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>callback<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/*F=f?*/</span>

      <span class="token comment">/*f(G?.())*/</span>
      <span class="token function-variable function">callbackStack</span> <span class="token operator">=</span> <span class="token parameter">_</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>localCopy<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token function">localCopy</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">return</span> <span class="token function">callback</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> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      <span class="token comment">// otherwise, when called without any arguments,</span>
      <span class="token comment">// and the `callbackStack` is executed and</span>
      <span class="token comment">// overwritten at the same time.</span>

      <span class="token keyword">if</span> <span class="token punctuation">(</span>callbackStack<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        callbackStack <span class="token operator">=</span> <span class="token function">callbackStack</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*F?.()*/</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// the original code returns the `callbackStack`</span>
    <span class="token comment">// through the implicit return, but it's not actually</span>
    <span class="token comment">// used for anything, it's just a side effect of</span>
    <span class="token comment">// compressing the code.</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Obviously this isn't the point of code-golf, to take someone's hard work and walk them back to the start (and probably even further back), but it was a good bit of brain exercise for me.</p>
<p>For comparison, here's the <a href="https://www.reddit.com/r/javascript/comments/1uc0scy/comment/ot4dm0o/">Redditor's explanation</a>.</p>
<p><em>Originally published on <a href="https://remysharp.com/2026/06/29/decompressing-33-signal-bytes">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Platform Decay (The Murderbot Diaries, #8) [book]</title>
      <guid isPermaLink="false">platform-decay</guid>
      <link>https://remysharp.com/books/2026/platform-decay</link>
      <pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[Solid entry into the series.
I've read all the previous Murderbot books, but since the last, I also watched the TV series - which I equally enjoyed, but…or put a weird spin on reading this latest book.
I'd entirely forgotten the &quot;diary&quot; part, and because of the TV series, I had the external perspective and wondered why this book was both being told from Murderbot's internal monologue, but also why there was so much…noise, I guess the word would be.
Once I'd finally remembered that this was the actual format of the book I settled into it, reminding myself there wouldn't be huge character developments (because the diaries tend to last for one mission/episode).
Still, the Murderbot character is in fact growing and evolving and that's fun to read.
The story pulled me along pretty well. Not quite the rip roaring page turner, but a solid entry all the same.
I'm not 100% sure you could just pick this book up without having read at least a few previous books, which is why I hadn't rated it higher (the very first novellas are absolutely excellent).
Enjoyable, even if it took me a minute to remember the specific Murderbot format.]]></description>
      <content:encoded><![CDATA[<p>Solid entry into the series.</p>
<p>I've read all the previous Murderbot books, but since the last, I also watched the TV series - which I equally enjoyed, but…or put a weird spin on reading this latest book.</p>
<p>I'd entirely forgotten the &quot;diary&quot; part, and because of the TV series, I had the external perspective and wondered why this book was both being told from Murderbot's internal monologue, but also why there was so much…noise, I guess the word would be.</p>
<p>Once I'd finally remembered that this was the actual format of the book I settled into it, reminding myself there wouldn't be huge character developments (because the diaries tend to last for one mission/episode).</p>
<p>Still, the Murderbot character is in fact growing and evolving and that's fun to read.</p>
<p>The story pulled me along pretty well. Not quite the rip roaring page turner, but a solid entry all the same.</p>
<p>I'm not 100% sure you could just pick this book up without having read at least a few previous books, which is why I hadn't rated it higher (the very first novellas are absolutely excellent).</p>
<p>Enjoyable, even if it took me a minute to remember the specific Murderbot format.</p>
<p><em>Originally published on <a href="https://remysharp.com/books/2026/platform-decay">Remy Sharp's b:log</a></em></p>]]></content:encoded>
    </item>
    <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>
  </channel>
</rss>