Here’s another project I never properly documented when I initially put it together. The idea hit me out of nowhere: could you arrange black cubes in a 3D grid inside a 21x21x21 cube so that projections from each face display six different QR codes, each with its own message?
Wait a minute, you might think — creating three unique projections sounds doable, but opposite faces would mirror each other, right? Not necessarily. I’d previously figured out how to make double-sided QR codes that can display different messages depending on the orientation, thanks to error correction. This trick works well for short messages (under, like, 8–11 characters), though some QR readers might struggle to interpret them.
Building the Cube: 3D challenge
The main question became: could we combine three pairs of projections along different axes, so all six QR codes would display as intended?
To do this, imagine having three projection candidates and needing to check if they’re compatible. If a cell on a projection is white, then every cell in that column should be white to avoid casting shadows. So, we start with a fully filled cube and erase rows or columns where a projection cell is white. If, after this, enough black cubes remain to cast the necessary shadows, the projection candidates work together.
Projection candidates
The next step was to generate compatible projection candidates, which required a bit of creativity. To maximize possible combinations, I looked at padding options for each QR code. For instance, imagine I wanted to put the message “ONE” on one side of the cube and “TWO” on the opposite side. If I pad “TWO” with spaces on either side, I could create slight variations such as “TWO_____“, “_TWO____“, etc. I do the same for “ONE” at the same time, so it several hundreds of suitable codes — each unique padding arrangement yielded a distinct “double-sided” QR code.
Repeating this for 3 pairs of messages (ONE+TWO, THREE+FOUR, FIVE+SIX), I ended up with 216, 134, and 186 combinations correspondingly. Altogether, it gives us 5+ millions of configurations to test. While this sounded overwhelming, brute-forcing through these combinations revealed that around 1 in every 200 combinations produced a compatible result.
The First Combination & Beyond
If you’d like to try it out yourself, here’s an interactive demo showcasing my first working combination.
Too lazy to try a QR reader? No problem; you can watch my quick 42-second video.
After finding first solutions, I wondered: can we achieve the same effect with fewer cubes? Starting with about 1,700 cubes (in an average solution), I applied a greedy algorithm, deleting cubes one by one until no more could be removed without disrupting the projections. The result: a minimalist cube with just 375 cubes, readable from all six sides — though it looks a bit rough, like an unfinished Death Star:
Bonus: minimal, aesthetic solutions
Reducing cube count further posed a new question: how to create a visually balanced cube without sacrificing readability. A quick test with random sequences reduced the cube count to 294, yielding a much more appealing structure.
For anyone up for the challenge, feel free to explore further and find even better solutions. The code for experimenting with these cube combinations is on GitHub.