On Heathcliff and hackish image manipulation

This should probably just be two posts, but it’s been months since I posted anything and I’m just going to go for it. But if you just want to see me talk about a terrible bodge-job of a shell script, scroll down a bit.

For a while I’ve had this idea to start a Twitter bot that posts a strip made up of a random Heathcliff panel paired with a random Heathcliff caption. There are a few reasons for this, the first of which is that under Peter Gallagher’s tenure, Heathcliff has gotten… weird. Recurring themes include friendly but inexplicable robots, helmets that communicate what their wearer is thinking (maybe?), the Garbage Ape, the magical levitating properties of bubblegum1, the meat tank… the strip has gotten to be a real experience for every possible state of the human mind. But more importantly, the strip tends to follow a handful of rules. The vast majority of daily strips are a single panel, have Heathcliff in them, and have a caption that is spoken by some non-Heathcliff entity. Generally, there are at least two entities grouped together in the scene, one of whom is speaking the captioned text to the other. Often this is Grandpa and Grandma Nutmeg, Grandma Nutmeg and Mrs. Jablonski, Iggy and Willy, two random birds, two random mice, two random fish in a fishbowl… it’s rarely terribly significant who is speaking, just that someone is commenting on the scene in front of them.

All of these rules mean that, just in a sort of technical, editorial sense, most captions should basically work with most panels. My theory was that since they largely are technically compatible, and since the strip largely exists in this curious space, that this experiment would likely work in more ways than one. I ended up not going full bot with this experiment; ensuring that good, comprehensive alt text was present was a high priority, so every post on Heathcliff Stew is created manually and scheduled ahead of time. This is also important because my script is quite imperfect, with about 10% of attempts resulting in failure modes including entire strips being inserted instead of mere captions, cut off captions, and double captions. Since I have to intervene anyway, I have simple rule of my own: I don’t curate. As long as a strip doesn’t meet one of the failure modes, I post it. I have made a couple of exceptions, where I thought the combination of panel and caption could have potentially been offensive or insensitive; if I have even the slightest iffy feeling about it, I just… don’t have to post it. But otherwise, everything gets posted.

This was important to me, because I don’t think curating out only the good ones is… fair, exactly? I think that the idea that the Heathcliff world is strange enough that this often works is very funny, and in fact, I often have to double-check that I’m not actually working with a failure. When the strips are good, they’re very good. But the world of Heathcliff still has rules and norms and plenty of the randomized strips simply aren’t good. I think it’s only fair to the land of Westfinster to post these Ls alongside the bangers. In a recent interview, Peter Gallagher said,

There are a couple of other [Twitter accounts] – and I appreciate anybody who’s doing stuff – but there are guys who are just taking random Heathcliff comics and putting different captions on them. So they make absolutely no sense. I’m like, “Hey, come on.”

I kind of laughed when I first read this, but it gets to the heart of why I don’t want to post just the good ones. When the comics work, it’s a testament to the consistency of Gallagher’s bizarre vision of Westfinster, but if it worked all of the time, it would kind of just… dismantle that and reinforce the belief that Gallagher-era Heathcliffs are inherently random in design. And that’s not the reality of the situation. I don’t know, if you read this blog, you probably realize that I’m not a huge fan of artists having inalienable control over their work. Gallagher certainly didn’t seem to be trying to assert that, just expressing disappointment. I’d like to think that I’m exploring this world in a way that doesn’t disappoint, setting parameters that are at best clever détournement and at worst… what you’d expect out of a random comics machine.

About that machine…

So, the script itself. It’s an incredible hack that I don’t really want to post, but I learned a couple of things while trying to figure out how to do this in an incredibly hackish way. The key to hacking this together was Hough Lines detection, specifically the tool for this built in to ImageMagick. First we use a basic raster-based edge detection algorithm to reduce our image to a 1-bit representation of edges. The Hough Lines detector takes this and attempts to find lines, which it crucially saves out as vectors. The result is something like this (source):

Hough line transform: 130x2+150 218 184 169 197 216 230 190 234

