The Blogroll

From: Boagworld

Generative Imagery: Stop Settling for Stock

Stop settling for 'almost right' stock photos. A practical guide to generative imagery tools, when to use them, and how to get consistent results.

From: Adactio

Web Day Out × State Of The Browser

If you’re the kind of person who likes Web Day Out, you’re probably also the kind of person who likes State Of The Browser.

Web Day Out is all about what you can in web browsers right now, with an emphasis on immediately practical techniques and technologies. State Of The Browser is similar, but with room for fun demos that push the boundaries.

State Of The Browser is on Saturday, 28 February.

Web Day Out is on Thursday, 12 March.

It would be a shame if you had to choose between these two excellent events.

Well, you don’t have to!

If you buy a ticket for Web Day Out you can get a whopping 50% off the ticket price for State Of The Browser. Or if you can’t make it in person, your Web Day Out ticket gets you a free online ticket!

You might be thinking, “Well, much as I’d love to go to both events, I don’t think I can convince my boss to give me two conference days.” Worry ye not! State Of The Browser is on a Saturday, so unless you’re working an extremely extended work week, you still only need to take one day away from your desk to go to two events.

So don’t delay: get your ticket for Web Day Out. Then you’ll get an email with details on how to get your 50% discount for State Of The Browser (or your free online ticket, whichever you prefer).

But wait! What if you already bought a ticket for State Of The Browser? Check your email. You’ve been sent a very, very generous discount code for Web Day Out to thank you for getting your ticket nice and early.

I’ll see you at State Of The Browser in London …and then I’ll see you at Web Day Out in Brighton!

From: Chris Coyier

Just in case I haven’t made my feelings clear lately on the current United States of America administration, I shall blog. It’s the little things that make me think Donald Trump is a vindictive prick who, among his catalog of things he hates, is Black people. For instance, he’s chosen to change what days are […]

January 20, 2026, 5:26 pm >>

From: Chris Coyier

Worry Bird

I think the Worry Bird is a cute idea. You use it to, ya know, worry into, by rubbing your thumb into the satisfying little divot to do so. Of course, us web workers tend to turn our worry into superfluous personal website redesigns. [feels urge growing]

From: Adactio

Trad travels

For the past few years, I’ve been taking a trip to Spain at the end of September for the Cáceres Irish Fleadh. Last year I convinced my friends Liam and Monica to come along and they had a great time.

Like me, Liam just loves playing in sessions. Also like me, Liam likes to spend the gloomy short days of January thinking about travelling somewhere …and then playing in sessions there.

I told him I’d put together a list of potential trips for the discerning session hound. I figured I might as well share it here too…

First of all, there are Irish music festivals. Alas, most festivals don’t happen in the sunny climes of Spain. As you’d expect, most of them are in Ireland.

I’m heading to Carlingford at the end of this month for a weekend of Féile na Tána. I haven’t been before but it looks good. There’ll be the usual amalgam of workshops, concerts, and sessions.

Myself and Jessica will fly in to Belfast, then take the train down to Newry and get to Carlingford from there. You could fly into Dublin and get the train up to Dundalk, but the only Gatwick flights to Dublin are Ryan Air, and I’d rather entrust my instrument to EasyJet.

At the end of March we’re heading to Tullamore Trad Fest. That’s another one we haven’t been to before. Again, there’ll be workshops, concerts, and sessions.

Tullamore is just an hour away from Dublin by train and has plenty of accommodation options. We’ve booked into a nice-looking B&B.

There’s no avoiding Ryan Air for this trip and I want to take my good mandolin, so I’ve gone ahead and booked a separate seat for it. I don’t want to take any chances with an airline that actively seeks to elevate misery.

The festival I heartily recommend is Belfast Trad Fest at the end of July. It’s super convenient to get to with EasyJet flights from Gatwick—go to Belfast city airport, which is right downtown.

The festival offers a really good accommodation deal in modern student flats. The workshops are top-notch, and best of all, it has a really well-organised session trail. You can easily play in sessions all afternoon and evening.

This year, for the first time ever, Belfast trad fest is immediately followed by the all-Ireland fleadh, which promises to be pandemonium. I’ve never been to the fleadh before but I’m going to stick around Belfast for it.

You could head to the Willie Clancy Festival in Miltown Malbay at the start of July (the website seems to be having some issues right now). But good luck finding accommodation. The event is so big now that unless you’re camping, there’s not much chance of finding a place to stay. If you make it there though, non-stop sessions await. Non-stop chaos awaits too. That’s part of the deal. Great workshops though!

There are other festivals I haven’t been to but I’ve heard great things about. The Pádraig O’Keeffe Festival in Kerry in October sounds fantastic, especially if you like your polkas and slides. But it’s in Castleisland, which doesn’t have much in the way of accommodation. So unless you’ve got transport, it’s going to be tricky.

There’s a trad fest in Kilkenny in March. I’ve never been but they’ve got a session trail. You’d need to fly into either Dublin or Cork and then get on a bus. Either way, it’s Ryan Air from Gatwick.

I’ve also never been to the Ennis Trad Fest in county Clare in November but I’ve heard good things. Accommodation for the 2026 event is already in short supply though.

But you don’t need a festival to play in sessions. In fact, the kind of sessions you end up in at festivals have a different vibe to the usual sessions, simply because they’re formed of a hodge-podge of visiting players.

There a few spots in Ireland where you’re guaranteed a session pretty much any night of the week.

I love Galway. There are afternoon sessions in Taafe’s and Tigh Cóilí as well as evening sessions in the Crane and other places. You’d need to fly into Dublin and get the train from there. It takes about two hours.

Galway is busy in the summer time and accommodation can be pricy, but if you go off-season you can find some cheaper options.

Ennis has music most nights. There’s a regular bus service between Ennis and Shannon airport that’s nice and quick. You’d need to fly Ryan Air from Gatwick though.

And then there’s Belfast again. Even when the trad fest isn’t happening, Belfast has sessions seven nights a week. Check out the Belfast session guide Instagram account for up-to-date details.

I recommend staying in The Flint, but make sure you ask for a room on the top floor far away from the nightclub if you’re there on a weekend.

So, to recap, here are some festivals to check out:

And then for year-round session action, you can visit:

From: Chris Coyier

The Breakaway Moment

I know I’ve mentioned a ton of times: while I enjoy playing videos games sometimes, a little, I enjoy watching other people play them more. Even as a little kid. Like an awesome play date would be going over to a friends to watch them play. Perfect world, the friend would only play when I […]

From: Dave Rupert

The best version of my site so far...

You might have noticed that I did a big design refresh on my entire site… unless you’re on RSS I guess. I’ll talk about aspects in detail, but at a high level there’s been three big changes:

  1. A monospace font
  2. Named CSS grid lines
  3. Juicier multi-page view transitions

But my most favorite part is that today (when you set html { --hue-rotate: 15 }), my light theme looks like a stick of butter. And that brings me joy.

What didn’t change

Before I talk about what changed, here’s a quick list of the parts of my site that didn’t change:

Why change the parts you’re happy with, eh? Knowing what you want to change versus what you don’t want to change makes the whole process go faster.

All-in on a monospace font

My type system always falls apart. I start with a good setup and I’m guaranteed to ruin it over time. Whenever I read a site with a nice typeface and reasonable CPL, I started to feel like my system-ui based body text styles were letting me down. It didn’t feel cozy.

Then I saw Robin Rendle’s latest redesign (which is wonderful, btw) I wondered… Could I be a monospace font guy? Is that me? Do I identify as that? Is it too emo? Does it come off as a bad developer pun like bleep blorp I'm a programmer and using a computer bleep blorp?

All good questions to ask myself and exposes some insecurity I have, but I couldn’t shake the idea so I went for it.

The entire site is now set in Cascadia Mono which is a variant of Microsoft’s Cascadia Code. That decision is unintentionally on-brand for my current stage of life. Initially I wanted to use Inconsolata by Raph Levien, but it didn’t have a “numero” (№) symbol – which is a common missing glyph in a lot of indie fonts – and is an unfortunate piece of critical typographical infrastructure with my vibechecks.

In general I love the change. It feels very “me” right now. I worry about the readability of monospace fonts some, but I don’t think I was winning the Legibility Wars before.

Naming my grid lines

Improving the grid on my site is something I’ve wanted to do for nearly two years. The max-width container I had was fine before, but I relied a lot on margin overrides to change a container that felt like a hack that in my experience don’t scale.

Now I have something better with some sweet tech from Stephanie Eckles that I saw on Kevin Powell’s YouTube called “Named Grid Lines”. A not-so-well-known feature of grid is you can name the gutters in your grid template. The result is a grid that looks like this:

Full
Margin
Wide
Outdent
Content (Default)

See how all the grids collapse into one line that’s offset from the edge? That’s what I want. And then to use it, you specify the *-start and *-end line you tweak your container with a modifier class and make all the children start at a different grid line.

.foo.container > * {
	grid-column: wide-start / wide-end; 
  /* or grid-column: wide */
}

This gives me a lot of scalable control for my layout at the template level. For example, the layout of my homepage looks like this:

Header
Logo
Latest Posts
Projects
Footer

But when you click through to a single post, the template shifts to this:

Header
Title Goes Here
Content
Media
Content
Content
Media
Content
Content
Footer

I don’t have this setup, but I could write out a system of utility classes to make all this super flexible.

.full-start
.margin-start
.wide-start
.outdent-start
Default Content
.outdent-end
.wide-end
.margin-end
.full-end

That’s a lot of different layouts to craft. I look forward to more sustainable art direction for years to come. No more hacky negative margins or fixed positioned items… right?

More Multipage View Transitions

I’ve had multi-page view transitions on my site for years now. The original was a title transition from the index template to the post template where the post title would do a subtle swoop up and morph from an H3 to display-sized H1. This was great until I changed the font for my H1 (see above) and I obliterated the slight of hand magic I had before. Oops.

Now the flagship animation on my site is not typography dependent. If you navigate through my site, you’ll see that the “Dave” SVG on the homepage transitions into the main navigation on subpages. As a bonus, I get a little bit of much-needed branding on subpages. I didn’t do anything special other than naming the view transition and beefing up the stroke when the logo is in its smaller form.

The main nav is out-dented a bit by default, but using my new named columns I made the navigation go wider to match wide pages like my Bookshelf. Flexbox’s justify-content: space-between and view-transitions is doing all the heavy lifting on that animation there but I’m pleased with the effect and it feels natural (aka not synthetic and cheap).

I’m not a motion expert like Cyd Stumpel, but it feels good to have big, bold, un-ignorable view transitions on my site.

Slimmed down CSS

A redesign is always a great opportunity to clean house. I did the thing where I deleted my entire CSS and started from a naked page. Bit-by-bit I pulled back in the pieces I still needed.

I have about 40% less CSS which manifests in ~150 less lines of code to maintain and up to ~0.8 KB when compressed over the wire.

LoC Raw Min+Gzip Min+Brotli
Before 557 10.3 KB 2.76 KB 2.43 KB
After 391 5.36 KB 1.97 KB 1.76 KB

Now 0.8 KB isn’t much but because I inline my critical CSS the <head> on every page, this number matters. My entire homepage document is ~5.5 KB (Brotli), so that’s a 10%~20% performance improvement from cleaning up my CSS. How did I get these gains, you ask? Well…

One reason my CSS smaller is because I’m using modern CSS (nesting, :has(), :is(), :where(), :not(), etc). Those features seem like minor syntactic sugar but you also get more efficient selectors. For example my out-denting that I do in posts would previous be something like:

.post iframe, 
.post video, 
.post img,
.post table { }

In modern CSS that super-conjoined selector becomes something more expressive and elegant:

.post :is(iframe, video, img, table) {}

Those small improvements add up, but another reason the CSS is smaller is because its doing a lot less. Other than my inverse-sized H1s in posts, I’m not managing type styles at all beyond setting the body font-size. I think this is what Andy Bell calls “Be the Browser’s Mentor, Not Its Micromanager”. My strategy here is: Don’t futz with it until you can think of something way better than what the browser already does. That seems very Dao or Web’s Grain’y.

Onward to more art direction!

This redesign opens up a bright future for my site. I’ve already started on some of this work, but I’ll share that in a future post. I mentioned above but the named grid lines alone give me a lot of easy-to-use levers for expression. I touched up some old art-directed posts and they are benefitting from the changes already.

“Make it easy to play” seems like a good ethos for a personal site and I feel like I have that in the current manifestation.

From: Adactio

The datalist element on iOS 26

The datalist element is all fucked up on iOS. Again.

I haven’t “upgraded” my iPhone to iOS 26 and I have no plans to. The whole Liquid Glass thing is literally offputting. So I wouldn’t have known about the latest regression in Safari if a friend hadn’t texted me about the problem.

He was trying to do a search on The Session. He was looking for the tune, The Road To Town. He started typing this into the form on the home page of the site. He got as far as “The Road To”. That’s when the entire input was obscured by a suggestion from the associated datalist.

A screenshot of The Session on an iPhone during a search on the homepage. The search input is completely obscured by the text: The Road To Lisdoonvarna.

This is incredibly annoying and seems to be a pattern of behaviour for Safari. Features are supported …technically. But the implementation is so buggy as to be unusable.

I’ll probably have to do some user-agent sniffing, which I hate. And it won’t be enough to just sniff for Safari on iOS 26. Remember that every browser on iOS is just Webkit in a trenchcoat.

Time to file a bug and then wait God knows how long for an update to get rolled out.

Update: I filed a bug, but in the meantime it looks like user-agent sniffing is going to be impossible.

From: Boagworld

Be a contributor, not a lurker

Stop lurking. Start contributing. Simple ways to build reputation and relationships (without turning into a LinkedIn gremlin).

From: Adactio

Switch

Update: Never mind! It turns that Google’s issue is with unreachable robots.txt files, not absent robots.txt files. They really need to improve their messaging. Stand down everyone.

A bit has been flipped on Google Search.

Previously, the Googlebot would index any web page it came across, unless a robots.txt file said otherwise.

Now, a robots.txt file is required in order for the Googlebot to index a website.

This puzzles me. Until now, Google was all about “organising the world’s information and making it accessible.” This switch-up will limit “the world’s information” to “the information on websites that have a robots.txt file.”

They’re free to do this. Despite what some people think, Google isn’t a utility. It’s a business. Other search engines are available, with different business models. Kagi. Duck Duck Go. Google != the World Wide Web.

I am curious about this latest move with Google Search though. I’d love to know if it only applies to Google’s search bot. Google has other bots out crawling the web: Adsbot-Google, Google-Extended, Googlebot-Image, GoogleOther, Mediapartners-Google. I’m probably missing a few.

If the new default only applies to the searchbot and doesn’t include say, the crawler that’s fracking the web in order train Google’s large language model, then this is how things work now:

  • Your website won’t appear in search results unless you explicitly opt in.
  • Your website will be used as training data unless you explicitly opt out.

It would be good to get some clarity on this. Alas, the Google Search team are notoriously tight-lipped so I’m not holding my breath.

From: Stuff & Nonsense

Smashing Animations Part 8: Theming Animations Using CSS Relative Colour

Yours truly over at the Smashing Magazine: “CSS relative colour values are now widely supported. In this article, pioneering author and web designer Andy Clarke shares practical techniques for using them to theme and animate SVG graphics.”

Read Smashing Animations Part 8: Theming Animations Using CSS Relative Colour

From: Adactio

RAMO

Stop me if this sounds familiar to you…

There’s a conference you heard about it. It sounded really good but you never got ’round to getting a ticket. You were too busy thinking about work stuff. It was just one of those things that remained in the idle thought stage.

Then the day of the conference rolls around. You’re sitting in front of your computer seeing the social media posts from people at the event who are having a ball. The talks sound really good and you wish you could be there. You wonder why you never got ’round to getting that ticket.

Maybe you’ve experienced that when FFconf is happening and people like me are in the audience posting about some revelatory insight we’ve just received. Or maybe you see the blog posts and pictures from an event like dConstruct and you realise that you missed your chance to experience something special.

I’ve certainly experienced it when I’m not in Düsseldorf or Berlin for Beyond Tellerrand and all my friends are posting about how excellent it is.

It’s kind of like FOMO but instead of fear of missing out, it’s more like regret at missing out: RAMO.

I’m giving you advance warning. If you have anything at all to do with front-end development and you don’t come to Web Day Out, you are definitely going to experience RAMO.

Seriously, it is shaping up to be something very special indeed. Check out the schedule to see what I mean:

Tickets are just £225+VAT. Now is the time to get yours. It’s the second week of the new year. You’ve settled back into work. Now in the depths of Winter, you need something to look forward to, something that’s going to get you excited about making websites. That’s Web Day Out.

And if you need to convince your boss, I’ve got you covered.

January 13, 2026, 2:57 pm RAMO >>

From: Adactio

3 + 4

Toward the end of 2021, I wrote about working a four-day week. It really suited me. So much so that I’ve gone one further. For the past year or so I’ve been working a three-day week.

