Latest Posts (20 found)

Journelly 1.5 released: faster all around

Journelly feels like tweeting, but for your eyes only. A different take on note-taking or journaling for iOS, powered by plain text (Markdown + Org). If you're an Emacs user, Journelly complements your Org journal file on the go. Check out journelly.com for details. Journelly v1.5's biggest gain is performance. It should bring you an overall snappier experience, especially on larger journals. This release also brings new search features. A user reported migrating about ten years of journaling from Day One into Journelly: over 3,600 entries and thousands of images, converted from a Day One JSON export into Journelly's plain text format. With that much content, typing and navigating became sluggish. Journelly v1.5 brings a nice round of performance work, so typing, saving, and navigating are now smoother for journals of all sizes. If you're considering a similar move, Journelly should now comfortably handle years of entries. When you have entries from today's date in previous years, a new button appears on screen. Tap it to see what you were up to on this very day, years ago. The little badge shows how many matching entries were found. Not your cup of tea? Hide the button via "Menu > View > On This Day." Search now understands dates via a new filter: Dates can be written in your own language too ( , ), and can be combined with regular search terms and hashtags ( ). Matching dates are highlighted in entry titles. Prefer a calendar view? Tap the calendar button in the search bar to pick a day to search for. Days with entries are marked with a dot, offering a handy way to see when you wrote. This release fills in some missing translations and improves the Simplified Chinese (简体中文) text. Since launch , Journelly has remained a single-payment app. No subscriptions . That said, sustainable development has been tough without regular downloads , which is why development has slowed down. Help Journelly grow: Hope you enjoy the v1.5 update. Thank you for using Journelly and supporting indie development 💛💙❤️ Save cooking recipes, movies, music, restaurants, coffee shops… Jot down your thoughts. Save your favorite quotes. Use it as a journal, memo book, or notes. Write your shopping lists. Document your travels. finds everything from 2024. finds November 2024. finds every November, any year. (or ) finds every November 3rd, any year. (or ) finds that very day. Leave a review on the App Store . Share Journelly with your friends. Write or blog about Journelly to help spread the word.

0 views

Locating the source of a mysterious beep with Claude

Our house has a box room, full of boxes that we still haven't unpacked from our last move. A couple of weeks ago something in that room started intermittently beeping . The beeps were far enough apart that standing in the room and trying to determine the source of the noise was frustrating, and I really didn't want to dig through every one of those boxes. So I had Claude Code build Beep Locator , a software system for triangulating the source of a mysterious beep using multiple devices scattered around the room. Here's what Beep Locator looks like after it has been running for a while: You run Python web server to show the primary UI, and then use the QR code or URL to connect as many devices as you can spare to act as listeners - I was using two iPads, a phone, a MacBook Pro and a Surface Ultra. The devices then play noises to each other to help estimate their locations. This didn't work particularly well, so I added a "Rough mode" where you can drag their icons around in the space to provide rough locations which are then adjusted based on those sounds. Once that's set up, the devices all listen for the beep! I added a clapping mode too so I could test it by clapping my hands in different locations around the room - displayed as diamonds on the map. This helped me gain confidence that it was capable of locating a sound. Beeps show up on the map as an X, plus a line in the "Sounds located" log. You can replay these sounds (from each device in turn) to confirm they are the mysterious beep you are looking for, then click "This is the mystery beep" to mark them as such. Once you've confirmed the mysterious beep frequency the system will listen out for it, measure the interval between beeps, and use the triangulated locations to lock down the most likely location on the map. The system worked as intended. It gave me the position of the beep to within about 40cm, then I dug through that specific pile of boxes and found an ancient carbon monoxide detector that desperately wanted its batteries replaced. When I started working through this problem with Claude it quickly dug up BeepBeep: A High-Accuracy Acoustic-Based System for Ranging and Localization Using COTS Devices , a 2007 paper by Chunyi Peng, Guobin Shen, Yongguang Zhang, Yanlin Li, and Kun Tan. Here's that paper's abstract: We present the design, implementation, and evaluation of BeepBeep, a high-accuracy acoustic-based ranging system. It operates in a spontaneous, ad-hoc, and device-to-device context without leveraging any pre-planned infrastructure. It is a pure software-based solution and uses only the most basic set of commodity hardware – a speaker, a microphone, and some form of device-to-device communication – so that it is readily applicable to many low-cost sensor platforms and to most commercial-off-the-shelf mobile devices like cell phones and PDAs. It achieves high accuracy through a combination of three techniques: two-way sensing, self-recording, and sample counting. That sounded exactly like what we needed to build! Beep Locator runs a Python web application server that does most of the work. The listening devices then connect to that server via WebSockets and present a UI which requests browser microphone access. The listeners mainly work by recording a 60 second buffer of recent audio. They also run a simple beep detection algorithm (see detector.js ), which uses Fast Fourier Transform and a high-pass filter to identify potential beeps. It sends these events to the main server. When a beep is reported, the server has a device play a short chirp (the device with the lowest round-trip time to the server), then asks every listener upload a clip from about 0.6s before the beep to 0.8s after that chirp. This chirp allows the clips to be aligned with each other, a crucial step in locating the beep. I started this project using Claude Code Cloud via my iPhone, with Opus 5.5 running in Extra thinking effort mode. Here's that shared starter session , which began with this prompt against a newly created empty GitHub repository: That got me this problem.md file . As part of writing that up Claude found and read the BeepBeep paper, which is described in that file. The research looked good, so I told it: That got me to this point - most of the system was built, but nothing had actually tried running it yet. I cloned the new repository to my laptop and fired up Claude Code... and then Fable 5.2 was released , and this project seemed like an excellent opportunity to put that through its paces. I had Claude Code on my laptop start the server running, then made sure it could both see what was happening and make live changes to the software as it ran. This was already baked into the software: Opus 5.5 had built an installModule() method on the listeners that could be triggered over the WebSocket connection, meaning the admin server could execute arbitrary new code on any of its clients. On some devices, web pages that listen on the microphone request user permission any time the page reloads. The hot-swap module mechanism meant that we could deploy new code without having to manually interact with each of the listening devices in turn. From that point on my involvement was mainly to sit by the laptop chatting with Fable 5.2 about what was going on, and occasionally requesting new features. Here are some of the feature prompts I ran: This gave me the ability to drag listeners around the map. That added the thing where any time I clapped it would show on the map as a different symbol from the beeps. That made it easier to spot which symbol likely reflected which real-world sound. Now I could replay sounds, making it much easier to identify which recorded clip was the mysterious beep I was looking for. At this point I was getting close - I had a solid idea of where the beep was coming from, but wouldn't it be neat if I could reposition the listeners around that point to get an even finer location? And since I had one spare device, I then said: I think the most interesting part of this project is that I demonstrated it's possible to give Claude Code ears . Claude doesn't have native audio input (yet), but it can run JavaScript and Python code that can analyze audio captured by a microphone. I told it to run a web server with WebSocket connections to multiple listening devices, then had it both run a WebAudio microphone on those devices and hook them up so they could be sent fresh JavaScript code to execute via that WebSocket. Then I could pretty much leave Claude alone, hacking away at the problem, querying the audio logs, and reconfiguring its ears to help it solve the problem. I'm reminded of a similar hack I heard about at GitHub Universe a few weeks ago, where Martin Woodward told me he had been debugging the GitHub Universe Badge computers by plugging them into a computer via USB-C and then pointing a webcam at their screen, so his coding agent could tell if updates were working correctly or not. Figuring out ways to let coding agents perceive the world around them is a whole lot of fun. You are only seeing the long-form articles from my blog. Subscribe to /atom/everything/ to get all of my posts, or take a look at my other subscription options .

0 views

What if every Nix build were bit-reproducible?

