Appearance
@carrot/qr β
ts
Zero-dependency QR code encoder. Handles version selection, encoding mode detection, ReedβSolomon error correction, matrix construction with masking, and a pixel grid for renderers.
Installation β
ts
import { create, createGrid } from '@carrot/qr';Zero dependencies. Works in browser and Node.
Architecture β
Encoding Pipeline β
text β detectMode β getBestFitVersion β buildBitstream β splitBlocks
β generateEccBlocks (ReedβSolomon) β interleave β bytesToBits
β buildMatrix (placement + masking) β QrCode- Mode detection - auto-selects Numeric, Alphanumeric, or Byte based on input characters
- Version selection - finds the smallest version (1β40) that fits the data at the chosen ECC level
- Bitstream - encodes data with mode indicator, character count, and padding
- Block splitting - divides codewords into groups per the spec's block structure tables
- ReedβSolomon - generates error correction codewords per block using GF(256) polynomial division
- Interleaving - interleaves data and ECC blocks for burst error resilience
- Matrix building - places function patterns (finders, timing, alignment, format/version info), then data bits in the zigzag pattern, applies all 8 mask patterns, scores each, and selects the best
Module Types β
Every cell in the matrix is typed (ModuleType) so renderers can distinguish data modules from function patterns. This enables styled rendering - e.g. different colours for finders vs data, or skipping function pattern cells for custom finder rendering.
Pixel Grid β
createGrid() converts the module matrix into a QrPixelGrid with cardinal neighbour lookup (north/south/east/west, hasDarkNorth/South/East/West). This is the interface renderers use - neighbour awareness enables smooth/rounded rendering styles without re-scanning the matrix.
File Structure β
src/
βββ index.ts # Public API barrel
βββ create.ts # create(), createFromBytes(), createGrid()
βββ types.ts # Enums, QrCode, QrModule, QrPixel, QrPixelGrid
βββ encoding/
β βββ mode-detect.ts # Auto-detect numeric/alphanumeric/byte
β βββ data-tables.ts # Version capacity tables, ECC block structure
β βββ bitstream.ts # Data bitstream encoding
β βββ bit-buffer.ts # Bit-level buffer utilities
β βββ blocks.ts # Block splitting + interleaving
β βββ reed-solomon.ts # GF(256) ReedβSolomon ECC
βββ matrix/
β βββ placement.ts # Function pattern placement + data zigzag
β βββ builder.ts # Full matrix build + mask selection
β βββ masks.ts # 8 mask pattern implementations
β βββ format-info.ts # Format + version info encoding
βββ rendering/
βββ pixel-grid.ts # QrPixelGrid with neighbour lookupDependencies β
None.
Build β
bash
npm run buildCompiles TypeScript to ESM via tsc. Output lands in dist/.
Using @carrot/qr β
Zero-dependency QR code encoder with typed pixel output for custom rendering.
Import β
ts
import { create, createGrid, ErrorCorrection } from '@carrot/qr';Common Patterns β
1. Encode a URL β
ts
const code = create('https://example.com');
// code.version, code.size, code.modulesDefault ECC is Low. Use High if you plan to use a center cutout (logo overlay):
ts
const code = create('https://example.com', ErrorCorrection.High);2. Direct pixel access β
ts
for (let y = 0; y < code.size; y++) {
for (let x = 0; x < code.size; x++) {
if (code.pixel(x, y)) {
// dark module at (x, y)
}
}
}3. Pixel grid with neighbours β
For renderers that need neighbour awareness (rounded corners, smooth blobs):
ts
const grid = createGrid(code);
for (let y = 0; y < grid.size; y++) {
for (let x = 0; x < grid.size; x++) {
const pixel = grid.pixels[y][x];
if (!pixel.isDark) continue;
// Neighbour checks for smooth rendering
const hasTop = grid.hasDarkNorth(x, y);
const hasRight = grid.hasDarkEast(x, y);
// Full neighbour pixel (or null at edges)
const above = grid.north(x, y);
}
}4. Encode raw bytes β
ts
import { createFromBytes } from '@carrot/qr';
const payload = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
const code = createFromBytes(payload, ErrorCorrection.Medium);5. Module type inspection β
Each module carries its type - useful for styled rendering:
ts
import { ModuleType } from '@carrot/qr';
for (const row of code.modules) {
for (const mod of row) {
if (mod.type === ModuleType.Finder) {
// draw finder pattern differently
}
}
}6. Use with the Vue renderer β
ts
import { CarrotQr } from '@carrot/qr-vue';vue
<CarrotQr url="https://example.com" variant="smooth" :cutout="0.2">
<img src="/logo.svg" />
</CarrotQr>Error Correction Levels β
| Level | Recovery | Use Case |
|---|---|---|
Low | ~7% | Maximum data capacity |
Medium | ~15% | General purpose |
Quality | ~25% | Moderate damage tolerance |
High | ~30% | Best for logo overlays / center cutouts |
Tips β
- Use
HighECC with center cutouts - the cutout destroys modules, so you need the extra error correction capacity. createGridis optional - only needed if your renderer uses neighbour awareness. For simple pixel-on/pixel-off rendering,code.pixel(x, y)is sufficient.- Version auto-selects - the encoder picks the smallest QR version (1β40) that fits your data at the chosen ECC level.
Package Contents β
@carrot/qr-vue β
Import: import { ... } from '@carrot/qr-vue';
Vue Component β
CarrotQr - renders a QR code to canvas with reactive prop-driven updates.
| Prop | Type | Default | Description |
|---|---|---|---|
url | string | required | Text or URL to encode |
w | number | string | 200 | Width in CSS pixels (retina rendered at 2x) |
ecc | 'low' | 'medium' | 'quality' | 'high' | 'high' | Error correction level |
variant | 'basic' | 'dots' | 'smooth' | 'smooth' | Render style |
fg | string? | CSS --qr-fg or '#ffffff' | Foreground colour |
bg | string? | CSS --qr-bg or 'transparent' | Background colour |
accent | string? | CSS --qr-accent or fg | Accent colour (finders + alignment) |
cornerRadius | number | string | 0.4 | Corner radius (0β0.5) |
dotSize | number | string | 0.75 | Dot size fraction (dots variant, 0.3β1.0) |
cutout | number | string | 0 | Centre cutout size (0β0.4, fraction of QR size) |
finderStyle | 'square' | 'rounded' | 'circle' | 'circle' | Finder pattern style |
finderColor | string? | accent | Finder pattern colour override |
Slot: Default slot content is rendered as an overlay in the centre cutout area.
CSS custom properties: --qr-fg Β· --qr-bg Β· --qr-accent (read from the canvas element)
Renderer β
renderToCanvas(canvas, code, grid, opts?) - render a QR code onto a canvas element. Returns the canvas.
renderToOffscreen(code, grid, size, opts?) - create and render to a detached canvas.
Render Options β
QrRenderOptions:
| Field | Type | Default | Description |
|---|---|---|---|
variant | QrRenderVariant | 'smooth' | 'basic' Β· 'dots' Β· 'smooth' |
foreground | string | '#ffffff' | Dark module colour |
background | string | 'transparent' | Background colour |
accent | string | foreground | Accent for finders + alignment |
cornerRadius | number | 0.4 | 0 = square, 0.5 = full pill |
dotSize | number | 0.75 | Dot size fraction (dots variant) |
quietZone | number | 2 | Quiet zone in modules |
centerCutout | CenterCutout? | - | Centre logo area |
finderStyle | string | 'rounded' | 'square' Β· 'rounded' Β· 'circle' |
finderColor | string | accent | Finder colour override |
CenterCutout - { size, background?, cornerRadius?, padding? }