I work on Tuesday, Wednesday, and Thursday. From Friday to Monday, my days are my own.

This really changes the dynamic of the week. It no longer feels like an extended weekend. What I mean is that usually we think about the working week as the default and the weekend as the exception. That’s been flipped on its head for me. The three days I spend working feel like the exception.

Once again, this decision meant earning less money. But I’ve decided that I value time more than money. I know that’s a privileged position to be in. Many people have to expend all their time in order to make just enough money.

I’ve made some choices along the way that certainly help. I don’t have children. I don’t have a car. I live in a modest flat and I’ve paid off the mortgage. I live in a country where healthcare is free.

So I don’t have too many expenses. My biggest expenses are travel-related; getting to the States to see family, or travelling to Irish music festivals wherever they may be.

But still, working a three-day week means I can make enough to cover my expenses and still put some money aside for the future.

Now, this wouldn’t work for everyone. My work tends to be the kind that doesn’t require much direct collaboration (which is also why I mostly work from home). I imagine it could get frustrating being on a team of people working different numbers of days.

I’m also really lucky to have the choice to do this. I know that many workplaces wouldn’t allow this kind of lifestyle. Clearleft is different.

In my last conference talk, I touched on this:

I think you could you could divide management into two categories like you can do with programming languages. There is a very imperative school of management where it’s all about measurements, it’s all about those performance reports, it’s all about metrics, time tracking. Maybe they install software on your machine to track how long you’ve been working. It’s all about measuring those outputs.

That’s one approach to management. Then there’s a more declarative approach, where you just care about the work getting done and you don’t care how people do it. So if they want to work from home, let them work from home. If they want to work strange hours, let them work strange hours. What do you care as long as the work gets done? This is more about giving people autonomy and trust.

I’m very happy that Clearleft takes the declarative approach.

And I can reiterate what I said when I stopped working on Fridays:

I haven’t experienced any reduction in productivity. Quite the opposite. There may be a corollary to Parkinson’s Law: work contracts to fill the time available.

Now that I don’t work on Mondays, bank holiday weekends don’t mean much to me anymore. Or to put it another way, every weekend is like a bank holiday weekend. If I want to travel somewhere on a Friday and come back on a Monday, I don’t need to book any time off. That’s really nice.

I’ve got four days in a row to do with as I wish. I had to fight the urge to immediately launch into some new project or side-hustle to fill the time. I’m savouring it instead.

I’ve got time to take care of The Session. I’ve got time to read. I’ve got time to cook. I’ve got time to spend learning Irish. Mostly I’ve got time to just be.

From: Dave Rupert

Focus rings with nested contrast-color()?

