Cover illustration

TheDaily Front

Issue No. 10 Sunday, July 19 2026 #10 — SUNDAY, JULY 19, 2026
All the news that fits between a pinsetter, a parameter count, and a patent expiry.
Sunday, July 19, 2026 The Daily Front No. 10 — Contents
30stories
9,542points
4,109comments
263kllm tokens
Assembled with 29 model calls — 180,941 tokens read, 82,208 written.

Highlights

Show HN: I replaced a $120k bowling center system with $1,600 in ESP32s

A small-town bowling center sheds a six-figure scoring system for a homegrown ESP32 network and steals the day.

Qwen 3.8

Qwen and Kimi turn the open-weight model race into a capacity-crunching summer spectacle.

AI Mania Is Eviscerating Global Decision-Making

A fierce essay argues that AI enthusiasm is warping corporate judgment just as new studies question AI-aided confidence.

Blender 5.2 LTS

Blender’s 5.2 LTS release, Minecraft’s SDL3 move, and transcribe.cpp show the open-toolchain beat marching on.

A new Intel Itanium (IA-64) emulator that boots Windows

Retro computing has a banner day, from Amiga downloads and Macintosh icons to an Itanium emulator booting Windows.

From the Editor

Today’s front page finds the great machine age split between spectacle and shopcraft: trillion-parameter models jostle for attention while a bowling alley is rescued by a fistful of microcontrollers. As ever, dear reader, the future arrives not as one grand announcement, but as a mess of solder, servers, patents, and arguments in the margins.

  1. Show HN: I replaced a $120k bowling center system with $1,600 in ESP32s3
  2. Qwen 3.84
  3. Moonshot AI suspends new subscriptions due to Kimi K3 demand4
  4. OpenAI reduces Codex Model Context Size from 372k to 272k4
  5. AI Mania Is Eviscerating Global Decision-Making5
  6. AI advice made people less accurate but more confident – sudy6
  7. NYC may require landlords and realtors to disclose the use of AI in listings7
  8. Claude Code uses Bun written in Rust now8
  9. Infinities, impossibilities, and the man in the white linen suit9
  10. Transcribe.cpp10
  11. Scrying the AMD GFX1250 LLVM Tea Leaves11
  12. Minecraft: Java Edition now uses SDL312
  13. Blender 5.2 LTS13
  14. What I learned selling 2,500 MIDI recorders: Hardware is not so hard14
  15. HMD Touch 4G15
  16. The death and rebirth of my home server16
  17. Better and Cheaper Than IPTV17
  18. I joined the IndieWeb, here's what I learned18
  19. Dupes took over the world19
  20. Mathematicians still don't know the fastest way to multiply numbers20
  21. Land Atlas – soil, farmability, and crop analysis for land listings21
  22. Making Software: How to make a font22
  23. Cagire: Live Coding in Forth23
  24. UnifiedIR for Julia24
  25. Bananas sprout in Rayleigh Garden UK after 15 years25
  26. Classic Amiga titles, free to download26
  27. A Visual Catalog of Retro Macintosh Software26
  28. The Last MPEG-4 Visual Patent Has Expired26
  29. A new Intel Itanium (IA-64) emulator that boots Windows27
  30. C64 Basic Dungeon Crawler: Goblin Attack (C64 Basic Part 8)28
The Daily Front Page 2 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Main Street Firmware
show hn

Show HN: I replaced a $120k bowling center system with $1,600 in ESP32s

by section33·▲ 2,126 points·223 comments·news.ycombinator.com ↗
I might be the only SRE on Earth with his own bowling center.

I might be the only SRE on Earth with his own bowling center. It's a more in-depth gig than you'd think.

My family and I bought an abandoned 8-lane bowling center in the rural mid-west. In our small town there weren't many recreation options for families. You've heard of a food desert? This is an R&R desert.

It had been abandoned for a good reason. The roof leaks, the electrical system was constantly surging, and my 70-year-old bowling equipment (still) doesn't work perfectly. The system that keeps your score is particularly interesting to me. It's the thing you watch during your game, but it fades into the background beyond that. Turns out these things are really cool, but absurdly expensive.

Ours was installed in 2008 and cost six figures. It's calculating ball speed and trajectory, camera-based pin detection (object detection and trig, on ICs!), runs the fouling, the animations, the pinsetting machine and ball return. Very cool stuff for its age.

From the business perspective, my facility only cost me $105k. To forklift-replace the score keeping system runs anywhere between $80-$120k, depending on features, vendor, and unit age. No upgrades or service contracts, mind you, and every feature and customization is a new line item. That's for a 1:1 replacement on a system installed in 2008. Incredible, given how fast the tech world moves.

Replacement parts cost a shocking $4000 per pair of lanes. But wait, the bowling machines themselves are 70 years old, so what's this "advanced" system actually doing back there? Actuating a single relay to trigger that big old machine. Everything else is strictly mechanical. Meanwhile I've got a six-figure invoice in my hand. I'm upset.

Given the state of open hardware, computer vision, real-time event streaming, and open source running megascale products worldwide, there had to be a way to do this myself.

So far I've built an equivalent prototype for about $200 per lane-pair, $400 if you're fancy. ESP32 and ESPNow with an RS485 fallback, reporting to a raspberry pi lane computer that's really just redis and a state machine bolted to an ESP32 gateway for the mesh.

Since it's all ESP32, I've got a fistful of spare controllers in a drawer, pre-flashed or waiting to be. All common off-the-shelf hardware: microcontrollers wired to relays, optocouplers, and IR-break-beam sensors, each running slightly different firmware. Writing the firmware and protocol is the actual hard part.

It's an ESPNow star-topology mesh: each node emits events from its sensors and accepts commands for its controls, reporting to a gateway node connected to the raspi over UART. From there it's event streaming: RX packets get translated and tossed into redis, commands relay back out to the mesh as needed. RS485 sits underneath as a wired fallback for noisy RF environments.

Once the data's in redis, it's familiar middleware/React/websocket/pub-sub stuff. Any React dev can build their own UI and bowling animations. Since it all runs on commodity hardware, I can do legit anything I want as the proprietor, and I own all my data. Repairs take five minutes; I can swap the rig on a lane pair in under 10. I'd bet a house like mine could go from zero to running in an hour or two.

We're calling it OpenLaneLink, and I plan to open source the hardware, firmware, and software stack when it's ready. Bowling is fun, and I want to help keep it affordable for alleys like mine. I hate vendor lock-in. I'm not a fan of closed systems, calling support for every hiccup, or paying to "white label" my own equipment. Want to go Tron-themed for a night? Good luck finding a neon neumorphic theme in something bought at the turn of the century.

All that bugged me. Sure, bowling equipment is niche, but the open hardware and software landscape is amazing.

Thanks for reading! Let me know if anyone's interested in more posts about this bowling nonsense.

The Daily Front Page 3 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — The Open-Weight Rush
repository

OpenAI reduces Codex Model Context Size from 372k to 272k

by AmazingTurtle·▲ 338 points·159 comments·github.com ↗
★ 99,825⑂ 14,940 forks Rust

Lightweight coding agent that runs in your terminal

Read the full repository →

The Daily Front Page 4 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — The Mania Desk
article

AI Mania Is Eviscerating Global Decision-Making

by subset·▲ 398 points·250 comments·ludic.mataroa.blog ↗
I strongly believe there are entire companies right now under heavy AI psychosis.

I strongly believe there are entire companies right now under heavy AI psychosis and it’s impossible to have rational conversations with them about it. I can’t name any specific people because they include personal friends I deeply respect, but I worry about how this plays out.

Mitchell Hashimoto, of HashiCorp and Ghostty fame

Over the past year, I’ve run point on all of our company’s sales, led the technical components of all but two of our engagements, and over the lifetime of this blog have had something like 300 catchups with professionals from around the world. This has ranged from people on the ground in niche service industries to executives at Fortune 500 companies1. Because of this, I've had a front-row view to our collective institutions across both the private and public sector undergoing breath-taking mass psychosis. This essay is an attempt to describe the bizarre dynamics that are currently at play, as I am in the rare position where my wellbeing is not contingent on paying lip service to madness, and to reassure the people trying to survive amidst all of this that they are not crazy.

The reality is thus: the people in charge either have no plan, or see no path forwards other than keeping their heads down. Not at banks, not at hospitals, not in our government institutions. The world’s organisations have been captured by people in the throes of frothing excitement, and saner people who now live in a state of constant commingled fear and frustration.

I. AI Investments Are Generally Total Failures

Reading this while working for a division that pivoted to provide interfaces for agentic workflows, only to discover that only ten users had ever touched the products we made for agents, only to pivot again to support for agentic workflows, which has a lot of competition because every company has to do something agentic now and there's only like four things you can do in that space, is bracing.

– An editor of this essay

Are companies actually seeing massive productivity gains from their AI adoption? Does any of this sordid affair make sense?

This should be an easy question, but it is surprisingly hard to get a straight answer to it. Executives that tell the press that their company has gone insane will quickly find themselves removed from their positions. Employees who are honest will find themselves fired in short-order, or “randomly” selected for a round of layoffs. In fact, it is in the interests of almost every actor in the space – boards, executives, employees, vendors, consultants – to obfuscate and misrepresent the success rate of AI projects. Many publicly traded companies are putting out announcements about their AI productivity gains when I know for a fact that the businesses have done nothing other than purchase Copilot licenses and declare victory.

Yet we need to know if these projects are panning out – if the total focus on AI as a core tenet of business strategy is succeeding at a reasonable rate, then a discussion about the relative risk and reward is warranted.

Unfortunately, we live in a dark timeline. All of the AI projects we have observed as a team are failing. Every single one – we have seen 0% success in a year and a half, not only amongst projects we have been asked to participate in2, but even within projects that we have observed in passing while doing totally unrelated work. Even if you grant that AI tooling accelerates specific workloads, the method and scale of the current investments is senseless. Frequently the failure is not related to AI itself, but rather that companies are terminally bad at running software projects effectively, and as I have remarked previously, AI projects are subject to all the failure modes of normal projects plus you can get everything right and then still fail because of the method's novelty. Very few companies are so good at shipping software that they can afford the extra risk profile.

Often enough, though, it’s an actual failure in what LLMs can accomplish. The most common version of this, being rolled out across businesses around the world, is the internally-facing chatbot, or for the more daring company, the customer-facing chatbot. The story is always the same. For the former, I’ve never seen substantial internal uptake from inside a business. Employees don’t use internal chatbots because companies tend to have low-quality documentation and an LLM is not psychic – it can only know things that have been written down and made accessible. For the latter customer-facing applications, I have rarely had a pleasant experience as a consumer, with perhaps the exception of live transcription during medical appointments – hardly something worth pivoting an entire organisation around. In both cases, project leaders are very careful to avoid tracking basic metrics, such as whether the tools are being used at all, or they track metrics that are easily gamed.

For example, my last consumer interaction was attempting to get help from Mitsubishi following an automotive failure, where a very polite robot asked me to describe the problem and that I’d receive a call back as soon as someone was available. This was the single most competent implementation of such a project I’ve seen in the wild, in that the voice was natural sounding, responded quickly, was clearly “live” in production, and promised a swift resolution.

That was six months ago, and I did not, in fact, get a call back.

When Mitsubishi did not call me back, what happened? Did that request just go into the void, showing one less incident for the year? Does it appear that the phone bot resolved my query without the need for human intervention? All we know is that it didn’t show up as an error, or I’d have received a call. I’m sure it looks great in all sorts of ways except the one that matters, which is that I was planning to buy a car and decided not to buy another one of theirs.

For this reason, our team has quickly learned while on an engagement not to ask anything about ongoing AI projects in any context – by the time that project has started, it is too late for the management team, and intervention is not possible until a crisis point is inevitably reached. There is no conceivable positive outcome. The failure rate is so high that even basic inquiry leaves us in an untenable position. Any coherent question about how it’s going, what the goal is, who is using it, constitutes an inadvertent attack on the chain of command responsible for the work because there are no good answers to anything. Even in rare cases where my interlocutor has stated that things are going well (usually while the project is still mid-flight and failure has not had a chance to manifest), it is generally obvious that they are doomed, but at least in these cases I can simply agree and then go home to scream into a pillow for six hours straight3.

All of this is to say that I am very confident that almost every report at a company about “massive AI productivity gains” is untrue as a matter of brute fact. Even if some companies are seeing clear gains, this is the exception, not the norm. With that assumption in place, we can talk about the dynamics at play, and how it has become impossible for many organisations to stay focused on things that actually matter to their long-term (or even short-term) health.

II. Heretics Will Be Shot

It has become outright dangerous to even raise the possibility that AI might not be the solution to a problem, let alone be the sole focus of a company’s entire strategy.

In every sufficiently large business we have observed (say, with 500+ employees), we have noted that continued advancement, and increasingly continued employment, has started to require repeated professions of belief in the transformative power of AI for said business. I am not talking about providing ideas about how to use AI in the business – I mean religious profession, declarations of faith. Overwhelmingly these statements are made by non-technicians, though it is not uncommon for technicians to emit deranged statements to curry favour.

There have been several occasions where I have seen someone, apropos of nothing, blurt out almost word-for-word “AI is changing everything”, only to concede moments later that their organisation does not currently use LLMs for anything, and indeed, that they cannot name a single thing that has changed other than they get some use out of ChatGPT (frequently the free-tier). In one extreme case, I have seen an executive confess that they had never even used ChatGPT or any AI tool in their life, immediately after producing a technical strategy for an organisation with $2B+ in revenue which was entirely centered around AI.

Initially these statements were so absurd on their face that I thought it was some cynical ploy to achieve thought leader status, and there are certainly some people doing this – I have had it admitted to me. But the broader reality is so much worse: people who have no background in the technology at all actually believe what they are saying. As a general rule you should avoid getting into business with a liar, but if you must, you can at least reason with them even if only in private. A true believer is much more threatening because they are impervious to even inducement by self-interest.

The turning point in my belief was watching someone with a spectacular amount of money on the line fire their highest performers because they were achieving that performance without LLMs. When an employer publicly talks about AI innovation, we have to ask ourselves if they’re simply trying to manipulate the market or customers. When they privately commit to strategies like this with their own money at stake, with no attempt to communicate that strategy to external clients, I can only assume they really mean what they’re saying.

A while ago, I wrote “Contra Ptacek’s Terrible Article On AI”, which was focused on the fact that many of Ptacek’s points in his own essay “My AI Skeptic Friends Are All Nuts” were internally inconsistent4. But on the crux of the matter, we are actually in total agreement, because he opens his essay with this:

Tech execs are mandating LLM adoption. That’s bad strategy.

Which is to say that we can sidestep arguments about the precise utility of LLMs entirely and we’re left in a very simple place – it is entirely obvious to both myself and Ptacek, two people that are coming at this from fairly opposed views, that people are being really, really stupid about this, and that organisations are demanding bizarre workflow constraints from their specialist staff.5

These mandates have led to extremely strange places. Several of my peers now “AI-wash” their work, meaning that even when they can perfectly competently execute on their jobs to the satisfaction of their management teams, said managers are unhappy if the engineers haven’t used AI in the work… so now they’re lying about using LLMs even in contexts where their professional judgement is that they aren’t the appropriate tool. They just do the work, the same way they have for decades, and say Claude did it. Others are being measured on their AI bills with “token leaderboards”, where higher is better because I have evidently fallen into the pocket of Hell where the demons torment me by doing elaborate impressions of absolute fucking morons, so the people hired for their freakish ability to perform system optimisation do the obvious thing. They set the LLMs prompting themselves in a semi-plausible loop in case someone inspects the token consumption and then they watch Netflix. Not a single one has been caught, even when their own assessment of the output is that it isn’t suitable for deployment.

Checking out a parallel copy of our Go repository and telling the AI to rewrite the whole thing in Zig while I work on something else just so I can keep my job. I hate this shit so much. My job has usage tracking and quotas. I don’t use it for actual work, I just spin it up and disregard the output.

– An actual software engineer

In fact, the only people I know of to be fired over this whole thing are people that have expressed visible doubt about this organisational strategy, which again, even Ptacek thinks is transparently dumb. The net result is that everyone has learned very quickly to praise executives on their visionary AI prowess, or they will be gunned down in the proverbial streets.

III. AI Demos Are The Mind-Killer

Bless me, Father, for I have sinned. It has been ∞ days since my last confession. I accuse myself of the following sins:

One of the main pieces of infrastructure we deploy at our clients is an analytics-focused database called Snowflake – for a typical business, the bill is tiny because it’s a pay-as-you-go situation and we can process all their data in one minute a day, you get a very hands-off deployment, and in short it has many characteristics that are very pleasant for our work. One of the features in Snowflake that we don’t use is called Cortex.

Cortex is their AI chatbot layer, with the ability to plug into metadata (for non-nerds, descriptions of your data, like what a column in a spreadsheet means) and query a company’s database autonomously. In theory, you can ask a question like “What was our revenue for last week?” and it will spit out an answer.

It is not really suitable for production usage. From memory, the last time I was given a presentation on it, by actual Snowflake staff, they reported that ideal configuration results in something like ~92% accuracy due to the complexity of data at a large business (see: probably best-in-class for these tools, but imagine your CFO having one in every ten of their numbers be outright wrong) and there were serious issues with managing deployments. Nonetheless, it can be used to produce some very flashy demonstrations.

On several occasions, we’ve been exposed to folks that have been sort of lukewarm on our main offerings, but they really, really wanted to use AI to perform a natural language query on their data. And we thought “Okay, if you really want to see it, maybe we can caveat this appropriately and show you what it might look like.”

This was a terrible mistake. It backfired in the most predictable way imaginable – every lukewarm client that saw the chatbot in action, even with us telling them that it was not going to accomplish what they wanted, wanted to buy it immediately. Every other consideration, including millions of dollars that we could plausibly help them achieve by non-AI means, was swept aside. It was like a dark and terrible force seized control of their limbs, plunged their hands into their own chests, and presented their still-beating credit cards to us in grim supplication. We were so mortified by the inexplicable shift in energy that we (wisely) declined to take the money and ended the sales process, and soon thereafter removed Cortex from our list of demonstrations. It would have been too irresponsible to exploit this gap in their reasoning, and frankly, it was already irresponsible to have even run the demonstration – doctors don’t walk around showing off cool pills that they’d never prescribe.

Watching the total 180°, that shift from ice-cold to red-hot buying frenzy, was a deeply unsettling experience. It was personally uncomfortable to see people that clearly didn’t gel with us interpersonally suddenly dying to enter an ongoing relationship, but more broadly uncomfortable because for a brief moment I began to understand what is happening in sales meetings around the world. There was no warning I could have given that would have made them refuse to buy the damn thing – their appetite was as large as their budget could stretch, and some part of me wonders if this is because they knew that their ravenous hunger would be present in their own customers. They’d just buy it from us, then pivot right to a larger company and mind control their leadership team until the buck finally stops with the loser that needs to justify the expense. The main protection against this seems to be that the median vendor is so bad at their jobs that we had presented the first even somewhat-working products these people had seen, and this included an ASX-listed company that was already bragging about their AI usage. It took our team two hours to produce something that was frankly not that good – basically just typing text descriptions of data into a web browser – and it was still better than anything the leads had seen because they had nothing to show for all the investment.

In fact, we have been forced to opt out of every sale where the lead has expressed anything beyond the most fleeting curiosity in the use of AI in their business. I don’t mean that we’ve heard that they’re interested in AI and elected to drop the contract on moral grounds. I mean that, over the course of the engagement, these people have exhibited a pattern of behavior that has made it near-impossible to sell to them without incurring reputational and legal risk, and are furthermore crafting management environments that I can only describe as cultish, ineffective, and “please dear God, do not let it be on earth as it is on LinkedIn”.

IV. Executives, Game Theory, and The Emperor’s Clothes

The good news is, CISOs are used to having to protect the business from their hare-brained initiatives, and this one isn’t really that different, except that there’s a cult-like atmosphere to it that you didn’t see with, say, the cloud. It almost doesn’t matter whether you embrace the initiative or not; there’s work to be done to manage the risk, so that’s what you do. From talking to CISOs everywhere, I would say most of them are quietly skeptical but afraid to speak up.

– Career CISO and well-known speaker that asked to remain anonymous

Despite the substantial prevalence of true believers, many of the people running large AI initiatives, or making public statements about them, do not believe what they are saying. There are “heads of AI” who read this blog, at companies with $1B+ in annually recurring revenue, who have written in to say they believe their job is totally fraudulent but it was the only promotion pathway remaining at the organisation.

On a trip overseas, I had the privilege of a meeting with one of the Fortune 500 executives mentioned at the beginning of the post, who will remain anonymous so that they are not executed by firing squad by their board. As we were chatting, it became clear that they were very switched-on and technically competent, and they also happened to be at a company that had committed to the usual battery of exorbitant claims about their recent innovations – we’ve 100x’d our productivity, AI is the future of everything, I am but a vessel for OpenAI to make love to my wife. You know, normal things. But since I had them there without any microphones around, I asked why this was being repeated without opposition. Was it just sales fluff?

The answer was a lot more interesting. It was partially ridiculous sales material being delivered to an easily excitable audience, but this was not the dominant factor constraining honesty. Executives at their customers were saying absurd things about achieving 100x productivity, and this meant that if any executive at the vendor said that these gains were not plausible, it would undermine the credibility of the customer’s executive, be perceived as an attack (or heresy), and possibly result in an enterprise contract cancellation. And getting enterprise contracts cancelled because you wanted to opine on something that doesn’t really matter to your organisation’s mission is a great way to get fired.

But this company was also a major player, of the kind that signs enormous enterprise contracts with other companies. So presumably there is another vendor that has sold to them, and their CEO is worried that saying something sane will contradict this executive, and very quickly we can see how we can have executives around the world nervously pointing guns at each other, not wanting to be shot first but also watching everything gradually spiral out of control6. This is to say that we’re facing a coordination problem around executives being honest around the AI gains they’ve witnessed – if they co-operate, they keep their jobs. If they defect, they will possibly be fired by their embarrassed peers (who have now been implicitly called liars, cowards, or incompetents) and then replaced with someone that will toe the line anyway. If they could all admit the truth at once there might be some hope, but there is no way to coordinate that event.

This sounds deeply concerning, but it is worth noting that it means that some executives who are emitting nonsensical statements are not as dull as they might seem at first – they’re in a fraught political environment, where they are surrounded by many people that are gunning for their roles, and subject to the whims of a board that is undergoing similar pressure. Against all the dictates of reason, I have presented on navigating AI hype to people on S&P 500 boards7 and they are in exactly the same situation – the main comments I remember from the session were board members admitting they were skeptical, but expressing anxiety that their positions were contingent on demanding AI investment. One of them commented “investing this early seems like risk without much upside”. About two years later, I can see now that their decade-old multi-billion dollar organisation is now branded as “AI-native”, whatever the hell that means.

V. You Must Be This AI-Native To Ride

All of the above converges on the state that we find ourselves in now, where effective decisionmaking has ground to a halt. Collectively, what started as a few people undergoing either destabilising psychological events or being caught up in hype has now resulted in an environment where leaders cannot speak honestly about their beliefs on how best to guide organisations, for fear of being removed, creating a sort of distributed government by assassination. This means that the least sensible recommendations are going totally unchallenged, resulting in employees being evaluated on totally gameable metrics such as “money spent on AI”, and those employees must play along to avoid being terminated. This has also created an insatiable appetite for purchasing “AI” solutions, which target both true believers that will believe implausible claims, and also non-believers that cannot decline the purchases without having their commitment to the cause coming into question.

This means that all offers that are subject to internal politics at an ideologically captured organisation must include AI alignment, even if the value proposition is patently ambiguous. My assessment of the market so far is that a substantial component of the outburst of AI projects are actually non-AI projects with an AI element slapped on after the fact to pass the purity test.

For example, I recently witnessed an organisation handling a database migration from an Oracle database to Snowflake – instead of handling the migration directly, the vendor bolted on a preliminary phase which involved trying to get an LLM to automate the translation of the Oracle-flavored SQL to Snowflake-flavored SQL. When the project failed (due to issues getting enough permissions to automate the work, not because an LLM can’t do something that easy), the vendor simply started handling the translation by hand but the company billed it as an AI-driven success because some inconsequential portion of the SQL had been translated by AI before being pasted over.

What was actually purchased? A totally standard database migration to help an executive meet the strategic deliverable of decommissioning a system prior to license renewal. What was sold to their superiors? “I allocated a substantial percentage of my budget to AI and it helped me accomplish my mandate.” True AI projects, of the kind that is driven by an LLM as the sole mechanism underlying it, where the project can clearly fail to deliver specific numbers, are actually very rare. We mostly see them in the context of startups, and frankly we have stopped engaging with them because we kept getting to the end of the sales conversation and finding out they wanted us to build the product that they were marketing as completed.

However, some projects simply do not have an easy way to tack on the AI label, or the person advocating for them either does not want to lie or has not understood that lying has become necessary. In all cases, this either kills the request for funding outright, or adds a pervasive and intractable drag on all communications, as every request must be worked and re-worked until it is “AI enough”. Failure to comply will either result in denial or, in many cases, a demand from a true believer to know why the extra work “can’t be done with AI”. Many companies have actively publicized that this is their new hiring policy – when a member of staff requests additional headcount, they must demonstrate that they have tried to use AI first. The part that’s being left out is that if you say you used AI and still need the help, you will be labelled “bad at AI” and potentially laid off.

The net result of this is that almost every large organisation that I am aware of is no longer able to focus on anything important, unless they are one of the (very) few organisations where AI happens to address their highest priorities. They cannot buy sensible software, hire competent talent, communicate honestly with executives about the state of projects, or undertake any sort of sensible initiative.

VI. Navigating AI Mania

An emptiness falls through you
As you realize what this means
You're starting to feel what I feel
Now you've seen what I've seen

So Sick, Domesticated Incels

This is an unfortunate situation to be in, but it will pass eventually. I’ve learned a lot about the latent insanity that we have inculcated in our leadership strata, and unfortunately those traits will persist long past the current bubble, merely awaiting another similar reactivation trigger – and some organisations will stay captured until they have totally collapsed, in the way that not everyone has successfully moved away from the dreadful blockchain affair. That’s something to write about for another time.

What I wanted to get to were some thoughts on surviving the immediate crisis, either by directly making systemic improvements or by holding onto your sanity. I’ll start with the “making improvements” part, because that’s the situation I find myself in the most frequently.

When You Have Another Objective

We’re going to do a lot of sucking it up and smiling here. This section assumes that you are trying to achieve some goal that isn't repairing the organisation's manic stance, but either trying to course-correct a specific project (and possibly risk getting fired as either a leader or consultant) or achieve some totally unrelated goal.

  1. Where possible, when raising issues, do not have conversations about the state of AI projects in group settings, as this creates a dynamic where each individual member of the group is worried about outing themselves in front of their peers. Arrange for one-on-one settings. Make it clear that you are willing to countenance that the current AI environment is frothy, and that you will keep opinions unidentifiable when raising them elsewhere. Be extremely aware that the most outspoken people can be identified by their peers, so take care to avoid exposing your sources by, e.g. direct quotes. In the event that only a small minority (say, one person in a group of six people) is willing to speak out, it might be worth giving up and moving on to a patient that has better chances.
  2. For ongoing projects, an effective trick that I believe I picked up from Secrets of Consulting is the anonymous poll, where you can ask individuals to rate their opinion of an AI project’s success chances on a scale of 1 to 10. The typical split I have observed is half of those involved rating the project at a 3/10 and others at around an 8/10 – a clear bimodal split on a project that was already three years late. Bringing this data to a CEO can be an effective method of pointing out that some information is clearly being hidden from them on the state of the project.
  3. Always involve people on the ground. The only source of data on whether projects are succeeding or the investment is going anywhere are the people that use it for their day-to-day activity. Care must be taken to bring them into the environment where they are treated with respect (all sufficiently large companies have people that view subordinates as not-quite-real-people). It is not uncommon to uncover worldview-shaking information in short order – with one client, we uncovered that staff were totally unaware they had been given licenses for AI tooling, which cast into doubt all productivity claims.
  4. Do not question the broadest claims about AI. I cannot emphasize this enough. If someone says “AI is changing everything”, just let it pass if your goal is to fix an object-level problem rather than challenge the reality at the institution. The challenge can only come after you have gained the trust of the most senior person involved. Trust is gained over a meal in private where you assuage their anxieties, not by embarrassing them in front of peers.
  5. Remember that you do not know what statements have been emitted prior to entering a room. There will sometimes be people that have publicly committed to statements like “I am 100x more productive than I was last year”, and some may even wish they hadn’t said that but are too embarrassed to walk it back. In an untested room, common sense like “LLMs should not be allowed to deploy code without human review” can kill your chances to make an impact before you’ve even started.
  6. My practice requires me to maintain an honest relationship with my clients or the whole thing falls apart, so I can’t do this – but honestly, if you work in the fire service and need money to stop a puppy from catching fire, just lie. It’s fine. History will forgive you. Add a $10,000 AI chatbot to your project, exclusively discuss that part in meetings, whatever. Save that puppy.