The holy grail of build systems and package managers is bit-reproducible 1 builds. This is such a desired trait that nearly every Linux distribution has a reproducible builds project to track the progress and validity of their builds. Why is bit-reproducibility so important? Trust. You can trust that the software you are running has not been tampered with and is the same as what the developers intended if you can verify that when built from source, the output is identical. Making software bit-reproducible though is hard. There are a lot of ways that can introduce non-determinism into a build: timestamps, random seeds, thread scheduling, and more. Most distributions that have achieved “reproducible builds” have done so for only a subset of their packages, usually those that comprise the core of the ISO or distribution. Nix’s default model, the extensional model (input-addressed), famously works around the need for bit-reproducibility by hashing the inputs to a build and using that hash as the store path. This lets the build be repeatable even if the output is not bit-for-bit identical. It is an incredibly pragmatic solution to making builds repeatable, but it does not solve the problem of trust. We are still trusting the outputs uploaded to cache.nixos.org have not been tampered with. Nix also has an experimental content-addressed model (intensional model) where the paths are based on the content of the output, but crucially, it does not guarantee that the builds are bit-reproducible. This leaves us with an undesirable situation regardless of the model. For the extensional model, the smallest change in the inputs changes the store path which causes a cascade of rebuilds. For the intensional model, a single derivation can produce multiple different outputs. What if every build could be bit-reproducible? What would that mean for Nix and the extensional model? I have been working on Rewind , a deterministic virtual machine. It runs builds in a deterministic environment, which so far has mostly been used to investigate bugs. I have been thinking about what else a platform that runs builds deterministically makes possible. I started this thought by exploring how to make profile-guided optimization reproducible but I was just scratching the surface. When we try to make a build bit-reproducible, we usually go hunting for the sources of non-determinism: timestamps, random seeds, thread order. These are inputs the derivation does not account for, so they are not hashed into the store path. A simpler approach is to run the whole build inside a deterministic machine. Eelco’s thesis says outright that the extensional model assumes the builder is impure (§5.7). Build operations in general are not pure: the contents that a builder stores in the output path can depend on impure factors such as the system time. […] Thus, while any derivation can have a potentially infinite set of output path contents that can be produced by an execution of its builder, we view the elements of that set as interchangeable. But this is a model—an assumption about builders. Running a build within Rewind captures all of the implicit inputs to a build and makes them explicit, which makes any build bit-reproducible. 🤯 Aside: New to Rewind? Start with a flaky build you only catch once and dafuq is a deterministic VM? We can wrap any derivation in Rewind with a Nix function. takes the machine’s inputs and a derivation, and returns the same derivation with its builder running inside Rewind: 2 It works on any derivation and the resulting derivation is bit-reproducible every time. 3 Let’s look at a simple example of a build that is not bit-reproducible, and how when wrapped in Rewind, it becomes bit-reproducible. Here is a simple C program that prints a greeting and depends on a library. The derivation adds a build id and a build time to the output similar to what release builds often do to “stamp” their builds. The build id and build time are two common sources of non-determinism in builds. We have wrapped the derivation in a function to control whether the build runs in Rewind or not, and whether the build is content-addressed or not. Built on the host under the input-addressed model, fails : Built in Rewind, the same derivation passes: The UUID still comes from the kernel’s random pool and the time still comes from the clock. They are the same on every build because the pool’s seed and the clock’s start are initialized from the same values. Nice! We just got a build that is bit-reproducible even if it’s not content-addressed. You can find more details of the library and even making Rewind a Nix on Rewind’s Nix build reference . What does that mean for the content-addressed model? Since the outputs are not bit-reproducible, the same derivation gets a different path on each rebuild. 4 Producing multiple variants is problematic and the thesis notes the consequence (§6.4.1): you can end up with a closure that contains more than one variant of the same derivation. The fact that a derivation can resolve to any number of output paths due to impurity, leads to the problem that we might end up with a closure that contains more than one element from the output equivalence class of a derivation. With , both stores build the same bytes and print the same path: 5 One derivation, one path, in every store. Bit-reproducible outputs also mean cache hits across machines. If the bytes are the same, the content address is the same, and a path one machine built is a hit for every other: early cutoff optimization ftw! When we make every build bit-reproducible, the two models collapse into one. What does this mean for the extensional model? The extensional model was a wonderful pragmatic solution to a world where determinism was not guaranteed but it came at a cost: a single change in the inputs cascades through every downstream derivation. Adoption to content-addressed derivations has been slow similarly because producing multiple outputs makes it hard to reason about the closure of a derivation. When we have guaranteed bit-reproducibility, both problems disappear. Having a stable platform with which to build software reproducibly might completely change the toil of working to make software reproducible and change the economics of whether to leverage content-addressed derivations. The usefulness of a reproducible environment is not well explored and I think there are other interesting use cases for it. One that I’m exploring is to use it to make the act of performing a benchmark reproducible. Aside The cost is that the machine is now an input, Rewind included. Upgrade Rewind and every wrapped derivation rebuilds. Build on an Intel machine and you get a different, equally reproducible, output than on AMD. A tool that was designed for bug investigation and reproducibility of builds might have a larger impact on the software ecosystem than I had originally thought. It is a tool that can be used to make software more trustworthy, and all the wonderful beefits that come with it. It’s lame that I have to keep clarifying it as “bit” reproducible but the term is overloaded.  ↩ Rewind is a KVM-based virtual machine, so it requires a host with KVM support. It also requires the or system feature to be advertised by the host.  ↩ On the same Rewind version and the same CPU vendor. Fixed-output derivations are refused, because they need the network and the VM has none.  ↩ Two stores are used to illustrate buids on different machines.  ↩ Nix 2.35 changed how it hashes an output that mentions its own path, so the content address of such an output depends on the Nix version.  ↩ It’s lame that I have to keep clarifying it as “bit” reproducible but the term is overloaded.  ↩ Rewind is a KVM-based virtual machine, so it requires a host with KVM support. It also requires the or system feature to be advertised by the host.  ↩ On the same Rewind version and the same CPU vendor. Fixed-output derivations are refused, because they need the network and the VM has none.  ↩ Two stores are used to illustrate buids on different machines.  ↩ Nix 2.35 changed how it hashes an output that mentions its own path, so the content address of such an output depends on the Nix version.  ↩

0 views
Unsung Yesterday

Mailbag: Halloween 2026

I’m curious what you thought about the Halloween spell on Unsung ! In case you enjoyed it, here are some follow ups I collected since publishing: A few people online suggested the distinctive and creepy “I can do it” Monopoly Deluxe sample is from a cartoon Ren & Stimpy, which premiered not long before the game. I found an example that’s very close, but not quite exactly like the one from the game. (It’s not creepy in the video!) = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/mailbag-halloween-2026/1.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/mailbag-halloween-2026/1.1600w.avif" type="image/avif"> Nik Clayton added some color to the YouTube red and blue squares mystery , and specifically of the name of the YouTube channel – “Webdriver Torso”: This was a test not just of the video encoding pipeline, but of the entire end-user experience. So rather than using an API to upload the videos directly, a web browser was controlled, aka driven by a script to navigate through the YouTube UI and upload the random videos. This was done without showing any of the browser UI on the screen so it could be completely automated, often referred to as running the browser in headless mode, or if you prefer, just the torso . Hence “Webdriver Torso” as the account name. Obvious if you know the lingo, completely baffling if you don’t. Daniel Vincent wrote to me to explain the bug that caused the texts to my date to go completely missing : I work in the messaging business and I can tell you exactly why your use of typographer’s quotes caused mayhem in SMS. Back when the iPhone came out most carriers only supported the GSM-7 character set . Originally SMS only supported ASCII, which gave you the 140 byte limit. By using a 7-bit GSM-7 encoding they could cram 20 more characters into a message and also support certain extended characters (accents, etc. for languages that needed them). Needless to say, typographer’s quotes fall outside these character sets. When the messages were sent, the Unicode data would either get corrupt or the carrier (inbound or outbound) would mangle the message in other ways. This situation was different in other parts of the world – e.g. Asian countries – which adopted different character sets. (There was also the Latin-1 character set , but it did not fully cover Unicode and characters like typographer’s quotes were outside of it as well!) Other consequences of using characters outside the set may break the byte counting used for message concatenation […] resulting in only the first segment being delivered or no delivery at all. When Unicode support came to SMS in Western countries they supported it using UCS-2, which translates Unicode into a byte format which can be carried over SMS. This was about the time when Western countries started seeing emojis and such in their text composers. UCS-2 also has the downside of cutting segment length in half (to 70 characters) because it’s a double-byte encoding. This could increase your SMS bill back when people were charging per-SMS. It’s an interesting design challenge that might not be solvable. There was no way for my phone to ask the carrier whether the quotes were supported, or whether the message was received. You could imagine some sort of a situational warning that my special character use might cause the message to not appear, but design of warnings is hard thing and the message would have to be vague. What if this scared me for life, fearful of using other characters, or future emoji, or texting in general? Lastly, I could imagine the curly quotes to be replaced by straight ones quietly in this context, but… that ruins typography for everyone, and it’s entirely possible there I was one of the very few people on Earth facing this particular problem. A conversation with Nikita Prokopov made me piece together some of the iPhone jump scare bug conditions. The reason the touch screen might still respond to touches after clicking on the lock button is that the lock button still waits a bit to detect whether you tapped it twice for Apple Pay, or thrice for an accessibility shortcut. (If you disable both of these features, the problem disappears!) You might ask: why is the touch screen active if the phone is only waiting for the button press? Likely because… it’s cheaper. = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/mailbag-halloween-2026/2.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/mailbag-halloween-2026/2.1600w.avif" type="image/avif"> I don’t mean it disparagingly. Code needs to be as simple as possible. Disabling the touch screen would mean having to re-enable not just upon waking the phone the next time, but also it at the second button click, too – and that could be a source of new bugs. But Prokopov cast a shadow at “never caused any problems”: Same, but right pocket and I was getting letters a and z inserted into text fields that I will discover later after unlock. Drove me crazy. It seems that Apple doesn’t realize that their decision might be causing all sort of phantom touches for people. (I filed the bug inside Apple’s systems as FB25320712.) Vis-à-vis the Pac-Man sound bug , someone unearthed a bug report thread where people complain about it as it’s happening. At least this group of people identified it as coming from Pac-Man relatively quickly, but it’s still hard for me to read all these, even 16 years after: Disabling CoolPreviews did the trick. You guys are right... definitely a screw up somewhere along the line. I was getting sick to my stomach hearing that sound. Thank you for the information. Lastly, I got an email from Russ Segal, the creator of N.Y.C. The Big Apple videogame – and its bug that scared me so much as a kid : I had no idea that bug was there. I can tell you exactly what is happening. The old Atari computer did not have enough memory to keep the picture of the whole city at once, so the program just had a basic map of the whole city, not a whole picture. As you drive horizontally, the program only creates a vertical “slice” of the picture of the city – centered on where you are. And just before you drive off the end of the picture, it paints the next slice in front of you. When you went backward on the bridge you fell off the left side of the available picture, and the program painted more city for you. But because you are technically “off the map”, the city map is being read incorrectly – with some sort of misalignment. Not only will this make the buildings and blocks look weird, the painted city streets do not line up with where the cars think they should drive. So the cars will crash into stuff that is not supposed to be there. It was fun to see that message in my mailbox, and fun to see echoes of computing history: the way NYC The Big Apple did it is not exactly the same as streaming in Grand Theft Auto, but it’s a similar category of creating reality on demand just ahead of where the user is looking – and you can now imagine all sorts of similar GTA bugs that happened internally at Rockstar as the game was being made.

