Posts in Css (20 found)
fLaMEd fury 3 days ago

Making fLaMEd fury Glow Everywhere With an Eleventy Transform

What’s going on, Internet? I originally added a CSS class as a fun way to make my name (fLaMEd) and site name (fLaMEd fury) pop on the homepage. shellsharks gave me a shoutout for it, which inspired me to take it further and apply the effect site-wide. Site wide was the original intent and the problem was it was only being applied manually in a handful of places, and I kept forgetting to add it whenever I wrote a new post or created a new page. Classic. Instead of hunting through templates and markdown files, I’ve added an Eleventy HTML transform that automatically applies the glow up. I had Claude Code help me figure out the regex and the transform config. This allowed me to get this done before the kids came home. Don't @ me. The effect itself is a simple utility class using : Swap for whatever gradient custom property you have defined. The repeats the gradient across the text for a more dynamic flame effect. The transform lives in its own plugin file and gets registered in . It runs after Eleventy has rendered each page, tokenises the HTML by splitting on tags, tracks a skip-tag stack, and only replaces text in text nodes. Tags in the set, along with any span already carrying the class, push onto the stack. No replacement happens while the stack is non-empty, so link text, code examples, the page , and already-wrapped instances are all left alone. HTML attributes like and are never touched because they sit inside tag tokens, not text nodes. A single regex handles everything in one pass. The optional group matches " fury" (with space) or “fury” (without), so “flamed fury” and “flamedfury” (as it appears in the domain name) are both wrapped as a unit. The flag covers every capitalisation variant (“fLaMEd fury”, “Flamed Fury”, “FLAMED FURY”) with the original casing preserved in the output. This helps because I can be inconsistent with the styling at times. Export the plugin from wherever you manage your Eleventy plugins: Then register it in . Register it before any HTML prettify transform so the spans are in place before reformatting runs: That’s it. Any mention of the site name (fLaMEd fury) in body text gets the gradient automatically, in posts, templates, data-driven content, wherever. Look out for the easter egg I’ve dropped in. Later. Hey, thanks for reading this post in your feed reader! Want to chat? Reply by email or add me on XMPP , or send a webmention . Check out the posts archive on the website.

0 views
Kev Quirk 4 days ago

Introducing Pure Comments (and Pure Commons)

A few weeks ago I introduced Pure Blog a simple PHP based blogging platform that I've since moved to and I'm very happy. Once Pure Blog was done, I shifted my focus to start improving my commenting system . I ended that post by saying: At this point it's battle tested and working great. However, there's still some rough edges in the code, and security could definitely be improved. So over the next few weeks I'll be doing that, at which point I'll probably release it to the public so you too can have comments on your blog, if you want them. I've now finished that work and I'm ready to release Pure Comments to the world. 🎉 I'm really happy with how Pure Comments has turned out; it slots in perfectly with Pure Blog, which got me thinking about creating a broader suite of apps under the Pure umbrella. I've had Simple.css since 2022, and now I've added Pure Blog and Pure Comments to the fold. So I decided I needed an umbrella to house these disparate projects. That's where Pure Commons comes in. My vision for Pure Commons is to build it into a suite of simple, privacy focussed tools that are easy to self-host, and have just what you need and no more. Well, concurrent to working on Pure Comments, I've also started building a fully managed version that people will be able to use for a small monthly fee. That's about 60% done at this point, so I should be releasing that over the next few weeks. In the future I plan to add a managed version of Pure Blog too, but that will be far more complex than a managed version of Pure Comments. So I think that will take some time. I'm also looking at creating Pure Guestbook , which will obviously be a simple, self-hosted guestbook along the same vein as the other Pure apps. This should be relatively simple to build, as a guestbook is basically a simplified commenting system, so most of the code is already exists in Pure Comments. Looking beyond Pure Guestbook I have some other ideas, but you will have to wait and see... In the meantime, please take a look as Pure Comments - download the source code , take it for a spin, and provide any feedback/bugs you find. If you have any ideas for apps I could add to the Pure Commons family, please get in touch. Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️ You can reply to this post by email , or leave a comment .

0 views
Thomasorus 5 days ago

Is frontend development a dead-end career?

It's been almost a year at my current job. I was hired as a frontend developer and UI/UX coordinator, but I've been slowly shifting to a project manager role, which I enjoy a lot and where I think I contribute more. We build enterprise web apps, the kinds you will never see online, never hear about, but that power entire companies. The config application for the car assembly line, the bank counsellor website that outputs your mortgage rate, the warehouse inventory systems... That's the kind of thing we do. For backend engineers that's a very interesting job. You get to understand how entire professional fields work, and try to reproduce them in code. But for us the frontend guys? The interest is, limited to put it simply. We're talking about pages with multi-step conditional forms, tables with lots of columns and filters, 20 nuances of inputs, modals... The real challenge isn't building an innovative UI or UX, it's maintaining a consistency in project that can last years and go into the hands of multiple developers. Hence my UI/UX coordinator role where I look at my colleagues work and sternly say "That margin should be , not " . Because here's the thing: this type of client doesn't care if it's pretty or not and won't pay for design system work or maintenance. To them, stock Bootstrap or Material Design is amazingly beautiful compared to their current Windev application. What they want is stability and predictability, they care it works the same when they encounter the same interface. Sometimes, if a process is too complex for new hires, they will engage into talks to make it more user friendly, but that's it. Until recently, the only generated code we used were the types for TypeScript and API calls functions generated from the backend, which saved us a lot of repetitive work. We made experiments with generative AI and found out we could generate a lot of our template code. All that's left to do is connect both, the front of the frontend and the back of the frontend , mostly click events, stores, reactivity, and so on. People will say that's where the fun is, and sometimes yes, I agree. I've been on projects where building the state was basically building a complex state machine out of dozens of calls from vendor specific APIs. But how often do you do that? And why would you do that if you are developing the backend yourself and can pop an endpoint with all the data your frontend needs? And so I've been wondering about the future. With frameworks, component libraries, LLMs, the recession pushing to deliver fast even if mediocre code and features, who needs someone who can write HTML, CSS, JS? Who can pay for the craft of web development? Are the common frontend developers folks, not the already installed elite freelancers building websites for prestigious clients , only destined to do assembly line of components by prompting LLMs before putting some glue between code blocks they didn't write?

0 views

Learning Java Again

Java was my first programming language I learned, it’s my baby. Well also HTML and CSS. But for scripting, I’ve always enjoyed writing Java code. I’ve become pretty familiar with Python at this point, and haven’t touched Java in ages, but really feel the itch to pick it up seriously again since it is what taught me programming and computer science concepts to begin with. I actually still recommend Java as a first programming language over Python, since it touches a lot of concepts that I think are good to start with from the beginning. It’s easier to move to Python than to move to Java or C++ from Python. Anyone have project ideas or recommendations for writing more Java? Let me know :) Subscribe via email or RSS

1 views
Jim Nielsen 6 days ago

Making Icon Sets Easy With Web Origami

Over the years, I’ve used different icon sets on my blog. Right now I use Heroicons . The recommended way to use them is to copy/paste the source from the website directly into your HTML. It’s a pretty straightforward process: If you’re using React or Vue, there are also npm packages you can install so you can import the icons as components. But I’m not using either of those frameworks, so I need the raw SVGs and there’s no for those so I have to manually grab the ones I want. In the past, my approach has been to copy the SVGs into individual files in my project, like: Then I have a “component” for reading those icons from disk which I use in my template files to inline the SVGs in my HTML. For example: It’s fine. It works. It’s a lot of node boilerplate to read files from disk. But changing icons is a bit of a pain. I have to find new SVGs, overwrite my existing ones, re-commit them to source control, etc. I suppose it would be nice if I could just and get the raw SVGs installed into my folder and then I could read those. But that has its own set of trade-offs. For example: So the project’s npm packages don’t provide the raw SVGs. The website does, but I want a more programatic way to easily grab the icons I want. How can I do this? I’m using Web Origami for my blog which makes it easy to map icons I use in my templates to Heroicons hosted on Github. It doesn’t require an or a . Here’s an snippet of my file: As you can see, I name my icon (e.g. ) and then I point it to the SVG as hosted on Github via the Heroicons repo. Origami takes care of fetching the icons over the network and caching them in-memory. Beautiful, isn’t it? It kind of reminds me of import maps where you can map a bare module specifier to a URL (and Deno’s semi-abandoned HTTP imports which were beautiful in their own right). Origami makes file paths first-class citizens of the language — even “remote” file paths — so it’s very simple to create a single file that maps your icon names in a codebase to someone else’s icon names from a set, whether those are being installed on disk via npm or fetched over the internet. To simplify my example earlier, I can have a file like : Then I can reference those icons in my templates like this: Easy-peasy! And when I want to change icons, I simply update the entries in to point somewhere else — at a remote or local path. And if you really want to go the extra mile, you can use Origami’s caching feature: Rather than just caching the files in memory, this will cache them to a local folder like this: Which is really cool because now when I run my site locally I have a folder of SVG files cached locally that I can look at and explore (useful for debugging, etc.) This makes vendoring really easy if I want to put these in my project under source control. Just run the file once and boom, they’re on disk! There’s something really appealing to me about this. I think it’s because it feels very “webby” — akin to the same reasons I liked HTTP imports in Deno. You declare your dependencies with URLs, then they’re fetched over the network and become available to the rest of your code. No package manager middleman introducing extra complexity like versioning, transitive dependencies, install bloat, etc. What’s cool about Origami is that handling icons like this isn’t a “feature” of the language. It’s an outcome of the expressiveness of the language. In some frameworks, this kind of problem would require a special feature (that’s why you have special npm packages for implementations of Heroicons in frameworks like react and vue). But because of the way Origami is crafted as a tool, it sort of pushes you towards crafting solutions in the same manner as you would with web-based technologies (HTML/CSS/JS). It helps you speak “web platform” rather than some other abstraction on top of it. I like that. Reply via: Email · Mastodon · Bluesky Go to the website Search for the icon you want Click to “Copy SVG” Go back to your IDE and paste it Names are different between icon packs, so when you switch, names don’t match. For example, an icon might be named in one pack and in another. So changing sets requires going through all your templates and updating references. Icon packs are often quite large and you only need a subset. might install hundreds or even thousands of icons I don’t need.

0 views
David Bushell 1 weeks ago

Everything you never wanted to know about visually-hidden

