Latest Posts (20 found)

The Inference Shift

Read more of this content when you subscribe today. If you were looking for the ideal time to IPO, being a chip company in May 2026 is hard to beat. Reuters reported over the weekend : Cerebras Systems is set to raise the size and price of its initial public offering as soon as Monday, as demand for the artificial intelligence chipmaker’s shares continues to climb, two people familiar with the matter told Reuters on Sunday. The company is considering a new IPO price range of $150-$160 a share, up from $115-$125 a share, and raising the number of shares marketed to 30 million from 28 million, said the sources, who asked not to be identified because the information isn’t public yet. The fundamental driver of the ongoing surge in semiconductor stocks is, of course, AI, particularly the realization that agents are going to need a lot of compute . What Cerebras represents, however, is something broader: while the compute story for AI has been largely about GPUs, particularly from Nvidia, the future is going to look increasingly heterogeneous. The story of how Graphics Processing Units became the center of AI is a well-trodden one, but in brief: The number one use case for GPUs has been training, which stresses the third point in particular. While the calculations within each training step are massively parallel, the steps themselves are serial: every GPU has to share its results with every other GPU before the next step can begin. This is why a trillion-parameter model needs to fit in the aggregate memory of tens of thousands of GPUs that can communicate as one system. Nvidia dominates both problem spaces, first by securing HBM ahead of the rest of the industry, and second thanks to its investments in networking. Of course training isn’t the only AI workload: the other is inference. Inference has three main parts: The two decode steps alternate for every layer of the model (they’re interleaved, not in sequence), which is to say that decode is serial and memory-bandwidth bound. For every token generated, two distinct memory pools must be read: the KV cache, which stores context and grows with each token, and the model weights themselves. Both must be read in full to produce a single output token. GPUs handle all three needs: high compute for prefill, abundant HBM for KV cache and model weights, and chip-to-chip networking to pool memory across multiple chips when a single GPU isn’t enough. In other words, what works for training works for inference — look no further than the deal SpaceX made with Anthropic. From Anthropic’s blog : We’ve signed an agreement with SpaceX to use all of the compute capacity at their Colossus 1 data center. This gives us access to more than 300 megawatts of new capacity (over 220,000 NVIDIA GPUs) within the month. This additional capacity will directly improve capacity for Claude Pro and Claude Max subscribers. SpaceX retains Colossus 2 — presumably for both training of future models and inference of existing ones — and can afford to do both in the same data center precisely because xAI’s models aren’t getting much usage; more pertinently to this piece, they can do both in the same data center because both training and inference can be done on GPUs. Indeed, the GPUs Anthropic is contracting for at Colossus 1 were originally used for training as well; the fact that GPUs are so flexible is a big advantage. Cerebras makes something completely different. While a silicon wafer has a diameter of 300mm, the “reticle limit” — the maximum area that a lithography tool can expose on that wafer — is around 26mm x 33mm. This is the effective size limit for chips; going beyond that entails linking two separate chips together over a chip-to-chip interposer, which is exactly what Nvidia has done with the B200. Cerebras, on the other hand, has invented a way to lay down wiring across the so-called “scribe lines” that are the boundary between reticle exposures, making the entire wafer into a single chip with no need for relatively slow chip-to-chip linkages. The net result is a chip with a lot of compute and a lot of SRAM that is blisteringly fast to access. To put it in numbers, the WSE-3 (Cerebras’ latest chip) has 44GB of on-chip SRAM at 21 PB/s of bandwidth; an H100 has 80GB of HBM at 3.35 TB/s. In other words, the WSE-3 has just over half the memory of an H100, but 6,000 times the memory bandwidth. The reason to compare the WSE-3 to an H100 is that the H100 is the chip most used for inference — and inference is clearly what Cerebras is most well-suited for. You can use Cerebras chips for training, but the chip-to-chip networking story isn’t very compelling, which is to say that all of that compute and on-chip memory is mostly just sitting around; what is much more interesting is the idea of getting a stream of tokens at dramatically faster speed than you can from a GPU. Note, however, that the limitation in terms of training also potentially applies in terms of inference: as long as everything fits in on-chip memory Cerebras’ speed is an incredible experience; the moment you need more memory, whether that be for a larger model or, more likely, a larger KV cache, then Cerebras doesn’t make much sense, particularly given the price. That whole-wafer-as-chip technique means high yields are a massive challenge, which hugely drives up costs. At the same time, I do think there will be a market for Cerebras-style chips: right now the company is highlighting the usefulness of speed for coding — reasoning means a lot of tokens, which means that dramatically scaling up tokens-per-second equals faster thinking — but I think this is a temporary use case, for reasons I’ll explain in a bit. What does matter is how long humans are waiting for an answer, and as products like AI wearables become more of a thing, the speed of interaction, particularly for voice — which will be a function of token generation speed — will have a tangible effect on the user experience. I have previously made the case, including in Agents Over Bubbles , that we have gone through three inflection points in the LLM era: All of this falls under the banner of “inference”, but I think it will be increasingly clear that there is a difference between providing an answer — what I will call “answer inference” — and doing a task — what I will call “agentic inference.” Cerebras’ target market is “answer inference”; in the long run, I think the architecture for “agentic inference” will look a lot different, not just from Cerebras’ approach, but from the GPU approach as well. I mentioned above that fast inference for coding is a temporary use case. Specifically, coding with LLMs requires a human in the loop. It’s the human that defines what is to be coded, checks the work, commits the pull request, etc.; it’s not hard to envision a future, however, where all of this is completely handled by machines. This will apply to agentic work broadly: the true power of agents will not be that they do work for humans, but rather that they do work without human involvement at all. This, by extension, will mean that the likely best approach to solving agentic inference will look a lot different than answer inference. The most important aspect for answer inference is token speed; the most important aspect for agentic inference, however, is memory. Agents need context, state, and history. Some of that will live as active KV cache; some will live in host memory or SSDs; much of it will live in databases, logs, embeddings, and object stores. The important point is that agentic inference will be less about GPUs answering a question and more about the memory hierarchy wrapped around a model. Critically, this articulation of an agentic-specific memory hierarchy implies a necessary trade-off of speed for capacity. Here’s the thing, though: lower speed isn’t nearly as important a consideration if there isn’t a human in the loop. If an agent is waiting around for a job that is being run overnight, the agent doesn’t know or care about the user experience impact; what is most important is being able to accomplish a task, and if entirely new approaches to memory make that possible, then delays are fine. Meanwhile, if delays are fine, then all of the focus on pure compute power and high-bandwidth memory seems out of place: if latency isn’t the top priority, then slower and cheaper memory — like traditional DRAM, for example — makes a lot more sense. And if the entire system is mostly waiting on memory, then chips don’t need to be as fast as the cutting edge either. This represents a profound shift in future architectures, but it also doesn’t mean that current architectures are going away: At the same time, these categories won’t be equal in size or importance. Specifically, agentic inference will be the largest market by far, because that is the market that won’t be limited by humans or time. Today’s agents are fancy answer inference; in the future true agentic inference will be work done by computers according to dictates given by other computers, and the market size scales not with humans but with compute. To date the invocation of “scaling with compute” has implicitly meant Nvidia bullishness. However, much of Nvidia’s relative advantage to date has been a function of latency: Nvidia chips have fast compute, but keeping that compute busy has required big investments in ever-expanding HBM memory and networking. If latency isn’t the key constraint, however, then Nvidia’s approach seems less worth paying a premium for. Nvidia does recognize this shift: the company launched an inference framework called Dynamo that helps disaggregate different parts of inference, and is shipping products like standalone memory and CPU racks to enable increasingly large KV caches and faster tool use, the better to keep their expensive GPUs busy. Ultimately, however, it’s easy to see cost and simplicity being increasingly attractive to hyperscalers for agentic inference that isn’t remotely GPU-bound. China, meanwhile, for all of its lack of leading edge compute, has everything it needs for agentic inference: fast-enough (but not leading-edge) GPUs, fast-enough (but not leading-edge) CPUs, DRAM, hard drives, etc. The challenge, of course, is compute for training; it’s also possible that answer inference is more important for national security, at least when it comes to military applications. The other interesting angle is space: slower chips actually make space data centers more viable for a number of reasons. First, if memory can be offloaded, chips can be made much simpler and run much cooler. Second, older nodes, by virtue of being physically larger, will better withstand space radiation. Third, older nodes require less power, which means there will be less heat to dissipate via radiation. Fourth, not being on the bleeding edge will mean higher reliability, an important consideration given that satellites won’t be repairable. Nvidia CEO Jensen Huang regularly says that “Moore’s Law is Dead”; what he means is that the future of computing speed-ups will be a function of systems innovation, which is exactly what Nvidia has done. Maybe the most profound implication of agents that act without humans in the loop, however, will be that Moore’s Law doesn’t matter, and that the way we get more compute is by realizing that the compute we have is already good enough. Just as drawing pixels on a computer screen was a parallel process, which meant there was a direct connection between the number of processing units and graphics speed, making AI-related calculations was a parallel process, which meant there was a direct connection between the number of processing units and calculation speed. Nvidia enabled this dual-usage by making its graphics processors programmable, and created an entire software ecosystem called CUDA to make this programming accessible. The big difference between graphics and AI has been the size of the problem being solved — models are a lot bigger than video game textures — which has led to a dramatic expansion in high-bandwidth memory (HBM) per GPU, and dramatic innovations in terms of chip-to-chip networking to allow multiple chips to work together as one addressable system. Nvidia has been the leader in both. Prefill encodes everything the LLM needs to know into an understandable state; this is highly parallelizable and compute matters. The first part of decode entails reading the KV cache — which stores context, including the output of the prefill step — to make an attention calculation. This is a serial step where bandwidth matters, but the memory requirements are variable and increasingly large. The second part of decode is the feed-forward computation over the model weights; this is also a serial step where bandwidth matters, and the memory requirements are defined by the size of the model. ChatGPT demonstrated the utility of token prediction. o1 introduced the idea of reasoning, where more tokens meant better answers. Opus 4.5 and Claude Code introduced the first usable agents, which could actually accomplish tasks, using a combination of reasoning models and a harness that utilized tools, verified work, etc. Training will continue to matter, and Nvidia’s current architecture, including high-speed compute, large amounts of high-bandwidth memory, and high-speed networking, will likely continue to dominate. Answer inference will be a meaningful market, albeit a relatively small one, and speed from chips like Cerebras or Groq (I explained how Nvidia is deploying Groq’s LPUs here ) will be very useful. Agentic inference will gradually unbundle the GPU, which alternates between stranding high-bandwidth memory (during the prefill process) and stranding compute (during the decode process), in favor of increasingly sophisticated memory hierarchies dominated by high capacity and relatively lower cost memory types, with “good enough” compute; indeed, if anything it will be the speed of CPUs for things like tool use that will matter more than the speed of GPUs.

0 views
Unsung Today

A preview of the future

In his latest video , Shelby from Tech Tangents unpacked, installed, and put to use a truly forgotten product: IBM 3119, one of the first consumer flatbed scanners. The setup was a small nightmare, needing a rare hardware card installed in a specific computer, an ultra-particular combination of two operating systems working in lockstep, and even some careful memory balancing. Even after all that, a 300dpi page scanner in the late 1980s was still a force to be reckoned with. It’s hard to remember how enormous scanned files were compared to anything else then, even on a black-and-white scanner like this one. The video shows a simple 90-degree image rotation in highest quality requiring over 9 hours , and I believe it. But deep inside the video, at precisely 19:31, for only ten seconds, something appears that is absolutely worth celebrating. The nascent scanner software has a “curves” feature that allows you to redraw the shades of gray to capture shadows, highlights, and midtones exactly how you want them. Today, the feature would look something like this, with a real-time preview: There would be absolutely no way to do something like this in the late 1980s, when just rotating an image is an overnight operation, right? And yet: How was this accomplished? Absolutely brilliantly. Remember the palette swapping technique? Here, the entire screen’s palette is 256 shades of gray. It’s a very particular kind of a linear palette, and so you can easily take that line and… well, turn it into a curve. Since palette swapping happens on the graphic card, it takes as little as one frame of time, allowing for it to react to mouse movements as they happen. This must have been mind blowing to experience in the moment. Sure, it’s only a preview, and actually applying curves to the image would take many minut— No. This is a wrong frame of mind. Here’s my hot take: There are moments in software where the preview is more important than the feature following it. That’s because the preview making things faster isn’t just the difference between finishing something sooner or later. It’s a difference of doing something or not doing it at all. Would you even attempt to use curves if each adjustment took minutes or hours, especially in a land without undo? I love this preview that hints at what the future will be. I like this clever use of extremely limited technology and tight collaboration between engineering and design. It must have been nice to be in the room whenever someone had the flash of insight to use palette swapping this way. #above and beyond #flow #graphics #history

0 views

Photo Journal - Day 6

Today I returned to the park from day 4 armed with a macro lens I remembered I have. It's for a Nikon camera, and it's all manual (aperture ring and focus ring), but with an adapter it worked just fine with my Sony. I had some trouble with focusing, but I think a few of them turned out decently.

0 views

We need something better than touchscreens in cars