When You're Just Trying To Survive

This is for people that are just waiting for the bubble to burst and trying not to go nuts.

  1. I have bad news – accept that you are probably not going to meaningfully push back on any of this. This is not a feature of AI, it’s a feature of dysfunctional companies.
  2. If you feel like you’re going absolutely nuts, consider switching over to contracting. I’ve advocated for contracting many times over full-time employment, but you’ll get paid a lot more and be left out of most internal politics. Also when you run into a really intolerable situation, you’ll know that you’ve got a fixed end-date.
  3. I do my best to limit my uptake of AI-related news, as it is pretty crazy-making and unproductive to consume. I no longer visit Hackernews, Reddit, or really anywhere where I am going to be drip-fed nonsense, though I allow myself exceptions for very funny things like Apple suing OpenAI over alleged corporate espionage. Consume exactly the amount you need to feel like you aren’t going insane, then stop. Ditto for complaining with friends – and tell them that’s why you’re talking about it, which buys a lot of tolerance.
  4. When someone tells me they are using AI for something when they really shouldn’t be, I smile and nod as long as they are unlikely to get themselves killed. Even family. Especially family.
  5. When someone asks me for my opinion of AI as a programmer, I recommend saying “Oh, that stuff is pretty overblown” and then changing the topic, unless they are in a position where their opinion might influence something important. Non-programmers need this guidance the most.
  6. If you’re being asked to review huge volumes of terrible AI code, just assume that the organisation is going to burn you out and fire you. You will not convince the person drowning you in 2000 line PRs to stop. Start looking for a new job as if you have already been fired. I have seen this happen many times now, and it always plays out the same way – do the job search while you have energy. Don’t worry if your speed drops or management gets annoyed at you. There is no way to avoid that, you can simply choose whether it happens now because of your job search, or later because you are too depressed to work anymore.
  7. If your manager is responding to you with clearly AI-generated text, use AI to respond to save your sanity and then look for a new job. Many people assume they will get in trouble for being that obviously rude. You will not, this particular behavior is exhibited only by true believers, and they actually like that you’ve clearly not bothered to engage with them. I know, it’s fucking wild.
  8. If you’re being asked to max out on token usage, look for a new j – okay look, you get it, right? Go find a job that isn’t going to wrench reality from your tenuous grasp. They do exist, largely at companies so small that they don’t turn up on job platforms. It might take months to find one, so start now.

Fight the good fight, and don’t let the bastards grind you down. Godspeed.


  1. Also, and this is 100% true, Matt Mullenweg once asked me for coffee because he read the AI piledrive essay, and in context probably enjoyed it, but had to cancel because he hadn’t realized he had a flight later the same day. I am willing to pay a competent witch to hex him for this slight. 
  2. We have rejected all AI implementation work. It is absolutely a gigantic bubble and we have minimized our exposure to it – every single one of our current contracts would be totally unaffected by OpenAI collapsing, save for perhaps some second-order effects such a recession causing a client to become unable to pay us. And there’s nothing we can do to insulate ourselves from that anyway. 
  3. One of the most valuable rules I’ve heard, from Gerry Weinberg, is that consulting is influencing people at their request. Unless someone has indicated that they want us to stick my nose in, usually by explicitly saying they want guidance on general data strategy, we just let the projects fail in peace. You can barely recognize me, I’m so calm these days. 
  4. We have since kissed and made up in private, though I don’t think we’ve budged at all on the core points of our viewpoints. I maintain that Thomas is a very talented writer with a lot of good advice who just happened to blow it massively that one time because he takes Hackernews commenters too seriously. We all have our weaknesses. Mine is people telling me that “Scrum is good if you do it right”. 
  5. This is always baffling to me as a matter of being a responsible adult. If I was somehow CEO at a hospital or civil engineering firm, I would not for a second think it’s my place to start mandating specific procedures or building techniques without explicit agreement from the professionals on staff – how fucking clueless are the non-technicians who have attended a few talks and are now making mandates about how their extremely expensive professionals are doing their jobs? 
  6. If you’re an executive, board member, or anyone in charge of an “AI project” that feels trapped, I would love to hear from you. I will file the serial numbers off any stories very carefully, as I’ve done here and in every other article. 
  7. This sounds very fancy, but I think it was secretly one of those compulsory professional development things and half the audience were just like, making dinner. Truly, HR and professional bodies make victims of us all. 
The Daily Front Page 5 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — AI in the Wild
article

AI advice made people less accurate but more confident – sudy

by rbanffy·▲ 332 points·187 comments·thenextweb.com ↗

Willingness to say "I don't know" collapsed from 44% to 3% when AI was available. Monetary incentives barely helped.

AI advice made people three times less accurate but twice as confident, researchers found

TL;DR

Researchers found AI advice suppressed judgment suspension from 44% to 3%, accuracy from 27% to 9%, while confidence rose from 30% to 76%. People trusted wrong AI answers.

Researchers from three French and Italian universities found that access to AI advice collapsed people’s willingness to say “I don’t know” from 44% to 3%. Accuracy dropped from 27% to 9%. Confidence, meanwhile, rose from 30% to 76%. “People became much worse, the accuracy was only one third, but they were twice as confident,” said Valerio Capraro, associate professor at the University of Milano-Bicocca.

The study, authored by Capraro with Chiara Marcoccia of École Normale Supérieure and Walter Quattrociocchi of Sapienza University of Rome, deliberately used questions where AI models typically fail: visual details from films, such as the colour of a team’s uniform in Bend It Like Beckham. The researchers used Step 3.5 Flash, a model that was usually wrong on these questions, precisely so any reduction in judgment could not be explained as sensible delegation to a reliable tool. Some participants who would have answered correctly on their own asked the AI and became wrong.

Monetary incentives helped, but not much. Willingness to admit ignorance rose from 3% to 8% and accuracy from 9% to 16%, both still well below the no-AI baselines of 44% and 27%. Wharton researchers coined the term “cognitive surrender” earlier this year to describe the same phenomenon: people accepting incorrect AI answers 80% of the time while reporting higher confidence than those working without AI. The new study adds a sharper data point. It is not just that people trust wrong AI answers. It is that the mere availability of AI suppresses the cognitive habit of recognising what you do not know.

For humans, the capacity to say ‘I don’t know’ is very important because it represents the recognition of the limits of our own knowledge,” Capraro said. He is particularly concerned about children, who are growing up with these systems before they have developed critical thinking skills. Google’s AI search overhaul replaced links with confident AI-generated summaries, and Common Sense Media this week called that design an “unacceptable risk” for students. The pattern is consistent: AI products are designed to answer, never to say “I don’t know.” The humans using them are learning to do the same.

The Daily Front Page 6 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — AI in the Wild
article

NYC may require landlords and realtors to disclose the use of AI in listings

by gnabgib·▲ 574 points·260 comments·petapixel.com ↗

A man speaks at a podium with a city seal, flanked by officials. Behind them are American flags, posters with text, and a brick wall. People in the audience listen attentively.

New York City mayor Zohran Mamdani is having a very busy week. Just a day after announcing a “click-to-cancel” rule aimed at companies like Adobe, Mamdani is cracking down on “deceptive landlord practices,” including using AI-generated and AI-edited images designed to make properties look more appealing.

Mamdani and his team released a “Rental Ripoff Report” today, and in it, the administration outlines recommendations to require landlords and realtors to disclose the use of AI to alter their listings, including any imagery.

Alongside measures like recognizing tenant unions and expanding tenants’ bargaining rights, the report also says that landlords should “disclose when rental listings have been altered using artificial intelligence or other digital tools.”

Misleading AI-generated and AI-edited images in real estate listings are an increasingly serious problem, far beyond just New York City. While the results are occasionally funny, if not terrifying, there’s nothing funny about tenants being deceived when reality does not match photos on a listing. This is especially troublesome for tenants who have to sign a lease remotely, such as when moving somewhere for a new job.

“At Rental Ripoff Hearings across the five boroughs, we heard from thousands of New Yorkers living with mold that was never treated, pests that were never addressed and fees that were never explained. Listening was only the first step. This report turns those stories into concrete action. From requiring disclosure of AI-altered listings to bringing our code enforcement systems into the 21st century and finally recognizing tenant unions, we are making it clear that every New Yorker deserves a safe home — and every landlord who refuses to provide one will be held accountable,” Mayor Mamdani says, emphasis added.

“… these policies are rooted in real experiences and address real concerns,” adds Leila Bozorg, Deputy Mayor for Housing and Planning.

“The Rental Ripoff Hearings and today’s report are writing a new chapter in tenant power in New York City. Governing is a partnership. By bringing tenants’ voices directly into policy and taking unprecedented steps to facilitate tenant organizing across the city, we are showing what governing with New Yorkers looks like,” says Cea Weaver, Director, Mayor’s Office to Protect Tenants.

After Mayor Mamdani established the Rental Ripoff Hearings during his first week in office, he met with 2,400 New Yorkers across each borough to hear about the issues a wide range of people faced. Safety and living conditions were a major focus, as were deceptive practices by landlords.


Image creditsPhoto courtesy of Mayor Mamdani’s office.

The Daily Front Page 7 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — AI in the Wild
article

Claude Code uses Bun written in Rust now

by tosh·▲ 494 points·655 comments·simonwillison.net ↗

In Rewriting Bun in Rust Jarred Sumner made the following claim:

Claude Code v2.1.181 (released June 17th) and later use the Rust port of Bun. Startup got 10% faster on Linux but otherwise, barely anyone noticed. Boring is good.

I decided to have a poke at my own Claude Code installation to see if I could find evidence that it was using Bun written in Rust.

I found these two commands convincing:

strings ~/.local/bin/claude | grep -m1 'Bun v1'

For me this outputs Bun v1.4.0 (macOS arm64). The most recent release of Bun on GitHub is currently v1.3.14 from May 12th, so that v1.4.0 version number in Claude supports them shipping a preview of a not-yet-released Bun version.

(Update: The Rust version has been released as Bun canary - running bun upgrade --canary will install this release.)

strings ~/.local/bin/claude | grep -Eo 'src/[[:alnum:]_./-]+\.rs'

This outputs a list of 563 filenames, starting with these:

src/runtime/bake/dev_server/mod.rs
src/runtime/bake/production.rs
src/bundler/bundle_v2.rs

It looks like Bun in Rust is indeed being run in production across millions of different devices. Like Jarred said, "Boring is good".

Update: Here's a neat trick from Ajan Raj:

cat > /tmp/bun-version.ts <<'EOF'
console.log("embedded bun:", Bun.version);
process.exit(0);
EOF
BUN_OPTIONS="--preload=/tmp/bun-version.ts" claude --version

This outputs 1.4.0 for me.

Here's the commit from May 17th that updated the version in package.json to 1.4.0. That version hasn't been changed since then, but also hasn't yet made it into a tagged release outside of canary.

The Daily Front Page 8 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Limits and Ghosts
article

Infinities, impossibilities, and the man in the white linen suit

by iainharper·▲ 77 points·50 comments·iain.so ↗
The greatest logician since Aristotle, a man who had proved that mathematics itself contained truths it could never prove, died unable to trust a sandwich.

Infinities, impossibilities, and the man in the white linen suit

In the last years of his life, Kurt Gödel starved himself to death. Convinced that someone was poisoning his food, he ate only what his wife Adele had tasted first. When she was hospitalised after a stroke in late 1977, he stopped eating altogether. He died in Princeton Hospital on January 14th 1978, weighing 29 kilograms. The death certificate read “malnutrition and wasting from neglect caused by personality disturbance.” The greatest logician since Aristotle, a man who had proved that mathematics itself contained truths it could never reach, was killed by a distorted inner logic he could not escape.

Almost nobody outside mathematics knows his name. Einstein did. The two were faculty at Princeton’s Institute for Advanced Study from the 1940s onward, and Einstein, by then ageing and isolated from the mainstream of physics, told colleagues that he went to his office “just to have the privilege of walking home with Kurt Gödel.” They made an odd pair on the Princeton sidewalks, Einstein rumpled and laughing, Gödel dapper in a white linen suit, talking animatedly in German on their daily walk to and from the Institute. John von Neumann, who cancelled an entire lecture series on David Hilbert’s programme after reading Gödel’s 1931 paper, called his work “singular and monumental, a landmark which will remain visible far in space and time.”

So what did Gödel prove, and why does it matter now, in the middle of an AI boom that is spending trillions of dollars, much of it resting on the assumption that intelligence is a scaling problem?

An abstract image of a white linen jacket on a chair, stretching to infinity

What incompleteness means

Put simply, Gödel proved that mathematics cannot fully explain itself. The longer version requires a little patience. In 1900, the German mathematician David Hilbert challenged the field to build what amounted to a perfect machine for mathematics. Start with a set of basic rules (called axioms), things so obviously true they need no argument, and then derive every mathematical truth from those rules, step by mechanical step. If you could do that, mathematics would be complete, meaning every true statement would be provable, consistent, and free of contradictions. You could hand the whole enterprise over to a clerk who follows instructions. This was Hilbert’s programme, and for three decades it was the organising ambition of the field. Then, in 1931, at the age of 25, Gödel demolished it in one stroke.

Gödel’s first incompleteness theorem proved that any set of rules powerful enough to handle basic arithmetic will contain true statements it cannot prove, not because the rules were poorly chosen, but as a structural feature of rule-based systems themselves.

His trick was to construct a mathematical sentence that refers to itself. Consider the sentence, “This sentence has no proof.” Gödel’s technical feat, the part that fills his 1931 paper, was to build this sentence from pure arithmetic, by encoding statements about numbers as numbers themselves. It is not English smuggled into maths. It is pure maths. There are only two possibilities. Either the system can prove it, or it cannot.

If the system can prove “This sentence has no proof,” there is an immediate problem. We have just proved a sentence that claims to have no proof. A system that proves false things is contradictory, and contradictions in mathematics are fatal. Once you allow a single one, you can use it to prove anything, including that 1 equals 2. The system becomes useless.

If the system cannot prove “This sentence has no proof.”, there is a different problem. The sentence said it had no proof, and it turns out to be right. It is a true statement. But the system has no way to prove it. So we have a truth the system cannot reach, which means Hilbert’s rulebook has a blind spot.

Any sensible mathematical system would rather have blind spots than contradictions. So the sentence (logicians call it a Gödel sentence) is true but unprovable, and Hilbert’s dream of a rulebook that can prove every true thing was dead.

Gödel’s second theorem twisted the knife. It showed that no set of mathematical rules can prove, using only its own rules, that it is free of contradictions. If you want to check whether your system is trustworthy, you always need a bigger system to do the checking, and that bigger system inherits the same limitation. Turtles all the way down.

This is not mysticism, nor is it a claim about consciousness or creativity. It is a precise result about rule-based systems, the kind of systems that all software, including AI, are built from. That is what makes it relevant today.

The failed dream that built the computer

Hilbert had asked for one more thing, and Gödel’s paper left it wounded rather than dead. Alongside completeness and consistency, he wanted decidability, a mechanical method that could, in a finite number of steps, determine whether any mathematical statement follows from the rules. No genius required: crank the handle and read the verdict.

In 1936, a 23-year-old Cambridge fellow named Alan Turing killed that too. To prove that no mechanical method could exist, he first had to pin down what “mechanical method” meant, which nobody had done before. His answer was an imaginary device, a paper tape and a head that moves along it, reading and writing symbols according to a fixed table of rules. Anything a human clerk could work out by rote, this device could also work out.

Then he showed the device has a blind spot of its own. Imagine a fortune-teller who is never wrong, and a stubborn customer determined to sabotage every forecast. “You will leave by the door.” He climbs out the window. “You will take the window.” He strolls out the door. She is not bad at her job. The job is impossible because her prediction feeds back into the very behaviour it is trying to predict.

Turing turned that scene into code. The checker plays the fortune-teller. It is a program whose job is to read any other program the way you might read a recipe, then predict its fate. Either “this one finishes” or “this one grinds on forever.”

The saboteur plays the stubborn customer. It is a short program with a copy of the checker tucked inside, plus one standing rule. Ask the checker what I am predicted to do, then do the opposite. If the prediction is that it finishes, it deliberately loops forever. If the prediction is that it runs forever, it stops dead.

So what does the checker predict for the saboteur? “Finishes” is wrong, because the saboteur hears that and loops. “Grinds on forever” is wrong, because the saboteur hears that and stops.

The saboteur is assembled entirely from the checker’s own parts, which makes it inevitable rather than a fluke. Build a perfect checker, and you have, in the same afternoon, built the plans for the thing that breaks it. A perfect checker is therefore a contradiction in terms.

Programs that predict how other programs will behave most of the time are unremarkable — static analysers and type checkers are used routinely. The program that cannot exist is the one that is never wrong. This is the so-called halting problem: Gödel’s self-referential sentence, rebuilt from machinery, a machine then forced to ask a question about itself.

To show what machines cannot do, Turing had to invent the machine. His imaginary device is the theoretical blueprint of the general-purpose computer, a single machine that can run any program you feed it as data. Nine years later, John von Neumann, who knew Turing’s paper well and admired it, wrote the First Draft of a Report on the EDVAC, which is, in logical terms, Turing’s universal machine rendered in vacuum tubes. Essentially every computer built since follows that design. The laptop on your desk and the datacentre GPU training the next frontier model are, once the engineering is stripped away, the same device from a 1936 logic paper.

Gödel himself thought Turing had done him a favour. It was Turing’s definition of a mechanical procedure, he wrote, that made a “precise and unquestionably adequate” general version of his own theorems possible. And the machine in the theorem turned out to be the thing every business now runs on, born as a stepping stone in a proof about what it could never do.

The Gödel machine and the guarantee that vanished

Once you have a machine that can run any program, the next question is whether it can improve itself autonomously. In 2003, the German computer scientist Jürgen Schmidhuber proposed a thought experiment he called the Gödel machine. It was an AI agent designed to rewrite its own code, with one ironclad constraint. It would change itself only when it could first prove, with mathematical certainty, that the change would make it better. Not “test and see.” Prove it, as you would a theorem, before running the new version. No proof, no rewrite.

Nobody ever built one. To prove that a code change will improve future performance, you need to search through all possible mathematical arguments that could establish that fact. For any interesting problem, the number of candidate proofs is so astronomically large that the search would take longer than any improvement could ever be worth. It is the computational equivalent of insisting on a signed certificate from every possible future before crossing the road. The Gödel machine was provably optimal but completely impractical.

In May 2025, the Japanese AI lab Sakana released a system called the Darwin Gödel Machine. It retained the self-improvement loop but dropped the proof requirement. Instead of proving that a code change would help, the Darwin Gödel Machine proposes changes using a large language model, tests them against SWE-bench (a benchmark that scores whether an AI can fix real bugs in real software), and keeps what works. The name still invokes Gödel, but the mechanism is Darwinian. Natural selection, not formal proof. Fitness measured by benchmark scores, not mathematical certainty.

Judged purely on the scoreboard, it delivered. The system improved its SWE-bench score from 20% to 50% through autonomous self-modification. It developed emergent behaviours, such as patch validation and error memory, that no one had designed.

Schmidhuber’s original machine, though, had exactly one property that made it safe by construction: the proof. Every modification was guaranteed to be an improvement before it ran. The Darwin Gödel Machine replaced that guarantee with something weaker: passing the benchmarks. The difference between “provably better” and “scored higher on the benchmark test” is the difference between an aircraft type certified against a spec and one that simply hasn’t crashed yet.

This is, compressed into one system’s evolution, the trajectory of AI safety. The formal guarantee was too expensive, so the industry replaced it with empirical validation and hoped nobody would notice the difference. “Self-improving” went from a mathematical statement about proof-carrying code to a softer description of an agent that rewrites itself and checks whether the benchmarks improve. Gödel was gone.

Things mathematics cannot learn

Some problems in machine learning are mathematically unanswerable. In 2019, Shai Ben-David and colleagues published a paper in Nature Machine Intelligence under the understated but devastating title “Learnability can be undecidable.” They took a straightforward question, “given this type of problem, can a machine learn to solve it?”, and proved that the deepest rules of mathematics cannot always settle it. The answer is neither yes nor no. It is silence.

The word “learnable” has an exact meaning here. A machine studies a sample and produces a rule, which is then applied to data it has never seen. That is the basis of pretty much every model we commonly use. For any given problem type, learning theory asks whether a sample size guarantees that the rule will work. If such a guarantee exists, the problem is learnable. If none does, it is not. A simple question with two possible answers. Every type of problem is supposed to get an answer.

Ben-David’s team asked it about a mundane task, choosing which adverts to show a website’s visitors based on a sample of past ones. Was this learnable or not?

The answer, in their framework, depends on how many different kinds of visitors there could possibly be. That pool is not the eight billion people alive today. The model reduces each visitor to a profile of measurements, and measurements vary enormously. A visitor might linger on a page for three seconds or for a shade over three, and between any two possible profiles there is always room for a third. The pool of possibilities therefore has no end.

That arrangement, a finite sample making predictions about an endless pool, appears across almost every AI product on the market, not just in advertising. Training data is always finite. The world into which a system is deployed is not. Ben-David’s question is whether that leap can ever carry a guarantee, and everything hinges on how big the infinity is.

That sounds like it must have an answer, but it does not. Georg Cantor proved in the 1870s that infinity comes in sizes. Whole numbers form one infinity. The points on a line form a strictly bigger one, and the proof is surprisingly simple. Try to pair every whole number with a point on the line, and Cantor showed you will always miss some, no matter how clever your pairing. Two collections are both endless, yet one permanently outruns the other. The continuum hypothesis asks a follow-up so obvious it would occur to a child. Is there any size of infinity between those two?

Gödel proved in 1940 that the standard rules of mathematics can never prove the answer is no. Later, Paul Cohen proved in 1963, using a technique he invented for the purpose, that we can never prove the answer is yes (his proof is dense, and we’re already covering a lot of theoretical mathematics).

The upshot is that no cleverer generation is coming to settle this one. The rules of mathematics simply contain no answer. Take every rule of arithmetic and logic we have and follow them as far as they go, in any direction you like. You will never arrive at yes, and you will never arrive at no. The question is open in both directions, permanently.

Now the chain closes. Whether the advertising problem is learnable depends on the size of that infinity. The size of that infinity is a question mathematics cannot answer. So whether the advertising problem is learnable is a question mathematics cannot answer. The strange silence at the very bottom of mathematics travels up the chain and surfaces as a question about showing adverts to shoppers.

Obviously, no practical everyday ad campaign hangs on the continuum hypothesis. But the casualty was the promise. Learning theory is supposed to sort every problem into neat buckets: learnable or not. Ben-David found a problem it can never sort. Not a problem waiting for better mathematicians. A problem where the sorting itself is impossible. The University of Waterloo, Ben-David’s institution, described the result as “important and almost troubling.” No budget fixes this one, the way a budget can fix training costs or patchy data. It is a hole in the floor, a place where the mathematical ground itself gives way.

The neural network that exists and cannot be built

A complementary result, published in 2022, is narrower and stranger. Training a neural network is, at bottom, an exercise in trial and error. You show the network examples, measure how wrong its answers are, then nudge its millions of internal settings to make them slightly less wrong. Repeat this billions of times, and often the network converges on something remarkably good. The Cambridge mathematician Matthew Colbrook and colleagues showed in a 2022 paper in PNAS that this process has a hard boundary nobody expected.

The boundary appeared in medical imaging. An MRI scanner does not take a photograph. It collects measurements, and to keep patients in the incredibly claustrophobic machine for minutes rather than hours, it collects far fewer than a complete image needs. Software has to rebuild the full picture from the partial data. Neural networks became the favoured tool for this reconstruction because they do it faster and more sharply than the older mathematical methods.

Then researchers started probing the results and found something unnerving. Nudge the input slightly, with a trace of noise or a small movement by the patient, and the output could change out of all proportion. Sometimes the rebuilt scan came back looking perfect but wrong, showing details that were never in the body. Worse, it is a failure that does not look like a failure. A blurry image warns you. A crisp fabricated one does not.

A demonstration of capability may show nothing is amiss, not because anyone is cheating. A demo runs the network on typical inputs, the kind it was trained on, where it genuinely performs well. The failures live in the near-misses, a typical input plus a whisker of noise. Near-misses are endless, and a demo can show only a handful of scenarios. The demo is honest, and the danger sits exactly where it cannot look.

The natural presumptive diagnosis is undertraining. Feed it more scans and buy a bigger model, and surely the wobble irons itself out. That hope is what Colbrook’s theorem takes off the table. What the paper proved has two halves. First, for certain reconstruction problems, a network that is both accurate and stable exists. Somewhere in the space of all possible settings sits a configuration immune to the wobble. Second, no training procedure can find it. Not the ones we have. Not any. None at all, ever.

The second half is what kills the more-data hope. A training procedure is itself a program, a step-by-step recipe running on the machine Turing described, and the proof covers every recipe there could ever be. More data does not change that. Data is what you feed a recipe, and the theorem is about the recipes. It is like knowing a winning lottery ticket is in a barrel whilst simultaneously holding a proof that no way of drawing from the barrel will ever pull it out. The ticket is real. The searching is futile.

As Colbrook put it, the paradox Turing and Gödel identified has now been “brought forward into the world of AI”, and for certain problems the required algorithms simply cannot exist.

For the overwhelming majority of real-world problems, training works. But there is no general way to tell in advance which problems will defeat us, and the assumption that enough data and compute will always get us over the line is, in certain corners of the problem space, provably false.

The machine you cannot contain

The most provocative extension of Gödel’s legacy into AI concerns a question that sounds simple. Can we guarantee that a sufficiently powerful AI will not cause harm?

In 2021, Manuel Alfonseca and colleagues published a paper in the Journal of Artificial Intelligence Research arguing that, for a general-purpose superintelligent system, the answer is provably no. Their argument leans on the halting problem, the impossibility Turing established on his way to inventing the computer. You can check specific programs for specific bugs. What you cannot build is the universal checker, the one that works for any program in any situation.

Alfonseca’s team showed that asking “will this AI harm humans?” is, mathematically, the same type of question as asking “will this program halt?” Both require predicting the complete future behaviour of a system from its current state. To guarantee a system will never cause harm, you would need to trace every possible sequence of actions it could take and confirm that none is harmful. That is the halting problem in different clothes, and Turing proved that this class of prediction is impossible to guarantee. You cannot build a general-purpose AI safety monitor for the same reason you cannot build a general-purpose program-behaviour predictor. The task is not difficult. It is formally, provably, impossible.

The authors went further, showing that we may not even be able to recognise when a superintelligent system has arrived, because deciding whether a machine is smarter than a human falls into the same class of unanswerable questions. The argument is grounded, not speculative, though it assumes a generality beyond any AI system possesses today. No system currently available is general enough to handle any possible input the way a true Turing machine can.