Nobody asked for it but nevertheless, I present to you my definitive “it depends” tome on visually-hidden web content. I’ll probably make an amendment before you’ve finished reading. If you enjoy more questions than answers, buckle up! I’ll start with the original premise, even though I stray off-topic on tangents and never recover. I was nerd-sniped on Bluesky. Ana Tudor asked : Is there still any point to most styles in visually hidden classes in ’26? Any point to shrinking dimensions to and setting when to nothing via / reduces clickable area to nothing? And then no dimensions = no need for . @anatudor.bsky.social Ana proposed the following: Is this enough in 2026? As an occasional purveyor of the class myself, the question wriggled its way into my brain. I felt compelled to investigate the whole ordeal. Spoiler: I do not have a satisfactory yes-or-no answer, but I do have a wall of text! I went so deep down the rabbit hole I must start with a table of contents: I’m writing this based on the assumption that a class is considered acceptable for specific use cases . My final section on native visually-hidden addresses the bigger accessibility concerns. It’s not easy to say where this technique is appropriate. It is generally agreed to be OK but a symptom of — and not a fix for — other design issues. Appropriate use cases for are far fewer than you think. Skip to the history lesson if you’re familiar. , — there have been many variations on the class name. I’ve looked at popular implementations and compiled the kitchen sink version below. Please don’t copy this as a golden sample. It merely encompasses all I’ve seen. There are variations on the selector using pseudo-classes that allow for focus. Think “skip to main content” links, for example. What is the purpose of the class? The idea is to hide an element visually, but allow it to be discovered by assistive technology. Screen readers being the primary example. The element must be removed from layout flow. It should leave no render artefacts and have no side effects. It does this whilst trying to avoid the bugs and quirks of web browsers. If this sounds and looks just a bit hacky to you, you have a high tolerance for hacks! It’s a massive hack! How was this normalised? We’ll find out later. I’ll whittle down the properties for those unfamiliar. Absolute positioning is vital to remove the element from layout flow. Otherwise the position of surrounding elements will be affected by its presence. This crops the visible area to nothing. remains as a fallback but has long been deprecated and is obsolete. All modern browsers support . These two properties remove styles that may add layout dimensions. This group effectively gives the element zero dimensions. There are reasons for instead of and negative margin that I’ll cover later. Another property to ensure no visible pixels are drawn. I’ve seen the newer value used but what difference that makes if any is unclear. This was added to address text wrapping inside the square (I’ll explain later). So basically we have and a load of properties that attempted to make the element invisible. We cannot use or or because those remove elements from the accessibility tree. So the big question remains: why must we still ‘zero’ the dimensions? Why is not sufficient? To make sense of this mystery I went back to the beginning. It was tricky to research this topic because older articles have been corrected with modern information. I recovered many details from the archives and mailing lists with the help of those involved. They’re cited along the way. Our journey begins November 2004. A draft document titled “CSS Techniques for WCAG 2.0” edited by Wendy Chisholm and Becky Gibson includes a technique for invisible labels. While it is usually best to include visual labels for all form controls, there are situations where a visual label is not needed due to the surrounding textual description of the control and/or the content the control contains. Users of screen readers, however, need each form control to be explicitly labeled so the intent of the control is well understood when navigated to directly. Creating Invisible labels for form elements ( history ) The following CSS was provided: Could this be the original class? My research jumped through decades but eventually I found an email thread “CSS and invisible labels for forms” on the W3C WAI mailing list. This was a month prior, preluding the WCAG draft. A different technique from Bob Easton was noted: The beauty of this technique is that it enables using as much text as we feel appropriate, and the elements we feel appropriate. Imagine placing instructive text about the accessibility features of the page off left (as well as on the site’s accessibility statement). Imagine interspersing “start of…” landmarks through a page with heading tags. Or, imagine parking full lists off left, lists of access keys, for example. Screen readers can easily collect all headings and read complete lists. Now, we have a made for screen reader technique that really works! Screenreader Visibility - Bob Easton (2003) Easton attributed both Choan Gálvez and Dave Shea for their contributions. In same the thread, Gez Lemon proposed to ensure that text doesn’t bleed into the display area . Following up, Becky Gibson shared a test case covering the ideas. Lemon later published an article “Invisible Form Prompts” about the WCAG plans which attracted plenty of commenters including Bob Easton. The resulting WCAG draft guideline discussed both the and ideas. Note that instead of using the nosize style described above, you could instead use postion:absolute; and left:-200px; to position the label “offscreen”. This technique works with the screen readers as well. Only position elements offscreen in the top or left direction, if you put an item off to the right or the bottom, many browsers will add scroll bars to allow the user to reach the content. Creating Invisible labels for form elements Two options were known and considered towards the end of 2004. Why not both? Indeed, it appears Paul Bohman on the WebAIM mailing list suggested such a combination in February 2004. Bohman even discovered possibly the first zero width bug. I originally recommended setting the height and width to 0 pixels. This works with JAWS and Home Page Reader. However, this does not work with Window Eyes. If you set the height and width to 1 pixel, then the technique works with all browsers and all three of the screen readers I tested. Re: Hiding text using CSS - Paul Bohman Later in May 2004, Bohman along with Shane Anderson published a paper on this technique. Citations within included Bob Easton and Tom Gilder . Aside note: other zero width bugs have been discovered since. Manuel Matuzović noted in 2023 that links in Safari were not focusable . The zero width story continues as recently as February 2026 (last week). In browse mode in web browsers, NVDA no longer treats controls with 0 width or height as invisible. This may make it possible to access previously inaccessible “screen reader only” content on some websites. NVDA 2026.1 Beta TWO now available - NV Access News Digger further into WebAIM’s email archive uncovered a 2003 thread in which Tom Gilder shared a class for skip navigation links . I found Gilder’s blog in the web archives introducing this technique. I thought I’d put down my “skip navigation” link method down in proper writing as people seem to like it (and it gives me something to write about!). Try moving through the links on this page using the keyboard - the first link should magically appear from thin air and allow you to quickly jump to the blog tools, which modern/visual/graphical/CSS-enabled browsers (someone really needs to come up with an acronym for that) should display to the left of the content. Skip-a-dee-doo-dah - Tom Gilder Gilder’s post links to a Dave Shea post which in turn mentions the 2002 book “Building Accessible Websites” by Joe Clark . Chapter eight discusses the necessity of a “skip navigation” link due to table-based layout but advises: Keep them visible! Well-intentioned developers who already use page anchors to skip navigation will go to the trouble to set the anchor text in the tiniest possible font in the same colour as the background, rendering it invisible to graphical browsers (unless you happen to pass the mouse over it and notice the cursor shape change). Building Accessible Websites - 08. Navigation - Joe Clark Clark expressed frustration over common tricks like the invisible pixel. It’s clear no class existed when this was written. Choan Gálvez informed me that Eric Meyer would have the css-discuss mailing list. Eric kindly searched the backups but didn’t find any earlier discussion. However, Eric did find a thread on the W3C mailing list from 1999 in which Ian Jacobs (IBM) discusses the accessibility of “skip navigation” links. The desire to visually hide “skip navigation” links was likely the main precursor to the early techniques. In fact, Bob Easton said as much: As we move from tag soup to CSS governed design, we throw out the layout tables and we throw out the spacer images. Great! It feels wonderful to do that kind of house cleaning. So, what do we do with those “skip navigation” links that used to be attached to the invisible spacer images? Screenreader Visibility - Bob Easton (2003) I had originally missed that in my excitement seeing the class. I reckon we’ve reached the source of the class. At least conceptually. Technically, the class emerged from several ideas, rather than a “eureka” moment. Perhaps more can be gleaned from other CSS techniques such a the desire to improve accessibility of CSS image replacement . Bob Easton retired in 2008 after a 40 year career at IBM. I reached out to Bob who was surprised to learn this technique was still a topic today † . Bob emphasised the fact that it was always a clumsy workaround and something CSS probably wasn’t intended to accommodate . I’ll share more of Bob’s thoughts later. † I might have overdone the enthusiasm Let’s take an intermission! My contact page is where you can send corrections by the way :) The class stabilised for a period. Visit 2006 in the Wayback Machine to see WebAIM’s guide to invisible content — Paul Bohman’s version is still recommended. Moving forward to 2011, I found Jonathan Snook discussing the “clip method”. Snook leads us to Drupal developer Jeff Burnz the previous year. […] we still have the big problem of the page “jump” issue if this is applied to a focusable element, such as a link, like skip navigation links. WebAim and a few others endorse using the LEFT property instead of TOP, but this no go for Drupal because of major pain-in-the-butt issues with RTL. In early May 2010 I was getting pretty frustrated with this issue so I pulled out a big HTML reference and started scanning through it for any, and I mean ANY property I might have overlooked that could possible be used to solve this thorny issue. It was then I recalled using clip on a recent project so I looked up its values and yes, it can have 0 as a value. Using CSS clip as an Accessible Method of Hiding Content - Jeff Burnz It would seem Burnz discovered the technique independently and was probably the first to write about it. Burnz also notes a right-to-left (RTL) issue. This could explain why pushing content off-screen fell out of fashion. 2010 also saw the arrival of HTML5 Boilerplate along with issue #194 in which Jonathan Neal plays a key role in the discussion and comments: If we want to correct for every seemingly-reasonable possibility of overflow in every browser then we may want to consider [code below] This was their final decision. I’ve removed for clarity. This is very close to what we have now, no surprise since HTML5 Boilterplate was extremely popular. I’m leaning to conclude that the additional properties are really just there for the “possibility” of pixels escaping containment as much as fixing any identified problem. Thierry Koblentz covered the state of affairs in 2012 noting that: Webkit, Opera and to some extent IE do not play ball with [clip] . Koblentz prophesies: I wrote the declarations in the previous rule in a particular order because if one day clip works as everyone would expect, then we could drop all declarations after clip, and go back to the original Clip your hidden content for better accessibility - Thierry Koblentz Sound familiar? With those browsers obsolete, and if behaves itself, can the other properties be removed? Well we have 14 years of new bugs features to consider first. In 2016, J. Renée Beach published: Beware smushed off-screen accessible text . This appears to be the origin of (as demonstrated by Vispero .) Over a few sessions, Matt mentioned that the string of text “Show more reactions” was being smushed together and read as “Showmorereactions”. Beach’s class did not include the kitchen sink. The addition of became standard alongside everything else. Aside note: the origin of remains elusive. One Bootstrap issue shows it was rediscovered in 2018 to fix a browser bug. However, another HTML5 Boilterplate issue dated 2017 suggests negative margin broke reading order. Josh Comeau shared a React component in 2024 without margin. One of many examples showing that it has come in and out of fashion. We started with WCAG so let’s end there. The latest WCAG technique for “Using CSS to hide a portion of the link text” provides the following code. Circa 2020 the property was added as browser support increased and became deprecated. An obvious change I not sure warrants investigation (although someone had to be first!) That brings us back to what we have today. Are you still with me? As we’ve seen, many of the properties were thrown in for good measure. They exist to ensure absolutely no pixels are painted. They were adapted over the years to avoid various bugs, quirks, and edge cases. How many such decisions are now irrelevant? This is a classic Chesterton’s Fence scenario. Do not remove a fence until you know why it was put up in the first place. Well we kinda know why but the specifics are practically folklore at this point. Despite all that research, can we say for sure if any “why” is still relevant? Back to Ana Tudor’s suggestion. How do we know for sure? The only way is extensive testing. Unfortunately, I have neither the time nor skill to perform that adequately here. There is at least one concern with the code above, Curtis Wilcox noted that in Safari the focus ring behaves differently. Other minimum viable ideas have been presented before. Scott O’Hara proposed a different two-liner using . JAWS, Narrator, NVDA with Edge all seem to behave just fine. As do Firefox with JAWS and NVDA, and Safari on macOS with VoiceOver. Seems also fine with iOS VO+Safari and Android TalkBack with Firefox or Chrome. In none of these cases do we get the odd focus rings that have occurred with other visually hidden styles, as the content is scaled down to zero. Also because not hacked into a 1px by 1px box, there’s no text wrapping occurring, so no need to fix that issue. transform scale(0) to visually hide content - Scott O’Hara Sounds promising! It turns out Katrin Kampfrath had explored both minimum viable classes a couple of years ago, testing them against the traditional class. I am missing the experience and moreover actual user feedback, however, i prefer the screen reader read cursor to stay roughly in the document flow. There are screen reader users who can see. I suppose, a jumping read cursor is a bit like a shifting layout. Exploring the visually-hidden css - Katrin Kampfrath Kampfrath’s limited testing found the read cursor size differs for each class. The technique was favoured but caution is given. A few more years ago, Kitty Giraudel tested several ideas concluding that was still the most accessible for specific text use. This technique should only be used to mask text. In other words, there shouldn’t be any focusable element inside the hidden element. This could lead to annoying behaviours, like scrolling to an invisible element. Hiding content responsibly - Kitty Giraudel Zell Liew proposed a different idea in 2019. Many developers voiced their opinions, concerns, and experiments over at Twitter. I wanted to share with you what I consolidated and learned. A new (and easy) way to hide content accessibly - Zell Liew Liew’s idea was unfortunately torn asunder. Although there are cases like inclusively hiding checkboxes where near-zero opacity is more accessible. I’ve started to go back in time again! I’m also starting to question whether this class is a good idea. Unless we are capable and prepared to thoroughly test across every combination of browser and assistive technology — and keep that information updated — it’s impossible to recommend anything. This is impossible for developers! Why can’t browser vendors solve this natively? Once you’ve written 3000 words on a twenty year old CSS hack you start to question why it hasn’t been baked into web standards by now. Ben Myers wrote “The Web Needs a Native .visually-hidden” proposing ideas from HTML attributes to CSS properties. Scott O’Hara responded noting larger accessibility issues that are not so easily handled. O’Hara concludes: Introducing a native mechanism to save developers the trouble of having to use a wildly available CSS ruleset doesn’t solve any of those underlying issues. It just further pushes them under the rug. Visually hidden content is a hack that needs to be resolved, not enshrined - Scott O’Hara Sara Soueidan had floated the topic to the CSS working group back in 2016. Soueidan closed the issue in 2025, coming to a similar conclusion. I’ve been teaching accessibility for a little less than a decade now and if there’s one thing I learned is that developers will resort to using utility to do things that are more often than not just bad design decisions. Yes, there are valid and important use cases. But I agree with all of @scottaohara’s points, and most importantly I agree that we need to fix the underlying issues instead of standardizing a technique that is guaranteed to be overused and misused even more once it gets easier to use. csswg-drafts comment - Sara Soueidan Adrian Roselli has a blog post listing priorities for assigning an accessible name to a control. Like O’Hara and Soueidan, Roselli recognises there is no silver bullet. Hidden text is also used too casually to provide information for just screen reader users, creating overly-verbose content . For sighted screen reader users , it can be a frustrating experience to not be able to find what the screen reader is speaking, potentially causing the user to get lost on the page while visually hunting for it. My Priority of Methods for Labeling a Control - Adrian Roselli In short, many believe that a native visually-hidden would do more harm than good. The use-cases are far more nuanced and context sensitive than developers realise. It’s often a half-fix for a problem that can be avoided with better design. I’m torn on whether I agree that it’s ultimately a bad idea. A native version would give software an opportunity to understand the developer’s intent and define how “visually hidden” works in practice. It would be a pragmatic addition. The technique has persisted for over two decades and is still mentioned by WCAG. Yet it remains hacks upon hacks! How has it survived for so long? Is that a failure of developers, or a failure of the web platform? The web is overrun with inaccessible div soup . That is inexcusable. For the rest of us who care about accessibility — who try our best — I can’t help but feel the web platform has let us down. We shouldn’t be perilously navigating code hacks, conflicting advice, and half-supported standards. We need more energy money dedicated to accessibility. Not all problems can be solved with money. But what of the thousands of unpaid hours, whether volunteered or solicited, from those seeking to improve the web? I risk spiralling into a rant about browser vendors’ financial incentives, so let’s wrap up! I’ll end by quoting Bob Easton from our email conversation: From my early days in web development, I came to the belief that semantic HTML, combined with faultless keyboard navigation were the essentials for blind users. Experience with screen reader users bears that out. Where they might occasionally get tripped up is due to developers who are more interested in appearance than good structural practices. The use cases for hidden content are very few, such as hidden information about where a search field is, when an appearance-centric developer decided to present a search field with no visual label, just a cute unlabeled image of a magnifying glass. […] The people promoting hidden information are either deficient in using good structural practices, or not experienced with tools used by people they want to help. Bob ended with: You can’t go wrong with well crafted, semantically accurate structure. Ain’t that the truth. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. Accessibility notice Class walkthrough Where it all began Further adaptations Minimum viable technique Native visually-hidden Zero dimensions Position off-screen

