Sign in

Piccalilli

@piccalilli.front-end.social.ap.brid.gy
181 followers 0 following 925 posts

High quality, approachable and transferable content from people with decades of elite industry experience. 🌉 bridged from ⁂ front-end.social/@piccalilli, follow @ap.brid.gy to interact

PostsRepliesMedia
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 02/10/2026
The Index: Issue #200 It's issue #200 of The Index! A real milestone that we should celebrate with a dedicated CSS links issue! Sponsored by our friends at Mozilla Festival. piccalil.li/the-index/200
piccalil.li
The Index: Issue #200
It's issue #200 of The Index! A real milestone that we should celebrate with a dedicated CSS links issue! Sponsored by our friends at Mozilla Festival.
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 25/09/2026
The Index: Issue #199 It’s Friday, so let’s close out the week with some Good Links™ in The Index #199, sponsored by Mozilla Festival! piccalil.li/the-index/199
001
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 23/09/2026
It's so frustrating that this still hasn't been addressed with the new "masonry" capability. Not like we covered it over two years ago or anything. Thanks to Manuel for giving us the details here. www.matuzo.at/blog/2026/grid-lanes-…
matuzo.at
Your Grid Lanes will likely fail WCAG 2.4.3 - Manuel Matuzović
I’m a frontend developer, consultant, accessibility auditor, blogger, teacher, and book author from Austria.
002
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 23/09/2026
Stop buttons triggering zoom when they’re double tapped It’s annoying when your browser zooms if a button is rapidly tapped. There’s actually a really simple fix and no, you don’t have to prevent all zooming with a meta tag! […]
front-end.social
Original post on front-end.social
001
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 22/09/2026
In this free lesson from JavaScript for Everyone, @Wilto introduces us to concepts like execution threads, the event loop, and the callback and microtask queues, so we can start putting them to work. piccalilli.link/js4e-free-lesson-qu…
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 21/09/2026
There's been so much dry content about Temporal so far but Sophie Koonin has written about a nice creative usage here. localghost.dev/blog/time-based-back…
localghost.dev
Time-based background colour transitions with Temporal and CSS color-mix
I've given my website a bit of a refresh! There's a slightly updated layout if you're on desktop, plus I ditched the `etc` page and I've revamped my links page to be powered by raindrop.io. The minimalist theme is still minimalist, but a bit more fancy. The vaporwave theme has a newly jazzed-up nav bar with some adorable little icons. But the biggest change is to the city theme, which was previously a starry-sky dark mode theme. If you're reading this between the hours of 9pm - 5am, you might be wondering what all the fuss is about - it looks pretty much the same as it did before. That's because the theme changes depending on the time of day! You can select the time of day using the picker in the top right, after the theme switcher. I'm persisting the choice in session storage so you don't get attacked by sudden light mode when changing pages, but if you visit again in the future it'll reset back to "now". I was going to just turn the layout into a pastel lo-fi-aesthetic thing, but then I realised that a) I needed _some_ kind of dark mode and b) I'd miss the stars! So I thought... why not both? And why stop at just night and day? (Hat tip to Alistair Shepherd who did something similar with his beautiful Firewatch-inspired website.) Then I remembered that the Temporal API was available experimentally in Chrome and Firefox, and I'd been looking for an excuse to try it out. ## Introducing Temporal For the uninitiated, Temporal is a solution to the objectively terrible Date API in JavaScript. Date was based on Java's Date library, which was also objectively terrible and has long been deprecated. It's always really confusing that `Date` instances show either local or UTC time depending on which function you use to display them, and date operations are so fiddly that most of us turn to third party libraries like `date-fns` or `luxon`. Temporal massively simplifies the API, introducing some new concepts: * `PlainDateTime`: a date and time with no timezone (TZ) * `PlainDate`: a date with no time information and no TZ * `PlainTime`: a time with no date information and no TZ * `ZonedDateTime`: a date and time in a specified TZ `PlainTime` came in useful for this project, as we don't really care what the day is - only what time it is, so we know what colours to show. ### Getting the user's local time The first thing to do was figure out the time according to the user's browser. The `Temporal.Now` namespace has various methods for interacting with the current time, including `plainTimeISO()` which by default gives us a `PlainTime` in local time. (You can also pass in a time zone to get a zoned time.) const timeNow = Temporal.Now.plainTimeISO(); Now we need to know when to show the different colours. ## Defining the stages The day is split into four stages: sunrise, daytime, sunset and night. Daytime and night are long - 11.5 hours each - whereas sunrise and sunset each last 90 minutes. The background of the page has a two-colour gradient: --background: fixed linear-gradient(var(--bg-gradient-top), var(--bg-gradient-mid) 80%); The footer has an additional colour that's created with a linear gradient from transparent `oklch(0 0 0 / 0)` to the chosen third colour. background: linear-gradient(oklch(0 0 0 / 0) 40%, var(--bg-gradient-bottom)); This means the last colour sticks to the bottom of the page rather than stretching across the viewport height (it's hard to control even when you specify a percentage in the gradient). It also gives more of a glow that really looks like the sun rising/setting or the glow of the city, which I love. I defined an object for the stages and colours: const stages = { sunrise: { start: Temporal.PlainTime.from("06:30:00"), next: "day", color1: "oklch(0.618 0.3157 265.76)", color2: "oklch(0.8867 0.1222 328.24)", color3: "oklch(0.9529 0.1222 106.94)", }, day: { start: Temporal.PlainTime.from("08:00:00"), next: "sunset", color1: "oklch(58% 0.15433 300)", color2: "oklch(85% 0.22133 302)", color3: "oklch(98 0.22133 302)", }, sunset: { start: Temporal.PlainTime.from("19:30:00"), next: "night", color1: "oklch(0.6933 0.1899 297.53)", color2: "oklch(75.504% 0.24612 357.26)", color3: "oklch(88.591% 0.1422 62.595)", }, night: { start: Temporal.PlainTime.from("21:00:00"), next: "sunrise", color1: "oklch(25.27% 0.0919 276.73)", color2: "oklch(47.35% 0.284 283.78)", color3: "oklch(62.831% 0.23521 310.291)", }, }; CSS custom properties are easy to set via JS - you can use `root.style.setProperty`: root.style.setProperty( "--bg-gradient-top", "oklch(25.27% 0.0919 276.73)", ); Unlike `Date`, we don't have to do any gymnastics to compare Temporal instances: there's literally a `compare` function on each type of instance. Just like with other JS comparison functions, it returns `1` if the first instance is greater than the second, `0` if the two instances are the same, and `-1` if the first instance is less than the second. const compare = Temporal.PlainTime.compare // extracted for brevity switch (true) { case compare(timeNow, stages.sunrise.start) < 0 || compare(timeNow, stages.night.start) >= 0: { currentStageName = "night"; break; } case compare(timeNow, stages.sunrise.start) >= 0 && compare(timeNow, stages.day.start) < 0: { currentStageName = "sunrise"; break; } case compare(timeNow, stages.day.start) >= 0 && compare(timeNow, stages.sunset.start) < 0: { currentStageName = "day"; break; } case compare(timeNow, stages.sunset.start) >= 0 && compare(timeNow, stages.night.start) < 0: { currentStageName = "sunset"; break; } default: break; } Once we've got the stage name, we can look up the colours and set the custom property values. root.style.setProperty( "--bg-gradient-top", stages[currentStageName].color1, ); root.style.setProperty( "--bg-gradient-mid", stages[currentStageName].color2, ); root.style.setProperty( "--bg-gradient-bottom", stages[currentStageName].color3, ); I'm also setting a data attribute on the root so we can do some additional stage-based customisations, such as showing the stars when it's night. root.setAttribute("data-time", currentStageName); And that will give us our different gradient colours at different times of day! And _then_ I remembered that `color-mix` exists. Why restrict ourselves to just 4 times of day and 4 sets of colours, when we could make them... transition into each other????? ## Blending transitions with color-mix `color-mix` is an extremely cool CSS function that lets you, well, mix two colours together. You tell it what colour space you're working with, and the colours, and the browser magically outputs the mix between the two. background: color-mix(in oklch, color1, color2) Much like with gradients, you can also specify a percentage value for the colours, which indicates the proportions of the colours: background: color-mix(in oklch, color1 20%, color2) So I could gradually feed in a bit of the next stage's colour until the next stage took over completely. To get a percentage value for the next stage colour to feed in, I had to figure out how far through the current stage we are. First, I'm calculating the time until the next stage - super simple with the `until` function on `Temporal` instances: time1.until(time2) This gives us a `Temporal.Duration` which represents a period between two time points. So, for example, if it's 7:45pm now and we're calculating `timeUntilNextStage`: const timeUntilNextStage = timeNow.until(stages.night.start) console.log(timeUntilNextStage.toString()) // PT1H15M `Duration`s are stringified (and specified) using the ISO 8601 duration format, so "PT1H15M" means "period, time separator, 1 hour, 15 minutes".Time information appears after the `T`; if the duration had any date information in it, it'd appear before the `T`. We set `timeUntilNextStage` in the switch statement where we're deciding what stage we're in, for example: case compare(timeNow, stages.sunrise.start) >= 0 && compare(timeNow, stages.day.start) < 0: { currentStageName = "sunrise"; timeUntilNextStage = timeNow.until(stages.night.start); break; } Once we've got the duration representing time until the next stage, we need to know the duration between the start of the current stage and the start of the next stage - let's call it the "transition duration". For sunset-to-night and sunrise-to-day, the transition duration is always 90 minutes; for night-sunrise and day-sunset, it'd be 11.5 hours. I didn't want the colour mixing to happen all throughout the day, only around sunrise/sunset like in real life, so I just decided to hardcode the transition duration for day and night to be 90 minutes so it matches the other two. So for that, I can instantiate a `Duration` using the same ISO 8601 syntax: const entireTransitionDuration = Temporal.Duration.from("PT1H30M") Now I need to calculate the difference between the total duration and the time until next stage - basically, how far into the transition period we are, and therefore how much of a percentage we should mix in of the next colour. Handily, Temporal gives us a `subtract` function as well: const diff = entireTransitionDuration.subtract(timeUntilNextStage) Then to figure out the transition progress as a percentage, we can divide `diff` by `entireTransitionDuration`. We'll do that with the time values in seconds so we can divide them, using the instance's `total` function: const entireTransitionDurationInSeconds = entireTransitionDuration.total({ unit: "seconds" }) const diffInSeconds = diff.total({ unit: "seconds" }) const transitionProgressPercent = Math.round((diffInSeconds / entireTransitionDurationInSeconds)*100).toFixed() // gives us a string representation with 0 d.p. ### The midnight problem It's a little more complicated for the "night" stage, because that crosses midnight into the next day. Remember that our `PlainTime` only has time information, not date information - so if it's 10pm and you're asking it how long until sunrise at 6:30am, it'll give you a negative number! const now = Temporal.PlainTime.from("22:00") const sunrise = Temporal.PlainTime.from("06:30") const d = now.until(sunrise) // Temporal.Duration -PT15H30M This causes problems at the point where I calculate the diff, as it'll come out as a large number and completely throw off the calculations. I got around this by getting the absolute value of the duration with `.abs()`, so `timeUntilNextStage` will always be positive, even if it's before midnight: e.g. what was`-PT15H30M` will now be `PT15H30M`. Calculating the diff by subtracting that from a `transitionDuration` of 90 mins will always yield a negative number. case compare(timeNow, stages.sunrise.start) < 0 || compare(timeNow, stages.night.start) >= 0: { currentStageName = "night"; timeUntilNextStage = timeNow.until(stages.sunrise.start).abs(); break; } Then, we only calculate a transition percentage if `diff` is greater than 0: let transitionProgressPercent = 0; if (diffInSeconds > 0) { transitionProgressPercent = Math.round((diffInSeconds / entireTransitionDurationInSeconds) * 100); } This works for the daytime stage too: if it's more than 90 mins before sunset, it'll come out with a negative diff - so that will just display the daytime colours and no transition. ### Let's mix! Now we can use that percentage value (which will always be a whole number) in the `color-mix` function to dictate how much of the next colour we should interpolate. color-mix(in oklch, ${color1} ${transitionProgressPercent}%, ${color2}) I updated my `stages` object to include the next stage name as well: night: { start: Temporal.PlainTime.from("21:00:00"), next: "sunrise", color1: "oklch(25.27% 0.0919 276.73)", color2: "oklch(47.35% 0.284 283.78)", color3: "oklch(62.831% 0.23521 310.291)", }, // etc So we can get both colours dynamically when we set the variables with `color-mix`: root.style.setProperty( "--bg-gradient-top", `color-mix(in oklch, ${stages[nextStageName].color1} ${transitionProgressPercent}%, ${stages[currentStageName].color1})`, ); And that's how we transition the colours! ## Transitioning the transitions As a bonus touch, I wanted the colour change to transition smoothly when you switch between stages manually using the picker on the top right. By declaring my `bg-gradient-xx` variables using `@property`, I can tell the browsers that yes, they are definitely colours - and therefore they can be animated. Without this explicit custom property declaration, I could set the value of `--bg-gradient-top` to a number, or a position, or anything I wanted. By saying it's definitely a colour, the browser knows how to transition it into other values of the same type. I initially did this with `@property` declarations in the CSS: @property --bg-gradient-top { syntax: "<color>"; inherits: true; initial-value: oklch(...); } @property --bg-gradient-mid { syntax: "<color>"; inherits: true; initial-value: oklch(...); } @property --bg-gradient-bottom { syntax: "<color>"; inherits: true; initial-value: oklch(...); } Unfortunately, setting these in the CSS meant that you got a flash of whichever initial values I'd set before the JS kicked in and set the appropriate colours for time of day. If this page were server-driven, or always started from the same colour for everyone, it would've been fine. But the starting colour depends on your time zone and is only calculated when the initial JS runs. I got around this by setting the properties via JS instead: window.CSS.registerProperty({ name: "--bg-gradient-top", syntax: "<color>", inherits: true, initialValue: stages[currentStageName].color1, }); window.CSS.registerProperty({ name: "--bg-gradient-mid", syntax: "<color>", inherits: true, initialValue: stages[currentStageName].color2, }); window.CSS.registerProperty({ name: "--bg-gradient-bottom", syntax: "<color>", inherits: true, initialValue: stages[currentStageName].color3, }); I had to wrap these in a `try/catch` as it will throw if the property's already been defined. It wasn't super trivial to figure out if this property had already been set, as the CSS does define some values for these with the regular `--bg-gradient-xx: ...` syntax. On the `body` and `footer` I set `transition-property` and `transition-duration` to tell it which properties I want to animate: body { --background: fixed linear-gradient(var(--bg-gradient-top), var(--bg-gradient-mid) 80%); transition-property: --bg-gradient-top, --bg-gradient-mid; transition-duration: 0.5s; } footer { background: linear-gradient(oklch(0 0 0 / 0) 40%, var(--bg-gradient-bottom)); transition: --bg-gradient-bottom 0.5s; } And like motherflipping magic, the colours transition seamlessly into each other when the values change! I love CSS. The animation is such an unnecessary touch, but this is my website so unnecessary is the name of the game. ## Polyfilling Temporal for Safari Alas, Safari is behind the times. We love progressive enhancement, and of course I could have just removed any of the transition logic for people whose browsers don't support Temporal, but that's no fun. They deserve sunsets too! Writing a shim for Temporal was also no fun, but I did it because I love you. There are various Temporal polyfills around and about, but I didn't want to end up importing a whole lot of extra JS when I only needed one or two functions. I'm not using any kind of bundler on this site - I use Eleventy to generate the pages, but scripts are just imported vanilla - so I couldn't import something with NPM and expect it to tree-shake any bits I wasn't using. It was a lot more lightweight to just write my own. To check for Temporal support, it's a matter of just checking if `window.Temporal?.PlainTime` is undefined: const supportsTemporal = typeof window.Temporal?.PlainTime !== "undefined"; I'm checking for `PlainTime` specifically as some browsers may have very high level Temporal implementations, but we can't do much without `PlainTime`. To get the user's time in a non-Temporal world, we can just call the good old-fashioned `new Date()`: function getUserTime() { if (!supportsTemporal) { return new Date(); } return Temporal.Now.plainTimeISO(); } To compare dates, we do it by comparing epoch timestamps. These represent the number of milliseconds since the Unix epoch, 01 Jan 1970. export function jsDateCompare(date1, date2) { const date1Ms = date1.getTime(); const date2Ms = date2.getTime(); if (date1Ms === date2Ms) return 0; return date1Ms < date2Ms ? -1 : 1; } Then, we can just assign whichever version of the function we need: const compare = supportsTemporal ? Temporal.PlainTime.compare : jsDateCompare; To polyfill `until`, I've got a `durationBetween` function which will call `until` if Temporal's supported, otherwise it'll subtract two epoch timestamps, and divide the result by 1000 to get the duration as seconds: export function durationBetween(time1, time2) { if (!supportsTemporal) { return (time2.getTime() - time1.getTime()) / 1000; } return time1.until(time2); } Then I call it like this: case compare(timeNow, stages.sunset.start) >= 0 && compare(timeNow, stages.night.start) < 0: { currentStageName = "sunset"; timeUntilNextStage = durationBetween(timeNow, stages.night.start); break; } I wrote a whole suite of unit tests (for a PERSONAL project! I know!) to make sure behaviour was exactly the same, and it seems to be working nicely. I'm hoping I can remove the polyfills in time, but given that the web is beautifully backwards-compatible, it's not the end of the world if it stays around longer than it needs to. ## Fixing a weird background glitch in Safari SAFARI WHY. I started experiencing a very odd glitch in Safari for MacOS where the background gradient would only show up in the initial viewport - when you scrolled, it went white or black depending on whether it was light or dark mode. I narrowed it down to the `background-attachment: fixed` property of the body. After a lot of disabling random CSS and diffing against the `main` branch, which doesn't have that problem, I found out that it really doesn't play nicely with `container-type: inline-size`. In the course of redesigning the site, I'd added a new container context to the `<body>` element and in the process broken the gradient rendering for Safari, as something goes wrong when it tries to render the gradient background with a `fixed` attachment. Chrome, Firefox and iOS Safari were totally fine. When I half-jokingly said I'd have to find out what the modern equivalent of `<!--[IF IE]>` was, David Bushell pointed me to Eric Meyer's post about accessible table headers, which in turn led me to Browser Strangeness. That did indeed have a `@supports` query that targeted Safari for MacOS: @supports (not (-webkit-text-size-adjust:none)) and (font: -apple-system-body) { .selector { property:value; } } } I stuck a `position-attachment: initial` in there, and lo and behold, the problem went away. It means the background isn't quite how I wanted it to look in Safari, but I'll survive. ## This was surprisingly complex The individual moving parts of this project - getting the time and choosing colours, mixing the colours by percentages, animating the transitions - were not that complicated in isolation. Sure, they required me to learn things and look things up, but it was a fun thing to build (until the point where Safari came into the picture). The challenge came wiring it all together in a way that didn't cause flashes of unstyled content (the dreaded FOUC) or flashes of the wrong stage before we calculate the current time. This is a static site, so it's all client-side JS. Ideally I'd compute user's the current time on the server and serve the content with the correct colour values in the HTML, but my web host only supports static sites. To get around that I had to add another separate `init.js` script which runs instantly - it's got a bit of a copy and paste job going on with some of the functions, but it does a very rudimentary check of the user's current time and sets the stage accordingly with no transitions, just so there's _some_ styling on initial load. My JS is all modules, so is deferred by default. I experimented with making _all_ the JS render-blocking with `blocking="render"`, but that felt a bit gross and also didn't fix the FOUC in Firefox. But that's fine, y'know? It still loads in well under a second, and still looks good if you have JS disabled. It's my personal site and it doesn't need to be perfect.
013
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 21/09/2026
🚨 Our huge 35% discount on all courses ends tomorrow! 🚨 Use the coupon code PRICEFALL at checkout. Don't miss out! piccalil.li/courses
Autumn sale, September 8th until September 22nd. 