What it establishes still matters, though. Certain safety guarantees are not engineering problems awaiting a sufficiently clever solution. They are mathematical impossibilities, like trying to square the circle or list every real number between 0 and 1. The safety community can build better guardrails and better kill switches. What it cannot build, given the computational framework we share, is a system that certifies another system as unconditionally safe.

What Gödel would recognise

These four threads share a common ancestor in what Gödel proved in 1931, and Turing sharpened in 1936. Rule-based systems cannot fully account for themselves. A system cannot certify its own trustworthiness. A learning framework cannot determine its own boundaries. A safety strategy cannot verify its own completeness.

None of this is softened by the fact that a neural network feels organic rather than rule-like. A model’s weights are numbers, and its training is arithmetic, all of it running on von Neumann’s realisation of Turing’s imaginary device. AI is not adjacent to this mathematics. AI is made of it.

The AI industry, understandably, would rather not dwell on this. The commercial logic of scaling treats intelligence as a problem of sufficient resources, more data, more compute, more parameters, more money. Hard limits are a vibe-killer, and for the overwhelming majority of commercial applications, the limits Gödel identified are irrelevant. Your chatbot will not encounter the continuum hypothesis when re-drafting an email.

But whether a self-improving agent can guarantee that its improvements are genuine, and whether anyone can prove a system will not cause harm, are questions that sit squarely within the territory Gödel mapped. His inheritance is the precise framework that shows certain guarantees about thinking machines are provably unavailable, which is different from saying machines can never think.

Einstein’s eccentric walking companion saw it before anyone else. Formal systems cannot fully certify themselves. That was a logician’s problem in 1931. It became an engineer’s problem when Turing turned the proof into a machine. It is now a commercial problem, because the industry betting trillions on those machines is implicitly selling guarantees the mathematics has never supported. Guarantees generated by systems that cannot check themselves any more than Gödel’s own warped internal logic could. He died trapped inside it.

The Daily Front Page 9 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Speech, Locally
article

Transcribe.cpp

by sebjones·▲ 738 points·156 comments·workshop.cjpais.com ↗
It's accelerated everywhere.

I'm super excited to share transcribe.cpp today.

transcribe.cpp is a ggml based transcription library which supports all the latest transcription models. Every model published under the handy-computer HF org has been numerically validated and WER tested to match the reference implementation. It's accelerated everywhere.

I'm the author and maintainer of Handy. This library grew from the pains of distributing a cross-platform speech-to-text application to many people.

This is a v0.1.0 library which means that there are some rough edges which I cannot discover alone! Please report them, and let's fix them together!

Motivation

Let me say this. I think distributing a cross-platform application with the current ASR inference stack is terrible.

You've basically got whisper.cpp and ONNX. That's it. You could roll MLX in for Apple devices, but now you've to support two different engines and port models to each. I've been a fan of ONNX for getting model support into Handy quickly, but so much performance is left on the table with CPU only.

There are a few random libraries out there which claim to support a lot of models, but they have unknown authors, and unknown testing, as far as I've seen. They leave me with more questions than answers.

When will they stop maintaining this library? Has the creator thought about bindings so you can actually use it in a real desktop or mobile app? Is this effectively demo code? Have they benchmarked it? Is it faster than ONNX?

And this is what led to transcribe.cpp. As Handy's maintainer I needed a library I could trust. Where I could download a file and run inference on it. Where I can know that the inference coming from the model in the engine is as good as the reference implementation. The inference should run on the GPU for the best performance. It should be trivially embeddable in Handy, it cannot be a huge pytorch lib. It must be something that works on Mac, Windows, and Linux. And ggml seemed like by far the best way forward. It has a strong community, and a great distribution story.

So what do you get?

You get a fast and accurate inference engine with wide ranging model support.

  • Support for 16 ASR Families (60+ models) with more coming

  • Acceleration via Vulkan, Metal, CUDA, and TinyBLAS

  • Every model has been numerically verified and WER tested

  • Support for Streaming Transcription

  • Support for Batch Transcription

  • More or less drop in whisper.cpp replacement

  • Maintainer supported bindings in 4 Languages

    • Python
    • Javascript/Typescript
    • Rust
    • ObjC/Swift

Wide Model Support

We intend to support as many state-of-the-art transcription models as possible. As of today, we support most of the modern transcription models that are publicly available. There are a few missing still, but they will be added soon.

Acceleration Support

One of my top goals was to run any ASR model I wanted on Vulkan. In my opinion this is the floor for any application shipping local inference. For every model we support, there is a corresponding benchmark run from a Ryzen 4750U (CPU + Vulkan) on Fedora as well as on my M4 Max.

Numerically Verified

I also wanted to make sure that inference in transcribe.cpp is accurate and as close to the reference implementation as possible. This largely came from a huge degree of uncertainty of inference accuracy when using .onnx models I found on Hugging Face. In order to ensure the inference we do is correct we numerically validate every model versus the reference. On top of numerical validation, we run full WER sweeps to make sure that whatever the reference is outputting, we output the same thing. That means every model has run through thousands of utterances and is very close or same as the reference. And the results of this data are published in the transcribe.cpp repo as well as with each model on Hugging Face.

Drop In whisper.cpp replacement

transcribe.cpp is more or less a drop in support for whisper.cpp. The main reason for this is: Handy used whisper.cpp and I needed to ship an update with transcribe.cpp which would replace it. I needed to keep some compatibility with the very popular .bin files which run in whisper.cpp and shipped with Handy. transcribe.cpp can run them. There are some flags and features in whisper.cpp which we do not support yet. But I think for the vast majority of use cases our whisper implementation is solid and can replace whisper.cpp while having about equal performance.

Real Distribution

Language bindings were on my mind to begin with. While this library is written in C/C++, I needed bindings in Rust. And I also knew that in order for us to distribute local transcription as widely as possible, it requires at minimum decent first-party support of bindings. I've chosen 4 languages that I think are fairly representative of where people will use the library. I welcome others to contribute bindings directly to the project as well, assuming that they are willing to take on the maintenance burden of doing so.

And of course, at the end of the day, a lot of the decisions were driven by Handy. As a result of Handy being popular, I intend to maintain this library, just as I've done my best to maintain Handy. I intend to be someone who continues to maintain open source projects and contribute to the ecosystem where I can.

This library never would have existed without Handy because I wouldn't have had the problem of trying to support a bunch of different ASR models. I would have never learned all the use cases that people have for ASR. I've done my best to cover the ones that I hear about the most. Certainly, there are cases in the library that are not currently handled. If there are things that I missed, you are free to contribute to the library!

Making Local Speech to Text More Accessible

transcribe.cpp is aimed squarely at making locally run ASR easier. We know that transcription can run extremely accurately on most devices, and there should be no need to send your voice to a cloud service. An RK3566 can run models via transcribe.cpp faster than real time on its anemic CPU. Faster than real time transcription with SOTA models runs in a handful of watts. It's not a hope or a dream, it's a fact.

I think as we look forward to the future, more inference will start happening locally for one reason or the other. This brings the distribution story front and center. In order to have more applications running inference locally, we need to make running inference easier. Certainly transcribe.cpp does not solve this on the whole, and there is a long way to go, but I hope it's a small step forward. I've certainly learned a lot.

Gratitude

I am extremely thankful for all the folks who have supported this project.

First and foremost is to Mozilla AI, their BiR program, and Davide from Mozilla AI. This project was largely a problem in my head that I came to them with, and they decided to support me in solving the problem. At the time transcribe.cpp wasn't even a concrete idea, I was just exploring how to solve accelerated distribution in Handy. So a huge thanks to them, their support, and helping to bring this project into existence.

ggml. This project wouldn't be possible without ggml and all of the contributors to it. Thank you all so much for the work you've done. I think ggml really does amazing work in helping to make distributing local inference applications easy and possible.

Modal has also been a critical help for me. I reached out to them, and they gave me credits. These credits are put towards doing the WER testing and ensuring the library works well on CUDA. It is an immense help being able to verify the correctness of the work.

Blacksmith helps to power some of the CI/CD for transcribe.cpp. Again I reached out to them and they immediately responded with credits. Of course CI/CD is critical for making sure everything put out has been tested to at least some degree.

Hugging Face both for being a pillar in the local AI community, as well as providing the handy-computer org private storage, so I could upload models at my own will.

AI Assisted?

Yes absolutely. I don't think it's possible for a single individual to write an engine from scratch of this size using ggml in a handful of months without outside assistance. Were any of the words here written using AI? Nope. They came from my mouth or my fingers.

The Daily Front Page 10 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Silicon Tea Leaves
article

Scrying the AMD GFX1250 LLVM Tea Leaves

by mfiguiere·▲ 65 points·8 comments·chipsandcheese.com ↗
Scry the tea leaves that are LLVM commits.

In just a few short days, AMD will be showing off their brand new MI400 series of Datacenter Accelerators at their Advancing AI event but before that event comes, we thought it would be fun to attempt to scry the tea leaves that are LLVM commits to see what we can ascertain about this next generation of AMD accelerator.

LLVM currently has preliminary support for two new accelerators from AMD, under the codenames GFX1250 and GFX1251.

GFX1250 is an accelerator chip oriented at the machine learning market called MI455X and will be what powers the Helios rack. While the GFX1251 is oriented at the HPC market, named the MI430X and is projected by AMD to deliver over 200 TFLOPs of native double-precision compute.

We’ll focus on the GFX1250 for now though and save the GFX1251 for another day.

We’ll compare the architecture to the consumer variant, the previous generation of CDNA accelerators, and to some extent Nvidia’s Blackwell.

A curious note here is that while we know that these accelerators are not APUs, they are listed as such in LLVM.

Similarities to RDNA4

The biggest similarity with the consumer architectures is that we now have a WGP (Workgroup Processor) that are built up from two pairs of two SIMD32 arrays, but there is also four SIMDs per CU just like there was in GCN and CDNA. This seeming discrepancy is because there is no longer any need for the software to separate the two CUs in the WGP and AMD seems to use the terms interchangeably.

This “change” is probably not as structural as it might at first seem and might not even exist in hardware, the changes in the caching hierarchy simply makes the distinction pointless for the compiler as there is now a shared vector L0 cache for the whole WGP.

GFX1250 operates only in Wave32 mode, unlike RDNA that can run in Wave64 in addition to Wave32 mode. Prior CDNA GPUs can only run in Wave64 mode and we can expect to see some oddness there from a performance engineering point of view when porting things to the new accelerators and a lot of kernels will have to be re-evaluated for the new architecture.

It also seems like GFX1250 can run 20 waves per SIMD, which is four more than RDNA4 can do.

We do not know if any of these characteristics are a sign for where AMD goes on their GPUs, but I personally guess that it is a sign of times to come and a future generation of AMD GPUs will be locked to Wave32 and the “WGP” as it currently exist goes the way of the dodo but it seems like this is not happening anytime soon.

Similarly to RDNA4 we now get “WMMA” support, unlike the older “MFMA” featured in CDNA and this is where most of the machine learning capabilities of the GFX1250 will come from and we’ll look into it more later.

The dynamic VGPR allocation feature that was heavily touted in RDNA4 is missing, which is a bit strange to me since I would imagine it is even more important for machine learning workloads that are under much higher register pressure due to working with whole tensors instead of just individual vectors or matrices. The mode-switch is still there but the instruction to allocate new registers is documented as a no-op.

A Change in (C)DNA

One of the largest changes found in GFX125X is that each wave in a SIMD can now address up to 1024 Vector General Purpose Registers (VGPRs) from the Register File. This is a major improvement over prior CDNA generations where you had a split allocation of registers with up to 256 VGPRs and 256 Accumulation VGPRs, which can only be used by the matrix units, for a total of up to 512 registers allocated to a single wave at a time.

This is an even larger improvement over the register allocation behavior of the RDNA series of GPUs, RDNA can only allocate up to 256 registers to a single Wave with no allocation split. This is a major update that might at some point be part of a future generation GPU IP but I wouldn’t bet on it coming soon. We will just have to wait to see if the feature is going to stay locked to the Instinct line or if this ability to allocate up to 1024 registers to a single wave will make an appearance in the Radeon line up as well.

The maximum addressable local memory (LDS) is now 320kB per wavefront which is twice as much as CDNA4 and dwarfs the 64kB addressable in RDNA. But the actual LDS can actually be even larger, a major change in GFX125X is the merging of the LDS and vector L0 caches into what AMD is calling the WGP Cache (WGP$). While both nVidia and Intel have had a single structure for both cache and shared memory for a long time, AMD has been the odd vendor out with a split cache and LDS. GFX1250 now has a single 448KB structure that can be broken up into different allocations depending on what the compiler or programmer requests.

GFX1250 still supports packed fp32 operations allowing a single lane in the SIMD to process two fp32 operations at once just like CDNA2 and later, this practically means that when using packed instructions it has twice the vector width of RDNA.

It also inherits the more numerous and powerful SDMA units from CDNA.

Graphics Support

It is notable that nVidia and Intel do have some vestigial graphics hardware left on their accelerators and GFX125x differs a little from their offerings on this front.

  • No export instructions and therefore no rasterizer (like CDNA)
  • No image (texture) instructions (like CDNA)
  • No BVH (raytracing) instructions (like CDNA)
  • No vector parameter interpolation instructions that are used to access and interpolate vertex data in pixel shaders (like CDNA)
  • No MTBUF (typed buffer) instructions are supported (unlike CDNA and RDNA3)
  • No MUBUF (untyped buffer) instructions are supported (unlike CDNA and RDNA)
  • No LDS parameter and parameter direct loads (like CDNA)

We’re seeing that this GFX125x is even more of a pure compute accelerator than even prior CDNA architectures with nearly all graphics features having been removed. This probably saves a little bit of die space and removes features no one will miss, so it makes a lot of sense to me.

Tensor Operations

The headline feature of the MI455X is its AI capabilities, and the tensor units are what powers that. This seems to be a best of both worlds situation where AMD is combining the simpler programming model from RDNA4 with the higher performance and capabilities of CDNA4.

On RDNA4 WMMA operations are M = N = K = 16 (matrices are 16x16) except for the 4-bit ones that have K = 32 (arguments are 16x32 or 32x16 and accumulated into 16x16).

GFX1250 keeps M = N = 16, but K instead is the same as it was on CDNA4. K = 4 for 64-bit and 32-bit floating-point elements, K = 32 for floating-point 16-bit elements, K = 64 for fixed-point 8-bit elements and K = 128 for floating-point 8-bit elements. Interestingly the i4 operations stay at RDNA4 level at K=32 and are no longer a very popular data format in large AI inference scenarios due to the adoption of MX floating point operations.

Unlike on RDNA4 the sparse versions of WMMA seem to do less work per instruction than the dense ones by keeping K the same.

RDNA4 supports the following matrix of formats for WMMA

While CDNA4 supports the following for MFMA

And GFX1250 seems to support all the datatypes that are found on both CDNA4 and RDNA4 except for fp64 which seems to be restricted to GFX1251, including the support of OCP MX-style scaling that was previously available solely on CDNA4.

In addition there’s new instructions that allow you to transpose submatrices in LDS to complement the ones already in RNDA4. The fp4/fp6 versions of these have their own feature flag, that might be a sign that these will show up on consumer GPUs or it is just a coincidence.

It’s HIP to be … CUDA compatible?

Clusters

This seems to be AMD’s version of “Thread Block Clusters” that nVidia introduced in their Hopper architecture, and it seems like they allow you to schedule a cluster to a specific shader engine and seems to be a feature that will be available on future graphics hardware too.

In addition to allowing you to access the cluster information, AMD has also introduced cluster-level loads which allow you to write to the LDS of other workgroups within a cluster, similar or equivalent to multicast loads on Nvidia hardware.

Author’s Note: A claim that wasn’t substantiated about DSMEM was removed here.

Barriers

GFX1250 adds support for cluster-level barriers, which is a feature that is essentially required to make use of clusters and is equivalent to the Nvidia feature of the same name.

In addition we’re getting intrinsics for barrier arrival, the equivalent of mbarrier.arrive in Nvidia PTX. AMD does seem to take this support one step further though by not just implementing barriers in hardware but also full monitors, allowing the wave to be notified if a specific cache line is evicted from the L2 cache.

It’s unclear what these exactly are intended to be useful for since Nvidia doesn’t have a direct equivalent already, but I guess GPU programmers will find a lot of good uses for these intrinsics.

In addition to the split barriers and barrier objects already added in RDNA4, it also supports 16 named barrier objects. These are likely added as a compatibility thing, since they have been around since Nvidia’s Tesla architecture from 2006.

Transcendentals

AMD is adding hardware support for tanh, which is rare in traditional geometry but very common in neural networks as an activation function and in the solution of many differential equations.

But the whole unit seems to have been improved, they added bf16 support and the latency for fp32 operations have gone down from 9 cycles in RDNA4 to 8 cycles in GFX1250.

Cooperative Atomics

With GFX1250 we now have intrinsics to do 32x4B, 16x8B, and 8x16B atomic loads and store to global memory, the funky naming is because these are actually 128B atomic loads and stores, the first number implies how many lanes of each wavefront are involved in the atomic but the result is essentially 1, 2, or 4 complete 128B atomic memory operations.

At the hardware-level they aren’t special instructions but just a sequence of regular loads or stores that the hardware knows how to handle so that they end up on the bus correctly.

The first use-case for this that will pop into certain peoples minds is to use this to accelerate RPCS3’s Cell emulation, and while someone is obviously going to try and use it for that, there’s a bunch of use-cases for this. But a goal is likely to accelerate AMD’s equivalent to Nvidia’s Collective Communications Library (NCCL), creatively named ROCm Collective Communications Library, as explored in the paper Demystifying NCCL.

LL128 support was to some extent already enabled on CDNA but the format has now been changed to be equivalent to the Nvidia one instead of splitting into two 64B halves.

For technical reasons these operations are not available over PCIe but I assume these will be usable over CXL and UALink. Nvidia has a very similar limitation that it is only available in global memory or over NVLink.

Tensor Data Mover

Nvidia’s marketing name for this feature is the “Tensor Memory Accelerator”, and while this feature was already available to some extent in earlier CDNA iterations it has now gained more features especially related to tensors.

The basic version just allows you to load data from global memory into LDS without using the VGPRS.

While it isn’t completely clear to me exactly what capabilities are available to the tensor version since the types involved are opaque, the code isn’t totally obvious and the documentation isn’t completely clear. But Triton has some good documentation where the capabilities are enumerated. It is somewhat similar to Nvidia’s tcgen05.cp in capability except they transfer between global memory and LDS instead of between shared memory and tensor memory.

Explicit Prefetching of Vector Memory

GFX1250 adds explicit prefetching of vector memory, and AMD has finally added this feature that is available on many CPUs that are old enough to vote. Nvidia has supported this since Fermi so it really isn’t that exciting.

Some people might think that this has been a curious omission for GPUs, but unlike CPUs we’re rarely starved for registers so we can load data early and we can use the many waves running on the same core to hide the latency.

But I can imagine that inference kernels can gain some minor performance from this so it makes sense to add now I guess.

Data Dependencies

On AMD GPUs and accelerators the hardware can most of the time figure out data dependencies automatically, but in certain cases you need to do it manually.

On GCN and by extension CDNA you had three counters that allowed you to wait on operations to be completed so that you could ensure that previous operations had been completed before continuing.

  • VM_CNT for vector memory operations.

    • Incremented when a vector-memory load is issued and decremented when the data is written to the VGPRs.
    • Incremented when a vector memory store is issued and decremented when the data is written to L2 cache.
    • Incremented when a sample or image instruction is issued and decremented when the data is returned to VGPRs.
  • LGKM_CNT for LDS, GDS, Konstant (scalar memory read), and Message instructions.

    • Incremented when a LDS or GDS load is issued and decremented when the data is written to the VGPRs.
    • Incremented when a LDS or GDS store is issued and decremented when the data is written to the LDS or GDS.
    • Incremented for every DWORD worth of scalar load issued and decremented again for every DWORD read from the scalar data cache (SMEM)
    • Incremented for every message send issued and decremented when the message is actually sent.
  • EXP_CNT for VGPR exports, this is a graphics feature used for passing things like vertex positions and color values between shaders. This exists in CDNA but isn’t used so we’re going to conveniently ignore this counter

The big issue here with the GCN/CDNA setup of these counters is that instructions of different types are returned out-of-order. And in the case of scalar loads they are also returned out-of-order even within the same instruction type.

This regretfully means that you are likely to need to insert more waits more than would otherwise be required, especially for scalar reads where waiting for the counter to reach zero is the only useful value.

So AMD redesigned this part of the instruction set for RDNA4 and made it much more fine-grained. We now have a lot more of these counters.

  • LOADcnt counts the number of vector loads issued but not yet completed, similar to the first part of VM_CNT.
  • STOREcnt counts the number of vector stores issued but not yet completed, similar to the second part of VM_CNT.
  • SAMPLEcnt counts vector sample/gather/msaa/lod instructions issued but not yet completed, similar to the third part of VM_CNT.
  • DScnt counts the number of LDS instructions issued but not yet completed, equivalent to the first half of LGKM_CNT.
  • KMcnt counts the number of scalar loads and message sends issued but not yet completed, similar to the second half of LGKM_CNT.
  • EXPcnt counts the number of export or parameter loads outstanding, similar to EXP_CNT.
  • BVHcnt counts the number of vector memory BVH (raytracing) instructions issued but haven’t returned data yet. There’s obviously no GCN or CDNA equivalent since there’s raytracing hardware.

This means that RDNA4 has a lot more situations where it can avoid having to explicitly stall the core even though there is useful work to perform compared to GCN or CDNA prior to GFX1250.

And while this isn’t as big of a deal in compute tasks, in modern graphics tasks it does make a difference since for example you can issue texture reads far ahead and not have that block a regular memory load.

On GFX125x we don’t have the following graphics wait counts,

  • SAMPLEcnt doesn’t exist because there are no texture samplers.
  • EXPcnt doesn’t exist because there is no rasterizer.
  • BVHcnt doesn’t exist because there are no raytracing instructions.

But to compensate we get new ones that do not exist in RDNA4 at all,

  • ASYNCcnt, counts the number of outstanding asynchronous load and store instructions to LDS.
  • TENSORcnt, counts the number of outstanding tensor load and store instructions.
  • Xcnt, counts the number of memory operations that have not completed address translation yet and a wait here is required to be inserted before instructions that must not be retried in case of a page fault or similar.

The final one is either the most or the least interesting one to you, since it allows a simpler way to guarantee atomicity during XNACK replay.

Summary

It seems like a good improvement and AMD is catching up on features with both Hopper and Blackwell, hopefully that means that they can not only beat Nvidia in theoretical performance but also challenge the market leader in practical performance with MI455X and Helios.

The Daily Front Page 11 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — A New Window for Minecraft
article

Minecraft: Java Edition now uses SDL3

by ObviouslyFlamer·▲ 300 points·201 comments·minecraft.net ↗
We have switched the library used for window management, input and platform integration from GLFW to SDL3.

A Minecraft Java Snapshot

Happy Snapshot Tues... Thursday? Yes, you read that right! As we've entered peak vacation season here in Sweden, snapshots might not come out on their usual schedule.

In today's snapshot we have switched the library used for window management, input and platform integration from GLFW to SDL3.

We have also added new item components for custom furnace fuels, as well as several technical changes for signs, world generation and loot tables.

Happy mining!

Known Issues

  • Exclusive fullscreen mode on Windows may cause the game to crash in certain situations, especially when using multiple monitors
  • Entering Exclusive fullscreen mode crashes the game on Wayland

New Features

  • Players in spectator mode can now interact with portals to teleport

Changes

Minor Tweaks to Blocks, Items and Entities

  • Armadillos no longer try to roll up when submerged in liquids

UI

  • Removed the Raw Input mouse setting

    • Mouse input now always uses relative mouse mode while playing in-game
  • Key bindings now use physical keys instead of keyboard-layout-specific key codes

  • Borderless Fullscreen is now the default fullscreen mode

  • Switching between Borderless and Exclusive Fullscreen no longer requires restarting the game

  • Exclusive fullscreen mode on macOS is no longer supported

  • The minimum window size is now 320 by 240 pixels

  • On macOS, holding a key while entering text now displays the native accent and candidate popup

  • On Linux systems, the game will now use and prefer Wayland natively if available

Debug Overlay

  • The debug overlay now supports a separate GUI scale than the rest of the game

    • This is customizable through the Debug Options screen, F3 + F6
    • The default scale is "Auto", which tries to stay at a higher resolution than normal
    • Another option is "Unchanged", which matches your regular GUI scale
    • The rest of the options work the same as in the normal "GUI Scale", controlling the scale directly
  • Added a "player_speed" debug entry that displays the speed of the player in blocks per tick.

  • The debug overlay now shows the display refresh rate

Creative Inventory

  • Reordered mineral item and block ordering to have non-tiered ingredients up first, then tiered ingredients that craft into equipment last

    • Ingredients

      • Non-tiered minerals

      • Unrefined tiered minerals

      • Refined tiered minerals

        • Nuggets
        • Ingots
    • Building Blocks

      • Non-tiered mineral blocks and variants
      • Refined tiered mineral blocks and variants
      • Copper block family
    • Copper Blocks continue to be pushed to the end of the order in Building Blocks since they have a large list of content

  • Improved ordering of Natural Blocks tab so that all inner ordering of group content sequentially progresses from Overworld -> Nether -> End to stay consistent with other tabs

Technical Changes

  • The Data Pack version is now 111.0

  • The Resource Pack version is now 92.0

  • Loot table types that have a dedicated registry now support registry element and tag references

    • This means that the majority of fields of such types that previously accepted single elements will now accept either a namespaced ID or an inline value, while fields that previously accepted lists can now accept an inline value, a single namespaced ID, a list of namespaced IDs, a list of inline values, or a hash-prefixed tag ID

    • Affected types:

      • minecraft:advancement
      • minecraft:item_modifier
      • minecraft:loot_table
      • minecraft:number_provider
      • minecraft:predicate
      • minecraft:recipe
      • minecraft:slot_source
    • Existing reference types for predicates, item modifiers and slot sources are now obsolete and have been removed

Windowing and Input Backend

  • Minecraft now uses SDL3 instead of GLFW for window management, input and platform integration
  • Keyboard input now uses SDL scancodes for physical key positions and SDL keycodes for layout-dependent text editing shortcuts

Data Pack Version 111.0

  • Signs no longer automatically execute click events in custom text

Commands

Changes to spreadplayers

  • Whether a block is safe to spread a player to is now controlled by the #entities_can_teleport_to block tag

Environment Attributes

Added minecraft:gameplay/natural_mob_spawns

  • Defines mob spawns in an Environment Attribute Source

  • During worldgen placement, only Dimensions and Biomes will apply this Environment Attribute

  • Format: object with fields:

    • spawns_by_category - map of spawn category to weighted list of spawn data

      • Spawn data format: object with fields:

        • type - entity type, the entity to spawn
        • count - int provider, amount to spawn
    • spawn_costs - map of entity type to object with fields:

      • energy_budget - float, energy change allowed per spawn
      • charge - float, how much existing mobs will attract or repulse other charged mobs
  • Available attribute modifiers:

    • overlay

      • For each mob category, overrides the lower layer's spawn settings with the higher layer's, unless the category is not included
      • Merges each layer's spawn costs together, overriding the lower layer's spawn costs with the higher layer's if both define the same entity type
  • Default: Empty

Added minecraft:gameplay/creature_world_gen_spawn_probability

  • Sets the probability to run an iteration in which mobs defined to spawn in the creature mob category will spawn during world generation
  • Only Dimensions and Biomes will apply this Environment Attribute
  • Format: float with range [0,1)
  • Default: 0.1