6 views
David Bushell 1 weeks ago

Web font choice and loading strategy

When I rebuilt my website I took great care to optimise fonts for both performance and aesthetics. Fonts account for around 50% of my website (bytes downloaded on an empty cache). I designed and set a performance budget around my font usage. I use three distinct font families and three different methods to load them. Web fonts are usually defined by the CSS rule. The property allows us some control over how fonts are loaded. The value has become somewhat of a best practice — at least the most common default. The CSS spec says: Gives the font face an extremely small block period (100ms or less is recommended in most cases) and an infinite swap period . In other words, the browser draws the text immediately with a fallback if the font face isn’t loaded, but swaps the font face in as soon as it loads. CSS Fonts Module Level 4 - W3C That small “block period”, if implemented by the browser, renders an invisible font temporarily to minimise FOUC . Personally I default to and don’t change unless there are noticeable or measurable issues. Most of the time you’ll use swap. If you don’t know which option to use, go with swap. It allows you to use custom fonts and tip your hand to accessibility. font-display for the Masses - Jeremy Wagner Google Fonts’ default to which has performance gains. In effect, this makes the font files themselves asynchronous—the browser immediately displays our fallback text before swapping to the web font whenever it arrives. This means we’re not going to leave users looking at any invisible text (FOIT), which makes for both a faster and more pleasant experience. Speed Up Google Fonts - Harry Roberts Harry further notes that a suitable fallback is important, as I’ll discover below. My three fonts in order of importance are: Ahkio for headings. Its soft brush stroke style has a unique hand-drawn quality that remains open and legible. As of writing, I load three Ahkio weights at a combined 150 KB. That is outright greed! Ahkio is core to my brand so it takes priority in my performance budget (and financial budget, for that matter!) Testing revealed the 100ms † block period was not enough to avoid FOUC, despite optimisation techniques like preload . Ahkio’s design is more condensed so any fallback can wrap headings over additional lines. This adds significant layout shift. † Chrome blog mention a zero second block period . Firefox has a config preference default of 100ms. My solution was to use instead of which extends the block period from a recommended 0–100ms up to a much longer 3000ms. Gives the font face a short block period (3s is recommended in most cases) and an infinite swap period . In other words, the browser draws “invisible” text at first if it’s not loaded, but swaps the font face in as soon as it loads. CSS Fonts Module Level 4 - W3C This change was enough to avoid ugly FOUC under most conditions. Worst case scenario is three seconds of invisible headings. With my website’s core web vitals a “slow 4G” network can beat that by half. For my audience an extended block period is an acceptable trade-off. Hosting on an edge CDN with good cache headers helps minimised the cost. Update: Richard Rutter suggested which gives more fallback control than I knew. I shall experiment and report back! Atkinson Hyperlegible Next for body copy. It’s classed as a grotesque sans-serif with interesting quirks such as a serif on the lowercase ‘i’. I chose this font for both its accessible design and technical implementation as a variable font . One file at 78 KB provides both weight and italic variable axes. This allows me to give links a subtle weight boost. For italics I just go full-lean. I currently load Atkinson Hyperlegible with out of habit but I’m strongly considering why I don’t use . Gives the font face an extremely small block period (100ms or less is recommended in most cases) and a short swap period (3s is recommended in most cases). In other words, the font face is rendered with a fallback at first if it’s not loaded, but it’s swapped in as soon as it loads. However, if too much time passes, the fallback will be used for the rest of the page’s lifetime instead. CSS Fonts Module Level 4 - W3C The browser can give up and presumably stop downloading the font. The spec actually says that and “[must/should] only be used for small pieces of text.” Although it notes that most browsers implement the default with similar strategies to . 0xProto for code snippets. If my use of Ahkio was greedy, this is gluttonous! A default would be acceptable. My justification is that controlling presentation of code on a web development site is reasonable. 0xProto is designed for legibility with a personality that compliments my design. I don’t specify 0xProto with the CSS rule. Instead I use the JavaScript font loading API to conditionally load when a element is present. Note the name change because some browsers aren’t happy with a numeric first character. Not shown is the event wrapper around this code. I also load the script with both and attributes. This tells the browser the script is non-critical and avoids render blocking. I could probably defer loading even later without readers noticing the font pop in. Update: for clarity, browsers will conditionally load but JavaScript can purposefully delay the loading further to avoid fighting for bandwidth. When JavaScript is not available the system default is fine. There we have it, three fonts, three strategies, and a few open questions and decisions to make. Those may be answered when CrUX data catches up. My new website is a little chunkier than before but its well within reasonable limits. I’ll monitor performance and keep turning the dials. Web performance is about priorities . In isolation it’s impossible to say exactly how an individual asset should be loaded. There are upper limits, of course. How do you load a one megabyte font? You don’t. Unless you’re a font studio providing a complete type specimen. But even then you could split the font and progressive load different unicode ranges. I wonder if anyone does that? Anyway I’m rambling now, bye. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views
Dominik Weber 1 weeks ago

Lighthouse update February 16th

