Jeremy Keith
adactio.com.web.brid.gy
Jeremy Keith
@adactio.com.web.brid.gy
Making websites. Writing books. Hosting a podcast. Speaking at events. Living in Brighton. Working at Clearleft. Playing music. Taking photos. Answering email.
Nollaig shona daiobh go léir, a chairde!
December 25, 2025 at 9:02 PM
Christmas with Sandy
December 25, 2025 at 6:22 AM
No stars
It’s getting towards the end of the year. That’s when I put together a post reviewing the books I’ve read in the previous twelve months. I think I might change things up in 2026. Instead of waiting until the end of the year to write all the little reviews at once, I think I should write a review as soon as I finish a book. Instead of holding onto my reckons for months, I can just set them free one at a time. And I think I’m done with ratings. Stars. I’m not sure why I ever started, to be honest. Probably because everyone else was doing it. But they kind of just get in the way. I spend far too long deliberating about how many stars to give a book when I should be spending that time describing the effect that the book had on me. In any case, books, movies, music …it’s all entirely subjective. Assigning stars gives a veneer of something measurable, countable, and objective. That’s not how art works. But that’s just my opinion. I think I’ve also developed more of an aversion to scoring things the more it’s crept into everyday life. It feels like you can’t perform any kind of transaction without being asked later to rate the experience. I remember the first time I was ever in an Uber. This was many years ago in San Francisco. I was with a bunch of friends at an after-party for An Event Apart in the TypeKit offices. Someone suggested that we move on to a second location and proceeded to whip out the Uber app. I remember looking at the little icon of the car moving in real time as it approached our location. So futuristic! We all bundled into the car and off we went. The driver was a really nice guy. But at some point he made a navigational error and took us off track. He fixed it, but I remember my friend who had summoned the Uber was kind of miffed. When we were getting out of the car, the driver apologised profusely before driving off. My friend—who was basically showing me how this whole Uber thing worked—explained that he would now give a less than stellar review for the driver, becuase of that directional snafu. “Ah, come on”, I said, “he was a nice guy.” “This is how the app gets accurate data”, he responded. “But …it’s a person”, I said. Something about reviewing a person felt so wrong to me. Books, movies, music …I get it. But applying the same logic to a human being. That just didn’t sit right with me. Now we’re expected to review humans all the time. It still feels wrong to me. That’s probably why I’m done with ratings. No more stars from me.
adactio.com
December 24, 2025 at 12:36 AM
Sleepy Sandy
December 22, 2025 at 3:37 AM
Arizona
December 22, 2025 at 3:32 AM
Waking up in an airport hotel room with a runway view.
December 20, 2025 at 2:13 PM
Going to Arizona. brb
December 19, 2025 at 1:45 PM
Thursday session
December 18, 2025 at 7:12 PM
> Tradition is not the worship of ashes, but the preservation of fire.
December 18, 2025 at 11:40 AM
Wednesday session
December 17, 2025 at 8:38 PM
Tunes and typefaces
In an Irish session, tunes are almost never played in isolation. They’re played in sets. A set of tunes might be as few as two. More usually, it’s three or more. It’s unusual to change from one tune _type_ into another. You tend to get a set of jigs, or a set of reels, or a set of hornpipes. But it’s very common to change _key_ within a set. In fact, that’s often where a good set really stands out. There can be a real joy at that moment of switching. You might get a “Hup!” from someone listening to the session at that changeover. So how do you decide what tunes to play in a set? There are no real rules to this. Some people make up the set on the fly. Or you might try playing a set that you’ve heard other people play, maybe on a recording you like. On the one hand, you’re looking for contrast. You probably don’t want to play three tunes all in the same key. On the other hand, it’s nice when there’s some kind of connection between the tunes—something about the phrasing or emphasis perhaps. Pairing tunes for sets always reminds me of pairing typefaces. You don’t want the body copy and the headlines to be too similar, but you do want them to share some quality. In his classic book, On Web Typography, Jason says: > When it comes to choosing and pairing typefaces, I keep two things in mind: _distinction_ and _harmony_. To keep the system you’ve created for visual communication properly balanced, you need to choose typefaces that don’t compete too much with each other, but aren’t so similar as to be indistinguishable. The same could be said for pairing tunes in sets! Jason also says: > As another approach, opt for typefaces that share the same maker. That can work for sets of tunes too. While most tunes are traditional, with no known composer, the really good composed tunes have entered the canon. I’ve taken Jason’s advice for typefaces and applied to sets by playing a set of tunes by Junior Crehan or a set of tunes by Vincent Broderick. Mostly though, there’s no real system to it. Or at least, not one that can be easily articulated. Like Jason says: > And we’re back to that old chestnut about rules: there are many right answers, and no answers are really _wrong_ ; there are just different degrees of _good_.
adactio.com
December 17, 2025 at 10:19 AM
Spaceships, atoms, and cybernetics
Maureen has written a really good overview of web feeds for this year’s HTMHell advent calendar. The common belief is that nobody uses RSS feeds these days. And while it’s true that I wish more people used feed readers—the perfect antidote to being fed from an algorithm—the truth is that millions of people use RSS feeds every time they listen to a podcast. That’s what a podcast is: an RSS feed with `enclosure` elements that point to audio files. And just as a web feed doesn’t necessarily need to represent a list of blog posts, a podcast doesn’t necessarily need to be two or more people having a recorded conversation (though that does seem to be the most common format). A podcast can tell a story. I like those kinds of podcasts. The BBC are particularly good at this kind of episodic audio storytelling. I really enjoyed their series Thirteen minutes to the moon, all about the Apollo 11 mission. They followed it up with a series on Apollo 13, and most recently, a series on the space shuttle. Here’s the RSS feed for the 13 minutes podcast. Right now, the BBC have an ongoing series about the history of the atomic bomb. The first series was about Leo Szilard, the second series was about Klaus Fuchs, and the third series running right now is about the Cuban missile crisis. The hook is that each series is presented by people with a family connection to the events. The first series is presented by the granddaughter of one of the Oak Ridge scientists. The second series is presented by the granddaughter of Klaus Fuch’s spy handler in the UK—blimey! And the current series is presented by Nina Khrushcheva and Max Kennedy—double blimey! Here’s the RSS feed for The Bomb podcast. If you want a really deep dive into another pivotal twentieth century event, Evgeny Morozov made a podcast all about Stafford Beer and Salvadore Allende’s collaboration on cybernetics in Chile, the fabled Project Cybercyn. It’s fascinating stuff, though there’s an inevitable feeling of dread hanging over events because we know how this ends. The podcast is called The Santiago Boys, though I almost hesitate to call it a podcast because for some reason, the website does its best to hide the RSS feed, linking only to the silos of Spotify and Apple. Fortunately, thanks to this handy tool, I can say: Here’s the RSS feed for The Santiago Boys podcast. The unifying force behind all three of these stories is the cold war: * 13 Minutes—the space race, from the perspective of the United States. * The Bomb—the nuclear arms race, from Los Alamos to Cuba. * The Santiago Boys—the CIA-backed overthrow of a socialist democracy in Chile.
adactio.com
December 16, 2025 at 9:46 AM
Reading Prophet Song by Paul Lynch.
December 15, 2025 at 11:39 PM
Pan-fried Irish salmon.
December 13, 2025 at 3:09 PM
Skip intro
There’s the old adage “nobody gets fired for buying IBM”. Or to put it more broadly, “everyone else is doing it.” It’s dispiriting how often this explanation is given as justification for a dubious design decision, from home-page carousels to cookie banners. Nic Chan has written a great post about designing a contact form and how the process was derailed by the client pointing to other people’s contact forms …even when they’ve got very, very different user needs. It’s especially depressing when “everyone else is doing it” is used a substitute for any kind of accountability. Building an email service that’s going to track when people click on links in an email? That sounds dodgy. On the other hand, everyone else is doing it. Building a straightforward website, but making it a single-page app with client-side React that will be barely work on some devices and networks? That seems over-engineered. On the other hand, everyone else is doing it. Sometimes the “everyone else is doing it” phenomenon leads to a chain reaction where nobody even knows why anyone ever did it in the first place. Remember Flash? Remember when almost every website had a Flash intro? Everyone knew they were annoying and uneccessary, but everyone else was doing it. Instead of getting rid of the intros, we got “skip intro” links instead. This link was guaranteed to have a 100% clickthrough rate. I’ve noticed something similar with conference talks. So many of them begin with a little spiel about the speaker, their background, and their work experience. This might be interesting information, but this isn’t the right time or place for it. It’s already on the conference website, in the conference programme, and has probably just been reiterated by the conference host who just introduced the speaker. When I’ve asked why people do this, the responses generally come down to “everyone else is doing it.” It’s become an expected part of the conference talk, just like a Flash intro used to be an expected part of a website. When I’m curating a conference, I like to send speakers some information to help them prepare their talk. Some of this is practical stuff, like the tech set-up. Some of it is guidance for the slides, like ensuring sufficient colour contrast. And then there’s this: > Please don’t begin your talk with an introduction about yourself and your work history. You’ll be introduced on stage so it would be a shame to just repeat all that again. Also, it just gets in the way of the actual content of your talk. No need to provide your bona-fides. Personally, I just find it super cringe. That’s why I don’t do it if I’m giving a talk myself. As a host however, it’s a big part of my job. It’s way less cringe to have someone else big you up before the talk then doing it yourself.
adactio.com
December 11, 2025 at 12:17 PM
Sultans!
December 10, 2025 at 4:05 PM
Going to Cobh. brb
December 10, 2025 at 10:32 AM
Reading Rose/House by Arkady Martine.
December 9, 2025 at 9:37 PM
Monday session
December 8, 2025 at 8:56 PM
Sunday roast
December 7, 2025 at 5:28 PM
Thursday session
December 4, 2025 at 11:33 PM
Wednesday session
December 3, 2025 at 8:24 PM
Fiddlers three
December 2, 2025 at 8:55 PM
Tuesday session
December 2, 2025 at 8:29 PM
Installing web apps
Safari, Chrome, and Edge all allow you to install websites as though they’re apps. On mobile Safari, this is done with the “Add to home screen” option that’s buried deep in the “share” menu, making it all but useless. On the desktop, this is “Add to dock” in Safari, or “Install” in Chrome or Edge. Firefox doesn’t offer this functionality, which as a shame. Firefox is my browser of choice but they decided a while back to completely abandon progressive web apps (though they might reverse that decision soon). Anyway, being able to install websites as apps is fantastic! I’ve got a number of these “apps” in my dock: Mastodon, Bluesky, Instagram, The Session, Google Calendar, Google Meet. They all behave just like native apps. I can’t even tell which browser I used to initially install them. If you’d like to prompt users to install your website as an app, there’s not much you can do other than show them how to do it. But that might be about to change… I’ve been eagerly watching the proposal for a Web Install API. This would allow authors to put a button on a page that, when clicked, would trigger the installation process (the user would still need to confirm this, of course). Right now it’s a JavaScript API called `navigator.install`, but there’s talk of having a declarative version too. Personally, I think this would be an ideal job for an invoker command. Making a whole new `install` element seems ludicrously over-engineered to me when `button invoketarget="share"` is right there. Microsoft recently announced that they’d be testing the JavaScript API in an origin trial. I immediately signed up The Session for the trial. Then I updated the site to output the appropriate HTTP header. You still need to mess around in the browser configs to test this locally. Go to `edge://flags` or `chrome://flags/` and search for ‘Web App Installation API’, enable it and restart. I’m now using this API on the homepage of The Session. Unsurprisingly, I’ve wrapped up the functionality into an HTML web component that I call `button-install`. Here’s the code. You use it like this: <button-install> <button>Install the app</button> </button-install> Use whatever text you like inside the button. I wasn’t sure whether to keep the `button` element in the regular DOM or generate it in the Shadow DOM of the custom element. Seeing as the button requires JavaScript to do anything, the Shadow DOM option would make sense. As Tess put it, Shadow DOM is for hiding your shame—the bits of your interface that depend on JavaScript. In the end I decided to stick with a regular `button` element within the custom element, but I take steps to remove it when it’s not necessary. There’s a potential issue in having an element that could self-destruct if the browser doesn’t cut the mustard. There might be a flash of seeing the button before it gets removed. That could even cause a nasty layout shift. So far I haven’t seen this problem myself but I should probably use something like Scott’s CSS in reverse: fade _in_ the button with a little delay (during which time the button might end up getting removed anyway). My `connectedCallback` method starts by finding the button nested in the custom element: class ButtonInstall extends HTMLElement { connectedCallback () { this.button = this.querySelector('button'); … } customElements.define('button-install', ButtonInstall); If the `navigator.install` method doesn’t exist, remove the button. if (!navigator.install) { this.button.remove(); return; } If the current `display-mode` is `standalone`, then the site has already been installed, so remove the button. if (window.matchMedia('(display-mode: standalone)').matches) { this.button.remove(); return; } As an extra measure, I could also use the `display-mode` media query in CSS to hide the button: @media (display-mode: standalone) { button-install button { display: none; } } If the button has survived these tests, I can wire it up to the `navigator.install` method: this.button.addEventListener('click', async (ev) => { await navigator.install(); }); That’s all I’m doing for now. I’m not doing any `try`/`catch` stuff to handle all the permutations of what might happen next. I just hand it over to the browser from there. Feel free to use this code if you want. Adjust the code as needed. If your manifest file says `display: fullscreen` you’ll need to change the test in the JavaScript accordingly. Oh, and make sure your site already has a manifest file that has an `id` field in it. That’s required for `navigator.install` to work.
adactio.com
November 29, 2025 at 12:23 PM