0 views
David Bushell Yesterday

I was wrong about dark mode

Apple invented dark mode again! They’re calling the new feature Adaptive Dark Mode ™ . I’m learning that other browsers already had a similar feature . I assumed people relied on add-ons like Dark Reader (and millions do). Regardless, pushing what is effectively an accessibility option to the forefront goes a long way to help people respect it. My site used to have dark mode but I wasn’t happy with my colour choice and implementation. I redesigned my site back in Feb and removed it. Later I experimented with colour themes which I’ve since adapted for alternate blog banners . In that experiment I said: Personally I prefer reading with a dark theme for long-form content. Dark is not my brand though and I don’t believe every website needs to support colour scheme preference automatically. A good browser has reader mode, I use that all the time. “Just enabled reader mode!” What a load of rubbish. You have to understand that sometimes I just write stuff and I don’t read it back. This also contradicted my previous statement: That said, in [current year] brands with a digital presence — all of them? — should have a colour scheme for both. That’s probably more true. Certainly websites must work for forced dark mode. (Any site forcing itself upon users should go straight to jail.) So either provide a dark mode, or be prepared to test against every adaptive and forced dark mode implementation, or just let your website look broken. Probably easier to design a dark mode then? So that’s what I did, again. Maybe you noticed? If not, there’s a toggle button up top. At the risk of weighing in on the conversation I’ve opted for a two-state single button. I default to system preference. The mystery button flips between light and dark. Want to return to system default? Tough luck! You shouldn’t have clicked it. Delete local storage nerd! Technically I’m using a registered custom property with container style queries because it looks like fancy modern CSS. Three at-rules! Most of my light/dark theming is done by customs properties. The default light colours (A) are set on the root element. A style query applies the dark colours (B) on the element. For edge cases that don’t follow the A/B rule I can use one of two techniques. Either a style query inside a specific component: Or use the function: Note that I set to make aware of the user’s choice that might override their system preference. I wonder if I can do this once: Is that safe? Let me know! It’s not safe to do on the root element because browsers checks that for adaptive dark mode etc. I’ll stick to the verbose style queries for now until I’m sure. There’s a sprinkle of JavaScript to use local storage for the toggle button. It’d be better to use a cookie and a server-side template. My website is hosted on a static CDN and I’m not adding edge worker latency, so I’ll risk Flash of inAccurate coloR Theme (FART) . My site only risks a FART if a user’s choice doesn’t match their system preference. A week into my Noscript November experiment I see most websites are prone to a big FART because they rely entirely on JavaScript to enable dark mode. I’m not happy with my button using a hidden label. Bit of a design failure I need to address later. My original goal was to have multiple themes but I ran out of time. At the risk of soliciting replies to a question I didn’t ask, I would like your feedback on my choice of dark mode colours! Do they look nice? I don’t care whether dark mode makes your eyes bleed (turn it off) or you absolutely must have a 4-dimensional toggle. Stephanie Eckles wrote about the same CSS technique I use. Dave Rupert has explored the with variations. I saw Una Kravets is using with style queries to do something extra fancy. Stu Robson has written in depth on dynamic colour schemes too. If you read this entire post in an RSS reader and never clicked through, what a power move! Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views

When There Are Wolves Again

Lucy was a child during the 2020 pandemic, living with her grandmother and watching the chimney swifts swoop into their tiny homes. Hester was born on the day of the Chernobyl explosion; years later, she visits the site to film the feral dogs surviving in the exclusion zone, and the doctors working to care for them. She will smuggle a pup back home with her, finding that keeping herself alive means keeping well this tiny charge. Through horrific heat waves and uprisings, both women live through the wreckage of systems and bodies that climate change brings. Until one day they find each other, and find that where there are wolves, there is hope for another day. View this post on the web , reply via email , or become a supporter .

0 views
Brain Baking Yesterday

On Receiving Letters

In my beginners guide to writing snail mail , I hand out a few tips for getting started with letter writing as a lovely way of conversing with friends and strangers. I’ve sent 21 letters since then, but the fun doesn’t stop there: receiving a reply is just as exciting. Many people dismiss letter writing as a thing of the past—an activity one engaged in when one still had the time to sit down and write. The more society sped up, the less letters are being written: just send a quick email instead. Or wait, no need to even open up your emailclient: just send a quick instant message using your favourite messaging platform instead. But as we turn towards digitised tools to communicate, we also implicitly accept the standardisation that comes with it: the symbols being translated into ones and zeroes can be styled using your client’s font preferences, and sometimes we receive attaches, but that’s about it. When you send or receive a letter, you send or receive a filled canvas . That work of art is the result of a burst of creativitiy, not the outcome of keystrokes on a keyboard. In other words, you are exchanging artworks . A few examples might help here: One of the envelopes I received turned out to be a recycled map from Direkt Recycling. Once you open these, a portion of a map reveals itself, but there are also envelopes you can buy with these on the exterior, such as the following design available through shops such as Polly Paper . DRP DL Landkarte 10 Design-Kuverts Direktrecycling. Finding such an envelope in your mailbox is much more exciting than hearing the new mail jingle coming from your computer. The excitement doesn’t stop there. Receiving letters also provides the opportunity to admire the postage stamp and postmarks created by the sorting offices to encode the address and postage date. As mentioned in my previous article, here in Belgium you can design your own postage stamp—or of course buy one of the themed sets to decorate the top right corner of the envelope. None of these things are hard requirements for letter writing: a generic stamp of our favourite monarch will do. Yet it makes receiving a letter all the more fun. I keep a dedicated postage stamp page in my current notebook to collect the neat ones I received. Once that one is full, I’ll make a note of the page number where a new stamp page has been made to create a linked list enabling quick hops between those special pages. Of course, exchanging multiple letters with the same person yields predicable stamps. It’ll take 16 more before my Super Mario Land 2 ones are out. Left: notes on a biography of Blaise Pascal. Right: a dedicated postage stamp page. It’s always a treat to receive a letter, but it’s not just the letter itself that’s the treat! Some of those sorting office postmarks come with little decorations that I try to preserve as well, such as the post horn left of the German Start Trek stamp and the Freedom 250 circle of stars one on the round USA one. I’ve been told that in the inner philately circles these are called “cancelling marks” as they prevent you from reusing a stamp on the next envelope. Today I also learned that there’s an entire club dedicated to not collecting stamps but these postmarks (USA’s Post Mark Collector’s Club or the PMCC) and a museum preserving early marks . I’m very much a newbie when it comes to these things so I have no idea whether a PMCC-esque network exists in the EU. Please help me become a true philatelist! One of my pen pals writes on an old school Olivetti typewriter. When my wife dug up her late father’s carefully preserved typewriter, it turned out that it was the same model! The ink ribbon might need replacement but I’ll save that for another post. Typing with ten fingers on that thing is next to impossible. After a few attempts to compile a letter with the typewriter I reverted to one of the trusty fountain pens. Too much backspace misery. If you want to learn more about envelope sizes I recommend reading the story of Terry Smith the Envelope Cutter over at Spitalfields Life: Envelopes, especially of the brown manila variety, are mostly mundane objects that people prefer not to think about too much. But, at Baddeley Brothers, they make the envelopes of luxury and the envelopes of pleasure, envelopes with gilt crests embossed upon the flap, envelopes with enticing windows to peer through and envelopes lined with deep-coloured tissue – envelopes to lose yourself in. This is envelope-making as an art form, and Terry Smith is the supreme master of it. We need more lovely articles like that. I stumble upon these posts using Marginalia Search by the way, not using Google et al.Happy letter sending & receiving! If you’re still looking for a pen pal, be sure to drop me a (digital and then later hopefully analogue) note. Related topics: / letter writing / By Wouter Groeneveld on 9 November 2026.  Reply via email . Handwriting, pen, and ink/colour combinations always result in a unique letter. You can add stamps, paste stickers, mini-printed photos , washi tape pieces, … on there. You can write in any angle, add postscripts, use a marker to highlight words or sentences, … You can send along photocopied pages of books you’re discussing. You can cut out things and use that to decorate the letter, or use it as a basis of the letter. You can send along tea bags that fit in an envelope for the receiver to enjoy. Can you do that using email? Didn’t think so. You can decorate the envelope itself. You can create the envelope yourself using original recycled material.

