What if my contribution graph was a QR code? Same green squares, same commit rhythm scan it and it opens the profile. I couldn't stop thinking about it.
made this as a fun weekend project. It pulls a public GitHub heatmap and maps it onto a QR and also actually scans (hopefully).
what an export looks like, with labels >.<
paste a url. watch the board fill in.
GitQR grabs your public contribution calendar and encodes the profile URL into a version-4 QR at error correction level H.
Version 4 is a 33×33 module grid, the smallest symbol that still fits a github.com/username link at level H. Level H is the highest error-correction tier: roughly 30% of modules can be restyled and decoders still recover the URL.
Every dark module in that matrix gets a color from your heatmap. Column maps to week. Row maps to weekday. Intensity maps to how hard you were coding that day.
GitHub's calendar is ~53 weeks wide; the QR is 33 columns. Linear resampling maps each module to a heatmap cell, so nearby weeks can collide on the same level:
where
The position on the board is the position in your graph. Same grid logic, different job.
flowchart LR
url(["github.com/you"])
heatmap["heatmap<br/>weeks × 7"]
matrix["QR matrix<br/>33 × 33"]
same{{"same cell"}}
board(["styled board"])
url --> heatmap
url --> matrix
heatmap --> matrix
heatmap --> same
matrix --> same
same --> board
classDef pink fill:#FB70B3,color:#ffffff,stroke:#FB70B3
classDef white fill:#ffffff,color:#FB70B3,stroke:#FB70B3
class url,heatmap,matrix,board pink
class same white
The hard part is making it scannable while keeping the illusion.
GitQR tries all eight QR mask patterns and picks whichever keeps dark modules darkest on average. Pale colors on dark cells get a heavy penalty and kill phone reads.
Zero-contribution days that land on dark modules get forced to mid-gray instead of your palette's lightest swatch, so scanners can still separate them from the white background. Swapping palette doesn't re-encode.
The nav Scan QR button decodes the live board in the browser, the same way an export would be read, but without leaving the page.
Flip scan mode and the playground dims the board, frames the QR region, and preloads the decoder WASM. Click the code and GitQR rasterizes the current styled grid to a canvas bitmap, runs decode on that ImageData, and opens the recovered URL in a new tab if it matches what you encoded.
Decode is two passes on that bitmap:
- Fast pass - square black/white modules only, contribution colors stripped. Most styled QRs decode here.
- Styled fallback — full colors, gaps, and roundness at higher resolution, with rotation, inversion, and downscale enabled if the fast pass misses.
Engines run client-side in order: @qrstuff/qured, then zxing-wasm as backup.
Any failure tells you on the board before you export or share.
three things once you're on the board
|
scan
|
tune
|
export
|
components adapted from Fluid Functionalism by @micka_design
cat design inspired by Icons8 illustrations

