Latest Posts (20 found)
David Bushell Yesterday

Big Design, Bold Ideas

I’ve only gone and done it again! I redesigned my website. This is the eleventh major version. I dare say it’s my best attempt yet. There are similarities to what came before and plenty of fresh CSS paint to modernise the style. You can visit my time machine to see the ten previous designs that have graced my homepage. Almost two decades of work. What a journey! I’ve been comfortable and coasting for years. This year feels different. I’ve made a career building for the open web. That is now under attack. Both my career, and the web. A rising sea of slop is drowning out all common sense. I’m seeing peers struggle to find work, others succumb to the chatbot psychosis. There is no good reason for such drastic change. Yet change is being forced by the AI industrial complex on its relentless path of destruction. I’m not shy about my stance on AI . No thanks! My new homepage doubles down. I won’t be forced to use AI but I can’t ignore it. Can’t ignore the harm. Also I just felt like a new look was due. Last time I mocked up a concept in Adobe XD . Adobe in now unfashionable and Figma, although swank, has that Silicon Valley stench . Penpot is where the cool kids paint pretty pictures of websites. I’m somewhat of an artist myself so I gave Penpot a go. My current brand began in 2016 and evolved in 2018 . I loved the old design but the rigid layout didn’t afford much room to play with content. I spent a day pushing pixels and was quite chuffed with the results. I designed my bandit game in Pentpot too (below). That gave me the confidence to move into real code. I’m continuing with Atkinson Hyperlegible Next for body copy. I now license Ahkio for headings. I used Komika Title before but the all-caps was unwieldy. I’m too lazy to dig through backups to find my logotype source. If you know what font “David” is please tell me! I worked with Axia Create on brand strategy. On that front, we’ll have more exciting news to share later in the year! For now what I realised is that my audience here is technical. The days of small business owners seeking me are long gone. That market is served by Squarespace or Wix. It’s senior tech leads who are entrusted to find and recruit me, and peers within the industry who recommend me. This understanding gave me focus. To illustrate why AI is lame I made an interactive mini-game! The slot machine metaphor should be self-explanatory. I figured a bit of comedy would drive home my AI policy . In the current economy if you don’t have a sparkle emoji is it even a website? The game is built with HTML canvas, web components, and synchronised events I over-complicated to ensure a unique set of prizes. The secret to high performance motion blur is to cheat with pre-rendered PNGs. In hindsight I could have cheated more with a video. I commissioned Declan Chidlow to create a bespoke icon set. Declan delivered! The icons look so much better than the random assortment of placeholders I found. I’m glad I got a proper job done. I have neither the time nor skill for icons. Declan read my mind because I received a 88×31 web badge bonus gift. I had mocked up a few badges myself in Penpot. Scroll down to see them in the footer. Declan’s badge is first and my attempts follow. I haven’t quite nailed the pixel look yet. My new menu is built using with invoker commands and view transitions for a JavaScript-free experience. Modern web standards are so cool when the work together! I do have a tiny JS event listener to polyfill old browsers. The pixellated footer gradient is done with a WebGL shader. I had big plans but after several hours and too many Stack Overflow tabs, I moved on to more important things. This may turn into something later but I doubt I’ll progress trying to learn WebGL. Past features like my Wasm static search and speech synthesis remain on the relevant blog pages. I suspect I’ll be finding random one-off features I forgot to restyle. My homepage ends with another strong message. The internet is dominated by US-based big tech. Before backing powers across the Atlantic, consider UK and EU alternatives. The web begins at home. I remain open to working with clients and collaborators worldwide. I use some ‘big tech’ but I’m making an effort to push for European alternatives. US-based tech does not automatically mean “bad” but the absolute worst is certainly thriving there! Yeah I’m English, far from the smartest kind of European, but I try my best. I’ve been fortunate to find work despite the AI threat. I’m optimistic and I refuse to back down from calling out slop for what it is! I strongly believe others still care about a job well done. I very much doubt the touted “10x productivity” is resulting in 10x profits. The way I see it, I’m cheaper, better, and more ethical than subsidised slop. Let me know on the socials if you love or hate my new design :) P.S. I published this Sunday because Heisenbugs only appear in production. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views
David Bushell 1 weeks ago

Mozilla Slopaganda

Mozilla published a new State of Mozilla . It’s absolute slopaganda . A mess of trippy visuals and corpo-speak that’s been through the slop wringer too many times. I read it so you don’t have to. ⚠️ Warning: the State of Mozilla website has flashing graphics and janky animations. The website opens with a faux terminal console that logs some nonsense that’s too fast to read. It includes a weird line about “synth-mushroom pop”. This is not the only bizarre reference to magic mushrooms as we’ll see later. What other connection am I missing here? If you’re lucky, next you’ll be treated to a fake CAPTCHA including words “HU MAN”, “INT ERNET”, and “FU TUR E”. The leading headline is: Doing for AI what we did for the web Which I take to mean, lighting a fire under Microsoft and then fading into obscurity. They directly call out Microsoft later. Back then Mozilla had a competitive web product: Firefox. Mozilla has no AI product today to do anthing. Mozilla’s opening sales pitch — which is certified slop — includes this bullet point: We Choose a Different Economic Model: A ‘double bottom line’ — advancing our mission and shaping markets — continues to guide everything we do. If I may direct you to Mozilla’s financial report PDF: Approximately 86% and 85% of Mozilla’s revenues from customers with contracts were derived from one customer for the years ended December 31, 2024 and 2023, respectively. 2024 Audited Financial Statement (page 19) That one customer is of course: Google. I wonder why Mozilla are painting Microsoft as the enemy? Mozilla’s idea of a double bottom line is explained further on the “LEDGER” page † . Although extracting meaning from the words is beyond me. † I can’t link to anything because of the stupid splash screen and CAPTCHAs. The stakes section is wild. We’re asked to choose one of two futures. Future A is choosing Microsoft. This is represented by hot people making out and a creepy robot driver. Twenty five years ago, when Microsoft controlled 95% of browsers, they defined how people accessed information, who could build what, and on what terms. Mozilla did topple Microsoft’s Internet Explorer reign. Then both lost the browser war to Google’s Chrome. But no mention of Google; can’t bite the hand that feeds you. Future B is choosing Mozilla. And more shrooms, apparently. Imagine it’s 2030. You wake up and your digital world feels different — familiar, but freer. This future is AI fan fiction because Mozilla doesn’t actually have any AI products. So which future do you choose, dogging — don’t google it, or shrooms? Seriously, what is with the mushroom references? Is this part of the edgy “fellow kids” rebranding? The page is also adorned with a marquee repeating: “DO NOT ACCEPT DEFAULT SETTINGS”. This must be a subtle reference to Firefox’s on-by-default telemetry, “privacy-preserving” tracking, Google search, and new AI integration? This section is slop. If the future of AI and the web are still up for grabs, the tools we build - our products, programs and investments - are our most powerful levers in shaping how things work out. So surely Mozilla has an AI product to showcase now, right? Wrong. They have Firefox and Thunderbird. It’s nice they remembered about Thunderbird though that wasn’t a given. The rest of the page is vague vacuous promises about AI investment. Who is this written for, the ever expanding board and c-suite? Mozilla was born to challenge a tech monopoly […] — just not papa Google’s — […] and we succeeded not by becoming a significant player in the browser market […] — again leaning on history. Firefox has not been “significant” in years. Mozilla leadership has watched Firefox market share plummet and been helpless. Even if I was an AI lover, Mozilla has nothing to compete in the AI space. They just say things. With mushrooms. We’re focusing our ~$1.4B in reserves Mozilla claim $1.4 billion in reserves (and no debt). They’re funded by over half a billy anually from Google. 👏 Stop 👏 donating 👏 to 👏 Mozilla 👏 Mozilla is the same Big Tech they pretend to rebel against. Donate your money to a worthy open source independent project before it’s drowned by slop. State of Mozilla ends by covering the same empty AI-infused promises. Mozilla talk about the past because that’s all they have. Mozilla fantasise about the future because they have nothing in the present. My favourite part: Also, launch “AI controls” into Firefox, giving people a clear way to turn AI off entirely - current and future AI features. One of the few clear deliverable goals is an AI “kill switch”. Mozilla aren’t exactly sure what their AI future will be but at least you can say no . That’s something! As fun as it is to rib on Mozilla, the web needs Firefox. I feel for the Firefox developers who actually care. State of Mozilla will inspire no one. The sloppy prose are borderline unreadable. The presentation is designed to stop you reading. THE FUTURE IS EXPERIMENTAL SYNTH-MUSHROOM POP The future is Microsoft. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views
David Bushell 2 weeks ago

AI Policy and The Inevitable

