Tailscale iOS and macOS Shortcuts #

I worked on adding iOS and macOS Shortcuts support for Tailscale's latest release. I wrote a blog post with examples of shortcuts and automations that the Tailscale actions could be combined with. One that didn't make the cut was using sound recognition, for things like “In case of an emergency, break glass to activate Tailscale”.

iOS Shortcuts automation that connects Tailscale when the sound of breaking glass is detected Shortcut automation sound triggers: baby crying, shouting, kettle, and others

Other possibilities include "Cry/shout/scream to connect" and "Let your pet control your connection state".

Places Mihai Has Committed Code From #

I've been running lolcommits for 10 years, and it's captured some interesting moments from my time at Quip and Tailscale.

I've put together a gallery, it was a fun nostalgia trip to revisit so many places and coworkers.

Infinite Mac: 2022 In Review #

I've come to think of Infinite Mac as my forever project. There's always something to work on, whether it's expanding the library, improving compatibility, adding more platforms, improving performance, debugging data structures, bridging APIs from 30 years ago with modern web platform features, or fighting with frontend tooling. With that in mind, here's where things stand at the end of the year — there have been quite a few changes since my last post on the project.

Foundations

Befitting a long-term endeavor, I invested some time into maintainability. This included small changes like setting up auto-formatting and bigger ones around code organization. I moved all of the browser-specific audio, video, clipboard and other subsystem implementations into their own modules, instead of adding lots of branching to existing ones.

That cleaner separation, combined with changes to reduce diffs with the upstream, made it possible to rebase the repo on a more recent version of Basilisk II — I had still been basing my work on James Friend’s initial Emscripten port, which was a snapshot as of 2017. Most Basilisk II development is happening in the kanjitalk755’s fork, and I switched to building on top of that.

Finally, I made it easier to do native (macOS) builds of Basilisk II (and SheepShaver) from the same repo. This reduced the friction when tracking down behavioral differences between the native and web-based versions: I can instrument or modify shared code and then run it in both builds to see how it differs.

SheepShaver and Mac OS 9

With things on a more maintainable path, I decided to tackle a bigger project: PowerPC support (which would allow Mac OS 8.5 and later to run). This involved porting SheepShaver to WebAssembly/Emscripten. Luckily, it shares a lot of code and architectural decisions with Basilisk II (not surprising, since they were both created by Christian Bauer). The initial bringup and integration involved similar autoconf tweaks and #define changes to get the Emscripten build on the right code path. After that it was a matter of hooking up each subsytem to the existing implementations that bridged to the JavaScript/browser world.

The end result is running at macos9.app. My main takeaway is that it feels more sluggish than System 7 or Mac OS 8. A lot of that appears to be due to bloat in Mac OS 9 itself, running a PowerPC version of System 7 feels snappier. There’s probably low-hanging fruit in the emulation itself when targeting WebAssembly, but I have not done any investigations in that area.

Features

Infinite Mac Mac OS 9 ScreenshotMac OS 9 in an Apple Cinema Display bezel with dynamically-generated Stickies

A somewhat silly feature I wanted to implement was to show the changelog in the set of stickies that is shown at startup. I had been previously been embedding the data by hand (by booting each image and editing the Stickies file), but this was becoming tedious now that there were four separate variants and more frequent edits. I therefore reverse engineered the Stickies data format and then switched to dynamically generating it, including the changelog. A bit over-engineered perhaps (see the caveat below), but it was fun to reconstruct what Jens Alfke had implemented almost 30 years ago.

Another “because I felt like it” feature was adding era-appropriate screen bezels to the ersatz monitor that is shown around the screen. Technically beige was no longer in use by the time System 7 was released (the Snow White design language was fully rolled out a few years prior), so this may be something to revisit if older OS versions are supported.

I also added a couple of useful features: the ability to swap the control and command keys (so that shortcuts like Command-Q and Command-W can be used even when not in full screen mode) and clipboard syncing support. The latter has some interface impedance mismatch issues, since the clipboard API is asynchronous and has gesture trigger requirements. However, it seems to work well enough to get text in and out of the emulator in a more natural fashion than files saved in the “Uploads” folder.

Improved Compatibility