Changed minecraft:visual/ambient_particles

  • Now supports interpolation between Timeline keyframes (probabilities will be crossfaded)

  • Introduced support for new modifier: append

    • Unlike override which totally replaces the particle list, this modifier concatenates all elements with the layers below

Data Components

Added minecraft:cooking_fuel

  • Describes an item that can be used as fuel for a Furnace, Smoker or Blast Furnace

  • Format: object with fields

    • burn_time - namespaced ID pointing to an element of minecraft:number_provider registry representing the time, in ticks, for which this fuel will burn
    • speed_multiplier - namespaced ID pointing to an element of minecraft:number_provider registry representing the speed of the cooking/smelting

Added minecraft:brewing_fuel

  • Describes an item that can be used as fuel for a Brewing Stand

  • Format: object with fields

    • uses - namespaced ID pointing to an element of minecraft:number_provider registry representing the number of times this fuel will brew before being consumed
    • speed_multiplier - namespaced ID pointing to an element of minecraft:number_provider registry representing the speed of the brewing
  • Note: the #brewing_fuel item tag has been removed and will no longer function to register new brewing fuels

Added minecraft:sign_text_front and minecraft:sign_text_back

  • Two identical components that represent text in front and back of a sign

  • Contents will be displayed in item tooltip

  • The format is the same as front_text and back_text fields on minecraft:sign and minecraft:hanging_sign block entities, i.e.

    • messages - a list of text components

    • filtered_messages - an optional list of text components, if omitted, it will be set to the same value as messages

      • messages and filtered_messages must have same entry count
    • color - optional dye color, default: black

    • has_glowing_text - optional boolean, default: false

Added minecraft:waxed

  • A marker for blocks with contents that are waxed
  • No fields

Added minecraft:cushion/color

  • Applied to Cushion entities when they get placed using an item
  • Format: one of 16 dye colors

Added minecraft:villager_food

Represents items that Villagers can eat. Villagers will pick up items with this component in addition to items in the #villager_picks_up tag.

  • Format: object with fields

    • nutrition - positive integer, how much hunger the item satiates in the Villager once eaten

Added minecraft:mob_visibility

Represents the visibility percentage provided by an item with the appropriate minecraft:equippable component, modifying the range at which mobs are able to detect an entity

  • Format: object with fields

    • targeting_entity - an entity ID, a list of namespaced entity IDs, or a hash-prefixed entity tag to match

    • visibility - float (between 0.0 and 10.0), with 0.0 reducing the range at which mobs detects the entity to 2 blocks while 10.0 increases the detection range tenfold

      • While multiple items with this component stack, the maximum vision will still never exceed 10.0

Block Entity Data

Changed minecraft:sign and minecraft:hanging_sign

  • By default, commands and other click events contained in Sign text are no longer executed when the block is clicked

    • Additionally, text components on newly placed Signs are no longer resolved by default
    • New boolean field called allow_op_features (defaults to false) has been added to restore previous behavior
    • Placed Signs and items with the minecraft:block_entity_data component containing Sign data stored in worlds saved before this version will have allow_op_features set to true
    • Any newly created Sign will need to have that field set explicitly
  • Changed the rules for opening the Sign edit screen after a block is placed:

    • Previously, the screen would open unless minecraft:block_entity_data was applied successfully
    • Now, the screen will open only if it could be opened normally by clicking the block (i.e. it's not waxed and only has editable text on the front side)
  • Signs will now accept and return the minecraft:sign_text_front, minecraft:sign_text_back and minecraft:waxed components

Changed minecraft:brewing_stand

The following fields are now stored as integers rather than shorts:

  • Changed the BrewTime field from a short to an integer, this is the amount of time that the current brewing process has taken so far
  • Changed the Fuel field from a byte to an integer, this is the amount of fuel remaining

The following new fields have been added:

  • Added the total_brew_time integer field, this is the total amount of time the current brewing process will take
  • Added the total_fuel integer field, this represents the amount of fuel that was added in the last refuel
  • Added the speed_multiplier float field, this will be used to speed up or slow down the next brewing process

Changed minecraft:furnace, minecraft:smoker and minecraft:blast_furnace

The following fields are now stored as integers rather than shorts:

  • Changed the cooking_time_spent field from a short to an integer, this is the amount of time that the current cooking process has taken so far
  • Changed the cooking_total_time field from a short to an integer, this is the total amount of time the current cooking process will take
  • Changed the lit_time_remaining field from a short to an integer, this is the amount of burn time remaining
  • Changed the lit_total_time field from a short to an integer, this is the total amount of burn time that was added in the last refuel

The following new fields have been added:

  • Added the speed_multiplier float field, this will be used to speed up or slow down the next brewing process

Advancements

Rewards

  • The loot sub-field in the rewards field now accepts an inline value, a single namespaced ID, a list of namespaced IDs, a list of inline values, or a hash-prefixed tag ID of a minecraft:loot_table type

Triggers

  • Multiple fields that accepted a list of loot conditions are now stricter:

    • Previous functionality of a list of conditions was equivalent to a single minecraft:all_of condition has been removed
    • Additionally, type field is mandatory (previously it defaulted to minecraft:entity_properties)
  • Some fields that previously accepted only inline loot conditions now also accept a namespaced ID of a minecraft:predicate

  • The player field, available on all triggers except minecraft:impossible, now accepts an inline value or a namespaced ID of a minecraft:predicate type

    • To avoid duplication, this field is not mentioned in entries below
Changed minecraft:any_block_use trigger
  • The location field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:bee_nest_destroyed
  • The block field has been renamed to blocks and now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:block type
  • Added field state that matches block state properties (same format as minecraft:enter_block)
Changed minecraft:bred_animals trigger
  • child, parent, and partner fields now accept an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:brewed_potion trigger
  • The potion field now accepts minecraft:potion_contents data component predicate
Changed minecraft:cured_zombie_villager trigger
  • villager and zombie fields now accept an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:default_block_use trigger
  • The location field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:effects_changed trigger
  • The source field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:enter_block
  • The block field has been renamed to blocks and now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:block type
Changed minecraft:fall_after_explosion trigger
  • The cause field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:fishing_rod_hooked trigger
  • The entity field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:placed_block trigger
  • The location field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:item_used_on_block trigger
  • The location field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:allay_drop_item_on_block trigger
  • The location field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:player_killed_entity trigger
  • The entity field now accepts an inline value or a namespaced ID of a minecraft:predicate type
  • The killing_blow.tags.id field now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:damage_type type
Changed minecraft:entity_killed_player trigger
  • The entity field now accepts an inline value or a namespaced ID of a minecraft:predicate type
  • The killing_blow.tags.id field now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:damage_type type
Changed minecraft:kill_mob_near_sculk_catalyst trigger
  • The entity field now accepts an inline value or a namespaced ID of a minecraft:predicate type
  • The killing_blow.tags.id field now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:damage_type type
Changed minecraft:lightning_strike trigger
  • bystander and lightning fields now accept an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:player_generates_container_loot trigger
  • The loot_table field has been renamed to loot_tables and now accepts a single namespaced ID, a list of namespaced IDs, a list of inline values, or a hash-prefixed tag ID of a minecraft:loot_table type

    • If a tag or a list is used, trigger will run when any listed loot table is generated
Changed minecraft:thrown_item_picked_up_by_player trigger
  • The entity field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:thrown_item_picked_up_by_entity trigger
  • The entity field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:player_hurt_entity trigger
  • The entity field now accepts an inline value or a namespaced ID of a minecraft:predicate type
  • The damage.type.tags.id field now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:damage_type type
Changed minecraft:entity_hurt_player trigger
  • The damage.type.tags.id field now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:damage_type type
Changed minecraft:player_interacted_with_entity trigger
  • The entity field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:player_sheared_equipment trigger
  • The entity field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:crafter_recipe_crafted trigger
  • The recipe_id field has been renamed to recipes and now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:recipe type

    • If a tag or a list is used, trigger will run when any listed recipe is used
Changed minecraft:recipe_crafted trigger
  • The recipe_id field has been renamed to recipes and now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:recipe type

    • If a tag or a list is used, trigger will run when any listed recipe is used
Changed minecraft:recipe_unlocked trigger
  • The recipe field has been renamed to recipes and now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:recipe type

    • If a tag or a list is used, trigger will run when any listed recipe is unlocked
Changed minecraft:slide_down_block
  • The block field has been renamed to blocks and now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:block type
Changed minecraft:summoned_entity trigger
  • The entity field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:tame_animal trigger
  • The entity field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:target_hit trigger
  • The projectile field now accepts an inline value or a namespaced ID of a minecraft:predicate type
Changed minecraft:villager_trade trigger
  • The villager field now accepts an inline value or a namespaced ID of a minecraft:predicate type

Slot Sources

Changed minecraft:group

  • The terms field now accepts an inline value, a single namespaced ID, a list of namespaced IDs, a list of inline values, or a hash-prefixed tag ID of a minecraft:slot_source type

  • Inline format of minecraft:group (previously only a list of inline slot source) can now also accept a list of namespaced IDs, a list of inline values, or a hash-prefixed tag ID of a minecraft:slot_source type

    • This format is now available consistenly available for all fields of slot source

Changed minecraft:filtered

  • The slot_source field now accepts an inline value or a namespaced ID of a minecraft:slot_source type

Changed minecraft:contents

  • The slot_source field now accepts an inline value or a namespaced ID of a minecraft:slot_source type

Changed minecraft:limit_slots

  • The slot_source field now accepts an inline value or a namespaced ID of a minecraft:slot_source type

Removed minecraft:reference

  • This slot source has become obsolete, as any field that takes slot source now accepts (among other fields) a namespaced ID of a minecraft:slot_source type

Loot Tables

  • The rolls and bonus_rolls fields now accept an inline value or a namespaced ID of a minecraft:number_provider type

Loot Table Types

Added minecraft:container_process loot table type
  • Currently used to evaluate cooking and brewing fuel values

  • It takes the following parameters:

    • container, the container or inventory being evaluated
    • block_entity, the block entity being fueled
    • block_state, the current state of the block being fueled
    • origin, the location of the block being fueled
Changed minecraft:advancement_location
  • Block entities are now available in context and can be matched by conditions like minecraft:match_block

Loot Pool Entries

  • The conditions field in loot pool entries has been renamed to condition and now accepts an inline value or a namespaced ID of a minecraft:predicate type

  • The functions field in loot pool entries has been renamed to modifier and now accepts an inline value (including list as a short form of minecraft:sequence) or a namespaced ID of a minecraft:item_modifier type

    • This field is now present on all loot entries, including previously omitted minecraft:alternatives, minecraft:sequence and minecraft:group
Changed minecraft:tag loot pool entry
  • The name field has been renamed to items and now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:item type
Changed minecraft:loot_table loot pool entry
  • The value field now accepts a single namespaced ID, a list of namespaced IDs, a list of inline values, or a hash-prefixed tag ID of a minecraft:loot_table type

  • Added expand field, working the same as in minecraft:tag pool entry:

    • if true, each entry inside tag will be added to outer pool, with weights equal to weight of this entry
    • if false, this pool entry will operate as a single entry in outer pool. If this entry gets selected, it will return all items from all referenced loot tables

Loot Functions

  • The conditions field is now available in all loot functions and has been renamed to condition

    • It now also accepts an inline value or a namespaced ID, but no longer an inline list of conditions
    • Functionality of old condition list format can be achieved by explicitly using minecraft:all_of loot condition type
  • The function field (describing function type) has been renamed to type

Changed minecraft:sequence

  • The functions field now accepts an inline value, a single namespaced ID, a list of namespaced IDs, a list of inline values, or a hash-prefixed tag ID of a minecraft:item_modifier type

  • Added optional condition field which accepts an inline value or a namespaced ID of a minecraft:predicate type

  • Inline format of minecraft:sequence (previously only a list of inline functions) can now also accept a list of namespaced IDs, a list of inline values, or a hash-prefixed tag ID of a minecraft:item_modifier type

    • This format is now consistenly available for all fields of loot function type, which means that every such field can accept an inline value, a single namespaced ID, a list of namespaced IDs, a list of inline values, or a hash-prefixed tag ID of a minecraft:item_modifier type

Changed minecraft:modify_contents

  • The modifier field now accepts an inline value or a namespaced ID of a minecraft:item_modifier type

Changed minecraft:set_attributes

  • Number providers in amount sub-fields of modifiers list now accept an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:enchanted_count_increase

  • The count field now accepts an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:enchant_with_levels

  • The levels field now accepts an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:set_custom_model_data

  • Elements in floats and colors lists can now be an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:set_enchantments

  • Values in enchantments map can now be an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:set_count

  • The count field now accepts an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:limit_count

  • The min and max fields inside limit structure now accept an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:set_damage

  • The count field now accepts an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:set_ominous_bottle_amplifier

  • The amplifier field now accepts an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:set_random_dyes

  • The number_of_dyes field now accepts an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:set_stew_effect

  • The duration field in elements of effects list now accepts an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:set_loot_table

  • The name field has been renamed to tag

Changed minecraft:exploration_map

  • The destination field is no longer optional and now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:structure type

Removed minecraft:reference

  • This function has become obsolete, as any field that takes a function now accepts (among other things) a namespaced ID to other functions

Predicates

  • The condition field (describing predicate type) has been renamed to type

Changed minecraft:all_of

  • The terms field now accepts an inline value, a single namespaced ID, a list of namespaced IDs, a list of inline values, or a hash-prefixed tag ID of a minecraft:predicate type
  • Note: values of this type can no longer be shortened to a single list, a full object with type minecraft:all_of needs to be used explicitly

Changed minecraft:any_of

  • The terms field now accepts an inline value, a single namespaced ID, a list of namespaced IDs, a list of inline values, or a hash-prefixed tag ID of a minecraft:predicate type

Changed minecraft:inverted

  • The term field now accepts an inline value or a namespaced ID of a minecraft:predicate type

Changed minecraft:random_chance

  • The chance field now accepts an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:value_check

  • The value field now accepts an inline value or a namespaced ID of a minecraft:number_provider type
  • The min and max fields inside range structure now accept an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:time_check

  • The min and max fields inside value structure now accept an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:entity_scores

  • The min and max fields inside values of scores map now accept an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:damage_source_properties

  • The predicate.tags.id field now accepts a single namespaced ID, a list of namespaced IDs, or a hash-prefixed tag ID of a minecraft:damage_type type

Removed minecraft:reference

  • This condition has become obsolete, as any field that takes a loot condition now accepts (among other things) a namespaced ID to other conditions

Added vanilla predicates

  • minecraft:block/fast_cooking

Added minecraft:match_block condition type

Matches block state and optionally block entity data and components (if present)

Fields (same as elements of minecraft:can_place_on components):

  • blocks - optional block id, list of namespaced block IDs, or hash-prefixed block tag to match
  • state: optional map of block state property keys to values to match
  • nbt: optional block entity NBT to match
  • match will fail if this field is present, but block entity is not available in context
  • components - optional map of exact components to match
  • match will fail if this field is present, but block entity is not available in context
  • predicates - optional map of component predicates to match
  • match will fail if this field is present, but block entity is not available in context

Removed minecraft:block_state_property condition type

  • This has been fully replaced by minecraft:match_block

Number Providers

  • The type field always needs to be specified explicitly when using an inline number provider (it was previously defaulting to minecraft:uniform)

Added vanilla number providers

  • minecraft:cooking/time_bamboo

    • Returns the burn time in ticks for bamboo and scaffolding
  • minecraft:cooking/time_blaze_rod

    • Returns the burn time in ticks for blaze rods
  • minecraft:cooking/time_boats

    • Returns the burn time in ticks for boats
  • minecraft:cooking/time_coal

    • Returns the burn time in ticks for coal
  • minecraft:cooking/time_coal_block

    • Returns the burn time in ticks for coal blocks
  • minecraft:cooking/time_dried_kelp_block

    • Returns the burn time in ticks for dried kelp blocks
  • minecraft:cooking/time_dry_plants

    • Returns the burn time in ticks for various dry plants
  • minecraft:cooking/time_hanging_signs

    • Returns the burn time in ticks for hanging signs
  • minecraft:cooking/time_lava_bucket

    • Returns the burn time in tickss for lava buckets
  • minecraft:cooking/time_roots

    • Returns the burn time in ticks for mangrove roots
  • minecraft:cooking/time_wood_blocks

    • Returns the burn time in ticks for wood blocks
  • minecraft:cooking/time_wood_items_extra_small

    • Returns the burn time in ticks for very small wood items such as buttons
  • minecraft:cooking/time_wood_items_large

    • Returns the burn time in ticks for large wood items such as doors
  • minecraft:cooking/time_wood_items_small

    • Returns the burn time in ticks for small wood items such as bows
  • minecraft:cooking/time_wood_slabs

    • Returns the burn time in ticks for wood slabs
  • minecraft:cooking/time_wool

    • Returns the burn time in ticks for most wool blocks
  • minecraft:cooking/time_wool_carpets

    • Returns the burn time in ticks for wool carpets
  • minecraft:cooking/time_wool_slabs

    • Returns the burn time in ticks for wool slabs and cushions
  • minecraft:cooking/speed_default

    • Returns the default speed multiplier for cooking fuel
  • minecraft:brewing/speed_default

    • Returns the default speed multiplier for brewing fuel
  • minecraft:brewing/uses_default

    • Returns the default number of brews provided by brewing fuel

Changed minecraft:number_dispatcher

  • Fields:

    • cases - a list of cases in the order that the dispatcher will try to execute them

      • Fields:

        • condition - an inline value or a namespaced ID of a minecraft:predicate type
        • number_provider - an inline value or a namespaced ID of a minecraft:number_provider type which is executed if the condition is fulfilled
    • default - an optional inline value or a namespaced ID of a minecraft:number_provider type

      • Defaults to a constant 0 if omitted

Changed minecraft:conditional_value

  • Fields:

    • conditions - an inline value or a namespaced ID of a minecraft:predicate type

    • on_true - an inline value or a namespaced ID of a minecraft:number_provider type which is executed if its condition is fulfilled

    • on_false - an optional inline value or a namespaced ID of a minecraft:number_provider type

      • Defaults to a constant 0 if omitted

Changed minecraft:weighted_list

  • Fields:

    • distribution - a list of objects with the following fields

      • Fields:

        • data - an inline value or a namespaced ID of a minecraft:number_provider type
        • weight - a positive integer

Changed minecraft:uniform

  • The min and max fields now accept an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:binomial

  • The n and p fields now accept an inline value or a namespaced ID of a minecraft:number_provider type

Changed minecraft:sum

  • The summands field now accepts an inline value, a single namespaced ID, a list of namespaced IDs, a list of inline values, or a hash-prefixed tag ID of a minecraft:number_provider type

Recipes

Smoker and Blast Furnace Recipes

The recipes for Smokers and Blast Furnaces now use the same cooking time in their data definition as their Furnace counterparts.

The cooking time speedup is now done through the minecraft:cooking/speed_default Number Provider used by the furnace fuel components.

World Generation

Biomes

  • Removed the spawners, spawn_costs, and creature_spawn_probabi
The Daily Front Page 12 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — The Long Roar Ahead
article

Blender 5.2 LTS

by makizar·▲ 387 points·155 comments·blender.org ↗
Node-powered physics, online asset libraries, and fierce new features throughout with 2 years of LTS updates.

Node-powered physics, online asset libraries, and fierce new features throughout with 2 years of LTS updates.

Showcase Reel

Blender 5.2 LTS showcase reel featuring work by the Blender community.

Watch the Recap Video

New features overview by Jonathan Lampel and Wayne Dixon from CGCookie, Cartesian Caramel, Paul Caggegi

Blender 5.2 LTS splash artwork by Joanna Kobierska, featuring the now-extinct Panthera spelaea

GEOMETRY NODES

Music to your Nodes

Imagine driving your nodes with imported audio files, how does that sound?

The Sample Sound Frequencies node, coupled with the new Sound socket, brings audio-reactive animations and simulations to Geometry Nodes.

Sound files can be loaded directly into the node tree. To hear them during playback, add them to the Video Sequencer as well, and set Playback Sync to “Sync to Audio”.

Read Manual

Sample Sound Frequencies

Sample Sound Frequencies node.

Warning: contains sound. Audio-reactive animation by Cartesian Caramel.

Download Demo File

GEOMETRY NODES

Bevel and be well

A new node enters the chat: Mesh Bevel.

The long awaited power of detailed procedural control over the edges or vertices.

Read Manual

Cloth Dynamics

Quickly add a cloth-like behaviour to any mesh with a new node-based modifier (and a node group as well). Comes with a list of built-in controls for pinning, tearing, controlling stretch and bendiness.

Hair Dynamics

Hair physics work similarly to cloth: the only extra requirement is having a surface object to attach hair to. The set up itself can be automated with the updated Empty hair operator. 

Effectors

New node-based dynamics come with a bunch of built-in effectors for effortless gravity and/or surface collision application. In 5.2. LTS, three types of customisable effectors are available:

Colliders

Apply a Collider modifier to transform any closed mesh into a collision object. Or go further in a fully procedural set up and use the collider effector bundle and pass into the dynamics node.

Forces

Built-in gravity setup is available, as well as endless possibilities to build your own custom forces.

Custom effectors

Inject fully custom behaviour into simulations using Closure and Custom Effector nodes.

Tag&Filter

Tag-based filtering system for effectors is also here to easily determine which geometries they affect. Each simulated geometry can have multiple tags for the effector to specify which tags it should affect. 

Physics: Solved

Reimagined, node based: Blender 5.2. LTS introduces a brand new procedural approach to physics for hair and cloth simulations.

The power behind experimental node-based physics lies within the new built-in XPBD Solver node.

While built-in assets contain use-case specific declarative systems around it, advanced users can customize the simulations further. Adapt existing node groups by editing constraints as needed or create a new simulation system from scratch.

Read Manual

What the community is creating with node-based physics

Vegetation interaction test render with the new #blender 5.2 Alpha Cloth Dynamics node in #geometrynodes and rendered with #b3d Cycles
Animated hippo 3D model from Sketchfab pic.twitter.com/bBAeHrSO63

— Kevin Lim Wanasili (@_cgman_) May 20, 2026

Testing a bit more of the new cloth simulation in #geometrynodes on Blender 5.2, really cool, optimized, and above all very customizable! #b3d #clothsim pic.twitter.com/lDMtM09m4d

— Wender Silva (@wendervfx) June 29, 2026

Cloth sim experiment #b3d #geometrynodes pic.twitter.com/p8B6fM90x9

— Cartesian Caramel (@Cartesian_C) June 17, 2026

all done :) i learned a lot about the new cloth solver nodes. these are exciting times! pic.twitter.com/WKuqbgl1IH

— ashlee! COMMS OPEN (@ashlee3dee) May 18, 2026

Bundle Up

Blender 5.0 introduced the concept of bundles, which can now be attached to geometry to carry arbitrary data across modifier and object boundaries.

Use new Get Geometry Bundle and Set Geometry bundle nodes to unlock new workflows and possibilities.

Set and Get Geometry Bundle nodes.

Set and Get Geometry Bundle nodes.

More Geometry Nodes

Lists

Attributes

Strings

Empty Objects

Curves

Node Tools

Performance

CYCLES

Cached In

On scenes with many image textures, the new Texture Cache significantly reduces memory usage and startup time by automatically generating smaller, optimized texture files that load only the tiles and resolutions needed for rendering.

CYCLES

Easy Savings

One toggle, loads of memory savings.

Under Performance → Texture Cache, enable Auto Generate or click Generate. A corresponding .tx file will be generated for each image and automatically updated whenever the image file is modified.

Memory savings and performance improvements are highly scene-dependent. Using Texture Cache comes at the cost of a small rendering performance impact and increased disk space usage.

Read Blog Post

CYCLES & EEVEE

Paper-thin wall

Render physically accurate thin materials such as paper, leaves, and window sheets with the new Thin Wall mode in the Principled BSDF node.

When Thin Wall is enabled, the surface is treated as a slab with its layers mirrored around the base, and the thickness is assumed to be zero.

Thin Wall OFF Thin Wall OFF

Thin Wall ON Thin Wall ON

Render by Christopher 3D.

This new mode provides a more accurate approximation of thin transparent and translucent materials, combining reflection and transmission for thin glass surfaces, and diffuse and translucent scattering for thin subsurface materials.

Principled BSDF Thin Wall

Read Manual

Thin Wall OFF Thin Wall OFF

Thin Wall ON Thin Wall ON

Render by Christopher 3D.

New Color Spaces

COLOR MANAGEMENT

Awesome in Space

Organized color spaces into menus, adding new input color spaces for Apple, ARRI, Blackmagic Design, Canon, and Sony cameras, as well as support for Adobe RGB, common gamma values, and wide gamut textures.

More Cycles & Rendering

Cycles

Rendering

EEVEE

Eevolved

Blender 5.2 LTS is a major release for EEVEE, addressing long-standing usability issues from the transition to the EEVEE Next project architecture.

What’s New

Behind the Screen

The new Backface option under Screen Tracing controls how rays that intersect the back faces of visible geometry are handled.

When enabled, intersections with back faces are treated as valid hits instead of misses.

This can reduce light leaking when using screen-space global illumination, and lets you fine-tune the appearance of global illumination. It affects both Screen Space GI and Fast GI Approximation.

Read Manual

Double Sided

Both front and back faces contribute to global illumination (slider at 1.0)

Single Sided

Only front faces affect global illumination (slider at 0.0)

Disabled (Compatibility Mode)

Use it for compatibility with old renders.

What Got Better

ASSETS ♥ ONLINE

Essentials On Demand

Dozens of new parametric materials, compositing effects, HDR world backgrounds, Geometry Nodes setups, and many more assets have been added to the Essentials library.

The best part? Blender isn’t any larger. These new assets are hosted online, ready for download whenever you need them.

Asset Browser with Online Essentials

Make Them Yours

Watch this demo on customizing online assets by Simon from Blender Studio

Host Your Own

Need more? Host your own or add your favorite creator’s online asset libraries.

Smart indexing makes browsing thousands of assets a breeze.

Keep your assets up to date with a single click.

Read Manual

Add Remote Asset Library Preferences

Add your own online repository in the new Asset Libraries preferences section.

More in Assets

COMPOSITOR

New nodes, unlimited possibilities.

Do more in the Compositor with six new socket types supported: Matrix, Rotation, String, Object, Font, and Integer Vector.

Plus 35 new nodes all-around, from string manipulation to , many of which will already be familiar to Geometry Nodes users.

See All Compositing Nodes

Instant Looks

Whether you’re after a realistic filmic finish or a hand-painted watercolor or oil painting style, the new compositing assets provide a quick starting point for a wide range of looks.

Additionally, you’ll find new utility node groups that can be used as building blocks or incorporated into your own setups.

  • 3D to Screen Space: transform 3D coordinates from world to normalized camera space. The inverse is available as Screen to 3D Space. Use it, for example, to drive the Sun Beams position with a 3D object.
  • Transform and Project: lower level generalised variation of 3D to Screen Space that inputs from Transform and Projection to compute coordinates.
  • Project with Depth: transforms 2D coordinates with their corresponding depth into a 3D vector.

Gizmos Go Further

Compositor gizmos now support auto keying.

Transforming a gizmo will automatically insert keyframes, providing a direct way to animate compositing setups from the backdrop or the Image Editor, which now supports gizmos too!

As for the viewer gizmo, it now follows the image display offset, so handles stay aligned with the backdrop as you pan and zoom.

MORE IN COMPOSITOR

Performance & Quality

It’s a keeper.

The LTS in Blender 5.2 LTS stands for “long-term support”, meaning it will get fixes for up to two years, until July 2028.

Learn More

GREASE PENCIL

Fill Good Ink.

Welcome the new Grease Pencil Delaunay fill algorithm. It creates exact geometry from boundary strokes, with automatic gap detection, inverse filling, zoom-independent results, and much faster performance.

Read Manual