I live in the Greater Strasbourg area, and nearby, 30 kilometres away or so, there is a certain small-volume car manufacturer that understood years ago, before it was cool, that touchscreens in cars tend to age poorly. I love what they do instead of putting every command behind a fancy touchscreen: they try to give each of the main commands its own physical button, without relying on a capacitive piece of glass, as if we were still living in the first 120 years of the 140-year-old car industry. *1 There was no such screen in their previous flagship model (2005–2015), resulting in an interior that ages quite well compared to other interiors from the same era (imagine the resolution of these screens). Their recently-retired model , despite being released in 2016, doesn’t offer a single touchscreen either, and in the upcoming model , the screen only appears when needed, for instance, for GPS navigation. I’m not even sure if it’s touch-enabled. Why are such “simple” straight-to-the-point dashboards now synonymous with either brand boldness or retro design rather than best practice in driver interfaces? When did we all just sort of accept this as the de facto standard, even if touchscreens in cars suck? How much money do car manufacturers really save by centralising as much as possible into a single screen that tends to look the same across different brands and different models? How important is it for their sales and marketing departments to be able to highlight the fact that their cars are able to display the same familiar icons as the phones of their customers? This rant is not about being able to play songs from Apple Music or Spotify in your car’s stereo. This is not about the connectivity allowed by modern cars and the features it enables: this is about the look and ergonomics of it all. Why does everything have to be controlled via a big, luminous, colourful screen? Why does everything have to be displayed with a phone-inspired UI? When did Apple CarPlay and Android Auto become the face of most modern car software, and when did most car companies give up on that part? *2 When did we, as customers and drivers, get duped into thinking that good car interfaces had to involve giant touchscreens? Part of the answer is obvious: most car manufacturers are terrible at software, and they suck at user interfaces. Meanwhile, people have built natural habits with touchscreens over the past twenty years. For years people hated entering an address in their car’s GPS, so when something like Apple CarPlay became available, it felt like a breath of fresh air, it felt like the future. Car manufacturers noticed, and now they have the possibility to rely on iOS and Android to do most of the work regarding navigation, media, and phone connectivity. All of that while saving money by effectively externalising these features, at the cost of a dependency on ubiquitous and long-term-supported smartphone operating systems. All they have to do is include a nice screen, be “compatible” with Android Auto and Apple CarPlay, let you charge your phone while driving, and call it a day. And drivers seem to love this. *3 The problem is that if touchscreens are fine for some specific things in a car, this is not usually the case when actually driving. You know, that thing you do with a car and don’t do with an iPad? There are obvious safety concerns around the idea of people digging through menus and screens while operating a two-ton metal machine on public roads, but I want to complain about the quality of the experience most of all, which, as a software aficionado , I find to be infuriating most of the time. Why and when did we all collectively seem to settle for this? Why do we spend so much time complaining about MacOS and accept the mediocrity of car software as if nothing can be done, ever? Every time I want to play a specific song in my car (and when I don’t want to use Siri or when it doesn’t work — I’ll let you know which of the two is more common) I realise how terrible the experience is. Having to deal with five or six touch inputs at various locations on the screen, with questionable contrast and iconography, doesn’t really work when you’re using a moving, hovering hand while paying attention to traffic, does it? But it has nice candy-like colour icons, it looks like our phones, it feels “modern”, and we don’t really have to learn how to use it, we comply, and we forget about it. By contrast, changing temperature in my 2020 Kia Rio is as easy and reliable as it can get. I just turn a big knob. It has a nice feeling. I can tell from its physical orientation at which temperature it is set: between a “not heated at all” (blue area) and “warmest” (red area). It doesn’t lag. It doesn’t freeze. It doesn’t confuse me. If the AC is on, a separate button is lit up. The same goes for the ventilation speed, the window wipers and the tyre-pressure monitor reset. Physical buttons are not just great; they are undeniably better and safer to use for fixed actions, that’s why even iPhones still have volume up and down buttons. At night, these buttons are softly backlit, like my laptop keyboard, so I can see their status and location in the dark, but they don’t blind me and force me to readjust my sight every time I glance at the dashboard. Also, finger smudges. I want more of this, not less. I want the same ergonomics logic for music controls, for navigation, for communications. I want a button that is programmable to make a one-click phone call to my wife’s mobile phone. I want a button that always starts a specific playlist. Just like I don’t want MacOS to look and feel like iOS, I want my car to feel like a car, with its own personality, and not an iPad on wheels. Right now, when I look at car interiors from the 90s , I am jealous. I am almost smelling the leather and plastics, feeling the tactility of the dashboards, hearing the sounds they make. I am not sure how modern car interiors will feel in thirty years, let alone ten years from now. *4 To me, ideally, cars should behave like iPods and iTunes Sync: every time your phone connects to your car — wirelessly or not — playlists, albums, podcasts, contacts, saved maps, messages, and appointment locations should sync with those saved on the phone, and that’s it: let the car handle the software and the physicality of the interface. CarPlay should have the option for car manufacturers to run only as a syncing protocol for data, not a full iOS-like interface. I guess Steve Jobs was misunderstood by car manufacturers when he introduced the iPhone : Now, why do we need a revolutionary user interface? I mean, Here’s four smart phones, right? Motorola Q, the BlackBerry, Palm Treo, Nokia E62 – the usual suspects. And, what’s wrong with their user interfaces? Well, the problem with them is really sort of in the bottom 40 there. It’s, it’s this stuff right here. They all have these keyboards that are there whether you need them or not to be there. And they all have these control buttons that are fixed in plastic and are the same for every application. Well, every application wants a slightly different user interface, a slightly optimized set of buttons, just for it. If having a screen-only interface makes sense for phones, where the application can change drastically depending on the use case, it doesn’t sound like a relevant advantage for cars, where fixed control buttons and a constant user interface sounds like something you want. When Steve Ballmer famously commented on the iPhone , saying that it didn’t have a keyboard and didn’t make it a great “email machine”, he was mistaken because the iPhone can be a great email machine too. But I see what he meant: keyboards are obviously more capable for serious typing . They are in the way if you want to watch a video or browse the web, however, a keyboard fixed in plastic is better if typing is the main purpose of the device, just like laptops have keyboards. Even today, a lot of people miss having a keyboard on their phones . In that sense, car dashboards should be more like BlackBerry devices, and less like iPhones, because a dashboard should have the best design for driving, just like a BlackBerry had a keyboard to be the best at typing. *5 In the same iPhone keynote from 2007, Steve Jobs also quotes Alan Kay’s famous “ People who are really serious about software should make their own hardware. ” Well, I believe the opposite is also true, at least in the car industry: People who are really serious about hardware should make their own software. Special mention to the Saab cockpits, my beloved, along with their “Night Panel” feature . If you know, you know. I mean, look at it . Saab designed their cars with a mindset rooted in the aviation industry: each command legible and easily accessible, with the cockpit built around the driver. Imagine for a second if plane manufacturers took the “touchscreens everywhere” approach…  ^ I am not sure how CarPlay Ultra works: I hope it allows brands to customise the look and feel of the interface. I wouldn’t like to buy an Aston Martin and have my speedometer set in the San Francisco font. If I bought a Porsche, I wouldn’t want the cockpit to feel like a never-produced Apple Car. I would expect some personality and an on-brand, exclusive experience; Ferrari seems to be doing exactly that with the Lucce .  ^ Sure, they all have their own operating system, but it seems to be either used only for things the phone mirroring thing cannot do (like suspension settings and such). The exception being Tesla, but then the problem is the same: the tablet computer interface is front and centre.  ^ Even if things may start to change soon , hopefully.  ^ I just realised that BlackBerry (formerly known as RIM), weirdly, is working with car manufacturers on software (with QNX ), not on hardware (and also not on wheels).  ^ Special mention to the Saab cockpits, my beloved, along with their “Night Panel” feature . If you know, you know. I mean, look at it . Saab designed their cars with a mindset rooted in the aviation industry: each command legible and easily accessible, with the cockpit built around the driver. Imagine for a second if plane manufacturers took the “touchscreens everywhere” approach…  ^ I am not sure how CarPlay Ultra works: I hope it allows brands to customise the look and feel of the interface. I wouldn’t like to buy an Aston Martin and have my speedometer set in the San Francisco font. If I bought a Porsche, I wouldn’t want the cockpit to feel like a never-produced Apple Car. I would expect some personality and an on-brand, exclusive experience; Ferrari seems to be doing exactly that with the Lucce .  ^ Sure, they all have their own operating system, but it seems to be either used only for things the phone mirroring thing cannot do (like suspension settings and such). The exception being Tesla, but then the problem is the same: the tablet computer interface is front and centre.  ^ Even if things may start to change soon , hopefully.  ^ I just realised that BlackBerry (formerly known as RIM), weirdly, is working with car manufacturers on software (with QNX ), not on hardware (and also not on wheels).  ^

0 views
wh. Yesterday

SFT, RL, and On-Policy Distillation Through a Distributional Lens

I have been thinking about post-training methods in terms of distributions. A language model is a distribution over sequences. When we post-train it and attempt to teach it a task, we are reshaping this distribution. Different post-training methods differ in how they reshape this distribution, what they treat as the target and how directly they define this target. This is neither a very precise statement nor is it meant to be fully rigorous.

0 views
Ludicity Yesterday

The Worlds Left To Conquer

It has been a year and a half since I quit my job to start a consultancy. It took me years to build up to quitting, and I had not only a chip on my shoulder, but to quote Seth Sentry, “the guac and the dip and the salsa.” The people that read this blog probably understand what I’m talking about. I looked around at how organizations are run, at the people that told me what to do, and thought “Surely I could do a better job than this.” This feels like a dangerous train of thought. On one hand, that arrogance is precisely one of the mechanisms that makes someone incompetent. If you’ve learned everything, there’s no real reason to open up another book, and even that is rather generously assuming that the person providing a service to you has bothered to crack the spine on even one . On the other hand, how else are we to make sense of the world? If you walk out the door, you will be immediately clotheslined by institutions failing to achieve the most basic of tasks with any reliability. Almost every office I’ve walked into as an employee has been a decrepit nest populated by the beaten-down working class, a sickly ooze of self-important managers amongst whom a Gladwell reader ranks as a towering intellect, and executives that are feverishly muttering the word “AI” to credulous journalists as they blindly cut headcount. So many of these institutions seem to be held together by either regulatory capture or writhing clients bound by enterprise contracts like so much barbed wire. I’ve lost track of the number of times that someone has looked at work from a company like KPMG and gone “Ha ha ha, maybe we should all be consulting – then we can do terrible work and bill at two thousand dollars a day.” This joke is so overused that you can see the person saying it is reluctantly dispensing the cliché. So when I kicked off the company, some traitorous part of me was hoping that it would be difficult, as horrible as that would be for me personally. If it was hard, yes, perhaps I’d have to go back to some miserable office and be beset on all sides by smiling imbeciles talking about innovation, but it would make sense . It simply can’t be that easy to be free of those structures. Surely there’s a reason for it that isn’t simply “Wow, we’re systematically producing people that are terrible at their jobs and they can’t even see it.” Unfortunately, that really is most of the explanation. In late 2025, I said I’d write more after admitting how awkward it is to say the business is going well. I haven’t written anything for five months, and there’s no delicate way to put this, I drastically understated how well we’re doing. I'm ripping off the bandaid: in February 2026, I realised that we had already generated enough revenue to last us until 2027. On some engagements, I split my income several ways with teammates that weren’t on the job and still exceeded my corporate salary. For forty hours in 2025, I broke a thousand dollars an hour on tasks with measurable success metrics, an amount of money that would have seemed like some sort of sick joke two years ago, and both customers asked for a repeat engagement because the service quality was higher than what specialised firms were doing – I had spent about ten hours thinking about the engagement model. And we still have seven months left in the year. All of this is to say two things. The first, I’m not going to pretend that everyone would find it as easy as I do 1 , but it’s easy enough that basically anyone that can read both a book in software and the humanities will be fine. 2 The other is that this was all so easy that I’m going mad with boredom. Crept to their door, opened it slowly and tip-toed but, shit Somebody set the bar too low and I tripped over it Whoops, jumped up, tried to throw in a quick ultimate Just hopin' to scare 'em but, oh, it just killed both of 'em Bodies with slit throats on the linoleum I just throw 'em in dumpsters, the shit's appropriate Blue Shell , Seth Sentry I wish that I could say it was difficult to make things work. It would make sense of the world. I could have fun talking about going extremely overboard with machinations . The reality is that all of it, from service delivery to sales, has been more-or-less trivial. Closing and delivering a deal for twenty thousand dollars takes less time and energy than one sprint in a regular office. Nothing even feels high stakes – the global economy is so large that, for an efficient team, you can roll the sales conversation dice over and over until it turns up a 20. I personally blundered hundreds of thousands of dollars in sales over our first six months, and we’re fine . As a company, there are many things that I'd like to improve – it might sound silly given that we’re doing well and all our customers are happy (or lying to me), but the places where we're falling short of my expectations are extremely visible to me. By virtue of having a sizable following on this blog, I have extensive exposure to programmers that are better than me and people that are smarter than me. Every Thursday, I have a call with Efron Licht , and frankly I can scarcely grasp why someone that competent spends time talking to me 3 . The problem is that I’m not competing with Efron. If I was, I'd either have to study for five hours every day for the rest of my life, or shut the company down tomorrow. I’m competing with people that don’t have functional literacy. And it’s not just incompetence at programming, it’s everything. The world has phoned it in, leaving us with no pressure to push for excellence. Last year, I was unable to put clients on both Evidence and Prefect because the former failed to attend a sales meeting booked through their website and the latter failed to book a meeting after the ex-real estate agent they hired failed to actually schedule a meeting following outreach also through their website . Our (excellent) accounting team is Hales Redden , who managed my co-founder Jordan Andersen’s old physiotherapy business… because the people I tried in Melbourne don’t check their sales inbox. Our lawyer is reader Iain McLaren 4 because the firms I initially tried also don’t respond to their sales inbox . I cannot state this clearly enough – the bar is so low that it is hard to give people money . There are competent actors on the market, but at least in software, there are simply so few of them that you’re more likely to be allies than enemies. This was infuriating at first, comical later, and has now lapsed into depressing. As an employee, these people were an unending source of frustration, the same six-figure delinquents that would forget to renew my contracts when I was on a temporary visa. As an independent operator, they’re babies that have yet to develop executive function and I’m taking their candy. I’ll do it – candy is delicious and babies are weak – but it's hard to feel good about it after the thrill of being right wore off. Some days, I get to 5PM after pitching to fix a competitor's work, put my head in my hands, and go “There is no way you dumb motherfuckers can’t stand up a database. We’ve been on the moon. We’ve been on the fucking moon . There’s no way you dipshits cannot operate Google.” Nonetheless, there is money in my bank account and I’m in a house with three bedrooms, and we must all reckon with this dreadful portent. Is this it? I’m just going to stand up data platforms for the next forty years, a task so easy for us that we could do it drunk out of our minds, then die? As much as I enjoy having free time, the whole affair has been oddly unsatisfying. Every day, I wake up and feel like I’ve opted out of society. I don’t have the same problems as my peers anymore. Daily stand-up is a hazy memory that I remember with faint queasiness. And the very nature of consulting, even though we make the majority of our money on technical delivery rather than pure advice, is that we’re simply adding efficiency to clients. We’ve had the luxury of firing a few for bad vibes 5 , leaving us only with clients that we’re very happy to work with – but at the end of the day, they‘re doing the thing worth being proud of, and we’re simply an instrument. They do the admirable thing, and we make them better at it. It’s better than continuing to be an ultra-coward and getting paid to let people Do Scrum at me, but I dunno. Part of the reason that we’ve done so well to begin with is that we haven’t worried about scaling at all. I still think that is the obviously correct decision when you’re starting off and don’t want to take on debt. But at the same time, when a reader asks me if I’m hiring, my answer is essentially, “The whole business is designed for the team to be comfortable, and we didn’t build in the leeway to take care of other people.” My largest expenses outside of housing over the past year have been donations to a local writer’s group, Meridian Australis , and various bits to other causes, but this amounts to a few thousand dollars per year. I’m probably supposed to be content with that, but I’ve already quit my job, so what’s a bit more risk? Why am I always reading about unreflective narcissists and tedious bootlickers funding things? Why can’t the causes I care about have resources thrown at them without them having to contort their value systems for the money? At any rate, the passage is crystal clear in both cases: Alexander is not weeping in sorrow that there are no more throats to cut. This is not a picture of a man at the end of a career of world conquest; he’s at the beginning. “Look at all these throats—and I haven’t even cut one!” And Alexander Wept , Anthony Madrid We still run into problems all the time that aren’t solvable by simple efficiency – perverse incentives from sloppy legislation, places where buyers can’t understand enough to avoid exploitation, gambling companies run by vile degenerates, things that make me want to throw up. I am fully engaged with capitalism every day, and despite the fact that I’m winning for some definition of winning, much of it is grotesque. Sometimes I wonder whether I should have gone into medicine, like most of my family, but at the same time someone has to keep the databases running. So here’s what’s going to happen for now. We have seven months left in the year. Around the start of June, we’ll be done with our most complex work, and ready to try something new, where by “something new” I mean we’re going to pick some nerds (pejorative) and cut their throats. The area that we’ve picked out specifically is technical recruiting, if only because it is the most accessible area that is most densely populated with easy prey. It should take us a little bit to knock out a small platform 6 , then I’ll broadcast that here for readers to sign up. We’ve done some work in the space, and all I can say is that software recruiters are defenseless money piñatas incapable of serving the competent sectors of the market, and I am going to beat them with a large stick and then loot the wallets from their corpses. Is this it? I’m just going to stand up data platforms for the next forty years, a task so easy for us that we could do it smashed out of our fucking minds, then die? At a rough estimate, every time we place someone that would otherwise have had to go through the hellish experience of conventional recruiting, we could plausibly knock one individual recruiter out of the market because of their slim margins (due to all the incompetence), which will temporarily satisfy my never-ending lust for blood. Then we’re going to take that money and use it to knife someone else that's causing negligent misery, and funnel some of the excess into things we care about. If we do a really good job, I really believe we can meaningfully distort some section of the market, even if that’s just “Ugh, everyone knows you can't recruit software engineers in the A$180K band in Melbourne. Those Hermit Tech folks have destroyed all the margin and established themselves as supreme dictators, and also their CEO will bully you online if you do a bad job.” I’m going to commit economic violence for the next forty years, and get so good at it that we can do that smashed out of our minds, teach other people how to do it, then die, and some of you will pick up the work where we left off. I’ve had a sale for $100,000 fall through, and twenty minutes later said “Easy come, easy go” and moved on with my life. I’m sure this is trainable, but I can’t take credit for this because I think I’m just a weirdo.  ↩ It is unbelievable how much of a competitive advantage “Responds to emails from paying clients within 24 hours” is. The bar is subterranean.  ↩ Incidentally, the two largest influences on my company’s culture are Jesse Alford and Efron Licht, on team culture and programming fundamentals respectively. I don’t think Jesse has written anything particularly friendly for mass-consumption, but Efron has an amazing series called Starting Systems Programming that has been transformative for my practice. It might seem obvious to some of the most talented programmers in the audience, but I cannot recommend it highly enough for everyone else. If you enjoy it, I’m sure he’d get a huge kick out of an email, as I don’t think he has analytics. I’ll do a writeup on all my influences at some point, as the list is long and they all write quite a bit.  ↩ Certified Cool Dude, by the way.  ↩ To no one’s surprise, they’re mostly startups.  ↩ Think “limited window for candidate signups and extreme pickiness about employers, no CVs, and a hard limit on interview stages, and so on”, not Seek. I don’t think Seek has done anything wrong , they’re just the inevitable result of the state of letting the entire market use their service.  ↩ I’ve had a sale for $100,000 fall through, and twenty minutes later said “Easy come, easy go” and moved on with my life. I’m sure this is trainable, but I can’t take credit for this because I think I’m just a weirdo.  ↩ It is unbelievable how much of a competitive advantage “Responds to emails from paying clients within 24 hours” is. The bar is subterranean.  ↩ Incidentally, the two largest influences on my company’s culture are Jesse Alford and Efron Licht, on team culture and programming fundamentals respectively. I don’t think Jesse has written anything particularly friendly for mass-consumption, but Efron has an amazing series called Starting Systems Programming that has been transformative for my practice. It might seem obvious to some of the most talented programmers in the audience, but I cannot recommend it highly enough for everyone else. If you enjoy it, I’m sure he’d get a huge kick out of an email, as I don’t think he has analytics. I’ll do a writeup on all my influences at some point, as the list is long and they all write quite a bit.  ↩ Certified Cool Dude, by the way.  ↩ To no one’s surprise, they’re mostly startups.  ↩ Think “limited window for candidate signups and extreme pickiness about employers, no CVs, and a hard limit on interview stages, and so on”, not Seek. I don’t think Seek has done anything wrong , they’re just the inevitable result of the state of letting the entire market use their service.  ↩

0 views
Unsung Yesterday

Peaked in 2015

I have a confession to make. I prefer Apple TV’s 2015 remote: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/peaked-in-2015/1.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/peaked-in-2015/1.1600w.avif" type="image/avif"> The remote was universally ridiculed for its “which way is up?” problem – too much vertical symmetry which didn’t give your hand enough cues to know whether you’re picking it up the right way or the wrong way. Apple tried a half-measure first; in 2017 they broke the symmetry by making the MENU button slightly distinct in visual and tactile ways. Hindsight is 4K, but I don’t think it had a chance of working – the tactile cues were too subtle, and the visual ones do not matter when you’re not looking: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/peaked-in-2015/2.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/peaked-in-2015/2.1600w.avif" type="image/avif"> So Apple overshot – the subsequent 2021 edition was a full-measure-and-then-a-half: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/peaked-in-2015/3.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/peaked-in-2015/3.1600w.avif" type="image/avif"> The remote shrank the touch surface but otherwise drastically increased the volume, and added four arrows, two new buttons, and a strange iPod-inspired clock wheel interaction on top. And to me it started feeling a bit complicated, inching toward the very TV remotes that earlier designs ridiculed. (It also wasn’t as pleasant to touch, as the buttons feel a bit rougher.) But the reason I like the 2015 remote is primarily because it introduced one of my favourite gestures in recent history: tap to see progress. It’s hard to describe how wonderfully light this interaction feels every time I use it. You just tap anywhere on the remote’s top half, you see where you are in the video via a subtle UI, and then wait a few second for it to disappear. After this, doing the same in every other player – YouTube, Netflix, HBO Max, anything on a Mac or even the iPhone – feels clunky and heavy. In many of them, you can’t even see were you are without stopping the video! It gets better. Tap for the second time, and the elapsed time gets replaced by current time, and the remaining time by what the clock will say whenever you’re done watching. I thought this is delightful and clever, sneaking in clock functionality without showing it all the time. There is also this really nice gestural separation. When you watch the video, taps and swipes are safe. Anything that is “destructive” – that is, causes the video to stop, or rewind, or fast forward, is on the “click” layer: press stronger on the center to pause, or on either side to move forward or back. What I’m describing feels mechanically similar to other input devices, but the devil is in the details. On smartphones, everything is a tap, so you don’t really get anything lighter. On a Mac, tap as a gesture could only be available for people who opt in to press to click on their trackpad (like I do) – but the fact that tap is the default for clicking, means that can never realistically happen. The Apple TV tap feels conceptually like Mac’s hover instead, but so much more pleasant and elegant and simple. (I want to prototype tap on a Mac as a lightweight “explainer,” showing tooltips there instead of on hover.) To be fair, the tap gesture still exists in the still-current 2021 Apple TV remote, too – but the tap area is much smaller. And just in case you were curious, these are the first two editions: the 2005 remote – shipped with the iMac, predating Apple TV – and the 2010 remote. (I’m referring to model years, because Apple’s own names are so confusing.) = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/peaked-in-2015/6.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/peaked-in-2015/6.1600w.avif" type="image/avif"> = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/peaked-in-2015/7.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/peaked-in-2015/7.1600w.avif" type="image/avif"> I don’t have access to Apple’s user feedback, but I guess that Apple’s 2021 design was likely the very right thing to do. But looking at four-and-a-half of these models side by side, I am still in the 2015’s minimalistic, unusual, innovative corner. #apple #details #interface design #touch

0 views
Kev Quirk Yesterday

I'm off GitHub

Ok, that's it. I'm officially off GitHub. First I moved all of my private repos to my Synology, which was extremely easy to do. I did that around a week or so ago and it's be working great. Then I had to start sorting and moving all my public repos to Codeberg . Many were archived as I no longer maintained the projects, which left me with just 7 actual repos that I needed to move. Pure Blog/Comments and Simple.css were the most challenging as they all had other people who relied on them, but I managed to get them moved with a little bit of messing around. The others were super simply, I used Codeberg's migration tool to migrate the repos over, the ran a command locally to point my repos to a new target: That's it! Repo migrated. It's fine . And I don't mean that negatively - there's a lot less going on in the UI than on GitHub, but everything is still familiar and similarly laid out. There's been almost zero learning curve moving from GitHub to Codeberg, so props to the Codeberg team for that. I've applied for a Coderberg membership as I think it's important to support the open source projects we use, so hopefully that will be approved soon. Overall I'm very happy with the move. All the old GitHub repos have had their files updated to point to Codeberg, and they too have been archived. So that's one less piece of big tech I need to rely on. 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
ava's blog Yesterday

#LiegendDemo - protesting for ME/CFS treatment & visibility

Today, I attended a protest for the visibility of ME/CFS sufferers . ME/CFS is short for Myalgic encephalomyelitis/chronic fatigue syndrome ; it is a chronic illness characterized by extreme fatigue that doesn't improve with rest, along with sleep issues, dizziness, muscle and joint pain, cognitive difficulties, extreme sensitivity to stimuli, and more. There is significant overlap with what is often referred to as " Long Covid " or " Post Covid ", leading to speculation that they're one and the same. It is estimated that 1.5 Million people are affected in Germany alone, with around 40 Million estimated worldwide. One day, it could be you. The exact cause is still being investigated, but it is most often associated with a viral infection (Covid, Epstein-Barr, etc.), and while symptoms can sometimes be managed, a full recovery is very rare. There is currently no known treatment or cure, and diagnostic criteria are still being developed after all this time (50 years since the WHO has acknowledged it!), which makes getting a diagnosis hard. There is stigma around the illness, with doctors dismissing symptoms entirely or blaming it on mental illness or laziness, inappropriately trying to force sufferers to overexert themselves, worsening their symptoms. This is aided by the fact that ME/CFS is often not taught in medical degrees. This group of patients is especially vulnerable, because advocating for themselves takes so much energy they don't have. Many of them can not even get out of bed or do any strenuous mental tasks, or they have to spend the little energy they have with the bare minimum to survive and then have none left for their free time. They are frequently very isolated and lacking the support they need. Any exertion can cause weeks of increased symptoms (post-exertional malaise). Years of their life are just gone, spent existing in bed in a dark room, unable to think clearly or to really move, having difficulty speaking, having difficulty processing and enduring sounds, touch, or light. The fatigue can become so bad that they are unable to even talk. Their education, finances and careers suffer, they can no longer take care of themselves and their families or pets, they struggle with doctor's appointments or the paperwork required to receive assistance, disability benefits, etc. and often start to have other chronic illnesses like fibromyalgia, irritable bowel syndrome, postural orthostatic tachycardia syndrome (POTS) and more. It can affect both children and adults. It's easy to forget they exist because they are not visible out in public and left behind in public discourse. To make them visible, people all across the country meet up to lie on the floor - this happened for the first time in 2023, and is still going strong in 2026. I don't have ME/CFS, but after a Covid infection, I struggled with orthostatic issues, post-viral tachycardia, and my chronic illnesses (Crohn's and Bechterew's disease) sometimes cause me intense fatigue as well; so I can relate a little to some parts of the illness, but I am lucky that my issues have treatments that helped (and some I could recover from). It was important to me to show up when they can't. 1. Dedicated funding for ME/CFS Research funds must be specifically allocated to ME/CFS with PEM, rather than absorbed into broader post-infectious research categories. Otherwise, the disease risks being underfunded while still being treated politically as adequately addressed. 2. Priority for drugs and effective treatments Prioritize the development of medications and clinically effective therapies, not only basic research or administrative structures. 3.Mandatory involvement of patient organizations ME/CFS patient representatives with PEM expertise should be directly involved in planning and implementation. Past programs included people unfamiliar with the disease, resulting in research that overlooked core symptoms and legitimized unsuitable therapies. 4. Immediate funding for biomedical research Concrete biomedical projects should receive funding without delay, not spending years building structures before supporting treatment-oriented research, despite already existing promising drug approaches. 5. Clear disease definitions, rigorous research standards and exclusion of unsuitable research approaches Studies should use strict diagnostic criteria and focus on PEM as the defining symptom. Many previous studies examined general fatigue rather than properly diagnosed ME/CFS, producing weak or misleading results. Research that ignores the biological, multisystem nature of ME/CFS should not be funded. 6. Legal and political safeguards The so-called research decade should be backed by binding commitments rather than remaining a non-binding political initiative. Otherwise, funding and programs could be reduced or canceled after political changes. 7. Healthcare access, diagnostics, social support, and patient care, sustainable research infrastructure Long-term structures such as specialized centers, biobanks, patient registries, and clinical trial networks should be established to support ongoing nationwide ME/CFS research. 8. Use existing research and strengthen international cooperation Future work should build on existing ME/CFS findings and coordinate internationally to avoid redundant studies and accelerate progress. The International ME/CFS Awareness Day is on May 12th. Donate to the ME/CFS Research Foundation Read what people affected by ME/CFS say 18 Minute Short Documentary on YouTube, English Subtitles 🇩🇪 Doku: ME/CFS: Keine Kraft mehr 🇩🇪 ME/CFS sufferer in Austria making use of assisted suicide program 🇩🇪 Liegenddemo Germany 🇩🇪 MECFS.de 🇩🇪 MECFS-Info.de 🇩🇪 ME-Hilfe.de 🇩🇪 Fatigatio.de 🇩🇪 Nicht Genesen Kids Reply via email Published 09 May, 2026

0 views

Emulating old junk from yesteryear – or my obsession making native resolution PS2 emulation look good

