static-qr-code-generation
Installation
SKILL.md
Static QR Code Generation for HTML Assets
Problem
Custom inline JavaScript QR code generators (implementing Reed-Solomon error correction, module placement, and masking from scratch) are fragile. A single bit error in format information, version data, or mask pattern produces a QR code that looks correct visually but won't scan. Debugging these ~200-line implementations is impractical.
Context / Trigger Conditions
- QR code renders visually in the page but phone cameras/scanners can't decode it
- Hand-written QR generator using inline
<script>in an HTML file - The encoded URL is fixed (not dynamic/user-dependent)
- Marketing posters, event flyers, landing pages, or any static HTML asset
Solution
Step 1: Generate a static SVG using the qrcode npm library
# Install temporarily (don't add to project dependencies)
npm install qrcode
# Generate SVG with custom colors and cell size
node -e "
const QRCode = require('qrcode');
QRCode.toString('https://example.com', {
type: 'svg',
color: { dark: '#1A1613', light: '#F5F0E8' },
width: 200,
margin: 0,
errorCorrectionLevel: 'M'
}, (err, svg) => {
if (err) throw err;
process.stdout.write(svg);
});
" > /tmp/qr-output.svg
Key options:
color.dark/color.light: Match your design's color palettewidth: Pixel size of the output SVGmargin: Quiet zone modules (0 if your HTML provides its own padding)errorCorrectionLevel:L(7%),M(15%),Q(25%),H(30%) — useMfor print
Step 2: Embed the static SVG directly in HTML
Replace the empty container + JS generator:
<!-- Before: runtime generation (fragile) -->
<div id="qr-code"></div>
<script>/* 200 lines of QR encoding... */</script>
<!-- After: pre-generated static SVG (reliable) -->
<div id="qr-code">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" ...>
<!-- paste SVG contents here -->
</svg>
</div>
<!-- QR code: static SVG generated by qrcode library, encodes https://example.com -->
Step 3: Verify scannability
# Install zbar (QR decoder)
brew install zbar # macOS
# apt install zbar-tools # Linux
# Take a screenshot of the rendered page, then decode
zbarimg --raw -q screenshot.png
# Should output: https://example.com
Step 4: Clean up
# Remove the qrcode package (not needed as a project dependency)
npm uninstall qrcode
# Revert package.json / package-lock.json if changed
git checkout -- package.json package-lock.json
Verification
zbarimgdecodes the correct URL from a browser screenshot- Physical phone camera scan works at the rendered size
- No runtime JavaScript errors in console (since there's no JS)
Example
Applied in the Joe Speaking Japan launch poster (japan-launch-poster.html):
- Replaced ~200 lines of inline JS (GF arithmetic, Reed-Solomon, module placement, masking)
- Generated 200x200 SVG with
#1A1613on#F5F0E8(dark charcoal on warm cream) - Encodes
https://joespeaking.com/ja - Result: 2 lines of HTML + embedded SVG vs 200 lines of buggy JavaScript
Notes
- Static SVGs only work for fixed URLs. If the URL is dynamic (user-specific, session-based), you still need runtime generation — but use a proven library like
qrcodeloaded via CDN, not a hand-rolled implementation. - SVG vs Canvas: SVG scales perfectly for print (vector). For raster export, the browser renders the SVG at whatever resolution you need.
- Cell size matters for scanning: At print sizes, ensure individual QR modules are at least 2-3mm. For a 180x180px QR on a 2160px-wide poster, that's fine for standard print (300dpi).
- Error correction level M is the default sweet spot: 15% error tolerance handles minor print artifacts without making the QR overly dense.
References
- qrcode npm package — battle-tested QR generation library
- zbar — open-source barcode/QR decoder for verification
- QR Code specification: ISO/IEC 18004:2015