Branded QR code generator + short-link layer for every LVRN release, video, EPK, merch drop, event, and campaign across the entire roster.
Live tool: https://qrcode.lvrn.dev Short links: https://r.lvrn.dev/``
A full release-ops utility, not a generic QR widget. Every code is tied to an artist + a content type, optionally routed through a changeable short-link, branded with the LVRN mark (or a custom logo), and exported in every format the campaign needs.
Built for LVRN's internal use across the full roster — every LVRN signee plus the house mark itself.
The QR can encode r.lvrn.dev/<slug> instead of the raw DSP/EPK URL. The slug is mapped to the real destination in redirects/links.json. That means:
- You can reprint nothing. Spotify link, YouTube ID, merch URL — change any of them in
links.jsonand every QR already in the wild (posters, vinyl inserts, merch tags, billboards) points to the new destination on the next scan. - Every scan is a single owned hop — you can wire analytics or A/B routing in later without re-pressing.
- Slugs read like English —
r.lvrn.dev/alxapo-lobola-sznbeats a 90-char Spotify URL on any printed surface.
The "Use r.lvrn.dev short-link" toggle in the UI is off by default — direct URL is the safe choice until a slug is registered in links.json.
| Piece | Path | What it is |
|---|---|---|
| Web app | web/ |
Static site. HTML + vendored JS. Deployed to qrcode.lvrn.dev (Vercel). |
| Short-link redirector | redirects/ |
One serverless function + links.json. Deployed to r.lvrn.dev (separate Vercel project). |
| Python CLI | cli/ |
Batch generator for full campaign rollouts. |
| Registry | releases.json |
Append-only ledger of every QR ever generated by the CLI. |
All client-side. No backend, no database, no auth, no API keys. Browser localStorage holds the per-session web app registry; the CLI writes a versioned JSON file you can commit.
- Artist name + content type (Single / Album / Video / Pre-Save / EPK / Merch / Event / Social / Custom)
- Campaign tag → auto-generates a slug:
artist-type-tag - Manual override of slug at any time
- Module shape — Square / Rounded / Dots / Classy / Classy Rounded / Extra Rounded
- Corner shapes (outer + inner) controlled independently
- Custom dark + light colors via color pickers
- Error correction levels L / M / Q / H (H = 30%, default — needed for logo embed to still scan)
- LVRN mark embedded in center by default
- Upload any PNG / SVG / JPEG as a per-campaign logo
- One-click reset to LVRN mark
- Toggle embed on/off entirely
- PNG — 1024² crisp render
- SVG — true vector, scales to anything
- PDF — A4 portrait, print-ready, crop marks + artist title + scan caption + LVRN footer
- Multi-size .zip — one click delivers:
- 1024 PNG (social)
- 2048 print PNG
- SVG (vector)
- 1080×1920 story (QR on LVRN branded backdrop)
- 1080×1080 social square (branded)
manifest.jsonwith all metadata
- Live restyle — change any control, preview updates immediately
- Share link — copy a
?a=…&t=…&u=…URL that regenerates this exact QR with all settings (great for handoff to designers / handing the link to artists) - Local registry — per-browser session list of generated QRs, persisted in localStorage
- Keyboard shortcuts — ⌘↵ Generate · ⌘S Save · ⌘D Download PNG
- Toggle to encode short-link instead of direct URL
- Slugs mapped in
redirects/links.json - 302 redirect via Vercel serverless function — ~300ms p99 globally
- 404 page is LVRN-branded if a slug doesn't exist
cd web
python -m http.server 5560
# open http://localhost:5560That's it. No build step, no node_modules. The page pulls libraries from web/vendor/ and the LVRN logo from web/assets/logos/lvrn.svg.
cd cli
pip install -r requirements.txt
# single QR
python lvrn_qr.py generate \
--artist alxapo \
--type single \
--title lobola-szn \
--url https://open.spotify.com/track/EXAMPLE
# whole campaign rollout from CSV (artist,type,title,url[,ecc])
python lvrn_qr.py batch example-releases.csv
# show recent
python lvrn_qr.py registry --limit 50Output PNG + SVG files land in out/. The registry (releases.json) and short-link map (redirects/links.json) update automatically.
The web app and the redirector are two separate Vercel projects, deployed independently.
cd web
vercel --prod --yes --force(Domain qrcode.lvrn.dev is already attached to the lvrn-qr Vercel project.)
cd redirects
vercel --prod --yes --force(Domain r.lvrn.dev is attached to the lvrn-redirects Vercel project.)
Two files are gitignored because they contain live LVRN data:
redirects/links.json— the short-link → destination map (active production routes)releases.json— the CLI's all-time ledger of generated QRs
Both have committed .example.json siblings showing the shape. On a fresh clone, copy them:
cp redirects/links.example.json redirects/links.json
cp releases.example.json releases.jsonThen add your real entries locally. The Python CLI writes to these files automatically.
Edit redirects/links.json:
{
"alxapo-lobola-szn": "https://open.spotify.com/track/REAL_ID_HERE"
}…then redeploy the redirects/ project. The Python CLI does this automatically every time you generate a QR.
The web app accepts any free-text artist name — type it into the Artist field and the slug auto-generates. Nothing to configure.
The Python CLI reads its roster from web/artists.json. To add an artist, append an entry:
{
"roster": [
{ "slug": "lvrn", "name": "LVRN", "color": "#ffffff", "accent": "#000000" },
{ "slug": "example", "name": "Example Artist", "color": "#0fb8a4", "accent": "#ff6b1a" }
]
}Fields:
slug— kebab-case identifier, used as the URL slug prefix (example-single-summer-drop)name— display name, appears on PDF exports and registry entriescolor— primary brand color (hex)accent— secondary brand color (hex)
The CLI will now accept --artist example and use that brand color when rendering.
The repo ships with a starter
artists.jsoncontaining only the LVRN house mark and one example entry. The full LVRN roster is added locally and is not published here.
lvrn-qr/
├── web/ # static web app (qrcode.lvrn.dev)
│ ├── index.html # full UI + behaviour in one file
│ ├── vendor/ # self-hosted libraries (no CDN dependency)
│ │ ├── qr-code-styling.js # QR rendering with style controls
│ │ ├── gsap.min.js # animations
│ │ ├── jszip.min.js # multi-size pack export
│ │ └── jspdf.umd.min.js # PDF export
│ ├── assets/logos/lvrn.svg # the LVRN brand mark
│ ├── artists.json # roster (informational)
│ └── vercel.json # cleanUrls config
│
├── redirects/ # short-link layer (r.lvrn.dev)
│ ├── api/redirect.js # 302 redirect serverless function
│ ├── links.json # slug → destination map
│ ├── index.html # landing page (redirects to qrcode.lvrn.dev)
│ ├── package.json # ESM module flag
│ └── vercel.json # rewrites + host matching
│
├── cli/ # Python batch generator
│ ├── lvrn_qr.py # generate / batch / registry commands
│ ├── requirements.txt # qrcode[pil] + Pillow
│ └── example-releases.csv # sample CSV for batch
│
├── releases.json # all-time registry (CLI-written)
├── README.md # this file
├── LICENSE # proprietary — see below
└── .gitignore
Phase 2 (not yet shipped):
- Bulk web mode — paste a list of URLs or drop a CSV in the browser, get a zip back
- Spotify / Apple URL auto-detect — paste a DSP link, auto-fill artist + cover art
- Poster composition templates — QR auto-placed on artist cover-art style backgrounds (sized for IG, TT, A4, vinyl insert, gig poster)
- Team-wide shared registry — optional Supabase backend so the whole LVRN team sees the same QRs (currently per-browser only)
- Scan analytics — privacy-safe counters per slug, no cookies
Proprietary. See LICENSE.
This is exclusive LVRN tooling. Public visibility of the repo is for transparency / team collaboration — it is not an invitation to reuse, fork for commercial use, redeploy, or rebrand. Brand assets remain owned by their respective artists.
Licensing inquiries: moses@lvrn.com
Built and maintained by Moses Mawela · LVRN / Love Renaissance.