What’s important here is that we have a plaintext vector format describing a bunch of lines. More on this format (MVG) later, but it’s essentially a simplified version of SVG. This means with some hackish parsing, we can find the line that is (hopefully) the bottom of the panel frame, and split a strip into its panel and its caption. Originally I was just trying to detect the lowest horizontal line, but this caused a fair few failures where the caption was dense enough to cause erroneous line detections. I improved my success rate by just discarding lines that weren’t at least ten pixels or so high. Here’s the current version of this embarrassing script:

#!/bin/zsh
a=$RANDOM
b=$RANDOM
c=$RANDOM
d=$RANDOM
[[ -z $2 ]] && fullDate[1]=$(date -d "August 30, 2004 +"$(echo $a $(date "+%s") "1093838400-604800/%p" |dc)" weeks +"$(echo $b "5%p" |dc)" days") || fullDate[1]=$2
[[ -z $3 ]] && fullDate[2]=$(date -d "August 30, 2004 +"$(echo $c $(date "+%s") "1093838400-604800/%p" |dc)" weeks +"$(echo $d "5%p" |dc)" days") || fullDate[2]=$3
for i in 1 2; do
	temp[$i]=$(mktemp)
	shortDate[$i]=$(date -I -d $fullDate[$i])
	curl -o $temp[$i] $(date -d $fullDate[$i] "+http://picayune.uclick.com/comics/crhea/%Y/crhea%y%m%d.gif")
	mogrify -resize 300 $temp[$i]
let "targetHeight[$i] = $(identify -format '%h' $temp[$i])-10"
convert \( $temp[$i] -canny 0x1+10%+30% \) -background black -stroke red -hough-lines 130x2+150 mvg:- | grep -oP '(?<=line 0,)[^. ]*' | sort -nr | while read -r j; do
	[[ $j -lt $targetHeight[$i] ]] && let "crop[$i] = $j + 1" && break
	done
done
outFile=$(echo $1"."$shortDate[1]"+"$shortDate[2]".gif")
let "caption = $(identify -format '%h' $temp[2]) - $crop[2]"
convert $temp[1] -crop 300x$crop[1]+0+0 top/$outFile
convert $temp[2] -crop 300x$caption+0+$crop[2] bottom/$outFile
convert \( $temp[1] -crop 300x$crop[1]+0+0 \) \( $temp[2] -crop 300x$caption+0+$crop[2] \) -append $outFile

[[ -e captions.txt ]] && printf "ID $1\nPanel: $shortDate[1]\nCaption: $shortDate[2]\n($1)\n\n" >> captions.txt
sleep 2

Nobody should try to learn anything from this (well, maybe the Hough Lines trick). I start out setting a bunch of variables to $RANDOM, because zsh handles this environmental variable in an odd way; only certain things trigger a reseed, so just manually making the four random numbers I need is a surefire way to ensure I actually get… four random numbers. From here, I generate the random dates I need, assuming I haven’t passed them as arguments. Since this is just for me, the arguments are not parsed with any intelligence; $1 is always a prefix for the filename, $2 is always a panel to force, and $3 is always a caption to force. I test for $2 and $3 with -z, which checks for a zero-length string. A problem I was worried about here is how to do a random panel with a forced caption – if $2 is blank, then what we want as $3 will simply become $2. This is trivially hacked around, however, test.sh '' test will pass a zero-length string to $1 and “test” to $2.

Parsing the dates was, as always, a wild ride. GNU date tries to interpret the dates passed to it in a sort of magical way2. This isn’t documented in its manpage, and is only sort-of-kind-of documented in info. Fortunately, it’s easy enough to say August 30, 2004 (the date of the first Gallagher strip) + 420 weeks + 3 days. I generate two random numbers for each date so that I can do it in weeks/days format; this allows me to easily ensure I’m only getting strips from Monday through Saturday. Typically when I use date, I’m either fetching the current date or tomorrow. Every time I have to do something more complex with the utility, I run into this matter of trying to figure out what does and doesn’t work with its input schema, and as per usual, I don’t feel like I learned anything of material value this time. For forced dates, I just pass the unaltered values of $2 and/or $3. Fortunately date accepts ISO 8601 style YYYY-MM-DD dates, so I’ve been opting for this.