I’ve made minor updates to my AI Policy but you probably don’t care because you’re tired of reading criticism. You’ve dismissed all that because AI is inevitable. If you do care, and you should, you are not taking crazy pills! Billions pumped into the relentless marketing machine make for a very effective counter to one’s sanity. This post is primarily written towards web and software developers. All em-dashes were written by human. The reality is you just don’t care about the harm done by the AI industrial complex. You only care about the perceived harm to your ego and reputation. So you compartmentalise because pulling the one-armed code bandit is a rush. I’m not an “AI hater” despite calling myself that once. I don’t affiliate myself with any anti-AI movement (if those exist). I’m just looking at reality and seeing two things. None of this stuff works half as good as promised. Seems to me the hallucinations have spread from machine to human. Either that or I just have higher standards. It’s easy to be confused until you notice a high percentage of proponents are in on selling it. What bothers me most though is the way it’s made and sold. That’s the brunt of my AI Policy . But you don’t care, so moving on. I have no desire whatsoever to make a career babysitting a chat box — excuse me, Orchestration Engineering — regardless of how well it works. Sounds like mind-numbing drudgery by all accounts I’ve read that claim it’s their new nine-to-five. Last time I said no thanks I was mocked by one guy on Hacker News — well played sir — the implication being that I was entitled. That I should suck it up and accept change. Must I? In this timeline, wouldn’t further advancements in AI only increase the menialness of my labour? I’m sure that’ll pay well. Or am I supposed to be selling the AI too — that could be my misunderstanding here. What does the future hold for all of us? Spurious claims of “90% of my code is written by AI” and “AI has made me 10x more productive” are only ever backed up by vibes. Question: what’s your methodology, what metrics are you measuring? Do you have any comparable numbers prior to AI? Are we simply counting green squares on the GitHub contribution chart? Let’s put aside doubts around current quality and results. What about tomorrow? There’s no guarantee AI will get better. Training costs are exponential. The world’s data has been vacuumed and laundered. We’re seeing new AI products look suspiciously like old models wrapped in a trench coat. Stagnation is a real possibility. AI companies are teetering on the edge of a fiscal event horizon; and that’s the optimistic view. Nothing is ever said about the financial barrier to entry. The $200 per month heavily subsidised subscription excludes all but the privileged. I can already hear replies of “It’ll pay for itself with 10x productivity” — show me your 10x profits — “Costs will come down” — they’re going up. Let’s be honest this is white tech for the one percent. The only inevitability I see if that you’ll continue to ignore very real criticism because the train is leaving; buy a first class ticket or get left behind. What about those adversely affected? Sorry, I can’t hear you! Choo Choooo! Next stop: Gas Town . As things stand clients still can’t pay me to prompt. That’s all covered by my AI Policy . I moved the “Morals and Ethics” category first and extended it with recent events. I added “Economy” alongside “Employment and Education” . A few more additions were added elsewhere. My policy is not intending to be an academic essay. Some statements may need better sources. If you genuinely think I’m misinformed on certain topics I’m tentatively open to feedback. Please don’t @ me about energy usage, linking napkin math that ignores half of it. Yes my rhetoric is colourful at times. I’m not obliged to be civil when force-fed by the billion dollar machine that won’t take “no” for an answer — that wasn’t about one email , by the way. Taking a neutral and friendly stance on AI is not the middle ground when the scales are tipped by economic powers trying to destroy my career. AI criticism is not a personal attack. That is unless AI has replaced your personality, as well as your code. To my fellow level-headed developers, stay strong! Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views
David Bushell 2 weeks ago

Hmmarkdown 2

Everyone has an opinion on markdown but why stop there? Write your own parser, make those opinions reality! That’s what I did with Hmmarkdown — my HTML-aware markdown library. It has built my website content for the past year. Turns out parsing markdown (with HTML) isn’t easy. My original approach evolved into a game of whac-a-mole to quash edge case bugs. Last week I began a new parsing experiment I’d been mulling over. The idea proved workable and I finished the job. Hmmarkdown 2 was born! The new codebase is still rough around the edges but already an upgrade. I used my original test suite to ensure the same output. My primary goal was a more maintainable, extendable, and faster library, which it should be soon. Markdown is best in it’s simplest form . Complex extensions to the syntax make no sense. If HTML is the target and easier to markup, just write HTML! Existing markdown libraries allow HTML but they skip past it. The purpose of Hmmarkdown is to allow me to write primarily markdown but interweave HTML where it makes sense. Along with my original example , here’s a common pattern I use: The mix of HTML and markdown above is transformed into the HTML below. In practice I mix little markup but it’s extremely useful to have the ability. Was this worth the investment? Probably not, but I’m in too deep! My old parser separated lines by then grouped lines by block: paragraph, blockquote, heading, list, etc. Those blocks were then parsed as HTML (crudely). Text nodes were parsed for inline markdown: links, bold, italic, etc. A subset of block-level HTML elements were passed back through the parser. Regular expressions did the heavy lifting. That was the old architecture. It worked but it got messy. The new parser begins with a more traditional tokenizer. The tokenizer iterates the input character by character to generate an array of tokens, namely: † Wait a minute “+” is not markdown! I’ll explain later… Every token is a single ASCII character except for Tag and Text . Tag tokens are HTML tags, like , , or . Text tokens are a unicode string of everything else. From the tokens, I generate a basic DOM-like tree with a “root” node and child tokens. ‡ I ignore carriage returns (macOS user), they’re probably dealt with in Text nodes and eventually trimmed? Using the HTML + markdown input example below: The initial token tree state could be visualised like this: With this tree I recursively parse the open tag nodes where the tag name is in an allowed set. This lets me ignore hard-coded HTML tags like , , and where I never want to parse or modify. Using the node for example, I iterate the children to generate a new array of children . The first two tokens and are appended to the new array. Then an token is found so is called. It will return a node (or nothing, for false positives). If that fails will be tried. If nothing matches the and tokens are appended without change. In this example from the original input matches bold formatting. The tree state now looks that this: The next step wraps text and inline tags with HTML paragraphs. This is probably the ropiest area of my code but it works (mostly). tokens play a key role and they’re removed at this stage. Excess whitespace is also trimmed. Next I merge adjacent text tokens before applying SmartyPants replacement, and finally HTML entities are escaped. In this example because the token did not match markdown image syntax it is merged as text. The final HTML output is a simple recursive function over tree nodes to generate a string. I’ve added extra formatting for readability below. HTML attributes are never parsed they just come along for the ride. And that is how Hmmarkdown 2 works! Or at least should work . We’ll see if any formatting bugs appear on my website. The new tokenizer approach means I can largely avoid regex. The supported markdown syntax is still punishingly strict and opinionated. The code repo is public but I have plenty to tidy up and optimise. There is no validation nor error reporting. I wouldn’t advise using it unless you’re me! So about that token. Whereas unordered lists start with an token, ordered lists would be written as followed by . In fact, the numeric order and value doesn’t matter to markdown. Both examples should output identical items marked 1 and 2 sequentially. (Some libraries do add a attribute. That’s a thing I don’t need.) Anyway, this is a pain to parse. I would need eleven additional tokens for digits to and . That adds overhead and a lot of false positives in the look-ahead matching. To avoid this entirely I do a cheeky bit of regex pre-processing. Unordered list lines are replaced with before I tokenize. Now I can use the exact same logic I use to parse ordered lists. Hmmarkdown has never supported nested lists because in over a decade of blogging I’ve never nested a list. That saves me another headache. Tune in next year when I throw this all away and announce Hmmarkdown 3! Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. Exclamation Parentheses Square brackets Angle brackets

0 views
David Bushell 2 weeks ago

Proton Spam and the AI Consent Problem