As I was playing around with contrast-color(), I got a wild idea that you could use contrast-color() to invert its return value by nesting it: contrast-color(contrast-color(var(--some-color)). When would this be useful? Uh… Good question. I couldn’t come up with an example right away but after a bit I found one sitting right under my nose….

four buttons in one line. a secondary button, an accented primary button with a focus state, a subtle button and a transparent button

Our focus-rings in Fluent use a 1px inset white highlight and a 2px offset black focus-ring. It’s a smidge chonkier than the Chromium default. The reason we do this is to guarantee contrast against the focused-element, in the above example, a blue button. Without the addition of the white stroke, the black outline wouldn’t “pop” with enough contrast to the blue background.

To make this work, we have a --focus-inner-ring token and a --focus-outer-ring token themed for both light and dark modes.

*:focus-visible {
  box-shadow: 0 0 1px 0 var(--focus-inner-ring);
  outline: 2px solid var(--focus-outer-ring);
  outline-offset: 1px;
}

How would this change with nested contrast-color()?

*:focus-visible {
  outline: 2px solid contrast-color(var(--page-bg));
  outline-offset: 1px;
  box-shadow: 0 0 1px 0 contrast-color(contrast-color(var(--page-bg)));
}

All you would need is one token you probably already have (--page-bg) vs two tokens. Neat.

One consideration… your focus-ring isn’t always on a --page-bg. Sometimes it shows up on a --card-bg and this little trick might fall apart. As always, your mileage may vary.

Aside: This got me thinking it’d be nice to have a currentBackgroundColor like we have currentColor in CSS today. I’m not sure how much career I’ve got left to wait for that, but who knows.

On second thought…

Mulling this over a bit more… you might be better off using color-scheme and light-dark() for this instead.

 :root {
	 color-scheme: light dark;
 }
 
 *:focus-visible {
   box-shadow: 0 0 1px 0 light-dark(white, black);
   outline: 2px solid light-dark(black, white);
   outline-offset: 1px;
}

Yeah… I’d probably do that. You dodge the spotty contrast-color() support and have a singular function instead of a nested situation. It keeps it simple and readable.

If you converted this to tokens, you’d probably need four tokens to fill out the inner/outer and light/dark matrix. But I’d consider not using custom color tokens for focus-rings at all and embrace the higher contrast… or limit tokens to the outer-ring.

From: Chris Coyier

Normally I like to work or read on planes, but on a return home flight yesterday I was exhausted to the point that movies sounded best. Four (!) movies on Netflix:

January 10, 2026, 6:38 pm >>

From: Dave Rupert

Interpolate contrast-color() to manipulate lightness

In my first post on contrast-color() I demo’d using color-mix() to change a background-color on hover, but I will be honest… mixing black and white isn’t always what you want. It would be cool and helpful to coerce contrast-color() to return either 1 or -1 so that we could adjust lightness in a color function on hover instead of only mixing white and black.

Building on the inline CSS if() statements in my last post, we can use the same trick to interpolate the result of contrast-color() into a number.

Disclaimer: All caveats from the previous post about browser support, caching quirks, and expected syntax changes still apply.

See the Pen contrast-color() powered design system colors by Dave Rupert (@davatron5000) on CodePen.

Ahh… feel that? Now our states maintains its harmonious color palette where mixing in white or black gets us a bit muddier results. We’re picking another note on the scale of the color’s lightness ramp.

The relevant CSS to make this trick work goes like this:

/* Needed for if() statement */
@property --captured-color {
  syntax: "<color>";
  inherits: true;
  initial-value: white;
}

/* https://lea.verou.me/blog/2024/contrast-color/ */
@function --contrast-color(--bg-color) {
  --l: clamp(0, (l / var(--l-threshold, 0.623) - 1) * -infinity, 1);
  result: oklch(from var(--bg) var(--l) 0 0);
}

button {
  background-color: var(--ds-button-bg);
	--captured-color: --contrast-color(var(--ds-button-bg));
  --lighter-or-darker: if(
    style(--captured-color: oklch(1 0 0)): 2.5; /* go extra lighter */
    else: -1; /* go darker */
  );  
  ...
  
	&:hover, &:focus {
		background-color: oklch(
			from var(--ds-button-bg) 
			calc(l + (0.1 * var(--lighter-or-darker))) c h 
		);
  }
}

For comparison’s sake, I web-inspected up a little apples-to-apples, side-by-side of the adjusting lightness way and the color-mixing way of algorithmic hover states where it’s 10% lightened/darkened versus 10% mix of white/black.

a side by side look at adjusting lightness vs mixing in white and black. the rest for all the buttons is on top and the hover state for all the buttons is on the bottom. The hover states for the buttons on the adjusting lightness demo are a bit warmer, but probably hard to notice to the average person.

The difference is almost imperceptible, but the hover states from the “Adjust Lightness” method feel a tad bit warmer, particularly on the bottom row with the green, blue, and purple buttons. The difference becomes more obvious if the step is greater than 10%.

Unless your customers are a bunch of color dorks, they probably won’t see it the care you put into this. But I’m willing to wager that even if they don’t see the difference, they will be able to feel the difference.

We also get a lot more control with this if() statement route. For example, I can set the lighten amount to 2.5 (+25%) instead of 1 (+10%) because that’s what felt better. If you’re algorithmically generating your color palettes, it should be easy to find the ideal values; either a step-up or step-down, perhaps. And we’re also not just limited to lightness! You could mess with chroma or whatever the b in lab() is. Find what makes sense for your system.

A part of me wants to take this even further to get more control. For example, if the color is super dark (e.g. black) and the lightness value is below 0.1, lighten by 25%, otherwise lighten by 10%. That might be possible with an if() inside the oklch() or a sin() function… but that sounds like a lot of Math and probably hurts readability. More experiments to do though.

It’s fun to embark on this new world of algorithmic color schemes in vanilla CSS. While I’m excited to play, I’m more excited to see what your beautiful brains come up with.

From: Dave Rupert

Using your design system colors with contrast-color()

One predictable pain point with contrast-color() is that it only returns black and white named colors. From a design systems perspective, that’s not ideal because you want your colors. You want your harmonious brand and the colors you and your team spent thousands of man hours in meetings deciding on. Those colors.

In fact, an earlier version of Safari had color-contrast() (confusing I know, naming is hard) which allowed you to pass in a list of best candidates to choose from. I beleive that proposal got mired in standards discussions, color contrast algorithms, and competing proposals; and contrast-color() is what survived which got simplified down to a binary result.

In the future though, we can use contrast-color() and if() together to help pick the value we want. Alas, at the time of writing no browser supports both if() and contrast-color(). But we can use Lea Verou’s --contrast-color() workaround to experiment with how this will work in Chromium today.

See the Pen contrast-color() powered design system colors by Dave Rupert (@davatron5000) on CodePen.

The CSS to get this working looks something like this:

@property --captured-color {
  syntax: "<color>";
  inherits: true;
  initial-value: white;
}

/* https://lea.verou.me/blog/2024/contrast-color/ */
@function --contrast-color(--bg-color) {
  --l: clamp(0, (l / var(--l-threshold, 0.623) - 1) * -infinity, 1);
  result: oklch(from var(--bg) var(--l) 0 0);
}

:root {
  --ds-text-white: wheat;
  --ds-text-black: darkslategray;
}

button {
  background-color: var(--ds-button-bg);
  --captured-color: --contrast-color(var(--ds-button-bg));
  
  color: if(
     style(--captured-color: oklch(1 0 0)): var(--ds-text-white);
     else: var(--ds-text-black);
  );
}

And that’s it! Using (a form of) contrast-color() you can select the proper tokens from your design system. Cool.

One quirky bit needed to make it work is defining a type for --captured-color using CSS @property, a trick I learned from Roma Komarov. To be honest I don’t fully understand the why behind Registered Custom Properties and the Computed Value Time Behavior superpower, but my simple brain created a rule “If you’re going to compare a variable to a <color> in a CSS if() statement, make sure to register the variable as a <color>.”

If/when any of the browsers start supporting both features, I expect we’ll have to update oklch(1 0 0) in the style query to white or rgb(255 255 255). At least, I hope it works that way.

One unexpected challenge that I encountered with this demo was that if I abstracted out the if statement out into its own custom function, it would break. I’m not 100% sure why but I think it’s based on how CSS functions cache results. I’ll have to dig into this more, but I’m happy the inline if statement works. Hopefully someone smarter can figure it out.

Anyways, exiting times. And can we pause for a moment and marvel at how this is all vanilla 2026 CSS?! What a world.

From: Stuff & Nonsense

The Timex x Pan Am Waterbury Automatic Ace

Talk to my family and friends, and they’ll tell you I never bloody stop talking about the IWC Big Pilot 43 watch that I bought to celebrate my 60th in November. Mechanical watches are all over my social media feeds, and the other day I did a double-take when the algorithm suggested I might like a new design from, of all companies, Timex.

The Timex x Pan Am Waterbury Automatic Ace is a 41mm brushed stainless-steel watch from a collaboration between Timex and the nostalgic Pan Am brand. I immediately thought there was something familiar in this watch’s design. But I couldn’t somehow put my finger on it.

Left: IWC Big Pilot 43. Right: Timex x Pan Am Waterbury. (Images from IWC and Timex.)

The Timex x Pan Am Waterbury bears more than a passing resemblance to the latest addition to IWC’s iconic Big Pilot line, the Big Pilot 43, which is on my wrist now. But it most closely resembles IWC’s Pilot’s Watch Mark XX. You can see just how closely Timex followed IWC when the two dials are scaled to match.

Left: Timex x Pan Am Waterbury. Right: IWC Pilot’s Watch Mark XX. (Images from IWC and Timex.)

The Timex’s hour and second hands match the IWC Mark XX, while the minute hand is straighter. Its date window is the same size, although I’m unsure why the dot—between it and the marker in the 3 o’clock position—was necessary. Placing the word “Automatic” under the 6 is neat and leaves room for the Pan Am logo above. I actually prefer this placement to IWC’s, where it’s beneath the Mark XX type. The size relationship between the words “Timex” and “The Waterbury” looks identical to that between “IWC” and “Schaffhausen.”

Close-up of the Timex x Pan Am Waterbury dial. (Image from Timex.)

Timex did a nice job of placing the Pan Am logo on the crown and using its signature blue on the inside of the strap.

Pan Am logo on the crown. (Images from Timex.)

On the dial, the line between that famous logo and the plane icon at the 12 o’clock position comes straight from Pan Am’s design history.

Linework on the Pan Am logo and Timex dial. (Images from Pan Am and Timex.)

I don’t know which typeface Timex chose for their numerals on the Waterbury dial, but it certainly isn’t the Helvetica, which Pan Am briefly switched to between 1970 and 1973.

Helvetica and the short-lived Pan Am brand redesign. (Image from Timex.)

Oh, and if you’re curious how Helvetica looks on a watch dial, IWC used it for the numerals on its 1993-released Mark XII.

Helvetica on the IWC Mark XII. (Image from Chrono24.)

I suppose that, being a collaboration with Pan Am, the question to answer is whether this is a successful pilot’s watch design? I’d say it is. It’s not overly large, but it is legible. The skinny minute hand isn’t as obvious as IWC’s, and there’s that inexplicable dot next to the date window, but as an homage to the pilot’s watch, it’s nice. Is it more than an homage to IWC’s iconic Big Pilot design? I’d say so.

But I like it. Hell, I might just buy one for fun to wear places and times when I wouldn’t be comfortable wearing the real thing.

From: Chris Coyier

Jeremy: 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 […]

January 8, 2026, 6:43 pm >>

From: Dave Rupert

Algorithmic hover states with contrast-color()

Firefox 146 added support for contrast-color() joining Safari 26 in the First Implementor’s Club. For those unfamiliar, contrast-color(<color>) is a new CSS function that will take a <color> as input and returns either white or black depending on which has the most contrast.

The quintessential example is choosing a foreground text color with the best contrast.

button {
	--button-bg: red;
	background: var(--button-bg);
	color: contrast-color(var(--button-bg)); 
	/* @returns black (5.25:1 WCAG AA Pass) 
			not white (3.99:1 WCAG AA Fail) */
}

If someone changes --button-bg to purple, the foreground color automatically resolves to the either white or black, whichever has more contrast. It avoids having to set an extra token for color and takes the guess work out of picking an accessible foreground color.

I think this is going to be an incredible boon to design systems where I don’t control what --button-bg is, but I do care about providing accessible experiences. And I think that’s the goal of this feature; to have “smart defaults” that lead to more accessible websites, easier algorithmically-driven color systems, and better “theme a whole website from a single color picker” demos.

Sure contrast-color() can do foreground colors, but what about backgrounds?

We’re having conversations at work about algorithmically driven rest/hover/active states for Buttons. In the current Baseline you can use color-mix() to lighten/darken colors on :hover

button {
	background-color: var(--button-bg);
	color: contrast-color(var(--button-bg));

	&:hover, &:focus {
		background-color: color-mix(
			in srgb,
			var(--button-bg) 90%,
			black 10%
		)
	}
}

The code above will dim your button on :hover 10% by mixing in black. But what if our Buttons are already dark (black, navy, etc)? In that situation we want to lighten the background-color instead of dimming. We can glue on new classes like button.lighten-on-hover or button.invert-hover and that works… until we get to light and dark theme modes of our Button where you probably want to lighten/darken oppositely depending on the mode…

Ugh. In that situation you’d have @media (prefers-color-scheme: dark), [data-theme="dark"] styles in your Button styles and people are mad now because the Button styles are too complex. There’s got to be a better way!

Well, do I have good news for you…

See the Pen contrast-color() powered lighten/darken bg on hover by Dave Rupert (@davatron5000) on CodePen.

Per my previous conversations, I wondered if we could use contrast-color() to programmatically lighten/darken an button based on its current background-color. If the Button is black, and the contrast-color is white, let’s mix in white (and vice versa):

:root {
	color-scheme: light dark;
	--button-bg: light-dark(navyblue, lightpurple);
}

button {
	background-color: var(--button-bg);
	color: color-contrast(var(--button-bg));

	&:hover, &:focus {
		background-color: color-mix(
			in srgb,
			var(--button-bg) 75%, 
			contrast-color(var(--button-bg)) 10%
		)
	}
}

Huzzah! Now our Button’s hover states go in the desired direction and our foreground color is intrinsically styled based on its own background-color. Nice. From a design systems perspective I’m pretty excited about the possibility to remove a bunch of state-based tokens from our collection.

Now available in… everywhere?

This approach only works in Safari and Firefox. However, if I use Lea Verou’s method of polyfilling contrast-color(), we can pop in a custom @function --contrast-color() that works in Chromium 139+. The final working solution looks like this:

/* @function supported in Chromium */
@function --contrast-color(--bg-color) {
  --l: clamp(0, (l / var(--l-threshold, 0.623) - 1) * -infinity, 1);
  result: oklch(from var(--bg-color) var(--l) 0 h);
}

button {
  /* contrast-color() supported in Safari & Firefox */
  --button-fg: contrast-color(var(--button-bg));
  
  @supports not (color: contrast-color(red)) {
    --button-fg: --contrast-color(var(--button-bg));
  }
  
  background: var(--button-bg);
  color: var(--button-fg);
  
  &:hover,
  &:focus{
    background-color: color-mix(
      in srgb,
      var(--button-bg) 75%,
      var(--button-fg) 10%
    );
  }
}

Depending on your browser matrix, this may work for you. It’s probably a smidge too new for us to roll out to customers, right now but for personal sites heck yeah.

This is interesting tech and I’m excited to dig in more. And spoiler alert, this is the first post in a small little series I have already written up for you.

From: Boagworld

Stop Lurking. Start Getting Known.

A practical, low-effort system for building your reputation (without turning it into a second job).

From: Boagworld

What I’m seeing for UX as we move into 2026

Not predictions. Just what I'm noticing among the UX professionals I work with right now.

From: Stuff & Nonsense

Snow mode has just gotten even chillier

Although we’ve had a smattering of snow here in the Rhineland—where I’m basing myself for a couple of months—at home, an “arctic blast” means snow is threatening. Last week, I added a snow mode to my websites, but my pioneer characters still looked toasty and warm, and unaffected by the wintery conditions. So, it was time for them to get chilly.

My blog page animated graphic without snow.
Graphic with snow but characters still look warm.

I’ve been writing about CSS relative colour properties for Smashing Magazine, but until those articles land, here’s the short version.

Instead of specifying my characters’ skin tones in the SVG using a fill value:

<path fill="#F7F1ED" class="skin-highlight" d="[…]"/>
<path fill="#F7BEA1" class="skin-mid" d="[…]"/>
<path fill="#BA7E5E" d="[…]" class="skin-dark" />

And changing the colours via those class attributes, I removed the fill attributes altogether and replaced them with inline styles, which include custom properties:

<path style="fill: var(--skin-mid);" d="[…]"/>
<path style="fill: var(--skin-mid);" d="[…]"/>
<path style="fill: var(--skin-dark);" d="[…]"/>

Now, before you rush to your keyboard to tell me that inline CSS is bad, when used with custom properties, it’s very, very good indeed. As for those custom properties, they’re not just plain ol’ colour values; they’re a colour system. To start with, yes, I have those normal skin colours:

--skin-highlight-base: #F7F1ED;
--skin-mid-base: #F7BEA1;
--skin-dark-base: #BA7E5E;

I used them to turn Hex into OKLCH so I could manipulate each channel separately:

--skin-highlight: oklch(from var(--skin-highlight-base)
calc(l + var(--env-l))
calc(c * var(--env-c))
calc(h + var(--env-h))
/ calc(alpha * var(--env-a)) );

Those --env-* variables define how much each colour channel shifts. These are my placeholders, which leave the original colours untouched:

.outlaw {
--env-l: 0;
--env-c: 1;
--env-h: 0;
--env-a: 1; }

Snow mode is a toggle, so I then defined a new set of variables just for when it’s active:

.snow-mode .outlaw {
--chilly-l: -0.04;
--chilly-c: 0.35;
--chilly-h: -38;
--chilly-a: 1; }

Rather than changing the base environment values, I introduced a second set specifically for cold conditions. Then swapped the environment variables for chilly ones:

--skin-highlight: oklch(
from var(--skin-highlight-base) calc(l + var(--chilly-l)) calc(c * var(--chilly-c)) calc(h + var(--chilly-h)) /
calc(alpha * var(--chilly-a))
);

Then, I registered those properties to make them animatable:

@property --chilly-l {
syntax: "";
inherits: true;
initial-value: 0; }

@property --chilly-c {
syntax: "";
inherits: true;
initial-value: 1; }

@property --chilly-h {
syntax: "";
inherits: true;
initial-value: 0; }

@property --chilly-a {
syntax: "";
inherits: true;
initial-value: 1; }

And added a transition so the characters start off looking warm and then get progressively colder:

@media (prefers-reduced-motion: no-preference) {
.outlaw {
transition:
--chilly-l 15s ease,
--chilly-c 10s ease,
--chilly-h 10s ease,
--chilly-a 10s ease; }
}
Characters getting chilly.

I love adding surprise behaviours—especially ones that reinforce the idea that these characters are reacting to their environment. So now, when someone hovers over a chilly character, they also shiver:

@media (prefers-reduced-motion: no-preference) {
.snow-mode .outlaw:hover {
--shiver-duration: 0.5s;
--shiver-x: 1.5px;
--shiver-y: 0.4px;
animation: shiver var(--shiver-duration) ease-in-out infinite;
transform-origin: center bottom; }
Graphic with snow and characters looking chillier over time.

These are subtle changes, but they add to the fun. Most importantly, by changing the way I set up colour for my animated graphics, I can have much more fun more easily in the future.

Check out the new chilly characters on my home and blog pages.

From: Chris Coyier

Quite a lovely essay from Henry: When those promises of exorbitant wealth and a life of decadence through per-click monetization ultimately dry up (or come with a steep moral or creative cost), creators and learners must look for new solutions for how educational content is shared on the Internet. The most self-evident, convivial answer is an old […]

January 4, 2026, 7:56 pm >>

From: Rachel Andrew

2025 in review

I concluded my 2024 review post by saying that I hoped to make the move back to the North of England in 2025. The event that defined 2025 (other than my 50th birthday!) is that I managed to do just that, and I’m writing this post from a little town in Northumberland, where I’ve been […]

From: Adactio

2025

Here’s the new year, same as the old year. Well, not the same, but pretty similar.

At the end of 2024, I wrote:

It was a year dominated by Ukraine and Gaza. Utterly horrific and unnecessary death courtesy of Putin and Netanyahu

See what I mean?

2025 added an extra dose of American carnage with Trump’s psychotic combination of cruelty and incompetence directed at the very foundations of the country. I’ve got to be honest, I’m tired of the USA living rent-free in my head so I’ve issued an eviction notice. It’s not that I don’t have sympathy and empathy for what’s happening there, but a majority of the country voted for this …again. Like a dog voting to have its nose rubbed in its own shit. Maybe this time the lesson will stick.

Anyway, leaving world events aside (yes, please!), I also said this at the end of last year:

For me personally, 2024 was just fine. I was relatively healthy all year. The people I love were relatively healthy too. I don’t take that for granted.

Again, same. No major health issues in 2025. My loved ones are well. My gratitude grows.

I’ve already written about how much music I played in 2025. I’m hoping to continue that trajectory in 2026 with lots of sessions. We’re four days into the year and I’ve already had two excellent sessions. There are another three lined up this week.

One of the highlights of 2025 was my trip with Jessica to Donegal. Learning Irish by day, playing in sessions by night, all while surrounded by gorgeous scenery. I’ve already got a return trip planned for 2026. I’m also planning to be back in Belfast for the annual tradfest.

Other 2025 highlights include:

Most of my travel in 2025 was either for music or family.

I made three trips to the States to see the in-laws: California, Florida, and most recently, Arizona. I can’t say I feel very comfortable going to the States right now, especially to Florida, where people openly display their intolerance on their T-shirts, and Arizona where they openly display their guns.

I went back to my hometown of Cobh a few times during the year to visit my mother.

Aside from those family trips, I went to Belfast, Donegal, Galway, and Clare in Ireland, Cáceres in Spain, Namur in Belgium, and Amsterdam. Only that last one was work-related. I always make sure to get to CSS Day.

Meanwhile here on my website, I posted 695 times in 2025. That includes 345 notes, 262 links, and 86 blog posts. Here are some I’m quite fond of:

All in all, 2025 was a grand year for me. It wasn’t all that different from the year before. I’m at an age where the years aren’t all that differentiated from one another. I’m okay with that because I’m also at an age where I know what brings me joy and satisfaction, and I can focus on those things.

So here’s to 2026, which I hope I will spend doing more of what I did in 2025: playing music, speaking Irish, eating good food, hanging out with friends, reading good books, travelling to interesting places, and staying relatively healthy.

I’m sitting playing my lovely red mandolin and smiling at the camera. Mé seanding on the street pointing over my shoulder at a red brick building behind me. A selfie in an auditorium with big screens displaying the Clearleft logo. Myself and Jessica dressed in black with our instruments in our backs taking a selfie in a bus shelter. A selfie with Jessica with green grass and a sandy beach in the background under a blue sky with a few clouds. A selfie of me wearing a blue shirt and blue hoodie on a sandy beach next to the ocean under a sky that is half clear and half cloudy.

From: Chris Coyier

Default Apps Early 2026

It’s a time of slow change for me when it comes to the apps I use most regularly. I also maintain my subscription to SetApp, because I use a handful of things it offers that makes it super worth it: TablePlus, Typeface, Paste, CleanMyMac, Bartender, etc.

From: Boagworld

Giving Users A Voice Through Virtual Personas

Turn scattered user research into AI-powered personas that give anyone consolidated multi-perspective feedback from a single question.

From: Zeldman

Cold Storage

Good UX is what companies do when they have to. A company that has your stuff locked away doesn’t have to.

The post Cold Storage appeared first on Jeffrey Zeldman Presents.

From: Chris Coyier

JA Westenberg: When you write a blog post, you’re creating a standalone document with a permanent URL. It exists at a specific address on the web, and that address doesn’t change based on who’s looking at it, when they’re looking at it, or what algorithm has decided they should see next. The post is there, […]

January 2, 2026, 12:58 pm >>

From: Dave Rupert

Twenty Twenty-Five

2025 was… a year. And I made it to the end of that year. If you’re reading this, I imagine you did too and let’s celebrate that. But also not one without loss; of loved ones, of health, of relationships, of jobs, of liberties, of pursuits of happiness. Let’s mourn those.

My year was mundane by most accounts. I worked, I family’d, and with the remaining life force I focused on myself. A couple failed side projects and half-baked game ideas in there but welcomingly “unproductive” relative to what I normally subject myself to. On a handful of fronts this year has been about scaling back in what I burden myself with, in material posessions, in finances, in obligations, and elsewhere. Ideally, I can clear the plate of duties that demand my limited attention. To be so bored that I read a magazine.

Resolutions resolved

I set some slightly different goals last year. Let’s check on last year’s goals:

  • 🟢 Seize work opportunities - I’ll call this a success. Released a design system and token system. An executive-level mandate caused us to pivot the entire design language using the tokens. Success. Other big products are beginning to use our team’s work, we’re recognized for the accessibility of our product… which is great.
  • 🔴 Hunker down and be creative - In the interest of binaries, I’ll say no. I think I gravitated to work and mind-numbing recovery, not creativity. I wasn’t very productive beyond work and family life. I think given “the situation” in the homeland, that’s okay.
  • 🟠 Slow down to 1x mode - I still watch and listen way too much in 2x but at a certain point it does feel natural. Certain content gets the 1x treatment, but not enough. I did slow down though, generally speaking. Less books, less blog posts, less side projects. And that’s okay.
  • 🔴 Join a club - I made attempts to join two different writing clubs, but it didn’t work out. One met on an inconvenient night and I guess I failed the application for the other one. I joined a Discord for a Gunpla group… but never went. Closest I got to joining a club is a dad band that plays after our kids’ band practices.
  • 🟢 Understand myself - I’m progressing on my health journey to untangle the knot of anxiety, weight, and ADHD. I’ve done all the important appointments and follow-ups. I’ve done the diet. I’ve done the exercise. I’ve got new medications all lined up. Waiting for something to change.

A month-by-month breakdown

  • Jan
    • New pain meds
    • New ADHD meds
  • Feb
    • Launched internal design system
    • Shipped cross-product/platform token system
  • Mar
    • Landscaping project
    • Trip to Arizona
    • Renaissance Faire
  • Apr
    • Cheer competition in New Orleans
    • New car
    • 45th Birthday
  • May
    • New ADHD meds
  • Jun
    • Trip to Grand Canyon
  • Jul
    • Shipped design system redesign
    • Trip to San Diego
  • Aug
    • Back to school
  • Sept
    • Volunteered at Austin-Oita 夏祭り
    • New BP meds
  • Oct
    • Trip to Santa Barbara
  • Nov
    • The Beths
    • Rainer Maria and Cap’n Jazz
    • Launched Grid-Paper
  • Dec
    • New BP meds
    • New GLP-1 meds
    • Christmas in Nebraska

The school rush and kid activities fill most non-working hours. It’s a lot of work right now but we signed up for it by having children. Speaking of children, my daughter’s cheer team won a national championship, which is an incredible accomplishment and experience for her. And my son started playing guitar this year which makes the whole family happy. Both kids are 10+ now which feels like we’re entering a new era in parenting; more autonomy, different problems, deeper conversations, movies with curse words, and more attitude. It’s new territory.

An average amount of books

I had a sub-goal of reading less this year and I succeeded! That feels good.

I encountered a lot of mediocre books this year but there were some bangers in there like The Dawn of Everything, The Wrong Stuff, and The Sirens’ Call. It’s possible I’ve maxed out on books though. My appetite to seek out new books to read in the last two months has been super low. They’re all starting to blur into a large mush. I have a backlog of manga to read… perhaps next year is the year I get back into comics?

An average amount of blogging

I published 53 posts in 2025 which averages to a post-a-week, but there’s some hot streaks in there skewing the stats. It’s less than the year before which (again) I’ll count as a win. Behind the scenes there’s dozens of half-finished posts, but it takes so much effort to finish a technical post about CSS or web components who knows when those will see the light of day.

Here’s a smattering of posts that either made the rounds or I’m proud of:

I’m sure I left something out but no need to overthink it. You can peruse the archive if you want.

Living in the zone of shit

American politics drove a lot of my daily vibes this year. Day-after-day of bullshit executive orders, tariffs, lies, DOGE, fuckups, coverups, corruption, kidnappings, gulags, military occupation of democratic US cities under false pretenses, murders at sea, billionaires, institutional collapse, and everything else is exhausting. The economic anxiety weighed heavily on me; we even panic bought a car! But watching groceries get more expensive, budgets get tighter, all while the President and his cronies launch crypto grifts to launder money from billionaires and foreign governments in an open influence peddling scheme is infuriating.

I had to step back from news a bit for my own mental health, but also it’s getting repetitive. Regime does stupid/illegal thing, PERSON gets DESTROYED by THING (but never does), consequences never happen, the world is unjust. I know the strategy is to exhaust, but I hit peak outrage years ago and this feels like a long, unshakable hangover of bad decisions. My trust in any form of government erodes like sand cliffs.

Mix in a highly speculative tech hype cycle which makes up a disproportionate amount of the economy and stock market valuation… and it’s hard to shake off a sense of dread.

Focusing on my physical and mental health

All my extra spoons went to wrangling my physical and mental health. Sometimes that manifested as staring at an iPad on my recliner after long day at work, but it also involved a lot of doctors visits. This has been a year and a half long journey (since good healthcare kicked in) of prioritizing myself. And while the news isn’t all great, I’m getting a clearer picture of the brain and body I’m dealing with. There’s a long road ahead and I don’t actually know when/if it gets better, but having a pathway forward means a lot right now.

I was unconsolably grumpy for nearly two months straight. It could be burnout. It could be cheese-moving. It could be depression manifesting differently. What I learned from going through that spell was good people and great music are the secret to being happy. At least for me. And I need to make sure I’m building that into the regular rhythms of my life.

2026: No New Projects

Next year has the potential to be good. If a certain elderly statesman, for example, passed away from age-related illnesses… that might change the mood considerably. But speaking to what’s within my sphere of control, I think there’s capacity for goodness.

For 2026, I’m adopting a mantra of “No new projects.” There will be new projects of course; they fit all the interest, novelty, challenge, urgency, and passion (INCUP) requirements that motivate ADHD brains. The spirit of “No new projects” is to finish more projects than I start. In the last month or so I’ve been aggressive on closing out old lingering to-dos; home improvements, organizing, taxes, managing devices, etc. and I want to continue that work of clearing out all those nagging unfinished bits. I want to buy back precious Brain RAM so I feel less overwhelmed all the time.

“No new projects” helps me be more present and realize when I’m creating work for myself. When I buy a new device, or an instrument, or think about building my own home server array… “No new projects” puts a hurdle in the way of that decision so that I don’t DDoS myself with a backlog of small jobs pursuing an impulse.

I tend to externalize, but 2026 also feels highly dependent on what happens in tech in the next year. A change in my job? A robot taking my job? A mass layoff? A bubble bursting? An industry collapse? A retreat to a smaller web? A new and unexpected technological breakthrough? As I hinted earlier, it feels like the entirety of tech has hitched itself to a highly speculative bet and we all have to wait and see what happens. The lack of clarity and concrete vision for the future of human-centered computing and labor creates a feeling of insecurity for me. A trillion dollar hurricane. Displacement.

But we can write. And we can dream. And we can imagine a future where humans connect.

From: Chris Coyier

Three good thoughts from Shane Parrish: Short-term results come from intensity. Long-term results come from consistency. ** Ninety percent of success can be boiled down to consistently doing the obvious thing for an uncommonly long period of time without convincing yourself that you’re smarter than you are. *** Working smart isn’t the opposite of working […]

December 31, 2025, 11:06 pm >>

From: Stuff & Nonsense

A new gold mine graphic animation

Of all the “pioneering” graphic animations I’ve made this year, the one I disliked the most was on my contact page. That was one of the first ones I’d produced, and it was before I’d really got into the process. Anyway, it’s gone, replaced with a new gold mine graphic.

This time, I set my Magnificent 7 pioneers in the entrance to a gold mine. There’s dust in the air, gold shimmering, and oil lamps glowing and swinging.

New gold mine graphic with characters
New gold mine graphic with characters

I started with a loose pencil sketch.

Pencil sketch of my gold mine
Pencil sketch of my gold mine

I moved the artwork into Sketch to make my vectors. I kept the elements I knew I wanted to animate separate so I could add them to my graphic more easily later:

  • Background buckets swaying
  • Dust particles in the air
  • Lamps glowing and swinging
  • Pile of gold shimmering

CSS animations make the buckets sway, and lamps swing, then a little vanilla JS spawns and animates the dust particles and gold shimmers. Here’s the gold mine graphic on its own, so you can see all the components.

New gold mine graphic without characters
New gold mine graphic without characters

As I said before, I’ve been having way too much fun with my website since I implemented the new pioneer characters, so I doubt this will be the last time I add new features. In fact, I guarantee it won’t be.

From: Chris Coyier

Does the leadership at my company promote a xenophobic agenda and use the wealth I help them acquire to donate directly to bigoted causes and politicians I find despicable? Yeah, sure. Did I celebrate my last birthday at Drag Brunch? Also yes. I even tipped with five-dollar bills. I contain multitudes, and would appreciate it […]

December 30, 2025, 12:41 pm >>

From: Adactio

Music in 2025

I really like it when people post their end-of-year music round-up. Colly, Jon, and Naz have all posted about music they listened to in 2025.

I recognise almost none of the albums that they’ve listed. That’s because my musical brain has been almost entirely conquered by Irish traditional music.

2025 was a year filled with music for me. Mostly it was music that I was playing. I think I might’ve spent more time playing music than listening to music this year. I like that ratio.

Brighton has a healthy session scene. Most weeks I get to play in more than one. Even better, I had some great tunes outside of the pub environment, calling around to people’s houses or having them over for a nice cup of tea with some jigs’n’reels.

Most of my travel in 2025 was music-based. The Willie Clancy Summer School in County Clare. Belfast Trad Fest in Northern Ireland. The Cáceres fleadh in Spain. The inaugural Namur Irish Music Festival in Belgium.

There’s nothing better than being in a good session, and I enjoyed some great ones this year. I think my mandolin-playing has benefited from it too.

I also got hold of some albums released in 2025…

The second Copley Street album is, unsurprisingly, excellent.

The second volume of Mná na bPíob is, also unsurprisingly, also excellent.

But I think my favourite album of 2025 is Òran na hEala by Maurice Bradley. Terrific tunes, superb piping, and equally superb fiddle playing.

I’ve been in a session two with Maurice Bradley during previous tradfests in Belfast. I was looking forward to seeing him there again this year to tell him how much I like the album. Alas, he passed away shortly after the album was released. Ar dheis Dé go raibh a anam. A great loss to Irish music.

Oh, I did get one album released in 2025 that isn’t traditional Irish music, and it’s really, really good:

Deep Black Water by Salter Cane.

Okay, that’s cheating because I’m in the band, but honestly, I think the album is genuinely excellent. Every track is a banger, in my somewhat-biased opinion. Have a listen for yourself and see what you think.

My wish for 2026 is that I’ll have plenty of opportunities to play those songs live. In between all the sessions.

From: Adactio

Books I read in 2025

I read 28 books in 2025. Looking back over that list, there are a few recurring themes…

I read less of the Greek mythology retellings than last year but I seem to have developed a taste for medieval stories like Matrix, Nobber, and Haven.

I finally got ‘round to reading some classics of post-apocalypse fiction like Earth Abides and I Am Legend.

I read lots of short story collections: Salt Slow, Bloodchild And Other Stories, The Bloody Chamber And Other Stories, Folk, and The End of the World is a Cul de Sac. There’s quite a dollop of horror in some of those.

I’m clearly hankering for the homeland because I read a lot of books set in Ireland: The Country Girls, Haven, Prophet Song, The End of the World is a Cul de Sac, and Nobber.

And there’s the usual smattering of sci-fi from the likes of Nnedi Okorafor, Adrian Tchaikovsky, Arkady Martine, Becky Chambers, and Emily St. John Mandel.

Here’s what I thought of these 28 books, without any star ratings

Earth Abides by George R. Stewart

I started this one in 2024 and finished it in the first few weeks of 2025. It’s a classic piece of post-apocalypse fiction from 1949. It’s vivid and rich in detail, but there are some odd ideas that flirt with eugenics. There’s a really strange passage where the narrator skirts around describing the skin colour of his new-found love interest. I get the feeling that this was very transgressive at the time, but it’s just a bit weird now.

The Last Song Of Penelope by Claire North

The final book in Claire North’s Songs Of Penelope trilogy is the one that intersects the most with The Odyssey. There’s a looming sense of impending tragedy because of that; we’ve spent the last two books getting to know the handmaids of Ithica and now here comes Odysseus to fuck things up. I enjoyed the whole trilogy immensely.

Short Stories In Irish by Olly Richards

This is a great way to get used to reading in Irish. The stories start very simple and get slightly more complex as throughout the book. None of the stories are going to win any prizes for storytelling, but that’s not the point. If you’re learning Irish, I think this book is a great tool to augment your lessons.

Sea Of Tranquility by Emily St. John Mandel

Nothing will ever top the brilliance of Station Eleven but I still enjoyed this time-travel tale set in the interconnected Emily St. John Mandel cinematic universe.

The Heart In Winter by Kevin Barry

A very Irish western. The language is never dull and the characters are almost mythological in personality.

Matrix by Lauren Groff

One woman’s life in a medieval convent. What’s really engrossing is not just the changes to the protaganist over her lifetime but the changes she makes to the community.

Hera by Jennifer Saint

I didn’t enjoy this quite as much as Jennifer Saint’s previous books. Maybe that’s because this is set almost entirely in the milieu of gods rather than mortals.

A Psalm For The Wild-Built by Becky Chambers

A short book about a tea-making monk meeting a long-lost robot and going on a road trip together. It’s all quite lovely.

Bloodchild And Other Stories by Octavia Butler

A superb collection of short stories. Bloodchild itself is a classic, but every one of the stories in this collection is top notch. Some genuinely shudder-inducing moments.

Salt Slow by Julia Armfield

Staying with short story collections, this one is all killer, no filler. Julia Armfield knows how to grab you with a perfect opening line. Any one of these stories could be the basis for a whole novel. Or a David Cronenberg film.

The Voyage Home by Pat Barker

The third book in Pat Barker’s retelling of the aftermath of the Trojan war is just as gritty as the first two, but this one has more overt supernatural elements. A grimly satisfying conclusion.

Folk by Zoe Gilbert

A collection of loosely-connected short stories dripping with English supernatural folk horror. The world-building is impressive and the cumulative effect really gets under your skin.

Death of the Author by Nnedi Okorafor

The description of the Nigerian diaspora in America is the strongest part of this book. But I found it hard to get very involved with the main character’s narrative.

Bear Head by Adrian Tchaikovsky

The sequel to Dogs Of War and just as good. On the one hand, it’s a rip-roaring action story. On the other hand, it’s a genuinely thought-provoking examination of free will.

A History Of Ireland in 100 Words by Sharon Arbuthnot, Máire Ní Mhaonaigh, and Gregory Toner

Every attendee at Oideas Gael in Glencolmcille received a free copy of this book. I kept it on the coffee table and dipped into it every now and then over the course of the year. There are plenty of fascinating tidbits in here about old Irish.

Haven by Emma Donoghue

Medieval monks travel to the most inhospitable rock off the coast of Kerry and start building the beehive huts you can still see on Skellig Michael today. Strong on atmosphere but quite light on plot.

Doggerland by Ben Smith

Fairly dripping with damp atmosphere, this book has three characters off the coast of a near-future Britain. The world-building is vivid and bleak. Like The Sunken Land Begins to Rise Again by M. John Harrison, it’s got a brexity vibe to the climate crisis.

Bee Speaker by Adrian Tchaikovsky

I found this third book in the Dogs Of War series to be pretty disappointing. Plenty of action, but not much in the way of subtext this time.

Yellowface by Rebecca F Kuang

Surprisingly schlocky. Kind of good fun for a while but it overstays its welcome.

Nobber by Oisín Fagan

Gory goings-on in a medieval village in county Meath. For once, this is a medieval tale set in harsh sunlight rather than mist-covered moors. By the end, it’s almost Tarantino-like in its body count.

Orbital by Samantha Harvey

A fairly light book where nothing much happens, but that nothing much is happening on the International Space Station. I liked the way it managed to balance the mundane details of day-to-day life with the utterly mind-blowing perspective of being in low Earth orbit. Pairs nicely with side two of Hounds Of Love.

The End of the World is a Cul de Sac by Louise Kennedy

Louise Kennedy is rightly getting a lot of praise for her novel Trespasses, but her first book of short stories is equally impressive. Every one feels rooted in reality and the writing is never less than brilliant.

A Prayer for the Crown-Shy by Becky Chambers

The second short book in the Monk and Robot solarpunk series. It’s all quite cozy and pleasant.

Our Wives Under The Sea by Julia Armfield

I said that each short story in Julia Armfield’s Salt Slow could be a full-length novel, but reading her full-length novel I thought it would’ve been better as a short story. It’s strong on atmosphere, but it’s dragged out for too long.

I Am Legend by Richard Matheson

Another classic of post-apocalyptic fiction that looks for a scientific basis for vampirism. It’s a grim story that Richard Matheson tells in his typically excellent style.

The Country Girls by Edna O’Brien

Reading this book today it’s hard to understand how it caused such a stir when it was first published. But leaving that aside, it’s a superb piece of writing where every character feels real and whole.

The Bloody Chamber And Other Stories by Angela Carter

If I’m going to read classic short horror stories, then I’ve got to read this. Twisted fairy tales told in florid gothic style.

Rose/House by Arkady Martine

An entertaining novella that’s a whodunnit in a haunted house, except the haunting is by an Artificial Intelligence. The setting feels like a character, and I don’t just mean the house—this near-future New Mexico is tactile and real.

Prophet Song by Paul Lynch

I haven’t finished this just yet, but I think I can confidentally pass judgement. And my judgement is: wow! Just an astonishing piece of work. An incredible depiction of life under an increasing totalitarian regime. The fact that it’s set in Ireland makes it feel even more urgent. George Orwell meets Roddy Doyle. And the centre of it all is a central character who could step right off the page.

There you have it. A year of books. I didn’t make a concious decision to avoid non-fiction, but perhaps in 2026 I should redress the imbalance.

If I had to pick a favourite novel from the year, it would probably be Prophet Song. But that might just be the recency bias speaking.

If you’re looking for some excellent short stories, I highly recommend Salt Slow and The End of the World is a Cul de Sac.

About half of the 28 books I read this year came from the local library. What an incredible place! I aim to continue making full use of it in 2026. You should do the same.

From: Stuff & Nonsense

Let it snow

Winter’s definitely arrived, and there’s a chill wind blowing. We haven’t had snow in the village yet, but it’s falling on my website, courtesy of a new ‘snow mode.’

My winter blog page graphic animation

Visit my home page or blog to see that winter’s set in. On the home page, snow now covers the cacti and craggy rocks. On my blog, it’s settled on the buildings. And, unless animations have been turned off, snowflakes drift down from the sky. Brrrrr.

Adding snow to my existing animated graphics was surprisingly easy. I added three layers to my SVGs:

  1. Falling snow
  2. Settled snow
  3. Chilliness overlay
Settled snow layer
Chilliness overlay layer

That overlay lies on top of the background elements. It has a blue fill colour and a blending mode that cools whatever’s behind it. I think it’s incredible how much of a difference a colour blend can make to how the artwork feels. Then, alongside the button which starts/stops all animations, I added another which toggles the snow.

Snow mode on
Snow mode off

Toggle snow mode on and off to see the effect of these layers.


As you might’ve noticed, I’ve been having way too much fun with my website since I implemented the new pioneer characters, and in my mind, there’s nowt wrong with that.

From: Adactio

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.

From: Dave Rupert

Vibe Check №41

🎵 Christmas time is here. Happiness and cheer. Fun for all… that children call… their favorite time of year.

School’s out. The work laptop’s closed. Now is a good time to recount the vibes. I wanted to get out this vibecheck before embarking on the annual recap that way it’s less moodier than years prior.

Fixing my mood with music

Last vibe check I was super grumpy. Thankfully, I was able to start shaking off that cloud by fixing my mood with music. I am not kidding when I say I got to see three of my favorite bands in the span of a month.

the beths on stage

The first was my current favorite band The Beths. According to Spotify Wrapped I’m a Top 0.2% global fan. They came through Austin and played an incredible set at Emo’s. All the hits. I was enchanted for one evening.

Then a week or so later I saw my friend Richard’s band Heartswarm play at The Aristocrat. I have a lot of friends who play music and in a town like Austin I was feeling remorse for not enjoying that more at every chance I get.

Then, a couple nights later, I saw one of my all time favorite emo bands when Rainer Maria open for my other absolute most favorite (midwest) emo band Cap’n Jazz. The show was so great and the audience was an even 50/50 split between dads over 45 and queer kids under 21. What a cross-section of society! And because my friend Richard is friends with Mike Kinsella, I got to hang out with the him a bit. Cool dude and an honor to finally meet in person.

A couple weeks after that, I took my son and his friend to their first hardcore punk show featuring Dark Thoughts opening for Béton Armé. First time hearing all these bands but Dark Thoughts was awesome. Béton Armé had incredible energy. But the real surprise was Houston hardcore punk/ska band Liberty & Justice. Being from Houston I wondered if we knew similar people in the punk scene. I didn’t summon up enough courage to ask though because it’s been decades since I lived there, but after texting some friends back home I learned the lead singer is good friends with my old neighbor and grew up in the next town over. Small world.

Coding vibes

Despite a heavy workload at work and home projects piling up, I summoned some energy to work on some coding projects at night.

A tennis app for my wife

My wife likes to obsess over tennis scores and ratings; not limited to hers and the team she captains, but for anyone she knows in the United States. She was having trouble accessing the site she uses (tennisrecord.com) and I thought we were potentially IP-banned because she uses it so much. the app is kind of a terrible user experience… so why not try to make a good one?

One constraint I added to the project was that I had to vibe code it. Partly because that’s the approximate amount of spoons I had for this project, but also to practice wrangling these machines a bit better.

Vibe coding was –per usual– a rollercoaster. I told it what I wanted (a multi-page Vite app that uses Netlify functions to connect to the USTA API) and it seemed to like that. The agent generated a PRD.md. I read the PRD. It looked good. I made some edits. I ran the plan…

It did not follow the plan. It went off and scaffolded out the entire application and most of the views. While super impressive in such a short amount of time, generally speaking, that’s not what you want? With software I find you want to step down a path iteratively and make sure you’re not repeating the same mistakes. It would benefit LLMs to maintain a tight context window instead of doing a full blow-out on the first prompt… but that’s not what LLMs do, is it? They drive down a road until it ends and tend to go overboard; they build out features you didn’t even ask for. Also worth nothing they charge per token used.

For example it didn’t understand how to write and use web components. It wrote thousands of lines of JavaScript in an imperative way, which is the opposite of what I asked for and the antithesis of the web components ethos which tends to be highly declarative and template driven. After a half-dozen repeated failures I tried the prompt “Use Lit” and seemed to understand that (sometimes). I need to re-read the chatlogs because I was able to turn the corner on quality but it required a lot of hand-holding and babysitting the machine. It excelled at short tasks like “Rename X to Y” but to be honest “Find & Replace in Project” isn’t a hard task for me. I think where it can be good is tedious work like changing API structures (renaming functions, etc) and then extrapolating that change out to the rest of the project.

Ultimately the project died in an unceremonious way when the USTA denied my application for an API key. Boo. I will never know if all those API endpoints that weren’t in the documentation actually worked or if Copilot just invented them. Also impacting the project was the fact that Quiet UI disappeared from the internet, which is a special kind of setback for doc-dependent LLMs. Oh well. I’d rank it a mixed success. I got through my personal quality-via-the-LLM barrier, but trying to corral the stateless machine wasn’t the most enjoyable experience and I didn’t ship the app.

An app for analog drawing

I loved graph paper as a kid. I used to buy giant pads of it and make scale architectural models of my house. The algorithm surfaced some cool isomorphic dungeon drawing videos for me but the process of sourcing some graph paper let me down. I wanted to print out a couple sheets of graph paper but I kept getting skeezed out by my options on image search. Low-res JPEGs with shitty logos splattered all over. No sense of how big it’d actually be when I printed it out.

screenshot of my grid paper app with some configurable settings in a header and a grid covering the entire background

So I spent an evening making my own little Grid Paper app. I’m pleased with the results. It supports grids, dot-grids, isomorphic grids, perspective grids, and dual-hex grids. I have a branch locally that adds normal hex grids and more fidelity but it’s a complete refactor so it’ll take some time to finish out.

All said, I’m happy with the time vs effort results on this project. A couple nights worth of work.

Retrogaming

I got a neat little Anbernic retro-handheld emulator for Christmas last year but to be honest I hadn’t played it much. The system was lacking a lot of the first-party blockbuster games I loved. Y’know what I’m talking about… the sbarro brothers, the sanics, the pokey-mens, the mega-dudes; those sorts of games.

I mentioned this to a friend and he helped me… ahem… backup some games I had. And that was enough of a spark to inspire me to swap out the default operating system to a custom one called Knulli and I made it feel neat-o by installing the Techdweeb theme.

I’m loving it so much more. I’ve been playing through a game where you capture these little critters and use them in ethically-questionable battles against other children and adults. So that’s fun and been a great way to relax that isn’t doomscrolling or YouTube rabbit holes.

Statistical Breakdown

📖 Reading

SapiensAt HomeSlow DownControl FreakIt's Only DrowningA Libertarian Walks Into a Bear
  • Sapiens ★★★½ - This book very much fits into my historical graphic novel wheelhouse. It suffers some of the common problems with the real-book-to-comic genre (long speeches, hammy conversation setups, etc) and I struggled at the beginning, but towards the middle I latched on and enjoyed it enough to get the second book from the Library… which I didn’t read. One eyebrow-raising bit is that it somewhat opens the door to “These people have different DNA”-type phrenology or supremacy narratives. Woof.

  • At Home DNF - I did not finish this book, but I did enjoy it. I probably prefer a more linear history lesson on a single topic, but Bill Bryson does something unique and ties together a tapestry of historical anecdotes based on common objects found in his home. I may pick this up again in the future when things slow down and my mind can wander more.

  • Slow Down ★★★★½ - Comrades! Degrowth is a topic I’m interested in. How do we break away from the “always grow” cycle of Capitalism and it’s climate death march. Kōhei Saitō suggests communism, leaning on the contemporary writings of Marx that didn’t make it in Das Kapital that were focused around ecological sustainability as opposed to revolution.

  • Control Freak ★★ - I’m always up for some video game history and CliffyB’s has played a role in some of gaming’s biggest moments. The book starts with a classic nerd coming-of-age at the dawn of the internet story that is familiar, his father’s passing, but before digging into his time at Epic games, the story takes a sudden turn recounting his own sexual abuse. Then it hops back into video games like nothing happened. The book is soaked in CliffyB’s non-malignant but very apparent narcissism. Name drops. Affairs. Divorce. Matching Lambos. Markers of success CliffyB seems to wear like self-deprecating badges of honor. I don’t mean to take from CliffyB’s successes (Unreal Tournament, Gears of War, Fortnite, etc) and those portions of the book are interesting in their own right, but overall… it felt like a very personal story rather than a general nerds-to-riches type story.

  • It’s Only Drowning ★★★½ - Author David Litt decides to take up surfing late-in-life. To achieve this goal he must befriend his twenty-something brother-in-law. It’s a story of self-realization and challenging yourself to achieve a difficult goal as well as bridging an awkward familial/generational/political gap. I think it also embodies the male loneliness epidemic; a desire to have relationships with people who aren’t our spouse, to be invited, and to belong.

  • A Libertarian Walks Into a Bear [In progress]

📝 Blogging

I had a secret theme –that I don’t if anyone picked up on– but I was trying to share things I like. A couple got serious, but most of them were simple posts about a game or YouTube series I like. I think this also helped put me in a better moo.

These posts are easier technical posts. They don’t get as many hits… but they also don’t get stuck in months-long quality assurance and demo-building limbo.

📺 Media Diet

Movies

Podcasts

  • Systems of Harm (S2) - I’m late to it but been enjoying season two of Systems of Harm.
  • Nice Try (S1) - A podcast about failed utopias.
  • Beyond that the usual If Books Could Kill & Maintenance Phase routine.

YouTubes

  • Been really into Rust vods.

🎙 Recording

Chris and I wrapped up our 14th season of Shop Talk. 695 episodes of showing up every week. Can’t believe we’ll be at 700 soon.

⌨️ Open source

  • 🎉 Fluent Web Components v3 is in Release Candidate - It’s been a lot of work (138 beta versions) to get here. But we’re happy with the progress as well as the capabilities.

👾 Video games

  • Retro gaming: As said above, I got into retro-gaming. I’m happy to mine this vein for awhile.
  • Puzzle games (see blog).

From: Meyerweb

Targeting by Reference in the Shadow DOM

A new way to allow elements inside a Shadow DOM to be targeted for accessibility or other reasons.

From: Stuff & Nonsense

Smashing Animations Part 7: Recreating Toon Text With CSS And SVG

Yours truly over at the Smashing Magazine: “In this article, pioneering author and web designer Andy Clarke shows his techniques for creating Toon Text titles using modern CSS and SVG.”

Read Smashing Animations Part 7: Recreating Toon Text With CSS And SVG

From: Stuff & Nonsense

Designing banners for the Academy of Scoring Arts

While the smart people finish the Academy of Scoring Arts website’s CMS development, I’ve been rummaging through my design files and rediscovered several concepts that didn’t make it into the final design.

Old Academy of Scoring Arts website banner

Like 20,110,000* others, the Academy of Scoring Arts website was topped by a full-width banner with a faded background image, intro text, and a big ol’ button. The image was somewhat relevant; the text did, at least, explain what the website is about; and the button was, well, big. But by now, most people have trained their brains to scroll straight past banners like this to get to the real content.

What I wanted instead was something that reflected the messages I cared about communicating—community, connections between musicians, and musicality.

I’m a big admirer of Erik Nitsche’s work. He’s best known for the annual reports and posters he designed for General Dynamics, but it’s his album covers—those mixes of colour, shape, and distinctive typography—that I return to most often.

Album covers by Erik Nitsche

Dozens of Nitsche’s covers went into my research folder, but the piano-key graphic from The Amazing Bud Powell, Vol. 5 stood out. Early in the design process, with only placeholder graphics needed for first concepts, there was very little difference between my version and Nitsche’s original.

Erik Nitsche inspired placeholder design

At this stage, graphics like these are valuable talking points as I get to know a client and their likes and dislikes. The feedback was clear: the Academy is less jazz-oriented and more orchestral. More importantly, the graphic didn’t convey a sense of community or connection. That sent me in a different direction.

While visiting an abstract art exhibition in the summer, I saw work by Juan Gris, Wassily Kandinsky, Joan Miró, and Pablo Picasso. Gris’s cubist paintings resonate with me more than Picasso’s, so experimentation began with a graphic inspired by his 1913 painting Still Life With a Guitar.

Juan Gris inspired design

These sketches used flat colour and no texture—enough to test the idea with the team without over-committing. The increased energy landed well, but the concept itself didn’t. It still felt too literal. The idea was worth pushing further, though. To make it more abstract and energetic, I looked to Kandinsky. His paintings are full of movement, and that sense of motion felt right for a community of composers.

Wassily Kandinsky inspired design

Drawing abstract lines and shapes, with added shading and transparency, created more depth. The result was closer to what I had in mind. From there, I also explored a looser, more free-flowing direction inspired by Joan Miró.

Joan Miro inspired design
Joan Miro inspired design

These were by far my favourite artist-inspired designs. The Academy team weren’t convinced and asked me to explore a different direction, including images of their members to emphasise the community aspects of their work. I still wanted to communicate connections, so I added lines connecting the people and made parts of them pop out of the shapes to loosen the composition and give it more energy.

People in circles (final)
People in irregular shapes (final)

This was the direction the Academy team felt best reflected their brand and what they aimed to communicate to their members.


Looking back through my folders, I’m reminded how many ideas never make it past a first iteration—and that’s never a failure. Design decisions are often subjective, so every attempt becomes a conversation. Those conversations matter, because they’re how I move past my own preferences and get closer to what a client is trying to express. In the end, it’s those conversations that shape the final result far more than any single idea.


* May not be entirely accurate, but what the hell.

From: Chris Coyier

EMTBs in Bend

The decision is in from the Forest Service: Of the over 500 miles of singletrack maintained by COTA, about 320 miles of trails are in the Deschutes National Forest (DNF). As of December 2025, it is now allowed to use Class 1 pedal-assist e-bikes on 160 miles of those trails. Feels like this is on […]

From: Stuff & Nonsense

Updates to my Toon Text styles gallery and generator

I mentioned last week that as well as expanding my Toon Text styles gallery, I’d added a Toon Text generator to help me (and you) create text in the style of those classic cartoon title cards. Now, I’ve launched a major update to both.

Toon Text demonstrates how to style text to resemble cartoon title cards using CSS properties, including background-clip, filters, text-shadow, text-stroke, and more. I’m building the collection as I love experimenting with combining those properties.

The Toon Text generator lets you use those properties to create Toon Text from presets or from scratch and see the results instantly.

Toon Text
Go to Toon Text

Updates to Toon Text

As my collection grows, I wanted to add filtering to the page based on how I tag each example. There’s now navigation which filters the examples by tag, for example filter. JavaScript automatically populates this navigation from my tags and displays how many examples are tagged.

Previously, I’d added buttons which navigated to the Toon Text generator. Now, JavaScript reads the computed styles of each example and passes them to the generator to use as starting points for creating new Toon Text. It even passes the title text.

Toon Text generator
Go to Toon Text generator

Updates to the Toon Text generator

As I mentioned, navigating from the Toon Text gallery to the generator now allows you to use its styles as starting points. I’ve also added new presets and a sticky contenteditable preview box.

I’ll no doubt refine both of these over time, but for now, here’s my updated Toon Text styles gallery and Toon Text generator. You might also like my more accessible text splitting tool, Splinter.js. which I also introduced today.

From: Stuff & Nonsense

Splinter.js — I made a more accessible text splitting tool

Sometimes I don’t want to style a whole word or heading. I want to style individual letters—to nudge a character into place, give one glyph extra weight, or animate a few letters independently. Sadly, some splitting solutions don’t deliver an always accessible result. With the help of a developer pal, I've written my own text splitter, Splinter.js.

In plain HTML and CSS, there’s only one reliable way to do that: wrap each character in its own span element. I could do that manually, but that would be fragile, hard to maintain, and would quickly fall apart when copy changes. Instead, when I need per-letter control, I use a text-splitting library like splt.js (although other solutions are available). This takes a text node and automatically wraps words or characters, giving me extra hooks to animate and style without messing up my markup.

The problem

It’s an approach that keeps HTML readable and semantic, while giving me the fine-grained control I need to recreate the uneven, characterful typography you see in classic cartoon title cards. However, this approach comes with accessibility caveats, as most screen readers read text nodes in order. So this:

<h2>Hum Sweet Hum</h2>

Reads as you’d expect:

“Hum Sweet Hum”

But this:

<h2>
<span>H</span>
<span>u</span>
<span>m</span>
[…]
</h2>

That can be interpreted differently depending on the browser and screen reader. Some will concatenate the letters and read the words correctly. Others may pause between letters, which in a worst-case scenario might sound like:

“H…” “U…” “M…”

Splinter.js
Go to Splinter.js

My solution, Splinter.js

To activate my Toon Text splitter, add a data-split="toon" attribute to the element you want to split:

<h2 data-split="toon">Hum Sweet Hum</h2>

First, Splinter.js separates each word into individual letters and wraps them in a span element with a toon-char class and aria-hidden attributes applied:

<span class="toon-char" aria-hidden="true">H</span>
<span class="toon-char" aria-hidden="true">u</span>
<span class="toon-char" aria-hidden="true">m</span>

The script then takes the initial content of the splintered element and adds it as an aria-label attribute to help maintain accessibility:

<h2 data-split="toon" aria-label="Hum Sweet Hum">
<span class="toon-char" aria-hidden="true">H</span>
<span class="toon-char" aria-hidden="true">u</span>
<span class="toon-char" aria-hidden="true">m</span>
</h2>

Lines of text separated by <br> elements are wrapped in a span element with a toon-line class attribute applied:

<h2 data-split="toon" aria-label="Hum Sweet Hum">
<span class="toon-line">
<span class="toon-char" aria-hidden="true">H</span>
<span class="toon-char" aria-hidden="true">u</span>
<span class="toon-char" aria-hidden="true">m</span>
</span>
[…]
</h2>

With those class attributes applied, I can then style individual characters as I choose.


My goal is make a text splitter which is more accessible than others I’ve found. If you’re an accessibility expert, I’d love to hear your thoughts and suggestions for how to improve Splinter.js.

I also wanted to make Splinter.js small, really small. The minified script file weighs in at only 1.3Kb. If you’re a Javascript expert, I’d love to see your improvements. Splinter.js is available on GitHub.

So here’s Splinter.js, a lightweight and (hopefully) more accessible text splitting tool.

From: Chris Coyier

Media Diet

🎵 Florence + The Machine, Everybody Scream — I have no prior Florence experience but really like this album. The whole “start slow and build a song to a wild ass peak” thing works for me. “You Can Have It All” is a favorite. A little called out by “It must be nice to be a […]

From: Zeldman

Accessibility is a human right, cruelty a human wrong.

Once more for the folks in the back. Calibri is easier than Times New Roman for folks with certain visual disabilities to read. That’s why the Biden Administration chose Calibri for their digital communications: to include more people and make life just a wee bit easier for the disabled. And who in their right mind could […]

The post Accessibility is a human right, cruelty a human wrong. appeared first on Jeffrey Zeldman Presents.

From: Stuff & Nonsense

I made a tool to generate Toon Text

Partway through writing an upcoming article for Smashing Magazine, I decided it would be helpful to have a tool to generate text styled like that in my beloved cartoon titles. So I made one.

My Toon Text tool enables you to add colours, strokes, and multiple text shadows. You can change the paint order, apply letter-spacing, and preview your text using a few sample fonts. Then, you can copy the CSS to your clipboard to use in a project.

I’ll no doubt refine it over time, but for now, here’s my Toon Text generator. You might also like my growing collection of Toon Text examples, inspired by classic Hanna-Barbera title cards.

From: Stuff & Nonsense

Unfinished Business #138: Would you like a glass of champagne?

In this episode of Unfinished Business, Andy and Rich talk about retainers and maintenance contracts, and Andy asks Richard’s advice on how to sell them to new clients. As he’s prone to do, Andy also talks about Wrexham football club.


Sponsored by Contract Killer

Most web design contract templates are stuffed with boilerplate content your clients will never read. Contract Killer covers everything—payments, revisions, scope, and timelines—in plain, human language. Trusted by designers for over a decade. Peer-reviewed, fully customisable, and built to keep projects on track, and your invoices paid.

Buy Contract Killer


Also available on YouTube

For anyone who can’t get enough Unfinished Business, we publish the show in video format on YouTube.

Watch “Unfinished Business” on YouTube

Sponsor Unfinished Business

The best way to promote your product or service to the Unfinished Business audience of creative professionals, designers, and developers. Sponsors get one exclusive two-minute ad per episode, live read by me or Rich, which feels personal and relatable. We can use your script or ad-lib, and you’ll also receive a link on each episode’s post, as well as a thank-you on our Bluesky and Mastodon accounts. Interested? We’d love to hear from you.

Support Unfinished Business on Patreon

We also have three monthly membership plans so you can support Unfinished Business on Patreon. $5, $10, and $20 if you’re feeling especially generous. All money goes towards podcast editing and hosting. Support Unfinished Business on Patreon.

From: Boagworld

Your Christmas Shakedown!

I'm disappearing until January. But first, a festive shakedown.

From: Boagworld

How UX Professionals Can Lead AI Strategy

Lead your organization’s AI strategy before someone else defines it for you. A practical framework for UX professionals to shape AI implementation.

From: Stuff & Nonsense

A new workshop space for my side projects

You know what it’s like. You decide to make a fun little side project. No need to integrate it into your main codebase. It doesn’t have to have compatible CSS or HTML, so no worries. Then you make another one. Same deal. Then another. Oh. All of a sudden, you have several projects, and there are annoying differences between them.

That was me. I made my collection of classic cartoon toon titles cards. Then I added my new toon text collection and created a tool for making cartoon-style text. I also had the hosted examples from my magazine articles, and when I looked at them together, the differences were too much for me to ignore.

Space for creative code experiments and passion projects

So for the past few evenings, I’ve been bringing all these little projects together into what I’m calling my “workshop”. It’s essentially a landing page linking to the various projects.

I also created unified headers and footers, as well as a stripped-down stylesheet. The overall CSS architecture is a little more complicated than I’d like, but it works for now:

  1. Top level stylesheet for all workshop components (workshop.css)
  2. Second-level stylesheet for specific projects (styles.css)
  3. Embedded CSS on specific pages, for unique elements

Hopefully, this will make new projects and updates to existing ones easier. Plus, I feel happier that everything feels more integrated into my overall website design.


Go to my workshop.

From: Boagworld

AI for UI Designers: From Fear to Fluency

A realistic look at AI's impact on design careers, plus practical techniques for using AI in brand research, wireframing, and prototyping.

From: Stuff & Nonsense

Getting creative with the Measure

Yours truly over at CSS Tricks: “I spend an unhealthy amount of time on the typography in my designs, and if you’ve read any traditional typography books, you might remember “the measure.” If not, it’s simply the length of a line of text. But measure means more than that, and once you understand what it represents, it can change how you think about layout entirely.”

Read Getting creative with the Measure.

From: Boagworld

Wrapping Up: Your Path Forward as a UX Leader

Final thoughts and encouragement for UX leaders navigating organizational challenges. Keep going from failure to failure.

From: Stuff & Nonsense

IW329303 4 ME AT 60

I’m not entirely sure how it happened, but it was yours truly’s 60th last week. I spent it in Germany with Sue and Alex and one of the highlights of the trip was buying a watch to celebrate that big birthday.

For years I’d said, “When I grow up, I want to buy an IWC Big Pilot.” IWC (International Watch Company) is based in Schaffhausen in Switzerland and I have fond memories of the place as I once worked with Sinar—a large format camera company—who were based near there.

Original IWC pilots watch

IWC first made its B-Uhr pilot’s watch for the Luftwaffe and was one of five suppliers to the German air force. The design requirements included an oversized crown—usable while wearing gloves—and a highly legible dial. Even its strap was extra-long, designed to be worn over a pilot’s jacket. But this isn’t a history of the Big Pilot. For that, you should read this article on Monochrome Watches.

We’d stopped in Schaffhausen on our way back from France this summer and visited the IWC boutique and museum connected to their factory. This was my first opportunity in a long time to try on the Big Pilot I wanted when I grew up.

2002 IWC Big Pilot without 2, 3, and 4 numerals.

IWC introduced a modern version (IW5002) of the wartime Die Grosse Fliegeruhr in 2002, retaining the signature elements of the original design. It had a matte black dial and highly legible Arabic numerals. It also included an impressively long power reserve, so—along with a date window at the six o’clock position—IWC added a power reserve indicator at three o’clock. That meant there was no room for a 2, 3, or 4.

2025 IWC Big Pilot with cut-off 2 and 4 numerals.

A few years later, IWC redesigned the dial (IW500401), and it’s stayed the same ever since. So the model I tried on kept the power reserve indicator but brought back the 2 and 4 numerals, with the indicator cutting across them. That’s a detail I honestly hadn’t noticed until I tried the watch on in the boutique. And when I saw it, I knew it was a detail I couldn’t live with.

My IWC Big Pilot 43 with a blue dial.

Fortunately, my dream wasn’t entirely shattered: in 2021, IWC released a smaller, more wearable 43mm version. The 46mm Big Pilot is a big watch, but as someone with big wrists, I didn’t mind that. I was concerned the 43mm might look too small on my wrist. Luckily, it didn’t. But most importantly, its design removes the date window and the power reserve indicator, restoring the full 2, 3, and 4 numerals. As I already own a black U-Boat watch, I opted for a Big Pilot 43 with a blue dial and strap and bought an extra brown strap to turn my watch into a mini Petit Prince design.

Open case back on the IWC Big Pilot 43.

And unlike the closed case of the 46mm Big Pilot, the 43mm model has an open case back to show off the movement.

To say that I love my new watch is an understatement. Yes, it’s an expensive item, but I’ll enjoy wearing it every day. That, and I’m only going to turn 60 once. It’s funny because I don’t consider myself a “watch guy,” and I didn’t wear a watch at all for 30 years. My social media feeds are full of videos about Rolex and other luxury brands, but I’m not interested in owning one of them. I bought my IWC because I like the simplicity of its design and because I’m nostalgic for Schaffhausen. This isn’t going to be part of a collection, although (please don’t tell my wife) I’d also love to own this.

IW510504, a limited edition stainless steel watch released in 2018 to commemorate IWC’s 150th anniversary.

Mum’s the word.

From: Dave Rupert

One thing churches do well

Two friends of mine (brothers, actually) got laid off from their job at a megachurch here in Austin. We met through a mutual friend that started attending their church. Our kids hang out on Roblox, so we’re connected through dadship and games. They oversaw a lot of the music and arts work that went into the weekly service. I wasn’t involved in the church so their unceremonious departure doesn’t impact me as much as folks in their community, but friends losing work is not fun and I feel for their families.

[Smash cut: my son on stage playing in front of pretend groupies]

My son is learning to play the guitar at School of Rock. One cool aspect about the School of Rock program is that you go from knowing nothing to performing a rock show in ~4 months after signing up. Recitals are nothing new when learning an instrument or a performing art, but those in my experience tend to be on longer annual timescales. School of Rock throws you in the deep end and that rock show commitment adds a lot of positive pressure to learn your instrument.

[Smash cut: me journaling in a coffee shop in my twenties]

These coinciding events got me thinking about church, music, and the relationship there of improving your craft through regular opportunities to perform. I thought about my past, my friends’ pasts, and my son’s potential future and I realized something that one thing faith-based communities do well is that they offer an endless series of opportunities for people to improve and show-off their talents.

At the heart of that is a not-so-secret ladder system. Nearly every faith community I’ve been apart of has had a buffet of special interest groups to rope newcomers in and get them involved at a level that matches their skill. They ask you about your interests and then encourage you1 to use those in service of the community.

  • Play music? You can play for a small group. Prove yourself and move onto the Wednesday service. Ready for the big Sunday show? Start as the fifth guitar. Then the third. Then lead.
  • Artistic? You do art with kids in Sunday school. Move on to making artsy b-roll videos. Your art in front of everyone in the big church: a painting, a solo, a poem, an interpretive dance!
  • Make websites or graphics? You can manage the WordPress, make the PowerPoints legible, make the weekly pamphlets, improve the signage, and spruce up the walls.
  • Like to talk in front of people? Go to a small group. Lead a small group. Lead a mission trip. Get on stage during the Sunday service. Lead the Sunday service when the pastor is out.
  • Have a knack for organizing people? Join a special interest group and invite friends. Encourage people to volunteer for the local Habitat for Humanity outreach. Be the greeter who connects people to special interest groups.
  • A closeted queer kid that loves theater? There’s the big Christmas show –sometimes with live animals!– that happens every year. Churches and youth groups love skits (for some weird reason). And the technical queers can run the soundboard or manage the lights. You may even get a headset.
  • Know a lot about a particular topic (bible, finance, history)? Lead a Sunday school class about it. Host a weekend seminar. A whole week seminar.
  • Handy? Join the church cleanup. Volunteer to fix that leaking window. Fix the broken A/C. Organize a shed or barn raising. Run the Habitat for Humanity group. Be the knowledgeable one on the mission trip.

There’s no shortage of jobs in a thriving community. And while some jobs skew business (the treasurer), administrative (the secretary), or mechanical (the maintenance crew); the bulk of jobs fall under the umbrella of the performing and visual arts. I find this curious in a world where getting a degree in fine arts is often chided or joked about as being non-contributing.

I assume other religions across the world have different flavors of these ladders of opportunity. And I assume secular volunteer organizations might have these kinds of ladders, but I imagine they have way less acoustic guitars. The “speaker circuit” in tech sort of functions like this; local meetup, to regional conference, to national, to international, to keynote speaker, to giving a TED Talk ladder is familiar.

Why would a church provide this service? What is this platform for the performing and visual arts worth? Well I can tell you we pay ~$400/month for School of Rock, so it’s somewhere in that ballpark. It’s possible this social apparatus does return dividends in the offering plate, but I think the key benefit this provides is a place of belonging. A place to exercise talents publicly and regularly that might otherwise remain dormant. Creating that ladder of opportunity is effective at keeping “involvement” –a community’s most important metric by which it lives and dies– at an all time high and engagement keeps the machine turning.

[Smash cut: an announcement board with a hand-drawn thermometer that’s half-filled and renderings of a new building mounted with poster putty]

In most of my experiences at a certain point (when money exchanges hands) and at a certain scale (over ~150 people), the church ladder begins to posture itself towards being another capitalistic corporate ladder with patriarchal undertones. The eternal growth model and the innate desire to build ever larger buildings replace vision and connection. The work becomes about managing real estate and optimizing to keep the pews full. Efficiency rises, the arts and music morph into a Live, Laugh, Love poster with mass appeal.

Anyways, if you were trying to build a new community (or replace religion with something more compassionate)… I would think about building these kinds of ladders. I have no doubt you’ve encountered someone who has developed their gifts or skills in an incubator like this. You may even be reading a person-like-that’s blog right now.

  1. “Encourage you”, or “extract from you”, depending on your perspective or experience

From: Boagworld

Quantifying UX Success and Proving Value

Learn to measure and communicate UX value through quantitative data, qualitative stories, and financial impact calculations.

From: Dave Rupert

Grid Paper

screenshot of my grid paper app with some configurable settings in a header and a grid covering the entire background

Try Grid Paper

I’ve been getting into drawing dungeons on isomorphic grids. It’s fun but I was a little frustrated with the process of sourcing and printing out graph paper with an isomorphic grid on it. You have two bad options, basically:

  1. Download a low-res JPG you found on Google Image search where the grid sizes are wonky and it has a giant URL on it. I needed something clean and simple.
  2. Buy grid paper on Amazon in bulk. Now I’m thinking about centimeters vs. inches, cost, color, paper size, style, and quantity before I draw a single dungeon. I needed something ad hoc and with less commitment.

After 15 minutes of getting frustrated I said “I can build this.” And so I did using HTML, CSS, and the tiniest bit of JavaScript. And because it’s a webpage… why limit myself to one kind of grid? I’m able to support ~7 grids types using different kinds of background gradients:

  • Grids
  • Dot Grids
  • Isomorphic Grids
  • Isomorphic Dot Grids
  • Dual Hex Grids
  • Perspective Grids
  • Two-Point Perspective Grids

Feeling good about this little tool. The quality can be a bit blurry but background gradients and printers are weird. It’d be nice to make it crisper and I might put some effort at the task (use SVG patterns?)… but at less than 5kb and a couple of nights worth of work, I’m happy with the result. It “made the rounds” as they say on the socials and seems to be a common issue other people experience, so I’ll call that a success.

From: Bludice

JavaScript SpeechSynthesis API

As the web continues to be the medium for all users, standards bodies need to continue to provide new APIs to enrich user experience and accessibility. One underused API for unsighted users is speechSynthesis, an API to programmatically direct the browser to audibly speak any arbitrary string. The Code You can direct the browser to […]

The post JavaScript SpeechSynthesis API appeared first on David Walsh Blog.

From: Stuff & Nonsense

My CSS layout strategy

Last week, I explained my strategy for writing CSS selectors. Today, I’ll explain how I decide on and design layouts. It isn’t really about grids; it’s about a repeatable way to make layout decisions.

Studying the content

Before I open Sketch to design or Nova to code, I study the content I’m laying out, as it’s crucial to start with the content and not a predefined container. I decide what’s most important on a page, what elements should be grouped, what should attract attention, and what can stay quiet. This research gives me a sense of the hierarchy I need to create and ideas for expressing it through layout.

Choosing the right grid for the job

How do I know which grid to choose? Each grid type brings something different to a design, so my answer depends on several factors. Let’s break that “it depends” down.

People will be familiar with the ubiquitous 12-column grid, which ships with most frameworks and platforms. The familiarity of its 2-up, 3-up, and 4-up components makes twelve columns an obvious choice when working with developers or in teams.

A compound grid is two or more grids of any type—column, modular, symmetrical, and asymmetrical—on one page. They can occupy separate areas or overlap. Compound grids provide more flexibility, and their interplay of two or more grids is often far more interesting than a single grid in isolation.

A modular grid contains rectangles or square units arranged horizontally and vertically, and is fabulous for organising complex content, so it’s puzzling why so few designers use them.

Then, occasionally, there’s no grid at all, for when I want to tell a very particular story.

What’s important to remember is that choosing a grid should be a design decision. There is no default. Different grids create different feelings and behaviours, so selecting the right one is a design decision, not a technical convenience.

Defining a grid

When I’m implementing a grid in HTML and CSS, I typically define it once, regardless of how many times I plan to use it. I keep a handy set of grid column templates in my boilerplate file, including a 12-column grid and a 4+5 compound:

:root {
--grid-12-col: repeat(12, 1fr);
--grid-compound: 2fr 1fr 1fr 2fr 2fr 1fr 1fr 2fr; }

I apply my chosen grid using a single style:

.layout {
display: grid;
grid-template-columns: var(--grid-12-col); }

I also define values for gap sizes, margins, and a maximum width:

:root {
--grid-column-gap: 1.5rem;
--grid-row-gap: 1.5rem;
--grid-margins: 0 auto;
--grid-max: 80rem; }

.layout {
gap: var(--grid-row-gap) var(--grid-column-gap);
margin: var(--grid-margins);
max-inline-size: var(--grid-max); }

Whether I intend to use child elements or subgrid, these styles permeate my entire grid implementation. And by defining grids, gaps, and max-width once using CSS custom properties, every layout across a project inherits consistency without repeating code.

Creating reusable layout permutations

Every layout instance contains either one, two, three or more child elements, usually divisions or other structural HTML elements. I separate my layout concerns into that underlying grid and then define the arrangements of the child elements using data-attributes:

<div class="layout" data-layout="flow">
<div>[…]</div>
<div>[…]</div>
</div>

[data-layout="flow"] > *:nth-child (1) { […] }
[data-layout="flow"] > *:nth-child (2) { […] }

Instead of designing layouts from scratch each time, I sketch and name arrangements of child elements so I can reach for them quickly as I design.

In that last example, I named the arrangement and proportions of the two-column layout “flow.” But how do I decide how to name them? Well, I could derive names based on their appearance, like “flow,” “split,” or “stack.” But I tend to run out of possibilities doing that.

Instead, I could call them after their content or function, with names like “hero” or “gallery.” But what happens when I need the hero’s layout for something different? Of course, I could just name them after the grid tracks they occupy, with names like “1–5,” “5–9,” and “10-13,” but what if I decide to change the underlying grid and those track numbers change? Honestly, I’ve driven myself nuts thinking about this.

What do I do instead? I avoid the problem altogether and name them after cartoon characters on my own website, capital cities in my Layout Love templates, Welsh politicians for Changemakers, and composers for the Academy of Scoring Arts:

[data-layout="bartok"]
[data-layout="beethhoven"]
[data-layout="bizet"]

Yes, I know this naming convention doesn’t reflect the appearance, content, function, or grid tracks, but it helps me think, “I need the Brahms layout for this.”

Should I use a standard naming convention across all my projects? Maybe. But then I wouldn’t be able to amuse myself coming up with names for my projects. Could there even be an industry standard naming convention? Heck, I wrote about that five years ago, twelve years ago, and as far back as 2004.

Deciding between Grid and Flexbox

I don’t have a checklist for when Grid is a better option than Flexbox, or vice versa, but I do have certain criteria when deciding which to use. Generally, when an element needs to be laid out in one dimension—such as a navigation bar or a group of elements—I will use Flexbox. When I need two dimensions, I choose Grid. Sometimes, the choice comes down to something as simple as how I want the last or widowed item to behave, and whether it should maintain the grid layout or flex to fill the available width. If it’s the former, I use Grid. When it’s the latter, I choose Flexbox.

Adding Multi-column layout

Then there are times when I want to introduce columns which don’t necessarily conform to the layout grid. These might be multi-column text in an article or spreading lists across more than one column to maximise my use of available space. This is when a Multi-column layout is ideal, and I use the measure to define column width rather than the underlying grid layout. Multi-column layout gives me freedom to break away from the grid when a story needs a more editorial flow.

A repeatable way to make layout decisions

My layout strategy isn’t really about grids; it’s about a repeatable way to make layout decisions. It starts with content, moves through choosing the right grid for the story I want to tell, and finishes with reusable permutations that help my designs stay consistent.

From: Bludice

Fix “This video format is not supported” on YouTube TV

Setting up a new computer is bliss — no old, unused apps and the machine performs much better than the previous. Unfortunately, you may encounter new problems based on the new hardware. One such issue I encountered with my new MacBook was a “This video format is not supported” message when I went to YouTube […]

The post Fix “This video format is not supported” on YouTube TV appeared first on David Walsh Blog.

From: Dave Rupert

Inkwell Games

the cute and adorable launch buttons for Inkwell Games' games Stars and Fields

Inkwell Games bills itself as “Daily puzzles worth thinking about” and that’s a great tagline. Right now they offer two daily puzzles: Stars and Fields. Both are enjoyable but I rank Stars as a bit above Fields but as I get better at understanding the patterns of Fields it’s growing on me each day.

Like the NYT, the puzzles grow in difficulty over the week and don’t feel bad if you miss a day because they’ll let you play any of other the puzzles from that week. I highly recommend Stars as a starter, it’s like Minesweeper meets Sudoku where each row, column, and box has two stars. It seems impossible at first, but over time you get a rhythm for cracking this cryptic.

One feature both Stars and Fields have that might be controversial to puzzle purists is a “Check” button. In practice this acts sort of like a “Guess” button where you’re at a dead end and have a guess, but don’t know for sure. It happens a lot in Fields where you’re staring at a grid of numbers with no clear move. Inkwell even wrote a blog post trying to de-stigmatize looking ahead which I appreciate immensely. The purist part of your brain feels guilty guessing at first, but in some ways it teaches you to trust your gut and intuition over time. I used to always need guesses in Stars and Fields but I’ve finished dozens on both now with zero guesses. That’s improvement and the wrinkles in my brain tingle with progress.

If you’re a fan of daily puzzle games, put these in your routine. The playful aesthetic of Inkwell Games’ games always bring a smile. I’m excited to try their upcoming puzzle Snakes and roll it into my daily routine.

From: Dave Rupert

Clues by Sam

A grid of emoji character tiles with names and job titles on each tile. There is one revealed tile on the edge for Pam that is green and she's saying she has 3 innocent neighbors on the edges

Clues By Sam is a daily puzzle game where you get to uncover a criminal conspiracy by following the clues… made by Sam… err… Johannes. It’s a little if-this-then-that logic puzzle where Pam implicates Bob as a criminal and because Bob is a plumber and there’s one innocent plumber then Sally is innocent. It starts simple but overtime but often the clues will feel like they lead to a dead end… but there’s always a way to solve the puzzle. It has a sudoku-like quality to it. Like the NYT crossword the difficulty scales up over the week and is a good way to burn 10 minutes.

Clues by Sam is great. It’s the first game in my daily puzzle routine. It makes me feel like the world’s greatest detective sometimes. Other times it makes me realize I’m not detail-oriented enough to be an investigator. The whole puzzle is a dopamine rush and a pang of sadness hits when I finish the puzzle for there are no more Clues By Sam left to solve that day. I think that’s a good sign of a good game; players wanting to come back. But lucky for me, Clues By Sam is now offering a puzzle pack of 50 puzzles. A nice way to hook people when they’re already addicted.

From: Dave Rupert

La Rinconada, Peru

Above the clouds in the Peruvian Andes there is a town named La Rinconada. It holds the title of being the highest year-round settlement in the world. At one point swelling to 30,000 people, the population has dwindled some now near 12,000. The weather is cold and the oxygen is thin. It’s incredible what humans are able to tolerate to survive. Existing there is dangerous, but that’s where the problems start.

A brief disclaimer before going further...

I want to be careful to not confuse poverty problems with systemic problems. Despite the gold in the hills, La Rinconada is a poor town. One documentary suggests people end up here because that’s the only option left for them. When talking about people in poverty, it’s easy to fall into a trap of drive-by poverty tourism and say “What a mess! Can you believe people live like this?!” but this is people’s lives and I want to be respectful of that. What I want to highlight below are the systems and power structures that create this environment.

La Rinconada’s entire economy centers around extracting gold from Mount Ananea. Being so far away from the nearest municipality, the unregulated mining corporations (legal and illegal) are the defacto government. Workers toil under the cachorreo system, mining for 30 days straight without pay and then one day a month they get claim to as much ore as they can haul out on their person. Some prefer this deal, some get assigned to mine empty veins and make no money that month. Women –who aren’t allowed to work in the mines because of a belief they’d curse the mine– must sift and scavenge in the washes of waste rock or near the toxic cyanide and mercury contaminated tailing pools for discarded ore. It’s uncertain work in hazardous conditions. It takes around two to eight metric tons of ore to produce one ring.

La Rinconada is a lawless city. A small police station exists, but they are overrun by the illegal mining corporations and the gangs. In the mines and on dark streets, murders and robberies are a common occurrence. No banks, so people carry all their cash and gold making for easy marks. The gangs traffick humans from Peru, Bolivia, and Columbia then forced them (including minors) into prostitution. It’s generally considered not a safe place. An even harsher reality for those living there permanently.

As expected with limited government services, the water in La Rinconada is not safe to drink and unmanaged waste fills the streets and alleyways. But despite all the challenges it’s still a town where people live. There is a school and there are kids playing soccer in the streets. Women sell wares in shops and offer street meats, cocoa leaves, and warm soup to hungry miners. Grass growing in concrete type of shit. A human spirit.

While the struggle to survive at the top of the world is real for the people of La Rinconada, the town is for me an allegory of what life is like under a libertarian corporatocracy; where unregulated corporations profit from unfair worker wages, where women get cast to the fringes of society, and where organized crime rules the streets. If I described La Rinconada to you under the guise of a mining colony on the Moon, you’d tell me to ease off on the dystopian sci-fi shit. But this is what’s happening on Earth –today– in the town closest to the Moon. It’s possible that this is what mining towns have always been like, but all I see is the invisible hand of unfettered Capitalism and the true cost of gilded ballroom walls.

From: Dave Rupert

Golden candlesticks

Cover of Arthur Miller's The Crucible

In high school I had the weird, cyclical circumstance of reading Arthur Miller’s The Crucible at least once a year at every grade level. Like Groundhog’s day but set in fictionalized 17th century Salem. While I appreciated the easy grade at the time due to uncoordinated curriculum, reading and acting out The Crucible half a dozen times in those formative years means it left an imprint on my subconscious.

There’s a scene in Act 2 when famous demonologist and witch hunter Reverend John Hale visits protagonist John Proctor. He’s there to shake him down about his poor church attendance and also insinuate his wife is a witch. Proctor defends himself (and his wife) and during his defense makes a big deal about the golden candlesticks in the small, clapboard church (that Proctor put the roof on). The local priest Reverend Samuel Parris –whose bewitched daughter started this whole inquisition– preached about the golden candlesticks for twenty weeks until he got them.

That scene about the candlesticks always stuck out to me. It’s an embodiment of Church’s hypocrisy and materialism which Proctor detests so much that he says “it hurt my prayer.” And Proctor’s right. God doesn’t give a shit about the kind of candlesticks you use. Arguably the pewter ones made by Francis Nurse were a greater act of worship. The Crucible of course is a dramatized tale, but we don’t have to look far for examples of religious figures taking material wealth from the people they’re meant to serve and to paint glamour on top of their image… then casting dispersion on the non-churchgoers and the cabal of “witches” (lebsians, probably) in the woods while your own house is not in order. It’s a morality tale about whose sin is greater.


Everyday now I watch the news and see images like this:

Donald Trump in the Oval Office meeting with a head of state. The two presidents sit in the center of the frame with the Vice President and other cabinet members forming a v-shape extening towards the camera. At the top of the frame boom microphones dangle. Behind Trump is the fireplace, now adorned in gold finishes, with gold urns on top of the mantle, and gold borers around all the picture frames (except Teddy Roosevelt). The side tables with bronze busts are also encrusted with gold. The lamps gold. The mirror gold.

If America were some Pre-Colonial empire I might understand this image. If America was some oil-rich Arabian principality, I might understand this image. But I don’t understand this image. It looks painted on. Imported cheaply.

On the walls are men who (some) through their public service earned that gold border, though they probably wouldn’t care to have it otherwise. Because they understood the job was not for them, it’s for the people. In the foreground is a selfish man who lived a life of fraud, aggrandizing himself at every opportunity, basking in the golden reflections of his fraudulence.

To him this is the height of luxury and power. To me it’s an embarrassment. And in the words of John Proctor, “It hurts my prayer.”

From: Dave Rupert

Precious Plastic

The same people behind Project Kamp also run a project called Precious Plastic which is an open source plastic recycling platform. As most are well aware, plastic is a major problem polluting our land, our beaches, our rivers, our oceans, and our balls. While Ocean Cleanup is progressing nicely, only 10% of the world’s plastic is recycled. That’s appallingly low for something we know is a huge issue. That’s the problem Precious Plastic is trying to solve.

How does Precious Plastic work? Like Project Kamp, they make open source research modules available to help you start a business recycling plastic. They offer guides on building your own machines , creating objects, running a business, and operating a space. There’s even a small marketplace where you can buy injection molds and a library of products for inspiration. It’s almost like a startup in a box but instead of burning GPUs in Iowa to fancy-autocomplete some text, you’re melting garbage into table tops, cups, bowls, phone cases, and other knickknacks. Or you can specialize in making the raw materials (plastic chips, slabs, etc) that others can use to make their dream products. Nice.

The coolest part about Precious Plastic is that it’s a distributed open model that empowers local communities to solve their own plastic problems. My favorite example of this model is this young woman in Indonesia who recycled over 70 tons of plastic in two years while making $200k/yr.

Inspiring. Anyways, setting up a Precious Plastic facility like this is on my tech-exit vision board short list.

From: Dave Rupert

Project Kamp

I’m a sucker for off-grid DIY content. And a double-sucker for commune documentaries. And this post is about a project that scratches both those itches.

Project Kamp is a sustainable living community in the hills of central Portugal. The unique thing about this cooperative living situation is that they’re sharing the process of reclaiming the land and growing an environmentally friendly community via their YouTube channel and open source modules. As with any project, there are ups and downs but week after week they make progress on tackling their list of problems challenges (which they address every 8th video) while maintaining their core values.

When it comes to making decisions on how to grow or what projects to tackle, Project Kamp prioritizes environmental sustainability above nearly all other factors. That work manifests in installing solar panels, water management, repairing old buildings, waste management for dozens of people using outhouses, converting abandoned trailers into housing using recycled materials, and a lot of chopping down mimosa trees (an invasive species that starves out native oaks). It’s encouraging to watch a group of like-minded folks working to build the kind of world they want to live in.

At the time of writing, they’re on Episode #165 and while you don’t have to watch them all (it’s a lot of chopping mimosa trees), I do recommend going back in time a bit to watch the land evolve over time. I dropped in at Season 2 but the quality goes up in Season 3 and can recommend either as a starting point. From the outside looking in, Project Kamp seems like a bunch of sweet people trying hard to build something that lasts. If I was twenty years younger with no kids and still had a back, I’d probably consider applying to stay there.

From: Stuff & Nonsense

Smashing Animations Part 6: Magnificent SVGs with use and CSS Custom Properties

Yours truly over at the Smashing Magazine: “SVG is one of those web technologies that’s both elegant and, at times, infuriating. In this article, pioneering author and web designer Andy Clarke explains his technique for animating SVG elements that are hidden in the Shadow DOM.”

Read Smashing Animations Part 6: Magnificent SVGs with use and CSS Custom Properties

From: Dave Rupert

The built-in storytelling of Rust

Two survival-ist looking costumed characters with weapons approach a large rusty spherical building

Although I technically own the game and played it once a decade ago; I had a horrible time playing Rust. Other players called me the N-word several times, I died almost instantly, my frame rates were trash, and after three hours I put it down and never played it again. Despite that first-run experience, I’ve spent a lot of time watching Rust videos in the last month.

Rust is like a hyper-realistic version of Minecraft but way more violent. You start naked on a beach with a rock and have to farm resources, craft tools, make clothes, and build shelter. That’s where the similarities to Minecraft stop. In Rust you’re on a single island with up to 200 other people in a player-vs-player Battle Royale-like situation. Over time alliances grow into clans, shelters expand into fortified bases, and the PvP combat escalates as users craft weapons like bows, guns, and rocket launchers. And then after a set period of time, the server wipes itself and deletes everything. The story resets.

Also different than Minecraft, across the map there are a dozen or so “monuments” or zones that players need to go to complete certain tasks. Gameplay-wise, this creates a nice forcing function where players must interact over limited resources to progress in their skill trees. It also creates opportunities for PvP combat and learning a bit more about what your neighbors are doing.

The storytelling

What I’ve found enjoyable about Rust is that it has an element of built-in storytelling. Clan rivalries, limited resources, stealth activities, combat, forced interactions, in-game events, all topped with a challenging progression system. And because the server duration is longer than a human could ever possibly stay awake, you won’t know the state of your game until you log in the next day. Was your base raided while you slept in real life? Drama!

Those are great elements for a story! The somewhat predictable plot and building-tension-conflict loop makes for a good rhythm. The best Rust streamers understand how to extract and bottle this drama and tension. Below are some of my favorite story formats.

Solo Survival

Rush has clans. Sometimes large clans. When a streamer chooses to survive a wipe without teaming up it creates an instant sort of sense of tension.

Base Building

A lot of videos are about building big, impenetrable bases. These have a good engineering vibes… but if I must admit, once you create total security the drama dissipates… that’s why you start picking fights with other clans.

Eco Raids

Eco-raiding is a form of min-maxing resources by breaking into an opponent’s base without using explosives. Spending the time to level-up your skill tree to get explosives is hard and takes forever, so why not find bases where you can break-in using simple tools like hammers, spears, and molotov cocktails. There’s an element of trolling to it, exploiting offline users, but it’s there’s an element of risk to it as well. While crime doesn’t always pay, it’s fun when it does. From a digital security standpoint, it goes to show that almost everyone has an flaw to exploit in their defenses.

Art of Rust

The PvP aspects of Rust seem inevitable, but some players take it beyond the pure game economy min-maxing and make something beautiful in the game spending precious hard-to-get resources on decorative tasks. It becomes a form of ephemeral art, a mono-no-aware. There are actually art community servers that function more like Minecraft’s creative mode, if that’s your thing, but I appreciate the challenge and temporary-ness of doing it in Vanilla Rust.

Is this PvP ASMR chill stream, chat?

I don’t fully understand how PvP games can be chill, but it seems to work. It creates a relaxing ASMR feeling for me. When I played Rust a decade ago I had such an awful stressful time I never wanted to pick the game up again ever in my life, but here I am a decade later watching hours and hours Rust play to wind down my day. And I think it all comes down to Rust’s storytelling. I know big game shops think about this, but if I were creating a big AAA game right now I’d think a lot about how each level, match, or instance tells a cohesive story and how your players could package that up into content, which is then marketing for your game.

From: Dave Rupert

ARIatHOME

Ari Miller is a New York based beat maker who started streaming from his bedroom in 2020. He grew his following by engaging with other popular streamers but where I learned about him was his from viral street performances where he dawns a 55-lbs mobile production studio. He puts on his backpack and walks around New York city with a keyboard, a BOSS RC-505 MKII Loop Station, a microphone, and a computer to run it all through Ableton.

The beats Ari makes are incredible and his production skills are going to win him a Grammy some day. It’s all off the dome live in front of people while walking down the street. Ari doesn’t stop at beats. He takes it to the next level and invites strangers to hop on the mic and he tailors the beat to their personal style and preferences. It’s improv. It’s art. It’s music. It’s communion. There’s something pure about the creativity happening.

What I think I like best about ARIatHOME is this: Seeing creative people expressing their gifts gives me hope. I know I’m watching six hour livestreams edited down to a 15 minute supercut, but Ari seems to have no trouble finding people who have talent and can rap. It might be becuase New York is the birthplace of hip-hop, but the city isn’t short of people willing to step up to the mic and drop some bars right there in the middle of the street.

I also love that ARIatHOME reinforces the mythos that New York is a city full of characters. On every block Ari seems to find someone with more personality than I’ve ever seen in my whole life. Bombastic people with big attitudes, next-level fashion, and outrageous rhymes. It’s like everyone in New York City has that main character energy and Ari seems to be able to draw it out and put it on full display.

The world needs less apartment tours and more of this.

From: Dave Rupert

Random Mini Dungeons

I stumbled onto Odd ArtworksRandom Mini Dungeon video series via the algorithm. He rolls against a dice table to generate a theme and requirements and starts drawing an isomorphic dungeon on a single sheet of paper. It’s almost like a Solo-RPG meets Inktober mashup activity.

The process is straight forward: roll dice, spend an hour to an afternoon drawing the dungeon, scan it, add three layers of gray tones for shading, add color, then add glowing effects. All wrapped up in a “Draw and Talk” format, it makes for a nice predictable ASMR formula. He then collects all the dungeons and goblins he draws and puts them in a stapled zine.

The cartoony style is adorable and reminds me a bit of Kyle Ferrin from Leder Games’s style, who I’m fond of because I got to play DnD with Kyle once. Generating dungeons this way could be a great way to create one-shot mini-dungeons for your campaign (doubly-so if you run a campaign for kids). As a bonus you could surprise players at the end with a little artwork to remember the campaign.

Anyways, I think it’s great and adds positive vibes into the world. You can buy Odd Artwork’s zines his website: https://www.oddartworks.com/

From: Stuff & Nonsense

My CSS selector strategy

Writing good CSS is all about restraint. As an example, I used to over-specify too many things in my stylesheets. It was a bad habit picked up from BEM, OOCSS, and from developers who flattened everything with classes to dodge specificity. Now I think of my CSS selector strategy as a “progressive narrowing of scope.”

I start broad, letting global rules and element selectors do most of the work, and I get more specific only when I need to. This approach keeps my stylesheets smaller, faster, and hopefully much easier to understand. Here’s what I do:

  1. Keep styles as global as possible
  2. Use element selectors
  3. Identify things
  4. Classify things
  5. Vary things

To give you an insight into my strategy, I’ll use examples from the Academy of Scoring Arts project I finished most recently.

Academy of Scoring Arts
My Academy of Scoring Arts project

Element selectors keep styles as global as possible

When I begin a new stylesheet, I start with the broad strokes, typically colour, typography, and spacing. These global styles are the foundation for the rest of my CSS. Element selectors already describe what they are, so I rely on them to do as much as possible. Let’s say I’m styling headlines. I apply styles which will affect how every headline looks:

:is(h1, h2, h3, h4, h5, h6) {
font-family: "Bankside Sans VF";
font-style: normal;
font-variation-settings: "wght" 500, "wdth" 40;
font-weight: normal;
line-height: 1.3;
margin-block: 0 clamp(0.5625rem, 0.5408rem + 0.1087vi, 0.625rem);
text-transform: uppercase;
text-wrap: balance; }

By styling elements first, I get a consistent baseline across my entire stylesheet and avoid repeating styles in multiple selectors. Only when I have element selector styles for the HTML elements I’m using do I progressively narrow the scope by identifying, classifying, and varying their styles.


1) ID selectors identify things

Despite what you might’ve picked up, there’s absolutely nothing wrong with using ID selectors in the correct context, for example, when I know there’ll be only one of something on a page. This might be an introduction section, banner component, or site-wide footer.

Academy of Scoring Arts sign-up page
Academy of Scoring Arts sign-up page

On the Academy of Scoring Arts’ sign-up page, I know there’ll only ever be one block of pricing options, so I used an ID selector:

#options { […] }

There’ll be only one banner component:

#banner { […] }

And one banner logo:

#banner-logo { […] }

Using ID selectors makes an element’s identity obvious at a glance. They’re also handy for linking to those page fragments later.


2) Class selectors classify things

