Templates can now render QR codes alongside the Code 39 / Code 128 barcodes we shipped earlier today. The new qr() DSL builder produces QR codes as native PDF vector graphics — no font to embed, no image to fetch, no rasterisation.
qr("https://pay.example.com/inv/{{invoice.number}}", {
ecc: "M", // "L" | "M" (default) | "Q" | "H"
size: 120, // total width/height in pt (square)
alt: "Scan to pay invoice {{invoice.number}}",
});
The value accepts {{template}} placeholders and resolves at render time, so the same template renders a different code for every payload. The encoder auto-selects the smallest QR version that fits (21×21 up to 177×177 modules), picks the most efficient encoding mode (numeric, alphanumeric, or UTF-8 byte), and chooses the lowest-penalty mask per the ISO/IEC 18004 spec.
Pick the error-correction level for the conditions the code will live in: L for clean on-screen URLs, M (default) for everyday print, Q for receipts and dim lighting, H for thermal labels and anywhere damage is likely. Higher ECC means a larger symbol for the same payload — aim for a module width of at least 1pt so phone cameras can resolve it reliably.
The three invoice templates in the library (Classic, Modern, Compact) now include a "scan to pay" QR next to their payment-instructions block. Skill: see pdf-template-author.md §QR Codes.