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

vuescanr

v0.2.3

Published

A powerful and efficient Vue 3 barcode scanning library with real-time detection using WebAssembly

Readme

useZbar API Documentation

Complete API documentation for the useZbar composable function.

Overview

useZbar is a Vue 3 composable that provides a high-level interface for real-time barcode detection using a camera feed.

Basic Usage

import { useZbar } from 'vuescanr'

const {
  init,               // Initialize camera settings and get permission
  start,              // Start video stream from camera to canvas
  stop,               // Stop video stream from camera
  pause,              // Pause video stream
  resume,             // Resume video stream
  video,              // HTMLVideoElement ref - camera stream
  canvas,             // HTMLCanvasElement ref - display canvas
  detect,             // Detection function
  captureFrame,       // Single frame capture function
  startFrameCapture,  // Start continuous frame capture
  stopFrameCapture,   // Stop continuous frame capture
  cleanup             // Resource cleanup
} = useZbar()

API Reference

video

  • Type: Ref<HTMLVideoElement | null>
  • Description: Reference to the video element containing the camera stream
  • Usage: Template binding for hidden video element
<video ref="video" autoplay playsinline hidden></video>

canvas

  • Type: Ref<HTMLCanvasElement | null>
  • Description: Reference to the canvas where frames and visualization are drawn
  • Usage: Template binding for display canvas
<canvas ref="canvas"></canvas>

camera

  • Type: CameraObject
  • Description: Camera control interface
  • Methods:
    • init(config?: Config) - Initialize camera with optional config
    • start() - Start camera stream
    • pause() - Pause camera stream
    • resume() - Resume camera stream
    • stop() - Stop camera stream
// Initialize with custom config
await init({
  canvasWidth: 640,
  canvasHeight: 480
})

// Start the stream
await camera.start()

// Control the stream
pause()
resume()
stop()

captureFrame()

  • Type: () => void
  • Description: Captures a single frame from the video stream to the canvas
  • Usage: Called automatically by startFrameCapture() or manually for single captures
// Manual single frame capture
captureFrame()

// Now canvas contains the frame
const ctx = canvas.value?.getContext('2d')
console.log('Frame captured')

startFrameCapture(intervalMs?)

  • Type: (intervalMs?: number) => void
  • Parameters:
    • intervalMs (optional, default: 33ms = ~30fps) - Interval between frame captures
  • Description: Continuously captures frames from the video stream to the canvas
  • Usage: Call this to begin continuous frame capture
// Start with default interval (30fps)
startFrameCapture()

// Or specify custom interval
startFrameCapture(50) // ~20fps

stopFrameCapture()

  • Type: () => void
  • Description: Stops continuous frame capture. Last frame remains frozen on canvas.
  • Usage: Call when you want to freeze the camera stream
stopFrameCapture()

// Canvas now shows the last captured frame
// Perfect for displaying detection results

detect(config?)

  • Type: (config?: DetectionConfig) => Promise<ZBarSymbol[]>
  • Parameters:
    • config (optional) - Detection configuration object
  • Returns: Promise resolving to array of detected barcode symbols
  • Description: Performs barcode detection on the current canvas content

DetectionConfig

interface DetectionConfig {
  enableVisualization?: boolean      // Draw detection boxes (default: true)
  visualizationColor?: string        // Hex color for drawing (default: "#00ff0080")
  visualizationLineWidth?: number    // Line width in pixels (default: 2)
  multipleDetection?: boolean        // Detect all barcodes or just first (default: false)
}

Usage Examples

// Basic detection
const symbols = await detect()

// Detection with visualization
const symbols = await detect({
  enableVisualization: true,
  visualizationColor: '#00ff0080'
})

// Multiple barcode detection
const symbols = await detect({
  multipleDetection: true
})

// Custom visualization
const symbols = await detect({
  enableVisualization: true,
  visualizationColor: '#ff0000aa',
  visualizationLineWidth: 3
})

// Process results
symbols.forEach(symbol => {
  const barcode = symbol.decode('utf-8')
  console.log('Detected:', barcode)
})

cleanup()

  • Type: () => void
  • Description: Cleans up resources (OffscreenCanvas, etc.)
  • Usage: Call in component unmount hook
onUnmounted(() => {
  cleanup()
})

Complete Example

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { useZbar } from 'vuescanr'
import type { ZBarSymbol } from '@undecaf/zbar-wasm'

const {
  camera,
  detect,
  video,
  canvas,
  startFrameCapture,
  stopFrameCapture,
  cleanup
} = useZbar()

const detected = ref<string[]>([])
const isScanning = ref(false)
const scanInterval = ref<number | null>(null)