Lately I’ve been on a kick to tackle the latter part of PS2 graphics emulation that never seems to come up, analog TV emulation. 99% of the PS2 emulation space is all about upscaling to the max, cranking out 4K with polygons so sharp they can cleave mountains in half, but that’s not particularly to my taste, which is why paraLLEl-GS focuses more on the super-sampling aspects rather than raw upscaling. Earlier blog post on the paraLLEl-GS here if you have no idea what I’m referring to. For example, a raw native render with progressive scan (640×448) with paraLLEl-GS backend: With Vulkan HW renderer in PCSX2, a basic 2x upscale would look like: which is obviously higher resolution, but does not attempt to resolve aliasing either, and as upscaling factors go up, the mismatch between texture resolution, polygon counts and output resolution create a jarring effect for me. The approach I tend to favor is super-sampling and keeping the resolution native, even if it means a more blurred resolve. Here’s how it’d look with 16x SSAA. This is quite overkill for most cases, but why not. There is a special mode in paraLLEl-GS that can scanout the 16x super-samples at double the resolution, which is effectively 4x SSAA at double the resolution. It can look great when it works well, but the key word is when . This approach is not playing to the strengths of paraLLEl-GS at all, but it’s a thing. The main problem is that 2D images like HUD elements remain at native resolution with integer scale, which can create a jarring look, and post processing passes can mess up things in some cases. My main focus is on the native resolution, super sampled output, since it has very few gotchas compared to other upscaling styles. For a while, I’ve relied on FSR1 to do the upscaling, which is just a temporary hack. While properly anti-aliased 3D can look surprisingly good with FSR1 when blown up to large resolutions (what it is designed for), 2D game elements still create questionable artifacts. Text upscaling starts looking like those old HQ2x, SuperEagle and xBR filters that used to be popular with SNES emulators. That’s likely because FSR1 is “just” edge-aware Lanczos filtering at its core. Still, at SD resolutions there’s only so much you can do to blow it up to a modern display. The result here is of course quite blurry, but looking at it from a reasonable distance, it can look sort-of okay on a good day. The only proper way to display SD content is in my opinion to use a CRT, or in lieu of getting a nerd tan, CRT shaders. Simulating CRTs has been done to death to the point Hel is blushing, so I feel a bit uncomfortable even trying to write about it, but this post wouldn’t be complete without it. RetroArch has like 23428323 CRT shader presets already, and there’s nothing novel about any of this. However, there are some considerations for PS2 that most CRT shaders don’t target: A lot of CRT shaders assume a high quality VGA-style monitor. Nothing wrong with that of course, but I find most of them a bit “too” good for PS2. Where we’re going, we’ll need that analog fuzz too. I’ve been deep down the rabbit hole looking up old specifications to get a deeper appreciation for the brilliant engineering involved in making color TV work all those years ago, and the PS2 era was the last hurrah for SD CRTs, 480i warts and all. I’ve sort of gone through all of this stuff before back in my early days of programming, but I’d like to think I’m a little smarter than I was back then, and I learned far more details than I knew before. From a graphics programming PoV this is hardly “difficult” stuff like debugging random GPU hangs at 10pm on a Friday coming from the latest and greatest AAA game, but hey, sometimes you just gotta relax with some good old DSP coding to stay sane. The signal processing for NTSC and PAL is fairly straight forward and it’s actually a good entry point into signal processing for graphics programmers since it combines very visual things with actual real world problems. Component is the highest quality analog cable (actually, 3 cables!) available to consumers. It supports progressive scan which very few PS2 games natively supported. Simulating this cable is quite trivial. Composite is the yellow cable “everyone” used. This one is the hardest since separating luma from chroma in the same single-channel signal is actually kinda complicated to do well. Most of the time I spent was trying various strategies for this problem and try to come up with a look that seems authentic and “tastefully shitty” S-Video is very similar to composite, except that luma and chroma are separate signals. Chroma is packed into one cable and chroma decoding is basically same as for composite signals, where phase and amplitude dictate the hue and saturation. Main difference to component is that bandwidth for chroma should be quite low, so more color smearing should be present. Us Euro-bros technically had RGB SCART too, but I’ve never seen those cables myself for a Sony console. I believe our old N64 and GameCube had those, but I’d have to double check next time I visit the family … While it is very easy to find a ton of content online about old TV standards, your random YouTube video is not going to have the minute detail needed to implement much. I found “Video Demystified – A Handbook for the Digital Engineer (2005)” by Keith Jack which has ton of great detail that is often left out to make sure my implementation stays grounded. BT.601 defined how to take NTSC and PAL signals and turn them into the digital domain. It is the foundation for all digital video today. The primary interest for us is that the standard defines a 13.5 MHz sampling rate. This was supposedly chosen since it was convenient for both NTSC and PAL and filtering requirements. This scheme works out to 720 horizontal pixels for NTSC and PAL when you account for 525 lines at 29.97 Hz and 625 lines at 30 Hz. The H-sync part of the analog signal pads out to a bit over 800 pixels, but that’s irrelevant here. I also learned just recently why it’s called YUV444, 422, 420, etc: The “4:2:2” notation now commonly used originally applied to NTSC and PAL video, 480i and 480p Systems implying that Y, U and V were sampled at 4×, 2× and 2× the color subcarrier frequency, respectively. The “4:2:2” notation was then adapted to BT.601 digital component video, implying that the sampling frequencies of Y, Cb and Cr were 4×, 2× and 2× 3.375 MHz, respectively. Now you know! The Nyquist frequency of SD video is thus 6.75 MHz. Talking about video like this is a little weird, but it will make more sense later since analog signals like NTSC and PAL have a certain bandwidth, which limits how much horizontal resolution we can cram into it. The number of video lines is hardcoded. The video signal is really just a 1D signal if you look at it in an oscilloscope (haven’t seen those since my Bachelors …). The next question was to determine the sampling rate of the PS2 CRTC. Given it generates analog signals, it’s not obvious that PS2 would use a standard frequency here. However, several old forum threads I found did indeed suggest that PS2 is based around the 13.5 MHz rate. This is likely because it could use off-the-shelf video DACs at the time. The nominal maximum horizontal resolution of PS2 is 640 pixels, but it seems like overscan is supposed to stretch the 640 pixels out to fill the screen anyway. Even if 480 lines are “visible” in NTSC, games typically just render 448 lines since the top and bottom is eaten by overscan by most TVs. The actual CRTC clock seems to be 54 MHz, because when programming the CRTC, you’re supposed to set some dividers which ends up determining the resolution. E.g. 640 pixel width is a divider of 4, 512 pixels a divider of 5 and so on. It conveniently supports most relevant horizontal resolutions like this. My armchair theory for how this works is that the CRTC runs at 54 MHz and uses the divider to do a zero order hold (aka nearest filtering) which is then fed into the DAC. Either that or the console is really doing horizontal linear filtering up to 640 pixels and does composite video generation at 13.5 MHz. I’m not sure what really happens, so I just have to guess. I’m not quite obsessed enough to have an oscilloscope to suss out micro-details like these from a real PS2. The PS2 is technically able to emit 1080i and 720p signals, so there’s no reason why it couldn’t do analog video processing at the full 54 MHz. To debug any of this we need test images. I don’t exactly have test signal generators that TV engineers had back in the day, so I had to synthesize something. The use for these is to validate various edge cases in the NTSC and PAL decoding process. The basic idea is to have some 75% color bars at the top to validate the color pipeline. The middle section is a sweeping increase of horizontal frequency up to Nyquist of 6.75 MHz. Each 1 MHz section is delimited by a single line color bar. The lower portion is a sweep with increasing frequencies. This is used to test the comb filter. Doing FIR filter design by hand is uh … not something I have time for. Anything beyond the basic windowed sinc design process gets annoying very quickly. GNU Octave is a free alternative to Matlab that does what we need for these tasks. While we can do composite video generation at the 13.5 MHz rate, it is not easy to avoid aliasing, especially since we will be modulating with a chroma subcarrier that will shift the spectrum all over the place, potentially creating aliases out of thin air. The handbook calls for a 2x oversampling to avoid this. First, the image is padded out to fill 720 horizontal pixels for BT.601 reasons. Then, integer scale the image up to 2880xN (to match with how I understand the CRTC to work), and downsample that with a low-pass to 1440xN which completes a clean 2x oversampling. A polyphase upsampling filter is of course possible too to avoid the intermediate upscale, but that’s needless complexity for something that literally takes 10 microseconds on the GPU The immediate upscale is not written to memory at least, the filter just assumes a 2880 pixel input and it’s just sampling the input texture redundantly instead. Since these are fundamentally analog signals, we only filter horizontally. The natural image type for these is 1D Array. All the processing shaders are 1D as well. (The 1504 width is just extra padding for convolutions.) It’s all the same thing really. NTSC is the oddball one with YIQ but in practice this difference is completely irrelevant. The original idea of IQ was to take the blue and red difference signals and rotate them by 33 degrees to make it so that I would align with skin tones better, and give I more bandwidth than Q . However, the handbook doesn’t seem to give it too much consideration. Especially not for composite signals which are not meant to be sent over the air. The implementation of this is really just doing a 3×3 matrix multiply with RGB, nothing special. NTSC and PAL have fairly narrow bandwidth defined for their broadcast signals, but composite signals don’t really have those strict limits. However, since the digital input has Nyquist at 6.75 MHz the handbook calls for bandlimiting the signal to about 6 MHz anyway. Super sharp falloff filters just lead to ringing. Component video is specified by BT.1358 and doubles the sampling rate to 27 MHz. Y should fall off at about 11 MHz and chroma half that. Interpreting that in interlaced terms, the falloff should start at 5.5 MHz, getting close-ish to the Nyquist limit for SD video. After filtering luma and chroma, just decode back to RGB and we have a nice signal, done. Chroma is nuked down to ~1.3 MHz or so for composite / S-Video. Sometimes, 0.6 MHz is called for it seems, but it’s quite unclear … S-Video can ignore the modulation + demodulation part if we just want to simulate the smear, but it was easier to let it go through the full chain for completeness. Despite the chroma bandwidth being so horrible, it sort of looks good. Amazing how terrible our eyes are at seeing color detail. I wonder if this is there the esoteric 4:1:1 YCbCr subsampling mode comes from now that I think about it … E.g. NTSC luma filter, which starts falling off at about 4.2 MHz and stops at 6.75 MHz-ish. Broadcast NTSC is capped well below this bandwidth. Chroma encode, with ~1.3 MHz passband: Main difference for PAL is that luma passband is a bit higher. PAL-B (which Norway used) seems to specify 5 MHz rather than 4.2 MHz. Generating these filters can be done easily with firls and friends in Octave. The handbook calls for a gaussian kernel for chroma to avoid any ringing, but I missed that memo Either way, these are implemented with trivial convolutions which GPUs eat up like butter. This is the first point where NTSC and PAL differ significantly. While NTSC and PAL have different color subcarrier frequencies, PAL is also a bit more sophisticated. The “sign” of V is where Phase Alternate Line comes in. It flips every scanline. In broadcasting, this was meant to fix bad colors being introduced during broadcasting through complicated terrain (and boy do we have that over here in Norway). Bad phase shifts being introduced by NTSC will manifest as hue shifts. The basic idea behind PAL is that if phase shifts are introduced by signal reflections the sign flipping of V every scanline ensures that the decoded hue is complementary from scanline to scanline. This manifests as the Hanover Bar artifact. By averaging chroma from scanlines, the errors cancel out and we recover the correct color with slightly less saturation. The cost is of course reduced vertical chroma precision, but given how comically smeared chroma is horizontally, I’m not sure this matters, and digital video uses 4:2:0 subsampling anyway. Now, broadcasting considerations are kind of irrelevant for something like composite video (I would think), but I’m not sure if PAL TVs skip the filter for anything not coming from an antenna. I kept the vertical chroma filter in my implementation because it’s neat to have. The NTSC chroma subcarrier is constructed such that every scanline completes 227.5 cycles. Every line flips chroma phase which is very convenient and makes luma and chroma separation less complicated. The NTSC chroma pattern is a checkerboard as a result. PAL is more annoying here. A half cycle method would not work since V is already flipping every line, so PAL chose 287.75 cycles. On top of that a tiny 1 / 625 cycle offset per line is added for … reasons. The V flipping leads to a chroma pattern where U takes a diagonal pattern while V has a pattern along the other diagonal. Frame progression is also a concern. As fields are scanned, each time the same field is drawn, the chroma subcarrier should have opposite phases. This follows naturally from how fields are drawn. The period of NTSC is 4 fields: As we can see, things repeat after 4 fields and this point is easy to miss. The artifacts introduced by composite video should ideally cancel themselves out over time which manifests itself as flickery noise rather than a horribly glitched image. PAL is annoying and has a longer cycle of 8 fields due to the three-quarter of a cycle setup. After completing 2500 lines (625 * 4), the chroma subcarrier has completed an integer number of cycles, and the sign of V is back to where it started. After modulation, the NTSC color bar signal looks more like: and the next line flips phase as expected: Some old Nintendo consoles (and likely others) emit NTSC and PAL in non-standard ways. E.g. NES is infamous for shifting the chroma carrier by 120 degrees instead of 180 which leads to very particular artifacts. See NESdev Wiki for more detail. It’s easy to mess up RGB to YUV conversions and the compositing process. The handbook had reference outputs for RGB inputs in NTSC and PAL where I could confirm that the math was indeed correct. The things to check are that minimum and maximum of the signal are what they should be. NTSC, at least the US variant of it maps black to 7.5 IRE (just think of it as some abstract voltage) and white to 100.0 IRE, and it tripped me up a bit at first since the NTSC color bars were defined in terms of this shifted and scaled IRE value. Looking at the peaks and valleys of the generated composite signal in RenderDoc is enough since we just need to eyeball it. Close enough is good enough. This is non-trivial and a source of endless head scratching. Chroma information lives in the frequency spectrum around the carrier, but so does higher frequency luma detail. The basic theory for comb filters is to take advantage of the opposing phase of the chroma carrier. For NTSC, I used this basic structure from the handbook: In code, this translates to: Ideally, by adding two neighbor lines, chroma should cancel out and only luma remains. Subtracting, we cancel luma and only chroma remains. We know that chroma won’t (or at least shouldn’t) exist outside its bandwidth, so the result is run through a bandpass filter that centers around the carrier frequency, and we have an estimate for the modulated chroma signal. Since the composite signal is Y + C, we subtract the chroma estimate from composite signal to form a Y estimate. Chroma can now be demodulated and low-passed to remove the harmonics introduced by demodulation. This filter works “perfectly” for regions where the chroma is constant, but not so much where there are discontinuities. This results in “chroma dots” where the color subcarrier bleeds into decoded luminance. Notice the dot pattern on the bottom of the image. Thus, different colors modulate the luminance intensity differently, creating a “dot” pattern on the scan line between two col- ors. To eliminate these “hanging dots,” a chroma trap filter is sometimes used after the comb filter. In the real world of analog circuitry, having a perfectly locked signal like this is probably also not too realistic to assume. The literature also calls out for notch filtering as an approach. I attempted combining a comb filter with a notch filter on top to reduce the artifacts, but it is quite tricky to create a notch filter that works well. A simple FIR notch filter with zeroes is easy enough to make: This filter is convolved with a simple low-pass to complete the luma decoding filter. This approach just leads to severe blurring for NTSC and a band-stop filter approach just lead to less severe blurring and ringing instead, so I’m not sure what should be done. Unfortunately, the handbook isn’t clear on what kind of filtering is called for here. IIR notch filter designs can be super sharp to surgically carve out the carrier, but IIR filtering is also a massive pain in the ass on GPUs. It’s also likely to ring heavily too, which I found rather annoying in my testing. E.g. 3-line comb NTSC without the notch (integer nearest upscale from 640×240): and with notch: Yikes. There’s no way this notch approach is correct. It’s like we’re getting double vision here. It does clean up the chroma dots though, so … yay? Going beyond these base techniques there’s adaptive filtering where the filtering strategy changes based on which kind of case we’re dealing with. And even more sophisticated is taking advantage of temporal information (look ma’, TAA has been a thing since forever :D) since N fields in the past we have complementary chroma phase perfectly aligned to our pixel grid. Very cool stuff, but I doubt consumer TVs at the time would have those. The added latency for doing this kind of analysis doesn’t sound like something you’d want for games at least … Either way, I’m not designing high-end TV circuitry in the late 90s/early 2000s here. We can just flip on S-Video to simulate the perfect Y/C separator, so at some point I have to decide that I’ve done enough filter masturbation and move on. This was way harder than expected and I had to bang my head against the wall for a while to come up with a good solution. The ~90 degree shift every scanline means the basic comb filter for NTSC won’t work at all. The handbook has two main strategies here. Either a delay line which is slightly longer than a scanline to align the phases: Or use a highly magical “PAL modifier”: The function of this modifier is esoteric as all hell, but I think the purpose of it is to phase shift the signal by 90 degrees to “realign” the carrier somehow (it will still be off by 0.6 degrees). This filter path with two bandpass filters just got so messy, and I couldn’t figure out how to debug the thing effectively (were the inevitable visual artifacts my bugs or just the filter being bad?) that I eventually gave up and designed my own filter. That’s more fun anyway. I started from first principles and designed a 3×3 kernel that should be able to perfectly pass a chrominance signal and 100% reject any luminance signal that is DC in either horizontal or vertical direction. To make things simple I started with the assumption of 4 samples per subcarrier cycle to make the examples easier. Given a constant value of 1.0 for U, a signal would look something like: U = sin(wt) with N + 0.75 cycles per line here. A kernel that satisfies the criteria is: The sum of all rows and column is 0, meaning that if the signal is DC either horizontally or vertically, the result is completely filtered out. The filter also rejects V signals. V = +/- cos(wt) and looks like This is just the same signal flipped horizontally, so: Then a combined filter is made that accepts U and V signals together. U and V can be perfectly split later during demodulation so that is okay. This just boils down to a simple diagonal edge detection filter (high pass vertically and horizontally), but actually works quite well. To deal with the actual 2x oversampled rate of 27 MHz and the PAL subcarrier at ~4.433 MHz, the ~90 degree shift per line is about 1.51 samples, so to make this sort of work, I stretched out the horizontal kernel to a 5-tap filter: The vertical kernel remains the same of Some error is introduced since we’re not sampling the signal 100% correctly anymore (theoretically we need a sinc to reconstruct the signal perfectly), but I measured the reconstructed error to be -40 dB, which is good enough I think. The measured error for U and V were also similar, which indicates no weird artifacts from the V flips. With this 15-tap kernel, we get a pretty good chroma estimate even in PAL. From here the same ideas as NTSC apply, bandpass the estimate and subtract it from composite signal to get luma. Notch filtering to cleanup the chroma dots worked way, way better for PAL than NTSC, likely because the carrier has a much higher frequency on PAL, so the low pass behavior of the notch isn’t as devastating to image quality as it is on NTSC. In the end I think I prefer 3-line comb + notch for PAL and just plain 3-line comb for NTSC. These screenshots are just one still frame (or rather, field). The color fringing will cancel out the next field and it’s hard to show the effect without seeing it at full 60 fields per second. While PlayStation 2 didn’t support this hack mode, GameCube did back in the day. It’s a non-standard video mode that has same refresh rate as NTSC and vertical resolution, but retains the bandwidth and chroma encoding system of PAL, the best of both worlds! My implementation can trivially implement this by just enabling PAL on 60 Hz games. Only thing I’m not quite clear on is how the 1 / 625 subcarrier offset per line is supposed to work, but it’s a non-standard mode anyway, so eeeeeh. With comb filter and notch on NTSC: As expected, luma detail is murdered around ~3.58 MHz carrier. Also serious color fringing due to the extreme high frequency diagonal patterns. In the pattern at the bottom, no fringing is observed since the comb filter did its job as expected. PAL is similar, but the carrier and notch moves to ~4.43 MHz instead: The main feature of PAL is being robust against phase shifts during analog broadcasts. It’s a little unclear if composite inputs cared about this case, but for completeness sake, I implemented it. This path is naturally skipped for S-Video and Component outputs since I can’t imagine a TV caring about that for the more luxurious inputs. It doesn’t take many degrees of error in the phase to get quite different colors for NTSC. For PAL, the phase error manifests as complementary errors every line. However, by averaging out chroma vertically, we can recover the original chroma almost perfectly. At worst, a little less saturation. This topic is kind of unfortunate in that it’s done to death already, and it’s a 100% subjective topic meaning that everyone has some kind of opinion, none which agree with each other. Holy wars have been fought over less. Trying to write anything fresh about this topic is futile in 2026 – the heyday of CRT hobbyist shader development was in the early 2010s – but I felt the need to explain what I did at the very least. If anything, it’s a useful intro to writing your own shader. https://nyanpasu64.gitlab.io/blog/crt-appearance-tv-monitor/ is a good read too for more background information. The most obvious part of a CRT filter is scanlines, however, the idea that CRT images should have clearly visible scanlines is actually an artifact of 240p. For PS2 games, we’re operating at either 480i or 480p for NTSC. For interlaced video, we expect each individual field to have clearly visible scanlines, but the complete image (fused together by our brains) should not. The beam profile should be tuned as such. What most shaders do is for each scanline to take a gaussian distribution in the Y direction, sampled for the neighbor lines to cover the useful portion of the kernel. Another common effect is that very bright scanlines are smeared out, supposedly due to the electron guns not being as stable when they’re driven at high voltages. This can be simulated by varying the standard deviation. It can be subtle, but creates a neat effect I think. Exactly how to come up with the beam profile for a given input voltage is purely up to taste I suppose, I doubt there is a linear relationship between R’G’B’ value and standard deviation of the beam The sampled RGB value is in gamma-space still, since the CRT gamma curve is due to the phosphor response, not the CRT itself adjusting the gamma curve. The BT.1886 standard calls for a 2.4 gamma for SD content, which is the default and looks good. I also added options to use 2.2 (NTSC legacy) and 2.8 (?!, PAL legacy) for fun. Most CRT shaders I’ve seen apply gamma in this way: I think it would depend on whether or not the phosphor’s response is a function of how many electrons hit it, or individual “particles” respond to the energy of the electrons hitting them, where the gaussian beam profile is just a distribution of how many particles light up. In the latter interpretation, the code as-is makes sense, while the first interpretation would call for apply a gamma function on the gaussian profile. The visual output as-is looks good to me at any rate. After this point, all color math happens in linear light, so floating point render targets is a must. Color CRTs get their colors by having colored phosphors that are arranged in some kind of grid. The venerable Trinitrons use vertical stripes of RGB, and I like that look. While CRTs don’t really have a horizontal resolution, there is a “dot pitch”, which sort of dictates resolution. This part is the key to create the “texture” of a CRT. From what I read online a typical dot pitch for consumer TVs was 0.5 – 1.0 mm, and for a typical 20″ CRT, I estimated a reasonable number of RGB triads to be ~640 or so. Close enough to BT.601 standard horizontal resolution, neat. From what I understand, this value is also referred to as “TVL”, and these values seem ballpark reasonable. When looked at a distance from the screen, the dots blend together nicely as we’d expect. It’s basically just LCD subpixels, just larger. The dot layout I used was mostly lifted from Lotte’s CRT shader, but the approach can probably be found in a million shaders already. Just alternating stripes of R, G and B. I suppose a perfect mask of 0.0 should be used here, but it doesn’t end up looking as good as I’d like, even after adding glow effects, so I think the intent behind passing through a portion of other colors is more of a pragmatic decision. At least I cannot think of a physical interpretation of why we’d want to do it. The signal we are creating has a ton of high frequency information and we need to be very careful sampling it such that obvious aliasing is avoided. The common mistake is to just render this shader at output resolution and hoping for the best. This will almost surely lead to terrible aliasing patterns in the image. Bad aliasing of the scanlines in Y direction leads to a low frequency pumping pattern in the image which is extremely distracting, and bad aliasing in the X direction leads to a horribly noisy pattern due to uneven sampling of the dot mask. The easy fix is to render the effect at an integer multiple. E.g. if input image is 240 lines, render to a height that is an integer multiple of that. For the color dot mask, make sure the horizontal resolution is e.g. 3 times the dot resolution (one pixel for R, G, B dots). I ended up with something like width = 640 * 3, and height = 240 * 6 (3x sampling for progressive). A nebulous effect of the CRT is the glow aspect to it. Anyone can tell it’s there, but it’s not entirely clear to me why this happens. Google searches don’t turn up anything useful either. Without knowing the physical reason for it, it’s hard to emulate accurately. Could it be scattering effects inside the thick CRT glass perhaps? Either way, the common way to emulate this effect is to compute a gaussian blur (lots of those around here) and composite it over the original image. Very similar to the usual HDR + bloom effect that games in the 2010s loved to overuse. The main effect here is that the phosphor dots end up blending together nicely, yet retain the added “texture” that the aperture grille pattern gives. Humans like to see some high frequency detail, even if that detail is completely bogus. That’s the common trick behind video compression after all. The glow component, boosted up a ton to make it very visible: With the typical HDR effect in HD games, only very bright pixels participate in the effect, effectively spreading excess light energy over a larger area of pixels. It makes little sense to do anything like this for a CRT shader unless there is a physical threshold where phosphors just randomly start to glow more than they should, but all of this is purely up to taste anyway. Here’s from Soul Calibur II with progressive scan, component cable emulation and 16x SSAA, without any glow added. The look is very harsh to me. (The full-screen image is needed to see it without the extreme aliasing caused by thumbnailing.) Some glow on top and it looks like: Purely up to taste how much to add of course. I like a decent amount of glow. Phosphors don’t turn off right away when they’re lit. It’s very quick though, but adding a few percent of feedback between frames seems to help a bit with making 480i games look better with less flicker. This is not really how things work in the real world I think, but a reasonable approximation. We need a high quality rescaler to get the integer sampled CRT to the screen without introducing significant aliasing from the aperture grille or scanlines. The way to go here is simply to use a proper windowed sinc or something like that. I don’t like it, so I don’t implement it. If you do, make sure to consider resampling it properly to not introduce more aliasing. A point many shaders miss is that the RGB of a modern monitor is not the same as RGB on an old CRT TV. What we think of RGB today is usually BT.709 sRGB which defines a set of color primaries and white point. Old SDTV era video uses BT.601 which is a bit narrower than BT.709. In linear RGB space, this transform is a trivial 3×3 matrix multiply. I actually learned that the very old NTSC 1953 standard defines a set of primaries that were extremely saturated compared to the standards of today. While the primaries of 1953 were aspirational, it was clearly way too early. SMPTE refined NTSC to use more reasonable primaries as part of BT.601. PAL primaries are almost exactly the same (TVs tended to use the same phosphor formulation across the world I suppose), but there’s a theoretical difference so I added both for good measure. Supposedly, Japan kept the use of legacy NTSC 1953 primaries, so that opens an interesting question if the same games actually looked vastly different in Japan compared to the rest of the world? I’ve never heard anything mention this before, so who knows. Either way, I support enabling those primaries for fun. The look of it is quite … something? It would need a HDR monitor with solid gamut to do justice. Here’s with standard BT.601 primaries: (From Legaia 2, which is a purely field rendered game, hence the scanlines) and with NTSC 1953 primaries. Almost like the “Interpret sRGB as Display P3” bullshit that phones do these days to “pop”. Given all the masking we’re doing which lower average brightness, it’s beneficial to support HDR10 rendering. Now that HDR is widely available on Linux too, enjoying some HDR CRT shaders is a good time I added a few modes where I can target a specified maximum nit level. KDE at least respects MaxCLL HDR metadata and disables tonemapping if MaxCLL falls within bounds of the display. I also added a no-tonemap option where MaxCLL = 0 (unknown), which makes KDE tonemap how it wants to. Black Frame Insertion and their friends have been a thing in emulation for ages, and it works quite well with CRT simulation, especially to sell the de-interlacing effect properly. In my implementation, I query EXT_present_timing and decide how many frames I should insert in-between. There’s a gentler falloff between the frames. The overall screen brightness decreases a lot as expected, but with HDR, we can crank the brightness of the proper frame up to compensate. It’s still very experimental and any missed frame leads to horrrrrrrible flicker at the moment (big epilepsy warning), so it’s not something I actually recommend, but it’s fun to experiment with. While simulating each field independently with scanlines, we get de-interlacing the same way a CRT would in theory. This is not free from flicker of course, but most games had mitigation strategies for this. The PS2 supported blending two frames being sent to the video output. Most games render internally at e.g. 448p @ 30 FPS, but since they cannot output that resolution without component cables, the frame is output interlaced over two fields where the CRTC scans every other line rather than every line. That tends to look quite flickery if done as-is given how aliased PS2 graphics are, so what pretty much every game did was using the two CRTCs to blend the two frames vertically before sending it by programming a 1 pixel offset with duplicate inputs. By shifting the offset every field, the 30 FPS progressive image could be scanned out nicely into a 60 FPS interlaced image. This is the “flicker filter” that some games allowed toggling. Here’s a RenderDoc capture showing that CRTC 1 and 2 are configured with one pixel offset in Y: After merging and blending the frames together, a smoothed image is sent. PCSX2 GSdx and paraLLEl-GS have modes to detect this pattern and just scan out the full 480p of course, without the added blurring. Most games fall into this pattern, which is fortunate if we want to avoid interlacing shenanigans, but not all games are so nice to deal with. The “Anti-Blur” option is designed precisely for disabling this filter. I also added an option to force-disable the automatic progressive scan, mostly to test the video output that the games would actually have output back in the day, which is interlaced video. Some games decided that they wanted to render at 60 FPS and sacrifice half the vertical resolution to do so, jittering the rendering to stay in sync with the interlaced output. These are painful to deal with to this day since they absolutely require some kind of de-interlacing solution to look good. I never got satisfactory results with a typical de-interlacer, but the CRT simulation does a quite good job at it I think. It’s not perfect (interlacing wasn’t exactly perfect on CRTs either), but it’s usable for me to the point now that I can play interlaced games as intended. It’s not really possible to demonstrate this with screenshots. Some games break if you try to promote them to progressive scan, because the games might decide for some stupid reason to use the SCANMSK feature to discard pixels every other line, and rely on the FRAME scanout mode to exactly scan out the pixels that were not masked. Kings’s Field IV is an example of this absolute insanity. I maintain a patch for PCSX2-git which supports parallel-gs and now this CRT/analog thing. This is super niche stuff that I don’t really expect many people to actually use, but it’s there for those who are interested. It does what I need at least, and that’s what’s important to me. I put together some test video clips in HEVC/PQ/4:4:4/1440p at ridiculously high bitrates. I tried AV1 but my CPU could not decode it in real time, so it is what it is ._. Clip 1 is: Raw RGB passed into the CRT. It uses the game’s native 480p and widescreen support. Super sampling is 4x SSAA. Clip 2 is: “PAL60” with 3-line comb + notch. It also uses the more default 4:3 and interlaced video. It has some frame drops which completely botch the interlace and even at comically large bitrates, the aperture grill effect doesn’t translate well, so it is what it is, but it’s a rough approximation of what it should look like. Anyway, I’m happy with the results. Time to actually play something instead of debugging stuff Analog TV input path 480i instead of 240p High refresh rate simulation Field 0: 262 lines, chroma carrier starts in + phase, ends in + phase due to even number of lines Field 1: 263 lines, chroma carrier starts in + phase, ends in – phase due to odd number of lines Field 2: 262 lines, chroma carrier starts in – phase, …