Unlike its input, date’s output formatting is well-documented. Helpfully, it allows any arbitrary text to be output along with the date variables, presumably so you can do something like %Y-%m-%d. I exploit this convenience, however, to format the entire URL of the strip image to download with curl. Once the two images are downloaded, I ensure they’re the same width (most of the Heathcliff strips seem to be 300px wide, but I’ve run into a few that aren’t, which obviously causes a problem when the two images don’t match) and then do the Hough Lines detection. ImageMagick’s MVG format is pretty easy to parse:

# Hough line transform: 130x2+150
viewbox 0 0 300 360
line 0,0.5 300,0.5  # 218
line 0,3.5 300,3.5  # 184
line 1.5,0 1.5,360  # 169
line 293.38,0 299.664,360  # 197
line 295.5,0 295.5,360  # 216
line 298.5,0 298.5,360  # 230
line 0,328.5 300,328.5  # 190
line 0,331.5 300,331.5  # 234

The lines are essentially ordered top-to-bottom, and horizontal lines are always going to start with line 0. My original naïve approach just grepped all such lines and took the last one, but my slightly-more-optimized approach iterates from the bottom up until one is at least 10 pixels from the bottom. I can probably optimize this better, as well as some of the values in the Hough Lines detection3. From here it’s a simple matter of mashing the two halves together.

All in all, for this sort of lightweight image detection task, ImageMagick’s tools are useful enough to hack together a good-enough shell script. Would I have been better served learning some actual image detection libraries and scripting something in Lua or Python? Probably, but I also likely would’ve gotten bored and given up before coming up with something useful. And ultimately I learned a few things about ImageMagick, I learned that when lazily parsing arguments '' counts as a zero-length yet extant string, and I learned that for hacks and code golfing purposes, date’s output formatting lets you go wild with arbitrary characters. Also, I’ve realized that the simplicity of ImageMagick’s MVG format could make it useful for going in the other direction in the future; generating MVG code in a script (or by hand) seems trivial compared to SVG. I still insist that anyone looking at my script above only use it as an example of what not to do, but it does the job I need it to with a success factor that I’m happy with, and I learned a few new tricks. Plus I can get a random Heathcliff any time I want.


  1. This might have started as a George Gately thing, tbh. I know a lot of Heathcliff history, but I haven’t dived into the deep end on this one. I just feel like I remember this as an older gag. ↩︎
  2. I haven’t used a BSD system in a while. I know BSD date is different, but I don’t remember off-hand if its input schema is as vague and reliant on heuristics as GNU’s. ↩︎
  3. Notably, this script has a massive failure rate if I try it on Marmaduke strips. These parameters don’t work generally, and need to be tweaked for the task at hand. ↩︎

Sony's resin tubes

Sony has a history of making ‘lifestyle’ consumer electronics alongside their more boring, everyday items. From the 1980s My First Sony line designed to indoctrinate children into brand loyalty1 to the beautiful clutch-like Vaio P palmtop, the company has never been afraid to experiment with form, function, and fashion. Occasionally, they’ll release wild products like the XEL-1 which read like concepts but actually get released, albeit at silly prices.

One such item was the made-to-order NSA-PF1 ‘Sountina’, a six-foot tall speaker released in or around 2008. It wasn’t sold in the United States, but a 2012 archive of an exporter’s site shows that you could acquire one here for a cool $17,000. It’s a beautiful device, with some relatively traditional-looking speaker stuff holding up a glowing resin tube. This tube, which Sony likes to call ‘organic glass’ while plastering the product with disclaimers instead of just admitting that resin is itself a very cool material, serves more than just a decorative purpose: it is vibrated from below to act as the unit’s tweeter. A longstanding issue with loudspeaker design is that high frequencies are extremely directional, leading to ‘sweet spots’ where listeners have to be positioned. A cylinder that radiates high frequencies out at all angles is a clever approach to solving this issue.

