sanguinecha.me/leon

Bad Apple, but...

13-Jun-2025

Update (18-Oct-2026): Some videos have since been unlisted and removed from this page. They are far below my current standards and I just don't like having them public anymore. As with all me-related things, you are free to dig at your own risk.

So I make Bad Apple videos. Quite a few, actually. Some of them take a quick evening to code and render, while others take… a bit longer than that.

I like Bad Apple memes. They're what motivated me to start making YouTube videos in the first place. I even made one at a hackathon (Bad Apple but it's NUSMods) and got to present it in front of a crowd at school. That's a pretty neat highlight of my life.

Regardless, it's gotten a bit stale now. I would say I've done pretty much everything I wanted to with this meme. So unless I get a funny one-off idea, I probably won't make more any time soon.

The NUSMods one has a separate write-up here. The rest are listed in this post, in chronological order. I've also included a short introduction to Bad Apple in case you have no idea what I've been talking about.

All the code I've written for these videos is in my GitHub repo. I do not apologize for the lack of readable or clean code.


What is Bad Apple?

There are already tons of explanations of Bad Apple available online, but I think most of them take a bottom-up approach. They start from the original game (Touhou), the song, the music video, and so on. That's totally fine, but I think the average "Bad Apple enjoyer" probably doesn't care about all that jazz.

I'm not in the Touhou fandom myself (does listening to Touhou songs count?), but I can appreciate the creativity and effort that goes into making these Bad Apple videos. So let's start from there instead.

This list is surely incomplete, but hopefully you can see how convoluted it gets.

Really, the only thing you need to know about Bad Apple is that it's (more or less) a black-and-white video. So anything that can encode just two colors can be used to display Bad Apple. The video itself is immaterial. It's the "Hello, World!" for nerds with too much time on their hands.


Made out of Bad Apple

This is a fun one. What if the frames of Bad Apple could make up Bad Apple itself?

The original Bad Apple video has a resolution of 480 × 360 pixels. So the idea is to create a 10 × 10 mosaic of frames, each scaled down to 48 × 36, so that together they resemble the original video.

The steps are simple, if a little computationally expensive. First, resize every frame down to 48 × 36. Then, for each full-size frame, divide into 10 × 10 sections and find the resized frame that best matches each section.

How do I match the sections? Well, here's where it gets a bit dubious. The video is in black and white, which means each pixel has a value from 0 to 255. For a section and a candidate frame, I compute the absolute difference in value for each pair of corresponding pixels. Then, I add up these differences to get a candidate's score. The candidate with the lowest score is selected.

This heuristic is pretty bad, since it doesn't account for where the individual pixels are and just treats them as a collective. Nonetheless, the result was decent enough for me.

There's no intelligent pruning here either. I just brute-forced it. With 6572 frames, each with 100 sections, and each section requiring 6572 comparisons, it took ages to render everything.

This has been done before, and much better than I have. Oh well.

Tupper's Self-Referential Formula

Tupper's Self-Referential Formula is one of those things that, personally, I don't think really lives up to its name.

Essentially, the formula can plot every single binary image of height at most 17 (its width doesn't have to be exactly 106, despite what many sources claim). The idea is simple: just treat the entire image as a huge binary number. Each vertical slice of length 17 along the y-axis represents some image.

When Jeff Tupper first included this formula in his 2001 paper, I assume he picked a slice that looked like the formula itself just for fun. At no point does he claim it's "self-referential". I'm not sure where that name came from, but it makes the whole thing sound much more magnificent than it is. Still, the formula is short, clever, and cute.

Oh, right. Bad Apple.

I figured the effect would work better if I used a pre-existing site that plots the image for you. I used Tupper's Self-Referential Formula Playground.

Resizing the images to 106 × 17 (the site requires the width to be 106) and converting them into the corresponding binary values was easy enough. Actually entering the number into the site was a bit harder. I ran some Javascript code in the console to do it automatically. I also had a script that took a screenshot of the site after each frame was rendered.

Surprisingly, I was the first one to do this. So there's that.

Wordle

It's a game. It's got squares. Green squares. Yellow squares. Gray squares. I had to do it.

Each frame is broken up into 15 separate Wordle games. All games are valid: the answer is a valid word, and the coloring follows standard Wordle rules. That being said, some of these games involve guessing the same (wrong) word multiple times, so they're not exactly "realistic". But it's Bad Apple, so I don't think anyone cares that much.

Wordle word lists are publicly available online, and picking the right words to get the right colors isn't too hard either, because of a secret fact you might not know: English has a lot of words! There are a ton of games that would satisfy the constraints, so I just randomly generated one each time.

By the way, all these games are played in normal mode. A hard mode version is left as an exercise for the reader.

Morse code

It's amazing how boring writing about the same thing (just in slightly different configurations) can get. But this is the last one for now. Fantastic.

First, I needed to pick a Morse code website, so I went with the first result on Google. Then it was a matter of finding a message that encodes into the right sequence of dots and dashes.

One difficulty is that the position of a character's Morse code depends on all the characters before it. That means I can't easily fix the position of a specific character in advance. Also, because the Morse code is displayed in a rectangular text box, I had to deal with line breaks and other formatting issues, which was a real headache.

Essentially, I add one character at a time, generate the corresponding Morse code output, and see how well it resembles the desired frame. To make it efficient, I can cache results that I've already computed. So if the current output has X dots and dashes, I don't have to explore that state again.

In other words, this is dynamic programming (which I did iteratively, not recursively). I store a score representing how well the current Morse code matches the frame, something like dp[X] = score.

This is a gross over-simplification, but I do think this was one of the more computationally challenging Bad Apple videos to make. So do check out the code if you're interested.