0 views
Karboosx Yesterday

Don't make another AI chat bot

## AI Chat bots should be deprecated AI has come to our lives and different services for good (probably). Just look at what Microsoft is doing with Copilot :D ![microsoft copilot promo image](/image...

0 views
ava's blog 2 days ago

your social media habits sound like an abusive relationship

Most people in my life still use big social media platforms. My wife, for example, is on Tumblr. As someone who has been off of these platforms for quite a while, some of the things people share with me sound extremely odd to me; weird rules and behaviors they feel the need to abide by or else!.... Whatever that may be. Some I even recognize from back when I used them, but now I have a completely different view of them as I am no longer embedded in a culture that normalizes them. For one, apparently some people are scared of unfollowing others. " I can't unfollow them! We already follow each other for years and they'd notice and then it's awkward! " so they'd rather stick it out with someone they no longer like or whose posts they don't wanna see. They'd rather filter out all posts via keywords and other means than just unfollow. Internet strangers! Not even people in real life they'd run into. Why do you feel the need to lie so much just to protect a random person's feelings about having one less follower? The whole concept of being trapped with someone because you're "mutuals" is insane! Why do you care whether only one side follows the other? What does it matter? Why do you fuel the notion that unfollowing means downgrading a friendship or rejecting someone completely? It shouldn't be this way and you voluntarily participate in this. Same with blocking. " I can't block. That is so harsh. I can instead just block them and unblock them again so we are both unfollowed from each other. This is called softblocking. " Okay? And what for? So you can pretend it was totally a website glitch that made you guys unfollow each other? As if they wouldn't notice and know. Everyone knows what softblocking is on those platforms! Don't kid yourself. When they refollow you again, what then? What if they message you and ask why you unfollowed, the dreadful thing you fear? Many then go on to lie, saying it must have totally been an accident, and follow them again?? Guys, it's a website, pixels on a screen - you can be honest. They're not gonna stick a hand through your screen to strangle you? Thanks to digital mediums, it has never been easier to just ride out awkward shit and ignore things. Make use of it. Pressing a button is not being aggressive or dramatic. "*No, I cannot message them directly, that is awkward, we have never interacted before!" ... so? Damn, the website/app offers DMs and now you can't even privately message strangers on the internet anymore? What has this place come to? Now you're just there to scroll and passively consume ads and no longer talk to the people that share the ads around voluntarily? DMing someone is "intimate"? You are "harassing" someone with a simple message they can choose to open or ignore? Do you hear yourself? Then there is the far more subtle or platform-specific stuff... like the fact that people feel like they can't comment in the replies until others have done so, or cannot reblog something because the post is still "too small"; that liking old posts is "creepy"; watching or not watching a story, liking or not liking a post has deep consequences; you have to put things in the tags instead of the post body to be safe of OPs wrath and signal that this is for your followers only (just for OP to screenshot the tags anyway and rake you over the coals). There's also people that are too scared to challenge others directly and openly on the respective post, and instead screenshot it, put a water filter over it to visually signify they disagree with its content, and then post it themselves? The type of stuff they are comfortable to say when they think OP won't notice, while being too scared to do it underneath the post, and just living off of follower validation like " Look how dumb this is! Hype me up, like this post, comment that you agree! " is so embarrassing to see. As people on there are treating public interactions as definitive signs and ownership, when someone bad follows you and likes your posts, while you don't even follow back, you're still treated as attracting and tolerating the bad person, therefore implicitly agreeing to their vile views. I guess that's where the whole culture of " Do Not Interact " disclaimers comes from, because you have to prove from the get-go where your alliances are and as a precaution for when you haven't deeply vetted every follower you have. In the same vein, people seem to proactively confess old opinions, archive tweets, lock accounts, or add disclaimers to avoid or soften hypothetical future attacks. It all adds up to weird stories... I can't even completely recall it, investigative, roundabout stuff with second accounts and softblocking and other checks, weaponizing features of the platform, circumventing things, completely normalized mutual surveillance disguised as casual browsing, where they manually actively check who viewed stories, who liked posts, posting times, and other activity to judge the friendship level? All of this is tip-toeing around, scared to offend someone, worried about nebulous consequences and being subject to toxic rage; never getting out of the awful behaviors you're subjected to by your peers in high school. It's as if you're in an abusive relationship with the platform and its users, and it's uncomfortable to see from the outside how scared it makes you to actually interact with anyone online or use the space for what it is made for. It's like your online home constantly has signs of a punch hole in drywall. I see it with my wife as well, who also has a blog on here and sometimes would like to reply to some other blog posts on Bearblog, but never ends up doing it because " It's weird to barely post and then immediately shit on someone else's post. " and other convoluted reasons that only exist because social media culture is what it is. If you relate to anything in this post, you have been conditioned by people who can only scream and shout and " I am not reading all that " and siccing their followers on you. How sad! You're like a beaten puppy and your behaviors are completely warped. It's actively harmful for you, and I wouldn't be surprised if it significantly fuels the social anxiety you feel even when offline. In the online spaces you're in, you are always asked to put the needs of someone else above yours that you cannot even fully anticipate because they're a nebulous mob entity. Your nervous system constantly deals with the risk of using this app or site blowing up in your face, and you're always scared when you see a bunch of notifications coming up. I don't know how you can feel mentally well when this is always looming over your head. Spending my online time in places where none of this weird stuff exists has really put it into perspective. I can just reply! I can just send emails or reach out otherwise! No stress, no worries! No followers, no blocking! Again, I know why all these exist in theory, and many I've known from my own time on these platforms, but none of it is justified - period. You don't have to tell me why any of these are valid or why they happen; this is like listening to an abuse victim justify the abuse. Sometimes you can only see how badly you've been treated months or years after you leave. Reply via email Published 09 May, 2026

