PixelQR

Paint pixel art. It becomes a real, scannable QR code — the art is the code.

Canvas

drag to paint · right-click = erase · ctrl+z = undo
Generation
Brush
Surface
Style
Presets
Image
Canvas

The dashed outline is your free surface — everything inside is guaranteed clean: no random code cells, what you paint is what scans. The faint-diagonal ring around it is the QR's own machine zone (plus the fixed finder/timing skeleton): the code's randomness lives there, never inside your surface. Red dots mark ink that didn't fit — switch to a higher version for a bigger surface, or erase it.

The ordinary QR code. Any phone camera reads it.

Your QR

How does this work?

A QR code at error-correction level H is built to survive up to ~30% damage — that tolerance is a budget, and PixelQR spends it to make one region of the code fully yours: a free surface where every cell is pinned to your drawing (ink dark, background light). The code's own random cells are pushed outside it into the ring — they're what keeps every link unique, and they never mix with your art. What you paint is what scans.

  • Free surface (dashed outline) — the shape you choose, sized from the available code budget, guaranteed to end up 100% free of random code cells. A square, a circle or a cross; bigger versions buy a bigger surface (v3 ≈ 13×13 cells, v4 ≈ 17×17, v5 ≈ 19×19, v6 ≈ 23×23 for this link length; a shorter link buys more). If a pattern is stubborn, the surface steps one cell smaller until the guarantee holds — it never shows noise.
  • The code ring — everything outside the surface (faint diagonal) is the QR's machine zone: finder patterns, timing, and the random data cells carrying your link plus the digital signatures that make it decode. Its randomness is what makes the code unique.
  • Free payload bits — the pad codewords after the payload terminator are never read by decoders. The app solves them with linear algebra (same family of trick as QArt/QArtText codes) to pin another batch of surface cells exactly — 16 free bits at v3, 96 at v4, 176 at v5 — spending no scan margin at all.
  • Styled rendering — dots or rounded tiles with rounded finders, the look commercial design-QR generators use to calm the noise down. Every style is verified by decoding the styled render itself (crisp and blurred), so the pretty version is the scannable version.
  • Sacrificed codewords — every 8 module bits form one codeword. Flipping the codeword's bits costs the decoder only one error, so each sacrificed codeword pins a whole batch of surface cells.
  • Pattern-fit search — the popup pattern is determined by the link and the mask. The app quietly tries variant encodings and all 8 masks, then keeps the one whose free cells fit your drawing best (the tiny #x fragment it may add to your link only changes the anchor, not the page).
  • Live verification — after every edit, the code is decoded in your browser with a real QR decoder (jsQR), both crisp and blurred/shrunk to simulate scanning at a distance. If it fails, the flip budget is auto-trimmed until it passes.
  • Red dots in the canvas mark ink that didn't fit the budget — that's your cue to switch to a higher version (bigger surface) or simplify that area.
  • Round profile pictures — a profile picture is a circle, and a circle has no corners, so the three finder patterns of a square QR sit exactly where a circular crop would eat them. In standard mode the QR is inscribed in the circle, so every eye stays inside it and any phone reads it. In custom mode the grid is a disc and the eyes sit inside it, so the code fills the circle edge to edge — at the cost of no longer being a standard QR.

Everything runs in your browser — no server, no uploads. Built on qrcode-generator (MIT) and jsQR (Apache-2.0). Point your phone's camera at the preview to scan it.