Skip to content

Conversation

@simonw
Copy link
Owner

@simonw simonw commented Feb 8, 2026

Add webcam support to qr.html, maybe inspired by how is-it-a-bird does it

Summary

This PR adds webcam-based QR code scanning capabilities to the QR Code Decoder, complementing the existing image upload functionality. Users can now switch between image and webcam modes, with support for front/back camera switching and pinch-to-zoom on mobile devices.

Key Changes

  • Mode Toggle UI: Added image/webcam mode buttons allowing users to switch between upload and live scanning
  • Webcam Scanning: Implemented real-time QR code detection from webcam feed with continuous scanning loop (200ms intervals)
  • Camera Controls:
    • Start/Stop camera buttons
    • Switch camera button (front/back) for devices with multiple cameras
    • Camera availability detection
  • Pinch-to-Zoom: Added touch gesture support for zooming in/out on the video feed (1x to 4x range) with double-tap to reset
  • Improved Styling:
    • Updated to modern system font stack
    • Enhanced drop zone with better visual feedback and hover states
    • Added dedicated styling for webcam container, controls, and status indicators
    • Improved accessibility with better color contrast and visual hierarchy
  • Security: Added HTML escaping for URL display to prevent XSS vulnerabilities
  • UX Improvements:
    • Refactored result display into reusable displayResult() function
    • Added status messages for camera operations
    • Made drop area clickable for file selection
    • Added helpful hints for both image and webcam modes

Implementation Details

  • Webcam stream is properly cleaned up when switching modes or stopping
  • Scanning only occurs when webcam is active and stream is available
  • Camera constraints request ideal 640x480 resolution for optimal QR detection
  • Touch events use { passive: false } to enable preventDefault() for pinch gestures
  • Zoom state persists during scanning but resets when camera is stopped

https://claude.ai/code/session_01WkRNE7y8xrRmXdyHNrYKij

Add a webcam mode alongside the existing image upload mode, inspired by
the is-it-a-bird webcam implementation. Features include:

- Image/Webcam mode toggle buttons
- Live camera feed with continuous QR scanning every 200ms
- Front/rear camera switching on multi-camera devices
- Pinch-to-zoom with double-tap reset on mobile
- Shared displayResult function with HTML escaping for URLs
- Improved dropzone styling consistent with other tools

https://claude.ai/code/session_01WkRNE7y8xrRmXdyHNrYKij
@claude
Copy link
Contributor

claude bot commented Feb 8, 2026

Claude finished @simonw's task —— View job


PR Review Complete ✅

Overall Assessment: This is a well-implemented addition that adds valuable webcam scanning functionality with good attention to UX and security details.

Strengths

Code Quality & Best Practices:

  • Clean, well-structured code with logical separation of concerns
  • Consistent naming conventions and good variable naming
  • Proper use of async/await patterns for camera operations
  • Good CSS organization with semantic class names
  • Modern JavaScript features used appropriately

Security:

  • HTML escaping implemented correctly - escapeHtml() function at qr.html:390-394 properly prevents XSS
  • URL validation - isValidUrl() function validates URLs before creating links
  • Safe DOM manipulation - Uses textContent for untrusted data, innerHTML only for escaped content

User Experience:

  • Intuitive mode toggle between image and webcam scanning
  • Proper cleanup of webcam resources when switching modes
  • Good visual feedback with status messages and hover states
  • Accessible design with proper contrast and visual hierarchy

⚠️ Areas for Improvement

Performance Considerations:

  • Scan interval frequency (qr.html:534): 200ms scanning interval may be aggressive for battery life. Consider:
    • Increasing interval to 300-500ms for better battery performance
    • Implementing adaptive scanning (faster when QR detected, slower when not)

Potential Issues:

  • Canvas recreation (qr.html:504): New canvas created on every scan frame could impact performance
    • Consider reusing a single canvas instance
    • Only recreate when video dimensions change

Code Robustness:

  • Error handling: Camera permission errors could be more user-friendly (qr.html:467-470)
  • Browser compatibility: No feature detection for getUserMedia or touch events
  • Memory cleanup: Consider explicitly nulling canvas context after use

📝 Minor Suggestions

Touch Event Handling:

  • Double-tap detection (qr.html:584-598) could conflict with browser zoom - consider longer delay
  • Touch event listeners could benefit from cleanup when switching modes

CSS:

  • Consider adding user-select: none to video wrapper to prevent accidental text selection during pinch gestures

JavaScript:

  • The preventDefaults function name could be more descriptive (e.g., preventDragDefaults)

🧪 Test Coverage

  • No automated tests present (expected for this type of tool)
  • Manual testing scenarios should include:
    • Multiple camera switching
    • Permission denial handling
    • Various QR code types and orientations
    • Pinch-to-zoom edge cases
    • Browser compatibility testing

🔒 Security Assessment

The security implementation is solid with proper XSS prevention measures in place. The HTML escaping for URL display adequately addresses the mentioned security concern.

Verdict: ✅ APPROVE - This is a quality implementation that adds valuable functionality while maintaining security and usability standards. The suggested performance optimizations are minor and don't block the core functionality.

@simonw
Copy link
Owner Author

simonw commented Feb 8, 2026

Perfect:

CleanShot 2026-02-07 at 19 36 39@2x

@simonw simonw merged commit d4336f4 into main Feb 8, 2026
2 of 4 checks passed
@simonw simonw deleted the claude/add-webcam-qr-scanner-V6eI9 branch February 8, 2026 03:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants