# Static Qr Code Generation

> Fix unscannable QR codes in HTML posters, marketing assets, and static pages. Use when: (1) a custom inline JavaScript QR generator produces codes that won't scan, (2) you need a QR code for a fixed/known URL in a static HTML file, (3) debugging Reed-Solomon or masking bugs in hand-rolled QR generators. Solution: replace runtime JS generation with a pre-generated static SVG from the `qrcode` npm library, then verify with `zbarimg`.

- Skill: `hubeiqiao/static-qr-code-generation` (Agent Skill)
- Install (CLI): `npx skillmds@latest add hubeiqiao/static-qr-code-generation`
- Raw SKILL.md: https://api.skillmd.com/api/skills/hubeiqiao/static-qr-code-generation/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: hubeiqiao (https://skillmd.com/u/hubeiqiao)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/hubeiqiao/static-qr-code-generation

---


# 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

```bash
# 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 palette
- `width`: Pixel size of the output SVG
- `margin`: Quiet zone modules (0 if your HTML provides its own padding)
- `errorCorrectionLevel`: `L` (7%), `M` (15%), `Q` (25%), `H` (30%) — use `M` for print

### Step 2: Embed the static SVG directly in HTML

Replace the empty container + JS generator:

```html
<!-- 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

```bash
# 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

```bash
# 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
1. `zbarimg` decodes the correct URL from a browser screenshot
2. Physical phone camera scan works at the rendered size
3. 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 `#1A1613` on `#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 `qrcode` loaded 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](https://www.npmjs.com/package/qrcode) — battle-tested QR generation library
- [zbar](https://zbar.sourceforge.net/) — open-source barcode/QR decoder for verification
- QR Code specification: ISO/IEC 18004:2015