35% off all courses. 

Save over £80 with code “PRICEFALL”
001
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 18/09/2026
Dan Cederholm has brought out yet another affordable, and very nice font. simplebits.shop/products/kyroh
simplebits.shop
Kyroh
Kyroh is an all-caps, sans-serif display font inspired by a vintage luggage label from the National Hotel in Cairo, Egypt (found in the amazing book from Letterform Archive). I riffed off the hand-lettered word “EGYPT” from the label and filled out the rest of the alphabet informed by those five letterforms. I love how
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 18/09/2026
Our huge 35% discount on all courses ends on Tuesday. Use the coupon code PRICEFALL at checkout. Don't miss out! piccalil.li/courses
Autumn sale, September 8th until September 22nd. 

35% off all courses. 

Save over £80 with code “PRICEFALL”
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 18/09/2026
The Index: Issue #198 It’s Friday, so let’s close out the week with some Good Links™ in The Index #198! piccalil.li/the-index/198
piccalil.li
The Index: Issue #198
It’s Friday, so let’s close out the week with some Good Links™ in The Index #198!
001
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 17/09/2026
A decent custom checkbox pattern for until ::checkmark is ready We're a while off from being able to leverage ::checkmark with checkbox styling, but here's a decent way to get the styling control you want, while preserving the useful parts of the native input element […]
front-end.social
Original post on front-end.social
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 16/09/2026
Mat has not given up and nor should you! wil.to/js4e/newsletter/mat-update-22
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 15/09/2026
There's only one week left of our huge 35% discount on all courses if you use the coupon code PRICEFALL at checkout. Don't miss out! piccalil.li/courses
Autumn sale, September 8th until September 22nd. 