0 views
Susam Pal 2 days ago

I Will Not Add Query Strings to Your URLs

Last evening, a short blog post appeared in my feed reader that felt as if it spoke directly to me. It is Chris Morgan's excellent post I've banned query strings . Chris is someone whose Internet comments I have been reading for about half a decade now. I first stumbled upon his comments on Hacker News, where he left very detailed feedback on a small collection of boilerplate CSS rules I had shared there. I am by no means a web developer. I have spent most of my professional life doing systems programming in C and C++. However, developing websites and writing small HTML tools has been a long-time hobby for me. I have learnt most of my web development skills as a hobbyist by studying what other people do: first by viewing the source of websites I liked in the early 2000s, and later by occasionally getting possessed by the urge to implement a new game or tool and searching MDN Web Docs to learn whatever I needed to make it work. One problem with learning a skill this way is that you sometimes pick up habits and practices that are fashionable but not necessarily optimal or correct. So it was really valuable to me when Chris commented on my collection of boilerplate CSS rules. It helped me improve my CSS a lot. In fact, a few of the lessons from his comment have really stuck with me; I keep them in mind whenever I make a hobby HTML project: always retain underlines in links and retain purple for visited links. I have been following Chris's posts and comments on web-related topics since then. He often posts great feedback on web-related projects. Whenever I come across one, I make sure to read them carefully, even when the project isn't mine. I always end up learning something nice and useful from his comments. Here is one such recent example from the Lobsters story Adding author context to RSS . A couple of months ago, I created a new project called Wander Console . It is a small, decentralised, self-hosted web console that lets visitors to your website explore interesting websites and pages recommended by a community of independent personal website owners. For example, my console is here: susam.net/wander/ . If you click the 'Wander' button there, the tool loads a random personal web page recommended by the Wander community. The tool consists of one HTML file that implements the console and one JavaScript file where the website owner defines a list of neighbouring consoles along with a list of web pages they recommend. If you copy these two files to your web server, you instantly have a Wander console live on the Web. You don't need any server-side logic or server-side software beyond a basic web server to run Wander Console. You can even host it in constrained environments like Codeberg Pages or GitHub Pages. When you click the 'Wander' button, the console connects to other remote consoles, fetches web page recommendations, picks one randomly and loads it in your web browser. It is a bit like the now defunct StumbleUpon but it is completely decentralised. It is also a bit like web rings except that the community network is not restricted to being a cycle; it is a graph that can take any shape. There are currently over 50 websites hosting this tool. Together, they recommend over 1500 web pages. You can find a recent snapshot of the list of known consoles and the pages they recommend at susam.codeberg.page/wcn/ . To learn more about this tool or to set it up on your website, please see codeberg.org/susam/wander . In case you were wondering why I suddenly plugged my project into this post in the previous section, it is because I recently added a dubious feature to that project that I myself was not entirely convinced about. That misfeature is relevant to this post. In version 0.4.0 of Wander Console, I added support for a query parameter while loading web pages. For example, if you encountered midnight.pub while using the console at susam.net/wander/ , the console loaded the page using the following URL: This allowed the owner of the recommended website to see, via their access logs, that the visit originated from a Wander Console. Chris's recent blog post is critical of features like this. He writes: I don't like people adding tracking stuff to URLs. Still less do I like people adding tracking stuff to my URLs. ? Did I ask? If I wanted to know I'd look at the header; and if it isn't there, it's probably for a good reason. You abuse your users by adding that to the link. I mentioned earlier that I was not entirely convinced that adding a referral query string was a good thing to do. Why did I add it anyway? I succumbed to popular demand. Let me briefly describe my frame of mind when I considered and implemented that feature. When I first saw the feature request on Codeberg, my initial reaction was reluctance. I wasn't convinced it was a good feature. But I was too busy with some ongoing algebraic graph theory research, another recent hobby, with a looming deadline, so I didn't have a lot of time to think about it clearly. In fact, everything about Wander Console has been made in very little time during the short breaks I used to take from my research. I made the first version of the console in about one and a half hours one early morning when my brain was too tired to read more algebraic graph theory literature and I really needed a break. During another such break, I revisited that feature request and, despite my reservations, decided to implement it anyway. During yet another such break, I am writing this post. Normally, I don't like adding too many new features to my little projects. I want them to have a limited scope. I also want them to become stable over time. After a project has fulfilled some essential requirements I had, I just want to call it feature complete and never add another feature to it again. I'll fix bugs, of course. But I don't like to keep adding new features endlessly. That's my style of maintaining my hobby projects. So it should have been very easy for me to ignore the feature request for adding a referral query string to URLs loaded by the console tool. But I think a tired body and mind, worn down by long and intense research work, took a toll on me. Although my gut feeling was telling me that it was not a good feature, I couldn't articulate to myself exactly why. So I implemented the referral query string feature anyway. While doing so, I added an opt-out mechanism to the configuration, so that if someone else didn't like the feature, they could disable it for themselves. This was another mistake. A questionable feature like this should be implemented as an opt-in feature, not an opt-out feature, if implemented at all. The fact that I didn't have a lot of time to reason through the implications of this feature meant that I just went ahead and implemented it without thinking about it critically. As the famous quote from Jurassic Park goes: It soon turned out that my gut feeling was correct. After I implemented that feature, a page from one of my favourite websites refused to load in the console. To illustrate the problem, here are a few similar but slightly different URLs for that page: The first and second URLs load fine, but the third URL returns an HTTP 404 error page. The website uses the query string to determine which one of its several font collections to show. So when we add an arbitrary query string to the URL, the website tries to interpret it as a font collection identifier and the page fails to load. That is why, when my tool added the query parameter to the first URL, the page failed to load. Later, with a little time to breathe and some hindsight, I could articulate why adding referral query strings to a working URL was such a bad idea. Altering a URL gives you a new URL. The new URL could point to a completely different resource, or to no resource at all, even if the alteration is as small as adding a seemingly harmless query string. By adding the referral query string, I had effectively broken a working URL from a website I am very fond of. It is also worth asking whether an HTML tool should concern itself with referral query strings at all when web browsers already have a mechanism for this: the HTTP Referer header, governed by Referrer-Policy . That policy can be set at the server level, the document level or even on individual links. The Web standards already provide deliberate controls to decide how much referrer information should be sent. Appending referral query strings to URLs bypasses those controls. It moves a privacy and attribution concern out of the referrer mechanism and embeds it into the destination URL instead. I don't think an HTML tool should do that. There is also a moral question here about whether it is okay to modify a given URL on behalf of the user in order to insert a referral query string into it. I think it isn't. In the end, I decided to remove the referral query string feature from Wander Console. One might wonder why I couldn't simply leave the feature in as an opt-in. Well, the answer is that once I had deemed the feature misguided, I no longer wanted it to be part of my software in any form. The project is still new and we are still in the days of 0.x releases, so if there is a good time to remove features, this is it. But my ongoing research work left me with no time to do it. Finally, when the post I've banned query strings appeared in my feed reader last evening, it nudged me just enough to take a little time away from my academic hobby and devote it to removing that ill-considered feature. The feature is now gone. See commit b26d77c for details. The latest release, version 0.6.0, does not have it anymore. This is a lesson I'll remember for any new hobby projects I happen to make in the future. If I ever load URLs again, I'll load them exactly as the website's author intended. I will never add query strings to your URLs. Read on website | #web | #technology Wisdom on the Web Wander on the Web Broken URLs https://int10h.org/oldschool-pc-fonts/fontlist/ https://int10h.org/oldschool-pc-fonts/fontlist/?2 https://int10h.org/oldschool-pc-fonts/fontlist/?foo

0 views
Sean Goedecke 2 days ago

AI makes weak engineers less harmful