0 views
Stratechery Yesterday

Jensen Huang’s Affair, The Culper Report, Huang’s Righteousness

Nvidia CEO Jensen Huang admitted to an affair with a Chinese spy, and that might not be the end of his troubles. I hope he survives, but his influence will never be the same.

0 views
Kev Quirk Yesterday

2026-11-09 09:50: Just another day in Casa Quirk. 🤣

Just another day in Casa Quirk. 🤣 Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️ You can reply to this post by email , or leave a comment .

0 views

Hide your slop PR descriptions behind <details><summary>

Most of the changes I make to my projects these days come in the form of PRs opened for me by Claude Code or Codex. The PR is my unit of work - I use them to bundle commits together, iterating on them until a feature is complete, document decisions and then merge the finished result. Today's coding agents are great at writing PR descriptions. The problem is that they are too good. An agent-written PR description is accurate and comprehensive. It describes the problem, the detailed solution, and the steps taken to verify it. That's a lot of information to absorb. It's not necessarily slop, but it reads like slop! It's very easy to spot an AI-written PR, and as with other forms of AI writing my instant reaction is best summarized as "I'm not reading all of that". It doesn't matter how accurate or useful the information is, I'm instantly put off by the thought that it will take me longer to read than it took the driving author to write... even when that driving author is me! I want human editorial judgement. I want someone to have thought just long enough about the PR to give me a human-approved introduction that helps me understand, at a high level, what the PR is for and whether it deserves more of my attention. I think I've found a low-effort way to do this that feels right. The HTML elements render as a collapsed heading (the summary) that can be expanded to view the larger piece of text. The code looks like this: When rendered, it looks like this : Crucially, is supported in GitHub Markdown . You can drop those tags directly into an issue comment or PR description and GitHub will hide the details and display just the summary plus an expansion arrow. I've started using this for my AI-generated pull requests. The opening paragraph of my PRs will be carefully selected to act as a high-level explanation of what's going on - the shortest text a human can read that will help get them up to speed. I'll sometimes throw in a screenshot as well, since images are often the best way to quickly illustrate a new feature. The full agent-written essay then follows in a . I use the model name and often the effort level as that summary, to make it abundantly clear what is going on - "Claude Opus 5.5 Medium" for example. My PRs don't feel nearly as sloppy now! The information is all still there, but a reader can glance at it and get the top, human-curated information without their eyes glazing over at multiple paragraphs of agent-written details. I don't always write the introduction myself - sometimes the agent has given me what I need already, hidden away in the avalanche of other text. My promise to the reader is that the short opener will represent my human judgement as to what is definitely worth their time. Here are some recent examples where I've used this pattern, including the opener I used: I used to have trouble remembering the order of the tags - is it or ? Here are two tricks that helped me. First, and most obviously, the is clearly the bit where you summarize the details. That's the tag for your line of text that can be clicked to expand - the element must then wrap everything else. An even better trick is to always refer to these two tags as "details-summary". "details-summary" is two syllables followed by three syllables. That rolls off the tongue more smoothly than the three-two punch of "summary-details". Say "details-summary" out loud just a few times and you'll never forget the order of the tags again. (I still wish GitHub would add a button to their Markdown editor for this - partly to save me painstakingly typing it on my mobile keyboard, and partly to help spread the word to more GitHub users that this feature exists.) You are only seeing the long-form articles from my blog. Subscribe to /atom/everything/ to get all of my posts, or take a look at my other subscription options . datasette PR #3052: Redesign row page as a vertical list of fields - "The row page showed its single row as a one-row table. For wide tables, like a 46-column GitHub table, that scrolled far off to the right and left most of the page blank." (then a screenshot) datasette PR #3043: Pagination bar showing which rows are on the current page - "Table pages that span more than one page now make it obvious where you are, and offer navigation at the top of the page as well as the bottom." (plus screenshot) datasette PR #3042: Load edit-tools.js on demand via a small loader - " (~220KB) was loaded on every table, row and database page, even for users who couldn't edit anything. Now only load it for users who can edit when they first interact with an edit feature (including mouse over an edit link)." datasette-agent PR #51: register_agent_reference_types plugin hook - "Lets plugins add their own kinds of item to the tagging in the chat composer using a new plugin hook." - pictured above. llm PR #1838: Add llm openai endpoint add/list/remove/path commands - "Adds commands for managing the records in , so OpenAI-compatible endpoints can be saved from the command line instead of by hand-editing YAML." - then copied output.

0 views

The race to secure record-like information for domains

