Reuse the encoder outside this site

Download

qrpeach.js is a standalone browser QR library that creates QR codes and helps you understand them. It returns the full encoding path — payload bytes, bitstream values, ECC blocks, zigzag placement, and the final symbol — so you can inspect, debug, or teach every step. Drop it into any browser page with no external dependencies.

npm install qrpeach

The published package carries the browser build, versioned metadata, and CDN entry points so you can install the package or reuse the same files from npm-backed CDNs.

Open npm

jsDelivr and UNPKG

Version tables, alignment centers, remainder bits, Reed-Solomon block rows, mode bits, ECC format bits, and source metadata are embedded directly in qrpeach.js, so the same single-file browser build can be loaded from jsDelivr or UNPKG.

Open jsDelivr

GitHub Release Download

Each successful publish also uploads stable release assets so you can download qrpeach.js directly without going through a package manager or CDN cache.

Direct Download

Package Endpoints

These are the public services the published package is intended to live on.

npm install qrpeach

https://www.npmjs.com/package/qrpeach
https://cdn.jsdelivr.net/npm/qrpeach@latest/qrpeach.min.js
https://unpkg.com/qrpeach@latest/qrpeach.min.js
https://github.com/dahln/qrpeach/releases/latest/download/qrpeach.js

Basic Browser Use

Load the published browser build from a package CDN. The library computes the final masked symbol itself.

<script src="https://cdn.jsdelivr.net/npm/qrpeach@latest/qrpeach.min.js"></script>
<script>
  const model = QRPeach.Generate({
    type: 'text',
    inputs: { value: 'HELLO WORLD' },
    version: 2,
    ecc: 'M'
  });

  console.log(model.ok);
  console.log(model.payloadText);
  console.log(model.values);
  console.log(model.finalQr);
</script>

API Entry Points

The browser build exposes two public methods on window.QRPeach: one for generation and one for debugging.

window.QRPeach
QRPeach.Generate(options, format?, renderOptions?)
QRPeach.Debug(source, options?)

Generate returns a QR model or a render-ready SVG/PNG/JPG asset. Debug returns JSON-safe diagnostic data either from generation inputs/models or from an uploaded QR image.

Global API Catalog

Each entry below includes the exported name, what parameters it accepts, and what shape it returns.

Name

window.QRPeach

Description

Primary browser-global namespace. Loading the published browser build from npm, jsDelivr, UNPKG, or the GitHub release asset attaches the minimal public API here.

Parameters

None.

Load the browser build, then read window.QRPeach.

Returns

{
  Generate: Function,
  Debug: Function
}

Code Snippet

<script src="https://unpkg.com/qrpeach@latest/qrpeach.min.js"></script>
<script>
  const api = window.QRPeach;
  console.log(Object.keys(api));
</script>

Name

QRPeach.Generate(options, format?, renderOptions?)

Description

Generates a QR model from a payload type, typed inputs, version, and ECC level. When you also pass an output format, it returns a render-ready SVG, PNG, or JPG asset and can optionally trigger a browser download.

Parameters

options: {
  type?: 'text' | 'uri' | 'url' | 'email' | 'phone' | 'sms' | 'contact' | 'vcard' | 'event' | 'wifi' | 'geo';
  inputs?:
    | { value: string } // uri or url
    | { address: string, subject?: string, body?: string }
    | { number: string }
    | { number: string, message?: string }
    | { name?: string, org?: string, phone?: string, email?: string, url?: string, note?: string }
    | { title?: string, start?: string, end?: string, location?: string, description?: string, allDay?: boolean, timezone?: string }
    | { ssid: string, encryption?: 'WPA' | 'WEP' | 'nopass', password?: string, hidden?: boolean }
    | { lat: string, lng: string, query?: string };
  version?: number;     // 1 through 40, default 2
  ecc?: 'L' | 'M' | 'Q' | 'H';
  enableMask?: boolean; // default true
}

format?: 'svg' | 'png' | 'jpg' | 'jpeg'