const startScanning = () => {
  if (isScanning.value) return
  isScanning.value = true

  const scan = async () => {
    try {
      const symbols = await detect({
        enableVisualization: true,
        visualizationColor: '#00ff0080',
        multipleDetection: true
      })

      if (symbols.length > 0) {
        const barcodes = symbols.map(s => s.decode('utf-8'))
        detected.value = barcodes
        
        // Stop after detection
        stopScanning()
      }
    } catch (error) {
      console.error('Detection error:', error)
    }
  }

  scanInterval.value = window.setInterval(scan, 100)
}

const stopScanning = () => {
  if (scanInterval.value) {
    clearInterval(scanInterval.value)
    scanInterval.value = null
  }
  isScanning.value = false
  stopFrameCapture()
}

const reset = () => {
  detected.value = []
  const ctx = canvas.value?.getContext('2d')
  if (ctx && canvas.value) {
    ctx.clearRect(0, 0, canvas.value.width, canvas.value.height)
  }
  resume()
  startFrameCapture()
  startScanning()
}

onMounted(async () => {
  await init()
  await start()
  startFrameCapture()
  startScanning()
})

onUnmounted(() => {
  stopScanning()
  cleanup()
})
</script>

<template>
  <div class="scanner">
    <video ref="video" autoplay playsinline hidden></video>
    <canvas ref="canvas" class="preview"></canvas>

    <div v-if="detected.length > 0" class="results">
      <h2>Detected Barcodes</h2>
      <div v-for="(code, i) in detected" :key="i" class="barcode">
        {{ i + 1 }}. {{ code }}
      </div>
      <button @click="reset">Scan Again</button>
    </div>

    <div v-else-if="isScanning" class="scanning">
      Scanning...
    </div>
  </div>
</template>

Real-Time Scanning Pattern

For real-time scanning applications:

const SCAN_INTERVAL = 100 // milliseconds between scans
const MIN_DETECTION_INTERVAL = 50 // throttle rapid detections

const scan = async () => {
  try {
    const symbols = await detect({
      enableVisualization: true,
      multipleDetection: false // single barcode mode
    })

    if (symbols.length > 0) {
      const now = performance.now()
      if (now - lastDetectionTime > MIN_DETECTION_INTERVAL) {
        handleDetection(symbols)
        lastDetectionTime = now
      }
    }
  } catch (error) {
    console.error('Scanning error:', error)
  }
}

const intervalId = setInterval(scan, SCAN_INTERVAL)

// Cleanup
onUnmounted(() => {
  clearInterval(intervalId)
  stopFrameCapture()
  cleanup()
})

Error Handling

const scan = async () => {
  try {
    const symbols = await detect()
    
    if (symbols.length === 0) {
      console.log('No barcode found')
      return
    }

    const barcode = symbols[0].decode('utf-8')
    console.log('Barcode:', barcode)
  } catch (error) {
    if (error instanceof Error) {
      console.error('Detection failed:', error.message)
    }
  }
}

Performance Optimization

  1. Frame Capture Interval: Adjust based on detection needs

    startFrameCapture(50)  // 20fps - more frequent
    startFrameCapture(100) // 10fps - less frequent
  2. Detection Throttling: Prevent excessive detections

    const MIN_DETECTION_INTERVAL = 100 // ms between detections
  3. Visualization Toggle: Disable when not needed

    await detect({
      enableVisualization: false // Production mode
    })
  4. Single Detection Mode: Faster than multiple detection

    await detect({
      multipleDetection: false // Only detect first barcode
    })

TypeScript Support

Full TypeScript support with proper types:

import { useZbar } from 'vuescanr'
import type { ZBarSymbol } from '@undecaf/zbar-wasm'

const { detect } = useZbar()

const symbols: ZBarSymbol[] = await detect()
symbols.forEach(symbol => {
  // symbol has proper typing
  const decoded: string = symbol.decode('utf-8')
})

Troubleshooting

Camera Not Starting

try {
  await init()
  await start()
} catch (error) {
  console.error('Camera error:', error)
  // Check browser permissions
  // Ensure HTTPS in production
}

No Barcodes Detected

  • Check barcode is within camera frame
  • Ensure adequate lighting
  • Try adjusting visualization color for better visibility
  • Check browser console for errors

Performance Issues

  • Increase frame capture interval (lower fps)
  • Disable visualization
  • Use single detection mode
  • Check browser DevTools Performance tab

Browser Compatibility

All modern browsers with:

  • MediaStream API
  • Canvas API
  • WebAssembly
  • Promise support

FAQ

Q: Can I use this in production?
A: Yes, it's designed for production use with proper error handling and resource management.

Q: Does it work on mobile?
A: Yes, fully tested on iOS and Android browsers.

Q: Can I detect multiple barcodes at once?
A: Yes, set multipleDetection: true in detection config.

Q: How do I customize the visualization?
A: Use visualizationColor and visualizationLineWidth in detect config.

Q: What formats does it support?
A: All zbar-wasm supported formats (CODE128, EAN-13, UPC, QR, etc.)

License

MIT