It’s sort of surprising, but we’re still figuring out how to secure simple, record-like information for domain names in an application-accessible way. Think about it. How would you bind the following to a domain name? Importantly, how would you secure it? Since we’re talking about domain names, lets start with DNS. The classic solution adds configuration as TXT records: Notice that we use an underscored subdomain label to make it clear we aren’t talking about a hostname. The protocol name is then repeated to make it abundantly clear this record is related to the protocol. As is, we can’t claim this solution is secure. DNS-based network interference is trivial and widespread. The best practice for securing DNS records is DNSSEC, which uses cryptographic signing. I’m not going to debate the security properties of DNSSEC in this post. There are strong opinions on both sides and the most helpful answer likely depends on the context in which you work. For the sake of this blog post I’ll wave my hands and call this “secure enough” to side-step the issue. In any case, the rest of the post doesn’t depend on a favorable or unfavorable assessment of the security properties of DNSSEC. Even the strongest supporters of DNSSEC need to face the reality that DNSSEC isn’t widely adopted. There’s no single answer that quantifies DNSSEC adoption. At Fox Loop Software I collect adoption metrics for various Internet protocols; we just released the first dashboard . Our approach highlights that adoption rates vary widely depending on which cohort you measure. For example, here are the adoption rates of DNSSEC signed MX records among second-level domain names that accept email: From the perspective of an application developer, it is not reasonable to expect that a customer domain name will support DNSSEC. Until this changes, application developers must use alternate solutions if they need security. If my application is web-based then there’s a pretty obvious solution as I already have an HTTPS secured endpoint. I can use the HTTPS .well-known approach ( RFC 8615 ). These records are secured by HTTPS. The developer experience is excellent: adding a record could be as easy as dropping a file in a web server directory. Fetching records is a simple HTTP GET request. But not everything is a web-based application. Can we extend this solution to other protocols? Email is a very old protocol, predating not only TLS but the entire Internet as well. Over time all sorts of additions have been bolted on to modernize and maintain the protocol. Many of these additions added new DNS TXT records, such as SPF, DKIM, and DMARC. These records can be secured by DNSSEC but do not require it, so tampering of these records is unmitigated or otherwise tolerated. Let’s look past these examples to a problem that clearly requires a secure record. Email has an awkward problem, which is how hostnames are managed. When a message transfer agent (MTA) relays an email it needs to discover the destination MTA. This is solved using an MX record, which specifies the target MTA’s domain name. I’ve measured that around 80% of domains host their email on a different domain name, often using providers like Google or Microsoft. When sending an email, the MTA will discover a chain from the user’s email address to the receiving MTA’s TLS certificate, like this: The sending MTA now needs to decide if it trusts the connection. Unfortunately, smtp.provider.com, as seen in the TLS certificate, does not match example.com, as provided in the email address. The only link between the two domain names is an MX record, which typically unsigned and therefor insecure. Without trustworthy information, certificate validation cannot succeed and the sending MTA must skip validation. Lack of certificate validation means that receiving MTAs can use a self-signed, expired, or even a certificate with the wrong name; the sending MTA does not care. This approach is known as “opportunistic encryption” and it provides strong protection against passive eavesdropping. But without a way to validate the receiving MTA’s TLS certificate, active attacks remained unmitigated. Email cannot enforce authenticated MTA-to-MTA transit encryption until this hostname mis-match problem is solved in a secure way. Many email security conversations focus on end-to-end encryption. It is a great solution to many of the security problems facing email, but it doesn’t fully address the problem being discussed here. Message relaying requires the MTA to know the recipient’s email address. This is known as “envelope information” and it cannot be end-to-end encrypted. Methods like PGP encryption can not and do not protect this information, as they only encrypt the message body. The only way to protect this information from network-level attackers is to ensure the message is delivered to the correct MTA, which requires authenticated transit encryption. When I first encountered this issue I was surprised as there is no analogous problem on the web. The issue relates to the semantic difference between a CNAME and an MX record. A CNAME record pointing at a web hosting provider’s server is a matter of identity and that server can get a TLS certificate to prove it. An MX record does not permit the target email server to get a corresponding TLS certificate. A web browser is able to compare the name in the TLS certificate with the name shown in the address bar and can expect these to strictly match. An MTA doesn’t compare the name in the TLS certificate with the domain name in the “to” address as a mismatch is typically expected. Further, email is sent asynchronously so there are no humans involved in MTA-to-MTA communications. While web browsers can show a certificate warning message to allow users to make their own security decisions, an MTA is all on its own. Email providers often tout support for transit encryption but the lack of certificate validation makes email traveling between MTAs about as secure as a user browsing the web while always clicking through invalid certificate warnings. Interestingly, email has adopted two solutions to this problem: a DNSSEC-based approach and an HTTPS .well-known approach. This give us a unique opportunity to compare these approaches head-to-head as they attempt to solve the same problem. The DNSSEC approach is SMTP DNS-based Authentication of Named Entities (DANE) ( RFC 7672 ), which was standardized in 2015. DANE requires DNSSEC signing in both the customer and email provider’s DNS zones for the protection to have full effect. DANE adds the TLSA DNS record. Here’s an example: This record indicates that the MTA-to-MTA connection can use authenticated encryption. Specifically, this record indicates that the receiving MTA should provide a TLS certificate with a public key digest of “6111A…”. Validating this pinned certificate does not depend on the certificate authority (CA) system. SMTP DANE signals that it should be possible to cryptographically validate the chain from the domain name in the email address to the domain name on the receiving MTA’s TLS certificate. One key benefit of DNSSEC, which we’ll revisit, is that blocking of a signed record can be distinguished from a non-existent policy. When the TLSA record does not exist, the authoritative DNS server should provide a signed proof of non-existence (NSEC). This acts as a fail safe: if DNSSEC is enabled and the sender cannot determine the DANE policy, then the sender can conclude that it is not safe to send the message as network interference may be present. Email providers realized that slow adoption of DNSSEC was delaying authenticated transit encryption between MTAs. They looked at what other tools were available and found inspiration from the HTTPS .well-known approach. Standardized in 2018, SMTP MTA Strict Transport Security (MTA-STS) ( RFC 8461 ) provides an HTTPS-based solution. Here’s what it looks like: Notice that the mta-sts subdomain is used instead of the bare domain. This best practice stems from the need to isolate security policies from whatever website lives at the bare domain; often a marketing website which may not have a security posture suitable for cross-protocol policies like MTA-STS. To distinguish any pre-existing use of the mta-sts subdomain the “_mta-sts” TXT record must also be set. Finally, policy caching was added as a partial mitigation of intermittent network interference. Like DANE, MTA-STS signals that the sender should strictly authenticate TLS. The MX record is duplicated in the MTA-STS policy, relying on HTTPS to secure the link. MTA-STS requires the receiving MTA to have a TLS certificate issued by a well-trusted CA. An MTA-STS policy document is fairly unchanging, making it well-suited for inexpensive, widely available, and highly scalable static web hosting. Many domain owners implement MTA-STS by adding the subdomain to an existing web server, as a virtual host, although it turns out this isn’t always a good idea. The TLS certificate renewal process is an obvious point of failure for MTA-STS. When a user-facing website goes down users complain, support tickets are filed, and the certificates are quickly renewed. The MTA-STS policy server fails open when it’s certificate expires. Senders will fall back to using opportunistic encryption and users won’t notice any disruption. As such an expired TLS certificate on an MTA-STS policy server can go unnoticed. To address this lack of visibility, TLS Reporting ( RFC 8460 ) was created, which allows email servers to share deliverability reports with each other. Another problem, which I think is an even larger issue, are web servers that block email servers from accessing their MTA-STS policy. You’ve probably noticed a sharp rise in bots, scrapers, and other unwanted automated traffic impacting the web. In the rush to protect web servers from these ills many sites inadvertently blocked access to their MTA-STS policy. An email server fetching an MTA-STS policy can look a lot like unwanted traffic: it’s automated and its coming from data center IP ranges. Misapplying security policies intended to protect user-facing websites from unwanted bot traffic degrades API-like interfaces. One unique benefit of SMTP DANE is that the policy cannot be blocked without the sender noticing. An MTA-STS policy server can be blocked just like any other web server and this blocking cannot easily be distinguish from a non-existent policy. While MTA-STS caching can protect against intermittent network-level blocking of the policy server, the first email sent to a domain is always vulnerable due to an empty cache. The effectiveness of MTA-STS in preventing an on-path attacker from intercepting email is questionable if the same on-path attacker can block the sender from discovering the MTA-STS policy. By these measures, DANE seems like the stronger option. DANE’s reliance on DNSSEC signing is its major weakness. Measurements show that 0.9-1.2% of domain names that receive email have DANE support, which doesn’t provide much practical protection yet. Worse, large providers like gmail.com lack DNSSEC support, so the per-user impact may be larger. Unless DNSSEC adoption can grow among large email providers, DANE can only be a partial solution. In contrast, HTTPS is very widely adopted making MTA-STS familiar to practitioners, even with these challenges. The web has blazed a path that MTA-STS can likely follow. HTTP Strict Transport Security (HSTS) ( RFC 6769 ) is essentially MTA-STS for the web (or visa-versa). HSTS is similarly vulnerable when the cache is empty. Web browsers mitigate this issue using a preload list, which ships in the browser. Out-of-the-box, the web browser knows that popular websites, like wikipedia.com, strictly use HTTPS. While there are challenges with HSTS, like the size of the list , this may have marginal impact for a server-side technology like email. I think MTA-STS can copy this solution. There are unknowns, like who would build an MTA-STS preload list, why we trust them to do so, and the exact semantics needed for a domain to be added. In any case, I think we should wait on increased MTA-STS adoption before we take those next steps. The adoption rates of MTA-STS and SMTP DANE tell an important story about how application protocols can secure domain information in practice. The fact that email has both a DNSSEC and an HTTPS approach gives us a way to spectate. Current measurements show that MTA-STS has overtaken DANE among the top-ranked domain names. Given the importance of protecting messages, including envelope information which cannot be end-to-end encrypted, these results are disappointing. Prior work shows that TLS downgrade attacks on email are widespread . With the slow adoption of email security protocols since that study, the situation is unlikely to have improved. We can and should do better. These SMTP DANE and MTA-STS measurements will be published quarterly. Subscribe to the newsletter to follow the trends. MTA-STS isn’t the only protocol that works this way. OpenPGP Web Key Directory (WKD) ( draft-koch-openpgp-webkey-service-22 ) uses an HTTPS .well-known approach to secure PGP key distribution, facilitating end-to-end encryption of message bodies. The WKD “advanced method”, seen above, follows the best practice of using a protocol-specific subdomain. The analogous DNSSEC-based approach is OPENPGPKEY ( RFC 7929 ). Unfortunately, the SHA-256 hash does not provide meaningful privacy. Use of this protocol can leak the email addresses of your correspondents to passive network-level eavesdroppers. This highlights the importance of encryption, not just signing. Other protocols like Mail AutoConfig ( draft-ietf-mailmaint-autoconfig-07 ) simplify the process of setting up an email client and similar applications. Again we see this protocol follow the security best practice of using a protocol-specific subdomain. There are over 100 registered .well-known URIs , showing the popularity of this approach. Many of these tolerate lower security properties and use the bare domain name instead of a protocol-specific subdomain. While I’ve thus far framed the discussion as a competition, DNSSEC and HTTPS .well-known are actually complementary. We don’t need one approach to defeat the other: we’ll see ecosystem improvements as both solutions are adopted, side-by-side. HTTPS .well-known can offload large policy documents and allow rapid experimentation, avoiding the size limits of UDP packets and the slow process of adding new DNS record types. DNSSEC can sign the CAA record, providing improved security during TLS certificate issuance. DANE could even replace the CAs entirely, a topic of renewed interest after the recent eMudhra mishap . After all, we wouldn’t need the CAs if we had a secure DNS . I see complementary nature of DNSSEC and HTTPS .well-known emphasized in another draft, Domain Authority (DA): A DNS-Designated Service Endpoint for Domain Information ( draft-swaminathan-da-00 ), which seeks to standardize the use of HTTPS to add capabilities to domain names beyond what DNS can natively support. While I think the current draft is too ambitious in scope, it provides a great summary of the benefits an HTTPS-based policy retrieval layer can provide beyond DNS. Unfortunately, we still have an insecure DNS. But progress in the domain name ecosystem is not blocked by DNS. MTA-STS shows that an HTTPS approach is immediately usable. Hello! I'm Robert Alexander, a DevSecOps consultant available for contract work . This blog features some of my work and thoughts on software, the cloud, and security. You can subscribe to my posts with your favorite RSS client and follow me on Mastodon . If you'd like to show your appreciation and help support my writing, you can do so via this link.

0 views
Playtank Yesterday

A Small Non-Update

Just wanted to mention why the blog suddenly stopped. It’s been updated on the 12th of every month for a couple of years, after all. Some of you are regular readers! First of all, it will be coming back! Probably not until 2027, but I have more than 100 work in progress posts to wrap up and get out there. Among those, a rework of An Object-Rich World that adds two other broad categories of systemic architectures, including sample code, and turns it into a series of three posts instead of one. I also have a finished post on why generative Ai is a poor match with systemic design and architecture that I really want to get out there. But all of that will have to wait, because I recently started working fulltime on my own project, on my own dime. So I don’t quite have the spare time needed to research and write the kinds of posts I like writing. There are already enough new things to talk about after just a couple of months of doing my own thing, so the writing will definitely resume at some point. Hopefully, you all keep hanging around until there’s more to share! Check out the Blog Guide to see if you missed anything. This blog is still the foundation for a lot of the things I do as well as a wider conversation on systemic design in games. Catch you on the flip side!

1 views
Ankur Sethi Yesterday

May cause respiratory effects