## Website to feed The past week had first and foremost one improvement, website to feed conversion. It enables users to subscribe to websites that don't provide an RSS feed. This feature consists of multiple areas. The backbone is extracting items from a website based on CSS selectors, and then putting those items through the same pipeline as items of an RSS feed. Meaning extracting full content, calculating reading time, creating a summary, creating an about sentence, interpreting language and topic, and so on. Additional areas are all about making it easier to use. Showing the website and letting users select items simplifies the feature, for many websites it's not necessary to even know about the selectors. This also required some heuristics about which elements to select and how to find the repeating items from just one selection. The user experience can always be improved, but I think as it is right now it's already quite decent. The next step for this feature is to automatically find the relevant items, without the user having to select anything. ## Next steps An ongoing thing is the first user experience. It's not where I want it to be, but honestly it's difficult to know or imagine how it should be. One issue that came up repeatedly is the premium trial, and that users don't want to provide their credit card just to start the trial. That's fair. Though Paddle, the payment system Lighthouse uses, doesn't provide another option. They have it as private beta, but I didn't get invited to that unfortunately. So I'm going to bite the bullet and implement this myself. Won't be as great as if Paddle does it, but at least users will get the premium experience for 2 weeks after signup. An improvement I had my eyes on for some time is using the HTML of RSS feed items for the preview. Lighthouse attempts to parse the full content for all items, but that's not always possible. If websites disallow it via robots.txt, or block via bot protection, Lighthouse doesn't get the content. In these cases it shows that access was blocked. But if the feed contains some content, that could be displayed. Feeds usually don't contain the full content, but it's at least something. One more thing I wanted to do for a long time, and can finally make time for, is creating collections of feeds for specific topics. For example "Frontier AI labs", "Company engineering blogs", "JS ecosystem", and so on. The [blogroll editor](https://lighthouseapp.io/tools/blogroll-editor) is the basis for that. It lets you create a collection of websites and feeds, and export OPML from that. I'm going to improve its UX a bit and then start creating these collections.

0 views
Kev Quirk 2 weeks ago

Updates to My Commenting System

I've been making some updates to my personal commenting system . Before they looked like this: It was just a simple table that contained every comment, both original and replies, in one table. As more people commented, it got a little unwieldy and confusing, so I've changed the layout to that it's all nested comment threads now: I've been using it for around 6 months and have received well over a hundred comments, plus moving it from Jekyll to Pure Blog was extremely simple - just some CSS changes, actually. At this point it's battle tested and working great. However, there's still some rough edges in the code, and security could definitely be improved. So over the next few weeks I'll be doing that, at which point I'll probably release it to the public so you too can have comments on your blog, if you want them.

0 views
David Bushell 2 weeks ago

Declarative Dialog Menu with Invoker Commands

The off-canvas menu — aka the Hamburger , if you must — has been hot ever since Jobs’ invented mobile web and Ethan Marcott put a name to responsive design . Making an off-canvas menu free from heinous JavaScript has always been possible, but not ideal. I wrote up one technique for Smashing Magazine in 2013. Later I explored in an absurdly titled post where I used the new Popover API . I strongly push clients towards a simple, always visible, flex-box-wrapping list of links. Not least because leaving the subject unattended leads to a multi-level monstrosity. I also believe that good design and content strategy should allow users to navigate and complete primary goals without touching the “main menu”. However, I concede that Hamburgers are now mainstream UI. Jason Bradberry makes a compelling case . This month I redesigned my website . Taking the menu off-canvas at all breakpoints was a painful decision. I’m still not at peace with it. I don’t like plain icons. To somewhat appease my anguish I added big bold “Menu” text. The HTML for the button is pure declarative goodness. I added an extra “open” prefix for assistive tech. Aside note: Ana Tudor asked do we still need all those “visually hidden” styles? I’m using them out of an abundance of caution but my feeling is that Ana is on to something. The menu HTML is just as clean. It’s that simple! I’ve only removed my opinionated class names I use to draw the rest of the owl . I’ll explain more of my style choices later. This technique uses the wonderful new Invoker Command API for interactivity. It is similar to the I mentioned earlier. With a real we get free focus management and more, as Chris Coyier explains . I made a basic CodePen demo for the code above. So here’s the bad news. Invoker commands are so new they must be polyfilled for old browsers. Good news; you don’t need a hefty script. Feature detection isn’t strictly necessary. Keith Cirkel has a more extensive polyfill if you need full API coverage like JavaScript events. My basic version overrides the declarative API with the JavaScript API for one specific use case, and the behaviour remains the same. Let’s get into CSS by starting with my favourite: A strong contrast outline around buttons and links with room to breath. This is not typically visible for pointer events. For other interactions like keyboard navigation it’s visible. The first button inside the dialog, i.e. “Close (menu)”, is naturally given focus by the browser (focus is ‘trapped’ inside the dialog). In most browsers focus remains invisible for pointer events. WebKit has bug. When using or invoker commands the style is visible on the close button for pointer events. This seems wrong, it’s inconsistent, and clients absolutely rage at seeing “ugly” focus — seriously, what is their problem?! I think I’ve found a reliable ‘fix’. Please do not copy this untested . From my limited testing with Apple devices and macOS VoiceOver I found no adverse effects. Below I’ve expanded the ‘not open’ condition within the event listener. First I confirm the event is relevant. I can’t check for an instance of because of the handler. I’d have to listen for keyboard events and that gets murky. Then I check if the focused element has the visible style. If both conditions are true, I remove and reapply focus in a non-visible manner. The boolean is Safari 18.4 onwards. Like I said: extreme caution! But I believe this fixes WebKit’s inconsistency. Feedback is very welcome. I’ll update here if concerns are raised. Native dialog elements allow us to press the ESC key to dismiss them. What about clicking the backdrop? We must opt-in to this behaviour with the attribute. Chris Ferdinandi has written about this and the JavaScript fallback . That’s enough JavaScript! My menu uses a combination of both basic CSS transitions and cross-document view transitions . For on-page transitions I use the setup below. As an example here I fade opacity in and out. How you choose to use nesting selectors and the rule is a matter of taste. I like my at-rules top level. My menu also transitions out when a link is clicked. This does not trigger the closing dialog event. Instead the closing transition is mirrored by a cross-document view transition. The example below handles the fade out for page transitions. Note that I only transition the old view state for the closing menu. The new state is hidden (“off-canvas”). Technically it should be possible to use view transitions to achieve the on-page open and close effects too. I’ve personally found browsers to still be a little janky around view transitions — bugs, or skill issue? It’s probably best to wrap a media query around transitions. “Reduced” is a significant word. It does not mean “no motion”. That said, I have no idea how to assess what is adequately reduced! No motion is a safe bet… I think? So there we have it! Declarative dialog menu with invoker commands, topped with a medley of CSS transitions and a sprinkle of almost optional JavaScript. Aren’t modern web standards wonderful, when they work? I can’t end this topic without mentioning Jim Nielsen’s menu . I won’t spoil the fun, take a look! When I realised how it works, my first reaction was “is that allowed?!” It work’s remarkably well for Jim’s blog. I don’t recall seeing that idea in the wild elsewhere. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views

The LLM Context Tax: Best Tips for Tax Avoidance