35% off all courses. 

Save over £80 with code “PRICEFALL”
010
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 14/09/2026
We very rarely share video content, but this episode was an absolute delight to watch. They're running a hackathon too which is well worth checking out. codetv.dev/series/web-dev-challenge…
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 11/09/2026
A very handy looking tool that certainly beats a laborious Photoshop process. ditherimage.online
ditherimage.online
Dither Image Online
Get professional dithering effects instantly with this dithertone free tool. Features real-time, local processing with no sign-up required for maximum speed and security.
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 11/09/2026
Just a quick reminder, we're offering a huge 35% discount on all courses if you use the coupon code PRICEFALL at checkout. piccalil.li/courses
Autumn sale, September 8th until September 22nd. 

35% off all courses. 

Save over £80 with code “PRICEFALL”
001
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 11/09/2026
The Index: Issue #197 It’s Friday, so let’s close out the week with some Good Links™ in The Index #197! piccalil.li/the-index/197
piccalil.li
The Index: Issue #197
It’s Friday, so let’s close out the week with some Good Links™ in The Index #197!
001
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 10/09/2026
JavaScript for Everyone's Mat Marquis takes us on a history lesson of how document.all ended up being the only object that is falsy. Not to spoil the show, but it's IE's fault… youtube.com/shorts/Ntii4QH6iaY Grab JavaScript for Everyone here: piccalil.li/javascript-for-everyone
piccalil.li
JavaScript for Everyone
A high quality, expansive written course that will elevate your JavaScript skills to a level you never thought was achievable.
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 09/09/2026
This is great fun! bayeuxgo.live
bayeuxgo.live
Bayeux Go!
Bayeux Go! Thou art Harold. Go forth and win thine battle. Jump your way to victory, avoiding arrows…
012
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 09/09/2026
Save 35% on all courses for two weeks only The summer is over and the autumn (or fall, for our American friends) is here, so we're offering a huge 35% discount on all courses if you use the coupon code PRICEFALL at checkout. piccalil.li/links/pricefall-2026
piccalil.li
Save 35% on all courses for two weeks only
The summer is over and the autumn (or fall, for our American friends) is here, so we're offering a huge 35% discount on all courses if you use the coupon code PRICEFALL at checkout.
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 08/09/2026
In this free lesson from JavaScript for Everyone, @Wilto guides us through the intricacies of asynchronous functions, restitching the fabric of time in the process. piccalilli.link/js4e-free-lesson-qu…
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 08/09/2026
The summer is over and the autumn (or fall, for our American friends) is here, so we're offering a huge 35% discount on all courses if you use the coupon code PRICEFALL at checkout. piccalil.li/courses
Autumn sale, September 8th until September 22nd. 

35% off all courses. 