Ready. Set. Go Random.

Dots and Squares line materials now feature Placement settings to control the distribution of shapes along a stroke.

Strokes are now generated at render time instead of as extra geometry, significantly improving performance compared to subdividing strokes with the modifier.

More Online

Don’t forget to enable the Online Essentials Asset library: which includes 19 new Grease Pencil brushes by Blender Studio artists and Daniel Martínez Lara.

Bundled brush assets got refreshed thumbnails as well as new material controls for Dots, plus settings updates for Airbrush, Ink Pen Rough and Pencil soft brushes.

Even more Grease Pencil

ANIMATION

Loop Mood

Introducing Playback Loop modes!

  • Infinite
  • Stop at End Frame
  • Stop at Start Frame
  • Restore Frame
  • Bounce

Read Manual

MORE ANIMATION & RIGGING

Graph Editor

Native LoopTools in Blender 5.2 LTS

Three operators from the LoopTools add-on now built-in Blender 5.2 LTS.

MODELING

Stay In The Loop

To Circle, Space Edge Loops Evenly and Flatten operators from the popular Loop Tools add-on are now available as native operators.

Rewritten from scratch in C++ for improved performance, while also fixing several corner-case issues.

MORE IN MODELING

MORE IN UV EDITING

Get the artwork

Blender splash artwork source files are available for you to play with!

Download Blend File (141 MB)

See All Demo Files

Splash artwork by Joanna Kobierska, based on a model by Ken Barthelmey.

SCULPT

Not So Primitive

Sculpt mode expands its toolkit: drop primitives straight into sculpts with the Add Primitive tool.

Insert Cubes, Cones, Cylinders, UV and Icon Spheres while in Sculpt mode.

Read Manual

Drop primitives straight into sculpts with Add Primitive.

SCULPT

Scene! Project!

Wrap surfaces onto nearby geometry with the new Scene Project brush, and keep painted color intact through repeated voxel remeshing with a smoother color workflow along the way.

Read Manual

See the new Scene Project brush in action in this live demo by Daniel Bystedt.

Remesh, don’t wreck.

The voxel remesher now interpolates vertex and corner attributes, instead of taking the value of the nearest point in the original mesh.

This update provides better preservation of vertex painted meshes after repeated remeshing.

5.1 5.1

5.2 LTS 5.2 LTS

Vertex Colors preservation comparison between 5.1 and 5.2 LTS

EVEN MORE SCULPT & PAINT

Sculpt

Paint

VIDEO SEQUENCER

STACK, STYLE, SCOPE

The Video Sequencer mastering kit gets real in 5.2 LTS: share compositor effects as modifier assets, style titles and toggle modifiers per preview or render. All of that and more plus grading with HDR scopes.

COMPOSITOR + VSE

A new Compositor effect strip runs compositor node trees directly on the timeline with zero, one, or two inputs, plus an effect fader on the input group.

Strip modifiers now expose inputs in the panel, driven by the node group interface like Geometry Nodes. Save compositor node trees as Strip Modifier assets to add them from the Add Modifier menu later. In the modifier extras menu, you can hide the node group selector so shared assets feel like built-in modifiers.

Last but not least: modifiers and effects can now run on the GPU, a real solution needed for heavier graphs and large blurs.

Write in Style

Text strips now support style presets.

Font, outline, shadows, layout, all settings in the Style panel are stored.

Three presets come built-in:

  • Subtitle: classic movie subtitles.
  • Main Title: big, centered text.
  • Corner Title: smaller titles in the bottom-left corner.

Make Space

Line Spacing can now be adjusted in text strips relative to the font height, or in absolute pixels.

Subtitle

Main Title

Corner Title

Now you see me, now you don’t.

Strip modifiers now have a preview visibility toggle just like object modifiers, so you can cut heavy processing from playback without touching the final export.

This also means that cached frames are kept in memory after rendering, making the next preview faster with the same result.

PERFORMANCE BOOSTS

USER INTERFACE

DETAILS MATTER

Long-term support comes with a long list of small UI improvements that make a huge difference for those who blend on daily basis.

Do a Quick Flip!

Need portrait instead of landscape? Right-click Resolution X or Resolution Y and use new Swap Dimensions operator to quickly flip render dimensions.

OUTLINER

Active Focus

Turn on Scroll to Active in the Outliner to keep focus on the active object.

Elements inside collapsed Collections, and children of collapsed parents, are ignored in order to keep your Outliner tidy.

Cozy Sidebar

Fit more on your sidebar!

Compact mode turns the sidebar tabs into squares fitting the first two letters of the name, first two letters of each word, or even an icon.

Similar to bl_category for the panel name, define bl_icon and the ID of your icon.

Additionally, you can now click-drag to switch the active tab, and the sidebar is always visible even with a single tab.

VIRTUAL REALITY

Great Scout

Jump straight into your 3D scene with Location Scouting!

Block camera vantage points and assess camera properties in VR with full 3D environment immersion.

Full Control

The VR Controller default bindings deadzone threshold was adjusted to provide a smoother user experience.

Read Manual

I/O

Alembic

OpenUSD

Images

Video & Audio Output

STL

glTF: New in Import/Export

BUT WAIT, THERE’S MORE

Theme

Core

Motion Tracking

Python API

Plus hundreds of bug fixes, code cleanups and refactors.
See the full list of changes.

CREDITS

Blender is a community project.
Learn more on how you can contribute to Blender.

List of developers who contributed to Blender 5.2 LTS and all-time contributors.

Splash artwork: Joanna Kobierska, based on a model by Ken Barthelmey.
Thin Wall renders by Christopher 3D. VR Location Scouting image by Daniel Bystedt.

Huge thanks to everyone involved! 🧡

The Blender team. July 14th, 2026

The Daily Front Page 13 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — The Maker’s Ledger
article

What I learned selling 2,500 MIDI recorders: Hardware is not so hard

by chipweinberger·▲ 471 points·215 comments·chipweinberger.com ↗
After a career in software, I got to build hardware.

A year and a half ago, I launched Jamcorder.

A Jamcorder connected to a piano

A Jamcorder, in situ.

It marked the completion of two life goals of mine.

First, I finally had the piano recording device I’d always wanted: a fully automated device that captures everything I play, no human-involvement required.

And second, after a career in software, I got to build hardware. It was super fun.

2500 units have already been sold, and counting! People genuinely love it! And it’s able to stand on its own feet as a business. In my eyes, that’s a success.

For my first blog post, I want to reflect on the biggest surprise I encountered creating Jamcorder.

Hardware is not so hard

A timeline of early Jamcorder prototypes

A selection of prototypes, from the first prototype to the first pre-production unit.

Coming from a career in software, I expected building hardware to be the hardest part.

After all, hardware is hard. That’s the saying, right?

Electronics design, plastics, manufacturing, fulfilment, component shortages, etc, etc, etc.

I expected these & more to make hardware hard.

But, it wasn’t.

Jamcorders being assembled and packed in a kitchen

To refine the process, I hand assembled the first 500 units myself. It took 4 days. Unexpectedly, everything went completely smoothly and I made no changes. Yes, really.

I kept waiting for something to get me by surprise. A scrapped production run (my worst nightmare). Or component sourcing issues, perhaps?

It never happened. (Though Trump’s tariffs were a close call).

The hardest part of building Jamcorder was still, by far, the software -- roughly 200K lines of code spread across the firmware, app, and manufacturing tooling. It took over 3 years and many long nights in a pre-LLM world.

When compared to that, the hardware was undeniably smooth sailing.

For the record, I don’t think I’m special. It’s just that hardware’s reputation for being difficult is, IMO, overstated.

Now, granted, Jamcorder is -- very much intentionally -- a simple device. I get that.

The Jamcorder printed circuit board

The Jamcorder PCB. 25 unique components. The MIDI connectors are made to order, everything else on the PCB is off-the-shelf.

Assembly is just a single screw, for a single PCB. The injection mold has generous draft, no slides.

I cut low battery detection, ambient light detection, the power-button, even USB-C.

All these things kept Jamcorder simple.

I’m also under no illusion that 2500 units is a lot by most standards.

But you know what? The hardware side would have been easy regardless.

Don’t get me wrong. If Jamcorder was 10x more complex, or 100x more scale, that would be a different story (and a very popular product!).

Or if I was trying to compete in the smartwatch market, or the car market, or any number of very established industries with low margins, good luck.

But for me the take away still is: “hardware is as hard as you make it”.

If you’re thinking about building a hardware product & have a way to protect your margins, don’t let building hardware scare you.

It’s not as hard as the saying goes.

POSTSCRIPT

I don’t want to end this article without some practical take-aways. So here are my top recommendations for successfully shipping hardware that worked for me at medium scale:

  1. Keep your BOM simple. Avoid single-manufacturer components wherever possible.
  2. Avoid complex assembly and calibration.
  3. Partner with a Chinese assembly house and suppliers. Alibaba is your friend.
  4. Aim for at least 70% gross margin or more.
  5. Keep your company lean. Scaling hardware is slower.
  6. Have a strong anti-counterfeit strategy. Don’t overlook this.
  7. Do final Q/A in-house & hold finished inventory locally.
  8. Request samples before every production run.
  9. Write a step-by-step manufacturing & assembly guide with pictures.
  10. Keep your packaging small. A value dense product makes everything easier.

Chip Weinberger carrying the first Jamcorder shipment to the post office

Me dropping off the first 100 units at the post office. A good day!

The Daily Front Page 14 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — The Little Phone Returns
article

HMD Touch 4G

by thisislife2·▲ 70 points·71 comments·hmd.com ↗
It’s not your old keypad phone. It’s not a bulky smartphone.

HMD Touch 4G

It’s not your old keypad phone. It’s not a bulky smartphone. This is a hybrid phone, combining the best of both worlds: Cloud Phone Service, video calls and voice messaging through the Express Chat App with other Express Chat users, Wi-Fi support, and a touchscreen — all in one small package.

HMD Touch 4G hybrid phone

Smart features. Small phone.

  • Touchscreen

    Vibrant touchscreen with smooth scrolling.

    HMD Touch 4G has a touchscreen

  • Cloud phone service

    Cricket results, news, weather, and more.

    News, cricket and more on HMD Touch 4G

  • Express Chat app

    Video call and voice message with other Express Chat users.

    HMD Touch 4G has the Express Chat app

  • Global roaming

    Supports 4G LTE bands for broad network connectivity. ²

    HMD Touch 4G supports 4G LTE

What it’s about

The next step in phone evolution

The line between smartphone and feature phone just got a bit smudgy. HMD Touch 4G boasts a vibrant touchscreen — that makes it nice and smooth to swipe between features like the Cloud Phone Service and the Express Chat app for video calls. It does all of this and more while maintaining the simplicity, reliability, and affordability of a feature phone. This is a hybrid phone.

About hybrid phones

Online Chat

The Express Chat app: for expression that breaks barriers

HMD Touch 4G comes with the Express Chat app for texting and video calling with other Express Chat users. Chat one-on-one or in groups, even with smartphone users. The Express Chat app is free to download for Android™ and iOS® devices. Just another way HMD Touch 4G bridges the feature phone and smartphone worlds.

  • Video calling

    Use the selfie camera to video call with other Express Chat users.

    Video call on the Express Chat app

  • Voice messaging

    Hold the Quick-Call button to record a voice message.

    Record voice messages on the Express Chat app

  • Text chat

    Send texts, photos, and emojis in private chats and groups.

    Share texts and photos on the Express Chat app

  • For smartphones

    Express Chat is free to download on Android and iOS® devices.

    The Express Chat app is available on smartphones

Global roaming

Take your HMD Touch 4G around the world with you

Enjoy HD voice calls and other online features while you travel. With support for a wide range of 4G LTE bands, HMD Touch 4G helps you make the most of global networks around the world.

Cloud phone service

A world of smart experiences

Entertainment, socials, games, friends, and finding information — that’s what Cloud Phone Service is all about. Whether you want to check the latest videos, view tomorrow’s weather forecast, or read up on the latest cricket results, it’s all just a few touches away on HMD Touch 4G through cloud-hosted browser shortcuts.

Packed with big features

  • Quick-call button

    For emergency contact calling and voice message recording.

    Quick-call button on HMD Touch 4G

  • Connectivity

    WiFi support, hotspot feature, and Bluetooth enabled.

    HMD Touch 4G has Bluetooth connectivity

  • Cameras

    Capture photos and videos with front and back cameras.

    HMD Touch 4G has front and back cameras

  • Battery

    1950 mAh battery and USB Type-C charging. ¹

    HMD Touch 4G has a 1950 mAh battery and USB Type-C charging

Design

Smart features in a little package

HMD Touch 4G combines the modern, clean-cut look of a smartphone with the compact form of a feature phone to give you a stylish, easy-to-use device. It easily fits your pocket, your bag, and your lifestyle.

Currently only available in India.

All rights reserved. All specifications, features and other product information provided are subject to change without notice. All images are for illustrative purposes only.

¹Battery has limited recharge cycles and battery capacity reduces over time. Eventually the battery may need to be replaced.

The Daily Front Page 15 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Home Server Obituary
article

The death and rebirth of my home server

by steinuil·▲ 131 points·84 comments·sgt.hootr.club ↗
Not eager to ruin the evening by starting a debugging session then and there, I chalked it up to a simple inconvenience.

A few evenings ago my partner and I were in the mood to install this particular Linux ISO. The guys from Red Letter Systems had spoken of it well, it had good reviews on boundingboxd, and my partner liked the installation trailer.

I opened Tremotesf on my phone to check whether I already had it on the Pi, but the torrent list wouldn't load. The SMB mount wouldn't mount. I couldn't SSH into it either.

Not eager to ruin the evening by starting a debugging session then and there, I chalked it up to a simple issue with the recent changes I made to the NixOS configuration and resolved to take a look at it the next day.

The next day

I hooked the Pi up to the dedicated debugging display I have in the closet, cracked knuckles, said "it's debugging time" or something to that effect, and rebooted the brick.

The current NixOS generation started booting, loaded the kernel and... hung there. No more output. The previous generation did the same. I took the microSD card out for further inspection.

The first obvious step was to fsck it; the power had mysteriously gone out in the whole building a few days prior, and perhaps it happened right when one of the blocks containing some files important for the boot process was being written? Anyway, it was worth a check. fsck.ext4 reported and fixed lots of errors. Running it again reported the FS as clean, but ejecting and then plugging the card back in turned up more errors...

Long story short, the card was likely dead, and the blackout had simply delivered the coup de grace. Press F to pay respects.

Taking inventory

This Raspberry Pi 4B had been running for years almost 24/7 so this didn't come as a surprise. My understanding is that SD cards can sustain a comparatively small number of write cycles before they start to fail. The surprising part was that mine managed to run for so long with no issues, considering how badly I'd been treating it. The microSD was mounted as the root FS and I had taken next to no precautions to minimize writes.

I didn't lose much, all things considered. The important stuff mostly lived in external HDDs and the configuration lived almost entirely in my NixOS configuration. The only things that lived on the microSD card and I had no backup for were .torrent files and caches for Navidrome, Jellyfin, and slskd, all of which I could easily regenerate. Immich's data was safely backed up on an external drive and I was taking regular backups, so nothing was lost there.

I've never had a "primary" drive die on me like this before; the worst I've seen were a few dead flash drives that contained nothing important. The fear of a dead drive and lost data has resided in the back of my mind ever since I was a teenager and accidentally the main OS X partition on my macbook while trying to install Linux for the first time, but now it's worse than ever, so I wanted to take strong precautions.

Configuring the new setup

I set out to rebuild my home server with a few things in mind:

  • Try to minimize writes to the microSD.
  • Have some redundancy in the data stored on external hard drives.
  • Back up everything important.

Swap, /tmp, and other volatile data

Swap is useful to have, even with the 8GB of RAM on my Pi, but I don't think swapping to the microSD is a good idea if I want it to live long, so I could either swap to an external HDD (very slow) or use zram.

zram, formerly called compcache, is a Linux kernel module for creating a compressed block device in RAM, i.e. a RAM disk with on-the-fly disk compression.

The common uses for zram are swap or /tmp. I chose to enable zram for swap but not for /tmp, which I kept as a normal RAM disk; I'm not 100% sure how these two features interact but I figured I'd let the kernel figure out how and when to swap out the cold pages in /tmp to the compressed swap rather than reserving a separate block for it.

{
  # Enable in-memory compressed swap device
  zramSwap.enable = true;

  # Use a RAM disk for /tmp
  boot.tmp.useTmpfs = true;
}

I also chose to have journald log to memory rather than to disk. I need to investigate whether it's possible to log to memory and only occasionally flush to disk (in which case I'd mount /var/log to a subvolume on an HDD) but I haven't figured that part out yet.

{
  # Store journal logs in memory to /run/log/journal
  services.journald.storage = "volatile";
}

The microSD card remains mounted to /, but I disabled atime because it causes writes whenever a file is accessed and I don't think it's very useful.

{
  fileSystems."/" = {
    device = "/dev/disk/by-label/takodachi";
    fsType = "ext4";
    options = [ "noatime" ];
  };
}

External HDDs

If you live in the current year of 2026 you probably know this is not a good time to be buying any new drives (or RAM, or GPUs, or anything that can be used to build datacenters and feed the pockets of executives enraptured by AI psychosis) and that it's a better idea to get scrappy and creative with what you have.

I have tons of drives lying around of all sorts of makes, sizes, and ages. I treat them mostly as cold storage for old data that I kinda want to keep; they're the digital equivalent of a junk drawer. I've always wanted to immolate them for a higher purpose but never quite found one until now. I took two of these old 2.5" HDDs from the pile.

The first was a 500GB drive that contained a Windows filesystem. This used in my partner's laptop; a 3KG behemoth from another era of business machines, meant more as a desktop you could easily move to another desk and occasionally bring home rather than a truly portable machine. First I swapped out the HDD with an SSD as an act of mercy on the dying laptop; eventually I set my partner up with a Surface Pro 5 running NixOS and they kindly gave me the old laptop and HDD to play around with.

I know setting up somebody else's computer with NixOS sounds like domestic violence but trust me, it's working out and they're very happy with the laptop. I'll write a post on that someday.

The second was a 320GB drive that seemed to contain... a home assistant installation? I have no idea how that ended up there. Anyway, this was a Hitachi drive with an apple logo on it, so it used to be inside either my 2006 white plastic macbook or a mac mini of a similar vintage.

I connected these two pieces of history to a docking station and created a btrfs pool with raid1 replication. I fittingly named it ポンコツ (piece of junk).

sudo mkfs.btrfs --data raid1 --metadata raid1 --label ponkotsu /dev/sdX /dev/sdY

I went with btrfs because it's what I know (it runs on my desktop and laptop), I like subvolumes (more on that later), and I like the flexibility of its pools. You don't have to plan the topology of the pool beforehand, you can add drives to the pool whenever you want, and they don't have to be of the same size.

Obviously you'll want the drives to be close in size if you don't wanna end up with wasted space: the size(largest drive) has to be equal or less than the sum(size(drive) for remaining drives). At this point I only had 320GB to use, but I would increase that number later in the process.

Subvolumes

I had a whole section about btrfs subvolumes here and how I set different mount options on each one, but as I just learned, most mount options are applied to the whole filesystem! I don't know where this misconception came from.

My plan was to have one btrfs subvolume per service, and to do it declaratively I created an autosubvol module. The configuration looks like this:

{
  services.autosubvol = {
    enable = true;
    disks.ponkotsu = {
      device = "/dev/disk/by-uuid/<pool uuid>";
      subvolumes.immich = {
        mountPoint = "/var/lib/immich";
        mountOptions = [ "noatime" ];
        requiredBy = [ "immich-server.service" ];
      };
    };
  };
}

The module creates some systemd units:

  • One .mount unit for each disk at /run/btrfs-roots/<name>.
  • One autosubvol-ensure-<disk>-<subvolume>.service oneshot unit with a script that checks whether the subvolume exists and, if not, creates it. It's configured with RemainAfterExit=true so that the .mount unit for the subvolume can depend on it.
  • One .mount unit for each subvolume, mounted to the specified mountPoint. It depends on the autosubvol-ensure .service and sets Before= and RequiredBy= on the units it is requiredBy.

The different types of dependencies in systemd still puzzle me so I'm not 100% sure this is correct, but the systemd.unit manpage mentions that RequiresMountsFor= is roughly equivalent to After= and Requires=, which are respectively the inverse of Before= and RequiredBy=? I'm guessing this is either correct or subtly broken in a way that might come back to bite me when I least want to fix it.

I think this makes each service module look very clean.

{
  config,
  ...
}:
{
  services.immich = {
    enable = true;
    # ...
  };

  services.autosubvol.disks.ponkotsu.subvolumes.immich = {
    mountPoint = config.services.immich.mediaLocation;
    mountOptions = [ "noatime" ];
    requiredBy = [ "immich-server.service" ];
  };
}

I also created a subvolume for /var/cache for good measure.

{
  fileSystems."/var/cache" = {
    device = "/dev/disk/by-uuid/...";
    fsType = "btrfs";
    options = [
      "subvol=@cache"
      "noatime"
      "nofail"
    ];
  };
}

Backups

Back when I set up Immich I also created a Nix module that acts as a bridge between sops-nix and the restic nixpkgs module. The implementation is only a few lines of code, and it looks like this in my Nix configuration:

{
  internal.backups.restic.immich = {
    paths = [ "/var/lib/immich" ];
    exclude = [
      "/var/lib/immich/encoded-video"
      "/var/lib/immich/thumbs"
    ];
    pruneOpts = [
      "--keep-daily 7"
      "--keep-weekly 4"
      "--keep-monthly 3"
    ];
  };
}

Since each service is on its own subvolume I could probably set up a local backup system using snapshots and btrfs send with a disk entirely dedicated to backups that I'd keep powered off most of the time, but since right now I don't have that many disks and it's getting increasingly difficult to get new ones, I'm gonna leave that for better times. An S3 bucket and replication will have to do.

Groups and permissions

I want several services to have access to my Linux ISOs: Transmission, Jellyfin, Navidrome, and a few others. I handled this by creating a media group and assigning it as an extra group to all the applications that need to read or write those files.

{
  users.groups.media = {};
  users.users.steenuil.extraGroups = [ "media" ];
  users.users.jellyfin.extraGroups = [ "media" ];

  services.transmission = {
    group = "media";
    downloadDirPermissions = "2775";
    settings.umask = "002";
  };
}

The part that makes this work is Transmission's downloadDirPermissions set to 2775. The 2 indicates that the setgid bit is on, which means that if /srv/linux-isos is owned by the media group, every file and directory created inside it will inherit the media group rather than the creator's primary group.

Monitoring

This is one part I haven't fully figured out yet. The only precaution I have taken is to regularly run btrfs scrubs on the pool to connect any errors and decide whether to take a closer look at the S.M.A.R.T stats based on the number of errors on each drive.

I'd like to set up smartd and perhaps connect it to a nice dashboard like Scrutiny, but since I'm running many other services and I wouldn't mind having more statistics on them, perhaps it'd be more useful to set up Prometheus and then figure out how to display everything on a nice Grafana dashboard? I know next to nothing about Grafana so it all looks a bit daunting and overkill to me, but it might be a good learning experience.

Feeding the pool

Let's get back to the spinning rust; we were at two disks in the pool. I wanted to add a 1TB drive to the pool while also copying its contents to it. The disk was already partitioned exactly in half and most of the data was in its back half, so I formatted the front half as btrfs, added it to the pool, copied the back half to the pool, and then extended the btrfs partition to fill the disk. I'm not sure how effective this was in terms of speed, but it saved me a btrfs balance.

To save the Pi some trouble I set up Immich on my desktop and restored from the backup there, and since I avoided moving the thumbnails in the previous steps I regenerated all of them in webp.

This is the current state of the pool: a 1TB disk, a 500GB, and a 320GB one; raid1 for both data and metadata. I'm planning to add another old 500GB disk to it and I'll probably keep it that way until either drive prices go down, or one of the drives dies.

I also have a 10TB disk still formatted with ext4 and filled to the brim with Linux ISOs that I can't reasonably add to the pool, so I'll just back up whatever I think is important and ride it until it dies. #yolo

The new microSD

Since I'm putting much less pressure on the microSD card I went with a 64GB one rather than the 128GB I used before. I searched for a "high endurance" card because they're supposed to have more write cycles before they give up the ghost.

I'm not completely sure what I got in the end though. This whole ordeal happened just a few days prior to the vacation I'm writing this post from, so I ordered a card that would arrive on Saturday: the day before I left. Saturday morning came and the package still hadn't shipped, so I had to cancel it, get off my ass, and walk to the nearest home appliance store.

It wasn't too bad. I took a nice stroll, took a photo of some of those Asian beetles that are invading southern Europe and leaving a trail of half eaten leaves in their wake.

Plants being devoured by several Japanese beetles

The store had AC. I had a look at the latest gimmick phones. I walked out with a 64GB microSD card claiming to be high endurance, and even a discounted UPS.

Deployment

NixOS is an intimidating project when you're starting out. There's way too much information scattered through the interwebs to fully grasp it. You get used to it though. Your brain does the translating.

You could bootstrap a NixOS installation on a Pi by downloading the official NixOS image and start from an empty system, or you could just know in your heart of hearts that all you need is this module:

{
  modulesPath,
  ...
}:
{
  imports = [
    "${modulesPath}/installer/sd-card/sd-image-aarch64.nix"
  ];

  sdImage.rootVolumeLabel = "takodachi";
}

To be able to cast this incantation:

nix build .#nixosConfigurations.takodachi.config.system.build.sdImage

Which will build an .img file that you can dd to a microSD card to get your system up and running, with no intermediary steps.

Finishing up

After imaging the microSD card all I had to do was hook everything up to the new UPS and plug it in, and in a few seconds I could SSH into the Pi and start resolving some minor issues with the new configuration.

I left for my vacation a bit late, but with Navidrome up and running and able to serve music to listen to on the drive there.

The Daily Front Page 16 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Casting Shadows
repository

Better and Cheaper Than IPTV

by xonery·▲ 328 points·103 comments·github.com ↗
★ 1,419⑂ 43 forks Go

Point it at any web page and it finds the video, extracts the stream, transcodes it and casts in real time to your TV. It even burns subtitles….

Smart TVs won't cast arbitrary web video, and screen mirroring is laggy and drops resolution. Castor casts the real stream instead, at full quality, from your terminal.

Point Castor at a web page you are watching, or at a direct stream URL, and it finds the video, extracts the stream, transcodes it for your TV, and casts in real time. It can also resolve an IMDB/TMDB id against sources you configure yourself, and burn in auto-generated subtitles.

To extract, it launches headless Chrome and watches network traffic over the Chrome DevTools Protocol, then runs a short action pipeline to start playback: click the page, navigate into the largest iframe, and click again as a fallback. This works on pages that allow automated playback, and won't work everywhere.

A general-purpose casting tool: it casts only what you point it at. See Purpose and disclaimer.

Browsing titles in the castor TUI
Run castor cast to browse titles and cast, without leaving the terminal.

Installation

The recommended way to run Castor is the native binary. It runs directly on your machine, so it shares your TV's network (required for device discovery). It requires Chrome/Chromium (headless extraction), ffmpeg (transcoding), and ffprobe (format detection) on your PATH. A Linux-only Docker image that bundles all three is also available.

Homebrew (macOS)

brew install --cask stupside/tap/castor

From source

Needs Go 1.26+ and cmake (the whisper.cpp bindings are cgo and link a locally built libwhisper.a):

git clone --recurse-submodules https://github.com/stupside/castor.git
cd castor
make          # builds libwhisper.a, then the castor binary

go install won't work: the vendored whisper.cpp bindings come in through a local replace and need that prebuilt static lib.

Quick start

Tell Castor which TV to use: find its name with castor scan and put it in config.yaml.

device:
  name: "Living Room TV"   # exact name from `castor scan`
  type: dlna