On Jan 14th Proton sent out an email newsletter with the subject line: Introducing Projects - Try Lumo’s powerful new feature now Lumo is Proton’s “AI” offering. There is a problem with this email. And I’m not talking about the question of how exactly AI aligns with Proton’s core values of privacy and security . The problem is I had already explicitly opted out of Lumo emails. That toggle for “Lumo product updates” is unchecked. Lumo is the only topic I’m not subscribed to. Proton has over a dozen newsletters, including some crypto nonsense. I opt-in to everything but Lumo, I gave an undeniable no to Lumo emails. So the email I received from Proton is spam , right? My understanding is that spam is a violation of GDPR and UK data protection laws. Regardless, Proton’s email is a clear abuse of their own service towards a paying business customer. Before I grab my pitchfork I emailed Proton support. Despite the subject line and contents, and despite the “From Lumo” name and address, maybe this was an honest mistake? Proton’s first reply explained how to opt-out. Hello David, Thank you for contacting us. You can unsubscribe from the newsletters if you do the following: - Log in to your account at https://account.protonvpn.com/login - Navigate to the Account category - Disable the check-marks under “Email subscriptions” - If you need additional assistance, let me know. [screenshot of the same opt-out toggle] -Have a nice day. John Support directs me to the exact same “Lumo product updates” toggle I had already unchecked. I replied explaining that I had already opted out. Support replies saying they’re “checking this with the team” then later replies again asking for screenshots. Can you make sure to send me a screenshot of this newsletter option disabled, as well as the date when the last message was sent to you regarding the Lumo offer? You can send me a screenshot of the whole message, including the date. Is it perhaps 14 January 2026 that you received the message? I found that last line curious, are they dealing with other unhappy customers? Maybe I’m reading too much into it. I sent the screenshots and signed off with “Don’t try to pretend this fits into another newsletter category.” After more “checking this with the team” I got a response today. In this case, the mentioned newsletter is for promoting Lumo Business Suit to Business-related plans. Hence, why you received it, as Product Updates and Email Subscription are two different things. In the subscription section, you will see the “Email Subscription” category, where you can disable the newsletter in order to avoid getting it in the future. If I understand correctly, Proton are claiming this email is the “Proton for Business newsletter” . Not the “Lumo product updates” newsletter. I don’t know about you, but I think that’s baloney. Proton Support had five full business days to come up with a better excuse. Please tell me, how can I have been any more explicit about opting out of Lumo emails, only to receive “Try Lumo” “From Lumo”, and be told that is not actually a Lumo email? Has anyone else noticed that the AI industry can’t take “no” for an answer? AI is being force-fed into every corner of tech. It’s unfathomable to them that some of us aren’t interested. The entire AI industry is built upon a common principle of non-consent. They laugh in the face of IP and copyright law. AI bots DDoS websites and lie about user-agents . Can it get worse than the sickening actions of Grok? I dread to think. As Proton has demonstrated above, and Mozilla/Firefox recently too, the AI industry simply will not accept “no” as an answer. Some examples like spam are more trivial than others, but the growing trend is vile and disturbing. I do not want your AI. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views
David Bushell 3 months ago

Better Alt Text

It’s been a rare week where I was able to (mostly) ignore client comms and do whatever I wanted! That means perusing my “todo” list, scoffing at past me for believing I’d ever do half of it, and plucking out a gem. One of those gems was a link to “Developing an alt text button for images on [James’ Coffee Blog]” . I like this feature. I want it on my blog! My blog wraps images and videos in a element with an optional caption. Reduced markup example below. How to add visible alt text? I decided to use declarative popover . I used popover for my glossary web component but that implementation required JavaScript. This new feature can be done script-free! Below is an example of the end result. Click the “ALT” button to reveal the text popover (unless you’re in RSS land, in which case visit the example , and if you’re not in Chrome, see below). To implement this I appended an extra and element with the declarative popover attributes after the image. I generate unique popover and anchor names in my build script. I can’t define them as inline custom properties because of my locked down content security policy . Instead I use the attribute function in CSS. Anchor positioning allows me to place these elements over the image. I could have used absolute positioning inside the if not for the caption extending the parent block. Sadly using means only one thing… My visible alt text feature is Chrome-only! I’ll pray for Interop 2026 salvation and call it progressive enhancement for now. To position the popover I first tried but that sits the popover around/outside the image. Instead I need to sit inside/above the image. The allows that. The button is positioned in a similar way. Aside from being Chrome-only I think this is a cool feature. Last time I tried to use anchor positioning I almost cried in frustration… so this was a success! It will force me to write better alt text. How do I write alt text good? Advice is welcome. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

1 views
David Bushell 3 months ago

Croissant Favicons and Tauri Troubles

Croissant v0.4 is out! I fixed a few minor bugs and added favicons. I’ve had a surprising amount of feedback. I wasn’t expecting anyone to care about an app I designed for myself. Thanks to all who managed to navigate my contact form . Croissant’s design philosophy is vague because I’m just making it up as I go along. Essentially it’s an experiment in keeping it simple. Not “MVP” because MVP is nonsense — and not “minimalism” because that does not mean good. Croissant is just basic and unbloated. The three most requested features have been: Folders is never going to happen, sorry! That would literally double the codebase for a feature I’d never use myself but have to maintain. Bookmarks is possible. Croissant is just a reader not an organisation tool but I see the value of “read later”. Not sure how this will work yet. I do not want to build a bookmark manager. Favicons has happened! When I declared “no icons” I was talking about the craze of UI icons everywhere . Icons without labels! Meaningless béziers from self-important designers that leave the rest of us saying “WTF does this button do?” Favicons actually serve a purpose and improve the design. Favicons are a simple feature but were not easy to implement. Tauri is causing me headaches. I’m starting to rethink if I should continue the native app wrapper or focus solely on the PWA . The web platform always wins. How many cautionary tales must I read before I accept the truth! Why am I wasting time debugging Tauri and Apple’s webview for issues that don’t even exist in Safari? Wasted time and energy. I’m accruing non-transferable knowledge in my (very) limited brain capacity. Croissant v0.4 might be the last native macOS version. It only exists because the PWA requires a server proxy (CORS) that has privacy concerns . Maybe I can add a “bring your own proxy” feature? Podcast feeds include an image tag but basic RSS does not. There are standardised ways to provide an image/icon with and web manifests . These both require parsing the website’s HTML to discover. I’m relying on “known” root locations; namely: These locations aren’t required for either icon but browsers check there by default so it’s a good place to guess. For the 200-ish blogs I subscribe to I get a ~65% success rate. Not ideal but good enough for now. I really want to avoid HTML spelunking but I may have to. Expect an improvement in the next update. For now a croissant emoji is used for missing icons. I’m using the Offscreen Canvas API to generate a standard image size to cache locally. Favicons are currently cached for a week before refreshing. First I tried using a service worker to cache. Tauri was not happy. Second I tried using OPFS with the File System API. Tauri was not happy. I dumped Base64 into local storage and Tauri was OK with that but I wasn’t because that’s horrible. Finally I went back to IndexedDB which is perfectly happy storing binary blobs. So you can see why Tauri is on thin ice! I don’t want tech choices dictating what parts of the web platform I can use without jumping through non-standard hurdles. That’s all for now. I hope to have another update this year! Visit CroissantRSS.com to download or install Croissant as a progressive web app. Oh yeah… and I kinda messed up deployment of the PWA service worker so you may need to backup, remove, and reinstall… sorry! Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views
David Bushell 4 months ago

RSS Club #004: Ghost of Autumn

The summer solstice has long past which means it’s Christmas soon if the local supermarkets are to be believed. I refuse to eat a mince pie before November at the earliest. Daylight savings time will come to an end (impossible to know exactly when). For the UK that means dark mornings, dark evenings, and grey skies around noon. It’s time to hibernate! I can recommend a bit of entertainment to wile away the winter. Imperium by Robert Harris is the first book of the Cicero trilogy. Although fiction, this novel is based upon real events at the end of the Roman Republic. The series follows the political career of Marcus Tullius Cicero . A fascinating era of human history. Move over Wordle, Connections is the new daily brain teaser. New to me anyway. If puzzle numbers are to go by it’s been around for years. Presumably inspired by the Connecting Wall you must make 4 groups from 16 words. Green is supposed to be the most obvious but I keep finding the blue group first. I’ve just finished playing Ghost of Yōtei the spiritual sequel to Ghost of Tsushima . If I rated Tsushima 5 stars I’d give Yōtei 4 stars. I achieved the platinum trophy for 100% completion in both games. The game is beautifully designed and fun to explore. Fair warning: moderate spoilers ahead. Yōtei is a great game but the story doesn’t hit the same emotional level as Tsushima. The ending fell flat for me and overstayed its welcome. The antagonists progressively lost their mystique until they became boring. Their repeated escapes were eye-rolling. It made Atsu look dumb and the Matsumae clan comically inept. Plot points are forced and pacing is criminally ruined by bad open world design. They front-load the starting area with the most side activities and then almost immediately move the main quest elsewhere. Ignore content, or ignore story? You can fast travel back and forth of course but it ruins the immersion. I played 20 hours and only saw two cutscenes. Most side characters are relegated to vendor NPC level which was disappointing. I’m left confused as to what purpose the wolf served? Despite these issues it was an experience worthy of the hours invested. As we know the true game is finding the tengai hat and fundoshi armour and terrifying the local samurai. I’m afraid I did not dare witness the final cutscene in this attire. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views
David Bushell 4 months ago

What is a Linux?