Narrowing the scope further, I start to classify things. For instance, the videos component contains multiple items. Quite often, I’ll style those child elements using a descendant selector:

#videos > * { […] }

Otherwise, I add class attribute values and use class selectors:

.item-video { […] }
Academy of Scoring Arts videos page
Academy of Scoring Arts videos page

Using class selectors defines repeating patterns of styling. Articles in a feed, members of a team, or videos in a collection:

.item-article { […] }
.item-member { […] }
.item-video { […] }

I use class selectors to apply typographic styles:

.alt-lede { […] } /* Lede paragraphs */
.alt-uppercase { […] } /* Uppercase text */

And other classifications of elements, including badges, buttons, and specific form elements:

.alt-btn { […] } /* Styled buttons and links */
.alt-pill { […] } /* Pill-shaped badges */
.alt-checkbox { […] } /* Styled checkboxes */

I also use a class selector to define all my various layouts, which are based on the same underlying grid:

.layout {
display: grid;
gap: 1.5rem;
grid-template-columns: repeat(12, 1fr); }

Once I’ve identified and classified the key elements, my next step is to vary them.


3) Attribute selectors vary things

Staying with layout styles, in the past, I might’ve used a single class attribute to bind a style to an element, like this:

.layout-bartok { […] }

But this meant duplicating styles whenever I added a new layout. I could’ve (and did) use BEM’s multiple class attributes:

.layout .layout_bartok { […] }

But this always felt clumsy, so now I separate my layout concerns into the underlying grid styles using a class selector and define the specific layout as data using an attribute selector:

.layout { […] }

[data-layout="bartok"] { […] }

[data-layout="beethoven"] { […] }

[data-layout="bizet"] { […] }
Academy of Scoring Arts layouts
Academy of Scoring Arts layouts

(Why I named my layout components after famous composers is a topic for another day.)

With data attributes, I’m not just styling layout components differently; I’m making it explicit that one layout is different from another in a way which is semantically richer than using class selectors.

Academy of Scoring Arts
Academy of Scoring Arts sign-up page

Let’s say I have several price options in a group and I want to highlight one. Semantically, I want to state the identity of the element (#options,) classify the options (.option,) then vary how one of them looks:

<div class="option" data-variant="highlighted">

And in my CSS:

.option { 
border: 2px solid ##2896be; }

.option[data-variant="highlighted"] { 
background-color: #212121;
border: 3px solid #7ec339;
animation: triple-pulse-simple 3s ease-in-out 2s;
transform-origin: center; }

In my mind, there’s an important distinction between classifying elements which form part of a group and varying the styles. For example, I might have multiple standard blockquotes and other larger pullquotes. I use an element selector to style a standard blockquote. But although larger pullquotes have the same styling, they don’t form a semantic classification. Instead, they’re variations, so I use a data-attribute:

blockquote p { font-size: 1rem; } 
blockquote[data-variant="m"] p { font-size: 1.2rem; }
blockquote[data-variant="l"] p { font-size: 1.5rem; }

All my horizontal rules share styles, which I apply using an element selector. But when I need to vary thickness, I use a data-attribute:

hr {
border-block-start: 1px solid #2896be; 
margin-block: 1.5rem; }

hr[data-width="l"] {
border-width: 3px; }

My horizontal rules frequently act as section dividers, which require more space in the block direction, so I use a different data-attribute:

[data-function="divider"] {
margin-block: 3rem; }

And in my design for the Academy of Scoring Arts, some horizontal rules are decorative devices:

[data-device="stripe"] {
border-block-start: 40px solid #7ec339; }

Styled buttons can have several variants, from different sizes to various widths:

.alt-btn {
padding: .75em 1em; }

.alt-btn[data-variant="s"] {
padding: .5em .7em; }

.alt-btn[data-variant="block"] {
box-sizing: border-box;
width: 100%; }

And some buttons might animate when someone interacts with them:

.alt-btn[data-animation="shakeX"] { […] }

I often need to vary how some elements look, even when they’re built on the same blocks as others. For example, I might have an unordered list with items aligned to the left, and a list of social media links where they’re centred:

[data-content="social"] li { […] }

Or modular grid layouts which contain team members ([data-content="team"]) vs layouts which contain photos ([data-content="photos"]):

[data-content="team"] > * { […] }
[data-content="photos"] > * { […] }

Once I started thinking this way, I began to see every element in terms of its identity, classification, and variation. Each level builds on the last, intentionally narrowing the scope of my styles.

Magnificent 7 graphic animations
My Magnificent 7 graphic animations

How I think about elements is my strategy

My selector strategy isn’t a framework or a naming convention. It’s how I think about what elements in my markup are, how they relate to each other, their role, and what content they contain. Progressively narrowing the scope keeps my stylesheets fast, small, and as well-organised as I can make them. And it avoids over-engineering to override how CSS was designed to work, including the cascade and specificity.

From: Stuff & Nonsense

I built a silly shooting game in less than 300KB

When I’ve had a few spare minutes, I’ve been adding to and optimising my Magnificent 7 character animations to improve rendering speed. Then I had the idea to build a silly fairground-style shooting game, and I set myself the challenge of keeping it as small as possible.

My silly fairground-style shooting game

You’ll find the Shooting Gallery on my articles page. It’s a temporary place while I test out the game, as people hardly ever go there.

For the game, I flattened my characters into cut-outs, unifying and simplifying the colours to make them look more like the two-dimensional targets you find at a fairground.

Characters flattened to make fairground targets

Then I added three bullseyes to each target, a background graphic, some bunting, and a swinging saloon sign.

Background, graphics, and a saloon sign

Playing the game

The aim is to hit as many bullseyes as you can in 60 seconds while the characters glide from left to right. You can change how quickly they move to make things trickier. Hitting each bullseye puts a hole in it and plays a sound. Hit three bullseyes on the same target, and it falls back (for a while.)

Hit as many bullseyes as you can

Level 1: HTML

I like to keep my markup semantic and straightforward. The game’s HTML starts with a container and the swinging sign:

<div id="shooting-gallery">
 <div id="shooting-gallery-sign">[…]</div>
 […]
</div>

Then, there’s a scrolling container in which the characters move left and right:

<div id="shooting-gallery-scroll-container">
 <div id="shooting-gallery-items">[…]</div>
 […]
</div>

Each character’s SVG and its three bullseyes sit inside their own division, with inline styles to position each target:

<div class="shooting-gallery-item">
 <div class="item-content">
 <img src="billy.svg" alt="">
 <button class="target" style="top: 0%; left: calc(50% - 15px);">
 <span class="target-hole"></span></button>
 […]
 </div>
</div>

There’s another division for the game controls, including the score, time remaining, and speed controls:

<div id="shooting-gallery-hud">

<div>
 <h3>Score</h3>
 <p id="shooting-gallery-score">0</p>
</div>

<div>
 <h3>Time</h3>
 <p id="shooting-gallery-timer">60</p>
</div>

<div id="speed-control">
 <label for="gallery-speed"><span id="speed-value">Normal</span></label>
 <input type="range" id="gallery-speed" min="1" max="4" value="2" step="1">
</div> 

</div>

Plus divisions for my intro text:

<div id="shooting-gallery-intro">
 <h2 id="shooting-gallery-message">[…]</h2>
 <button id="shooting-gallery-button">Start</button>
</div>

And the overlay, which counts down to starting the game:

<div id="shooting-gallery-countdown">
 <span id="countdown-number">3</span>
</div>

Finally, there are sounds for that countdown and the bullet hits:

<audio id="bullet-sound" preload="auto">
 <source src="bullet-hit.mp3" type="audio/mpeg">
</audio>

<audio id="countdown-sound" preload="auto">
 <source src="timer.mp3" type="audio/mpeg">
</audio>

The HTML builds a simple structure: a stage for characters, a HUD for gameplay info, and a few extras for sounds and interactions. Nothing fancy, just semantic markup ready for styling and scripting.


Level 2: CSS

I began with the core animations, such as the targets falling back in 3D when they’re hit three times:

@keyframes gallery-fall {
0% { transform: rotateX(0) translateZ(0) scale(1); }
100% { transform: rotateX(80deg) translateZ(-100px) translateY(50px) scale(0.8); }
}

Then, I added a background to the shooting gallery and used border-image to add bunting to the bottom border:

#shooting-gallery {
background: url(bg.svg) no-repeat center / cover;
border-style: solid;
border-bottom-width: 50px;
border-image: url("border.svg") 0 0 100 0 / 0 0 50px 0 / 0 repeat; }

Character targets

The characters scroll horizontally inside a flex container:

#shooting-gallery-scroll-container {
overflow: auto hidden;
width: 100%; }

And applied perspective to their parent for a more realistic effect when the characters fall back:

#shooting-gallery-items {
display: flex;
min-width: 800%;
perspective: 1000px;
transform-style: preserve-3d;
width: auto; }