It's 11pm on a Sunday as I write this. It's Diwali. I'm visiting my parents in Delhi, as I've done every year since I moved away over a decade ago. I'm feeling a certain way right now. I'm writing this post so I don't forget this feeling. The fireworks outside are so loud that it feels like the world is ending. They've been going off for three or four hours now. I'm cowering inside my bedroom, thinking they will stop any moment now. But they just won't stop. There are so many of them. Why won't they stop? Aren't the people of this city tired of setting fire to the world yet? How have they not run out of things to burn? How many more hours of fire and brimstone until their hunger is sated? Our dogs are afraid. They've been trying to burrow into the sofa cushions since the first sporadic sounds of fireworks began at sunset. How must the animals on the streets feel right now? I know from living here for the first twenty-two years of my life that many animals won't make it to tomorrow morning. Many will be badly maimed. Many will perish out of fear. There will be fewer birds in the city for a few days. Oh, and then there's the main event: the smoke. So much smoke . My weather app tells me the AQI in my area is 500. Then it goes on to say, rather matter of factly: May cause respiratory effects even for healthy people and serious health impacts for people with lung/heart diseases. The health impacts may be experienced even during light physical activity. Here's the dataviz, just to drive the point home: This is, somehow, considered just fine around these parts. Normal. Unremarkable. I wore a mask when I went outside during the day. Here's what my mask looked like when I got back in the evening (top), compared to a fresh mask I just opened (bottom): See that gray? There's so much smoke outside that I can't see across the street. The air purifier is barely able to keep the indoor AQI at 250: I've never had any love for Diwali. I only visit my parents during this time because, well, it's Diwali. They want me here, I love them, and I like to see them happy. But as I see the people of Delhi set fire to years of their lives—and the lives of those who did not consent to being part of their so-called celebrations —I can't help but wonder if these trip are worth it anymore. I've had respiratory issues ever since I got COVID in 2020. I've spent lakhs of rupees on doctors, medication, masks, air purifiers, and treatments. I'm always masked up in crowded spaces. I take my flu shots regularly. I've stopped going to gigs and concerts because there are too many smokers at these events. What I mean to say is: I've been careful with my health, but it feels like I'm throwing it all away by choosing to be in Delhi tonight. I don't know how much of my life and health this trip will steal from me. I don't know if I'll fall sick while I'm here, and in what way. I'm afraid of going to sleep, because who knows what state my respiratory system will be in when I wake up tomorrow. My nose is already stuffy. I can already feel the post-nasal drip creeping up on me. My eyes and throat are already burning. In the afternoon I bought a fresh can of pressured saline wash to clean out my nasal cavity, but I left it in the car. The car is outside. I can't go outside. Outside is where the air purifier isn't . I'm afraid of even going to the bathroom, because the air purifier can't clean the air in there. I'm so afraid for my health right now. What's wrong with this city? I don't understand. I was born and raised here. I lived here for twenty-two years. But I just don't get it. What am I missing? Why is this happening? Why are people doing this? I feel so powerless and angry, hiding indoors, waiting out armageddon. There's nothing I can do to stop people from poisoning the air. Worse, there's nothing I can do to save myself. No amount of money or technology or medicine can save me when the air is made entirely of smoke. I just want to go home. I just want to be in Bangalore, where it's safe. I wish I hadn't come to Delhi at all.

0 views
Jim Nielsen Yesterday

Addition By Subtraction

I still think saying no is important. In that vein, here’s something I shipped by removing functionality (and I think my site is better for it). For the longest time on my icon gallery sites , you could view a list of icons in four pixel dimensions: Each of these sizes could be accessed via a control on the website. This has been true for years on my site, whether it’s the current site: Or an older version of the site: By default, I loaded the 128-pixel version of the icons. But if you wanted to see other sizes, you could. However, the more I used the site myself the more I thought, “Four options is too many”. When it comes to choice, what I really wanted was: (Plus three is always a good number , unless you have a reason otherwise). So I removed the big 512 option. If I want to study an icon at that size and detail, I click through to the icon’s detail page. Now there are three options for list views: 56, 128, and 256. Small (great on mobile), 128 (great by default), and big (let me see more detail). It’s simple to think about: You don’t need to think about it anymore than that. I mean you can , but I’ve found I don’t need to. So I’ve taken that off your plate. Less cognitive overhead. Maybe one day I’ll add a slider and make it all dynamic. But for now, I like this small addition by subtraction. Reply via: Email · Mastodon · Bluesky You get a size by default. Not big enough? Go up a size. Too big? Go down a size.

0 views
Rik Huijzer Yesterday

Thunderstruck

Luke 10:17-18 (KJV), "And the seventy returned again with joy, saying, Lord, even the devils are subject unto us through thy name. And he said unto them, I beheld Satan as lightning fall from heaven ." Even Satanists seem to be aware of this as shown by Anton LaVey, founder of the Church of Satan. He used to wear a inverted pentagram with a lighting bolt inside it. Anton LaVey, founder of the Church of Satan, wearing horns and his personal Sigil. Anton LaVey wearing his Sigil at another moment (source: fandom.com ). This jewel is known as the Church of Satan Sigil of Anton LaVey and can even be bought on Amazon. Amazon sales advertisement image for the Church of Satan Sigil of Anton LaVey (source: Amazon). Together with his Sigil, he was also a big fan of the Sign of the horns, LaVey doing the Sign of the horns (source: RollingStone ). In an interview, LaVey explained that "This is the Sign of the horns. A curse sign. Two fingers extended." LaVey explaining that the Sign of the horns is a curse sign (source: YouTube ). As a side-note, in the same interview he explains that you "have to be bad to be good" and when the interviewer asks "Is it true you teach people how to make voodoo dolls and stick pins in them to hurt people", LaVey answers, "That's right. I believe that hate is necessary in a controlled way just as much as love is necessary." Isaiah 5:20 (KJV), "Woe unto them that call evil good, and good evil; that put darkness for light, and light for darkness; that put bitter for sweet, and sweet for bitter!" In the book The Secret Life of a Satanist (1990) about Anton LaVey written by Blanche Barton, LaVey goes one step further and claims, "In reality, our mainstay influence is just the tip of the iceberg. For every one of those kids you see at rock concerts holding up the Sign of the horns and not knowing anything about it, there are maybe five more kids who have read the The Satanic Bible, know what Satanism is, and are growing up to the stage now where they are gaining positions of power and having a real effect in the world around us. In the motion picture industry, the arts, business, academia, politics — they don’t wear it on their sleeves so you probably wouldn’t even know they were Satanists." Even though Satanists lie often, this statement seems to be true -to hopefully be continued-

0 views
Manuel Moreale 2 days ago

The web used to belong somewhere

There are a couple of related ideas I found myself writing about here and there, either on the IRC server or on Quxnet . Ideas and thoughts about what the web used to be, how it used to feel, about how things have changed, and what can be done to bring at least some of the old web back. We often point fingers at the big social media platforms, with their relentless algorithmic curation as the cause for the awfulness of the modern web. Maybe we blame the SEO folks, or the influencers. There’s a multitude of different characters who each played their role in turning the “old web” into “today’s web”. And I’m not going to pretend they didn’t play a role, because they did. What I am going to argue for, though, is that there’s something else that has contributed a lot more to the changes that we’ve seen over the past few decades, and that’s the fact that the web used to belong somewhere. And I mean that in the physical sense. I’m not the first one to say this; you can find plenty of other posts out there making this exact point. But it’s a point worth repeating. There was a time when in order to go online you had to physically go to a specific place: a desk in the house, an internet cafe, a computer lab. The web wasn’t always with you, and you were not always in it and with it. You had to go somewhere, do what you needed to do, and then leave. BRB? AFK? Acronyms from what feels like a distant past. You are never away from the keyboard today, because there’s a phone following you around everywhere all the time. The internet feels exhausting these days because it’s always there. It’s become what feels like an inescapable presence, for better or for worse. I’ve been particularly unhappy over the past few weeks, for a variety of reasons. And one thing I noticed is that every time I’m in a down phase of life, I can go look at my phone usage and it’s inevitably higher than it should be. At least for me, there’s a 1:1 correlation between how good I feel and how much of a presence the phone is in my life. And the phone is just a proxy for the web because browsing is 95% of what I do on my phone, since I don’t game and I don’t have social apps. And that’s quite ironic considering I make websites for a living. I build for the web, and at the same time, spending more time than necessary on it makes me terribly unhappy. But it feels different when I can leave the web behind, when I can get up from my chair, leave my desk, and the web is no longer with me. That feels healthier. The problem is that most of the world doesn’t work that way anymore. If you leave and come back, you’ll probably have a hard time catching up with everything that has happened while you were away because everybody else is not taking a break. And so even if we managed somehow to get rid of algorithmic curation and infinite scrolls and all those things, the web would still not feel like the “old web”. Because the web used to belong to a place. It sadly doesn’t anymore. Thank you for using and believing in RSS. You're awesome. Send me an email :: Sign my guestbook :: Become a supporter

0 views
James Stanley 2 days ago

How to make a CNC plasma cutter with high-frequency start

