Case Study
Qrgen
“A fast, privacy-first QR studio—premium styling and logo embedding without paywalls, watermarks, or noise.”
Role
Product, design, and engineering (solo)
Duration
Ongoing · open source
Path
~/projects/qrgen
Tech Stack
Vue 3, TypeScript, Vite, Tailwind CSS, DaisyUI, qr-code-styling, VueUse, vue-advanced-cropper, Lucide

Summary
I built QRGen as a performance-minded, privacy-centric web app for creating and styling QR codes. I was tired of the "utility app" trap—paywalls, watermarks, ad clutter, and capped exports—so I shipped a free, open tool that still feels premium: logo embedding, advanced visuals, and a UI I'd put in front of a client.
Problem
The QR space is full of half-solutions: "free" generators that watermark downloads, cap resolution, or hide basic styling behind subscriptions; cluttered interfaces built for ad inventory, not clarity; and hosted flows that ask you to trust an opaque backend with the very URLs and text you're encoding. For anyone shipping branded materials—or just caring about privacy—that's a frustrating set of tradeoffs.
Role and scope
Role Product, design, and engineering (solo)
Duration Ongoing · open source
Process and decisions
Styling without breaking scannability
Gradients, dot styles, and logo overlays look great until they don't scan. I had to balance expressiveness with contrast, quiet areas around the finder patterns, and logo sizing—then keep checking real-world scans, not just the preview.
"Premium" UX with a zero-friction promise
Advanced controls can read as complexity. I focused on progressive disclosure—accordions/tabs, clear grouping—so beginners get a fast path while I still expose granular control over eyes, dots, and color.
A privacy story that matches the implementation
I only wanted to claim client-side generation if the architecture backed it: generation and export stay in the browser, dependencies stay purposeful, and the baseline avoids invasive analytics. That consistency became part of the product, not a footnote.
Solution overview
QRGen is how I chose to invert that model: no ads, no accounts, no server-side generation of your content. I built it as a Vue 3 + Vite + TypeScript app with a dual-pane workflow—controls on one side, a live preview on the other—using qr-code-styling for the hard parts (rounded modules, gradients, reliable rendering). I treated branding as a first-class flow: upload a logo, crop it in place, and keep scan reliability in mind with sensible defaults. The result is a tool that feels like a small studio product while staying MIT-licensed and inspectable on GitHub.
Key takeaways
- I paired a sharp problem (utility category fatigue) with a sharp constraint: client-side, no account wall.
- I let a focused library own rendering complexity and spent my time on preview speed and exports I'd trust.
- I treated discoverability of advanced features as part of polish—styling power shouldn't mean a confusing layout.
- I shipped MIT licensing so privacy and behavior are things people can verify, not just copy on a landing page.