Now cast a page you are watching, or a stream URL you have:

castor cast player https://example.com/watch/some-video

For the interactive browser, which searches titles and casts them for you, add a TMDB key and a source (see Configuration), then run castor cast:

Selecting a cast target in the castor TUI

Run castor --help for every command and its flags.

Configuration

Castor reads config.yaml from the current directory, or the path passed to --config. The only required key is the device to cast to (shown in Quick start); everything mechanical (timeouts, probing, capture, transcoding, network interface, Chrome discovery) has working defaults. Keep secrets out of the committed file: put them in a git-ignored config.local.yaml that overlays it, or in CASTOR_SECTION__FIELD environment variables. See SECURITY.md.

Sources

cast movie, cast episode, and the interactive browser resolve a title id against sources you configure. Castor bundles none, so add your own (sites you are authorized to use). There is no catalog and no lookup: Castor substitutes the id into the templates you write, prefixes each of your proxies, and opens the resulting page, then extracts the stream exactly like cast player. For example, castor cast movie tt12300742 opens https://your-source.example/embed/movie/tt12300742.

sources:
  - proxies: ["https://your-source.example"]   # base URLs, tried in order
    templates:
      movie: "/embed/movie/{itemID}"
      episode: "/embed/tv/{itemID}/{season}-{episode}"

TMDB

The interactive browser (castor cast) uses a TMDB API key to search titles; direct commands like cast movie <id> do not need it. Get a free key from themoviedb.org and keep it in config.local.yaml:

tmdb:
  api_key: "<KEY>"

Subtitles

Auto-generated subtitles, transcribed with whisper and burned into the video. Off by default:

whisper:
  enable: true             # off by default
  # language: "fr"         # default: English
  # model_path: ""         # default: ggml-tiny.en (~75 MB, auto-downloaded)

Supported devices

DLNA / UPnP

Any TV implementing the DLNA/UPnP MediaRenderer:1 profile works, which covers virtually every smart TV sold in the last decade: Samsung (tested), LG, Sony Bravia, Panasonic Viera, Philips, Hisense, TCL, VIZIO, Sharp. Networked players like Kodi, VLC, and Plex also work. Run castor scan to list what is on your network.

Chromecast

Experimental: implemented but untested. Contributions welcome.

Docker (optional)

A Linux-only alternative that bundles Chrome, ffmpeg, and ffprobe.

Warning

Docker can only reach your TV from a Linux host on the same LAN. Discovery uses SSDP multicast and the TV streams back from Castor's replay server, and neither survives Docker's bridge network, so --network host is required. On Docker Desktop (macOS/Windows) that flag is a silent no-op: the container lands on Docker Desktop's internal VM subnet (e.g. 192.168.65.x) instead of your LAN, so scan finds nothing and cast fails with device "…" (type dlna) not found. Run the native binary on macOS/Windows instead, or bridge a Linux VM onto your LAN (e.g. Lima + socket_vmnet).

On a Linux box or NAS on the same network as the TV, the prebuilt ghcr.io/stupside/castor image saves you installing the dependencies by hand:

# Discover devices (no config required)
docker run --rm --network host ghcr.io/stupside/castor:latest scan

# Cast, mounting config.yaml and a persistent model cache
docker run --rm --network host \
  -v "$PWD/config.yaml:/config.yaml" \
  -v castor-cache:/root/.cache \
  ghcr.io/stupside/castor:latest \
  cast player https://example.com/watch/some-video

The container reads config from config.yaml at /config.yaml, so run every command from the directory holding it. The castor-cache volume keeps the auto-downloaded whisper models between runs; swap :latest for any release tag to pin a version.

Note

DLNA passthrough and hardware encoding. When the TV can already play the source video (H.264 inside a profile and level it accepts), Castor stream-copies it instead of re-encoding, dropping CPU use to near zero. When a re-encode is unavoidable (a codec the TV rejects, or burned-in subtitles), Castor picks a hardware H.264 encoder if one actually works on the host (VA-API on an Intel Linux box, VideoToolbox on the native macOS binary) and otherwise falls back to software libx264. To let the Docker container reach an Intel GPU for VA-API, add --device /dev/dri to docker run (the --network host flag alone does not expose the GPU); without it, or on a host with no working hardware encoder, Castor stays on libx264.

Purpose and disclaimer

Castor is a general-purpose caster, not a service tied to any particular site.

  • It hosts nothing. No bundled video, catalog, or sources: Castor casts only a page, stream URL, or source you supply and are authorized to use, much like a Chromecast.
  • It does not touch DRM. Castor does not decrypt or circumvent DRM, and cannot cast DRM-protected services.
  • Using it lawfully is your responsibility. Whether a site's terms of use and your local law allow what you do with Castor is on you. Do not use it to infringe copyright.

Castor is provided as-is for lawful, personal, and educational use.

Contributing

See CONTRIBUTING.md.

The Daily Front Page 17 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Owning the Web Again
article

I joined the IndieWeb, here's what I learned

by andros·▲ 191 points·94 comments·en.andros.dev ↗
It was more than an empty concept or a feeling of nostalgia for the web of the 90s.

Driven by curiosity, I decided to find out what the IndieWeb tag that kept showing up on some blogs and Mastodon toots was all about. I quickly discovered it was more than an empty concept or a feeling of nostalgia for the web of the 90s. It was a movement with concrete ideas, protocols and an active community! As I read through their wiki, I understood their position and the intelligence of their proposals more and more. Such was my enthusiasm that I decided to follow their advice and adopt the protocols that made sense for my site. After finishing the tests and adjustments, I can confirm that the experience has been very positive: I have learned a lot, the UX of my website has improved a bit more, and I enjoyed the process.

That is why I decided to write this article, cleaning up my notes from these last few months. Maybe it will help someone else discover it, and along the way, improve the health of the web. And for the nosy ones, I will also tell you which pieces I implemented, which ones I discarded and why, and which pieces of advice turned out to be the most useful.

But first, we need to answer a fundamental question.

What is the IndieWeb

The IndieWeb defines itself as "a people-focused alternative to the corporate web". It does not propose a piece of software or a framework, but an ideological foundation. It deliberately embraces a plurality of approaches and projects. As its homepage says: "we are people-focused instead of project-focused".

It all started in 2010, when Aaron Parecki and Tantek Çelik attended the Federated Social Web Summit in Portland. They left with the feeling that a different approach was needed: fewer protocols and more creators. In 2011 the first IndieWebCamp was held in Portland, and they have been celebrated every year around the world ever since, along with the Homebrew Website Club, meetups where people get together to improve their personal websites.

The 3 pillars that define it are:

  • Your content is yours: when you post something on the web, it should belong to you, not a corporation. Too many companies have shut down and taken their users' data with them.
  • You are better connected: your articles can be distributed to any platform, not just one, and responses and likes from other services can come back to your site so you have everything in one place.
  • You are in control: you can post anything you want, in any format you want, with readable and permanent URLs that will always work.

So we could say it is a community of personal, independent websites that share these commitments.

That is also why it does not forbid you from using social networks, but it does fight against walled gardens.

The enemy has a name: the silo

The entire IndieWeb vocabulary is built in opposition to one concept: the silo, also called a walled garden. The wiki defines it as a centralized website, typically owned by a for-profit corporation, that claims some rights over the content you contribute and restricts access in some way. Its characteristics:

  • They require you to create a site-specific account to participate.
  • They only let you interact with other accounts on the same site.
  • And they typically add: restrictive terms of service, license claims over what you create inside, walls that prevent indexing, or barriers to importing and exporting your content.

Why is this a problem? Because silos die, and when they die they take your content with them. The site-deaths page ("Where incredible journeys end", a nod to the corporate euphemism our incredible journey) keeps a devastating chronology:

  • GeoCities: Yahoo shut it down on October 26, 2009. 23 million pages gone.
  • MySpace: in 2019, during a server migration, it lost all the music uploaded during its first 12 years, more than 50 million songs from 14 million artists.
  • Google+: shut down in April 2019.
  • Posterous, FriendFeed, Vine, Yahoo Groups, TinyLetter, Cohost... the list keeps growing, and it even has sections for "upcoming deaths" and for acquisitions, which tend to foreshadow them.

The silo does not even need to die: the web is fragile by default. According to a 2024 Pew Research study, 38% of the web pages that existed in 2013 were no longer accessible a decade later.

The IndieWeb's conclusion is not "don't use social networks". It is more subtle: use whatever you want, but make sure the canonical copy of your content lives on a domain you control.

That is why it defines a set of principles to fight against the fragility of the network.

The principles

The community is guided by 11 principles:

  1. Own your data: your content, your metadata and your identity live under your domain, and you retain access to them over time.
  2. Use and publish visible data: for humans first, machines second. No parallel APIs if the HTML can carry the data.
  3. Make what you need: build tools for yourself, not for some hypothetical user. "If you design for some hypothetical user, they may not actually exist; if you make for yourself, you actually do exist."
  4. Use what you make: use what you build every day. "If you aren't depending on it, why should anybody else?"
  5. Document your stuff: you already have a place to speak your mind, use it to document your processes, ideas and code. You help others and your future self.
  6. Open source your stuff: not mandatory, but it helps others get onto the independent web faster.
  7. UX before protocols: user experience first, and then the simplest, most minimal protocol sufficient to support it, and nothing more. They sum it up as "UX before plumbing".
  8. Modularity: small, loosely coupled pieces, so you don't depend on a specific device, language or platform.
  9. Longevity: build for the long web. "If human society is able to preserve ancient papyrus, Victorian photographs and dinosaur bones, we should be able to build web technology that doesn't require us to destroy everything we've done every few years in the name of progress."
  10. Plurality: deliberately encouraging diverse approaches makes the community more resilient than any monoculture.
  11. And above all, have fun: remember the web of the 90s, GeoCities, loud backgrounds and animated GIFs. "It may have been ugly and badly coded but it was fun. Keep the web weird and interesting."

The numbering is just for reference, not a priority. The community does not demand that you fulfill them all, but it does ask you to keep them in mind.

But the IndieWeb does not live on principles alone. There is a set of standards that helps make your sites more open, interoperable and resistant to disappearing.

The technical part

The IndieWeb does not invent a platform; it defines a handful of small standards that compose with each other. The official index orders them by age and breadth of implementation.

Let's go one by one.

The starting point: your domain

It is not a protocol, but it is the prerequisite for everything else: your own domain used as your primary identity online. It is the first step of the Getting Started guide and the bare minimum the community considers necessary to be "on" the IndieWeb. If tomorrow you change hosting or CMS while keeping the domain, all your links, readers and search rankings survive the move.

microformats2: your HTML is your API

microformats2 solves one problem: making your content machine-readable without publishing parallel files or building an API.

The implementation is elegant, since it uses CSS classes that you add to the HTML you already have. The prefixes indicate the data type: h-* for roots, p-* for plain text, u-* for URLs, dt-* for dates and e-* for embedded HTML. The two essential vocabularies:

h-card is your identity: the online equivalent of a business card. With a minimum of name, URL and photo on your homepage, readers show your profile next to your posts and applications recognize you. It works like a domain-based Gravatar instead of an email-based one:

<a class="h-card" href="https://example.com">
  
  Jane Doe
</a>

h-entry is the unit of content: the markup of a post. The wiki calls it "the key building block for the indieweb":

<article class="h-entry">
  <h1 class="p-name">Article title</h1>
  <p>By <a class="p-author h-card" href="https://example.com">Jane Doe</a>,
     <time class="dt-published" datetime="2026-07-19">July 19, 2026</time></p>
  <div class="e-content">
    <p>The post content...</p>
  </div>
</article>

There is also h-feed, which groups several h-entry elements to turn your listing page into a feed you can subscribe to straight from the HTML.

The wiki sums it up in a phrase I love:

Your website is your API