The issue with high-frequency start ("HF start") on plasma cutters is that igniting the pilot arc creates an enormous amount of electromagnetic interference which causes problems for nearby electronics, in particular tending to disconnect the USB connection to your CNC motion controller. You can solve this by talking to the motion controller over WiFi. This is my machine in its temporary location on the workbench: If you still need to acquire a plasma cutter then I obviously recommend trying to get one with "blowback start" instead of "HF start" so that you don't have to worry about it. In acquiring a machine with HF start I made an error. But I got it to work anyway, so if you already have an HF start machine and you want to use it for CNC, you might be able to do the same thing. I kind of wanted a CNC plasma cutter because I have recently spent lots of time and end mills making planar parts like this for my cyclecar at excruciatingly low feed rates and depths of cut: So I started placing some bids on eBay and accidentally won a Parkside PPS 30 B2 for £80: The seller stated that he bought it from Lidl on a whim but then realised it needed a compressor and he didn't have one. If I had done my research I would not have bid on a machine without blowback start, but here we are. So when it arrived I set it up on the garage floor and tried to run my 6040 CNC router while lighting the plasma arc. As you might predict, I couldn't get it to work. Most of the time lighting the arc would disconnect UGS from Grbl. But serendipitously I was running a test program that had a small number of very long and very slow movements, which meant I had several minutes of motion left in Grbl's buffer, and I noticed that even though UGS got disconnected from Grbl and was totally broken... Grbl was still moving the machine! It was still following my gcode perfectly. So the issue isn't that the HF start actually prevents Grbl from working, it's just that it disconnects the USB serial connection . Solution: use FluidNC on an ESP32 board and talk to it over WiFi. FluidNC is Grbl-compatible but suitable for more modern microcontrollers. Charlie suggested talking to the controller over fibre optic, which would probably work even better than WiFi but is more faff to set up. Annoyingly, ESP32 outputs are 3.3v instead of 5v. I made up a breakout board for an Arduino Nano ESP32 on a piece of stripboard with a 74HCT245 abused as a level-shifter on the outputs and this was sufficient to provide 5v output from 3.3v input, unsure how legit this is. You can see my custom breakout board in here: I initially experimented with some small stepper motors with A4988 drivers, left over from when I dismantled my i3 clone 3d printer , and I think these would have been fine. But I also had some spare Leadshine easy servos from the unfinished CNC mini mill project I bought years ago. I didn't think the Leadshine servos would work because I thought the interference would confuse the encoder input, but I tested them and they seemed fine. And they're more powerful and better so I used them. But for a plasma cutter I really don't think fancy servos are necessary, the cutting load is basically zero, it's just a glorified pen plotter. The Leadshine documentation says they need at least 18v, but I only had a 12v power supply lying around so I tried it and it seems fine. I did subsequently connect the alarm output from the servo to an input on FluidNC and it kept falsely triggering every time the arc started (sigh) so I am running the servos without the alarm input. That's no worse a position than I would have been in using open-loop stepper motors anyway. My motion platform is made out of box section steel and 3d printed parts: With GT2 belts left over from the same 3d printer, and printed pulleys. The bigger of the two orange parts was a 36-hour print and used 700g of material, that's my biggest ever 3d print. All printed in ABS-GF on Bambu Studio "strength" setting. The "linear rails" consist of 608 bearings riding directly on the steel box section. I didn't make any of them adjustable but I should have done because it has slightly more play in it than I would prefer. Again this would be nowhere near adequate for a router but for a plasma cutter I think it should be fine. (The aluminium foil wrapped around the torch lead was a shielding experiment from before I was using FluidNC, it didn't help, I just haven't taken it off yet). I need to get a larger water tray. To fire the arc on the plasma cutter, it has a 2-pin GX16 connector which you normally connect to the torch trigger. I connected it to a relay operated by FluidNC so that I can turn it on/off with M3/M5. (But note you need to give FluidNC a non-zero "spindle speed" else M3 won't do anything, so get used to "M3 S1"). So at this point I have a working CNC motion system, with an HF start plasma cutter that I can fire from CNC control. Time to cut something out? Unfortunately I have no plasma cutting experience and (story of my life) it's harder than it looks. I messed around with the air pressure, current setting, and feed rate, and I just couldn't get a clean cut in 4mm steel. That's disappointing because the machine documentation says it can cut through up to 12mm steel. But I tried a piece of 3mm steel and my first test cuts worked a lot better, so I tried to cut out a heart shape. (I got ChatGPT to write the gcode for this). It blew the fuse in the extension lead 3/4 of the way through because I foolishly had the compressor and plasma cutter plugged into the same one. D'oh! I moved the compressor to a different extension lead and then it worked first time, albeit with a lot of slag on the underside of the cut: I cleaned this off with the angle grinder and you can see that along one axis my machine is cutting nice straight sides but on the other axis it is quite badly bevelled: I am going to replace the consumables in the torch when they arrive, and failing that I am going to make the torch clamp angle adjustable, and I expect I will be able to get rid of the bevel, but I don't know if the combination of the excessive bevel and the poor cutting performance are evidence that my machine is actually faulty. This may be the real reason it was sold on eBay after hardly any use. I have subsequently had my 16 amp breaker trip a few times while cutting so I may want to either find a way to run the compressor on a different circuit or else upgrade the circuit I have. These are the switches and lights on my control cabinet: Though the "alarm" light is now surplus as the servo drives can no longer trigger it. The "torch" light comes on when FluidNC is asking for the relay to turn on, but the relay doesn't actually turn on unless the switch is set to "enable". This is so I can ensure that even when I'm fumbling the gcode the torch can't light unexpectedly. And btw I obviously don't have an emergency stop button on this machine, but I can still toggle the torch off, or switch the power off, and there's no world in which I'm running a plasma cutter unattended, so I'm not very worried about it. I also don't have limit switches. I don't really understand why people bother putting limit switches on DIY machines (unless they have an automatic tool changer or whatever). What's the benefit to having a global coordinate system? You need to set up work coordinates for every job anyway. I don't have limit switches on any of my machines, but on this one in particular I expect limit switches would falsely trigger whenever the HF arc starts. So what have we learnt about making CNC plasma cutters? you can use a HF start machine if you talk to the motion controller over WiFi you don't want any inputs to the microcontroller, including limit switches, emergency stop, alarm inputs, USB serial if you make linear rails out of box section and ball bearings then make some of them adjustable so that you can take out the play GT2 belts are adequate 3d-printed structure is adequate getting correct cutting parameters is not any easier than it is with milling unfortunately, so still lots to learn Leadshine easy servos appear to work with 12v supply even though the documentation says they need at least 18v I made a custom gcode sender to talk to FluidNC because I wanted it to work differently to any existing ones and coding agents make software cheap, but I'm pretty sure UGS can talk over WiFi so it is not necessary to make your own sender. If you make a CNC plasma cutter using information from this post then please email me and show me, I'd love to hear from you. you can use a HF start machine if you talk to the motion controller over WiFi you don't want any inputs to the microcontroller, including limit switches, emergency stop, alarm inputs, USB serial if you make linear rails out of box section and ball bearings then make some of them adjustable so that you can take out the play GT2 belts are adequate 3d-printed structure is adequate getting correct cutting parameters is not any easier than it is with milling unfortunately, so still lots to learn Leadshine easy servos appear to work with 12v supply even though the documentation says they need at least 18v

0 views
Kev Quirk 2 days ago

Does Money Buy Happiness?

by Tuesdays Child Tuesdays Child talks about how they think money = happiness. It's an interesting debate with people on both sides of the fence. Read post ➡ I found this post via this reply on Bubbles. Both are interesting takes, for different reasons. For me, money doesn't buy happiness - it buys the removal of financial stress. What actually makes you happy is the people around you and the decisions you make with whatever you have. I've kinda talked about this before in my when was I happiest post. I grew up in a very poor home. After my mum and dad split up, our house was repossessed and we ended up living in a rough area surrounded by gangs, drug addicts, and prostitutes. My mum worked every hour god sends as a cleaner just to make ends meet, while I looked after the younger kids. We didn't know if the bills would be paid and were stuck in a cycle of weekly payday loans for years . On paper, that doesn't sound like a happy existence, right? But we were happy. As we settled in, we became part of the community, and watching all the street drama - like the regular fights and arrests that are common in rough areas - just became part of the entertainment, like watching a live episode of Jerry Springer . It wasn't all sunshine and roses, though. I remember one time when the addict that lived opposite us came busting into our flat screaming that her baby had died and she needed to call an ambulance. Back then there were no mobile phones, and our landline was in mum's bedroom. So mum obviously let her go call an ambulance. Turns out her baby was fine, but she knew our phone was in mum's bedroom and she took the opportunity to steal all mum's jewellery for drug money. Still, most of my memories from back then are good ones. I fondly remember sitting with my mum on a Friday night watching a stream of comedy shows like Cheers and Frasier . Once in a blue moon she'd say, "do you fancy a pizza?" Obviously I did! I'd jump on my bike, cycle to the local takeaway, and get us a 10" pizza to share because that's all we could afford. My god, were we happy. We were together, money be damned. Today, my life is the polar opposite of how I grew up. We live in a lovely quaint village in the Welsh countryside and I earn a very good living. Having money solves certain problems - like not having to worry about paying the bills or putting food on the table - which certainly makes life easier, even if it doesn't automatically make you happy. It still comes down to the choices you make along the way. Four years ago, we bought our dream home in the country. It's an old place that needs a ton of renovation work, which comes with big bills of its own. Had we stayed in our old house, we could have been mortgage-free by now. Would having no mortgage have made us happier? Probably not. That house was too small for us, right in the middle of a large town, and it felt claustrophobic. Taking on the bigger financial commitment gave us the lifestyle we actually wanted. I am happy today, but not because of what I earn. I'm happy because I'm surrounded by the people I love, living the life we want to live. On the other end of the scale from my childhood, you could have a millionaire who's completely alone and tries to fill that void with things - nice watches, nice cars, a nice home. With no-one to share it with, it's all just meaningless stuff. I think of it like a see-saw. The sweet spot is somewhere in the middle: having enough money that you don't have to worry about the basics, without spending your whole life climbing the ladder and missing out on time with the people who matter. That's a big part of why I stepped down last year . Money doesn't necessarily mean happiness. It can certainly help, though. Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️ You can reply to this post by email , or leave a comment .