preserve-3d applied to the characters content creates the effect:

.item-content {
position: relative;
transform-origin: bottom center;
transform-style: preserve-3d; }

When someone hits all three bullseyes, the script adds a fallen class:

.shooting-gallery-item.fallen .item-content {
animation: gallery-fall 0.5s ease forwards;
pointer-events: none;
transform-origin: bottom center; }

Bullseyes

For each of the bullseye buttons, I added a background and a crosshair cursor:

.shooting-gallery-item button.target {
background: url("bullseye.svg") center/contain no-repeat;
cursor: crosshair;
height: 30px;
position: absolute;
width: 30px; }

I wanted audible and visual feedback when someone’s shot’s on target. Each button contains an additional span element:

<div class="item-content">
 <button class="target">
 <span class="target-hole"></span></button>
 […]
</div>

.target-hole {
background: url("hole.svg") center/contain no-repeat;
display: none;
height: 100%;
width: 100%; }

That hole is hidden by default but becomes visible when someone hits a target:

.target.hit .target-hole {
display: block; }

The characters also wobble every time they’re hit:

@keyframes gallery-wobble {
0%,100% { transform:rotate(0) }
25% { transform:rotate(-3deg) }
75% { transform:rotate(3deg)} }
}

shooting-gallery-item.gallery-wobble .item-content {
animation: gallery-wobble .3s ease; }