Do you build websites like me? Maybe you’re an Apple user, by fandom, or the fact that macOS is not Windows. You’ve probably heard about this Linux thing. But what is it? In this post I try to explain what is a Linux and how Linux does what it be. ⚠️ This will be a blog post where the minutest of details is well actually-ied by orange site dwelling vultures. I’ll do my best to remain factual. At a high level Linux is best described as an OS (operating system) like Windows or macOS. Where Linux differs is that its components are all open source. Open source refers to the source code. Linux code is freely available. “Free” can mean gratis ; without payment. But open source licenses like GPL and MIT explicitly allow the sale of software. “Free” can also mean libre ; unrestricted, allowing users to modify and redistribute the code. Linux software is typically both free and free. You may see acronyms like OSS (open source software), and FOSS/FLOSS (free/libre and open source software), emphasising a more liberal ideology. Some believe that non-free JavaScript is nothing short of malware forced upon users. Think about the sins you’ve committed with JavaScript and ask yourself: are they wrong? Linux and OSS is a wonderful can of worms with polarising opinions. We can break down Linux usage into three categories. Linux can be “headless” meaning there is no desktop GUI. Headless systems are operated via the command line and keyboard (except for the occasional web control panel). This is the backbone of the Internet. The vast majority of web servers are headless Linux. “Desktop Linux” refers to the less nerdy experience of using a GUI with a mouse. Linux has never done well in this category. Depending on whom you ask, Windows (with a capital W) dominates. Steam survey puts Windows at 95% for gaming. Other sources are more favourable towards macOS reporting upwards of 15%. Linux is niche for desktop. Some will claim success for Linux in the guise of Android OS . Although technically based on Linux much of Android and Google’s success is antithetical to FOSS principles. SteamOS from Valve is a gaming Linux distro making moves in this category. Embedded systems are things like factory robots, orbital satellites, smart fridges, fast food kiosks, etc. There’s a good chance these devices run Linux. If it’s Windows you’ll know by the blue screen and horrendous input latency. That was four categories, sorry. Linux is not one operating system but many serving different requirements. If Bill Gates created Windows and Steve Jobs oversaw macOS, who’s the Linux mastermind? Linux is named after Linus Torvalds who is still the lead developer of the Linux kernel. But there is no Microsoft or Apple of Linux. Due to its open source nature, Linux is more like a collection of interchangeable pieces working together. There is no default Linux install. You must choose a distribution like a starter Pokémon. Linux distros differ in their choice of core pieces like: The Linux kernel includes the low-level services common to all Linux systems. The kernel also has drivers for hardware and file systems. Each distro typically compiles its own kernel which means hardware support can vary out of the box. It’s possible to recompile the kernel to include modules specific to your needs. Linux distros can exist for niche and specialised use cases. OpenWrt is a distro for network devices like wireless routers. DietPi is a lightweight choice for single board computers (a favourite of mine). Distros exist for seasoned nerds. Gentoo Linux is compiled from source with highly specific optimisation flags. NixOS provides an immutable base with declarative builds. If no distro meets your requirements, why not build Linux from scratch? You can find all sorts of weird and wonderful distros on Distro Watch . If you consult the distro timeline on Wikipedia you can see an extensive hierarchy. It’s overwhelming! Know that most are hobbyist projects not maintained for long. They’re nothing more than pre-installed software, opinionated settings, and a wallpaper. Distros like Debian and Arch Linux offer a more generalised OS. They provide the base for most commonly used distros. RHEL (Red Hat Enterprise Linux) also exists for the corporate world. From Debian comes Ubuntu and Raspberry Pi OS . Ubuntu desktop is by far the most popular distro for day-to-day use. Ubuntu makes significant changes to Debian and provides its own downstream package repository. Where should you start? You’ll get some crazy bad answers. Just try Ubuntu. It has the “network effect” and you’re more likely to find support online. This advice is likely to elicit the most comments! Desktop Linux can look wildly different across distros. There is no universal desktop GUI like you’d find on Windows or macOS. KDE offers the classic Windows-like experience. Gnome is more akin to macOS. XFCE is a lightweight option. Hyprland strips back the GUI using a tiled window presentation. There is a shortage of design and accessibility expertise within FOSS. Linux can be ugly and inaccessible at times. If you like design perfection Linux can make your eye twitch. On the plus side, you’re not stuck with a vendor-locked experience. Desktop environments provide hundreds of dials to customise their appearance. Want a start menu? You can add one! Hate the dock? Remove it! Some parts of Linux are even styled and scripted with CSS and JavaScript. Distros come with a package manager (think NPM). This is the main source of system updates and software. On Debian-based systems you’ll find commands. Arch-based systems use . Distros may include a custom GUI and auto-update feature for those scared of the command line. Linux has multiple upstream package repositories. If you run on Debian you’ll get an old version (politely referred to as: “stable”). In comparison, running on Arch gives you the cutting edge, likely compiled from Github last night. Remember that almost everything around Linux is open source. You’re free to compile and install software from anywhere. Software maintainers often provide an install script. See Node.js for example: To download and immediately execute a script from the Internet is insanely insecure! You’re suppose to vet the code first but nobody does. Every Linux system is different so software support can be tricky. Containerised software has become a popular distribution method to solve compatibility issues. Flatpak is the leading choice and Flathub is a bountiful app store. AppImage is a similar project. Ubuntu is trying to make Snaps happen in this space. Hopefully I’ve explained what Linux is! But is it for you? Linux can be a great OS if you’re a web developer writing code. All the familar tools should be available. If you like to tinker, Linux will be a never-ending source of weekend projects . Linux has unrivalled backwards compatibility and avoids the comparable bloat of Windows and macOS. Older hardware can feel surprisingly fresh under Linux. If you require access to proprietary design software like the Adobe suite you’re out of luck. This is why I’m stuck on macOS for my day job. Clients love to deliver vendor lock-in with their designs. There are often 3rd-party workarounds for apps like Figma. Unofficial apps are always buggy and prone to breakage. Both the best and worse parts about Linux is too much choice. Everything can be modified, replaced, improved, and broken. I’ll end before this turns into a book. Let me know if you found this informative! Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. The Linux kernel A package manager A boot and init system Network utilities Desktop experience

1 views
David Bushell 4 months ago

Email: The Final Form

I’m taking one last stab at my contact form before it’s binned forever. Back in May I came up with a “progressive dehancement” technique to validate form submissions. For non-JavaScript ‘users’ I took the drastic measure of blocking all @gmail and @outlook addresses. Along with problem phrases like “SEO” and entire unicode ranges. Despite my best effort to maintain a JavaScript-free form I failed. Bots have ruined the web! I’ve done the unthinkable and added a CAPTCHA thing. I chose the invisible Cloudflare Turnstile . It seems to be accessible and the least intrusive. I’m using to add the three worst words in web development. At least it’s not “Please use Chrome”. That’s worse I suppose. Cloudflare is a controversial choice not least because some employees sponsor unsavoury projects . Is it time to deflare? I degoogled years ago. I degithubed a few months ago. I mostly deflared moving to Bunny CDN but my contact form remains on Cloudflare. Why is it so difficult to find reputable services? Just don’t be a bad guy! I considered rolling my own invisible CAPTCHA thing. It’s security by obscurity when you think about it. Over summer I had a go at building Anubis at home . The “proof of work” is really just “proof of JavaScript” in practice. I don’t want JavaScript gatekeeping my entire website. Cloudflare’s secret sauce will be some combination of browser detection and heuristics. If this fails I’m tapping out and you can email me directly. It’s weird that my address is unobscured yet I get more spam via the contact form! Update: Note for October 11th Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views
David Bushell 4 months ago

Not My Cup of Tea