renderOptions?: {
  filename?: string,
  download?: boolean,       // default false when format is provided
  cellSize?: number,
  marginModules?: number,   // default 4
  foreground?: string,      // CSS color, default #000000
  background?: string,      // CSS color, default #ffffff
  quality?: number          // JPG only, default 0.92
}

Returns

Without format:

{
  ok: boolean,
  type: string,
  inputs:
    | { value: string } // uri or url
    | { address: string, subject?: string, body?: string }
    | { number: string }
    | { number: string, message?: string }
    | { name?: string, org?: string, phone?: string, email?: string, url?: string, note?: string }
    | { title?: string, start?: string, end?: string, location?: string, description?: string, allDay?: boolean, timezone?: string }
    | { ssid: string, encryption?: 'WPA' | 'WEP' | 'nopass', password?: string, hidden?: boolean }
    | { lat: string, lng: string, query?: string },
  version: number,
  ecc: 'L' | 'M' | 'Q' | 'H',
  totalBytes: number,
  dataBytes: number,
  eccBytes: number,
  countBits: number,
  capacityBits: number,
  payloadInfo: {
    type: string,
    typeLabel: string,
    envelope: string,
    description: string,
    scannerRule: string,
    inputs:
      | { value: string } // uri or url
      | { address: string, subject?: string, body?: string }
      | { number: string }
      | { number: string, message?: string }
      | { name?: string, org?: string, phone?: string, email?: string, url?: string, note?: string }
      | { title?: string, start?: string, end?: string, location?: string, description?: string, allDay?: boolean, timezone?: string }
      | { ssid: string, encryption?: 'WPA' | 'WEP' | 'nopass', password?: string, hidden?: boolean }
      | { lat: string, lng: string, query?: string },
    payload: string
  },
  payloadText: string,
  payloadBytes: Array<{ value: number, char: string, charLabel: string, charIndex: number, byteOffset: number, byteCount: number }>,
  chars: Array<{ char: string, charLabel: string, bytes: number[], byteStart: number, byteEnd: number }>,
  bits: Array<{
    bit: '0' | '1',
    kind: 'mode' | 'count' | 'payload' | 'terminator' | 'padbits' | 'padcw',
    summary: string,
    detail: string,
    bitNumber: number | null,
    charIndex?: number,
    charLabel?: string,
    byteIndex?: number,
    byteValue?: number,
    padValue?: number
  }>,
  values: Array<{
    index: number,
    key: string,
    kind: string,
    label: string,
    bitStart: number,
    bitEnd: number,
    bitLength: number,
    bits: string,
    summary: string,
    detail: string,
    charIndex: number | null,
    charLabel: string,
    byteValues: number[],
    moduleStartIndex: number,
    moduleEndIndex: number
  }>,
  charMap: Array<{ index: number, char: string, charLabel: string, bytes: number[], bitStart: number, bitEnd: number, moduleStartIndex: number, moduleEndIndex: number }>,
  dataByteValues: number[],
  terminatorBits: number,
  alignBits: number,
  padByteStart: number,
  padByteCount: number,
  payloadBitLength: number,
  remainder: number,
  versionInfo: {
    version: number,
    size: number,
    totalModules: number,
    alignmentPatternCount: number,
    hasVersionInfo: boolean,
    totalCodewords: number,
    dataCodewords: number,
    eccCodewords: number,
    remainderBits: number,
    capacities: {
      numeric: number,
      alphanumeric: number,
      binary: number,
      kanji: number
    },
    eccProfile: {
      L: number,
      M: number,
      Q: number,
      H: number
    },
    rsBlocks: {
      dataCodewords: number,
      ecCodewordsPerBlock: number,
      groups: Array<{ blocks: number, dataCodewords: number }>
    }
  },
  moduleGrid: { size: number, aligns: number[][], grid: number[][] },
  zigzagPath: Array<{ index: number, r: number, c: number }>,
  finalQr?: {
    matrix: boolean[][],
    moduleCount: number,
    cellSize: number,
    maskPattern: number,
    maskPenalty: number,
    maskEnabled: boolean,
    formatInfo: { value: number, bits: string, eccBits: string, maskBits: string, bchBits: string },
    rsBlocks: Array<{ group: number, index: number, data: number[], ecc: number[] }>,
    interleavedCodewords: Array<{ index: number, kind: 'data' | 'ecc', block: number, indexInBlock: number, value: number, hex: string }>,
    placedBits: Array<{ index: number, row: number, col: number, kind: 'data' | 'ecc' | 'remainder', codewordIndex: number | null, block: number | null, indexInBlock: number, bitIndex: number, value: number, byteValue: number, maskedValue: number }>
  },
  error?: string,
  requiredBits?: number,
  suggestion?: number | null
}

