Skip to main content
skill CX Codex

extension-qr-code — Claude Code skill: camera QR scanner

Adds QR code scanning through the device camera to a React app. Useful when you need to read a code right in the browser.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add caffeinelabs/skills --skill extension-qr-code -a claude-code
Open on GitHub

What extension-qr-code does

The skill ships a ready-made React hook, useQRScanner, from the @caffeinelabs/qr-code package. It sits on top of the camera component and decodes codes with jsQR. The hook returns the list of scanned codes, camera state, and methods to start, stop and switch the camera.

The hook itself cannot be modified. Configuration is small: scanInterval sets how often scanning happens in milliseconds, maxResults caps the result history, and jsQRUrl points at where the jsQR library loads from. By default jsQR comes from the jsdelivr CDN, so the app depends on an outside network — worth checking how the scanner behaves without CDN access.

Two packages sit underneath: @caffeineai/qr-code at ~0.1.2 and @caffeineai/camera at ~0.1.1. Attach videoRef to the video element and keep a hidden canvasRef for processing. Camera errors land in the error field, and the skill expects you to surface them in the UI.

What it helps with

  • scan a QR code with a phone camera in the browser
  • show a timestamped history of scanned codes
  • switch between front and rear cameras
  • handle the case where the camera is unsupported or blocked
  • clear results before starting a new scan

Example prompts for the agent

  • wire up useQRScanner from @caffeineai/qr-code and build a scanner component
  • add a switch camera button and show it only on mobile
  • render the camera error when error is not null

How to install extension-qr-code

1Skills CLI (Vercel)

npx skills add caffeinelabs/skills --skill extension-qr-code -a claude-code

2Manually: put the files in place

~/.claude/skills/extension-qr-code/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/extension-qr-code/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about extension-qr-code

How do I install extension-qr-code in Claude?

Run npx skills add caffeinelabs/skills --skill extension-qr-code -a claude-code. The skill lands in ~/.claude/skills/extension-qr-code/SKILL.md.

What does extension-qr-code do?

It adds QR code scanning through the device camera, built on the useQRScanner React hook and jsQR decoding.

What packages does it need?

@caffeineai/qr-code at ~0.1.2 and @caffeineai/camera at ~0.1.1. The hook is imported from @caffeinelabs/qr-code and cannot be edited.

Source text

SKILL.md · Apache-2.0
---
name: extension-qr-code
description: QR code scanner using the camera.
version: 0.1.5
compatibility:
  npm:
    "@caffeineai/qr-code": "~0.1.2"
    "@caffeineai/camera": "~0.1.1"
caffeineai-subscription: [none]
---

