Skip to content

@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
  1. Mode detection - auto-selects Numeric, Alphanumeric, or Byte based on input characters
  2. Version selection - finds the smallest version (1–40) that fits the data at the chosen ECC level
  3. Bitstream - encodes data with mode indicator, character count, and padding
  4. Block splitting - divides codewords into groups per the spec's block structure tables
  5. Reed–Solomon - generates error correction codewords per block using GF(256) polynomial division
  6. Interleaving - interleaves data and ECC blocks for burst error resilience
  7. 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 lookup

Dependencies ​

None.

Build ​

bash
npm run build

Compiles 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.modules

Default 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 ​

LevelRecoveryUse 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 High ECC with center cutouts - the cutout destroys modules, so you need the extra error correction capacity.
  • createGrid is 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.

PropTypeDefaultDescription
urlstringrequiredText or URL to encode
wnumber | string200Width in CSS pixels (retina rendered at 2x)
ecc'low' | 'medium' | 'quality' | 'high''high'Error correction level
variant'basic' | 'dots' | 'smooth''smooth'Render style
fgstring?CSS --qr-fg or '#ffffff'Foreground colour
bgstring?CSS --qr-bg or 'transparent'Background colour
accentstring?CSS --qr-accent or fgAccent colour (finders + alignment)
cornerRadiusnumber | string0.4Corner radius (0–0.5)
dotSizenumber | string0.75Dot size fraction (dots variant, 0.3–1.0)
cutoutnumber | string0Centre cutout size (0–0.4, fraction of QR size)
finderStyle'square' | 'rounded' | 'circle''circle'Finder pattern style
finderColorstring?accentFinder 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:

FieldTypeDefaultDescription
variantQrRenderVariant'smooth''basic' Β· 'dots' Β· 'smooth'
foregroundstring'#ffffff'Dark module colour
backgroundstring'transparent'Background colour
accentstringforegroundAccent for finders + alignment
cornerRadiusnumber0.40 = square, 0.5 = full pill
dotSizenumber0.75Dot size fraction (dots variant)
quietZonenumber2Quiet zone in modules
centerCutoutCenterCutout?-Centre logo area
finderStylestring'rounded''square' Β· 'rounded' Β· 'circle'
finderColorstringaccentFinder colour override

CenterCutout - { size, background?, cornerRadius?, padding? }

Carrot