For the emulators to be more than just a curiosity (that gets played with for a few minutes and then forgotten), having compatibility that’s at least as good as the native builds is important. I spent some time fixing small bugs, like missing thousands/16-bit support, handling screen resolution changes, and making the audio less laggy.

A bigger task was improving the accuracy of FPU emulation. This manifested itself as two bugs that initially seemed unrelated - a calculator program failed when doing any operation, and scroll thumbs did not move in Mac OS 8. A tip from a user pointed out that native builds of Basilisk II used to have the latter problem too, back in 2018. Running with a build from that era reproduced the scrollbar behavior, and the calculator issue too, when I tried it on a hunch (presumably the scroll thumb drawing routines do a floating point division to compute the offset).

I then did a bisect of changes to find where it got fixed, and ended up with the switch in FPU implementations to a standard IEEE 754-based one (instead of a custom implementation). However, the WebAssembly version was already using the IEEE 754 implementation, thus it should be on the same code path. I eventually realized that the native build (on an Intel Mac) was on the USE_LONG_DOUBLE sub-path, while the WebAssembly one ends up with vanilla 64-bit doubles. Both x87 and the 68881 support extended precision (80-bit specifically), which makes IEEE 754 a good match for them, but that’s not the case for the WebAssemby virtual machine. I then checked to see what the arm64 port of Basilisk II does (as an example of another platform without extended precision support), and it uses a different FPU implementation, based on mpfr. Switching to it resolved the issue, albeit with a performance hit (hopefully no one is doing long Infini-D renders in a browser).

Another place where an external tip provided a key clue was in tracking down the case of missing sound support in Mac OS 8 and 9. A user that was hosting their own instance of the emulator reported that sound worked for them, which was surprising. I initially thought it was due to a different system image, but I could still not get it to work even when I used theirs. I eventually realized that they had a simpler build process, and were not using machfs to do the dynamic Stickies insertion mentioned above. When I switched to passing through my system image unmodified, sound began to work.

There’s probably another subtle bug in the HFS data structures that machfs emits (I have already fixed a couple), but I did not feel like diving into Inside Macintosh: Files again just yet. Instead I switched to a lower-tech way of inserting the dynamically-generated Stickies file into the disk image: a placeholder file whose contents can then replaced by operating at the raw bytes level.

Coverage

Somewhat surprisingly, the SheepShaver/Mac OS 9 work ended up on Hacker News before it was fully ready. The discussion was nice, though mostly in a nostalgic/“they don’t make them like they used to” vein. Amusingly, the TL of the .app domain project noticed their use. The discussion also inspired me to change the default alert sound to Sosumi.

The Register also had an article about Mac OS 9 where the author actually reached out and got some quotes from me — I appreciated the effort. A Japanese site had a pretty in-depth article about kanjitalk7.app, it’s nice that the localized version was noticed.

My favorite was a very thorough YouTube video about the project, including a demo of the LAN/AppleTalk functionality that I cobbled together over the summer.

What’s Next

I’d like to broaden the versions of System Software/Mac OS that can be run in a browser. There is some amount of “gap filling” between the 7.5, 8.1 and 9.0.4 images (Mac OS 8.5 has a special place in my heart because I got my start doing real development for the 32-bit icns icons that it introduced). However, older versions (System 6 and earlier) are only supported in other emulators, as this handy spreadsheet shows. There is an existing mini vMac Emscripten port that could serve as a starting point.

There is some cost involved with all this. Currently this includes 4 .app domain names at $10/each per year, the Cloudflare Workers Paid plan at $5/month (to get Durable Objects that are used for LAN) and a GitHub Git LFS data pack at $5/month. This is still at a point where it’s a reasonable “hobby” budget (especially compared to woodworking or 3D printing or photography, as examples of hobbies where gear cost can escalate), but I’m considering setting up a Patreon or GitHub sponsorship in case others do want to support the work.

Though I’m enjoying the solo aspects of this work (as far as working on whatever I want with no coordination overhead), I’m not opposed to outside contributions — it was nice to get a PR to improve the scrolling behavior on small screens. Hopefully there’ll be more of that in 2023.

But really the main goal is to continue to have fun.