The Sountina was clearly an extravagant R&D display by Sony; I would be shocked if they sold more than a handful. Truthfully, most people who can drop five figures on their loudspeakers aren’t going to have Sony at the top of their list. But if we fast-forward to around 20162, Sony released something more attainable, albeit something that was still largely an impractical lifestyle objet d’art. This something was the tabletop LSPX-S1 speaker, still described as a ‘Glass Sound Speaker’ with asterisks upon asterisks explaining that ‘glass’ means ‘organic glass’, and ‘organic glass’ means ‘resin’. This unit retailed for around $800, was mass-produced, and did make its way over to the U.S. The model number is notable here; alongside the LSPX-S1 was the LSPX-P1, a short-throw projector. Both were announced as part of a marketing initiative called ‘Life Space UX’3. Foreshadowed in an interview about the Sountina, the LSPX-S1 has a warm filament-style LED toward its base, making it resemble a lantern more than a speaker.

These sold in some quantity, at least, as they’re abundant on eBay. But there isn’t much in the way of user information on them out there, and I suspect that’s because yet again… if you’re plonking down $800 for a Bluetooth speaker, you’re probably not looking to Sony first. Doubly so if you want to make a stereo pair. Last year (I think?), Sony improved on this issue somewhat with the $450 LSPX-S2. This is still an expensive lifestyle device, and therefore one with little information out there, but with some finagling I managed to acquire a display unit for a very good price. If you’ve made it this far, let’s talk about the LSPX-S2.

Actually, no, sorry. Before I can talk about this little resin tube, I need to talk briefly about my taste in loudspeakers so that we’re on the same page. I’ve been looking for a bedside unit, and because of the way my bed is more of a living space than a sleeping space, a 360° tweeter device has been appealing to me for a while. I had been tempted by the SoundMatters Upstage360, especially once new units started popping up for half price or so on eBay. This, of course, was also rather suspect though, and while SoundMatters is a company I’ve owned and enjoyed a number of products from, the comments on the Kickstarter didn’t paint an image of confidence. To switch gears for a second, I do not like multi-way speakers. My ‘real’ hifi system has Audience ClairAudient 2x2 loudspeakers, which use 4 full-range drivers each for the sake of efficiency. There’s no crossover, no sense of tweeter/midrange/woofer, and this is how I like it. I have always had a problem with cohesion in multi-way loudspeaker designs. Yet, I accepted when thinking about the Upstage360 that this would be unavoidable, and given how few 360° speakers are out there, I was willing to try a two-way design with the Sony as well. One final preference of mine that the Sony does make use of is a passive radiator design in lieu of a bass port or the like. I only mention all of this because we all tend to have different things that we want out of audio. I want full, but not booming bass. I’ll take cohesion over inaudible frequency response. With this product, specifically, I’ll compromise things for omnidirectional sound.

While I don’t care about packaging, the LSPX-S2 is certainly packaged like a lifestyle product. The outside of the box has a silhouette of the speaker on it, which… given its shape and size, really makes it look like the packaging for a magic wand4. The manual harkens back to the Sountina’s, in a way – Sony proudly gave the Sountina a full-color manual to set it apart, and while the LSPX-S2 is not this, it does have two rather chic spot colors (a sort-of pink and a sort-of brown) in addition to black, and it’s laid out in a much more… friendly fashion than most. The friendliness hurts more than it helps, but overall the manual is fairly extensive. This is important because the unit has Bluetooth, which can be paired traditionally or via NFC, as well as some WiFi functionality, and an app to control some of the more complicated bits. The WiFi can be tied to a UPnP server on your network, which I may try at some point, or Spotify Connect, which I will never try because fuck Spotify. The app also lists a handful of services like YouTube and Soundcloud, but I think these just… launch those respective apps? All in all, the app is pretty terrible, but I’m primarily concerned with using this as a normal Bluetooth and analog line-in speaker.