For reading, microformats; for writing, Micropub (we'll get there).

rel="me": verified identity without a central authority

rel-me is the simplest piece and the one with the most immediate effect. An attribute on a link that says "the destination of this link represents the same person as the current page":

<a href="https://mastodon.social/@jane" rel="me">Mastodon</a>

Verification requires reciprocity: your website links to the profile and the profile links back to your website, both with rel="me". With that you get distributed identity verification, with no central authority involved. It is exactly the mechanism behind Mastodon's green verified checkmark: if your page links to your profile with rel-me and your profile links back, Mastodon shows your domain as verified. It is also supported by Threads, PixelFed, GitHub, Keybase and Wikipedia.

On top of rel-me sits RelMeAuth: authenticating on services with your personal URL, delegating the identity proof to an OAuth provider (like GitHub) that your homepage links to. It is the foundation of services like IndieLogin.

Webmention: conversations between sites

Webmention is the star standard, a W3C Recommendation since January 12, 2017, and the modern successor of Pingback. It solves conversations between sites: comments, likes, replies and reposts from web to web, with no platform in between. Many people use it as a replacement for Disqus.

The flow is deliberately simple:

  1. I write a post that links to an article of yours.
  2. My server visits your article and looks for your endpoint: an HTTP header Link: <...>; rel="webmention" or a <link rel="webmention"> in the HTML.
  3. It sends a POST with only two parameters: source (my post) and target (yours).
POST /webmention HTTP/1.1
Host: your-site.com
Content-Type: application/x-www-form-urlencoded

source=https://my-site.com/my-post&target=https://your-site.com/your-article
  1. Your server verifies the mention: the specification requires downloading the source and checking that it really contains a link to the target. Without that verification, anyone could fabricate fake mentions.
  2. Once verified, your site decides what to do with it. And here is where microformats comes in: by parsing the h-entry of the source you know whether it is a reply (u-in-reply-to), a like (u-like-of) or a repost (u-repost-of), and the author's h-card lets you display their name and photo like in any comment section.

If this sounds like a social network to you, that's because it is! Every site is a node in the network, and the links between them form the social graph.

It is not a perfect system, since it suffers from the same problems as any other decentralized network, which is why there are a couple of extensions that attack its weak points:

  • Vouch, against spam: the webmention carries a third parameter with the URL of a "voucher", a site you already know that links to the sender's domain. It shifts the filtering cost from the receiver to the sender.
  • Salmention, to propagate threads: if someone replies to a comment on my post, the original post finds out by re-sending update webmentions to everyone involved.

You don't escape spam or moderation. However, it is a good foundation for building a distributed comment system.

What if your website has no backend? You are not left out: webmention.io receives webmentions on your behalf. You add a <link> in your HTML pointing to the service and it gives you an API to query and display them. It is exactly what you need if you use a static site generator like Hugo, Jekyll or Eleventy.

IndieAuth: your domain as your login

IndieAuth answers the question: what if your identity for signing in were your URL, instead of "you on Google" or "you on Facebook"? Technically it is OAuth 2.0, the standard for authentication and authorization. Both users and applications are identified by URLs, which removes the need for prior client registration ("IndieAuth uses DNS as a replacement for client registration"), and PKCE is mandatory (a security mechanism that prevents an attacker from stealing the access token).

The flow in a nutshell: you type your domain in the login form, the service fetches your page and discovers your authorization server via rel="indieauth-metadata", redirects you there, you authenticate however you prefer (password, email, RelMeAuth), and the service receives confirmation that you control that URL. It is a living standard that the community considers stable.

Micropub: publish from any client

Micropub, a W3C Recommendation since May 2017, separates the publishing interface from your site's software: any application (web, iOS, Android) can create, edit and delete posts on your domain. It replaces the old MetaWeblog and AtomPub, which depended on sharing your password, with OAuth tokens obtained via IndieAuth.

The beautiful part is its vocabulary: it does not invent one, it is serialized microformats. Creating a post is a POST with h=entry and the same h-entry properties:

curl https://your-site.com/micropub \
  -d h=entry \
  -d "content=Hello world" \
  -H "Authorization: Bearer XXXXXXX"

If you are already used to working with REST APIs, it will feel very natural.

WebSub: real-time feeds

WebSub, formerly known as PubSubHubbub, a W3C Recommendation since January 2018, removes feed polling: instead of a thousand readers asking your server every half hour whether there is something new, you notify a hub when you publish and the hub instantly notifies all subscribers via webhooks. It reduces the load on your server and updates arrive without delay.

Many feed readers and aggregators support WebSub, such as Feedly or NewsBlur.

Microsub: the decoupled reader

Microsub is the youngest standard and still a draft. Think of it as the infrastructure that ties everything together into a social reading application.

There are 2 layers: a server that does the plumbing (managing subscriptions, fetching and parsing feeds, normalizing data) and a client that only renders the reading interface. This way clients compete on UX and your subscriptions are portable between them. Combined with Micropub to reply from the reader and Webmention to notify, it forms the complete architecture of the IndieWeb "social reader".

Publishing strategy: POSSE, PESOS and backfeed

Besides the principles and the protocols, the IndieWeb offers a mental model for coexisting with social networks without giving them your content:

POSSE (Publish on your Own Site, Syndicate Elsewhere): publish on your site first and then push copies to the networks, each one with a link to the original. It is the recommended technique. Your friends keep reading you where they already are, you keep the canonical copy, and if the network shuts down or bans you tomorrow, you lose nothing. The term was coined by Tantek Çelik in 2012, and it is practiced by everyone from Cory Doctorow on Pluralistic to Molly White, who repopularized it in 2024. A nice detail from the wiki: linking to the original from the copy is also "internet aikido" against spammers who copy posts, because they copy the link that credits you too.

PESOS (Publish Elsewhere, Syndicate to your Own Site): the reverse path, publishing on the silo and archiving a copy on your site afterwards. The wiki is honest about its advantages (silo apps are very polished, and it is asynchronous: if your website goes down, you can still publish), but considers it inferior: you publish subject to the silo's terms from the very first second, your copy is not the canonical one and you inherit its limits, like character caps or links wrapped in t.co.

Backfeed: the reverse syndication of interactions. The likes, replies and reposts that your POSSE copies receive on the networks come back to your original post as webmentions. This way the full conversation is archived on your domain, safe from the next silo death. The reference service is Bridgy: it watches your copies on Mastodon, GitHub, Flickr, Reddit or Bluesky and sends you a webmention for each interaction.

In short: you publish on your site, you syndicate to the silos with a link back, and the reactions come back home converted into webmentions.

Relationship with the Fediverse, RSS and friends

It may surprise you, but the IndieWeb does not live isolated from the Fediverse. Fun fact: protocols like Webmention, Micropub and WebSub came out of the same place, the W3C Social Web Working Group. The same group also gave birth to the famous ActivityPub, the protocol of the Fediverse. They are first cousins, although they follow different philosophies.

The Fediverse federates servers: your identity is @user@instance, and if you don't run your own instance, you depend on someone else's. The wiki does not mince words: joining a Mastodon instance means going "from one silo, to a perhaps more open source-based and more open standards supporting silo, yet still dependent on another central org", with the aggravating factor of the admintax, the brutal cost of moderating and maintaining an instance. The IndieWeb federates websites: your identity is your domain and federation is just one more channel.

However, they are not incompatible. Bridgy Fed is the bridge that converts your h-card, your h-entry and your webmentions to ActivityPub (and Bluesky's AT Protocol) and vice versa. The result is that your domain becomes a Fediverse account of the form @example.com@example.com where people can find and follow you from Mastodon, and replies come back to your post as backfeed. Mastodon understands that your profile and your posts live on your site.

RSS/Atom feeds, however, are a different story, since the IndieWeb considers them formats with structural problems. The argument is the DRY principle: the content is already in your HTML, so maintaining a parallel XML copy is a "maintenance tax", a separate code path that can drift out of sync, weighs more (there are Atom files up to 4.5 times larger than their HTML equivalent) and offers a terrible experience when a human clicks on the feed link. Their alternative is h-feed: the HTML itself as the feed. But as so often happens, being technically superior does not mean being accepted. They themselves admit that very few readers support microformats. Therefore, they recommend h-feed for the IndieWeb and RSS/Atom for the rest of the planet.

How to get started

The Getting Started guide recommends these steps, in this order:

  1. Get your domain and use it as your primary identity online. A concrete tip they give: consider the registrar's whois privacy options, but only if you fully trust the provider, because ownership disputes get complicated if you are not listed as the legal owner.
  2. Set up hosting: a managed service if you are starting out (they mention GitHub Pages, Netlify, Neocities...), self-hosting if you know what you are doing.
  3. Create your pages: static site generator, handwritten HTML or a CMS, it doesn't matter. There is no official technology, and that is deliberate (the plurality principle).
  4. Syndicate to other platforms (POSSE) with links back to the original.
  5. Add microformats: rel="me" links to your profiles on the homepage and h-entry markup on your posts.
  6. Validate your work with IndieWebify.me, which checks your rel-me, your h-card and your h-entry step by step.
  7. Join the community: share what you build even if it is a single page, and document it on the wiki for the next person.

For those who want a more gradual path there is IndieMark, a scale of levels, an orientation guide for developers.

What I have implemented (and what I have not)

I promised you at the beginning that I would tell you which pieces I implemented, which ones I discarded and why. Here is the list:

  • Webmention, sending and receiving. Sending is automated with a daily task that notifies the external links of new articles, with a 24-hour margin to fix typos before telling anyone. I use the receiving side to include a list of references at the end of each article. However, I keep it separate from my comments, since those are managed by email.
  • h-entry on every article and h-card on the homepage, verified with mf2py.
  • rel="me" in the footer pointing to Mastodon, GitHub and Org Social, with its corresponding green checkmark.
  • Micropub and IndieAuth: a conscious decision. My publishing interface is my editor and git; articles are versioned markdown. A publishing endpoint gives me nothing.
  • WebSub: evaluated and discarded. Since my publishing is deliberately delayed by 24 hours, "real time" does not justify the complexity.
  • h-feed: my article cards are reused in other contexts, such as the suggestions that appear inside each article, and marking them up would generate ambiguous h-entries for parsers. If I had designed the templates with this structure in mind, it would have been different. RSS covers that role just fine.

But the advice that helped me the most is not technical, it is about philosophy and web design ethics. Scattered across the wiki, it is worth gold with or without the IndieWeb. My selection:

  • Plain HTML is the most durable format. You can read the whole web without using JavaScript.
  • Cool URIs don't change: design permalinks you can maintain forever. For example, I can change the slug of an article and it will still work.
  • Gradual commitment, silo by silo: no exodus needed. Every type of content you start publishing on your own site first is a step forward in owning your data.
  • Think about extreme longevity: the wiki seriously discusses what happens to your website when you die, from the "dead man's switch" that hands the keys to someone you trust, to the practical problem Peter Molnar sums up as: "who's going to pay for your domain if you're not?".

And... have fun. An imperfect, weird personal website is worth more than a spotless template you are bored of maintaining.

The Daily Front Page 18 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — The Age of the Dupe
article

Dupes took over the world

by gumby·▲ 84 points·78 comments·vox.com ↗
A commercial ecosystem built around providing consumers cheaper substitutes for products they want.

The Verge’s Mia Sato explains the appeal and big business of dupes.

Business And Economy In New York

Fake designer purses for sale in Manhattan on July 6, 2024.

Beata Zawrzel/NurPhoto via Getty Images

When Deckers, the company behind fleece-lined UGG boots, recently took Quince to court over its lookalike boots, it tried to bar Quince from referencing “dupe culture” at trial.

The bid failed, confirming that “dupes” and “dupe culture” — a commercial ecosystem built around providing consumers cheaper alternatives to name-brand products — are cultural phenomena here to stay.

The trial focused on whether Quince’s shearling boots that really, really look like UGGs violated the existing patent for the design. And in a twist, the jury ruled that yes, Quince had copied the UGG design — but the patent over the UGG boot should not have been issued in the first place because the design was too generic to protect. The ruling opened the door for Quince and any other brand to make a similar-looking boot, opening up a new frontier for “dupe culture.”

And the culture is, undoubtedly, thriving. While it used to be embarrassing to own a fake, that’s no longer the case. Today, if you can find a cheaper, knock-off alternative – that’s a life hack.

In our online age, social media and online shopping exist awash in copies, dupes, and knock-off versions of name-brand products. Rather than outright counterfeits, these products carefully step around trademark and copyright rules with the express purpose of offering consumers cheaper alternatives to something a different brand created. It’s become an entire industry, embraced by influencers and companies like Quince.

In her recent piece, “Knock It Off!,” Mia Sato, a senior reporter at The Verge, outlines just a few things that have been duped recently: makeup, Le Creuset Dutch ovens, hand sanitizer, designer perfumes, Apple AirPods Max, Oura Ring fitness trackers, viral phone cases, dishwasher pods, famous banana pudding recipes, Pilates workouts, and the entire island of Santorini.

“We could probably surmise that there will be even more dupes in the future,” Sato told Today, Explained co-host Sean Rameswaram, “but I think there are more dupes than have ever existed in the history of mankind right now.”

She joined Sean on Today, Explained to discuss the rise of “dupe culture” and changing ideas of ownership and originality in an era of internet-driven mass consumption.

Below is an excerpt of the conversation, edited for length and clarity. There’s more in the full podcast, so listen to Today, Explained wherever you get podcasts, including Apple Podcasts, Pandora, and Spotify.

What exactly is dupe culture? What has it become?

Dupe culture is this idea that the limitlessness of the internet allows you to find a cheaper alternative, a copy, something that is a reasonable stand-in for the thing that you actually want. And it has permeated every industry: guitars, clothing, makeup, food, recipes.

There are dupes for Lululemon pants. There are dupes for Birkin bags, which are incredibly expensive, incredibly hard to purchase designer handbags that go for tens of thousands of dollars. There was a $50 version for sale at Walmart. It was called the ‘Wirkin.’

There are dupes for fancy pots and pans. There are dupes for lip glosses and lip oils and lip stains. There are dupes for vacations — someone was marketing a different island as a dupe of Santorini, right? You can apply this dupe framing to just about anything.

What’s different now is that dupes are kind of just a way of life, in that you don’t have to go somewhere seedy or weird or black market-y to get a dupe. Anything you can think of, dupe culture means that there is a dupe out there somewhere. But it’s walking a line, being very careful not to infringe on things like trademarks or copyright.

And how do you find your dupes? Do you just go to dupe dot com?

Dupe dot com is a thing. Dupe.com, basically, you can copy a URL to any product, plug it into dupe.com, and it will do a reverse image search of the web and find products that look similar. Some of them might be cheaper, some of them might be expensive, but the whole idea is you’re looking for lookalikes.

A lot of modern online shopping actually has all the tools you need to find a dupe. Amazon, for example, just introduced a new feature where you can write out a text version of what you’re looking for, and it will use AI to generate an image of what it thinks you’re describing and then use that AI-generated image to look for similar products. It’s basically a reverse image search.

TikTok has a feature where if you pause a video, it will highlight products in the video and you can click those products and find similar-looking dupes on TikTok Shop. So finding dupes has never been easier because a lot of these features are built into the platforms that we’re using in the first place.

When you talk about copying and pasting a URL into dupe.com or all these reverse image searches, where do we end up on the legality?

That’s sort of the million billion dollar question: What is allowed?

Obviously I’m not a lawyer, but when IP attorneys describe this to me, every, every question I would ask them, they’re kind of like, It depends. When you get down to something like fashion, one expert told me that a lot of it is not protectable. This shirt that I’m wearing, right? It’s like a button-down shirt with a lace pattern. No one should be able to own that specific thing. And just because a fast-fashion company were to rip this off, is there legal grounds to sue them? Maybe not. Just because two products look the same doesn’t necessarily mean that it’s illegal.

And it can turn people against you, right? People feel like they can rip off [guitar manufacturer] Fender because Fender’s the biggest fish. And people feel like they can rip off UGGs because for a decade, it was the boot to have and it doesn’t feel like they’re struggling.

Is that a part of this broader dupe culture that may or may not be peaking right now?

The public’s engagement with dupe culture is endlessly fascinating to me because people have a lot of thoughts. Often, the thoughts are, ‘Of course I’m going to buy a dupe of a Birkin because I can’t afford a $50,000 handbag. If there’s a cheaper alternative, I’m just going to buy that because poor people deserve nice things too, or I shouldn’t have to be mega-wealthy to afford a bag that I like.’ That thinking often colors the dupe discourse.

It gets messy and it gets really heated and emotional, I think, because we’re talking about something that Americans love to do, which is to consume, which is to shop. People get really defensive and protective of what they’re able to buy and the morality of dupes.

The dupe, I think, is never enough. This is my hot take, but I think when you have a dupe, you still lust over the product it’s duping. And in that way, it’s doing the opposite of putting them out of business. It’s actually making them even more aspirational.

I think that modern online shopping has kind of lied to consumers and almost rewired our brains to make us think that there is such a thing that costs five dollars and will last a really long time and is ethically made and looks good. Often, that is not the case. And often, that’s what dupes are.

They give you the illusion of finding something nice or finding something beautiful or something that you identify with, but when you strip away a lot of it, it’s a lie. You get what you pay for. And the cost of things has gone down so much, especially since Temu and SHEIN, these ultra-fast-fashion brands, that I think consumers have forgotten what is literally possible when it comes to cheap and good products. I think cheap and good products do still exist, but not to the extent that we would like to believe.

How did you think when you’re writing your piece, Mia, about where the internet has taken the idea of originality?

I think our current algorithm-driven feeds make it so that copying someone or recreating something is not just easier, but it actually sometimes makes more sense. Think about the way that trends circulate, right? The platforms encourage us to use the same sounds as other people, do the same dances, edit in the same way, pick up on the same formats. They want dupes of the content.

What I was interested in when I was writing this piece was that the textures of the internet, the endless copies and the similar but different creators and the little niches were recreating themselves in our physical world, in the things that we surround ourselves with. If you went home and looked around your house, you probably have a dupe of something. I have dupes of stuff in my house that I didn’t even know were dupes. They’re all over, and sometimes you buy a dupe without even realizing it.

The Daily Front Page 19 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — The Times Table Mystery
article

Mathematicians still don't know the fastest way to multiply numbers

by beardyw·▲ 222 points·137 comments·scientificamerican.com ↗
Memorization won’t cut it when the teacher asks for three-digit multiplication.

A 23-year-old student overturned an ancient conjecture about one of math’s simplest operations

Man writes mathematical equations on chalkboard

Justin Lewis/Getty Images

Elementary school students might memorize their times tables for single-digit numbers, but memorization won’t cut it when the teacher asks for three-digit multiplication. This requires an algorithm: students are taught to stack one number atop another and multiply each digit of the bottom number by each digit of the top one. For millennia, mathematicians believed this to be the fastest multiplication method, until a 23-year-old made a shocking discovery in 1960, which led to a mystery that remains unsolved to this day.

This mystery is critical to anyone who partakes in the digital world because multiplication is a foundational operation for computers. Encryption, robotics, artificial intelligence, audio processing and pretty much everything else we task silicon chips with involves multiplication, sometimes of huge numbers many times over. At this scale, even a simple operation becomes a bottleneck, and any extra efficiency has global economic consequences.

To understand the nature of that bottleneck, observe how the grade-school algorithm handles growth. When you multiply two two-digit numbers, you perform four single-digit multiplications. If you bump that up to a three-digit pair of numbers, you do nine single-digit multiplications. The workload scales with the square of the number of digits (n2, where n is the number of digits in the numbers being multiplied). When analyzing an algorithm like this, computer scientists don’t measure speed in seconds, because that depends on the hardware. Instead they count the computational steps. They also ignore minor bookkeeping details, such as the time it takes to carry a one when multiplying. When numbers get large enough, those lower-level operations cease to matter, entirely eclipsed by the more intensive operations involved. Computer scientists denote the number of steps using what’s called Big O notation: the grade-school algorithm, for example, takes O(n2) steps, which is read as “order n squared.” Broadly speaking, if the numbers are twice as long, the algorithm takes four times as much computational work to execute. If the numbers are a thousand times as long, it takes a million (1,000 squared) times as much work.

Since antiquity, mathematicians have suspected that O(n2) was an inherent speed limit for multiplication. The celebrated Soviet math professor Andrey Kolmogorov posed the O(n^2) speed limit as a formal conjecture and mentioned it during a 1960 seminar at Moscow State University. Whenever mathematicians propose a conjecture, they are planting a flag of sorts and waiting for others to either prove or disprove them. It took just a week for Anatoly Karatsuba, then a 23-year-old student in the audience, to return and prove Kolmogorov wrong. Kolmogorov was stunned. The result was published in the prestigious Proceedings of the USSR Academy of Sciences, but amusingly, Karatsuba didn’t write it. Kolmogorov wrote the formal proof himself and submitted it for publication with Karatsuba listed as the lead author. Karatsuba only found out about the paper when he received the reprints in the mail.

Karatsuba’s genius was realizing that you can trade expensive, time-consuming multiplications for cheap, fast additions. Adding two n-digit numbers takes only O(n) time because it entails a single sweep through the digits rather than a complete sweep through the top number for every digit of the bottom number, as in multiplication. To see how Karatsuba traded multiplication for addition, let’s look at a small example. The method would be overly complicated for such a simple problem, but it saves a meaningful amount of time when numbers get larger.

In this simple example, let’s calculate 12 × 34.

First, we split both numbers into their tens and ones digits. Assign a = 1 and b = 2 (for 12), and c = 3 and d = 4 (for 34). Algebraically, we can rewrite 12 × 34 as (10a + b) × (10c + d).

Expanding this gives 100(ac) + 10(ad + bc) + (bd).

To solve the equation in the traditional way, one must perform four distinct multiplications: ac = 3, ad = 4, bc = 6 and bd = 8, which is exactly what the grade-school stacking method entails. (Note that we don’t count the multiplications by 100 or by 10 because those only involve plopping zeroes at the ends of numbers.) Karatsuba noticed a brilliant algebraic trick. Once you compute the first and last terms, ac and bd, you can figure out that pesky middle term (ad + bc) with one more multiplication step rather than two. You don’t need to calculate ad and bc individually:

(ad + bc) = ((a + b) × (c + d)) – acbd,

Or with our concrete numbers:

((1 × 4) + (2 × 3)) = ((1 + 2) × (3 + 4)) – 3 – 8 = 10.

Pause to notice the weirdness in the equation above. It suggests that to multiply 12 × 34 quickly, you should add the 1 and the 2 in 12 and the 3 and the 4 in 34. This is hardly a natural thing to do. No wonder it took so long for someone to figure it out. It ends up reducing the workload, however: because we’ve already computed ac and bd, the right-hand side only contains one more multiplication, plus some additions and subtractions.

Returning to 100(ac) + 10(ad + bc) + (bd), we only need three multiplications rather than four. We compute ac and bd in the straightforward way and then use Karatsuba’s trick to compute (ad + bc) with a single multiplication. Plugging in ac = 3, bd = 8 and (ad + bc) = 10 gives our answer of 408.

We shaved one multiplication off the procedure. If that seems measly, Karatsuba has another insight in store. Say we’re multiplying bigger numbers: 1,234 × 5,678. We split them in half like we did before: a = 12, b = 34, c = 56 and d = 78, and we write the problem as (100a + b) × (100c + d) = 10,000(ac) + 100(ad + bc) + (bd).

We can solve this with three multiplications. Those multiplications, however, now involve two-digit numbers. Luckily, we know a way to multiply two-digit numbers with only three single-digit multiplications each! In total, a problem that would take 16 single-digit multiplications the traditional way now needs only nine. By recursively applying Karatsuba’s trick on large numbers, the savings compound. It splits the input numbers in half, then splits those halves in half, and so on, applying this four-for-three trade all the way down. The algorithm works out to have a running time of roughly O(n1.585), which is drastically faster than O(n2). For reference, multiplying a pair of thousand-digit numbers involves a million single-digit multiplications using the grade-school method but fewer than 57,000 using Karatsuba’s algorithm.

The 23-year-old’s efficiency is baked into software that runs every day. Because of its extra overhead (the additions, managing the repeated splitting and recombining of numbers, and so on) its advantages over the grade-school algorithm don’t kick in until numbers grow relatively big. Python, for example, is a popular programming language that is famously smooth at handling integers of any size. If you peek into Python's underlying source code (search “Karatsuba” here), you will see it relies on a hybrid approach. For modestly sized inputs, it uses the grade-school math, but once numbers reach around 630 decimal digits, it flips a switch and employs Karatsuba’s algorithm. That many digits might seem gargantuan by terrestrial standards, but computers deal with much bigger. (Technical aside: On most modern machines Python stores large numbers in base 230, so the linked Karatsuba cutoff of 70 digits in base 230 translates to roughly 630 decimal digits).

Karatsuba’s algorithm ignited a decades-long race to find the ultimate speed limit of multiplication. That pursuit culminated in 2019, when mathematicians David Harvey and Joris van der Hoeven described an extremely sophisticated algorithm that beat Karatsuba’s by more than any of the previous breakthroughs. The new algorithm runs in O(n × log n) time. Here log denotes the logarithm of n, which is a function that grows very slowly. It’s a staggering result. The function n × log n is just a little bit bigger than n itself. This means that calculating the product of two massive numbers requires only a little more time than adding them, or even reading them, would in the first place (it takes n computational steps to read all n digits of a number).

The triumph comes with a crucial caveat, though. Just as Karatsuba’s algorithm only outperforms the grade-school approach when numbers get reasonably large, the Harvey-van der Hoeven algorithm doesn’t pull ahead until the numbers become truly galactic. In computer science, a “galactic algorithm” is a formal term for a method that is impressively efficient on sufficiently large numbers but will never be useful in practice because the numbers are so large.

Even with that asterisk, it was a watershed achievement. It secured the record for the fastest known multiplication method in principle and could pave the way for algorithms that run in O(n × log n) steps, not just in principle, but in practice. Today, theoretical computer scientists widely suspect that O(n × log n) is the fastest possible speed for multiplication, and formally proving it has become the holy grail for this niche field of mathematics. But as history reminds us, widespread consensus is not a mathematical proof. Conjectures about the speed limit of multiplication have been overturned before.

The Daily Front Page 20 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Workbench Briefs
article

Land Atlas – soil, farmability, and crop analysis for land listings

Land Atlas captures listings as you browse any land marketplace, then scores every parcel with government-grade data: USDA soil quality averaged over the actual acreage, ten-year climate records, FEMA flood zones, wetlands, and distance to the power grid — distilled into one honest farmability score.

USDA SSURGO soil survey

10-year climate archive

FEMA flood zones

USFWS wetlands inventory

OpenStreetMap grid & roads

Every parcel, scored like an analyst would

One capture pulls the listing into your Atlas and runs the full analysis automatically — no spreadsheets, no tab-juggling across six government websites.

Soil quality over the whole parcel

Not a single point sample: soil is area-weighted across every USDA map unit inside the parcel's actual acreage — or inside a boundary you draw on the map.

Farmability score & crop fit

Soil, climate, and land risk blended into one 0–100 score, plus a ranked list of the 16 crops that fit the parcel's pH, drainage, frost window, and heat profile.

Flood & wetland risk

FEMA flood-zone classification and National Wetlands Inventory overlap, scored with the terrain — so "cheap bottomland" surprises show up before you visit.

Grid & road access

Distance to the nearest substation, transmission line, power plant, and highway — the site-selection data enterprise land platforms charge for.

Comps from your own pipeline

Every parcel is percentile-ranked on price per acre against comparable listings you've captured in the same state and size band.

Projects, exports, reports

Group parcels into assemblage projects with blended stats, export filtered views to CSV, and print a clean per-parcel analysis report.

How it works

Three steps from "saw it on a listing site" to "fully analyzed in my Atlas."

Install the extension

One click adds the capture button to your browser. Works on the major land marketplaces — listing pages and search results alike.

Browse like you already do

Hit capture on any listing (or auto-save every listing you view). Title, price, acreage, photos, and location come along automatically.

Read the analysis

Soil, climate, crops, risk, grid access, and comps are computed in the background and waiting on the map — on desktop or your phone.

Honest by design. Every score shows its factors and its gaps: estimated values are labeled, missing layers are listed, and analysis is never presented as more certain than its sources. Data comes from public USDA, FEMA, USFWS, and OpenStreetMap services and is screening-level — it narrows the shortlist, it doesn't replace due diligence.

See it with real listings

The live demo is the actual Atlas — hundreds of analyzed parcels, browsable by anyone with the link.

The Daily Front Page 21 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Workbench Briefs
The Daily Front Page 22 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Workbench Briefs
article

Cagire: Live Coding in Forth

by surprisetalk·▲ 91 points·11 comments·cagire.raphaelforment.fr ↗

Download

Platform Terminal Desktop macOS (Universal) zip zip · dmg · app Linux (x86_64) zip · AppImage zip · AppImage Linux (ARM) zip · AppImage zip · AppImage Windows (x86_64) zip zip

Source code and issue tracker on Gitea. You can also compile the software yourself from source!

About

Cagire is a step sequencer where each step contains a Forth script instead of typical note data. When the sequencer reaches a step, it runs the associated script. Scripts can produce sound, trigger samples, apply effects, or do nothing at all. You are free to define what your scripts will do. Cagire includes a built-in audio engine called Doux. No external software is needed to make sound. It comes with oscillators, sample players, filters, reverb, delay, distortion, and more.

Documentation

Cagire ships with built-in interactive documentation. Browse it right inside the app, where every example is runnable on the spot. The manual is a full book, both a tutorial and a reference. It covers the interface, the two Forth-like languages and the sound engine. A printable edition of the same manual also exists.

The language

Cagire scripts are written in Forth, a concatenative language you read one word at a time, from right to left. One step can do many things, here is an example:

saw snd
< c4 eb3 g3 > note
[ .5 .8 ] choose gain
( 8 crush ) sometimes
0.5 decay
.

A second language, Arf, lives between curly braces and allows you to write your own DSP when the basics are not enough:

{
    110 saw 800 lpf
    out
} synth .

Features (click to learn more!)

Synthesis Sampling Filters Effects Modulation Theory Probability Sequencer Play Live Projects MIDI OSC Ableton Link Recording Visuals Forth Dictionary Themes Cross-platform

Gallery

Sequencer view with a scope and spectrum visualizer, level meters and the 32-step grid

Main view with the sample browser open, showing a folder tree and a waveform preview

Step script editor defining a synth voice with an effects chain of reverb, flanger and delay

Patterns view with a bank grid, track lanes and a pattern properties panel

Dictionary view with a category tree beside Forth word entries and stack effects

Help view showing the engine manual page on spread and detune, with prose and Forth examples

Engine view showing OSC output configuration alongside level meters and an oscilloscope

Sampler view with a recorded waveform and a trim selection in edit mode

Black and white theme showing a step script editor with a stack visualizer

Live Coding

Live coding is a technique where a programmer writes code in real-time in front of an audience. It is a way to experiment with code, to share openly, to express yourself through code. It can be technical, poetical, weird, preferably all at once. Live coding can be used to create music, visual art, and other forms of media. Live coding is an autotelic activity: doing it is its own reward. There are no errors, only fun. Learn more at TOPLAP or livecoding.fr.

The Daily Front Page 23 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Workbench Briefs
repository

UnifiedIR for Julia

by vimarsh6739·▲ 91 points·17 comments·github.com ↗
★ 48,905⑂ 5,853 forks Julia

The Julia Programming Language

il_1588xN 2422929160_bfaa-1-600x596

Our current IR data structures in Base are about 10 years old at this point. They've held up relatively well, but there are also big problems with. I think the three biggest are that the IR is somewhat hard to use (both for general API design reasons as well as for semantic reasons relating to ownership and invalidation), that it is not extensible to various other use cases that have grown in the ecosystem (leading to people either suffering through hacks or just building their own IR data structures) and really that it was never design to be an externally facing system at all.

This PR tries to fix that by introducing UnifiedIR, a new top-level package alongside Compiler, JuliaSyntax and JuliaLowering (and depended upon by all three) that provides a self-contained, extensible set of IR data structures and operations for use both in Julia base and in the larger ecosystem.

It is a dialect-aware, region-based IR representation (similar to MLIR) but retains a fair bit of the design of the original Julia IR (and JuliaLowering) representation that I thought worked well. It is in particular designed to replace the following existing data structures:

  • SyntaxTree (from JuliaSyntax)
  • SyntaxGraph (from JuliaSyntax/Lowering)
  • CodeInfo (for inference purposes, codegen/interepreter are out of scope for the moment but should be adapted in the future)
  • IRCode
  • Various IRs within the ecosystem

To facilitate this, there is a core data structure that provides an efficient representation of the IR along with core utilities. Any particular user of this core data structure can expand it with additional columns (one entry per statement) and there is also a concept of layered views to make it easier to work with the IR in a particular application.

The currently defined layered views are:

  • An IncrementalCompact like extension that allows fast one-pass replacement passes
  • An LLVM-like view that maintains ordering through linked lists (thus making complicated CFG transforms a lot easier). To avoid the usual LLVM pitfall of quadratic order maintenance for large functions (which are important to some downstream applications), there's a fancy order maintenance algorithm that claude and I came up with (but still needs validation).
  • A graph like embedding for use by array compilers (as well as lowering) (Graphs are IR with no control flow dependency)
  • A tree-like encoding for use by lowering (trees are IR where every statement has exactly one user, except for the root, which has zero).

Major features include first class support for regions (making features like #58532 easy to implement as well as facilitating better integration will MLIR) as well as first class support for dialect extensions.

This PR ports inference, the optimizer and JuliaLowering to the new data structure, but does not yet enable it for bootstrap. That said, I ran about half of the test suite with this version of the compiler and things were working. This should be considered a bit of a preview PR and a basis for discussion. There's many things that still need to be done, but I wanted to put this up so I had something to point to as a basis for discussion.

The Daily Front Page 24 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Curiosities and Relics
article

Bananas sprout in Rayleigh Garden UK after 15 years

by teleforce·▲ 152 points·112 comments·bbc.com ↗

Supplied A woman with glasses and a hat posing next to a bunch of bananas

Emma (pictured) and Peter Stav waited 15 years for their plants to suddenly grow fruit

Could bananas be common in British gardens soon? Warmer summers and milder winters might mean new fruits appearing, while we say goodbye to some old favourites.

Peter and Emma Stav, tropical plant enthusiasts from Rayleigh in Essex, were astonished to see fruit finally grow on their collection of 200 banana plants after 15 years.

Peter, a 38-year-old school teacher, said: "I'm just absolutely amazed that it's happened."

Guy Barter from The Royal Horticultural Society said "heat-loving plants" such as olives, figs and apricots are excelling more, while traditional British crops like gooseberries and rhubarb are on the decline in some areas.

The chief horticulturist said: "The climate is getting warmer and bananas never used to flower 20 years ago. It would be a red letter day when the banana flowers."

Peter Stav A close up of a thick green stalk which is splitting off into fruit that slightly resembles bananas

Olives and apricots are thriving, while gooseberries and rhubarb struggle

The Musa Basjoo banana has always been famous for being able to survive UK winters, but the flower often needs protection from frost.

The Stavs have built walls around their plants to trap heat and create a "microclimate effect" for the colder winter weather.

Peter said: "Over the past couple of winters I haven't wrapped them up because they're nearly 3m (10ft) tall so it's very difficult to wrap them. This year due to the heatwave, the plant's actually fruited.

"You put one in the ground and you get another 10 come up. They split. They produce more and more and more."

Elsewhere in the East of England, a 76-year-old man from Suffolk was in "complete surprise" when his banana plant suddenly produced fruit for the first time.

Stephen Hind, of Pettistree near Wickham Market, bought the tree for his exotic garden a few years ago because "they just look good", and believes scorching temperatures played a part in bringing it to life.

Supplied A man wearing glasses, a dark blue T-shirt and light blue shorts stands next to a banana plant. There are a number of trees and plants behind him.

Stephen Hind takes pride in maintaining his garden, which is filled with exotic plants and trees

TV presenter and botanist James Wong said the hotter UK temperatures has made it "very easy" to grow bananas.

He said: "It's sort of impossible to water or fertilise them too much. They're incredibly fast growing if they have that heat.

"If people live in a really cold or exposed area or in the northern half of Britain, they might wrap up the stems.

"That basically creates like an insulating layer that protects a pocket of warm air around the plants and stops frost from damaging their cells."

'Mouthful of ball bearings'

BBC Studios James Wong looking closely at a plant

Botanist James Wong has appeared on the BBC's A Countryside Summer

Wong, 45, has presented for BBC series' Grow Your Own Drugs and Secrets of Your Food.

He pointed out that Musa Basjoos are not really for eating.

He said: "It's basically like having a mouth full of ball bearings with half a teaspoon of banana on them."

He added that growing banana plants in the UK is not new for a "geek in the plant world", but perhaps still niche to the average person.

The Daily Front Page 25 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Curiosities and Relics
article

A Visual Catalog of Retro Macintosh Software

by zdw·▲ 81 points·7 comments·marciot.com ↗

A picture might be worth a thousands words, but icons are a fun way to explore retro apps! Hover over any icon to see the file‘s name, the country of origin, and the name of the media; then go to about page to find links to the original media at the Macintosh Garden!

Finder application and document icons are highlighted in green and hovering over them will reveal their file type and creator codes.

article

The Last MPEG-4 Visual Patent Has Expired

by LorenDB·▲ 201 points·58 comments·phoronix.com ↗

MULTIMEDIA

If you are looking for a reason to celebrate today, the last of the MPEG-4 Part 2 patents expired today.

While the US and EU patents around MPEG-4 Part 2 expired in recent years, until today there remained one patent still active in Brazil. This final patent was BRPI0109962B1 - "process for storing and processing image information from successive images over time".

The VIA Licensing Alliance confirmed that this was the final MPEG-4 Visual patent and indeed expiring today, 19 July 2026.

MPEG-4 last patent

Great to see this day finally realized given the prevalence of MPEG-4.

The Daily Front Page 26 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Curiosities and Relics
article

A new Intel Itanium (IA-64) emulator that boots Windows

by jandeboevrie·▲ 75 points·63 comments·raymii.org ↗

More emulation goodness, an Intel Itanium (IA-64) emulator that boots Windows!

The emulation space is going crazy, after my previous post on Windows booting on DEC Alpha es40 emulator, there is now another huge breakthrough in the emulation of other non-x86 CPU emulation. Yufeng Gao with help from gdwnldsKSC (the man behind the updated es40-fork) has released version 0.1 of his Intel Itanium (IA-64) emulator that boots the Itanium version of Windows Server 2003 and Windows XP 64-bit. No OpenVMS or HP-UX yet and Linux / BSD also don't boot. But Windows is amazing already.

Here is a screenshot of Windows Server 2003 with the Luna theme running in the emulator:

win2k3 itanium

It runs quite slowly, (486-levels of performance on a Ryzen 5000 series according to this discord channel) but hey, it runs at all. How cool is that! Let's hope development continues and we might even get to run OpenVMS on Itanium, emulated. HP-UX would be nice as well, but I care more for OpenVMS. As far as I know there are no commercial Itanium emulators yet.

You can read more about the Intel Itanium (IA-64) CPU on Wikipedia and here is a great video from RetroBytes with some more history. Basically it was a promising architecture, but didn't make it and effectively it was only used for HP-UX and OpenVMS in the later years. But OpenVMS is now available on x86 and HP-UX is dead in the water, no migration path available there. I don't think Windows on Itanium was ever used intensively. If you do know of more usage in the real world, please let me know.

Here are two more screenshots, also showing Windows XP 64-bit for the Itaium:

win2k3 and xp itanium

winxp itanium

The screenshots come from discord.

The emulator was announced on Twitter:

emulator announced

The code is not open source, but the twitter thread stated:

Once cleaned up, it will be available here: https://github.com/TheBrokenPipe/ski.

Update: 2026-07-20: There seems to be a QEMU fork that can also run Server 2008.

See this repo. I haven't checked that one out but it does state that it's written using LLM's. Was mentioned on the Discord server.

Screenshots:

qemu-ia64-1

qemu-ia64-2

The Daily Front Page 27 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Dungeon in BASIC
article

C64 Basic Dungeon Crawler: Goblin Attack (C64 Basic Part 8)

by ibobev·▲ 69 points·5 comments·retrogamecoders.com ↗
This time they chase you.

Redefinable keys, goblins that chase you, d20 combat, and the memory bug that had the game silently overwriting itself.

In part seven the dungeon was full of goblins that were about as threatening as garden gnomes. They stayed exactly where the map generator dropped them. You could walk up, poke them, take five points of damage and stroll away, and they’d still be standing there in the same spot when you came back.

This time they chase you. A small change in code but big step forward in feel, and getting there dragged me into a weird and nasty memory bug that corrupted my character set while I watched. The bug is probably the most useful lesson in this whole part, so if you skim, don’t miss the memory section.

Open the full program and edit it in your browser here: part8d.bas in the RGC online IDE.

Where we got to last time

Quick recap of where part seven left off. We had a custom character set loading from disk, a map built out of three by three meta-tiles which randomly generated on every run, a player rolled up with proper Dungeons and Dragons style stats, collision detection that read the screen back with PEEK, and a teleport key for when the random map boxed you into a corner.

What it didn’t have was a game. Nothing threatened you, so there were no stakes.

Four things change in this part:

  • You can redefine the keys, because QAOP is not to everybody’s taste.
  • Goblins get a position, a health value, and a brain (albeit, a very small one).
  • Combat happens with a real d20 roll and a strength modifier.
  • And the game stops eating itself, which is a longer story than it sounds.

Choose your own keys

Somebody called me out on the controls, and for good reason. QAOP was one of the standards growing up so it’s burned into my fingers, but if you didn’t grow up with it, it’s a weird cluster of keys. I could have switched to WASD, but that annoys a different set of people just as much. The answer is that both sides are right, and the fix is to stop picking for them.

The trick to making this work is that the game must never compare against a literal key again. Instead of asking “did they press Q“, it should ask “did they press whatever is currently stored as the up key“. So first we need to store the defaults:

REM DEFAULT KEYS
QKEY$="Q"
AKEY$="A"
OKEY$="O"
PKEY$="P"
FKEY$="SPACE"

Those variable names look like they were chosen carelessly. They weren’t, and this is one of the common traps of Commodore BASIC for modern coders.

Only the first two letters actually matter

Commodore BASIC stores a variable name in exactly two bytes. You can type PLAYERHEALTH and it will happily accept it, but internally it only ever takes note of PL, so the other ten characters are read and thrown in the bin. Which means PLAYERHEALTH and PLAYERX are the same variable, which makes your game do something baffling and difficult to debug that has nothing to do with the logic you wrote.

That means my five key variables are deliberately unique in their first two characters: QK, AK, OK, PK, FK.

There’s a second, sneakier version of the same trap, and part seven’s code has a comment about it that people asked me to explain:

REM GL NOT GOLD - GO CLASHES WITH GOTO (2-LETTER NAMES)
GL=0

A variable name shouldn’t really contain a BASIC keyword anywhere inside it because BASIC tokenisers can get very unhappy when you do. The C64 doesn’t read your original code listing, it first needs to be tokenised, scanning left to right and replacing every keyword recognised with a token byte.

It doesn’t know or care that you meant GOLD as a name. It sees GO, which is a keyword ( GO TO with a space), swaps it for a token, and leaves you with a token followed by LD. If it tries to run that it will throwsa syntax error at you from a line that looks perfectly OK when viewed on screen.

The classic ones that get people are TO, IF, ON, OR and AND. So SCORE contains OR, COUNT (ON), TOTAL (TO). If a program refuses to work and you can’t see why, look at your variable names before you hack away at your logic.

Reading a key that you can’t predict

With the defaults in variables, the input routine changes from testing letters to testing variables:

IF P$=OKEY$ THEN PX=PX-1
IF P$=PKEY$ THEN PX=PX+1
IF P$=QKEY$ THEN PY=PY-1
IF P$=AKEY$ THEN PY=PY+1
IF P$=FKEY$ THEN GOSUB FIRE

Now the redefine screen just has to write new values into those five variables. The interesting constraint is that it has to use GET, not INPUT. INPUT waits for you to type something and press RETURN, it echoes what you type, and it has strong opinions about commas.

Someone remapping their controls might want to press a key that INPUT would freak out with or mangle, for example someone using an emulator might want to use the modern cursor keys. Asking them to press their chosen key and then hit RETURN is a sure way to get the wrong result, besides it’s one keypress too many for something that should feel immediate.

GET reads a single character from the keyboard buffer and returns immediately, whether or not anything is there. That “whether or not” needs to be tested. If the buffer is empty and you get an empty string, the program carries straight on, so GET on its own is not “wait for a key“, it’s “check for a key“. To make it wait, you must loop it until it gives you something useful:

CHANGETHISKEY:
GET K$: IF K$="" THEN GOTO CHANGETHISKEY
RETURN

Everything else is just asking the questions in order and recording the answers:

CHANGEKEYS:
PRINT "{CLR}{GREY}"
PRINT "CHANGE KEYS"
PRINT "==========="
PRINT ""
PRINT "DEFAULT: QAOP AND SPACE"
PRINT "PRESS THE KEY FOR UP"
GOSUB CHANGETHISKEY
QKEY$=K$
PRINT "PRESS THE KEY FOR DOWN"
GOSUB CHANGETHISKEY
AKEY$=K$
PRINT "PRESS THE KEY FOR LEFT"
GOSUB CHANGETHISKEY
OKEY$=K$
PRINT "PRESS THE KEY FOR RIGHT"
GOSUB CHANGETHISKEY
PKEY$=K$
PRINT "PRESS THE KEY FOR FIRE"
GOSUB CHANGETHISKEY
FKEY$=K$
PRINT "HAPPY WITH YOUR CHOICES? (Y/N)"
HOLDFORKEY:
GET A$
IF A$="" THEN GOTO HOLDFORKEY
IF A$="Y" THEN RETURN
IF A$="N" THEN GOTO CHANGEKEYS
RETURN

The confirmation at the end matters more than it looks. It’s very easy to fat-finger the third key of five, and without a way out you’d be stuck with a control scheme you didn’t really choose. Answering N jumps back to the label at the top and starts the whole thing again, which is about the easiest undo you’ll ever write.

One note if you’re typing this into a real machine rather than the IDE: those labels (CHANGEKEYS, CHANGETHISKEY) are a convenience of the RGC online IDE, which resolves them to line numbers when it tokenises. On a stock C64 they’d be GOSUB 4000 and friends. Same code, but uglier to read IMO. Download and open the .PRG if you want to see the line numbers in all their glory!

C64 BASIC with line numbers

If you prefer line numbers, you do you!

Goblins need to be tracked before they can move

Here’s something I glossed over in the video. Up until now, the goblins didn’t really exist as far as the program was concerned. They were drawn, sure, and by checking RAM the collision code could tell it had bumped into screen code 38, but the program had no way to track them, no idea how many there were, and no way to refer to any specific one.

That’s fine when a goblin is decoration, but the moment it needs to move, we need to know which one moved, from where, to where, and whether it’s still alive. So here the goblins get promoted from screen pixels to actual game objects:

REM DECLARE ENEMY VARIABLES
GC=0: REM GOBBO COUNT
DIM GH(10) : REM GOBBO HEALTH ARRAY
FOR GC=1 TO 10: GH(GC)=10: NEXT GC
GC=0
DIM GX(10) : DIM GY(10) : REM GOBBO LIST

Three parallel arrays: GX and GY hold each goblin’s column and row, GH holds its health, and the variable GC counts how many we’ve actually placed. Goblin number 3 is GX(3), GY(3), GH(3).

Parallel arrays are how you represent a record or a struct in a language that has no such thing, and on an 8-bit machine they’re faster than the alternative anyway.

The FOR GC=1 TO 10 loop is quietly reusing GC as its counter to fill every health slot with 10, then resetting it to zero. It saves a variable, and every variable you declare in BASIC costs you bytes plus a slot to search past on every single lookup. Small, this is the sort of thing that adds up.

Our goblins get added to the list right where they get drawn in the meta-tile routine. If the tile we’re about to stamp down is number 17, that’s the tile with a goblin in the middle:

DRAWMT:
PRINT MT$(MT,0);"{DOWN}{LEFT}{LEFT}{LEFT}";
PRINT MT$(MT,1);"{DOWN}{LEFT}{LEFT}{LEFT}";
PRINT MT$(MT,2);
REM IF MT=17 THEN IT CONTAINS A GOBBO
IF MT=17 THEN GOSUB ADDGOBBO
RETURN
ADDGOBBO:
REM ADD TO THE GOBBO LIST - GX=COL (X), GY=ROW (Y), MATCHES PX/PY
REM GUARD: STOP AT 10 SO GC NEVER EXCEEDS DIM GX(10) = ?BAD SUBSCRIPT
IF GC>=10 THEN RETURN
GC=GC+1
GX(GC)=COL+1
GY(GC)=ROW+1
RETURN

The +1 on each coordinate is the bit worth noting. ROW and COL are where the metatile starts, its top left corner, but the goblin isn’t at the top left, it’s in the middle of the three by three block. So the goblin’s real screen position is COL+1, ROW+1. Get this wrong and your goblins are all standing in a wall, one square up and to the left of where you can see them.

Ten metatile 17s could theoretically come up on a random map, so once GC hits 11 you’re writing to GX(11) in an array you dimensioned to 10, and BASIC stops your game dead with ?BAD SUBSCRIPT ERROR. Proper, fair enemy generation is on the list to do but for now this stops a crash.

Dumb enemy ‘AI’ that works

The game is turn based, which means the player moves, then the enemies move, then we check whether the game is over.

GAMELOOP:
OX=PX : OY=PY
REM PLAYER INPUT AND DRAWING
GOSUB KEYS
IF PX<>OX OR PY<>OY THEN GOSUB ERASEPLAYER
GOSUB DRAWPLAYER
REM HERE IS WHERE YOU PUT THE ENEMY LOGIC
GOSUB ENEMYLOGIC
REM CHECK GAME OVER CONDITIONS HERE
REM --------------------------------
REM RETURN TO GAMELOOP
GOTO GAMELOOP

Turn based offers some flexibility because the enemies only get to think after you press a key. There’s no timing, and no danger of the goblins running away with the CPU while you’re deciding what to do next. On a machine this slow, taking turns is the thing that makes enemy AI in BASIC viable.

The simplest enemy that is actually a threat is one that always moves towards you. It doesn’t calculate a path around walls, just walks in your direction each turn:

ENEMYLOGIC:
IF GC=0 THEN RETURN
FOR G=1 TO GC
REM SKIP DEAD GOBBOS (CBM BASIC CANT SKIP FORWARDS)
IF GH(G)<=0 THEN GOTO NEXTENEMY
REM START FROM CURRENT CELL, THEN NUDGE TOWARD PLAYER
IX=GX(G) : IY=GY(G)
IF GX(G)>PX THEN IX=GX(G)-1
IF GX(G)PY THEN IY=GY(G)-1
IF GY(G)

Read the four IF lines as a sentence and the whole “AI” is exposed. If the goblin’s column is bigger than yours it needs to go left, so knock one off. If it’s smaller, add one. Same for the rows. That’s it. Because both axes are tested independently, a goblin that’s up and to the left of you moves diagonally down and right in a single turn, which looks far more deliberate than the four comparisons appear.

The proposed move goes into IX and IY rather than straight into GX(G) and GY(G), and that separation is important because we don’t know yet if the move is possible, and we still need a copy of the old position. So IX and IY are “where it wants to go“, GX(G) and GY(G) stay “where it currently is“, and only MOVEENEMY is allowed to change one to the other.

The collision check is again a single PEEK. If the target cell contains screen code 46, aka a floor dot, it’s empty and the goblin can move to it. Anything else, such as a wall, an item, another goblin, you, and the condition fails and the goblin simply stands still for a turn. That one comparison eliminates the need for a whole complex navigation system, but it also means goblins pile up in doorways and get stuck behind walls like the keystone cops.

MOVEENEMY:
REM SET CURSOR POSITION TO OLD GOBBO CELL AND ERASE
GOSUB ERASEENEMY
REM SET TO NEW CELL AND DRAW
GX(G)=IX : GY(G)=IY
GOSUB DRAWENEMY
RETURN
ERASEENEMY:
ROW=GY(G) : COL=GX(G) : GOSUB CURSORSET : PRINT "{GREY}."
RETURN
DRAWENEMY:
ROW=IY : COL=IX : GOSUB CURSORSET : PRINT "{GREEN}&";
RETURN

The order in MOVEENEMY is intentional. Erase first, using the old GX(G)/GY(G), then overwrite them with the new position, and only then draw afresh. It’s the classic software sprite problem, you’re responsible for cleaning up your own mess, and you can only clean it up while you still remember where it was.

Why there’s a label in the middle of a FOR loop

That NEXTENEMY: label sitting just above NEXT G is there because Commodore BASIC has no CONTINUE to bail out of the FOR NEXT. There is nothing that means “I’m done here, move on with the next Goblin“.

What it does have is the much-loved GOTO. Jumping forward to a label immediately before the NEXT means the counter still increments, the loop still knows what it’s doing. We just skipped code. It’s a CONTINUE built out of the only option available to us.

You must jump to inside the loop, not out of it. If you GOTO out of a FOR and never reach the NEXT, the loop’s entry sticks around on the stack forever, do that enough and you get ?OUT OF MEMORY ERROR. Not a fun error message to debug when your program isn’t using much memory.

Roll for Combat

Combat is initiated from two directions. The goblin starts a fight if it ends its move next to you:

IF ABS(GX(G)-PX)<=1 AND ABS(GY(G)-PY)<=1 THEN GOSUB COMBAT

ABS strips the sign off a number, so ABS(GX(G)-PX) is “how many columns apart are we“. Both distances being 1 or less describes the eight squares surrounding you plus the one you’re standing on, so this is a neat one-line way of asking “are we in melee range“, diagonals included, without eight separate IF statement comparisons.

Also, of course, you can start a fight by colliding with a Gobbo on purpose:

REM GOBLINS HURT HP
REM - COMBAT WILL ERASE THE GOBBO WHEN THE GOBBO DIES
IF CH=38 THEN G=0:GOSUB COMBAT : RETURN

Compare that against part seven’s version, which was a flat HP=HP-5 and nothing else. Now it’s an actual fight. The G=0 is a marker meaning “we got here by walking into something, not by iterating the goblin list“, which combat uses to know it doesn’t have a specific goblin index to work with (yet).

Now, the actual D&D tabletop version of this is a lot of arithmetic. There’s a reason Pathfinder was often jokingly referred to as Mathfinder.

Real D&D checks which stat applies to what you’re doing (strength for melee, dexterity for a bow, intelligence or wisdom depending on your flavour of magic), derives a modifier, rolls a D20, adds the modifier, compares against the target’s Armour Class, then rolls damage with its own dice and its own modifiers. I’m not doing all of that here. I want it working first, and we can always come back and layer more complexity if we want to:

COMBAT:
REM ROLL D20
R=RND(-TI)
D20=INT(RND(1)*20)+1
REM ADD MODIFIER FROM STRENGTH
MOD=INT((STATS(0)-10)/2)
D20=D20+MOD
REM CHECK IF HIT GOBBO AC AND DETERMINE DAMAGE
IF D20<=8 THEN MSG$="MISS!":GOSUB ALERT: HP=HP-5:GOSUB SHOWHUD:RETURN
DMG=INT(RND(1)*8)+1+MOD
MSG$="HIT GOBBO WITH "+STR$(DMG)+" DAMAGE!":GOSUB ALERT
GH(GC)=GH(GC)-DMG
IF GH(G)<=0 AND G>0 THEN MSG$="GOBBO DEAD!":GOSUB ERASEENEMY:GOSUB ALERT
RETURN

INT(RND(1)*20)+1 is the d20. RND(1) gives a fraction from 0 up to (but never quite reaching) 1, times 20 gives 0 to 19.999, INT chops the fraction off leaving a whole number 0 to 19, so the +1 shifts it to 1 to 20. That pattern, INT(RND(1)*sides)+1, is every dice roll you will ever need.

INT((STATS(0)-10)/2) is the D&D ability modifier formula, straight out of the rulebook. STATS(0) is strength, 10 is average, and every two points above average gets you +1 to hit. Strength 16 gives you +3, strength 10 gives you +0, strength 7 gives you… something interesting, because INT on the C64 rounds towards negative infinity rather than towards zero, so INT(-1.5) is -2, not -1. That happens to match the tabletop rules exactly, which is a nice accident. And yes, MOD is a legal variable name here, unlike in a lot of other BASICs, because Commodore BASIC has no MOD operator to clash with.

The 8 in IF D20<=8 is the goblin’s Armour Class, hard-coded. Beat it and your hit connects. Miss and you take 5 damage, which is not how tabletop works at all (a miss should just be a miss), but it keeps the pressure on until proper goblin attack rolls arrive. Change that 8 if you want an easier or a nastier dungeon, that one number is your only difficulty setting right now.

R=RND(-TI) at the top reseeds the generator from the system clock. TI is a jiffy counter that the C64 increments 60 times a second from the moment you switch it on, and passing RND a negative number reseeds it rather than asking for the next number in the sequence. Without a reseed somewhere you’d get the same sequence of rolls every single time you ran the game, which is a great way to test and a terrible way to play.

One small ugliness to warn you about: STR$(DMG) always puts a leading space in front of a positive number, because Commodore BASIC reserves that column for a minus sign. That’s why the message reads “HIT GOBBO WITH 3 DAMAGE!” with a double space. MID$(STR$(DMG),2) would chop it off if it bothers you at this stage.

The bug that ate my character set

Now for the weird bit. Adding those goblin arrays broke the game in a way that looked nothing like an array problem.

The screen started glitching, text came out mangled. My “USE QAOP KEYS” prompt rendered as USE Q O P K Y S and various characters went missing entirely or turned into garbage. Nothing was crashing as such, in that there were no errors reported, the game just gradually stopped being able to spell.

The clue is in what broke. Something was overwriting my character set.

How C64 BASIC uses memory

To understand this you need to know how BASIC lays itself out in RAM, and it’s quite simple once you’ve been over it once or twice. Your program sits at the bottom, starting at address 2049. Immediately above it BASIC puts your scalar variables (integer, float, etc). Above those go your arrays. Things grow upwards as your program gets bigger and you declare more variables or arrays.

Strings are the odd ones out. They start at the top of BASIC memory and grow downwards, towards everything else. The two piles drive towards each other, and BASIC’s job is to notice when they’re about to collide and give you ?OUT OF MEMORY ERROR instead.

C64 Dungeon Game Memory Map

C64 Dungeon Game Memory Map

The address where that top-of-memory line is drawn lives in two bytes of zero page, 55 and 56, low byte first. BASIC checks against it but, and here’s where I messed up, only BASIC respects it. The VIC-II video chip doesn’t give a hoot and will happily read character data out of memory that BASIC is actively pushing variables into.

Why my character set was parked in the way

The VIC-II can only see 16K of memory at a time, and by default that slot is the bottom 16K, addresses 0 to 16383. Your custom character set has to live inside that area or the video chip cannot see it, no matter how much free RAM you have elsewhere. So all that lovely empty space above 16384 is useless for a charset, and everything has to be squeezed in down at the bottom, where BASIC also lives. That’s the bug right there in one sentence.

A single C64 character set is 2K. 256 characters, 8 bytes each, one byte per pixel row. But the ROM ships two of them, for the uppercase/graphics set and the lowercase set, and they live next to each other as a 4K block. When I originally built my custom charset file contained both, all 4K of it, and I sat it at address 12288, running up to 16383.

Except I never use the lowercase set because this game never switches case. So half of that 4K was wasted, and it was parked directly in the path of my ever-growing arrays. Once the program and variables grew up from 2049 to hit 12288, it started writing goblin coordinates right over the top of the letter A.

The solution is to trim the charset to just the 2K I actually need, shove it to the very top of the VIC’s window, and then tell BASIC to keep away.

AddressPart 7 (4K charset)Part 8 (2K charset)2049 upBASIC program, variables, arraysBASIC program, variables, arrays12288character set starts (collision)still free for BASIC14336character set (lowercase, unused)character set starts, BASIC stops here16383end of VIC-II’s 16K windowend of VIC-II’s 16K window

Moving the charset from 12288 to 14336 gives 2048 bytes back to BASIC, which is enough to keep growing for a good while. That’s why this version loads CHARS8C.BIN instead of CHARS.BIN. Same character set, but half the file size, and parked safely out of the way.

Pointing the VIC at the new address

The video chip is told where to find its characters by register 53272, and the number in it changed from 12 to 14:

POKE 53272,(PEEK(53272)AND240)+14

That line is doing three separate things. Register 53272 is shared: the top four bits say where screen memory is, the bottom four say where character memory is. We only want to change half of it and leave the rest exactly as we found it.

PEEK(53272) reads what’s there now. AND 240 masks off the bottom four bits and keeps the top four (240 is 11110000 in binary), so we hold on to the screen memory setting we don’t want to touch.

+14 writes our new charset setting into the gap we just cleared. Read, mask, replace. Do this instead of poking a raw number whenever a register can do two jobs at once.

As for why 14 means 14336: three of those bottom four bits are a character memory pointer, and the bottom bit is unused. So the value is effectively doubled before it’s used, giving 14 divided by 2 = 7, times 2048 bytes = 14336. Handily the useful values just go up in twos, and each step is 2K:

ValueCharacter memory atNotes00unusable, zero page and stack live here44096881921212288where my 4K charset used to start1414336where the trimmed 2K charset lives now

Telling BASIC where to stop

Moving the charset is only half the battle. BASIC still thinks it owns the memory all the way up to 40959 and will cheerfully expand into 14336 the moment it needs to. So we have to move its cage down:

REM MEMORY LIMITATION MITIGATION:
IF PEEK(2)<>73 THEN POKE 55,0:POKE 56,56:POKE 2,73:CLR

One line, four pokes, and every single one of them needs explaining.

POKE 55,0 and POKE 56,56 set that top-of-memory pointer. The 6502 stores addresses low byte first, so this is 56 times 256, plus 0, which is 14336. Exactly where the character set now starts. From this point on, BASIC believes the machine ends there and will raise an ?OUT OF MEMORY ERROR rather than silently vandalising my font.

CLR is what makes it work. Changing the pointer on its own achieves nothing, because BASIC thinks it has already worked out where the strings need to live based on the old setting. CLR is needed to set all its internal bookkeeping to match the pointers as they now stand. The problem is CLR does exactly what it says on the tin, it wipes every variable, every array, every open file, and resets the stack. It’s a scorched earth reset, and is why this line has to run before anything else in the program.

POKE 2,73 and the loop that never ends

Which brings us to the strange part: POKE 2,73, and checking PEEK(2)<>73.

Our program runs from the start more than once. Loading the character set from disk in BASIC restarts the program (that’s what LOAD from within a program does on a C64), which is why part seven had the A=A+1 counter deciding whether this pass should load the charset or set it up:

IF PEEK(2)<>73 THEN POKE 55,0:POKE 56,56:POKE 2,73:CLR
IF A=0 THEN PRINT CHR$(147)"LOADING, PLEASE WAIT "
A=A+1
IF A = 1 THEN GOTO CHARS
IF A = 2 THEN GOTO SETCHARS
CHARS:
LOAD "CHARS8C.BIN",8,1
SETCHARS:
POKE 53272,(PEEK(53272)AND240)+14

That counter works because LOAD restarts the program but leaves variables intact. Which is what CLR destroys. So I can’t use a normal variable as my “have I already done the memory fix” flag, because the thing the flag guards is the thing that erases it. Run it once, CLR wipes A back to zero, program restarts, sees the pointer needs fixing again, CLR, wipe, restart, forever.

So the flag has to live somewhere CLR doesn’t reach and that’s what memory location 2 is. It’s a byte in zero page, the fastest and most fought-over 256 bytes on a 6502 machine. 2 is one of the tiny handful that neither BASIC nor the KERNAL uses for anything. It’s spare, and it survives CLR. The only thing that clears it is powering off.

Using 73 as the value is arbitrary. Any value would do, 73 is just the best number (after 42). It just needs to be something unlikely to be sitting there by chance as a trustworthy answer. First run, location 2 holds whatever junk was there, so the test passes, we fix the pointers, drop our marker, and CLR. Restart, and now PEEK(2) is 73, so we skip straight past. No loop.

It’s not bulletproof, there is a one in 256 chance address 2 happens to contain 73 on a cold boot, in which case the fix never runs and you’re back to eating away at the character set. I’ll take those odds.

This whole episode is a lesson that clearly demonstrates that on an 8-bit machine, memory is a shared resource that YOU are responsible. BASIC, the VIC-II, the KERNAL and your code all work on the same 64K, and nobody stops you from shooting your own foot off. It will just cheerfully start behaving strangely and let you figure out why.

What’s next

There’s a FIRE: subroutine in there that does nothing at all right now, which tells you where my head is, but here is a list for future parts:

  • Goblins that hurt – they need to actually hit back instead of only inflict -5 damage on a miss.
  • Fair enemy generation – At the moment a random map can roll zero goblins, or too many too soon.
  • Win and lose conditions – right now your health can currently go negative and nothing happens.
  • More than one type of enemy – Means I can show movement patterns other than “walk toward the player”.
  • Fog of war – Make it so you don’t get the whole dungeon map displayed on turn one.
  • Stairs and levels – Progress, so there’s somewhere to go.

The whole program is up in the IDE if you want to peek and poke at it: part8d.bas. Perhaps, change the goblin’s AC from 8 to something crueller, or give the goblins a rule that makes them smarter. If you do build something out of it, I’d love to see it!

The Daily Front Page 28 of 29
Sunday, July 19, 2026 The Daily Front No. 10 — Colophon

That's the Front for Today

Issue No. 10 — Sunday, July 19, 2026 — went to press 2026-07-20 at 07:51 UTC.

About This Magazine

The Daily Front is a daily digital magazine assembled from the stories that reached the front page of Hacker News on Sunday, July 19, 2026. Headlines, points, and comment counts are recorded as they stood at press time. All articles remain the property of their original authors — every piece links back to its source and its discussion thread.

How It Was Made

Fetched, cleaned, and typeset by an automated pipeline. An editor model laid out the pages, chose the highlights, and briefed the cover illustrator — 29 model calls and 263k tokens in total. Set in Jacquard 12, Playfair Display, Source Serif 4, and IBM Plex Mono, all served via Google Fonts under the SIL Open Font License.

The Cover

The cover illustration was commissioned with this prompt:

A single cinematic scene shot as award‑winning retro film photography: inside a dimly lit rural bowling alley transformed into a futuristic machine room. Polished wooden lanes glow subtly like circuit traces; bowling balls roll past exposed microcontrollers and neatly bundled wiring integrated into the lane gutters. Enormous translucent server towers loom beyond rain‑streaked windows. A lone engineer kneels beside an old pinsetter, soldering iron in hand, caught in a pool of light. Overhead, faint ghostly clouds of light and haze suggest competing artificial intelligences without forming any readable shapes.

Photographic look and craft: 1970s/1980s analog color film (Kodak Portra‑style tones), fine natural grain, slight halation on highlights, gentle lens bloom, shallow depth of field, cinematic 50mm perspective, high dynamic range with dramatic chiaroscuro lighting. Muted warm amber practicals balanced against cool blue ambient fill, with one restrained warm accent. Ultra‑real, richly detailed, documentary‑cinematic composition, portrait orientation.

Absolutely no text, letters, numbers, signage, watermarks, or logos anywhere in the scene.

Production Ledger

StageModelCallsTokens InTokens Out
extractgpt-5.5 28 161,926 77,147
layoutgpt-5.5 1 19,015 5,061

The Publisher

Published by Johnny.

Support the Press

If The Daily Front brightens your morning, consider supporting its publisher.

Credits & Contact

All content — articles, posts, comments, and the images within them — belongs to its original authors and is reproduced here to point readers back to the source. Full credit goes to those creators; every item links to its original and its Hacker News discussion.

If you are an author and would like your content removed from an issue, write to hi@johnnys.page and it will be taken down.

Feedback is always welcome at the same address: hi@johnnys.page.

Credit where credit is due.

Every page of this issue began as someone else's work — these are the original sources, linked in full.

  1. Show HN: I replaced a $120k bowling center system with $1,600 in ESP32s by section33 — news.ycombinator.com·HN discussion ↗
  2. Qwen 3.8 by nh43215rgb — twitter.com·HN discussion ↗
  3. Moonshot AI suspends new subscriptions due to Kimi K3 demand by serialx — twitter.com·HN discussion ↗
  4. OpenAI reduces Codex Model Context Size from 372k to 272k by AmazingTurtle — github.com·HN discussion ↗
  5. AI Mania Is Eviscerating Global Decision-Making by subset — ludic.mataroa.blog·HN discussion ↗
  6. AI advice made people less accurate but more confident – sudy by rbanffy — thenextweb.com·HN discussion ↗
  7. NYC may require landlords and realtors to disclose the use of AI in listings by gnabgib — petapixel.com·HN discussion ↗
  8. Claude Code uses Bun written in Rust now by tosh — simonwillison.net·HN discussion ↗
  9. Infinities, impossibilities, and the man in the white linen suit by iainharper — iain.so·HN discussion ↗
  10. Transcribe.cpp by sebjones — workshop.cjpais.com·HN discussion ↗
  11. Scrying the AMD GFX1250 LLVM Tea Leaves by mfiguiere — chipsandcheese.com·HN discussion ↗
  12. Minecraft: Java Edition now uses SDL3 by ObviouslyFlamer — minecraft.net·HN discussion ↗
  13. Blender 5.2 LTS by makizar — blender.org·HN discussion ↗
  14. What I learned selling 2,500 MIDI recorders: Hardware is not so hard by chipweinberger — chipweinberger.com·HN discussion ↗
  15. HMD Touch 4G by thisislife2 — hmd.com·HN discussion ↗
  16. The death and rebirth of my home server by steinuil — sgt.hootr.club·HN discussion ↗
  17. Better and Cheaper Than IPTV by xonery — github.com·HN discussion ↗
  18. I joined the IndieWeb, here's what I learned by andros — en.andros.dev·HN discussion ↗
  19. Dupes took over the world by gumby — vox.com·HN discussion ↗
  20. Mathematicians still don't know the fastest way to multiply numbers by beardyw — scientificamerican.com·HN discussion ↗
  21. Land Atlas – soil, farmability, and crop analysis for land listings by L3dge — land-atlas-production.up.railway.app·HN discussion ↗
  22. Making Software: How to make a font by Garbage — makingsoftware.com·HN discussion ↗
  23. Cagire: Live Coding in Forth by surprisetalk — cagire.raphaelforment.fr·HN discussion ↗
  24. UnifiedIR for Julia by vimarsh6739 — github.com·HN discussion ↗
  25. Bananas sprout in Rayleigh Garden UK after 15 years by teleforce — bbc.com·HN discussion ↗
  26. Classic Amiga titles, free to download by doener — amigafreeware.downer.tech·HN discussion ↗
  27. A Visual Catalog of Retro Macintosh Software by zdw — marciot.com·HN discussion ↗
  28. The Last MPEG-4 Visual Patent Has Expired by LorenDB — phoronix.com·HN discussion ↗
  29. A new Intel Itanium (IA-64) emulator that boots Windows by jandeboevrie — raymii.org·HN discussion ↗
  30. C64 Basic Dungeon Crawler: Goblin Attack (C64 Basic Part 8) by ibobev — retrogamecoders.com·HN discussion ↗

Browse all issues in the archive →