Every token you send to an LLM costs money. Every token increases latency. And past a certain point, every additional token makes your agent dumber. This is the triple penalty of context bloat: higher costs, slower responses, and degraded performance through context rot, where the agent gets lost in its own accumulated noise. Context engineering is very important. The difference between a $0.50 query and a $5.00 query is often just how thoughtfully you manage context. Here’s what I’ll cover: Stable Prefixes for KV Cache Hits - The single most important optimization for production agents Append-Only Context - Why mutating context destroys your cache hit rate Store Tool Outputs in the Filesystem - Cursor’s approach to avoiding context bloat Design Precise Tools - How smart tool design reduces token consumption by 10x Clean Your Data First (Maximize Your Deductions) - Strip the garbage before it enters context Delegate to Cheaper Subagents (Offshore to Tax Havens) - Route token-heavy operations to smaller models Reusable Templates Over Regeneration (Standard Deductions) - Stop regenerating the same code The Lost-in-the-Middle Problem - Strategic placement of critical information Server-Side Compaction (Depreciation) - Let the API handle context decay automatically Output Token Budgeting (Withholding Tax) - The most expensive tokens are the ones you generate The 200K Pricing Cliff (The Tax Bracket) - The tax bracket that doubles your bill overnight Parallel Tool Calls (Filing Jointly) - Fewer round trips, less context accumulation Application-Level Response Caching (Tax-Exempt Status) - The cheapest token is the one you never send With Claude Opus 4.6, the math is brutal: That’s a 10x difference between cached and uncached inputs. Output tokens cost 5x more than uncached inputs. Most agent builders focus on prompt engineering while hemorrhaging money on context inefficiency. In most agent workflows, context grows substantially with each step while outputs remain compact. This makes input token optimization critical: a typical agent task might involve 50 tool calls, each accumulating context. The performance penalty is equally severe. Research shows that past 32K tokens, most models show sharp performance degradation. Your agent isn’t just getting expensive. It’s getting confused. This is the single most important metric for production agents: KV cache hit rate. The Manus team considers this the most important optimization for their agent infrastructure, and I agree completely. The principle is simple: LLMs process prompts autoregressively, token by token. If your prompt starts identically to a previous request, the model can reuse cached key-value computations for that prefix. The killer of cache hit rates? Timestamps. A common mistake is including a timestamp at the beginning of the system prompt. It’s a simple mistake but the impact is massive. The key is granularity: including the date is fine. Including the hour is acceptable since cache durations are typically 5 minutes (Anthropic default) to 10 minutes (OpenAI default), with longer options available. But never include seconds or milliseconds. A timestamp precise to the second guarantees every single request has a unique prefix. Zero cache hits. Maximum cost. Move all dynamic content (including timestamps) to the END of your prompt. System instructions, tool definitions, few-shot examples, all of these should come first and remain identical across requests. For distributed systems, ensure consistent request routing. Use session IDs to route requests to the same worker, maximizing the chance of hitting warm caches. Context should be append-only. Any modification to earlier content invalidates the KV cache from that point forward. This seems obvious but the violations are subtle: The tool definition problem is particularly insidious. If you dynamically add or remove tools based on context, you invalidate the cache for everything after the tool definitions. Manus solved this elegantly: instead of removing tools, they mask token logits during decoding to constrain which actions the model can select. The tool definitions stay constant (cache preserved), but the model is guided toward valid choices through output constraints. For simpler implementations, keep your tool definitions static and handle invalid tool calls gracefully in your orchestration layer. Deterministic serialization matters too. Python dicts don’t guarantee order. If you’re serializing tool definitions or context as JSON, use sort_keys=True or a library that guarantees deterministic output. A different key order = different tokens = cache miss. Cursor’s approach to context management changed how I think about agent architecture. Instead of stuffing tool outputs into the conversation, write them to files. In their A/B testing, this reduced total agent tokens by 46.9% for runs using MCP tools. The insight: agents don’t need complete information upfront. They need the ability to access information on demand. Files are the perfect abstraction for this. We apply this pattern everywhere: Shell command outputs : Write to files, let agent tail or grep as needed Search results : Return file paths, not full document contents API responses : Store raw responses, let agent extract what matters Intermediate computations : Persist to disk, reference by path When context windows fill up, Cursor triggers a summarization step but exposes chat history as files. The agent can search through past conversations to recover details lost in the lossy compression. Clever. A vague tool returns everything. A precise tool returns exactly what the agent needs. Consider an email search tool: The two-phase pattern: search returns metadata, separate tool returns full content. The agent decides which items deserve full retrieval. This is exactly how our conversation history tool works at Fintool. It passes date ranges or search terms and returns up to 100-200 results with only user messages and metadata. The agent then reads specific conversations by passing the conversation ID. Filter parameters like has_attachment, time_range, and sender let the agent narrow results before reading anything. The same pattern applies everywhere: Document search : Return titles and snippets, not full documents Database queries : Return row counts and sample rows, not full result sets File listings : Return paths and metadata, not contents API integrations : Return summaries, let agent drill down Each parameter you add to a tool is a chance to reduce returned tokens by an order of magnitude. Garbage tokens are still tokens. Clean your data before it enters context. For emails, this means: For HTML content, the gains are even larger. A typical webpage might be 100KB of HTML but only 5KB of actual content. CSS selectors that extract semantic regions (article, main, section) and discard navigation, ads, and tracking can reduce token counts by 90%+. Markdown uses significantly fewer tokens than HTML , making conversion valuable for any web content entering your pipeline. For financial data specifically: Strip SEC filing boilerplate (every 10-K has the same legal disclaimers) Collapse repeated table headers across pages Remove watermarks and page numbers from extracted text Normalize whitespace (multiple spaces, tabs, excessive newlines) Convert HTML tables to markdown tables The principle: remove noise at the earliest possible stage, not after tokenization. Every preprocessing step that runs before the LLM call saves money and improves quality. Not every task needs your most expensive model. The Claude Code subagent pattern processes 67% fewer tokens overall due to context isolation. Instead of stuffing every intermediate search result into a single global context, workers keep only what’s relevant inside their own window and return distilled outputs. Tasks perfect for cheaper subagents: Data extraction : Pull specific fields from documents Classification : Categorize emails, documents, or intents Summarization : Compress long documents before main agent sees them Validation : Check outputs against criteria Formatting : Convert between data formats The orchestrator sees condensed results, not raw context. This prevents hitting context limits and reduces the risk of the main agent getting confused by irrelevant details. Scope subagent tasks tightly. The more iterations a subagent requires, the more context it accumulates and the more tokens it consumes. Design for single-turn completion when possible. Every time an agent generates code from scratch, you’re paying for output tokens. Output tokens cost 5x input tokens with Claude. Stop regenerating the same patterns. Our document generation workflow used to be painfully inefficient: OLD APPROACH: User: “Create a DCF model for Apple” Agent: *generates 2,000 lines of Excel formulas from scratch* Cost: ~$0.50 in output tokens alone NEW APPROACH: User: “Create a DCF model for Apple” Agent: *loads DCF template, fills in Apple-specific values* Cost: ~$0.05 The template approach: Skill references template : dcf_template.xlsx in /public/skills/dcf/ Agent reads template once : Understands structure and placeholders Agent fills parameters : Company-specific values, assumptions WriteFile with minimal changes : Only modified cells, not full regeneration For code generation, the same principle applies. If your agent frequently generates similar Python scripts, data processing pipelines, or analysis frameworks, create reusable functions: # Instead of regenerating this every time: def process_earnings_transcript(path): # 50 lines of parsing code... # Reference a skill with reusable utilities: from skills.earnings import parse_transcript, extract_guidance The agent imports and calls rather than regenerates. Fewer output tokens, faster responses, more consistent results. Subscribe now LLMs don’t process context uniformly. Research shows a consistent U-shaped attention pattern: models attend strongly to the beginning and end of prompts while “losing” information in the middle. Strategic placement matters: System instructions : Beginning (highest attention) Current user request : End (recency bias) Critical context : Beginning or end, never middle Lower-priority background : Middle (acceptable loss) For retrieval-augmented generation, this means reordering retrieved documents. The most relevant chunks should go at the beginning and end. Lower-ranked chunks fill the middle. Manus uses an elegant hack: they maintain a todo.md file that gets updated throughout task execution. This “recites” current objectives at the end of context, combating the lost-in-the-middle effect across their typical 50-tool-call trajectories. We use a similar architecture at Fintool. As agents run, context grows until it hits the window limit. You used to have two options: build your own summarization pipeline, or implement observation masking (replacing old tool outputs with placeholders). Both require significant engineering. Now you can let the API handle it. Anthropic’s server-side compaction automatically summarizes your conversation when it approaches a configurable token threshold. Claude Code uses this internally, and it’s the reason you can run 50+ tool call sessions without the agent losing track of what it’s doing. The key design decisions: Trigger threshold : Default is 150K tokens. Set it lower if you want to stay under the 200K pricing cliff, or higher if you need more raw context before summarizing. Custom instructions : You can replace the default summarization prompt entirely. For financial workflows, something like “Preserve all numerical data, company names, and analytical conclusions” prevents the summary from losing critical details. Pause after compaction : The API can pause after generating the summary, letting you inject additional context (like preserving the last few messages verbatim) before continuing. This gives you control over what survives the compression. Compaction also stacks well with prompt caching. Add a cache breakpoint on your system prompt so it stays cached separately. When compaction occurs, only the summary needs to be written as a new cache entry. Your system prompt cache stays warm. The beauty of this approach: context depreciates in value over time, and the API handles the depreciation schedule for you. Output tokens are the most expensive tokens. With Claude Sonnet, outputs cost 5x inputs. With Opus, they cost 5x inputs that are already expensive. Yet most developers leave max_tokens unlimited and hope for the best. # BAD: Unlimited output response = client.messages.create( model=”claude-sonnet-4-20250514”, max_tokens=8192, # Model might use all of this messages=[...] ) # GOOD: Task-appropriate limits TASK_LIMITS = { “classification”: 50, “extraction”: 200, “short_answer”: 500, “analysis”: 2000, “code_generation”: 4000, } Structured outputs reduce verbosity. JSON responses use fewer tokens than natural language explanations of the same information. Natural language: “The company’s revenue was 94.5 billion dollars, which represents a year-over-year increase of 12.3 percent compared to the previous fiscal year’s revenue of 84.2 billion dollars.” Structured: {”revenue”: 94.5, “unit”: “B”, “yoy_change”: 12.3} For agents specifically, consider response chunking. Instead of generating a 10,000-token analysis in one shot, break it into phases: Outline phase : Generate structure (500 tokens) Section phases : Generate each section on demand (1000 tokens each) Review phase : Check and refine (500 tokens) This gives you control points to stop early if the user has what they need, rather than always generating the maximum possible output. With Claude Opus 4.6 and Sonnet 4.5, crossing 200K input tokens triggers premium pricing. Your per-token cost doubles: Opus goes from $5 to $10 per million input tokens, and output jumps from $25 to $37.50. This isn’t gradual. It’s a cliff. This is the LLM equivalent of a tax bracket. And just like tax planning, the right strategy is to stay under the threshold when you can. For agent workflows that risk crossing 200K, implement a context budget. Track cumulative input tokens across tool calls. When you approach the cliff, trigger aggressive compression: observation masking, summarization of older turns, or pruning low-value context. The cost of a compression step is far less than doubling your per-token rate for the rest of the conversation. Every sequential tool call is a round trip. Each round trip re-sends the full conversation context. If your agent makes 20 tool calls sequentially, that’s 20 times the context gets transmitted and billed. The Anthropic API supports parallel tool calls: the model can request multiple independent tool calls in a single response, and you execute them simultaneously. This means fewer round trips for the same amount of work. The savings compound. With fewer round trips, you accumulate less intermediate context, which means each subsequent round trip is also cheaper. Design your tools so that independent operations can be identified and batched by the model. The cheapest token is the one you never send to the API. Before any LLM call, check if you’ve already answered this question. At Fintool, we cache aggressively for earnings call summarizations and common queries. When a user asks for Apple’s latest earnings summary, we don’t regenerate it from scratch for every request. The first request pays the full cost. Every subsequent request is essentially free. This operates above the LLM layer entirely. It’s not prompt caching or KV cache. It’s your application deciding that this query has a valid cached response and short-circuiting the API call. Good candidates for application-level caching: Factual lookups : Company financials, earnings summaries, SEC filings Common queries : Questions that many users ask about the same data Deterministic transformations : Data formatting, unit conversions Stable analysis : Any output that won’t change until the underlying data changes The cache invalidation strategy matters. For financial data, earnings call summaries are stable once generated. Real-time price data obviously isn’t. Match your cache TTL to the volatility of the underlying data. Even partial caching helps. If an agent task involves five tool calls and you can cache two of them, you’ve cut 40% of your tool-related token costs without touching the LLM. The Meta Lesson Context engineering isn’t glamorous. It’s not the exciting part of building agents. But it’s the difference between a demo that impresses and a product that scales with decent gross margin. The best teams building sustainable agent products are obsessing over token efficiency the same way database engineers obsess over query optimization. Because at scale, every wasted token is money on fire. The context tax is real. But with the right architecture, it’s largely avoidable. Subscribe now Every token you send to an LLM costs money. Every token increases latency. And past a certain point, every additional token makes your agent dumber. This is the triple penalty of context bloat: higher costs, slower responses, and degraded performance through context rot, where the agent gets lost in its own accumulated noise. Context engineering is very important. The difference between a $0.50 query and a $5.00 query is often just how thoughtfully you manage context. Here’s what I’ll cover: Stable Prefixes for KV Cache Hits - The single most important optimization for production agents Append-Only Context - Why mutating context destroys your cache hit rate Store Tool Outputs in the Filesystem - Cursor’s approach to avoiding context bloat Design Precise Tools - How smart tool design reduces token consumption by 10x Clean Your Data First (Maximize Your Deductions) - Strip the garbage before it enters context Delegate to Cheaper Subagents (Offshore to Tax Havens) - Route token-heavy operations to smaller models Reusable Templates Over Regeneration (Standard Deductions) - Stop regenerating the same code The Lost-in-the-Middle Problem - Strategic placement of critical information Server-Side Compaction (Depreciation) - Let the API handle context decay automatically Output Token Budgeting (Withholding Tax) - The most expensive tokens are the ones you generate The 200K Pricing Cliff (The Tax Bracket) - The tax bracket that doubles your bill overnight Parallel Tool Calls (Filing Jointly) - Fewer round trips, less context accumulation Application-Level Response Caching (Tax-Exempt Status) - The cheapest token is the one you never send That’s a 10x difference between cached and uncached inputs. Output tokens cost 5x more than uncached inputs. Most agent builders focus on prompt engineering while hemorrhaging money on context inefficiency. In most agent workflows, context grows substantially with each step while outputs remain compact. This makes input token optimization critical: a typical agent task might involve 50 tool calls, each accumulating context. The performance penalty is equally severe. Research shows that past 32K tokens, most models show sharp performance degradation. Your agent isn’t just getting expensive. It’s getting confused. Stable Prefixes for KV Cache Hits This is the single most important metric for production agents: KV cache hit rate. The Manus team considers this the most important optimization for their agent infrastructure, and I agree completely. The principle is simple: LLMs process prompts autoregressively, token by token. If your prompt starts identically to a previous request, the model can reuse cached key-value computations for that prefix. The killer of cache hit rates? Timestamps. A common mistake is including a timestamp at the beginning of the system prompt. It’s a simple mistake but the impact is massive. The key is granularity: including the date is fine. Including the hour is acceptable since cache durations are typically 5 minutes (Anthropic default) to 10 minutes (OpenAI default), with longer options available. But never include seconds or milliseconds. A timestamp precise to the second guarantees every single request has a unique prefix. Zero cache hits. Maximum cost. Move all dynamic content (including timestamps) to the END of your prompt. System instructions, tool definitions, few-shot examples, all of these should come first and remain identical across requests. For distributed systems, ensure consistent request routing. Use session IDs to route requests to the same worker, maximizing the chance of hitting warm caches. Append-Only Context Context should be append-only. Any modification to earlier content invalidates the KV cache from that point forward. This seems obvious but the violations are subtle: The tool definition problem is particularly insidious. If you dynamically add or remove tools based on context, you invalidate the cache for everything after the tool definitions. Manus solved this elegantly: instead of removing tools, they mask token logits during decoding to constrain which actions the model can select. The tool definitions stay constant (cache preserved), but the model is guided toward valid choices through output constraints. For simpler implementations, keep your tool definitions static and handle invalid tool calls gracefully in your orchestration layer. Deterministic serialization matters too. Python dicts don’t guarantee order. If you’re serializing tool definitions or context as JSON, use sort_keys=True or a library that guarantees deterministic output. A different key order = different tokens = cache miss. Store Tool Outputs in the Filesystem Cursor’s approach to context management changed how I think about agent architecture. Instead of stuffing tool outputs into the conversation, write them to files. In their A/B testing, this reduced total agent tokens by 46.9% for runs using MCP tools. The insight: agents don’t need complete information upfront. They need the ability to access information on demand. Files are the perfect abstraction for this. We apply this pattern everywhere: Shell command outputs : Write to files, let agent tail or grep as needed Search results : Return file paths, not full document contents API responses : Store raw responses, let agent extract what matters Intermediate computations : Persist to disk, reference by path The two-phase pattern: search returns metadata, separate tool returns full content. The agent decides which items deserve full retrieval. This is exactly how our conversation history tool works at Fintool. It passes date ranges or search terms and returns up to 100-200 results with only user messages and metadata. The agent then reads specific conversations by passing the conversation ID. Filter parameters like has_attachment, time_range, and sender let the agent narrow results before reading anything. The same pattern applies everywhere: Document search : Return titles and snippets, not full documents Database queries : Return row counts and sample rows, not full result sets File listings : Return paths and metadata, not contents API integrations : Return summaries, let agent drill down For HTML content, the gains are even larger. A typical webpage might be 100KB of HTML but only 5KB of actual content. CSS selectors that extract semantic regions (article, main, section) and discard navigation, ads, and tracking can reduce token counts by 90%+. Markdown uses significantly fewer tokens than HTML , making conversion valuable for any web content entering your pipeline. For financial data specifically: Strip SEC filing boilerplate (every 10-K has the same legal disclaimers) Collapse repeated table headers across pages Remove watermarks and page numbers from extracted text Normalize whitespace (multiple spaces, tabs, excessive newlines) Convert HTML tables to markdown tables The Claude Code subagent pattern processes 67% fewer tokens overall due to context isolation. Instead of stuffing every intermediate search result into a single global context, workers keep only what’s relevant inside their own window and return distilled outputs. Tasks perfect for cheaper subagents: Data extraction : Pull specific fields from documents Classification : Categorize emails, documents, or intents Summarization : Compress long documents before main agent sees them Validation : Check outputs against criteria Formatting : Convert between data formats Scope subagent tasks tightly. The more iterations a subagent requires, the more context it accumulates and the more tokens it consumes. Design for single-turn completion when possible. Reusable Templates Over Regeneration (Standard Deductions) Every time an agent generates code from scratch, you’re paying for output tokens. Output tokens cost 5x input tokens with Claude. Stop regenerating the same patterns. Our document generation workflow used to be painfully inefficient: OLD APPROACH: User: “Create a DCF model for Apple” Agent: *generates 2,000 lines of Excel formulas from scratch* Cost: ~$0.50 in output tokens alone NEW APPROACH: User: “Create a DCF model for Apple” Agent: *loads DCF template, fills in Apple-specific values* Cost: ~$0.05 The template approach: Skill references template : dcf_template.xlsx in /public/skills/dcf/ Agent reads template once : Understands structure and placeholders Agent fills parameters : Company-specific values, assumptions WriteFile with minimal changes : Only modified cells, not full regeneration Strategic placement matters: System instructions : Beginning (highest attention) Current user request : End (recency bias) Critical context : Beginning or end, never middle Lower-priority background : Middle (acceptable loss) The key design decisions: Trigger threshold : Default is 150K tokens. Set it lower if you want to stay under the 200K pricing cliff, or higher if you need more raw context before summarizing. Custom instructions : You can replace the default summarization prompt entirely. For financial workflows, something like “Preserve all numerical data, company names, and analytical conclusions” prevents the summary from losing critical details. Pause after compaction : The API can pause after generating the summary, letting you inject additional context (like preserving the last few messages verbatim) before continuing. This gives you control over what survives the compression. Outline phase : Generate structure (500 tokens) Section phases : Generate each section on demand (1000 tokens each) Review phase : Check and refine (500 tokens) This is the LLM equivalent of a tax bracket. And just like tax planning, the right strategy is to stay under the threshold when you can. For agent workflows that risk crossing 200K, implement a context budget. Track cumulative input tokens across tool calls. When you approach the cliff, trigger aggressive compression: observation masking, summarization of older turns, or pruning low-value context. The cost of a compression step is far less than doubling your per-token rate for the rest of the conversation. Parallel Tool Calls (Filing Jointly) Every sequential tool call is a round trip. Each round trip re-sends the full conversation context. If your agent makes 20 tool calls sequentially, that’s 20 times the context gets transmitted and billed. The Anthropic API supports parallel tool calls: the model can request multiple independent tool calls in a single response, and you execute them simultaneously. This means fewer round trips for the same amount of work. The savings compound. With fewer round trips, you accumulate less intermediate context, which means each subsequent round trip is also cheaper. Design your tools so that independent operations can be identified and batched by the model. Application-Level Response Caching (Tax-Exempt Status) The cheapest token is the one you never send to the API. Before any LLM call, check if you’ve already answered this question. At Fintool, we cache aggressively for earnings call summarizations and common queries. When a user asks for Apple’s latest earnings summary, we don’t regenerate it from scratch for every request. The first request pays the full cost. Every subsequent request is essentially free. This operates above the LLM layer entirely. It’s not prompt caching or KV cache. It’s your application deciding that this query has a valid cached response and short-circuiting the API call. Good candidates for application-level caching: Factual lookups : Company financials, earnings summaries, SEC filings Common queries : Questions that many users ask about the same data Deterministic transformations : Data formatting, unit conversions Stable analysis : Any output that won’t change until the underlying data changes