As a speaker, it’s… pretty good! It’s certainly still not $450 good, but it does a few things very well. First and foremost, the omnidirectional resin tube thing works. And a lot of music that I enjoy sounds excellent on it. The mids are lush, and the bass is present… obviously not a room-shaker, but it doesn’t feel like it just cuts off at the low midrange. Treble is where things get a little bit tricky. I do think some of that lack of cohesion that I mentioned earlier comes through, particularly on very busy, wall-of-sound type recordings. In these instances, highs just feel a bit detached from the traditional loudspeaker to my ears. The treble can also be very peaky; higher-register vocals can be a bit harsh, and sibilant sounds kind of feel like they might shatter the glass tube, if it were actually made of such a material. But most well-recorded, well-mastered stuff sounds quite nice; instrumental music, be it acoustic or classic synths tends to sound excellent. Which, for me at least, fits the use-case of a mono5 omnidirectional speaker – it’s a chill background-music machine.

This background aspect also fits its candlelike aesthetic. While the LSPX-S1 had a quaint filament-style LED at its base, the LSPX-S2 has a warm LED that fires up into a clear dish of sorts to create an effect much like a tea-light. You can adjust the brightness of this, though it never gets brighter than mood lighting. Likely a better setting is its candle mode, which flickers gradually at random. This combined with the way the LED is configured makes for a really lovely little bit of mood lighting. I have returned to my room after an hour away and nearly scolded myself for leaving a candle lit. It’s a lovely look.

Finally, a few notes on UI. The app, as mentioned, is bad. It lets you control things like brightness, which is nice, though fortunately unnecessary. Even if the app was great, it’s best to assume these things don’t exist, because some day they won’t and… well, at that point you either have a functional product or a brick. On the unit, there are buttons both around the base of the unit, and under the unit. The controls on the outside are power (also used to switch candle mode on/off), push-to-play, and volume up/down. The push-to-play is the most meh of these, as it seems to pretty exclusively rely on Spotify, but I’m glad the power is available without lifting the device up. Under the unit are controls for pairing, brightness up/down, adding an additional speaker(s), and a shared button for a sleep timer and WPS. The sleep timer is a nice feature, though I wish it was on the outside of the device. Since the buttons are neither tactile nor lit, if you’re heading to sleep and your only light source is the dim LSPX-S2 itself… well, it isn’t very easy. The buttons on the outside of the device are barely raised, but the buttons on the bottom are not at all. They’re also a bit mushy, so even when you can see where you’re pressing, it doesn’t feel reliable. Last thing about the buttons – it’s nice that the power, etc. are on the outside, but they are so close to the bottom that you almost need to lift the device anyway. All in all, I’m glad Sony gave the LSPX-S2 as many physical buttons as they did; you can control everything important without the app, and the controls basically all make sense. The UX isn’t ideal, but in 2021… well, I’ve seen much worse.

I hope that Sony makes an LSPX-S3, or perfects the process on the LSPX-S2 such that it’s closer to the $200-250 range. It’s a nice luxury device that fills a lifestyle niche that Sony has always dabbled in; but you’re paying largely for this, it just does not sound like a $450 speaker. This said, there aren’t many speakers out there that fill the omnidirectional mono niche, so for a situation like mine… well, I’m glad I got a banger of a deal on this weird little resin mood light. It’s a truly pleasant ambient device.


  1. Okay, this is a little harsh. I mean it’s true, but it’s also true that children have different usage needs than adults, and things like volume limiters, simple controls, and rounded edges do genuinely make for a better product for a child. I don’t know that anyone else was doing this at the time with real electronics that were based on and ultimately worked as well as their adult counterpoints. ↩︎
  2. It’s hard to pinpoint exact dates on these products that got more attention as press releases and trade show items than actual, in-home reviewed products. ↩︎
  3. There’s not much to look at here, and the stylesheets have gone poof, but the WayBack machine has a snapshot of Sony’s Life Space UX page. ↩︎
  4. The sex type. ↩︎
  5. If you get two of them, you can configure them as a stereo pair. ↩︎

You need a Torx T10 driver to disassemble the 8BitDo Arcade Stick