CSS handles the static styling and the wobbly characters and falling targets so that a browser using hardware acceleration for smoothness and performance.

Larger screens

On larger screens, I gave the shooting gallery a cinematic 16:7 aspect ratio:

@media (min-width:48em) {
#shooting-gallery {
aspect-ratio: 16/7;
overflow-x: hidden; }
}

Then I reset the container’s horizontal overflow and used a keyframe animation to move the characters left and right during the game:

#shooting-gallery-scroll-container {
overflow-x: hidden; }

@keyframes gallery-row {
0% { transform: translateX(0); }
50% { transform: translateX(25%); }
100% { transform: translateX(0); }
}

#shooting-gallery-items {
animation: gallery-row 30s linear infinite;
min-width: auto;
width: 80%; }

During the game, the script tracks hits for 60 seconds. When someone hits three bullseyes on the same target, it falls back, reappearing a few seconds later. Players can also adjust the difficulty level by changing the movement speed.


Level 3: Performance

What about those all-important file sizes? How small could I make the game?

HTML 33Kb
CSS 7kb
JS 6.5kb
Audio 42Kb
SVG 195kb
TOTAL 283.5kb

Everything, including audio, graphics, and animation, fits comfortably under 300KB. Not bad for a complete mini-game with movement, sound, and interactivity.