1 views
fLaMEd fury 2 weeks ago

The Summer Took Hold

What’s going on, Internet? I was going to have this post as the December wrap up post but the summer took hold of me and here we are at the end of January and a week into Feb, lol. December kicked off with a Tuesday night gig, Lewis Capaldi At The Spark Arena , a fantastic show. I finished off a post about what music ownership means to me , I was happy to get that one out of drafts and published. Then we were straight into finishing up work for the year and I took some time to reflect on the beers I drunk , the books I read , and the music I enjoyed throughout the year. Christmas was an exciting time. With a four year old and a two year old we were in full hype mode. I also got into the hype and had a blast. We had a pre-Christmas lunch at my brother’s place with his family and my parents, two days of work and then straight into Christmas Eve prep which we had at my parent-in-law’s place with the kids, their aunties and all their grandparents. They actually managed to go to sleep and woke up super excited and we got to do it all over again on Christmas Day. I braved the mall on Boxing Day and managed to pick up the last copy of the 2025 Indie Store exclusive re-issue of Get Rich Or Die Tryin’ pressed on red vinyl. The mall itself wasn’t too bad, but the traffic into the mall was horrific. Worth it though. With Christmas out of the way we had a couple days down time before we started our road trip down south. This was so much fun. Our end destination was the Marlborough Sounds, and we broke the trip up into stages so we could explore some of the country and also make sure that the kids weren’t stuck in a car non-stop for days on end. On day one we headed to the Hawke’s Bay via Orakei Korako Cave & Geothermal Park . We stayed one night in Havelock North and visited the national aquarium in Napier before continuing on to Martinborough where we spent two nights. The kids got some grandparent time and my wife and I managed to head over the hill to Wellington to catch up with some friends. On New Year’s Eve we packed up the car again and made our way with the kids to the ferry terminal in Wellington to cross the Cook Strait and make the drive to a remote part of the Marlborough Sounds . After four nights down there enjoying the remote tranquility of the top of the South Island, we headed back to the ferry terminal in Picton to catch the boat back to Wellington and drove straight back to Martinborough for a week of working remote rather than cutting the road trip short. We then packed the car up for a final time and made our way back up north, back to Havelock North again for one more night. Before heading north again the next morning we took the kids to Splash Planet and had a fun time in the water and playing mini golf. We stopped off in Hastings for some ice cream before heading back to Taupō where we stopped off at the Hooker Falls and Cobb & Co for dinner. My wife and I have great memories of family dinners and birthday parties at the Cobb and were hoping the kids would have a blast, but I think they were over it and were just tired. Luckily it was only three more hours back to Tāmaki Makaurau so I made the drive home while the family slept. Then it was back home to unpack and get back to the reality of the weekly grind of school and work. What an epic road trip though. I look forward to more of them, and they’ll only get better as the kids get older. I’ve been watching a lot of great shows recently, old and new. I saw Tulsa King on Cory’s website, gave it a go and ended up watching the entirety of season one over a couple days. I’m going to get right onto season two as soon as I can. The second season of The Vince Staples Show was like a fever dream. Short episodes, easy to watch. My favourite universe, the Power Universe had season three of Power Book IV: Force on the screen and I loved it. It’s so over the top and the premise is wild. Great end to the series and looking forward to Power Book Legacy! I watched all four episodes of Sean Combs: The Reckoning - it really shows what a psycho that guy is. The fourth season of Industry has started and I’m watching my way through that, I have no idea if I actually like this show anymore - it’s kinda fever dream like itself, but I’ll keep watching it. Shrinking is back for its third season. And finally A Knight of the Seven Kingdoms started, I loved the books and I’m loving this show. Set a hundred years before the events of A Song Of Ice And Fire, it’s a bit more lighthearted and funny than Game Of Thrones was. Been a good run of movie watching over here recently. Partly due to Mr 4 taking more of an interest in them. He’d been coming home from preschool talking about KPop Demon Hunters , and we’d been listening to the music and so we sat down and watched the movie together one afternoon. I really enjoyed it. He did too. He’s also been into Paw Patrol recently so as a treat he’s been able to watch some of the Paw Patrol movies starting with PAW Patrol: The Movie , which I also ended up really enjoying. Surprising at the big names doing the voices. Totally different to the budget voices on the Tonies 🤣 So yeah, the movie was really good, although he got quite upset when Chase lost his confidence. It was cute. Christmas was also a bigger than usual thing in our household this year and so on Christmas Eve we all sat down together and watched Home Alone with him. A fun movie which he enjoyed, and maybe laughed a bit too hard at parts. When the kids did eventually go to bed I enjoyed the annual screening of The Guardians of the Galaxy Holiday Special . During the roadtrip we stayed at a motel on the way down south and we took advantage of the yearly screening of Grease - one of my all time favourite movies. After the kids sleeping for hours in the car we knew they weren’t going to bed easily so we had a family movie night. Grease isn’t a kids movie, but it’s also quite tame compared to movies today. I enjoyed it, they enjoyed it and we all had a good time, and they eventually went to sleep. The other movies I enjoyed were Woodstock 99 which dove into the absolute state of the 99 Woodstock festival and how it eventually turned into what it was. What a shit time that would have been. On the lighter side I enjoyed Good Fortune and then Shithouse , which has a shit name, but explored the isolating side of social interaction. Eleven records added to the collection across December and January. A lot of anniversary editions and special pressings landed on the shelf. Here’s all the posts I enjoyed recently. You can check out more over on the Bookmarks archive. Shellsharks is back and publishing Scrolls again so go check that out. Hyde is still publishing his Over/Under series and has just published issue #50 with Bobby Hiltz . I really love the way Hyde personalises each Over/Under interview with his guest - it makes for an interesting read and shows that he does go out of his way to read their websites. xandra has also just dropped the Autumn/Winter 2026 issue of Good Internet magazine. I can’t wait to get stuck in and read all the new articles while I wait for my physical edition to arrive. Plenty of hacking on the website over the break. I’ve been messing with the homepage layout. I’m still not entirely happy with the bento, but it’s fine for now. I’ve added a “Stuck In My Head” section that highlights the six most played songs from last.fm . I’ve also moved the webrings into the bento and revived my buttons collection - I’ve got more to add here later. I’ve started adding garden indicators for living posts that I intend to keep working on over time. I will eventually create a /garden/ page to list these pages for easy browsing. I guess that tag page serves that purpose at the moment. Along with that I think I’ve improved the post metadata on each post that helps tell the story better with category, tags, and dates. Let me know what you think. I spent some (a lot) of time unifying the look and feel across Beer Fridge , Recordshelf , Bookshelf , and Comics pages with cleaned up CSS and introducing a common layout for the stat cards. That damn comics page needs a lot of work. This update was brought to you by Girl in Stilettos by Annah Mac Hey, thanks for reading this post in your feed reader! Want to chat? Reply by email or add me on XMPP , or send a webmention . Check out the posts archive on the website. App selection criteria - Cory Dransfeldt on his criteria for choosing apps. Delete Spotify? Sure, But Don’t Just Replace it With Another Subscription - Stephanie Vee on thinking beyond just swapping one subscription for another. Why RSS matters - Ben Werdmuller on why RSS still matters. What happened to the comment section? - The History of the Web looks at what happened to comment sections. Three Predictions For The Web - Three predictions for the future of the web. IndieWeb Carnival December 2025 – The IndieWeb in 2030 - The Frugal Gamer hosts the December 2025 IndieWeb Carnival. Static sites killed the blog comment star - Did static sites kill blog comments, and can old tech bring them back? An Island in the Net in 2030? - Khürt Williams imagines the IndieWeb in 2030. Drinking The Largest Beer At The Airport Makes Everything Better - A celebration of the airport beer. Backing up Spotify - How to back up your Spotify library. 30 Years of br Tags - A look back at 30 years of the humble tag. Looking beyond collective blogging - V.H. Belvadi looks at what comes after collective blogging. Readers, writers and blogging ethics - On saying what you mean and being damned. How and Why Do I Blog? - Reflections on the how and why of blogging. Building an IndieWeb house (I): introduction - Starting the journey of building an IndieWeb house. The IndieWeb Doesn’t Need to ‘Take Off’ - Susam Pal on why the IndieWeb doesn’t need mass adoption. Experiences with social medias - Reflections on experiences with social media. Writing Hyperlinks: Salient, Descriptive, Start with Keyword - Nielsen Norman Group on writing better hyperlinks. Why 90s Movies Feel More Alive Than Anything on Netflix - Why 90s movies hit different. You should start a blog today - A nudge to start blogging. Self-hosting versus lots of small indieweb providers - The trade-offs between self-hosting and using small IndieWeb providers.