Not too long ago, I decided to get myself an 8BitDo Arcade Stick. If you’ve spent much time here, you might’ve noticed I’m rather into retrogaming. I grew up with joystick-based consoles and arcades, and while I’m happy using a modern gamepad these days, I do often wish I had that arcade feel when I’m emulating an older system. I was also drawn to the tinkering nature of an arcade stick; the actual joysticks and buttons are largely standardized, modular parts. Arcade sticks for home use are generally marketed toward fighting game players these days. I am not one of those. I’m also not well-established with the world of buying parts for and modifying these sticks. If either of those things describes you, this post will be boring and/or infuriating to you. But the information out there is patchy out best, and I’d like to do my part to share my experiences with this specific stick.

Resembling a classic Nintendo Advantage stick and prioritizing conveniences like Bluetooth1, I think the 8BitDo stick is intended for folks like me, vs. professional SNK-heads. Yet, the fact that it uses standard parts and is therefore easily moddable is one of their main selling points; in fact they seem particularly proud of their large joystick mounting plate, populated with myriad holes to accommodate a vast number of sticks on the market. With these two things in mind, I think they’ve done a rather poor job with the latter. Technically, it can be modified… but a lack of any sort of documentation and some curious internal decisions make this a bit difficult for folks falling into the former part of this marketing strategy.

For starters, the stick is held together with six Torx T10 screws. These are set deep inside rather narrow screwholes; you need a driver with a rather thin shaft (standard 14” multibit drivers won’t work). This is not insurmountable, but it is off-putting for something marketed as modifiable. Worse, they don’t tell you what driver you need, and none of the reviews/etc. that I found online mentioned it beyond complaining that it was a weird screw. Hence the post title. It’s also worth noting that these are just self-tapping screws cutting into plastic. Not great for something that will potentially be opened a lot for modding – it’s worth taking extra care with these2.

Once inside, there’s a ribbon cable going from the USB port on the bottom half of the case to one of the boards on the top half. This needs to be disconnected; after disconnecting it, everything important is on the top half. The two things that you might want to modify once you’re inside are the buttons and the joystick. We’ll start with the buttons.

There are two primary manners in which the buttons mount to the case: screw-in and snap-in. I had issues with both. I briefly had a full set of screw-in buttons installed. This was very difficult to manage, as the nuts just barely fit within the necessary space. In fact, I couldn’t turn the nuts; I had to get them tightly nestled within other bits of plastic and turn the buttons themselves to get them mounted. One was still so tight that I could not get it to fit perfectly flush. These were Crown/Samducksa buttons/nuts. Later, I acquired some Seimitsu screw-ins, and these nuts were even larger. Fortunately, the thread is standardized, so just get the slimmest nuts possible and use those on whatever buttons you want if you’re going to attempt screw-ins. The Crown/Samducksa nuts basically work, but there may be slimmer/better ones out there.

The snap-in buttons I tried were also tricky. I ended up going with some screw-in caps in snap-in housings3. While I was experimenting with things, quite a few of the snap-in buttons I had simply didn’t… snap in correctly. This would cause the buttons to be loose within the stick case, or the caps to bind up within the button housing. In addition to the eight 30mm primary buttons, there are two smaller (24mm) macro buttons at the top of the unit. I tried a couple of additional buttons in here as well, and the Seimitsu buttons that I purchased wouldn’t snap in at all. In the end, while the buttons are certainly sort of a standard, it’s very imperfect. Both screw-ins and snap-ins from major manufacturers were a complete crapshoot.

One thing that wasn’t an issue with button compatibility was the method of connection. Both the 24mm and 30mm buttons are wired up using .110mm lug-style quick disconnects. Every button I’ve seen for sale connects in the same way. The joystick, on the other hand, requires actual work regarding connectivity if you’re going to attempt to swap it. For starters, the stock joystick has .187mm lug-style quick disconnects that are soldered to an 8-pin header that connects to the main board. This header is not standard.