As blog topics go, last week’s Next.js clownshow was a freebie. A bit of front-end dev and a middle finger to fascism. I had it drafted before my tea went cold. I wasn’t expecting round two to hit harder. This week I momentarily lost the will to blog. Ok, I’m being very dramatic. It wasn’t writer’s block or imposter syndrome. Not the usual suspects. I was just stun-locked for a couple of days. Like any self-respecting person with an ounce of sanity, I’ve been off Twitter X since it got all fashy. Nevertheless, it’s impossible to avoid the crazy stuff. And this week’s crazy was another level. Enjoyed my discussion with PM Netanyahu on how AI education and literacy will keep our free societies ahead. We spoke about AI empowering everyone to build software and the importance of ensuring it serves quality and progress. Optimistic for peace, safety, and greatness for Israel and its neighbors. @rauchg Sep 29, 2025 (xcancel) - Guillermo Rauch On seeing this I noted in anger followed by a hastily worded social post: I wonder if @svelte.dev is onboard with this? The obvious answer is: ‘no’. Everything I already know suggests the Svelte maintainers are antithetical to Rauch. My words were clumsy not malicious. I was merely wondering what on earth does Svelte do? WTF does anyone do when a major funding source does… that? A quick catch-up for those unaware: In the wake of this mess some people were keen to remind everyone of Svelte’s independence. Rich Harris and others were lost for words. Can you blame them? I called out Svelte specifically because it’s the one project with ties to Vercel I care about. Svelte is a shining light in a rather bleak JavaScript ecosystem . I try to avoid political discussion online. I’m a little ham-fisted in questioning the ethics of my tech stack. Some argue that taking Vercel’s money has moral baggage. That it makes the recipient complicit in brand-washing. Personally I’m not sure what to think. To cut ties with Vercel would be morally courageous. Then what? There’s no easy alternative to keep the lights on. The day after Rauch’s infamous selfie Vercel announced $300M in series F funding . The “F” stands for “f*ck you” I’m told. Vercel’s pivot to AI banked them one third of a billy in a world where profit doesn’t matter . Until the “AI” bubble bursts Vercel are untouchable. Is it wrong to siphon off a little cheddar for better use? Let’s be honest, who else is funding open source software? Few users are willing to pay for it, developers included. The world revolves around load-bearing Nebraskans . So what can projects like Svelte do? Does it matter? Nothing matters anymore. You can just say things these days. Make up your own truths. Re-roll the chatbot until it agrees. And if your own chatbot continues to fact-check you just rewrite history . We live in a reality where you can spew white supremacy fan fiction for the boys on X and Cloudflare will sponsor your side hustle a week later. Moral bankruptcy is a desirable trait in this economy. Is it any wonder open source maintainers with a backbone are shell-shocked? I’ll leave Svelte to figure out how to navigate impossible waters. Let’s hope that open governance remains intact, lest it go off the rails . For the rest of us: Taking action and Doing The Right Thing is often difficult, always exhausting, but it is what we must do, together. We all deserve better. The world deserves better. It’ll take a little work to get there, but there is hope. We all have a choice - Salma Alam-Naylor Amen to that. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. Guillermo Rauch is CEO of Vercel Netanyahu is a wanted war criminal Vercel funds Svelte and employs creator Rich Harris Svelte remains open governance; not owned by Vercel Cut ties and take the moral victory for a day and then be amazed by the magical vanishing act of an entire dev community when asked for spare change tomorrow? Continue discarding skeets until the drama blows over? Pivot to “AI”?

0 views
David Bushell 4 months ago

RSS Club #003: Silksong

This is an “RSS-only” post where I discuss topics tangentially related to my usual web design and development feed. Ignore or enjoy! Before I delve into the dark corners of Pharloom I’d like to discuss one related topic. Silksong is a hard game that offers no affordances. There is no “easy mode”. There are no granular controls to tailor the experience to your individual ability or preference. Silksong is in stark contrast to games like Star Wars Outlaws by Ubisoft. Modern Ubisoft games take accessibility seriously. Outlaws has a huge list of accessibility options covering visuals, audio, controls, menus, and gameplay. Outlaws is a masterpiece of development that is unfortunately undone by being a rather boring game. The Silksong meme is “get good” and it’s a great game if your able to “get good”. But I strongly disagree with the notion that it has to be that way. Any argument for single-player games not providing “difficulty” settings is inherently exclusionist. If a game offers one mode, that does not mean all players experience the same challenge. An abled twenty year old memer is playing an easier game than anyone with a disadvantage. Be that any disability or distraction. How others experience a game should have absolutely no bearing on your own enjoyment. That’s just pathetic. Online discussion tends to fall into shallow gate-keeping. Providing more accessibility options would help ensure players get a comparable experience. Such options allow more players to find fun in a game. There’s a grey area between artistic choice and discrimination. I believe hard games should be allowed to exist in the same way comedians should be allowed to tell edgy jokes. The difference is games can have options, so why add self-imposed limits to exclude players? In 2007 game devs Team Cherry published a five star game, Hollow Knight . I never played it on release. I picked up the Voidheart Edition some years later and completed almost every challenge (can’t remember how far I got in the Pantheons). Silksong is the long awaited sequel. Hornet is the playable character replacing John Hollow Knight as Silksong’s protagonist. Hornet’s movement and play style is faster and more aggressive. If Hollow Knight was five stars I’d give Silksong three stars. A good game but nothing special and let down by lessons unlearned. Fair warning: spoilers galore below! Nothing is off limits. After 18 days and 52 in-game hours I rolled credits on Silksong. I immediately jumped back in for another week to tie up loose ends. After 68 hours, my Silksong adventure is over! I played the first Hollow Knight and shamelessly followed a walkthrough verbatim. Silksong was an amazing experience to explore blind and discover for myself. I followed every path and found every upgrade to make the main quest easier. I enjoyed the fast paced combat. That said, I can’t be bothered to 100% Silksong. I’ve seen two endings and I’ve watched the rest on YouTube. I’m in Act 3 and I joined the Flea Festival and I’m happy here! I’ve absolutely no desire to see more. A shame because there are cool boss fights I’m missing. But boss fights are what let this game down. Before I discuss the bad these are my top five in fight order: These were great fights I beat clean without spamming tools. Sadly, fun bosses were few and far between in Silksong. Too many bosses were giant amorphous blobs where contact damage from their fat-ass movement was more deadly than the attacks. Boring; forgettable. That’s my main criticism of Silksong; underwhelming boss fights and an over-reliance on harder gauntlet battles. The High Halls gauntlet would have felt more rewarding had I not been fatigued already. Most bosses I beat within a dozen tries. For me Silksong lacked a Soul Master moment where hours of practice and progress felt like a real achievement. First Sinner came close but as an optional hidden boss — I never got captured and had to break into The Slab — it didn’t feel like a major victory. I’m actually complaining about lack of — or the wrong kind of — difficulty in boss fights. Difficulty in a fun way where I learn to overcome a challenge. Not difficulty where I repeat the same madness until I get lucky and not caught in the air between fat bouncy blob, randomly spawning blob, and heat-seeking acid spew blob. Lazy game design is not fun. I know quite a lot of potentially cool bosses are in Act 3 along with possibly 20–30 hours of extra content. I wish I cared. It just feels like a chore to progress any further. Backloading the endgame is just bad design in my opinion. You might say I never finished the game and quit before the final act. Whatever, I got my money’s worth! Personally I think Silksong was comparably easier than I remembered Hollow Knight. Regardless, I found the difficulty in this game unfair. Deaths in Hollow Knight always felt preventable. Many deaths in Silksong came from gambling with flying enemies designed to punish no matter how you moved or attacked. Like many players I discovered poisoned Cogflys to be very effective against pesky flies. This made areas like Bilewater bearable. If everyone is using the same overpowered tactic that suggests poor game balance. Platforming challenges were fun once I mastered the 45° degree pogo. Longclaw made that easier. Climbing Mount Fay to unlock the double jump was a pleasant change of pace. I would have preferred a Path of Pain over Bilewater’s gimmick. The economic balance of rosaries and shards sucked and dissuaded me from experimenting. Many tools felt unnecessary and my load-out rarely changed. The Architect Crest looked interesting but farming shards was bad enough. I went 80% Hunter and 20% Reaper when I required longer attacks. I found Weavenest early which also locked in my choice. Silksong is a fantastic game overshadowed by the relative perfection that was the original Hollow Knight. In comparison I found Silksong a little too unfair and at times unrewarding. I don’t feel like I could play Silksong again but I could give Hollow Knight another run. Unlocking every skill in Hollow Knight felt like a big milestone. Silksong missed that mark. For me Silksong is a solid three stars that took risks but failed to improve on the original. I’ll be playing Ghost of Yōtei next! Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. First Sinner

0 views
David Bushell 4 months ago

How Much Does Freedom Cost?