0 views

Musically Horizontal Monads

Sorry for the delay! My household has had a couple of chaotic days of everyone-being-very-very-sick and house guests and 4:30am airport drop-offs. But we’re back! This blog post got written in several parts over several days, so it might be a little disjointed. Apologies. In the last post we discussed a way of attaching durations to instantaneous musical events: just wrap them with a duration, stupid! Then we wrote a function which takes an event stream of stopping points, as well as an event stream of starting points 1 . It then spans each starting event until the next stop or start. The stops are there so that we can add silence if necessary. Having a function like around is cool because it means we can just emit starting and stopping events from whatever upstream process we might like, and it will automatically turn them into “rhythm.” And of course, that upstream process is welcome to derive the stop stream from the start stream (or vice versa), if you don’t want to have to think about it. Anyway, that’s all and good. But musicians have a lot of intellectual moment behind not thinking about music that way. Instead they usually just think of having durations intrinsically attached to notes — that is to say, they conceive of the note and the duration at the same time. Since we have an explicit desideratum here of making it easy to get good results, we ought to provide some more conventional ways of thinking about writing lines. Writing lines is usually done as “pick a note and a duration, then after that duration, pick another note and another duration. Rinse and repeat.” Of course, there’s some wiggle room where you can instead choose to not select a note and leave silence in its place. Depending on how functional-programming-pilled you are, this either sounds like a monoid or a monad. Let’s explore both ideas, starting with the monoid. A horizontal monoid seems like it ought to sequence one piece of music before another, in a temporal-sense. That is, should play , and then once is done, it should play . Recall that already has instances, but looking at the type, they necessarily can’t be the right thing: If you’re unfamiliar with the newtype, it lifts the and instances over the structure. That is, we’ve effectively derived the following instances: The clue that this is doing the wrong thing for our purposes is the constraint. If we were putting one after another in time , we’d never need to combine s, and thus we would have no need for a instance. Thus, this instance must be doing a point-wise zip of times. Which is all to say that this is no good to us. What we instead must do is build a wrapper type which provides the correct temporal-sequencing monoid. Let’s take a moment to pour over our primitives and see if any of them are feasible for actually making that happen. The relevant primitive happens to be : which long-time readers might recall has seen some action on this blog in the past. The idea is that we will run the first until the first occurrence of the , then use that in order to switch to the given continuation. So gives us the “do one thing after another” semantics we want (notice its lack of a constraint!) This happens to be most of the work done, now it’s just a matter of accumulating the rest of the bits we need: the actual notes we’re playing, the start points, and the stop points. Let’s package all of that up into a little datatype: A horizontal structure then is some sort of newtype over . As it happens, writing the monadic horizontal structure is going to be a little more informative at this point, since we can lift the monoidal version out directly. But we can immediately put to work! In the exact style of Yampa Switching , we will use the inuation monad , which allows us to bind over the in some function — in our case, this will be the that curries out of . This is already well-treaded territory on this blog, so you can go read the Yampa Switching post if you’re curious about the exact details here. As a first approximation, wrapping this up gives us the type: However, this is somewhat unsatisfactory. s are covariant in their output (here ), but is invariant in that parameter. Blinding moving forward with as written would mean we wouldn’t have an operation which in practice turns out to be quite a limitation indeed! Instead we can do a little bit of a Yoneda -style encoding, where we hold onto a function that maps from into the eventual result of the invariant parameter. Check this thing out: The idea is that we delay building up our until you hand us a way of mapping from into whatever type you eventually end up wanting. We usually use a trick like this to get a free functor , but here we’re using it to get a free bifunctor : The and instances also come already-paid-for, but we must write them out ourselves: This concludes our diversion into writing . Popping the stack: recall we’re still trying to write a monadic horizontal structure. Which we can now write out as (with being left intentionally unmotivated for the time being), getting all our relevant instances for free: Take a moment to appreciate how amazing GHC is here; each of those deriving vias is lifting an unrelated type through a polytype and through a , the latter of which doesn’t have most instances we’re actually intersted in! 2 Our primary introduction form for is , which acts as one for some amount of time, before rendering a continuation of type : Note that we issue a start event at time 0, and both a stop event and switch event at time . From this we can derive and , both of which use a constant value across their , differing only in what they return as a monadic continuation: And of course, the function we had to invent the machinery in order to provide: It’s probably worth taking a moment to discuss what exactly the hell is going on with all of this crazy yoneda continuation monad stuff. What does it buy us? Lets write a little motif: notice that this emits notes relative to its input. In somewhat-standard notation, looks like this 3 : using this triangle symbol to indicate the continuation. But now check this out. We can bind the result in order to build a musical sequence; looks like this: This happens to be the underlying machinery in Tymoczko’s work on sequences (chapter 4 of Tonality ), though it is not presented as such (and I suspect he didn’t have monads in mind when writing it.) Revitalized with a real connection to real musical ideas, we press on through the mires of abstract nonsense. The most pressing problem remaining is how do we eliminate ? By means of : which isn’t actually unsafe, but will be due to a few additions to our API in a second. But a nicer eliminator is , which as originally promised, calls on our behalf: Here we use and pass it a dummy continuation, since we know we’re never going to actually sample it past the duration of our . Then we take the output , sample only at the start points , and pass the stop points through unmolested. It can also be useful to turn a directly into an event stream, ignoring its spans: The final two mysteries remaining are the unmotivated parameter in , and why is unsafe. Recall that musicians often think about periods of silence, or rests. While we could model rests as a value in a -typed , this would get rather in the way of our nice combinators! In particular, nothing says we must interpret a as a discrete function; if it’s continuous, then the value would make sense. But if we’re exporting discrete function, then the s never actually show up and the s are unnecessary. So here’s the trick; this phantom type in corresponds to “are there any rests in this value?” We can use a to get ourselves a type-level value to play with: Our new combinator is the only thing that uses the parameter: Notice that sets a stop point at t=0, and doesn’t create any new start points. Furthermore, the actual value of type here is an value. It claims to be “impossible,” which we will enforce momentarily. Something peculiar here is that we only have a single type of kind , namely . How can we differentiate s that use from those that don’t? Our old friend the ST trick comes knocking, requiring that remain fully polymorphic: Now can give us a continuous function only when the doesn’t contain any s! Usage of makes no such guarantees, and thus will crash with the impossible error when used on a . Note that has no such compunctions; it samples its function only at the designated start points, which doesn’t provide. And since our semigroup/applicative instances are all temporally end-to-end, nothing can introduce a start point inside of a . We began all of this looking for a temporal monoid whose multiplication would glue horizontal structures end-to-end. We then switched over to making a monad that did the same thing, but we don’t need to give up on our dreams of monoids! In fact, is already the monoid we want, with a minor niggle in that it wants a semigroup/monoid over the continuation value. If we tie that to be everything falls out for free: I don’t actually think this type is worth using, since it means our introduction forms need to be lifted into this newtype. But it’s nice to know that we could do such a thing if we wanted to! That’s all I have to say about rhythm for now. I don’t consider this to be the last word, but it’s as far as I’ve figured anything out. I’ve been reading a ton of textbooks on the topic, and the author who seems to be the least confused about it is Peter Westergaard . His formulation is in terms of “if you want a listener to mentally parse a hierarchical structure out of your notes, what properties would make that parsing easy?” That’s a thing I’d like to explore further, but I’m on a publishing deadline here, so I can’t take too much time to do research in between blog posts. Next time we’ll discuss Tymoczko’s theory of harmony , which will dramatically power up our ability to make something that sounds like music. Until then! Writing that sentence out makes it clear that I got the arguments backwards. Oops! ↩︎ As a little aside, if you’re not 90%+ of your instances, you should start. Good places to look for opportunities involve the wrappers in and . ↩︎ In glorious SVG. Sorry for the shitty image quality in previous posts! ↩︎ Writing that sentence out makes it clear that I got the arguments backwards. Oops! ↩︎ As a little aside, if you’re not 90%+ of your instances, you should start. Good places to look for opportunities involve the wrappers in and . ↩︎ In glorious SVG. Sorry for the shitty image quality in previous posts! ↩︎

0 views