Before getting into what is standard, I should mention that I had experience with a variety of buttons because buttons are cheap. Fiddling around to find out what worked well technically, aesthetically, and as far as play is concerned was fun and worth buying more than I needed. I also had experience with several joysticks, but this was not intentional or fun. I bought not one, but two joysticks that physically did not fit in the case; they were too deep and the bottom half of the case had no chance of mating with the top half. This makes sense – an arcade cabinet has a bit more wiggle room than a unit like this. But it’s worth putting out there – be smarter than me and look at the physical dimensions of any potential joystick. I ended up with a Seimitsu LS-324; Sanwa JLFs look like they should fit. My failed attempts both came from Industrias Lorenzo.

Most sticks come with their microswitches soldered to a PCB with a five-pin header on it. As mentioned, the stock joystick instead has microswitches with bare .187mm lug-style quick-disconnects. Unfortunately, as I also mentioned, these are soldered to wires that terminate in an eight-pin connector. This leaves you with a few options for joystick replacement. There are pads on the main board for the five connections (up, down, left, right, common ground) of the aforementioned five-pin header. One could solder wires to these pads that terminate in one of these connectors, making most of the available joysticks compatible. While I intend to do this at some point, I’ve taken another route for now – simply chopping the eight wires off at the soldered side, and crimping on .187mm quick disconnects. This leaves a non-zero, but still small number of compatible joysticks on the market. One advantage to this approach is that all four joysticks I have in my possession, as well as most others that I’ve seen use standard miniature-sized microswitches. Free from being soldered to a board, the quick-disconnect approach means that these switches can easily be swapped in and out. I cleaned the solder off of the ones that came with the stock joystick and can either freely use that stick again if I want, or keep the switches around as spares.

All in all, I’m happy with the stick. Having a Bluetooth arcade stick for retrogaming is an absolute joy. The stock joystick was mushy, and the stock buttons a bit touchy, but I was able to swap these things out. I do think that if 8BitDo is going to design this thing for a more casual audience while marketing it as customizable and widely compatible with various popular components… they need to do better. I’m a tinkerer; I had the necessary screwdriver to open it already, I knew not to wildly yank it apart because there was likely a ribbon cable joining the two halves, I recognized that I had to strip the existing joystick wiring and crimp on quick-disconnects. I don’t think I should’ve had to know all of this, given the way they’ve designed and are marketing it. Putting customizable things in the hands of non-tinkerers is great; it often makes tinkerers of them. But some guidance is key to making that a smooth process.


  1. Bluetooth was the selling point for me, and the reason I finally decided to invest in a stick. I understand why most of the sticks on the market are exclusively wired, but… well, again, I’m not using this as a professional tool. ↩︎
  2. I assume most people here know this, but if you don’t… when you’re re-fastening self-tapping screws, unscrew them first until they kind of click into the existing thread. Even on screws that aren’t self-tapping, this helps to avoid cross-threading, &c. ↩︎
  3. This combo was initially because I had a new color scheme I wanted to attempt, only available in screw-in, and I didn’t want to deal with the nut issue again if I didn’t have to. I ended up really liking the result, however. The screw-in caps are slightly smaller, leaving a slight gap between the cap and housing. This feels much better to me, as the typically gap-free button experience tends to get a little rubby feeling when hit off-center. I’m sure this is a faux pas. ↩︎
  4. Initially I wanted to go with the IL sticks because of their short throw and quick return to center. The LS-32 has a fairly short throw, which worked out great. I ended up modifying the LS-32 with a stronger (3lb) spring, an easy enough task because I had spring clip pliers on hand. Joysticks also often have different restrictor gates available – a square allows for full movement; rotating it restricts movement to up, down, left, right; a simple slotted gate restricts movement to only two directions. I ended up putting in an aftermarket octagonal gate, which allows for all eight directions but also gives a positive indent for any given movement to fall into. This was just a matter of four screws. ↩︎

The voice of a wizard hacking away

My pals at Sandy Pug Games have opened up preorders for WIZARDPUNK, a zine of various wizard stories and whatnot. It’s full of brilliant work, and I highly recommend checking it out! I have a little epistolary slice-of-life piece in it, which I’m honestly pretty proud of. In addition to this, I was asked if something rather curious was possible, if there was any way some audio-producing computer code could be squished down to a reasonable size such that someone could theoretically type it in. The final result of this exercise is in the zine as well, and it was the kind of code-golf-esque challenge that was so interesting to me that I essentially knocked it all out mentally while soaking in the tub.