Like other kinds of puzzle-solving, software engineering ability is strongly heavy-tailed. The strongest engineers produce way more useful output than the average, and the weakest engineers often are actively net-negative: instead of moving projects along, they create problems that their colleagues have to spend time solving. That’s why many tech companies try to build a small, ludicrously well-paid team instead of a large team of more average engineers, and why so far this seems to be a winning strategy. Being effective in a large tech company is often about managing this phenomenon: trying to arrange things so that the most competent people land on projects you want to succeed, and the least competent are shunted out of the way 1 . For instance, if you’re technical lead on a project, you more or less have to ensure 2 that the most critical pieces are in the hands of people who won’t screw them up (whether by directly assigning the work, or by making sure someone can “sit on the shoulder” of the engineer who you’re worried about). Claude Code changed this. Frontier LLMs don’t have the taste or the system familiarity of a strong engineer, but they have absolutely raised the floor for weak engineers. Instead of getting a pull request that could never possibly work or would cause immediate problems, the worst you’ll now see is a standard LLM pull request: wrong in some ways, baffling in others, but at least functional on the line-by-line level and not so obviously incorrect that someone with no knowledge of the codebase could point it out. That is a huge improvement! You can try this out yourself. If you attempt to deliberately make mistakes while working with a coding agent, you’ll find that the agent pushes back hard against many obvious errors (i.e. caching user data with a non-user-specific key, writing an infinite loop that might never terminate, or leaking open files). Of course, the agent will still miss subtle errors, particularly ones that require understanding other parts of the codebase. Working with the least effective engineers is now sometimes like working with a Claude Opus or Codex instance that you communicate with over Slack. Occasionally it’s literally that: your colleague is simply pasting your messages into Claude Code and pasting you the response. This is annoying, but it’s a much better experience than working with this kind of engineer directly. After all, you probably already work with a bunch of LLM instances. The Slack interface is not ideal - unlike using Claude Code directly, you sometimes wait hours or days for a response, and you don’t get visibility into the agent’s thought processes - but it’s still helpful on the margin. More compute being thrown at your problem is better than less. Of course, this isn’t a great state of affairs for the engineer in question, who is almost certainly learning less than if they were making their own (bad) decisions. It’s also a bad state of affairs for the company, who is paying a human salary and getting a Copilot subscription (which they’re likely also paying for) 3 . After the current push to figure out what value AI is adding to engineers, I suspect there will be a push to figure out what value engineers are adding to AI , and the engineers who aren’t adding much may find themselves out of a job. You can’t talk to Claude-over-Slack like you’d talk to normal Claude. If you tend to handle LLMs roughly (insulting them, or just being very curt), you’ll have to change your communication style. A human is going to read your messages, after all, even if you’re really interacting with a LLM. There’s no point being rude. But if, like me, you say please-and-thank-you to the models 4 , you can treat your LLM-using coworker as just another Copilot window or Codex tab. It’s far better than having to treat them as an unwitting saboteur. Not all net-negative engineers use AI tools like this. Many are strongly convinced in their own wrong opinions about how to build good software, or mistrust AI in general, or believe that relying heavily on LLMs is not a good way to improve 5 . But no strong engineers use AI tools like this. Even when they’re being lazy or sloppy, a capable engineer will have enough baseline taste to catch obvious AI-generated errors. So the phenomenon of engineers 6 becoming thin wrappers around Claude Code is limited to the kind of engineers for whom this is an improvement in their work product. More charitably: many “least competent” engineers are just out of their comfort zone, and can be fine or even excel under the right circumstances (though in my view the best engineers are able to do good work in a wide variety of environments). Also, I don’t currently work with a lot of incompetent people. Much of this is based on past experience or talking to other engineers in the industry. Since your managers are doing the same thing, this can sometimes feel like Moneyball: you’re trying to identify underappreciated talent who are strong enough to help you win without being so high-profile that your boss poaches them to lead something else. I suppose it’s better to pay for nothing than to pay for net-negative output, but it still doesn’t seem good . I think this is actually the right way to hold Claude Opus 4.7. Is this true? I think relying on LLMs is not a great way for most engineers to improve, but if LLM output is consistently better than your own, it might be different. So long as you’re paying attention to where the LLM does better, it could actually be a good way to learn. I don’t have as much experience (or anecdotes) about non-engineers falling into this trap, but this post has convinced me that it might be worse. More charitably: many “least competent” engineers are just out of their comfort zone, and can be fine or even excel under the right circumstances (though in my view the best engineers are able to do good work in a wide variety of environments). Also, I don’t currently work with a lot of incompetent people. Much of this is based on past experience or talking to other engineers in the industry. ↩ Since your managers are doing the same thing, this can sometimes feel like Moneyball: you’re trying to identify underappreciated talent who are strong enough to help you win without being so high-profile that your boss poaches them to lead something else. ↩ I suppose it’s better to pay for nothing than to pay for net-negative output, but it still doesn’t seem good . ↩ I think this is actually the right way to hold Claude Opus 4.7. ↩ Is this true? I think relying on LLMs is not a great way for most engineers to improve, but if LLM output is consistently better than your own, it might be different. So long as you’re paying attention to where the LLM does better, it could actually be a good way to learn. ↩ I don’t have as much experience (or anecdotes) about non-engineers falling into this trap, but this post has convinced me that it might be worse. ↩

0 views
Rob Zolkos 2 days ago

Watch Your Agents

I’ve been telling developers to watch their logs for years. Not just when something is broken. Not just when production is on fire. Watch them while you are building. Your logs are the closest thing you have to x-ray vision for a web application. Click a button in the browser, watch the request move through the app, and you can see what is really happening behind the scenes. The habit is simple: keep the server log visible while you work. When you do, you start spotting problems long before they become production issues: The logs give you immediate feedback. They make the invisible visible. Coding agents need the same treatment. When you are working with an agent, do not just look at the final diff. Watch what it is doing. Watch the commands it runs, the files it opens, the mistakes it repeats, and the little bits of glue code it keeps inventing along the way. That is the agent equivalent of watching your development log. You are not only checking whether this turn succeeded. You are looking for patterns that can make future turns better. Most coding agents keep some kind of session history: transcripts, tool calls, command output, file edits, errors, retries, and sometimes timing information. Those logs are useful after the fact. Point the agent at its own session logs and ask it to look for patterns: A prompt I like for this: This is the same habit as watching the Rails log after clicking around a page. You are looking for the part of the system that is doing too much work, guessing too often, or hiding useful signal. A useful signal is when the model keeps generating code to do the same mechanical task. For example, imagine you have a skill for publishing blog posts. Every time you run it, the model writes a small Ruby or Python snippet to: If the agent is generating that code every time, that is a smell. The model is doing work that should probably be deterministic. Ask the agent to turn that behavior into a script: Then update the skill so future agents call the script instead of improvising the logic. Bad pattern: every publishing session, the agent manually inspects YAML front matter and tries to remember the required fields. Better pattern: create that exits non-zero when , , , or are missing or malformed. Now the agent does not need to reason about the rules from scratch. It runs the command and reacts to the result. Bad pattern: the agent repeatedly writes one-off Python to resize screenshots, compare image dimensions, or calculate visual diffs. Better pattern: create with clear output like: The agent can use the result without reinventing image processing each time. Bad pattern: the agent keeps constructing ad hoc SQL to answer common questions like “which users have duplicate active subscriptions?” or “which jobs are stuck?” Better pattern: create named scripts or Rails tasks: Now the workflow is repeatable, reviewable, and safe to run again. Bad pattern: the agent writes custom code every time it needs to build a fake webhook payload or API response. Better pattern: create or a small fixture library that produces known-good examples. The agent stops guessing at payload shapes and starts using something the test suite can trust. Moving repeated agent behavior into deterministic tools gives you a few wins: Watch the agent the way you watch your logs. When you see friction, repetition, or uncertainty, ask whether the agent needs better instructions or a better tool. Sometimes the answer is a clearer prompt. Sometimes it is a skill. And sometimes the best thing you can do is take the fragile reasoning out of the model entirely and give it a boring, deterministic script to call. That is not making the agent less useful. That is making the whole system more useful. the same query firing 50 times because of an N+1 a page that feels fine locally but is doing way too much work a slow query that needs an index an unexpected redirect or extra request a cache miss you thought was a cache hit a background job being enqueued more often than expected parameters coming through in a shape you did not expect What tasks did you repeat multiple times in this session? What code did you generate only to throw away later? Which commands failed, and what would have prevented those failures? Did you write any one-off scripts that should become checked-in tools? Did you repeatedly search for the same files or project conventions? Were there project rules you had to infer that should be documented? Which parts of the workflow were deterministic enough to automate? What should be added to , a skill, or a script? If a smaller model had to do this next time, what tools or instructions would it need? parse front matter validate the title, summary, badge, tags, and date derive the final filename move the draft into Dependability: the same input produces the same output. Determinism: fewer “creative” variations in routine work. Testability: scripts can have tests; improvised reasoning usually cannot. Reviewability: a script can be read, improved, and versioned. Cost: once the workflow is encoded, you may be able to use a smaller model for that task. Speed: future turns spend less time rediscovering the same procedure.

0 views

Photo Journal - Day 5

Thought I would try something different for this entry! Each of these photos were taken with my Gameboy Camera attached to an Analogue Pocket (since it allows easy exporting). I've had this cartridge since I was a kid (I included 2 photos from back then for fun)! The following photos are from when I was a kid and have been sitting on the cartridge for 20+ years. ↑ This was one of the cats we had when I was a kid, his name was Benthem. He had massive cheeks! ↑ I imagine this was one of my friend's chickens that lived in the countryside.

0 views
Stratechery 2 days ago

2026.19: Earning & Spending

Welcome back to This Week in Stratechery! As a reminder, each week, every Friday, we’re sending out this overview of content in the Stratechery bundle; highlighted links are free for everyone . Additionally, you have complete control over what we send to you. If you don’t want to receive This Week in Stratechery emails (there is no podcast), please uncheck the box in your delivery settings . On that note, here were a few of our favorites this week. This week’s Sharp Tech video is on Messaging AI in 2026. What We Learned from Big Tech’s First Quarter. Apple, Amazon, Meta, Google and Microsoft all reported earnings last week, and as four of the five megacaps continue to pour massive sums into AI (first quarter CapEx was more than three times that of the Manhattan Project), there are no signs of that pace slowing. Ben broke it all down across several days, including divergent market reactions to great Google numbers and Meta numbers that were arguably even better , as well as the stories for Microsoft and Apple after Q1 . Sandwiched between those Daily Updates, Tuesday’s Article zoomed out to connect Amazon’s infrastructure spending history with its AI strategy going forward . All of it was a great way to parse numbers that continue to boggle the mind, and strategy that actually looks a lot more rational than the numbers sound.  — Andrew Sharp A Conversation with Joanna Stern. How does one write a book about a tech story that seems to change every other week? Joanna Stern accepted that challenge, and explained how it went in this week’s Stratechery Interview . The resulting conversation is a delightful glimpse into the process for one of the most creative tech writers alive and the making of a book that Ben loved. Stern’s shares her thoughts on using an LLM to make a career change, as well as how AI is changing medicine (and mammograms), and limits of LLMs that are still very real. To the latter point, if you’d like to learn more about how ChatGPT misdiagnosed a preying mantis pregnancy, start with this week’s interview, and then  you can buy the book here.   — AS What’s Next for the Celtics? Like many others across the media, I picked the Boston Celtics to make the NBA Finals in June. Alas, they barely made it out of April and were eliminated in the first round to Joel Embiid and the 76ers. The GOAT podcast recapped that disaster first on Monday with a salute to the Sixers (now bittersweet after two losses to the Knicks), and on Thursday’s episode, a longer look at the mess in Boston and a variety of thorny choices from here. Get caught up on all of that and the rest of Playoffs, and if you need an additional hoops fix, this week’s Sharp Text is a salute to the maddening charms of the Minnesota Timberwolves .  — AS Google Earnings, Meta Earnings — Wall Street loved Google’s earnings, and hated Meta’s, even though the latter’s core business was more impressive. The difference is that Google is monetizing its investments now (and it might be all Anthropic). Amazon’s Durability — Amazon looked behind in AI in the training era, but is well place in the inference era, thanks to its continued investment in the long-term. Microsoft Earnings, Apple Earnings — Microsoft unveils its new agentic business model, and Apple confronts shortages in memory and chips even as the Mac benefits from AI. An Interview with Joanna Stern About Living With AI — An interview with Joanna Stern about her new book about living with AI, and starting her own media company. The Wolves Are Why We Do This — A salute to the playoff Timberwolves. Plus: Notes on Vogue history, NBA upheaval, and the “geo” in geopolitics. Google and Meta Earnings Anthropic and xAI Sweden Made DC Great Again The Sixers Get Their Moment in the Sun, A Nightmare for Celtics Fans, Thoughts on the Way Into the Second Round A Championship Response from the Spurs, What’s Next for the Celtics?, Pre-Lottery Thoughts and Emotions

0 views
David Bushell 2 days ago

Unscrewing lightbulbs

Giving lightbulbs a MAC address was a mistake that I’m living with. I’m literally unscrewing lightbulbs to renew their DHCP lease @dbushell.com - Bluesky Instead of enjoying the bank holiday Monday I updated my homelab software. I was ‘inspired’ by the Copy Fail Linux bug to run full distro upgrades. This is my self-hosted update for Spring 2026 (rough documentation to give future me a chance). Monday’s fun risked a week of pain. I do have backups but restoring them on a broken LAN is tricky. I have an ISP provided wifi router to dust off in an emergency. Along with an absurdly long 15 metre HDMI cable I do not care to unravel. My winter update added a hardware fallback but that too requires careful rejigging. I have Proxmox hosts, virtual machines, and Raspberry DietPis . They were all on Debian 12 (Bookworm) with a kernel potentially susceptible to the bug. Minimal Debian installs are perfect because I run everything in Docker anyway. Data volumes are easy to backup or network mount. I can change host at will for any service. Debian is just sensible, well documented no-fuss Linux. I used to run “minimal” Ubuntu server. Following 24.04 I found myself debloating most of the Ubuntu part (i.e. snaps). It sounds like the new coreutils are a CVE party . Glad I escaped before that drama! As it happens, this week’s Linux Unplugged episode had Canonical’s VP of Engineering spewing embarrassing AI platitudes. “Ubuntu is not for you” was the only thing said worth remembering. I updated most of my VMs first because they’re easy to restore if anything fails. I followed Lubos Rendek’s guide . Start with a full package update and then change the package sources before running another step-by-step upgrade. The only non-Debian sources I have are Docker and Tailscale. Yes that means I run Docker inside Proxmox VMs — and you can’t stop me! That’s not even my worse crime… After the Trixie upgrade I found VMs were failing to obtain a LAN IP address. The virtual network device had been renamed from to . I edited and just changed the reference. There is surely a better/more predictable fix but this was the quickest. The same name was used across all VMs so I guess 18 is the magic number. Everything has been stable so far. If issues arise I’ll just nuke and pave from a Debian 13 ISO. Docker config and volumes are backed up independently of the VM images. DietPi has a long Trixie upgrade post I didn’t read. I just curled to bash: I gave the script a cursory glance before hitting enter. I have a Pi 4 running failover DNS and a Pi 5 running my public Forgejo instance . DietPi is ideal because of the tiny footprint; I run Docker here too. Raspberry Pi still hasn’t merged upstream Copy Fail fixes. I’m already in trouble if this bug can be exploited but I did the temporary fix out of caution. I wasn’t going to bother with Proxmox 9 but after a GUI update I was informed version 8 “end of life” was August 2026 . That is soon! I followed the official upgrade guide on my Mini-ITX server . Proxmox has a tool to check compatibility. I saw no red lights so I stopped all VMs, updated package sources to Trixie, and ran the upgrade. It is critical to run again before rebooting. I ran into the systemd-boot issue . Apparently if this is not removed the system fails to boot. If my particular box fails to boot I’m in big trouble because I broke video output and have yet to fix it. I have another Proxmox machine running virtualised OPNsense for my home router. I can’t stop the OPNsense VM and upgrade the host to Proxmox 9 because the host would have no network access. I had two options: I specifically set up option 1 for such a purpose. I went with option 2. I figured any software running in memory is still alive until I reboot, right? I didn’t question whether Proxmox would kill any processes itself (it didn’t). The update was suspiciously fast. I ran again and saw a lot of yellow warnings. Yikes. Eventually I noticed I’d failed to update some sources to Trixie and I’d installed a franken-distro. After fixing mistakes all I could do was reboot and pray for an agonising two minutes. OPNsense is the only non-Debian operating system in my homelab. I manage it entirely via the web GUI. The 26.1 update had quite a few significant changes. My DHCP setup was considered “legacy” and my firewall rules required a manual migration. Despite dumbening my smart home my lightbulbs still demand a WiFi connection. I program them myself to avoid Home Assistant and proprietary apps. Turns out I hard-coded IP addresses (discovery protocols are a joke.) Despite having dynamic IPs they remained stable until the OPNsense 26.1 DHCP update. I had no easy way to identify each light. Why would they name themselves anything useful? That’s how I ended up unscrewing the bulbs one by one to see which MAC address fell off the network. I gave them static IPs on a VLAN for future me to appreciate. And with that, my home network is up to date! Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. Use my failover VM YOLO it live