Trump’s National Design Studio has an executive order to “modernize the interfaces that serve everyday citizens” . That means rich/white people (but not the ‘disabled’ kind). The US government had digital service agencies that cared about a performant and accessible web until they got the DOGE treatment . The NDS’ latest website trumpcard.gov is a Next.js disasterclass . Vercel’s CEO Guillermo Rauch thinks an endorsement by a friend of Epstein is… a good thing? Anyway, Trump invites you to “Submit Your Appl 🦅 tion”. This side-eying American Bald Eagle is a 579 frame animation. Each frame is a 1671×1300 pixel PNG weighing on average 30 KB each. Frames 261 through 320, where the eagle is looking straight forward, are replaced by frame 320 to save bandwidth. Despite this valiant effort the total size of these PNG files is 16.7 megabytes . PNG frames are requested by a Web Worker and saved using the CacheStorage API. The worker returns URLs for each frame. The React hook is used ( very carefully ) to trigger to update an elements source. And that is how you get 16.7 MBs of freedom. Alternate text is seemingly used as a comment for developers. Eagle-eyed readers will have noticed the eagle’s body is a static image. The PNG frames only contain the head which is no larger than 400×400 in the centre. A quick crop and squoosh suggests a 20% saving with no quality loss. Using a lossy codec like AVIF would allow for anywhere between 50–80% smaller images with little perceptual quality loss. I’m guessing the animation trickery is done to superimpose the eagle over the text “Submit Your Application”. Is it worth the cost? No. Just use a video! You could just make the entire thing a video including the text (like my screen recording above). This would limit the responsive design and the initial text transition but would be much smaller than 16.7 MB. To retain separation of elements a video codec with alpha transparency can be used (see CSS-Tricks , Jake Archibald ). WebM/VP9 works in Chrome and Firefox and HEVC works for Safari/iOS. A quick test returns 500–800 KB depending on codec and quality. Using the HTML attribute allows to work in most browsers. These are rough numbers but suffice it to say a PNG based animation is expensive . Then again, if you’re in the market for a $1 million dollar card you can probably afford this too. Decapitating America’s “national bird” is not the only sin committed by the National Design Studio. Trump’s gold card website is a treasure trove of bad development. View source and see what fun you can find. And remember, for facist-friendly hosting™, think Vercel. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views
David Bushell 5 months ago

Let’s see Paul Allen’s CSS Reset

CSS “resets” are boilerplate code designed to remove or normalize browser defaults. They provide solid foundation to build bespoke CSS upon. When utilised correctly they should be unobtrusive. Any quirks being ones of personal taste and flair. These quirks are why CSS programmers obsess over their reset stylesheets like the infamous business card scene (YouTube) † . † ⚠️ beyond the satirical quotes, American Psycho is a brutal movie with extreme violence. Heed warning before watching, there are no further parallels to the comfort of web development! CSS resets have matured along with the CSS spec(s). They’ve gotten complicated. Some incorporate choices that can have big consequences if not used with care. Perhaps a good reason to roll your own CSS reset; you must understand every line. Here are a few notable recent examples to learn from: And saving the best for last: I won’t copy & paste it all because my CSS reset is a “living standard” like the HTML spec. You can find 👉 my CSS reset here 👈 You’ll have noticed I wrap all selectors in to zero out specificity, just in case. I will also typically import my CSS reset into the lowest cascade layer. If you don’t bikeshed those layer names in the comments I’ll be disappointed. I define my layers alongside top-level imports rather than wrapping large blocks of code. The only thing that gets imported earlier are declarations. Another “just in case”. Does this allow the browser to fetch fonts faster? No idea lol (ask Harry ). I will preload critical fonts in the anyway. I just like putting fonts up top in CSS; they’re special. This combo of selector and cascade layers make specificity a non-issue. I’ve been on the logical properties everywhere train for years. This practice allows for almost free right-to-left support. For nuances see RTL Styling 101 by Ahmad Shadeed. You’re missing out on that free RTL styling if you forget the class. The class is added by Google Translate. Google doesn’t alter the attribute so it won’t naturally flip without help. Kagi Translate does add — one of a thousand reasons to stop using Google. I prefix the naked tag name for clarity. Does that matter? Nope! My properties are ordered alphabetically because I’ve worked with Stu Robson . My haphazard aesthetic ragged edge ordering did not vibe with Stu’s sensible design system. I’ve been an alphabetical convert ever since. As an almost 40 year-old that still sings the alphabet to place letters, this is not easy for me. Siri, delete that last paragraph. Okay, what’s all that about? I once had a client that resized the browser below 300px and complained. The is more interesting. This enables a full viewport “hero”, depending how you go about it. It also allows you to push the footer to the bottom on shorter pages. Nothing weirder than seeing a floating footer in the middle. Why ? The viewport height on iOS Safari is dynamic (maybe Android browsers too, I forget). Anything sized to it causes janky layout thrashing on scroll. This BBC profile on Armand Duplantis using is a good example of that issue. The initial size before scrolling is usually the smallest. This fits my use case. I don’t actually reset stuff like the default heading margin. I always style those later. When arrives I may add: Just out of respect for the glorious new pseudo-class. I add to paragraphs and it does something in Safari . I don’t headings as some resetters do by default. I find that too opinionated. Only specific design patterns suit balanced headings. I love a bit of hanging punctuation so I yolo’d it. Then I learned from Jeremy Keith (as one does) this practice has unwanted side effects. So I reset it back to on form elements. A reset within a reset, is that code smell? I may or may not have secretly patched half a dozen client websites. Speaking of fancy pants typography, please show support for Richard Rutter’s Interop 2026 . Prioritise long-standing bugs first Big Browser 🙏 For a long time I refused to use “font smoothing”. I was staunchly a “please don’t mess with text rendering” person. That was until I did a deep dive on: What’s the deal with WebKit Font Smoothing? — I’m not happy with that post, it’s confusing, but the takeaway is I now add the style to my reset. So that’s my CSS reset . It has and will change over time. Let’s see yours! Do you keep it lean, or prefer a chonky reset? P.S. did I just big blog twice in one day? Is that allowed? Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. Chris Coyier (Sep 2025) UA+ (Apr 2025) Piccalilli (Sep 2023) Josh W. Comeau (2021–2025) Elad Shechter (Oct 2021)

0 views
David Bushell 5 months ago

I Shut The Emails Out

Last week I let the emails in by self-hosting an unencrypted SMTP server on port 25. That was a “fun” challenge but left me feeling exposed. I could host elsewhere but most reputable hosting providers block SMTP ports. I found another answer. I know. Bleh! Sellout to Big Tech why don’t I? I don’t see you opening ports into your home. Anyway, Cloudflare has this thing called Email Routing and Email Workers . Cloudflare handles the SMTP and verification of incoming emails. Emails can be forwarded elsewhere or handled by a worker. Catch-all can be configured so it’s wise to do your own address validation. My worker takes the following actions: I’m locked in to Cloudflare now for this side project. Might as well use the full suite. The basic worker script is simple. There is one issue I found. claims to be type: And claims to take type: — amongst others. In reality the email API does not play nicely with the storage API. My worker timed out after 5 minutes with an error. “Provided readable stream must have a known length (request/response body or readable half of FixedLengthStream)” That is why I’m using which I yoinked from @std/streams . I’d rather stream directly but this was a quick fix. Since I have a one megabyte limit it’s not a problem. My original idea was to generate an RSS feed for my Croissant web app à la Kill the Newsletter (which I could just use instead of reinventing…) HTML emails though are a special class of disaster. Semantics and accessibility, anyone? No? Table layouts from the ’90s? Oh, okay… that’s another blog post. Actually hold up. Do we just lose all respect for accessibility when coding HTML emails? Apparently so. I built an HTML email once early in my career and I refused to do it ever again. Here’s a screenshot of the web UI I was already working on to read emails. I’m employing similar tricks I learnt when sanitising RSS feeds . This time I allow inline styles. I remove scripts and images (no thanks). Content security policy is very effective at blocking any tracking attempts that might sneak through. I have a second proxy worker that receives a URL and resolves any HTTP redirects to return the real URL. For good measure, tracking params like are removed at every step. Email truly is the cesspit of the internet. Dreadful code. Ruthless tracking. Why am I doing this again? Most of these newsletters have an RSS and web version available. I can’t believe I let this stuff into my home! Come to think of it, maybe I can pass the plain text versions through a Markdown parser? Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. validate address reject emails larger than to an R2 Storage bucket with metadata

0 views
David Bushell 5 months ago

Trillion Dollar Elephants