The interesting bits are the constraints. The core explicit constraint is that it needs to be able to be typed in, but this brings with it implicit constraints to bring it from ‘theoretically typable’ to ‘someone might actually try this’. Length is an obvious one, and I think to not detract from the rest of the zine, a single spread was kind of ideal anyway. Actually being able to print and type it is another; we can’t just release raw binary data. Finally, while I initially wondered if there was a plausible way to have folks generate a .COM file or the like, ideally the code is something cross-platform and also recognizable to folks who are not nerd-ass single-board computer hobbyists like me.

What occurred to me was that we could embed a base64 BLOB of an MP3 file into an HTML5 audio element. Base64 means we’re using human-typable binary. HTML means literally everyone with a computer in 2020 can run it. Additionally, HTML is ubiquitous enough that a lot of people – even wizards who have never actually dealt with web design – will recognize it and know what to do with it with little to no direction. The remaining problem, and one that left my more skeptical than confident from the computer-free sanctity of my bath, was payload length.

Fortunately the audio clip I was going to be working with was essentially a vocal sample. I ended up converting it down to an 8kbps monaural MP3 file, which is… absurd. But, space-wise, everything was tight here. I initially tested with a 0.8 second sample of my voice, and was hopeful I might receive something comparable in length. The first sample I was sent was closer to two seconds, which sounds perfectly serviceable at first blush. But within our constraints, dealing with the scale we’re working with… doubling the size of the payload is significant to the point that it ultimately destroys the likelihood of the experiment remaining plausible1. Liam pared the clip down to one second, and we were back in business. It sounded crunchy and muddy, but 8kbps remained a sticking point. Going to 16kbps would double the payload which, again… is a big deal. It simply reduces the human-typable aspect far too much.

Even with these constraints in place, the payload is 2,572 characters for a hopeful wizard to theoretically type in. To make matters worse, even though they’re technically human-readable, they’re still seemingly random strings like M7wXBlcFATAE2V5eM. Formatting-wise, I tried to break them up into relatively short lines, but it’s still… a lot. This means that there’s a lot of room for error here. My understanding of MP3 is pretty limited. I assumed it doesn’t contain a checksum since it’s a streamable format, but I wasn’t entirely positive; if I was wrong, a single erroneous character might make a browser reject it. I also didn’t know how good (or bad) the error correction might be. This whole endeavour piqued my curiosity enough that I’ll likely try to read the spec some day, but for now… I just started replacing and deleting characters and mashing reload in my browser. Luckily, and somewhat surprisingly, it was actually very fault-tolerant! A sloppy wizard can make a considerable number of errors with little to no audible effect.

In the end, this was a fascinating experiment for me. None of it was particularly complicated, but figuring out these constraints and piecing together a viable solution? That’s the sort of wizard shit I can get behind. Anyway, go check out the wizard zine!


  1. The whole thing (payload and HTML wrapper) fills a two-page half-letter spread. It’s a lot, but it still feels manageable; you can see the entire thing in one go. Doubling this to four pages just feels far too daunting. ↩︎

Artwork of the Channel F (external)

Just a fun little link post. Title link goes to a lengthy and well-illustrated post by Kate Willaert highlighting the design of Fairchild Channel F game cartridges, manuals, and boxes. I’ve been spending a lot of time lately discussing the specific aesthetics of various consoles, and why they gravitated toward those aesthetics. The Channel F is one of those systems that I know all about the history of, but have somehow never actually experienced in person. So, I never really had it in my mind to mull over its aesthetic, but it is a trip. Of course, much like the later VCS, this was a time when video game graphics were… y’know, dots. So box and cartridge art tended to just go buck-wild.

Anyway, the Channel F had a colorful and cohesive aesthetic to its game art, and Willaert does a bang-up job of walking us through it. Apparently this is the third in a series she’s doing, with the Magnavox Odyssey and those games you’d type in from magazines and such being the first and second entries, respectively. Good stuff.