# QR Code Scanner
QR code scanner extension for [Caffeine AI](https://caffeine.ai?utm_source=caffeine-skill&utm_medium=referral).

## Overview

This skill adds QR code scanning using the device camera. Built on top of the camera component with jsQR for decoding.

# Frontend

For QR code scanner support:

There is a prefabricated React hook imported from `@caffeinelabs/qr-code` that cannot be modified.

```typescript filepath=@caffeinelabs/qr-code/src/hooks/useQRScanner.ts
import { RefObject } from 'react';
import { CameraConfig, CameraError } from '@caffeineai/camera';

export interface QRResult {
  // The decoded QR code data
  data: string;
  // Timestamp when the QR code was scanned
  timestamp: number;
}

export interface QRScannerConfig extends CameraConfig {
  // How often to scan for QR codes in milliseconds (default: 100)
  scanInterval?: number;
  // Maximum number of results to keep in history (default: 10)
  maxResults?: number;
  // URL to load jsQR library from (default: jsdelivr CDN)
  jsQRUrl?: string;
}

export interface UseQRScannerReturn {
  // Array of scanned QR codes (newest first)
  qrResults: QRResult[];
  // Whether currently scanning for QR codes
  isScanning: boolean;
  // Whether jsQR library has been loaded
  jsQRLoaded: boolean;
  
  // Camera state (pass-through from useCamera)
  isActive: boolean;
  isSupported: boolean | null;
  error: CameraError | null;
  isLoading: boolean;
  currentFacingMode: 'user' | 'environment';
  
  // Start camera and begin scanning - returns true on success
  startScanning: () => Promise<boolean>;
  // Stop scanning and camera
  stopScanning: () => Promise<void>;
  // Switch camera facing mode - returns true on success
  switchCamera: () => Promise<boolean>;
  // Clear all scan results
  clearResults: () => void;
  // Reset scanner state (stop scanning and clear results)
  reset: () => void;
  // Retry camera initialization after error - returns true on success
  retry: () => Promise<boolean>;
  
  // Ref to attach to video element for camera preview
  videoRef: RefObject<HTMLVideoElement>;
  // Ref to attach to canvas element used for QR processing (can be hidden)
  canvasRef: RefObject<HTMLCanvasElement>;
  
  // Computed state
  // Whether scanner is ready to use (jsQR loaded and camera supported)
  isReady: boolean;
  // Whether scanning can be started (ready + not loading)
  canStartScanning: boolean;
}

export declare function useQRScanner(config?: QRScannerConfig): UseQRScannerReturn;
```

Usage example:

```typescript filepath=example.ts
import { useQRScanner } from '@caffeineai/qr-code';

function QRScannerComponent() {
    const { 
        qrResults,
        isScanning,
        isActive,
        isSupported,
        error,
        isLoading,
        canStartScanning,
        startScanning,
        stopScanning,
        switchCamera,
        clearResults,
        videoRef,
        canvasRef 
    } = useQRScanner({ 
        facingMode: 'environment',
        scanInterval: 100,
        maxResults: 5
    });

    if (isSupported === false) {
        return <div>Camera not supported</div>;
    }

    return (
        <div>
            <video 
                ref={videoRef} 
                style={{ width: '100%', height: 'auto' }}
                playsInline
                muted
            />
            <canvas ref={canvasRef} style={{ display: 'none' }} />
            
            {error && <div>Error: {error.message}</div>}
            
            <div>
                <button onClick={startScanning} disabled={!canStartScanning}>
                    Start Scanning
                </button>
                <button onClick={stopScanning} disabled={isLoading || !isActive}>
                    Stop Scanning
                </button>
                {/* Only show switch camera on mobile */}
                {/Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) && (
                    <button onClick={switchCamera} disabled={isLoading || !isActive}>
                        Switch Camera
                    </button>
                )}
            </div>
            
            <div>
                <h3>Results {qrResults.length > 0 && <button onClick={clearResults}>Clear</button>}</h3>
                {qrResults.map(result => (
                    <div key={result.timestamp}>
                        <small>{new Date(result.timestamp).toLocaleTimeString()}</small>
                        <p>{result.data}</p>
                    </div>
                ))}
            </div>
        </div>
    );
}
```

Properly display QR scanner error messages in the app.

© caffeinelabs · Apache-2.0 · caffeinelabs/skills

Similar skills

Everything for Frontend and UI →

From the same set27

extension-email-calendar-events This skill adds calendar events and iCalendar invitation emails to an app. Useful when you need meetings with attendees without hand-building ICS files. CX Codex +1 28,400installs extension-email-marketing Adds topic-based marketing email to a Caffeine AI app: subscriber lists, unsubscribe tokens and an /unsubscribe page on your own frontend. CX Codex +1 28,100installs extension-camera Adds instructions for integrating a React useCamera hook into web apps. Useful for live camera previews and photo capture. CX Codex +1 28,100installs extension-stripe Adds Stripe card payments to a Caffeine AI project: checkout session creation and status checks. Useful when you need to take payments inside a canister. CX Codex +1 28,200installs extension-posting-to-x A skill for Caffeine builds that publish tweets to X. It sets the only supported path: the x-client package with OAuth 2.0 PKCE. CX Codex +1 28,100installs extension-openai Enforces the safe OpenAI integration pattern for Motoko canisters using openai-client. Prevents API key leaks and unnecessary billing multiplier in outcalls. CX Codex +1 28,100installs extension-email-raw This skill adds sending one email to several recipients through to, cc and bcc. Handy when a meeting reminder has to reach confirmed and tentative attendees at once. CX Codex +1 28,100installs extension-invite-links Adds invite links and RSVP collection to your project. Guests submit answers using unique codes without logging in, while admins view all responses after sign-in. CX Codex +1 28,100installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor