Sep 27, 2024 - Updated Jun 13, 2026
Nobody willingly goes out of their way to scan a QR code. Yet they have infested the world, because it’s the simplest way to visually share a URL. On signs, advertisements, and packaging of all sorts; if you look around and try to notice, it’s hard to stop noticing.
Of course, regular black and white QR codes are just the tip of the iceberg.
Many people want something personalized and on-brand, which is easily done by slapping a logo right in the middle. This is possible because QR codes, like CDs and DVDs, use Reed-Solomon error correction to recover damaged information.
While this can be executed with taste, it’s most often done lazily to poor effect.



QR codes are displayed small, and illegible logos are the rule. Moreover, more error correction requires a denser code with smaller pixels. If you’re not careful, you can end up with something ugly as well as impossible to scan.
Is there a way to craft a beautiful and scannable QR code?
Yes, that’s the whole blog post.
First, let’s cover what is possible.
Many have incorporated photos into the entire code. But there is a real tradeoff between image quality and usefulness.
For maximum style points, artists can design fully bespoke QR codes by hand.
There’s AI for this too. I recommend reading the creators’ blog post and Stable Diffusion QR Code 101. I’ll omit examples and leave a poem in their place.
I shall not beleaguer thy weary eyes,
nor further burden the web, world wide,
with pages from this Babelian picture tome.
This is not a place of honor,
there are thirteen fingers on her,
anime girl big boobs ancient rome.
One interesting direction is to simply change how the black and white squares are rendered.
I was so inspired that I wrote some code myself.


The design tool I made is available at qrframe.kylezhe.ng. It comes with presets that are simple to modify or create from scratch using Javascript.
With that, you have glimpsed a breadth of techniques, many of which will confuse users, some of which may fail to work with the modern smartphone camera app.
To truly understand where and why we can take creative liberties, we must start with how QR codes are structured and scanned.
Header
Data
Unused capacity
Error correction
Here’s all you need to remember to make an artistic QR code: the finder patterns must be the right shape, and the rest of the QR code just needs to be dark or light enough in the right place.
That’s 80% of it, but unfortunately there’s one major gotcha we’ve gotta cover.
Can you tell what I did wrong with these QR codes I drew using chalk?
Attempt 1 (terrible)
Attempt 2 (still unscannable)
The first one is janky, but I was legitimately confused why my second attempt failed.
Multipurpose scanners (like the default smartphone camera app) must first detect a QR code before any scanning is attempted. Compared to constantly active dumb scanners, smartphones are much pickier about what they’ll accept. It must “look like a QR code” to the black box that is the on-device computer vision model.
A rule of thumb is to use solid and highly contrasting colors while maintaining a good balance between dark and light pixels, but there’s no alternative to testing with real devices.
With that in mind, let’s cover existing ways people have successfully created artistic codes programmatically.
Created using Amazing-QR
In the simplest case, you can just place dots over the center of where each pixel would be. A dot at least 1/3 the width and height of a pixel is usually enough for it to decode properly.
Created using Visualead
In addition to a center dot, you can partially lighten or darken the entirety of each pixel.
By downscaling the image or using pixel art, the center dot can be hidden in plain sight. Dithering and limiting the color palette (quantization) both increase noise which also provides more camouflage.
The most unique technique I've seen involves generating word clouds. In this case, the overlay dots are used in an intermediate step to drive a text deforming algorithm.
The jump to animation is simple, since the same dot overlay can be drawn on each frame. This example changes over time to display the lyrics though.
Using up error correction capacity is obviously not ideal, but it’s also space inefficient. The correction capacity only increases by one byte for every two error correction bytes. And of course, some capacity has to be reserved for actual scanning errors, so the drawable area is quite limited.
The benefit is that the error correction process fixes errors at unknown locations, but what if we know where we want to introduce changes?
The data of a QR code is made up of message bytes and its corresponding error correction bytes. Any part of the message can be freely set, but changing the message defeats the purpose of a QR code.
Luckily, short messages are padded to fill up the capacity, and the padding can be freely set without changing the decoded content.
Since the error correction is calculated from the message, is there a way to calculate a message based on desired error correction? Yes, because Reed-Solomon codes are Maximum Distance Seperable (MDS) codes. We can solve a linear system to find the padding value that leads to an error correction byte.
Created using QArt Coder
URLs can have anchors like test.com#anchor. Usually, this scrolls to a specific part of a page, but an invalid anchor is just ignored. The math used to manipulate pixels by adding an anchor is covered in QArt Codes.
Created using MY-QR.ART
This site lets you draw the desired output data, which can be directly interpreted as part of the input text. The first half of the text is the url to a link redirect service and the random characters that follow act as a unique key. For details, see Hacking QR code design.
Created using QRpicture
Here, the data pixels match an image, but they are not part of the decoded message. In other words, they are changing the padding bytes. See their HN post.
(This padding manipulation method was first described in Expansion of Image Displayable Area in Design QR Code and Its Applications, 2011.)
In terms of animation, reverse-engineering the data for every "frame" is a bit more tedious, and the QR code is unlikely to be scannable. See their behind the scenes video to see how they approached it.
I ended up making my own reverse-engineered Bad Apple with the goal of making it somewhat scannable in realtime. Adding a noisy pattern makes it much more likely to be detected. The source code is an example in fuqr.
Since there aren’t too many examples of these, I’ll be showing my own work and giving my thoughts.
While each unique design will have unique challenges, hopefully these examples can give you some some idea of steps you can take.
Good artists copy. Often times human-made designs are possible to implement using code. Here, Douglas Coupland has replaced 2x2 squares of black and white with a corresponding dark or light colored square. Not only is this easy to code, it demonstrates a common tactic of replacing groups of pixels with a larger design element. See Vancouver Codes (2012) for more examples of his work.
Great artists steal. The original design is slick, but not all that glitters is a scannable QR code. When things don’t scan, experience tells us that we need solid colors and higher contrast. I opted to increase the dot size and density, especially for the finder patterns, and I filled the gap between dots with a dark shadow. This is less pretty, but a necessary compromise.
Great programmers steal by copying code. This QR code style option, along with many others, is found in the react-qrbtf repository under the MIT license. Building on top of existing code is a great way to make a new design, so feel free to use my code in the qrframe repository as well. The psychological damage you’ll suffer is cost enough.
Pathetic human attempt
Of course I had to digitally create what I failed to do in real life. With the help of roughjs, making hand-drawn SVGs is quite simple. Playing with the fill and roughness parameters really helped me understand where the line between undetectable and reliably scannable is. My manual drawing was not even close. I cannot overemphasize solid colors and high contrast.
Mosaic inside the Vatican museum
Exposure to all types of art is probably the best source of creative energy. The design is quite simple, but the effect is mighty like the elephant. If there’s a lesson to be learned here, it’s that rules are made to be respectfully broken. You CAN mess with the finder patterns, but notice how the cross shape is completely preserved in two of them.
The Mediterranean Sea
Created using fuqr
Animation is generally a bad idea since you want every frame to be scannable. But the call of the sea is unrelenting. In this example, each pixel only changes in scale, and the center 1/3 of each pixel is always the correct color like in the dot overlay technique. And that’s the final lesson, that none of these techniques are mutually exclusive.
Congratulations, you now know too much about QR codes!
I hope you learned something interesting, even if it’s not useful.
If you’d like to design a QR code, and you’re not afraid of writing a little code, give qrframe.kylezhe.ng a try.
The editor and rendering source code is available at qrframe while the QR code generator written in Rust that powers it is available at fuqr.
You can do it if you try, but also your time is precious.
See ya!
Here are some QR code thoughts I had to get off my mind.
There are many, there are 4, there is 1 encoding mode.
The mask selection step is deeply unserious.
Proprietary scannable codes are kinda funny. Tiktok, Snapchat, and Instagram have already replaced their custom codes (TikCode, Snapcode, Nametag, respectively) with stylized QR codes. 
Here are links I don’t want to lose.