With format:

Promise<{
  format: 'svg' | 'png' | 'jpg',
  filename: string,
  mimeType: string,
  blob: Blob,
  size: number,
  svg: string
}>

Code Snippet

const model = QRPeach.Generate({
  type: 'text',
  inputs: { value: 'HELLO WORLD' },
  version: 2,
  ecc: 'M'
});

console.log(model.ok);
console.log(model.finalQr.matrix);

const asset = await QRPeach.Generate({
  type: 'url',
  inputs: { value: 'https://example.com' },
  version: 3,
  ecc: 'M'
}, 'svg', { download: false });

console.log(asset.svg);

Name

QRPeach.Debug(source, options?)

Description

Returns well-formed JSON debug data. Pass generation options or a generated model to inspect QR construction data, or pass PNG, JPEG, or SVG bytes to run the internal virtual scan used by the encoder debugger.

Parameters

source:
  | Generate options object
  | Generate model object
  | Uint8Array
  | ArrayBuffer
  | TypedArray
  | number[]

options?: {
  mimeType?: 'image/png' | 'image/jpeg' | 'image/svg+xml',
  type?: 'image/png' | 'image/jpeg' | 'image/svg+xml',
  sourceLabel?: string
}

Returns

When source is Generate options or a Generate model:

{
  ok: boolean,
  type: string,
  inputs:
    | { value: string }
    | { address: string, subject?: string, body?: string }
    | { number: string }
    | { number: string, message?: string }
    | { name?: string, org?: string, phone?: string, email?: string, url?: string, note?: string }
    | { ssid: string, encryption?: 'WPA' | 'WEP' | 'nopass', password?: string, hidden?: boolean }
    | { lat: string, lng: string, query?: string },
  version: number,
  ecc: 'L' | 'M' | 'Q' | 'H',
  payloadInfo: {
    type: string,
    typeLabel: string,
    envelope: string,
    description: string,
    scannerRule: string,
    inputs:
      | { value: string }
      | { address: string, subject?: string, body?: string }
      | { number: string }
      | { number: string, message?: string }
      | { name?: string, org?: string, phone?: string, email?: string, url?: string, note?: string }
      | { ssid: string, encryption?: 'WPA' | 'WEP' | 'nopass', password?: string, hidden?: boolean }
      | { lat: string, lng: string, query?: string },
    payload: string
  },
  payloadText: string,
  payloadBytes: Array<{ value: number, char: string, charLabel: string, charIndex: number, byteOffset: number, byteCount: number }>,
  values: Array<{ index: number, key: string, kind: string, label: string, bitStart: number, bitEnd: number, bitLength: number, bits: string, summary: string, detail: string, charIndex: number | null, charLabel: string, byteValues: number[], moduleStartIndex: number, moduleEndIndex: number }>,
  charMap: Array<{ index: number, char: string, charLabel: string, bytes: number[], bitStart: number, bitEnd: number, moduleStartIndex: number, moduleEndIndex: number }>,
  versionInfo: {
    version: number,
    size: number,
    totalModules: number,
    alignmentPatternCount: number,
    hasVersionInfo: boolean,
    totalCodewords: number,
    dataCodewords: number,
    eccCodewords: number,
    remainderBits: number,
    capacities: { numeric: number, alphanumeric: number, binary: number, kanji: number },
    eccProfile: { L: number, M: number, Q: number, H: number },
    rsBlocks: { dataCodewords: number, ecCodewordsPerBlock: number, groups: Array<{ blocks: number, dataCodewords: number }> }
  },
  moduleGrid: { size: number, aligns: number[][], grid: number[][] },
  zigzagPath: Array<{ index: number, r: number, c: number }>,
  finalQr: {
    matrix: boolean[][],
    moduleCount: number,
    cellSize: number,
    maskPattern: number,
    maskPenalty: number,
    maskEnabled: boolean,
    formatInfo: { value: number, bits: string, eccBits: string, maskBits: string, bchBits: string },
    rsBlocks: Array<{ group: number, index: number, data: number[], ecc: number[] }>,
    interleavedCodewords: Array<{ index: number, kind: 'data' | 'ecc', block: number, indexInBlock: number, value: number, hex: string }>,
    placedBits: Array<{ index: number, row: number, col: number, kind: 'data' | 'ecc' | 'remainder', codewordIndex: number | null, block: number | null, indexInBlock: number, bitIndex: number, value: number, byteValue: number, maskedValue: number }>
  },
  error?: string
}