0 views
David Bushell 2 weeks ago

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
iDiallo 2 weeks ago

Microsoft Should Watch The Expanse

My favorite piece of technology in science fiction isn't lightsabers, flying spaceships, or even robots. It's AI. But not just any AI. My favorite is the one in the TV show The Expanse . If you watch The Expanse, the most advanced technology is, of course, the Epstein drive (an unfortunate name in this day and age). In their universe, humanity can travel to distant planets, the Belt, and Mars. Mars has the most high-tech military, which is incredibly cool. But the AI is still what impresses me most. If you watched the show, you're probably wondering what the hell I'm talking about right now. Because there is no mention of AI ever. The AI is barely visible. In fact, it's not visible at all. Most of the time, there aren't even voices. Instead, their computer interfaces respond directly to voice and gesture commands without returning any sass. In Season 1, Miller (the detective) is trying to solve a crime. Out of the blue, he just says, "Plot the course the Scopuli took over the past months." The course is plotted right there in his living room. No fuss, no interruptions, no "OK Google." And when he finally figures it out, no one says "You are absolutely right!" He then interacts with the holographic display in real time, asking for additional information and manipulating the data with gestures. At no point does he anthropomorphize the AI. It's always there, always available, always listening, but it never interrupts. This type of interaction is present throughout the series. In the Rocinante, James Holden will give commands like "seal bulkhead," "plot intercept course," or "scan for life signs," and the ship's computer simply executes. There are no loading screens, no chatbot personality trying to be helpful. The computer doesn't explain what it's doing or ask for confirmation on routine tasks. It just works. When Holden needs tactical information during a firefight, he doesn't open an app or navigate menus. He shouts questions, and relevant data appears on his helmet display. When Naomi needs to calculate a complex orbital maneuver, she doesn't fight with an interface. She thinks out loud, and the system provides the calculations she needs. This is the complete opposite of Microsoft's Copilot... Yes, this is about Copilot. In Microsoft's vision, they think they're designing an AI assistant, an AI copilot that's always there to help. You have Copilot in Excel, in Edge, in the taskbar. It's everywhere, yet it's as useless as you can imagine. What is Copilot? Is it ChatGPT or a wrapper around it? Is it a code assistant? Is it a search engine? Or wait, is it all of Microsoft Office now? It's attached to every application, yet it hasn't been particularly helpful. We now use Teams at work, and I see Copilot popping up every time to offer to help me, just like Clippy. OK, fine, I asked for the meaning of a term I hear often in this company. Copilot doesn't know. Well, it doesn't say it doesn't know. Instead, it gives me the definition of what it thinks the term means in general. Imagine for a second you're a manager and you hear developers talking about issues with Apache delaying a project. You don't know what Apache is, so you ask Copilot. It tells you that the Apache are a group of Native American tribes known for their resilience in the Southwest. If you don't know any better, you might take that definition at face value, never knowing that Copilot has does not have access to any of the company data. Now in the project retro, you'll blame a native American tribe for delaying the project. Copilot is everywhere, yet it is nowhere. Nobody deliberately opens it to solve a problem. Instead, it's like Google Plus from back in the day. If you randomly clicked seven times on the web, you would somehow end up with a Google Plus account and, for some reason, two YouTube accounts. Copilot is visible when it should be invisible, and verbose when it should be silent. It interrupts your workflow to offer help you didn't ask for, then fails to provide useful answers when you actually need them. It's the opposite of the AI in The Expanse. It doesn't fade in the background. It is constantly reminding you that you need to use it here and now. In The Expanse , the AI doesn't have a personality because it doesn't need one. It's not trying to be your friend or impress you with its conversational abilities. It's a tool, refined to perfection. It is not trying to replace your job, it is there to support you. Copilot only exists to impress you, and it fails at it every single time. Satya should binge-watch The Expanse. I'm not advocating for AI everything, but I am all for creating useful tools. And Copilot, as it currently exists, is one of the least useful implementations of AI I've encountered. The best technology is invisible. It doesn't announce itself, doesn't demand attention, and doesn't try to be clever. It simply works when you need it and disappears when you don't. I know Microsoft won't read this or learn from it. Instead, I expect Windows 12 to be renamed Microsoft Copilot OS. In The Expanse, the AI turn people into heroes. In our world, Copilot, Gemini, ChatGPT, all want to be the heroes. And they will differentiate themselves by trying to be the loudest.

0 views
HeyDingus 2 weeks ago