Save over £80 with code “PRICEFALL”
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 07/09/2026
Even the new custom <select> capabilities bring headaches, but at least Jake's got height sorted for you. jakearchibald.com/2026/goldilocks-s…
jakearchibald.com
The Goldilocks customizable select height
The 'ideal' sizing is more complicated than you think…
011
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 04/09/2026
'It’s hard to find anything other than anecdata from individuals telling us how AI has made them individually more productive. If AI really was creating measurable improvements in productivity across entire organisations, wouldn’t we be seeing that data?' […]
front-end.social
Original post on front-end.social
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 02/09/2026
A rather deep dive into how some of the newer CSS can make this age old pattern even better. dbushell.com/2026/07/03/fixing-full…
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 31/08/2026
One for the freelancers/moonlighters amongst us who are sick of over-complicated invoice solutions. usebilly.app/en
usebilly.app
Billy · Invoice Manager
A tool crafted with love for all the freelancers and small businesses that want their bureaucracy to be a little more organized and beautiful.
010
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 28/08/2026
It's about time we got this! www.matuzo.at/blog/2026/content-awa…
010
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 28/08/2026
The Index: Issue #196 It’s Friday, so let’s close out the week with some Good Links™ in The Index #196! piccalil.li/the-index/196
001
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 27/08/2026
We asked @Wilto what it is he likes about JavaScript. Knowing Mat, it's no surprise to hear him talk with affection for all its rough edges. "A little dust on the lens is all part of the charm" as he puts it. We've got a lot of time for this perspective. piccalilli.link/js4e-q-and-a-1
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 27/08/2026
A CLI for adding new music to the collection Adding markdown files for every new music item is a faff, so I built a multi-step CLI to do it for me. piccalil.li/projects/personal-site/…
piccalil.li
A CLI for adding new music to the collection
Adding markdown files for every new music item is a faff, so I built a multi-step CLI to do it for me.
001
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 26/08/2026
Actually mind-blowing read. Never use client-side only auth, pals. bobdahacker.com/blog/fifa-hack
bobdahacker.com
I Could've Rickrolled the Entire FIFA World Cup. All I Needed Was My ID.
How I found that anyone could register on FIFA's public Agent Platform, gain access to the Football Data Platform's Streaming Management panel, and get RTMP ingest URLs and stream keys for every live FIFA World Cup 2026 camera feed. I then spent hours calling FIFA, MediaKind, HBS, CISA, and the FBI trying to get someone to pick up the phone.
001
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 24/08/2026
A very good explainer of how the AT protocol stuff actually works. overreacted.io/a-social-filesystem
003
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 21/08/2026
'We’re approaching—or arguably are in—an era where ‘made by humans’ is a differentiator. A notion that something beyond money and prompts was put into whatever the heck it is we’re using or consuming or enjoying. We should never lose sight of that.' mindfuldesign.xyz/by-humans
mindfuldesign.xyz
By Humans, For Humans – Mindful Design
Now, more than ever, we need to consider the real, human impact of the work we do. This is a fundamental principle of Mindful Design.
010
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 21/08/2026
The Index: Issue #195 It’s Friday, so let’s close out the week with some Good Links™ in The Index #195! piccalil.li/the-index/195
piccalil.li
The Index: Issue #195
It’s Friday, so let’s close out the week with some Good Links™ in The Index #195!
001
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 20/08/2026
A look at the geolocation HTML element and how it works There’s a new HTML in town that provides a much better interface for geolocation than the older API. Daniel Schwarz is here to explain how it all works together […]
front-end.social
Original post on front-end.social
021
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 19/08/2026
We challenged Alistair to write this and boy, did they deliver! www.mohkohn.co.uk/writing/html-first
mohkohn.co.uk
How building an HTML-first site doubled our users overnight
My client was a utility company, and they had a big problem...
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 18/08/2026
In this free lesson from JavaScript for Everyone, @Wilto shows us to put the (eventual) results represented by one or more promises to use. piccalilli.link/js4e-free-lesson-qu…
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 17/08/2026
This is a really nice RSS reader-like standard.site reader. standard-reader.app
standard-reader.app
Today · Standard Reader
Fresh writing from the publications you subscribe to, every day.
011
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 14/08/2026
The AT protocol strikes again! This is a lovely curation and discovery resource. currents.is
currents.is
currents.is
102
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 14/08/2026
Sorry to everyone who has been getting two emails from the newsletter! We've identified the issue and fixed.
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 14/08/2026
The Index: Issue #194 It’s Friday, so let’s close out the week with some Good Links™ in The Index #194! piccalil.li/the-index/194
001
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 13/08/2026
Don't let JavaScript have the last laugh piccalilli.link/js4e-q-and-a-6
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 13/08/2026
A little progressive enhancement as a treat What do you do when you're working with a rate limited API, a large content base and a dream? Progressive enhancement of course. piccalil.li/projects/personal-site/9
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 12/08/2026
A thoroughly fascinating read. vale.rocks/posts/game-console-brows…
vale.rocks
Web Browsers on Video Game Consoles
Video game consoles have a long history with web browsers. From the advent of the World Wide Web, consoles have been trying to get online. Browsers on video game consoles were initially very much an attempt to provide a cheap gateway to the web for a casual audience lacking technical expertise, though as time progressed they’ve become a greater and more integrated part of systems. This article takes a look at browsers on video game consoles in detail, though only covers official web browsers. Many consoles have browsers installable via custom firmware and homebrew, but they’re beyond the scope of this post, as are non-web systems such as Satellaview and online services that didn’t provide a browser, such as XBAND, Sega Meganet, and Sega Channel. Game console browsers were of interest to web developers for a period while personal computing devices and mobile browsers were still establishing themselves. Overall, the development of console browsers provides an insight into a juvenile web, slowly growing and establishing itself, as well as an insight into game console user interfaces. ## CD-i The Compact Disc-Interactive format and hardware created by Philips and Sony was an ill-fated attempt to bring interactive multimedia to the masses. Development on the project started in the mid ’80s, and home players arrived in 1991. The CD-i’s inclusion as a ‘game console’ here is debatable as it was designed for and touted with much broader capabilities. However, towards the end of its life it was marketed much more as a game console, and it is as a game console that it is best known today – especially thanks to the infamous Mario and Zelda games. With a modem and a CD-Online disc (known as Web-i in the United States) released in late 1995, users could access the web in a very rudimentary manner. The term ‘internet-lite’ is seen paired with the CD-i frequently, for not only was the internet and indeed the entire World Wide Web burgeoning, but the CD-i was a rather limited machine that wasn’t well equipped for supporting the full-scale web. The main menu of CD-Online Disc 97-10. The browser worked and had links to various web portals but was very limited, even given the primitive web of the time. The CD-i’s limited RAM meant that it could store very little, and that simply using the browser would overwrite other values in memory, such as preferences and game saves. The idea was that the CD-i would be a cheaper, TV-based computing device, available at a price point lower than typical home computers that could make it the gateway to the internet for the less technologically literate. During 1996, the CD-i KeyControl keyboard was released, as were additional CD-Online discs. The idea being that new discs would be released periodically with additional games, software, and peripheral support. Records indicate six discs were released in total, with later versions including the ability to develop and deploy your own homepage. By late 1998, CD-Online was winding down on the CD-i, with a version of the service launching for PCs during the turn of the millennium. Throughout the early 2000s it fizzled out and domains went offline, with everything CD-Online coming to a complete close in the mid-2000s. ## Sega Saturn Sega’s 1994 console, the Saturn, gained internet access in late 1996 with the release of Sega Net Link – a tiny device with a custom chip and 28.8kbps modem that fit into the cartridge port. For the Net Link, United States based company PlanetWeb provided their PlanetWeb Browser as the ‘NetLink Custom Web Browser’, an efficient and lightweight browser with a bespoke engine which was tailored and released for various devices in collaboration with manufacturers. Reading PlanetWeb’s frequently asked questions page from 1997, it is clear their browser was built carefully to target television-based devices and existing consoles, making it optimal for the Saturn. Due to televisions having low-resolution screens compared to dedicated monitors, the PlanetWeb browser made use of ‘proprietary software technology for displaying clear, readable text and sharp images on an ordinary television.’. In other words, ‘the Browser features such advances as anti-aliased fonts’. For its time, and given it is on an extremely limited console, it is remarkably fully featured. The browser has an inbuilt magnifier that can zoom to multiple levels, image support, history, bookmarks, an address book, the ability to download files temporarily, and full parental controls for filtering.1 That is in addition to all the configurable options and settings available in a menu accessed by pressing `Start`. There is a wide selection of themes with different cursors and sounds – any of which wouldn’t be out of place in Kid Pix, with blips and bloops and springy sounds of all varieties. The main Net Link page in version 2 of the browser. Each district of the city is a navigable hyperlink. Each time PlanetWeb boots, a random splash screen is shown. Net Link was tied in to the Saturn’s wider online gaming capabilities, allowing ‘On-Line’ battles. Beyond direct multiplayer, it also built a community around the console. For a while PlanetWeb hosted a game exchange mail-in forum allowing users to email in their Saturn game saves via the browser to share them with other people. PlanetWeb also launched Planet WebMaster, a web development and hosting platform that people could use with their browser. In the United States of America, two versions of the browser were widely distributed. Version 2 and version 3. Version 3 brought greater optimisation, more legible fonts, and IRC support. Neither of these versions supported frames, however, instead displaying them as text links. Version 1 was pressed but never released due to a flaw in parental controls – all copies were destroyed. The final version of the browser was Beta 4.035, which was never released physically and was only available as a downloadable update. Version 4 introduced full support for displaying frames inline, more IRC commands, support for embedded wav and aif audio, more shortcuts, faster input, different bullet shapes, outlined fonts, better image format compatibility, and many bug fixes. Beta 4.035 even introduced SSL for e-commerce. It is likely version 4 would have seen a complete and full release had Sega not discontinued the Saturn in 1998 after rapidly losing market share to the Nintendo 64 and PlayStation, which dominated the market. Following the discontinuation, some users took it upon themselves to splice bits of version 4’s beta and previous stable versions together to compile a more complete and final browser experience. ## Apple Bandai Pippin Apple Computer Inc released the infamous Pippin in collaboration with Bandai in 1996. The Pippin is a fairly standard PowerPC computer under the hood and runs software built atop Classic Mac OS. As such, several variants of mainstream desktop browsers were ported. These browsers never saw major utilisation, however, as the Pippin was a failure, and people noted that the Sega Saturn was a far cheaper gateway to the web, even factoring in the additional cost of the Net Link attachment. For the North American market the @WORLD Browser, based upon Spyglass Mosaic, was released in 1996, bundled with @WORLD branded consoles sold in the United States. @WORLD browser came with plug-ins providing support for QuickTime and Macromedia Shockwave. It had filtering control via SurfWatch ProServer and support for some of Apple’s StyleWriter set of ink-jet printers. In mid-1997, a beta version titled @WORLD Online Suite Premium had an terrifically limited release. In early 1998, version 3 of the browser released, but details on what it changed are scarce, and by that time Bandai were announcing they were dropping support for the Pippin due to extremely poor sales. The local getting started page of @WORLD Browser. In April 1997, SurfEZ! (also called the Katz Media browser) was released for the Katz Media Player 2000 – an improved version of the Pippin distributed under licence in Canada and Europe. The console boasted mildly improved specs, and the browser supports HTML, plug-ins and Java, with capabilities for developers to customise the interface for specific solutions. In Japan, a disc titled ‘Internet Kit’ was distributed with Pippins. Version 1.0 was based on Netscape Navigator 1.12 and released in March 1996. It was superseded by version 1.1 in June of that year, which added support for saving images to floppy disc. Version 2.0 released in December 1996 and updated the browser to a Netscape Navigator 2.01 base while adding support for some StyleWriter printers. A Japanese/English machine translation plug-in was available for this version but required a 2MB memory module to use. J-DATA, a company that offered internet services for the Pippin in Japan, released NetCruiser (ネットクルーザー) 2.0 in a bundle with other software for the Pippin. NetCruiser was originally a Windows browser, before it was ported to the Macintosh and then to the Pippin via a process Apple called ‘pippinizing’, which was possible due to Pippin’s similarity to the Mac. J-DATA also published a monthly J.D.Press magazine which included listings of website addresses as barcodes, which could be scanned via a barcode reader device (titled the ‘Super Cat’) to bypass the laborious task of typing out a URL. In 1997, the final Pippin browser for the Japanese market, WebViewer, released in Japan. WebViewer, instead of being built upon Netscape Navigator, was instead built upon Internet Explorer 3.0. It brought much-improved performance but required an 8MB memory module to function. In some cases it was bundled with NetCruiser 3.0, an updated version of J-Data’s browser. Despite developing it at the same time as the Pipin, Apple didn’t release their own Cyberdog browser for the platform, nor did they release Safari on account of it not being introduced until several years later in 2003, long after they had stopped supporting the Pippin. ## Nintendo 64 The Nintendo 64, as it released in 1996, never received a browser, but the 64DD attachment, which released in 1999, brought internet capabilities to the console and a browser via Randnet Disc (ランドネットディスク) which released in early 2000. Randnet was Nintendo’s dreadfully unsuccessful Japan-exclusive online service. The Randnet Disc includes a general-purpose browser for the system, capable of rendering various webpages. While the browser can be controlled via the system’s normal controller, it also has support for keyboard and mouse input. Details about Randnet, and the browser particularly, are far from abundant. ## Game.com It is no fault of your own if you’ve never heard of the Game.com, for it was a poorly, dot-com doomed handheld game console from Tiger Electronics, who you may know for their licensed LCD handheld games. In 1997, with the release of the Game.com, they attempted to compete with the Game Boy to dire results one might expect. A large part of their marketing was that the Game.com had internet capabilities. Indeed, by purchasing the Internet Cartridge and connecting the device to a modem (either an existing one or the Game.com-branded model), you could access a non-graphical, text-only browser. It was very bare bones and feature-poor. ## Game Boy Colour The Game Boy Colour released in 1998, and in Japan exclusively received what one could charitably call a browser with Mobile Trainer in 2001. Using the Mobile Adapter GB, which is an accessory that connected to mobile phones, the Game Boy Colour could play games online. The Mobile Trainer cartridge, however, provided an email client and web browser. Given the Game Boy Colour’s meagre 8-bit processor, even calling it a browser is a stretch. It can only access an official Nintendo website, which included news, contests, and information about some downloadable content – arbitrary web addresses cannot be input. On account of the system’s limitations, it only supports a few HTML elements, like paragraphs and lists. Impressively though, it does support images, albeit in black and white. This system also worked on the Game Boy Advance by virtue of its backwards compatibility with the Game Boy Colour. ## Sega Dreamcast What would be Sega’s last console, the Dreamcast, released in 1998. It didn’t get one browser like its predecessor, the Saturn, but instead received three distinct lineages of browsers. Dream Passport, various versions of the PlanetWeb Browser, and Dreamkey. Dream Passport (ドリームパスポート) version 1.01 was bundled with Dreamcasts sold in Japan on launch. It lacked support for many web standards and common formats, so it was quickly obsoleted by the updated Dream Passport 2. Owners of the first version of Dream Passport could exchange their copy at some retailers for Dream Passport 2, free-of-charge, between the 5th and 31st August, 1999. After that time it had to be purchased online via Sega Direct. Very briefly in 2000 a version of Dream Passport was bundled with the Dreamcast LAN Adapter, titled ‘Dream Passport 2 for LAN’, before being replaced with Broadband Passport (ブロードバンドパスポート), a version bundled with the Dreamcast Broadband Adapter. Later in 2000, Dream Passport 3 released, again with improved support for web standards. The final technically improved version of Dream Passport to release was Dream Passport Premier in 2001. In addition to being usable on the Dreamcast, it can also be used to install versions of Dream Passport on Windows and Macintosh. There were also variants of Dream Passport produced, such as the themed Hello Kitty Dream Passport 2 (ハローキティのドリームパスポート2), Sakura Taisen Dream Passport 3 (サクラ大戦 ドリームパスポート3), and Dream Passport 3: Urban Style. The latter was part of an Internet Starter Kit aimed at non-tech-savvy folk – particularly, women. In addition to the special version of Dream Passport 3, the kit included a translucent keyboard and mouse, a mousepad, some manuals, and a guide: The Internet for Housewives. Also in Japan, Microsoft made an attempt to port the first generation of WebTV to the Dreamcast via the Microsoft WebTV Connection Kit (マイクロソフト ウェブ・ティービー接続キット). It was possible by virtue of the Dreamcast’s Windows CE abstraction layer and had an Internet Explorer-based browser. There were only two versions: the initial release version and Microsoft WebTV Connection Kit: 128bit SSL Compatible Version, which added exactly what the title suggests. In the United States of America, PlanetWeb returned with their PlanetWeb Browser under the name ‘Web Browser’. It first released for the Dreamcast in September 1999. A small version 1.2 update released afterwards, and in 2000, Web Browser 2.0 released with better JavaScript support and support for Macromedia Flash. It also added support for uploading and downloading Dreamcast save games, downloading and playing MP3s, and included a full copy of the puzzle game Sega Swirl. Web Browser 2.62 released in 2001 as a successor to 2.0 and included demos of StarLancer, Speed Devils Online, Typing of the Dead, and 4x4 Evo. It was replaced later the same year by Internet Browser v3.0, which brought support for Macromedia Flash 4, again improved JavaScript support (JavaScript 1.2), and the ability to play Java 1.1.8 applet-based web games with PlanetWeb’s own Java Virtual Machine (JVM). Internet Browser v3.0 open to FrogFind! The interface of PlanetWeb on the Dreamcast is very similar to the interface that was on the Saturn, albeit themed differently. It has the same menu, bookmarks system, address book, and zoom tool. Unfortunately the theming functionality wasn’t carried over. PlanetWeb also hosted a Dreamcast Fansite and web portal. Outside of Japan and the United States (mainly Europe and Australia), rather than Dream Passport or a version of PlanetWeb Browser, Dreamkey was bundled with consoles. Dreamkey was built on NetFront, a bespoke browser developed and provided on license by the Japanese company Access Co Ltd. The first version was 1.0, which was followed by 1.5 to add regional internet settings for the Republic of Ireland. Version 2.0 released in 2001 and updated the browser engine slightly, improved the on-screen keyboard, added support for the Dreamcast Mouse, and for a messaging service called Dreamnote. Dreamnote allowed sending messages, including voice messages via the Dreamcast’s microphone, and had a feature where Dreamnote users could see other Dreamnote users on the same website and communicate with them. In 2002, Dreamkey 3.0 released, removing restrictions surrounding internet service providers which had been imposed by Sega since version 1.0. A final version 3.1 was released exclusively in Spain and Portugal to fix regional issues in 2003. There is a wide variety of miscellany hidden in Dreamkey, including hidden 3D models, images, videos, demos, ‘Sonic the Hedgehog’ listed as a contributor in the credits, and the ability to use the Dreamcast’s light gun controller as a pointer, shooting links to click them. ## WonderSwan Launching in March 1999, the WonderSwan was a handheld game console that released exclusively in Japan. A tiny 16-bit console with a mere 16KB of RAM. In 2000, the MobileWonderGate launched – a collaboration between Bandai and the mobile network NTT DoCoMo. Interface of the MobileWonderGate browser. MobileWonderGate is a physical adapter using a phone connection that provided the WonderSwan with an internet connection and an extra 512KB of RAM. It allowed downloading additional content for some games, email, and an exceptionally limited browser. Its rudimentary engine has support for only a small subset of HTML 3.2. The browser itself has a bookmark system, and support for displaying GIFs, with settings to disable images, change their display, and configure the overall presentation of webpages. To bypass some of the severe limitations of the WonderSwan, web pages were proxied through a service to improve compatibility, not unlike Opera Mini. ## PlayStation 2 The PlayStation 2, which released in 2000, got a fairly substantial web system. The PlayStation Broadband Navigator (PlayStation BB, PSBBN) was available in Japan and, provided the user had a hard drive in their Expansion Bay, a memory card, and a network adapter, allowed users to take their PlayStation online. The PlayStation 2 only had a very rudimentary system interface, and PSBBN brought many more features. For the time, PSBBN was quite an advanced system. A pre-release version was released in early 2002, being replaced with v0.20 later in the year. v0.20 brought the ability for the software to update itself from the internet and manage save games. In v0.30, which released mid-2003, an email program was incorporated, as well as a service to handle monthly billing for some online games. A final minor update was released later in the year with v0.31 to fix an exploit. In addition to various ‘channels’ where game trailers, demos, and teasers were showcased in manners similar to websites, PSBBN had NetFront Browser 3.0. It supported HTML 4.1 and JavaScript. NetFront Browser 3.0 was also distributed for Linux for PlayStation 2. Also for the Japanese market, PlanetWeb produced EGBROWSER, which was released by Ergosoft Co Ltd in April of 2001. It includes Ergosoft’s Japanese/English machine translation and allows playback, though not saving, of MP3 files. It is a continuation of PlanetWeb’s bespoke browser system, functioning much the same as the releases on Sega’s consoles with a slightly tweaked interface. It supports HTML 3.2, CSS 1.0, various audio and image formats, SSL 3.0, Macromedia Flash 3.0, and JavaScript 1.1. It doesn’t support videos, Java applets, or PDFs. Following the release of PSBBN, an improved version titled EGBROWSER BB was released in 2002. It improved support for CSS and achieved compliance with HTML 4.0 while bumping Macromedia Flash to version 4.0. It also made use of the PlayStation Broadband Navigator to store more data, such as emails and cookies. In PAL regions, a Network Access Disc was distributed which had a browser that could access Central Station, the predecessor to PlayStation Network. It didn’t present any browser controls needed to access arbitrary websites, but people ‘hacked’ it to display sites of their choosing by pointing its configuration at an IP address other than Sony’s own. ## Nintendo DS For their 2004 console, the DS, Nintendo partnered with Opera to bring version 8.5 of the Opera browser to the console. Releasing in 2006, the browser was sold with a Memory Expansion Pak required to use the browser, which fit into the console’s Slot-2 and is usually reserved for Game Boy Advance games. It provided 8MB of RAM, increasing the DS’ total memory from 4MB to 12MB. The browser was released twice, once for the original model of the DS, and again for the sleeker 2006 hardware revision, the DS Lite. The only difference between the two being that the DS Lite version had a smaller Memory Expansion Pack that sat flush with the Lite’s smaller chassis. The original Expansion Pak works in the Lite but is the same size as a Game Boy Advance game and thus protrudes. Though limited, the DS’s browser fit a niche for mobile internet access in a world where smartphones were not yet ubiquitous. The DS Browser open to FrogFind! For a tiny browser on a very limited console, it is reasonably fully featured. It has support for JavaScript, images, history, bookmarks, searching, a reasonable degree of settings, zoom options, and display toggles. It doesn’t have support for videos or other complex multimedia, though. Inputs can be performed using the DS’s on-screen keyboard or by writing characters on the touchscreen to be interpreted via handwriting recognition. The browser lacked any inbuilt filtering system, instead advising people to find and configure a proxy. A password can also be configured to be required on launch. The browser manual notes that the browser might run out of memory sometimes and humorously notes that if it does, you should turn your DS off and then on again. Two presentation modes were available. The overview mode showed the complete page on the bottom screen, which could then be selected to view it on the top screen. The fit-to-width mode made the site take up the entire horizontal width of the display so that the user doesn’t need to pan around the page. In a time before responsive web design – which is a term that would only be coined in 2010 – this made websites designed exclusively for desktop use somewhat usable. While possible to use the interface without a stylus and to navigate using only the buttons or a finger, a stylus is the much more precise control method. ### DSi The DSi released in 2008 and had a browser included with its system software in most cases and was available to install for free through the DSi Shop if not. It forewent the need for a Memory Expansion Pak like the base DS thanks to the DSi’s inbuilt 16MB of RAM. The browser was much improved from the DS’, being a stripped-down version of Opera 9.50.2 Introduction of HTML canvas support, particularly, was major, and various sites including DSiPaint, DSiCade, DSiPlaza, and Social Neko, were built specifically for the DSi browser, taking advantage of the newly introduced support for canvas and other web technologies to facilitate more interactive experiences. The browser only supports one font and three font sizes, with content transformed to adhere to the limitation. Reviewers at the time were critical of its lack of support for Adobe Flash, lack of video capability, and its semi-regular errors messages about running out of memory, though they considered it a major improvement from the prior attempt to bring a browser to the DS. It still lacked capability for playing videos. The browser got a single update with version 1.4 in August 2009, which slightly reduced the browser’s size on the system. Despite having increased RAM, the DSi isn’t compatible with the DS browser due to a hard check for the Memory Expansion Pak, which cannot be installed in the DSi due to lacking Slot-2. ## Wii Continuing their partnership with Opera, the Internet Channel was the browser for Nintendo’s 2006 console, the Wii. The browser first saw a release for free in a trial capacity in late 2006 before launching fully in mid-April 2007. Starting in July of 2007, it became paid, costing 500 Wii Points. It remained at this price until the start of September 2009, when it became free once again, and switched from Macromedia Flash Player 7 to Adobe Flash Lite 3.1, based on Flash 8. Starting in October 2009, users who had purchased the Internet Channel during this paid period were offered a free Nintendo Entertainment System game valued at 500 points. The Internet Channel’s start page. On October 10th of 2007, the Internet Channel saw an update, which brought USB keyboard support; interface improvements; the ability to favourite 56 pages, up from 48; functions to copy text from webpages into the search field; and further integrations into the Wii system so that users could send links to users in their Wii Address Book via the Wii Message Board. Interestingly, trying to navigate to `/.` takes you directly to the website Slashdot, a long-standing shortcut in Opera. I’m surprised Nintendo allowed such a thing, which leads me to assume they were unaware. Google released Google Reader Play, a version of Google Reader specifically for use on the Wii, that later expanded for use on other consoles. As a very brief aside, the Wii’s precursor, the GameCube, didn’t have a web browser per se (at least nothing internet-enabled) but did have a browser engine. Various game demo discs were built with HTML using a browser by who else but PlanetWeb. Research into this is detailed in The GameCube’s Lost Internet Browser Discovered. ## PlayStation Portable The PlayStation Portable was released in 2005 and gained a free system-integrated web browser in September of that year with PlayStation Portable System Software 2.00. It used NetFront’s browser engine and got additional updates over time. In October 2005, 2.50 brought Unicode character support and the ability to save form inputs. 2.70 in April 2006 introduced support for Macromedia Flash 6. Trend Micro Web Security and Trend Micro Kids Safety were made available on the PSP in April 2009 to allow for content filtering. The browser was rather fully featured, with support for creating/editing/deleting bookmarks, managing history, changing text sizes and how the page displays, JavaScript, images, using a proxy, cookies, cache management, and up to three tabs. The PSP even had comprehensive support for RSS on a system level. Three view modes are made available by the browser. ‘Normal’ displays the page as served, ‘Just-Fit’ attempts to shrink some elements to fit the small screen without impacting layout too much, and ‘Smart-Fit’ forcefully wraps any content that horizontally overflows so it appears on the next line. The life of the PlayStation Portable’s Internet Browser was cut a tad short due to relying on SSL 3.0, which was quickly fled from by the bulk of websites when a major vulnerability was found in the protocol in late 2014. ## Xbox 360 Despite releasing in 2005, the Xbox 360 didn’t receive a browser until 2012, when it got a modified version of Internet Explorer 9. Initially it was only available to users paying for Xbox Live Gold (something that people were very unhappy about), but this restriction was later relaxed. Microsoft went as far as to publish a full paper about developing for Internet Explorer for Xbox, covering everything from how the input works to design considerations for televisions to browser feature support and testing. Though the browser has support for favouriting sites to return to later, it lacks any support for tabs or any other similar multi-tasking functionality. In the settings, toggles are present to enable requesting mobile versions of webpages, as well as to enable support for Microsoft’s SmartScreen filter to protect against malicious sites. Using the SmartGlass console companion app for Windows, Windows Phone, Android, and iOS allowed navigating and interacting with Internet Explorer on the Xbox 360 via a mobile device. An experience much nicer than trying to use the on-screen keyboard. The Xbox’s browser interface is peculiar due to it not entirely fitting the 360’s Metro Dashboard aesthetic and taking design cues from the flatter version of Metro seen on Windows 8. Being released so late in the console’s life cycle, it was never updated beyond Internet Explorer 9. ## PlayStation 3 The PlayStation 3 released in 2006 with NetFront’s browser running on NetFront’s proprietary engine, before later being replaced entirely with WebKit. It has a wealth of features: disableable JavaScript support, the ability to change the page resolution, a zoom function, multiple display sizes so pages could conform to standard desktop sizes or take up the whole screen, website screenshot functionality, options to copy the address, a bookmark and history system, the ability to save images, and tabbed browsing support via windows which can be slid between with the shoulder buttons. Internet Browser open to r/PS3 on Old Reddit. In November of 2007, version 2.00 was released which introduced Trend Micro Web Security and Kids Safety as options in the browse settings. Version 2.20 from March of 2008 allowed playback of some videos while they download. In July version 2.40 launched, which added an internet search option in the XMB and search as an option in the browse mode menu of the Internet Browser. However, this version was withdrawn later the same day due to instability, and the changes were more widely distributed a few days later in 2.41. In October of 2008 support for Adobe Flash 9 was introduced with version 2.50, and in December this was expanded to allow full-screen display of Flash content with version 2.53. Version 2.70 in April of 2009 brought several features pertaining to the system’s web browser. An internet search function was added to the games menu as a shortcut for performing a Google search on the item’s title; the ability to copy and paste text from websites was added; Internet Security was added as an option; and functions to copy the current page’s address and the address of a link were incorporated into the file menu. An estimate of how long a download will take was also added. In version 3.00 which released at the beginning of September 2009, the ability to take screenshots of web pages in the browser was added, and with version 4.10 in February 2012, the browser got a substantial update in that it moved to WebKit. This brought huge load speed, performance and stability improvements, support for some HTML5 features, and page layout accuracy benefits. In addition to these more notable changes, the Internet Browser also saw occasional performance and stability improvements throughout the console’s life. The PlayStation 3 also had support for connecting to printers and media servers, downloading content, and other advanced functionality not typically seen in game consoles. It is perhaps the closest a game console got to the ’90s dream of a game console serving as a computer on your television. ## PlayStation Vita Sony’s second (and far less successful) swing at the handheld gaming sector came in 2011 with the PS Vita. From launch it had a non-uninstallable web browser app. The browser is WebKit-based and has no support for Adobe Flash. Though it lacked tabs, the Vita browser did have support for up to eight tab-like windows, and links on a page could be opened in new windows at will. Attempting to open more than eight closes the last of the existing windows. Images can be downloaded from websites, and a comprehensive bookmarks system is included, allowing the creation, deletion, editing, and sorting of bookmarks, and even a way to keep them organised by filing them in nested bookmark folders. Some models of the Vita had support for 3G networking, making the browser usable while away from a Wi-Fi connection. Vita Browser application open to Hacker News. Open windows appear on the browser’s LiveArea screen, allowing quick access to them. As on the PlayStation 3, a button is present when viewing games in the system menu to perform a search for the game’s title in the browser. Many system apps also have a help action icon in their LiveArea which opens the application’s user guide in the browser. Via the Vita’s Parental Controls app, the browser can be disabled entirely, or Trend Micro Kids Safety and Web Security could be subscribed to for the browser. Alongside the PlayStation Portable and PlayStation 3 services, the Trend Micro services reached end-of-life in June 2022 and end of support a year later. System software version 1.80 which released in late August of 2012, brought the ability to scroll pages using the Vita’s rear touchpad and added a button to immediately jump to the top of the page. Version 2.00 in November 2012 improved the browser engine, let the browser use more GPU resources, allowed accessing the browser while in-game, and allowed selecting links with a pointer while holding down the shoulder buttons, in addition to via the touchscreen. In April of 2013, with version 2.10, support for displaying videos was added, provided the Vita has a memory card installed. That update also brought support for viewing HTML emails to the email app. The aforementioned video support was later enhanced in August with version 2.60 to support more videos. The next update came in October of 2014 with version 3.30, which allowed closing all open tabs at once and improved HTML and JavaScript support. In 2013 Sony released the short-lived PlayStation TV, a variant of the Vita designed as a home console. This brought the Vita experience, including its web browser, to the television. ## 3DS The Nintendo 3DS launched in February 2011 but didn’t receive its ‘Internet Browser’ until system update 2.0.0-2 in June 2011. Internet Browser uses the WebKit-based Netfront Browser NX v1.0. It is more like the later-released Wii U Internet Channel than the previous DS Browser, with a much more minimal interface that is in keeping with the 3DS’s bubbly, glossy system theme. 3DS Internet Browser’s main menu. The browser didn’t support Flash, nor video playback, and saw minimal updates throughout the system’s life, beyond patching exploits. The stylus can be slid across the lower screen to scroll pages, and unique to the 3DS Internet Browser is the ability to show `.mpo` image files in stereoscopic 3D on the top screen, though this doesn’t work inline. The browser offers a choice between Google and Yahoo! as search engines. To allow sharing images from the console, Nintendo provided the 3DS Image Share Service. It made use of the browser’s ability to download to and upload from the 3DS’s System Memory or SD Card. ### New 3DS The New Nintendo 3DS (a name which time has been rather unkind to) released in 2014 with a variety of hardware changes, though relevant to web browsing are the improved processors (four cores, up from two) and RAM (256MB, up from 128MB). Owing to this improved hardware, it received an improved version of the browser. Most notably, this improved release shipped with video playback support and a newer WebKit version with support for HTML5. It was based on NetFront Browser NX v3.0. Adobe Flash remained unsupported. It came with an entirely new user interface with options to explicitly request the mobile versions of pages and a toggle to enable more aggressive text wrapping. For Japanese models of the New 3DS, a mature content filter was implemented that could be disabled by purchasing a small paid verification DLC with a valid credit card. ## Wii U The Wii U released in 2012, and the launch system software was without a browser. However, the very first system software update, 2.0.0, which released on the same day as the console, immediately introduced the ‘Internet Browser’ application along with other network-connected apps. Initially shipping with NetFront Browser NX v2.1, the version of WebKit provided saw consistent updates throughout the Wii U’s life up until v3.0.4 in 2017. It doesn’t have support for any plugins such as Adobe Flash. The Wii U’s Internet Browser has a lot of the charm you’d expect from Wii-era Nintendo. The interface is displayed on the GamePad while the television displays spotlights over a stage curtain which can be opened and closed from the controller via a button. If the button is held down, the curtains are opened with a drum roll. If the curtain remains closed for a few seconds, a Mii appears in front of it and cycles through a collection of idle animations with various props. When the curtain is open, the page currently viewed on the gamepad takes up the entire television display. The Internet Browser shown on the GamePad, with the television output behind. The bookmark menu is a literal book, and pages of bookmarks can be flipped through. There are sixteen pages with five bookmarks each. The button for the bookmarks page is the user’s Mii holding a book, and as you flip through the pages of your virtual bookmarks book, your Mii can be seen flipping the pages in the bottom left corner of the GamePad. By depressing the Wii U GamePad’s shoulder buttons and tilting the controller back and forth, the webpage can be scrolled vertically. The GamePad provides complete control independent of the television display, allowing for actions such as adding videos to the queue without interrupting playback. The Internet Browser represents one of the rare few cases where the Wii U’s GamePad is genuinely an enhanced input method and not just a tacked-on gimmick. The browser only saw one major update, which came with version 4.0.0 in September of 2013. It introduced skipping and speeding up video playback with the shoulder buttons, saving usernames and passwords, PDF viewing capabilities, and the ability to access the browser while a game is suspended, so users can reference it for guides and use it without losing a save, or use the Wii U Image Share service which also launched with the update and brought the ability to quickly share screenshots to social media (it was discontinued alongside the 3DS version in October of 2022). It also brought an update to the settings. Previously, the settings only provided the ability to choose between Google or Yahoo! for search, manage saved data, and configure a proxy. However, the update added functionality to change the user agent and allow computers on the local network to access the browser’s developer tools. Nintendo even provided rather comprehensive developer documentation for the browser. For someone so inclined, the Wii’s Internet Channel can be run in the Wii U’s Wii Mode, but only if re-downloaded in the virtual Wii environment, as the Internet Channel can’t be transferred from the Wii to the Wii U with Nintendo’s Wii System Transfer tool. ## PlayStation 4 The PlayStation 4 released in 2013 with an inbuilt browser referred to creatively as ‘Internet Browser’. The browser uses WebKit, like Safari. It has multi-tasking functionality so that a user can switch between the browser and a game or application without either program fully closing and having to be reopened. It has web filtering support, bookmark functionality, and support for ‘Frequently Used Pages’ which presents the eight most recently accessed websites, and it can manage up to six windows but lacks support for viewing PDFs and Adobe Flash. The browser does support WebGL and JIT inside the PS4 store and platform content, but it isn’t exposed for external developers. As with many consoles before it, the PlayStation 4’s browser proved a solid vector for exploits to attack so that users could install custom firmware on their console. The PlayStation 4’s browser is not exposed as a dedicated application in the PlayStation VR (PSVR). ## Xbox One The Xbox One released the same year as the PlayStation 4, 2013, with its own inbuilt browser, an updated version of Internet Explorer. Sporting a modified interface, it – like the Xbox 360 version of Internet Explorer – was designed with support for the Xbox Kinect, keeping an interface that could be controlled with physical gesture controls and voice commands. It also brought the ability to use Internet Explorer in a split-screen view, so the user could display the browser alongside games and applications. In 2015 Internet Explorer was removed from the Xbox One with the ‘New Xbox One Experience’ update. In its place, the then new Microsoft Edge. This was the version now known as ‘Microsoft Edge Legacy’, built upon the EdgeHTML browser engine forked from Internet Explorer’s MSHTML (Trident) engine. It was no longer designed for the Kinect, instead having the interface of the desktop Windows 10 version. In 2020, a completely overhauled version of Edge, colloquially referred to as ‘New Edge’ and built upon Google’s Chromium began rolling out. This updated version reached the Xbox One in September 2021. As Edge is on a Windows 11 desktop, Edge is on the Xbox One. The experience is identical, down to the last pixel on the Microsoft Fluent-styled interface. Some specific features, namely browser extensions and downloads, aren’t supported. ## SteamOS Valve’s SteamOS operating system released in 2013 with an inbuilt web browser interface. This browser could also be accessed via Big Picture Mode on the desktop version of Steam. In late 2015 an update to the browser allowed playback of some DRM-protected content in the browser. The Steam client is built on the Chromium Embedded Framework (CEF), so is itself already a modified browser instance. In addition to the web browser made available in Big Picture Mode, a browser window is accessible in the in-game overlay of Steam’s desktop interface. It supports multiple tabs, bookmark management, and offers minimal browser settings, mainly allowing you to change the browser home page. In 2022 Steam released SteamOS 3.0, which came with an updated Big Picture Mode interface. However, since the release of 3.0 and as of publication, this updated interface exposes no general browser interface, in-game or otherwise. Being Linux-based, any browser that supports Linux can be installed trivially through external package management but can’t be installed directly via Steam itself. ## Xbox Series The two Xbox Series consoles, the Xbox Series S and the Xbox Series X, were released in 2020 and initially had Microsoft Edge Legacy – the same as the Xbox One. However, this was replaced with the new Chromium-based Edge at the same time as it was replaced on the Xbox One in September 2021. * * * Both Nintendo and PlayStation have refrained from releasing browser applications for their consoles following the Wii U and PlayStation 4, respectively. Neither the Switch, the Switch 2, nor the PlayStation 5 has a general-purpose, user-facing browser. Browsers are present in the systems for the purpose of facilitating login flows, content display, and web applications, such as Nintendo’s eShop, but they are restricted and don’t allow arbitrary navigation. Despite this, people often configure proxies, follow trails of links, or message themselves URLs to break outside of intended pages. Unfortunately performance using these methods is sub-par, as a result of the browsers not being built for general use. The Nintendo Switch and Switch 2 both use the WebKit-based NetFront NX browser, though it is worth clarifying that the similarity between the name of the browser, NetFront NX, and the Nintendo Switch’s development codename, NX, is pure coincidence. The PlayStation 5 uses Sony’s own wrapper around WebKit. While certainly a welcome addition to consoles, especially if wanting an exploit to enable running arbitrary software, general-purpose web browsers on game consoles are no longer as coveted of a feature as they once were. Time has moved on, and with it has brought cheap web-capable devices and budget television dongles with pre-installed browser apps. Developers can still take away lessons from the era of game console browsers, but a game console likely isn’t a person’s only method of getting online anymore, as it might have been in the ’90s with the Saturn. Instead, it is harder to log off from the web than it is to log onto it in our current era. No longer is the web a place one must venture to, for it is instead with us at all times. ## Footnotes 1. Filtering solutions are common features of game console web browsers, both for protection from malice and to block content deemed explicit. This is reasonable given that consoles are largely aimed at children. However, game consoles were and still remain popular tools for watching pornography. In 2014 Pornhub reported that ‘Millions of visitors come to Pornhub from their game consoles every month.’. Pornhub’s subsequent annual year-in-review posts still indicate that a sizable portion of users access pornography via their game consoles. This popularity can likely be attributed initially to consoles being one of the few network-connected devices in a household and then to being a convenient device connected to a large screen for viewing. Many parents and guardians are also unaware that game consoles are capable of accessing such content online and neglect to restrict them as such, as many annecdotes can attest to. ↩ 2. Despite some claims otherwise, the browser runs on the DSi itself and doesn’t use Opera Mini’s rendering proxy. ↩ *[IRC]: Internet Relay Chat *[DLC]: Downloadable Content *[MSHTML]: Microsoft Hyper Text Markup Language *[DRM]: Digital Rights Management
010
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 10/08/2026
Heydon Pickering has been very busy building out a declarative, web component-based system for making music with HTML, along with a stunning companion site. hyperblam.how
hyperblam.how
Hyperblam Docs Home
Documentation for HyperBlam. Make HTML make music.
113
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 07/08/2026
An interesting look behind the curtain that will make you smile. www.gamefile.news/p/panic-mail-arco…
gamefile.news
The amazing mail sent to a video game publisher
An old Activision idea from the 1980s has led to some incredible things in the 2020s for Panic, the publisher of Despelote, Arco and Time Flies: “The range of things we received was wild."
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 07/08/2026
The Index: Issue #193 It’s Friday, so let’s close out the week with some Good Links™ in The Index #193, sponsored by Retcon piccalil.li/the-index/193
021
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 06/08/2026
Working with ::highlight() using progressive enhancement piccalil.li/blog/working-with-highl…
piccalil.li
Working with ::highlight() using progressive enhancement
Using a baseline of elements, Sunkanmi Fafowora helps you to understand how the new highlight API works with some progressive enhancement for good measure.
111
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 05/08/2026
Just a thoroughly delightful read, as per usual from Jim. blog.jim-nielsen.com/2026/good-at-t…
blog.jim-nielsen.com
Being “Good” at Things
Golf content on social media is my online junk food and the other day I came across a video interviewing professional golfers that asks: “What does an amateur golfer have to shoot to be considered good?” It’s a leading question because the phrasing implicitly frames a number as the answer for a qualitative measurement, but I digress. All the pros give their answers. Some say you gotta shoot a number in 90’s. Others say the 80’s. Some even say the 70’s. Then along comes Collin Morikawa: > I don’t think there’s a number, but I think you have to be able to finish out every hole without, like, picking up a two-footer. Love it! I don’t want to go too deep on a social media golf interview clip, but… I love how he breaks out of the question’s implicit framing and really strikes at the heart of the qualitative question: “What does it mean to be good at golf?” Being “good”, in his eyes, is not shooting a specific number. Numbers are standardized proxies for measurement across a wide variety of players, skill levels, and — to be quite frank — degrees of honesty. Anyone who has played golf knows that scores can be easily manipulated. On a casual outing amongst friends, my “82” may be very different than the “82” of the players in front of me — or even the players in my own group. It all depends on how you play the game. So saying “if you can shoot number ___” is a very lossy picture of what it means to be “good” at golf — at least for amateurs. That’s why I love Morikawa’s answer: if you finish every hole and don’t get a double bogey, you’re “good” at golf. Because guess what? Finishing is the hard part. The consistency. Showing up to every hole, finishing out based on the actual rules of the game, not taking mulligans, not picking up a two-footer and saying “That’s good.” (Or even missing a two-footer and re-putting and giving yourself the make.) Relieving yourself of the exacting burden of the reality of the game is the easy way to play, but it doesn’t make you a better golfer. I think that’s true of so many things we do as humans: programming, design, writing, etc. If you want to be “good” at what you do, do the hard, little things that others gloss over. Do them consistently and well, with discipline and perseverance. If you do, then I’d say you’re “good” at what you do because “good” isn’t a number. It’s quality. A disposition. A way of being.
000
Piccalilli @piccalilli.front-end.social.ap.brid.gy · 04/08/2026
In this free lesson from JavaScript for Everyone, @Wilto teaches us how to use promises: objects that represent the result of asynchronous operations. piccalilli.link/js4e-free-lesson-qu…
001