0 views

Tiny Visitor Counter

I created a tiny script for counting per-page visitors on your site. It's as simple as uploading the PHP file to your server and pointing a tag to it. Leveraging the script as an image is an attempt to seed out bots (since they typically don't render images). Here's a live version of the script: You can grab the script on my Codeberg . To setup with Pure Blog , upload the PHP file to your folder and add the following HTML to your page and post footer HTML under Settings->Site (this assumes the script was uploaded to ):

0 views

Premium: AI's Circular Psychosis

In this week’s free newsletter, I explained how bad the circular AI economy is in the simplest-possible terms :  In other words, the entire AI economy effectively comes down to Anthropic and OpenAI, who take up at least 70% of Amazon’s Google’s, and Microsoft’s compute capacity , 70% to 80% of their AI revenues and 50% of their entire revenue backlog, per The Information : That’s $748 billion of the entire revenue backlog — not just AI compute — that’s dependent on Anthropic and OpenAI, two companies that cannot afford to pay these bills without constant venture capital infusions from either investors or the hyperscalers themselves.  This is a big problem, because Anthropic seems to be losing so much money that it had to raise $10 billion from Google , $5 billion from Amazon , and is reportedly trying to raise another $50 billion from investors , less than three months after it raised $30 billion on February 12, 2026, which was five months after it raised $13 billion in September 2025 . That’s $58 billion in eight months, with the potential to reach $108 billion. Now Anthropic is taking over all 300MW of SpaceX/xAI/Elon Musk’s Colossus-1 data center , which will likely cost somewhere in the region of $2.5 billion to $3.5 billion a year, given that most of the data center is made up of H100 and H200 GPUs ( with around 30,000 GB200 GPUs ). I also don’t think people realize how bad a sign this is for the larger AI economy. Musk built the 300MW Colossus-1 to be “ the most powerful AI training system in the world ,” specifically saying that it was built “ for training Grok ,” with inference handled through Oracle ( which originally earmarked Abilene for Musk but didn’t move fast enough for him ) and other cloud providers. xAI, as one of the largest non-big-two providers, had so little need for AI capacity that it was able to hand off the entirety of its self-built data center capacity to Anthropic.  If xAI doesn’t need 300MW of compute capacity that it spent at least $4 billion to build , who, exactly, are the other large customers for AI compute? I’m not even being facetious. I truly don’t know, I can’t find them, I spent most of last week looking for them , and the only answer I had a week ago was “Elon Musk buying a lot of compute for xAI to make the freaks on the Grok Subreddit able to generate pornography.”  xAI is also the only non-OpenAI/Anthropic AI lab that’s built its own capacity , capacity it clearly didn’t need, which begs the question as to why Musk needs however much capacity he’ll build at Colossus-2 . Musk claims that xAI had moved all training to Colossus-2 , but also that xAI would “ provide compute to AI companies that are taking the right steps to ensure it is good for humanity .” This apparently includes Anthropic, which Musk called “ misanthropic and evil ” a little over two months ago. Researchers believe that the actual capacity of Colossus-2 is 350MW . At $2.5bn a year or so, Anthropic will be effectively the entirety of xAI’s revenue, which was at around $107 million in the third quarter of 2025 .  To put this very, very simply: xAI should, in theory, have massive demand for AI compute, but its demand is apparently so small that it can flog a multi-billion-dollar data center to a competitor.  Sightline Climate found that 15.2GW of capacity is under construction and due to be completed by the end of 2027, and at this point I’m not sure anybody can make a compelling argument as to why it’s being built or who it’s for.  Who needs it? Who are the customers? Who is buying AI compute at such a scale that it would warrant so much construction? Where is the demand coming from if it’s not OpenAI and Anthropic? These questions shouldn’t be that hard to answer, but trust me, I’ve tried and cannot find a GPU compute customer larger than $100 million a year, and honestly, that customer was xAI.  Through many hours of research, I’ve found that the vast majority — as much as 95% — of all compute demand comes from a few places: Otherwise, every data center deal you’ve ever read about is for a theoretical future customer or an unnamed “anchor tenant” that gives them “guaranteed, pre-committed occupancy” without being identified in any way. Yet even that “pre-committed” language seems to be something of a myth, which I’ve chased down to a report from real estate firm JLL, who says that 92% of capacity currently under construction is precommitted through binding lease agreements or owner-occupied development . CBRE said it was 74.3% for the first half of 2025, and Cushman & Wakefield said it was 89% , though it also said that there was 25.3GW of capacity under construction, while Sightline sees 19.8GW under construction through the end of 2030. And man, I cannot express how fucking difficult it is to find actual data center customers outside of the ones I’ve named above. In fact, it’s pretty difficult to find any customers for GPU compute not named Anthropic, OpenAI, Microsoft, Google, Meta or Amazon.  Outside of OpenAI and Anthropic, effectively no AI software makes more than a few hundred million dollars a year, and to make that money, they have to spend it on tokens generated by models run by one of those two companies. When those companies generate those tokens, they then flow to one of a few infrastructure providers — I’ll get to the breakdown shortly — to rent out GPUs.  As I’ve discussed this week , at least 75% of Microsoft, Google and Amazon’s AI revenues come from OpenAI or Anthropic, and that’s before you count the money that Microsoft, Google and Amazon make reselling models from both companies. To get specific, The Information reports that Anthropic will pay around $1.6 billion to Amazon for reselling its models. OpenAI, per my own reporting , sent Microsoft $659 million as part of its revenue share. AI startups — all of whom are terribly unprofitable — predominantly spend their funding on models sold by OpenAI and Anthropic. Per Newcomer , as of August last year, Cursor was spending 100% of its revenue on Anthropic. Harvey, an AI tool for lawyers, raised $960 million between February 2025 and March 2026 , with most of those costs flowing to Anthropic and OpenAI.  Effectively every AI startup is a feeder for API revenue for Anthropic or OpenAI, and as a result, almost every dollar of AI revenue flows to either Google, Microsoft or Amazon. As Anthropic and OpenAI are extremely unprofitable, Google, Microsoft and Amazon then take that money and either re-invest it in OpenAI and Anthropic, as Google , Amazon and Microsoft have all done in the past few years.  At the beginning of the bubble, all three companies believed that OpenAI and Anthropic were golden geese that were, through the startups they inspired and powered, laying golden eggs that necessitated expanding their operations, leading them to spunk hundreds of billions of dollars in capex , with Amazon building the massive Project Rainier in Indiana for Anthropic and Microsoft the Atlanta and Wisconsin-based Fairwater data centers for OpenAI . They likely also thought their own services would grow fast enough to warrant the expansion, or that other large GPU consumers would rear their heads. That never happened. Instead, OpenAI grew bigger and more-demanding of Microsoft’s compute capacity, leading to Microsoft allowing it to seek other partners , in part (per The Information) because some executives believed OpenAI would die: By November 2025, OpenAI had signed a $300 billion deal with Oracle , a $22 billion deal with CoreWeave , a $38 billion deal with Amazon , and a theoretical deal with both AMD and NVIDIA . Yet by this point, Microsoft realized it was in a bind, with the majority — at least 70% if not more  of its AI revenues were dependent on OpenAI, but it had already walked away from 2GW of data center capacity to reduce its capex costs. It had also, as part of OpenAI’s conversion to a for-profit company, had convinced it to spend $250 billion in incremental revenue on Azure .  So Microsoft chose to start spreading out that capacity to neoclouds like Nebius and Nscale , effectively bankrolling their entire futures based on theoretical revenue from OpenAI, a company that plans to burn $852 billion in the next four years and cannot afford to pay any of its bills without continual subsidies. These companies were now part of a multi-threaded dependency that ultimately ended up at one place: OpenAI, which also makes up the vast majority of inference chip maker Cerebras’ revenue with its 3-year, $20 billion deal . Meanwhile, Amazon and Google thought they had it made. Anthropic was growing, and its compute demands were reasonable enough that neither had to stretch themselves too thin…until the second quarter of 2025, when Anthropic’s accelerated growth led to it starting to push against the limits of Google and Amazon’s capacity.  So Google agreed to backstop several billion dollars behind two deals with Fluidstack, a brand new AI compute company, and Amazon continued expanding its Project Rainier data center.  Yet Anthropic’s hunger wasn’t sated. After mocking OpenAI in February 2026 for “YOLOing” into compute deals (and having signed a cloud deal with Microsoft ), it massively expanded its AWS and Google Cloud deals , signed a deal with CoreWeave , and as I discussed above, took over the entirety of Musk’s Colossus-1 data center . And all of this is only happening because, based on my analysis, very little actual demand for AI compute exists outside of OpenAI and Anthropic, and OpenAI and Anthropic only exist because of Microsoft, Google, and Amazon both building and expanding their infrastructure to cater to them.  In reality, OpenAI and Anthropic are the only meaningful companies in the AI industry. They are the majority of revenue, the majority of capacity and the majority of demand. Microsoft, Google and Amazon have exploited the desperation in a tech industry that’s run out of hypergrowth ideas , and created a near-imaginary industry by propping up both companies. The mistake that most make in measuring the circularity of OpenAI and Anthropic is to focus entirely on the money raised — $13 billion from Microsoft and up to $50 billion from Amazon for OpenAI, and as much as $80 billion from Amazon and Google for Anthropic. The correct analysis starts with measuring infrastructure. Based on discussions with sources and analysis of multiple years of reporting, I estimate that of the roughly $700 billion in capex spent by Google, Meta and Microsoft since 2023, at least 5.5GW of capacity costing at least $300 billion has been built entirely for two companies. This has in turn inflated sales through multiple counterparties involving NVIDIA, ODMs like Quanta, Foxconn, Supermicro and Dell, and created a form of market-driven AI psychosis that inspired Meta to burn over $158 billion in three years and the entire world to convince itself that AI was the biggest thing ever. The reason that there isn’t another OpenAI or Anthropic is that Google, Microsoft, and Amazon bankrolled their entire infrastructure, fed them billions of dollars, and then charged them discount rates for their early compute, with sources telling me that Anthropic pays vastly below-market-rates for Trainium compute from Amazon, and The Information reporting that OpenAI was paying $1.30-per-A100-per hour in 2024, or at or around the cost of running them. By sacrificing their entire infrastructure to OpenAI and Anthropic, the hyperscalers created the illusion of demand by feeding themselves money, all while buying endless GPUs and TPUs to fill further data centers for two customers, both of whom paid discount rates that lost them money.  This capex bacchanalia gave all three companies a massive boost to their stock prices, so they kept going, even though there wasn’t really demand other than for Anthropic or OpenAI, two companies that they had to constantly cater to with investment capital and server maintenance. The belief became that all you had to do was plan to build a data center and you’d print money, boosting NVIDIA’s sales and associated counterparties in memory stocks like Sandisk . Except that never happened.  Every data center provider that doesn’t have an Anthropic, OpenAI, or Meta-related contract makes pathetic amounts of revenue that can barely keep up with their debt. AI startups make meager revenues, and lose multitudes more than they can ever hope to make.  The entire AI industry relies upon two companies that expect to burn at least $1 trillion in the next four years, with Anthropic, the supposed “compute-conscious” AI company, committing to at least $330 billion in spend in the next few years. Where does that money come from, exactly? Because neither of these companies have anything approaching a path to profitability.  Based on a deep analysis of every publicly-available source on AI compute, I can find only two significant — over $100 million a year — purchasers of AI compute outside of Anthropic, OpenAI, Meta, or associated parties like NVIDIA, Microsoft, Google and Amazon. Those two are Poolside, which reportedly spends $400 million a year , an untenable position as it only raised $500 million in total funding before its $2 billion in funding collapsed earlier this year , and Perplexity, which appears to spend some amount of money with CoreWeave and Microsoft Azure. Both run at a massive loss. Nowhere is this lack of true demand more obvious than in the neoclouds, which only seem capable of signing big deals with Anthropic, OpenAI, Microsoft (for OpenAI), and Google (for OpenAI). Oh, and Meta, who is doing this because the existence of ChatGPT gave Mark Zuckerberg such profound AI psychosis that he’s made Meta build him a CEO chatbot to talk to and burned over $150 billion. The AI industry is a brittle, circular economy, one only made possible by a lack of financial regulation and a tech industry that’s run out of ideas. Without hyperscalers propping up OpenAI and Anthropic, there would be no reason to buy so many GPUs or build so many data centers, and neoclouds would have no reason to exist. This is a giant con, a giant illusion, and a giant mistake. Meta, for reasons that defy logic. Microsoft, for OpenAI’s compute. Google, for Anthropic’s compute. Amazon, for Anthropic. 90%+ of all AI revenues flow through Anthropic and OpenAI. 90%+ of all AI compute demand comes from Anthropic, OpenAI, Meta, or associated counterparties like Google and Amazon buying compute for Anthropic or OpenAI. The vast majority of AI operations don’t require more than a few hundred to a thousand GPUs for inference, and at most 20,000 GPUs for training models. This means that for the 15.2GW of data centers under construction before 2027 ($157 billion in annual revenue) to make sense, thousands of companies will have to rent hundreds or thousands of GPUs. This also means that the DeepSeek problem — the reason that everybody freaked out in January 2025 — is actually industry-wide. More than 50% of Microsoft, Google, Amazon, CoreWeave, and Oracle’s entire revenue backlogs are from OpenAI and Anthropic. Neoclouds are unsustainable, imaginary businesses only made possible by continual subsidies from NVIDIA and the compute demands of OpenAI, Anthropic and Meta. Outside of Anthropic and OpenAI, only around $13 billion in AI compute demand exists, with much of it taken up by Meta and NVIDIA backstopping neoclouds like CoreWeave and IREN. ODMs like Supermicro, Dell, Quanta and Foxconn are largely dependent on AI server revenues that largely flow through OpenAI and Anthropic’s counterparties to fuel their server demand.

0 views