npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@reedscan/core

v0.2.4

Published

ReedSCAN: fast, steady barcode and QR code scanning in the browser. The camera, a box on every code, and a callback for each new one.

Readme

@reedscan/core

Barcode and QR scanning in the browser. You get the camera picture with a steady box on every code, in an element of yours, and a callback for each new code. It works on old Android phones and new iPhones alike, and decoding runs in workers, so the page stays smooth.

npm install @reedscan/core
import { createScanner } from "@reedscan/core";

const scanner = createScanner(document.querySelector("#scanner"), {
  licenseKey: "RS1.…",
  formats: ["QRCode", "DataMatrix", "Code128", "EAN13", "UPCA"],
  onScan: (scan) => console.log(scan.format, scan.value),
  onError: (error) => console.error(error.code, error.message),
});

// From a tap or click: browsers ask for camera permission, and iOS plays the beep only after one.
button.onclick = () => scanner.start();

Give the element a size (for example width: 100%; aspect-ratio: 3 / 4); the scanner fills it. The page must be served over HTTPS (or from localhost) for the camera to work.

Using React? See @reedscan/react.

Options

| Option | Default | | |---|---|---| | licenseKey | none | Your Reed Scan license key. | | formats | QR, Data Matrix, Code 128, EAN-13, UPC-A | Symbologies to read. Fewer is faster and safer. Also: PDF417, Aztec, Code39, Code93, Codabar, ITF, EAN8, UPCE. | | accept | anything | A RegExp or (value, format) => boolean. Codes that fail it are ignored. Use it for a length range too: (v, f) => f !== "Code128" \|\| v.length === 36. | | onScan | | Called for each code as it's reported (see repeat). Return false to skip the beep and vibration for it. | | onError | | Camera and decoder failures (ScannerError, with a code). | | onLicense | | What the license allows here, once the decoder has loaded. | | onEvaluationEnded | | Evaluation mode's time ran out and scanning stopped. | | beep, vibrate | true | Feedback on each reported code. | | boxes | true | Draw a box on each code. | | boxStyle | | (code) => ({ color, fill, width, label, labelBackground, labelColor, hidden }) or null, per code. Asked once per code: call restyle() when your answer changes. | | region | whole picture | { left, top, width, height }, fractions of the scanner element. Only codes whose centre is inside count; a code that moves in reports then. | | repeat | "per-sighting" | When a code reports again: "per-sighting" (each time it comes into view), "once" (until remove()), or { afterMs } (again while it stays in view). | | gapMs | 0 | One code at a time: after a report, nothing else reports for this long. A second code in view waits and reports when the gap ends, if it's still there. | | enabled | true | Start paused, with the camera on. | | facing | "back" | "front" for a fixed kiosk or desk camera. | | cameraStorageKey | "reedscan.camera.deviceId" | Where the chosen lens is remembered (the front one under the key + .front). null to never remember. | | onTracks | | Every frame, each code in view with its box in screen pixels, for drawing your own overlay. | | decoder | | A decoder from createDecoder(), shared between scanners. See Still images and fast reopening. | | resolution | "standard" | "dense" asks for 4K, for small codes far away. It's slower. | | workers | "auto" | Decoder workers, or "auto" for as many as the device has spare cores for. | | wasmUrl | jsDelivr | Where zxing_reader.wasm is served from. See Self-hosting. | | workerUrl | built in | Where the decoder worker is served from, for sites whose CSP refuses blob: workers. |

The returned Scanner has:

  • start(), stop() (camera off), destroy()
  • setEnabled(on): pause or resume reading with the camera kept on, for "done with this one" and hold-to-scan. Codes in view on resuming count as new sightings.
  • scans(), remove(value) (it reports again, even while still in view), clear()
  • setRegion(region), restyle(), tracks(), feedback() (the beep and vibration, for a code you accept later)
  • decodeImage(image), setFormats(), setTorch(), setZoom(), switchCamera(), setFacing()
  • the read-only running, enabled, camera and license

A find-and-pick screen, for example: codes in the brackets only, green once your lookup says it's the one.

const wanted = new Set();
const scanner = createScanner(el, {
  region: { left: 0.1, top: 0.35, width: 0.8, height: 0.3 },
  boxStyle: ({ value }) => (wanted.has(value) ? { color: "#2fb344", label: "✓ Pick", labelBackground: "#2fb344" } : { color: "#8a8f98", fill: "none", label: "" }),
  onScan: (scan) => {
    lookUp(scan.value).then((ok) => {
      if (ok) wanted.add(scan.value), scanner.restyle(), scanner.feedback();
    });
    return false; // no beep until the lookup says yes
  },
});

Still images and fast reopening

createDecoder() loads the decoding engine on its own. Share it between scanners that open and close often: a scanner given one starts without loading anything, and leaves it running when it's destroyed. It also reads still images, such as a QC photo:

import { createDecoder, createScanner } from "@reedscan/core";

const decoder = createDecoder({ licenseKey: "RS1.…" }); // at page load

const scanner = createScanner(el, { decoder, onScan }); // opens at once, each time
scanner.destroy(); // the decoder keeps running

const codes = await decoder.decodeImage(fileInput.files[0], { formats: ["Code128"] });
// [{ value, format, bytes, quad }] — quad in the image's pixels

decodeImage takes an image or canvas element, a File or Blob, an ImageBitmap or ImageData, and spends far more effort per picture than a live frame gets.

License keys

Without a key, Reed Scan runs in evaluation mode: it shows a watermark and stops scanning after 60 seconds (reload the page to scan again). On localhost, and on LAN addresses such as a phone on your dev server, it works fully without a key.

A key is locked to your domains, for example acme.com, *.acme.com. It's checked offline, in the browser, so scanning never depends on a license server. After a key's end date it keeps working for a 14-day grace period, with a console warning.

Get a key at reedscan.com.

Self-hosting

By default the decoder's wasm file (about 925 KB) loads from jsDelivr, pinned to this package's version. For offline warehouses, intranets or a strict CSP, serve it yourself:

cp node_modules/@reedscan/core/dist/zxing_reader.wasm public/
createScanner(el, { licenseKey, wasmUrl: "/zxing_reader.wasm" });

If your Content-Security-Policy doesn't allow worker-src blob:, copy dist/decoder.worker.js too and pass workerUrl: "/decoder.worker.js".

Browsers

Chrome and Edge 99+ (Android and desktop), Safari 16.4+ (iOS and macOS), Firefox 114+, Samsung Internet 18+. These need module workers and OffscreenCanvas. The page must be HTTPS.

License

Proprietary: see LICENSE. Production use needs a license key. Third-party components (zxing-cpp, zxing-wasm) are listed in NOTICE.

© IUJI Group