I was hesitant to post this because the WHATWG & friends war party is strong on the defence! I’d ask for parley but this is going to get spicy so I won’t feign friendship. I want my web career to survive. I want the web to be better. I want to address the trillion dollar elephants in the room. Quick heads-up: I do believe most individuals involved are good people trying to do a good job. I’m just venting frustration (and torturing a metaphor). Browser teams at trillion dollar companies Apple , Google , and Microsoft , are asking for Interop 2026 proposals . Along with other web platform contributors like Igalia and Mozilla — well some Mozilla employees; I can’t find an official blog. I’ve noted before I’m skeptical of Interop but I decided to play their game this year. I submitted a proposal for XSLT 3.0 . Seems like a good candidate? Well specced with what looks like a test suite . I expect my proposal to be ignored or disqualified. Regardless, this blog post isn’t about XSLT drama. That’s just a symptom. I just didn’t want the lack of proposal to be more ammunition for the inevitable firing squad. I’m not as cynical as some regarding Interop. I believe there is genuine attempt to engage with web developers here. I just wish they’d finish what they start before marching on. With Interop comes Baseline . Baseline gives you clear information about which web platform features are ready to use in your projects today. When reading an article, or choosing a library for your project, if the features used are all part of Baseline, you can trust the level of browser compatibility. Baseline (web.dev) (emphasis mine) That quote would be accurate… if “clear” and “trust” were replaced by “confusing” and “doubt”. My opinions on Baseline are summed up in one image I shitposted back in June. That’s obviously a joke, but I build a lot of websites and the reality is not as rosy as what Devrel PR wants you to believe. I wonder though, how can this process improve? Before you say: “please report bugs” let me get to my serious point. Let’s put the white guy surveys down and ask the real questions. Browser engine teams are custodians of the web platform and open web standards. That’s a big responsibility. Most are employed by trillion dollar companies . Those companies consider the web and its users a product and themselves the owner. It’s an awkward juxtaposition. Are we just going to keep ignoring it? They ask for bug reports with no compensation. The last bug I reported cost me over $1000 † to isolate, reproduce, and write-up. Why should I work for free? Sure, I get to improve the web, but why shouldn’t I profit when those companies do? † approximate USD equivalent for my time (and my rate is cheap for a white guy ) Any mention of “trillion dollar company” is immediately shot down; browser teams have a small budget. Not their fault. But if Google et al. refuse to invest appropriate funds into an open web, why should I be silent? That’s kind of a major problem. Who is in a better position to fix that? A loudmouth blogger, or employees who work there? Don’t get upset when I point out the trillion dollar elephant over your shoulder. Don’t act like I’m the problem. You’re employed by the problem. And if you’re not, why on earth would you defend this status quo? Just to be absolutely clear, am I saying browser vendors should pay developers who are solicited for their professional expertise? Yes I am. If their work is accepted under an agreed criteria. How is such a system structured? Not my problem. Let’s stop pretending we’re on equal footing, in this together for the betterment of a free and open web. Whilst there are trillion dollar elephants in the room these are my terms: Sorry, is that such a radical idea? I think every professional web developer should be saying the same thing. If you want me to change my tune: change the situation. I’d prefer if you echoed my call for more funding. Maybe there are internal efforts? Fantastic! Telling me I’m wrong and that I should allow my time and expertise to be exploited is another option, I guess. P.S. “trillion dollar” applies to market cap not cash on hand. That means share price × number of shares . It’s fiction. The stock market is a casino. Like any shitcoin if too many shares are sold the price plummets. Apple , Google , and Microsoft each have between $50–100 billion in the bank. Mozilla is not publicly traded but their 2023 financial position lists $263 million in “cash and cash equivalents” . P.P.S. my terms also apply to VC-funded companies that open source a few products and exploit “the community” for free labour. I’ve fallen for that trick. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. If you want professional consultation: pay me If you want professional bug reports: pay me If you want professional testing: pay me

0 views
David Bushell 5 months ago

I Let The Emails In

