From 2fbe6f4334c5a25dc33781ac2662a8fe519d8270 Mon Sep 17 00:00:00 2001 From: mikael-lovqvists-claude-agent Date: Sat, 21 Mar 2026 23:53:20 +0000 Subject: [PATCH] Camera selector, focus controls, and decode improvements - Camera picker with auto-selection of main back camera (index 0) - Manual/auto focus toggle button with focus distance slider - Dual binarizer (Hybrid + GlobalHistogram) for blur tolerance - Only vibrate on new unique scan result - Band canvas to restrict decoding to aim line region - Camera select overlaid in viewfinder corner Co-Authored-By: Claude Sonnet 4.6 --- app.mjs | 23 ++++++++++++++--------- index.html | 39 ++++++++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/app.mjs b/app.mjs index 7bce66b..121c7ec 100644 --- a/app.mjs +++ b/app.mjs @@ -11,7 +11,8 @@ const cam_info = document.getElementById('cam-info'); const focus_row = document.getElementById('focus-row'); const focus_slider = document.getElementById('focus-slider'); const focus_val_el = document.getElementById('focus-val'); -const focus_auto = document.getElementById('focus-auto'); +const focus_auto_btn = document.getElementById('focus-auto-btn'); +let focus_auto = true; // Canvases for ZXing decode pipeline const strip_canvas = document.createElement('canvas'); const strip_ctx = strip_canvas.getContext('2d', { willReadFrequently: true }); @@ -76,11 +77,18 @@ async function start_camera(device_id = null) { } if (!has_continuous) { - focus_auto.checked = false; - focus_auto.disabled = true; + focus_auto = false; + focus_auto_btn.disabled = true; + } else { + focus_auto_btn.disabled = false; } - - focus_auto.onchange = () => apply_focus(track, has_continuous, has_distance); + focus_auto_btn.classList.toggle('active', focus_auto); + focus_auto_btn.onclick = async () => { + focus_auto = !focus_auto; + focus_auto_btn.classList.toggle('active', focus_auto); + focus_slider.disabled = focus_auto; + await apply_focus(active_track, has_continuous, has_distance); + }; await apply_focus(track, has_continuous, has_distance); // Tap to focus (replace listener on camera switch) @@ -98,8 +106,7 @@ async function start_camera(device_id = null) { // --- Focus --- async function apply_focus(track, has_continuous, has_distance) { - const auto = focus_auto.checked; - focus_slider.disabled = auto; + const auto = focus_auto; try { if (auto && has_continuous) { await track.applyConstraints({ advanced: [{ focusMode: 'continuous' }] }); @@ -276,9 +283,7 @@ function attempt_decode() { band_canvas.width = strip_canvas.width; band_canvas.height = band_h; } - band_ctx.filter = 'contrast(1.8) brightness(1.05)'; band_ctx.drawImage(strip_canvas, 0, band_y, strip_canvas.width, band_h, 0, 0, strip_canvas.width, band_h); - band_ctx.filter = 'none'; decode_attempts++; const source = new ZXing.HTMLCanvasElementLuminanceSource(band_canvas); diff --git a/index.html b/index.html index d560439..1363097 100644 --- a/index.html +++ b/index.html @@ -55,6 +55,20 @@ height: 100%; } + #camera-select { + position: absolute; + bottom: 8px; + right: 8px; + max-width: 60%; + padding: 4px 6px; + background: rgba(0,0,0,0.6); + color: #dce4ef; + border: 1px solid #1e2a38; + border-radius: 6px; + font-family: inherit; + font-size: 11px; + } + #debug { position: absolute; top: 6px; @@ -117,6 +131,24 @@ font-size: 13px; } + #focus-auto-btn { + padding: 8px 14px; + border-radius: 6px; + border: 1px solid #1e2a38; + background: #181e28; + color: var(--dim); + font-family: inherit; + font-size: 13px; + cursor: pointer; + white-space: nowrap; + } + + #focus-auto-btn.active { + background: #0d1f15; + border-color: var(--accent); + color: var(--accent); + } + #focus-slider { flex: 1; accent-color: var(--accent); @@ -147,19 +179,16 @@
+
Point camera at a barcode
- + 0.30m
-