7 Things This Week [#182]

A weekly list of interesting things I found on the internet, posted on Sundays. Sometimes themed, often not. 1️⃣ Jose Munoz has a good tip for not getting sucked into doom-scrolling apps by Siri Suggestions in Search and the App Library: simply hide them from those areas. [ 🔗 josemunozmatos.com ] 2️⃣ I love a good stats-based pitch. Herman provides one for the benefits of morning exercise. [ 🔗 herman.bearblog.dev ] 3️⃣ Jason Fried explains a clever design detail about the power reserve indicator on a mechanical watch. [ 🔗 world.hey.com ] 4️⃣ I found myself nodding along to Chris Coyier’s list of words you should probably avoid using in your writing. [ 🔗 css-tricks.com ] 5️⃣ I spent a surprising amount of time recently perusing the depths of Louie Mantia’s portfolio and blog after reading his People & Blogs interview . He’s worked on so many cool things, lots of which have touched my life. [ 🔗 lmnt.me ] 6️⃣ Robert Birming made me feel a little better about my less-than-tidy house. [ 🔗 robertbirming.com ] 7️⃣ I’m not going to buy it, but I’m certainly intrigued by this tiny eReader that attaches via MagSafe onto the back of your phone. I love my Kobo, but it so often gets left behind. This would be a remedy. [ 🔗 theverge.com ] Thanks for reading 7 Things . If you enjoyed these links or have something neat to share, please let me know . And remember that you can get more links to internet nuggets that I’m finding every day by following me @jarrod on the social web. HeyDingus is a blog by Jarrod Blundy about technology, the great outdoors, and other musings. If you like what you see — the blog posts , shortcuts , wallpapers , scripts , or anything — please consider leaving a tip , checking out my store , or just sharing my work. Your support is much appreciated! I’m always happy to hear from you on social , or by good ol' email .

0 views
Kev Quirk 3 weeks ago

I've Moved to Pure Blog!

In my last post I introduced Pure Blog and ended the post by saying: I'm going to take a little break from coding for a few days, then come back and start migrating this site over to Pure Blog. Dogfoodin' yo! Yeah, I didn't take a break. Instead I've pretty much spent my entire weekend at the computer migrating this site from Jekyll to Pure Blog, and trying to make sure everything works ok. Along the way there were features that I wanted to add into Pure Blog to make my live easier, which I've now done, these include: As well as all this, I've also changed the way Pure Blog is formatted so that it's easier for people to update their Pure Blog version. While I was there, I also added a simple little update page in settings so people can see if they're running the latest version or not: Finally, I decided to give the site a new lick of paint. Which was by far the easiest part of this whole thing - just some custom CSS in the CMS and I ended up with this nice (albeit brutal) new design. The way I've architected Pure Blog should allow me to very easily change the design going forward, which is just fantastic for a perpetual fiddler, such as myself. OK, that's enough for one weekend. I hope publishing this post doesn't bring any other issues to the surface, but we shall see. Now I really am going to take a break from coding. This has been so much fun, and I continue to learn a lot. For now though, my brain needs a rest. Oh, if you're using Pure Blog, please do let me know - I'd love to hear your feedback. The reply button below should be working fine. 🙃 Thanks for reading this post via RSS. RSS is great, and you're great for using it. ❤️ You can reply to this post by email , or leave a comment . Hooks so I can automatically purge Bunny CDN cache when posts are published/updated. Implementing data files so I can generate things like my Blogroll and Projects pages from YML lists. Adding shortcodes so I can have a site wide email setting and things like my Reply by email button works at the bottom of every post. Post layout partial so I can add custom content below my posts without moving away from Pure Blog's upstream code.

0 views
Jim Nielsen 4 weeks ago

The Browser’s Little White Lies

So I’m making a thing and I want it to be styled different if the link’s been visited. Rather than build something myself in JavaScript, I figure I’ll just hook into the browser’s mechanism for tracking if a link’s been visited (a sensible approach, if I do say so myself ). Why write JavaScript when a little CSS will do? So I craft this: But it doesn’t work. is relatively new, and I’ve been known to muff it, so it’s probably just a syntax issue. I start researching. Wouldn’t you know it? We can’t have nice things. doesn’t always work like you’d expect because we (not me, mind you) exploited it. Here’s MDN : You can style visited links, but there are limits to which styles you can use. While is not mentioned specifically, other tricks like sibling selectors are: When using a sibling selector, such as , the adjacent element ( in this example) is styled as though the link were unvisited. Why? You guessed it. Security and privacy reasons. If it were not so, somebody could come along with a little JavaScript and uncover a user’s browsing history (imagine, for example, setting styles for visited and unvisited links, then using and checking style computations). MDN says browsers tell little white lies: To preserve users' privacy, browsers lie to web applications under certain circumstances So, from what I can tell, when I write the browser is telling the engine that handles styling that all items have never been (even if they have been). So where does that leave me? Now I will abandon CSS and go use JavaScript for something only JavaScript can do. That’s a good reason for JS. Reply via: Email · Mastodon · Bluesky

0 views
JSLegendDev 1 months ago

You Should Make Web Games

I recently realized that if it weren’t for the fact that making games for the web was possible, I would have probably never tried game development and stuck with it. While reflecting why this was the case, I came to the conclusion that there are certain characteristics about the web that makes it an ideal platform for beginners and more experienced game developers. That’s why I’d like to convince you to start making web games if you’re not doing so already. A prevalent issue that occurs to most game devs is over-scoping. I recently came across a game dev youtuber who struggled to finish anything and jumped from one incomplete project to another. They were an Unreal Engine solo dev and it was clear that the projects they wanted to make were just too ambitious. When making games for the web, you’re pretty limited in what you can do graphics wise and even scope wise (assuming you don’t make a browser based MMO that relies on a server). For example, as long as you don’t rely on a server, a web game will usually save its data in the player’s browser local storage which gets cleared after a week or so of inactivity or when the browser cache is cleared by the user. Because of this, you’ll rarely, if ever, see someone making a game with above a couple of hours of playtime because they know they can’t rely on save data being reliably accessible. This dramatically reduces the scope expected of a web game. The fact that web games are mostly short experiences is freeing. You don’t have to worry that players will complain due to a lack of content and therefore, feel pressured to inflate the playtime. With this worry out of the way, you can quickly go from game idea to a completed project and move on to the next idea before you even have the chance to get bored of your previous one. Due to the small scale nature of web games, you can explore different genres easily before finding what you truly like making or what garners the most attention. This quick iteration possible with web games has a lot of similarities with making YouTube videos. You make a video, you upload it, check its stats, work on the next one where you can improve or try something different. If you use itch.io to host your games, you get basically the same experience, you get stats where you can see how many views your game has, how many browser plays, if there are any comments, ratings, etc… Therefore, you get a fast feedback loop which is incredibly motivating as a beginner. You can quickly incorporate improvements in your next projects. Having access to statistics allows you to know if you’re moving in the right direction. You might be wondering, how do you get feedback on web games if there are no algorithms like on YouTube to serve your game to a new audience? What if you don’t have a preexisting audience? It’s true that if you publish your game on itch.io outside of participating in a game jam, you’ll be launching to crickets. That said, I’d like to make the point that reaching players with a web game is still ridiculously easy even if you don’t have an audience. Let’s explore a few avenues you can try. Publishing your game on Newgrounds is an almost guaranteed way to get at least a few players. This is because, when publishing your game on this platform, it has to go through a rating process where the site puts your game in front of real users. After the rating process is done, you’ll get a score on 5 and a few comments. From there your game can either become more popular or stay as is. While this is a tech forum, people do share games on there from time to time and they do end up on the front page. Usually, people there are technical so if you can also mention how your game was built, you might get more attention. For example, mentioning the programming language, framework, engine, etc… in the title of the post. That said, this is not strictly necessary. When a link gets popular on Hacker News, you’ll often start seeing it shared elsewhere on your behalf, for example on Reddit, on X/Twitter, etc… this can transform into a snowball effect and make your game viral. It offers a dedicated subreddit for webgames like /r/WebGames where you can post a link to your game. However, try looking beyond that. For example, you can submit your game to /r/CozyGamers if you’re making a cozy game as long you follow the rules. There is also nothing preventing you from using YouTube and other social media platforms to promote your game. Making devlogs or videos showcasing your game and putting the link to play it in the description is a great way to find new players. That said, at this point, you’re building an audience. It might take a while to get traction but because these platforms have recommendation algorithms, at some point, some people will come across your game. As with your standard PC game, the success you’ll see using the avenues I just listed depends highly on how remarkable your game is. The strength of web games is that if you don’t see traction with one project you can quickly spin up a new one and the time you invested in building one is an order of magnitude less thant what it would take to make a Steam release. Anyway, once one of your web games goes viral, you can invest time in making an expanded version for Steam. This seems obvious. Most people don’t want to download a game from an unknown developer because the risk of getting hacked is high. In fact, the well known game marketing expert Chriz Zukowski mentions in his post about analyzing itch.io’s traffic that people are 3 times more likely to try your game if it’s playable on the web VS having to download it. The friction of a web game is near 0, you’ll get more people willing to try it which translates into more people giving feedback, more attention, etc… which will in turn make a beginner more encouraged to continue their game dev journey. This is also useful for more experienced developers to know which project is worth spending more time on. The web is also not just for completed games. Let’s say you’re having trouble finishing a project, you can still publish it as cool prototype and it will garner attention if it’s good. This will in turn maybe motivate you to push through or have a better idea of what to work on next. Contrast this with making the same project available only through a download. Nobody is going to install a 15 minute game or prototype. Most people who ridicule web games, probably think of mobile-y casual games you find on web portals that are played by children during their computer lab classes. While there are games that serve this purpose, it’s a huge mistake to view them as just that. Web games can also serve as a wonderful litmus test to determine which game ideas and concepts are worth investing time into for a full release on Steam. Web games are therefore, great for validation. Chris Zukowksi, the game marketing expert that I mentioned previously, confirmed that this strategy actually works really well. You can check out the post were he lays this out, here . Anyway, I’d like to emphasize that if you’re using web technologies (HTML/CSS/JS) to make web games, you’re not stuck on the web. The process of bringing a web game to Steam has never been easier. Before, you had to configure tools like Electron to build executables for Windows, Mac and Linux. A process that took time to get right. You also had to spend additional time to configure your game’s Steam integration so you could access features like Steam achievements. However, now there is a convenient tool called GemShell that comes with a one-click export feature to build for Windows/Mac/Linux all at once on the same machine and an easy integration with Steam. I have partnered with its developer, to offer you a 15% discount if you purchase the tool using the following link : https://l0om.itch.io/jslegend . To be completely transparent, if you end up purchasing GemShell using the link above, I’ll get a cut of that sale. That said, you can try the lite version for free first to see if this tool suits your needs. If you invest time in learning web technologies to make web games, the skills you’ll acquire will expand what you can build beyond just games. You’ll be able to build unique projects that sits between game development and web development. The most prominent example of this, are the kind of projects you can find on the famous neal.fun website. According to what I’ve found online, Neal uses the Vue.js JavaScript framework to build his unique games and interactive sites that go regularly viral online. For example, one of Neal’s project is a website in which you must prove you’re not a robot by completing a series of CAPTCHA mini games. Finally, nothing prevents you from using your web skills to build apps or game dev tools that can be easily shared with others. To conclude, making games for the web is an ideal way to get into and stick with game development because of the platform’s natural constraints which encourage small finishable projects allowing the developer room for experimentation. Since web games don’t require a download to try them, this makes it far easier to get your games in front of players even with no prior audience by sharing them on various platforms like Newgrounds, Hacker News, Reddit, etc... Therefore, you have a quick feedback loop through views, comments, ratings allowing you to remain motivated to continue your game dev journey. Finally, successful web games can serve as validation and be expanded into a full Steam releases. I hope you enjoyed this post, I recommend subscribing to not miss out on future releases. Subscribe now In the meantime, you can read the following :

0 views
Andy Bell 1 months ago

Fun shadow coding challenge

Timehop just reminded me of this prototype I made 8 years ago . Scroll it and you’ll see that the central light source (orange line) affects the shadow. CSS has come on a lot in those 8 years, so could you do better? Would love to see it, so let me know if you do .

0 views
Chris Coyier 1 months ago

Tubes

Me, Stacey, and Miriam kicking it talkabout about CSS Scope & Mixins: Daniel and I chattin’ about playing the long game

0 views