Magnificent

This little game reminded me how much fun it is to build something purely for play, even if I’m the only one enjoying it. By keeping my markup minimal, reusing SVGs, and relying on CSS for movement and style, I ended up with a complete game under 300 KB. That’s lighter than one of those full-width hero images I’m always grumbling so much about.

From: Stuff & Nonsense

Unfinished Business #137: All about contracts

In this episode of Unfinished Business, Andy and Rich talk about contracts, how they use them, and some of the pitfalls they’ve both experienced.


Sponsored by Contract Killer

Most web design contract templates are stuffed with boilerplate content your clients will never read. Contract Killer covers everything—payments, revisions, scope, and timelines—in plain, human language. Trusted by designers for over a decade. Peer-reviewed, fully customisable, and built to keep projects on track, and your invoices paid.

Buy Contract Killer


Also available on YouTube

For anyone who can’t get enough Unfinished Business, we publish the show in video format on YouTube.

Watch “Unfinished Business” on YouTube

Sponsor Unfinished Business

The best way to promote your product or service to the Unfinished Business audience of creative professionals, designers, and developers. Sponsors get one exclusive two-minute ad per episode, live read by me or Rich, which feels personal and relatable. We can use your script or ad-lib, and you’ll also receive a link on each episode’s post, as well as a thank-you on our Bluesky and Mastodon accounts. Interested? We’d love to hear from you.

Support Unfinished Business on Patreon

We also have three monthly membership plans so you can support Unfinished Business on Patreon. $5, $10, and $20 if you’re feeling especially generous. All money goes towards podcast editing and hosting. Support Unfinished Business on Patreon.

From: Meyerweb

Custom Asidenotes

In which I turn inline asides into robustly enhanced sidenotes with CSS and just a touch of JS.

From: Stuff & Nonsense

Getting creative with small screens

Yours truly over at CSS Tricks: “Over the past few months, I’ve explored how we can get creative using well-supported CSS properties. Each article is intended to nudge web design away from uniformity, toward designs that are more distinctive and memorable. One bit of feedback deserves a follow up.”

Read Getting creative with small screens.

From: Meyerweb

Parenthetical Asidenotes

In which I turn inline asides into sidenotes, but not in a way anyone should actually use.

From: Stuff & Nonsense

Ambient animations in web design: Practical applications (Part 2)

Yours truly over at the Smashing Magazine: “Ambient animations are subtle, slow-moving details that add atmosphere without stealing the show. In part two of his series, web design pioneer Andy Clarke shows how ambient animations can add personality to any website design.”

Read Ambient animations in web design: Practical applications (Part 2)