When source is PNG, JPEG, or SVG bytes:

{
  ok: boolean,
  mimeType: string,
  byteLength: number,
  sourceLabel: string,
  image: {
    width: number,
    height: number,
    isSquare: boolean,
    threshold: number,
    darkPixelRatio: number,
    contrast: number,
    bounds: { left: number, top: number, right: number, bottom: number, width: number, height: number } | null,
    quietZone: { left: number, top: number, right: number, bottom: number } | null,
    modulePitch?: { x: number, y: number },
    quietZoneModules?: { left: number, top: number, right: number, bottom: number },
    moduleCount?: number
  } | null,
  engine: {
    name: string,
    externalDependencies: boolean
  },
  decodedText: string,
  symbol: {
    version: number,
    moduleCount: number,
    eccLevel: 'L' | 'M' | 'Q' | 'H',
    maskPattern: number,
    formatInfo: {
      level: 'L' | 'M' | 'Q' | 'H',
      maskPattern: number,
      value: number,
      bits: string,
      copyA: { value: number, bits: string, errorBits: number },
      copyB: { value: number, bits: string, errorBits: number }
    },
    versionInfo: {
      version: number,
      value: number,
      bits: string,
      copyA: { value: number, bits: string, errorBits: number },
      copyB: { value: number, bits: string, errorBits: number }
    } | null,
    bitCounts: {
      data: number,
      ecc: number,
      remainder: number
    },
    bitstreams: {
      metadata: string,
      format: string,
      version: string,
      data: string,
      ecc: string,
      remainder: string
    },
    codewords: {
      data: Array<{ index: number, bits: string, value: number, hex: string }>,
      ecc: Array<{ index: number, bits: string, value: number, hex: string }>
    },
    byteMode: {
      modeBits: string,
      countBits: string,
      byteCount: number,
      payloadBits: string,
      payloadBytes: number[],
      terminatorBits: string,
      alignBits: string,
      padCodewords: Array<{ index: number, bits: string, value: number, hex: string }>
    }
  } | null,
  issues: Array<{ severity: 'warning' | 'error', code: string, message: string, detail: string }>
}

Code Snippet

const model = QRPeach.Generate({
  type: 'wifi',
  inputs: {
    ssid: 'Cafe WiFi',
    encryption: 'WPA',
    password: 'secret123',
    hidden: false
  },
  version: 4,
  ecc: 'M'
});

const generationDebug = await QRPeach.Debug(model);
console.log(generationDebug.values.length);

const bytes = new TextEncoder().encode((await QRPeach.Generate({
  type: 'text',
  inputs: { value: 'HELLO WORLD' },
  version: 2,
  ecc: 'M'
}, 'svg')).svg);

const scanDebug = await QRPeach.Debug(bytes, {
  mimeType: 'image/svg+xml',
  sourceLabel: 'Generated SVG'
});

console.log(scanDebug.ok, scanDebug.symbol && scanDebug.symbol.version);