They say never operate your own email server. It’s all fine and dandy until Google et al. arbitrarily ban your IP address. Doesn’t matter if you configure DMARC, DKIM, and SPF — straight to jail. But that only applies to sending email . I think. I’m testing that theory. How easy is it to receive emails? Turns out it’s almost too easy. I coded an SMTP server in TypeScript. I added a couple of DNS records on a spare domain (redacted for obvious reasons). I rawdogged port 25 on my public IP address. I sent myself a test email from Gmail and it worked! Join me on the adventure of how I got this far. I’m using Deno flavoured TypeScript and below is the basic wrapper. I’ve simplified the example code below to illustrate specific concepts. Open the TCP server and pass off connections to an async function. The handler immediately responds in plain text. Wikipedia has a good example of a full message exchange. Only the number codes really matter. Then it reads buffered data until the connection closes. Commands are ASCII ending with the carriage return, line feed combo. I get a little fancy with the so that it throws an error on malformed text. Later I decided that giving unbridled to a 3rd-party was not a smart move. I added a couple of protections: By the way, this exact code never throws because the main thread is blocked. The abort signal task is never executed. Replacing the placeholder comment with an to read data unblocks the event loop. Handling commands is easy if you’re careless. I don’t even bother to parse commands properly. (Note to self: do a proper job.) If there is any command I don’t recognise I close the connection immediately. It was at this stage in my journey that I learnt of the command. The STARTTLS keyword is used to tell the SMTP client that the SMTP server is currently able to negotiate the use of TLS. It takes no parameters. This is supposed to be included as part of the response to . It’s worth noting at this point I’ve tested nothing in the wild. Had I tested I would have saved myself days of work. I found Deno’s function which looked ideal. But no, this only works from the client’s perspective ( issue #18451 ). One does not simply code the TLS handshake. (Some time later I found Mat’s @typemail/smtp — this looks much easier in Node!) It’s possible for an SMTP server to listen securely on port 465 with TLS by default. Deno has to replace . Say no more! Side quest: code an ACME library Side quest status: success! So after that 48 hour side quest I now have a TLS certificate. Which is useless because mail servers deliver to each other on port 25 unencrypted before upgrading with and I’m still blocked there. It’s confusing. Clients can connect directly over TLS to post emails (I think). Whatever, the only way to know for sure is to test in production. And this brings me back to the screenshot above. I opened the firewall on my router and let the emails in. And guess that? Google et al. don’t give a hoot about privacy! Even my beloved Proton will happily send unencrypted plain text emails. Barely compliant and poorly configured server held together by statements and a dream? Take the email! My server is suspect af and yet they handoff emails no sweat. Not their problem. If I tried to send email that’d be another story. For my project I’m just collecting email newsletter; did I mention that? We’ll see if they continue to deliver. If you have a port open on a public IP address you will be found . Especially if it’s a known port like 25. There are bots that literally scan every port of every IP. I log all messages in and out of my SMTP server. I use the free IPinfo.io service to do my own snooping. Here is an example of Google stopping by for a cup of tea. I decided it was best to block all connections from outside NA and EU. For my purposes those would be very unlikely. This one looked interesting: Sorry for the lack of hospitality :( When it’s running, my SMTP server is inside a container on a dedicated machine that is fire-walled off from the LAN. I won’t provide exact schematics because that would only highlight weaknesses in my setup. I’d prefer not to be hacked into oblivion. My server validates SPF and DKIM signatures of any email it receives. RFC 6376 was a formidable foe that had me close to tears. I know I don’t need to code all this myself, but where’s the fun in that? I’m throwing away emails that have malformed encoding. In this case parsing Quoted-Printable and MIME Words formats myself did not look fun. I found Mat’s lettercoder package that does a perfect job. I added a concurrent connection and rate limiter too. @ me if I’m missing another trick. The plan is to keep the SMTP server live and collect sample data. I want to know how feasible it is to run. I’m collecting email newsletters with the idea of designing a dedicated reader. I dislike newsletters in my inbox. This may be integrated into my Croissant RSS app. Of course, Kill the Newsletter! can do that job already. If it proves to be too much hassle I’ll slam the door on port 25. Does anybody know a hosting provided that allows port 25? I was going to use a Digital Ocean droplet for this task but that’s blocked. Update: one week later… I shut the emails out! Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. A generous 30 second timeout A maximum 1 MB message size

0 views
David Bushell 5 months ago

Croissant RSS Beta is Live!

and it has been for a couple of weeks . I’m bad at launching stuff but the important thing is that Croissant is live! I’ll tell you what you need to know. After this screenshot. Maybe try reading this post in Croissant! Croissant is an RSS reader I designed for myself. It might not be for you, but you’re welcome to try it and provide feedback. There are a few ways to use Croissant: Croissant is “beta” which means use the export feature regularly because I test in production. I’m half-joking, the code is stable now. Don’t ask me what “stable” means. Croissant was designed to be as light on features as possible. I hate software bloat so I experimented with the opposite idea. What features can I remove and still make a functional app? I have a few ideas I’d like to add (favicons is one) but updates will be slow and focused on bug fixes and accessibility improvements. Croissant was designed as a desktop app. It’s a responsive website, naturally, but my focus wasn’t on the mobile experience. That’s another excuse for bugs. Please @ me screenshots if anything looks bad on your flip phone. There is no auto-sync you must click the “Sync” button manually. Why? Check back later, I have a note to retrofit a cool philosophical reason for that choice. I subscribe to ~200 feeds that typically publish weekly or monthly. Croissant has no organisation. If you follow feeds that publish 10 times a day you might struggle. There is a single “Mark All as Read” button. It’s okay to accept defeat! I’ve added plenty of polish over the last two months. I’m happy with how it works but there is more to hone. I would like to add colour and typographic theme choices. Just for fun, but I reckon that’d make it more accessible for others. The annoying banner that appears on launch will be removed eventually! Croissant is “source available” not open source. You can review the code and compile for personal/non-commercial use. I chose this model because I have: The first point may change in future. I had considered selling Croissant in some fashion. There’s the whole ordeal with support etc I’m too busy to deal with right now. It should go without saying, but please do not redistribute the code on GitHub . I’ve written at length about the no build/no framework architecture, how I use web components and style them , the Tauri app , and an experimental feature: text to speech synthesis . I have a long series of notes starting July 3rd chronicling this journey. You can follow Croissant development by following my RSS feeds! They’re linked below. I won’t be offended if you don’t use Croissant to subscribe. That’s the awesome thing about RSS. It’s an open standard that has no gatekeeper. If you missed the link: CroissantRSS.com Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. Install CroissantRSS.com as a PWA Download the macOS app build from source (for personal use) no time for the burden of open source no desire to hand-feed the slop factories

0 views
David Bushell 5 months ago

RSS Club #002: Dino Edition

As the VC-funded web continues to ensloppify , it’s important to remember that we don’t need to play their games . Despite billion dollar efforts the web remains decentralised. We can hyperlink right past the wannabe gatekeepers. Like this hyperlink to the Animal Photo Reference Repository . “AI” animal approximations ain’t got nothing on the real deal. Did you know there’s a Reddit page for Defending AI Art . Absolutely bizarre. In my first “RSS-only” post I discussed my favourite whale books. Thank you for the reminders of Hitchhiker’s Guide , which after deliberation I’m tentatively qualifying as whale fiction. There is sadly no photo reference for many extinct animals, but we do have other non-AI artistic depictions. I’ve watched all the Jurassic Park movies which basically makes me a palaeontologist now. I’m here today to present my top five scariest dinosaurs. ⚠️ Spoiler warning. ⚠️ …from the the Jurassic “Cinematic Universe”, which plays fast and loose with its definition and depiction of dinosaurs across seven movies. Yeah seven; they rebooted it this year with Scarlett Johansson and Mahershala Ali . It’s passable. The Jurassic movies cover many genres including comedy, outright horror, and Jeff Goldblum . I love these movies because no matter how dreadful the plot becomes a good dino spook never gets old. This is not a paid sponsor I just think dinosaurs are awesome. In reverse order. Jurassic World: Dominion (2022) is an absolute travesty. They brought back the original cast and squandered it. The movie lost sight of what made the franchise great. The Therizinosaurus also lost sight but it was never explained how it was blinded. This long-fingered feathered psycho could have been the main villain. The swamp scene (YouTube) where Therizinosaurus stalks Bryce Dallas Howard , who silently escapes underwater before rising for air, was channeling Apocalypse Now energy. Unfortunately the rest of the movie removed all suspense and danger. Jurassic Park III (2001) is an underrated movie in the franchise. They’d done Raptors twice. They upped the ante with two T-rex and baby T-rex in The Lost World (1997) . What could they do next, three T-rex? That’d be as ludicrous as four naans . The new big bad Spinosaurus was vicious and fast with a terrific intro (YouTube) . Having the Spinosaurus swallow the satellite phone and using the ringtone to announce its presence was a masterful plot device rivalling any horror movie. Number three might be a controversial choice. Jurassic World (2015) is in many ways a retelling of the original movie, except they invented a fake dinosaur. Indominus Rex’s paddock escape (YouTube) is a thrilling introduction. I-Rex on the loose as the park panics to lockdown adds a permanent tension to the movie. Before the franchise shit the bed with raptor-whispering, Raptors sent a shiver down the spine. First appearing in Jurassic Park (1993) , they’re one of four dinosaur species † to appear in all seven movies. An unseen raptor gets the first kill in the movies opening sequence. The early feeding scene (YouTube) is frightening and we still don’t see the raptors. Once they appear around an hour in their reputation is defined. It’s edge of the seat stuff for the rest of the movie. Nowadays they’d have their own TikTok account before the movie even hit cinemas. † Parasaurolophus, Triceratops, and Tyrannosaurus are the rest ( apparently ). The other confirmed species to appear in all seven movies is, of course, Human. And aren’t we the real dinosaurs? An easy and obvious top spot for the T-rex. Peak Spielberg cinema. The original movie was well paced and truly terrifying at times. Notice how the night scene in T-rex’s escape (YouTube) is lit. It feels dark yet you can actually see the action. A lost art in modern cinematography. T-rex really pops off in the 2nd movie. Again, the night scene rescuing baby T-rex (YouTube) is a Spielberg masterclass. T-rex is done dirty in the 3rd movie, but get’s revenge in the 4th. The standout scene in Jurassic World: Rebirth (2025) is a T-rex cameo battling a yellow rubber dinghy. This pays homage to the original novel by Michael Crichton . Although the Pteranodons are a threat in multiple movies, they lack the scare factor for my list. They get a bigger role in the latest movie but it’s all so lacklustre. Jurassic World: Fallen Kingdom (2018) ; the Indoraptor feigning sleep to escape it’s cage is a great scene (YouTube) . It promises so much only to be thwarted by plot armour and well polished hardwood floors. And I can’t have two phonies on my list. The Mosasaurus , a massive aquatic reptile, first appeared as a sideshow in Jurassic World . Its lurking cameo (YouTube) in Fallen Kingdom has Jaws-like vibes. Sadly we don’t see it again until Rebirth which again is a weak effort. Shoutout to those who dare criticise the original T-rex scene because of a supposed plot hole. Where exactly does the cliff suddenly come from? To be fair, it’s a good question and I like a low stakes conspiracy theory, but also shut up and enjoy the best movie ever made. And read the two Michael Crichton novels the movies miss a lot of action. BTW, I stealth launched my Croissant RSS reader app! It can be used as a PWA (experimental) and macOS app. Croissant is “source available” not open source at this time. I’m still considering the best open source approach as I develop it. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views
David Bushell 6 months ago

RSS Club #001

Welcome to RSS Club! The first rule of RSS Club is: you tell everyone about RSS Club. RSS is the best way to follow weblogs. I’ve used NetNewsWire for years and I’m now building Croissant RSS to control my own reading experience. Croissant will be available in September as kind of a “beta” release. You’ll have no doubt heard at least one web-adjacent “content creator” embarrass themselves by saying “RSS is dead”. They left the open web behind to build their fragile empire on a platform of proprietary sand. They became slaves to an algorithm. Now that algorithm is starting to reject them in favour of AI slop. Big Tech has invested billions; they’re peddling slop whether anyone wants it or not. Open standards like RSS are a panacea for “the algorithm” — AI or otherwise; always has been. RSS broadcasts, shares, notifies, collates, and aggregates. All without a middleman. RSS bypasses the tech bro nonsense and they can’t do anything to stop it! The broligarchy love to talk about “democratising” tech. That is code, not very subtle code, for you “participating” under their control. The web doesn’t need false governance. The web is decentralised and RSS strengthens the web. But you know this, so remind others about RSS! To be honest I’ve not really thought this through. I’ve seen other bloggers do RSS-only posts. I like the idea of bonus content. My RSS Club posts will have real public URLs. You’re welcome to bookmark and share those pages. They won’t be listed in my blog index or sitemap. My RSS feed will be the only way to discover them. I’ll publish to RSS Club infrequently. Monthly, at most. Maybe not even monthly. Maybe never again! RSS Club will be the only place where you’ll find my list of… I’ve not completed the list yet, obviously, but I’m currently reading (and listening) to Whalefall , which I heard was being adapted into a motion picture. Believe it or not I’ve read Moby Dick twice. All (both) books in my list centre around the mighty Sperm Whale . Sperm whales are, in my opinion, the most interesting whale. Yes their name literally refers to semen. Their bulbous heads are filled with Spermaceti . The substance was initially believed to be whale semen, due to its appearance when fresh. Sperm whales dive to incredible depths to eat Giant and even Colossal Squid . There is almost no footage of such squid alive in their natural habitat; they are the mythical Kraken . And a sperm whale’s supper. The bigger Blue Whale is estimated to be the largest animal ever . More massive than even Sauropods. Blue whales feed on krill , not squid. Pathetic. You cannot unsubscribe from whale facts, by the way. There is contention within the emoji world as to which species of whale should be illustrated. There are currently two unicode points: The abstract nature of the designs makes it impossible to classify most emoji but a few have unmistakable characteristics of a sperm whale. Anyway, please help me complete my top ten whale books. If you’re familiar with whale fiction please get in touch and recommend. Space Whales qualify. End of transmission. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. Moby-Dick; or, The Whale, by Herman Melville Whalefall, by Daniel Kraus Whale U+1F40B Spouting Whale U+1F433

0 views