The previous loop was running but never finding the QR. Three changes
to make it actually decode AND make any future failure visible:
1. inversionAttempts: 'dontInvert' -> 'attemptBoth'
Some camera exposures wash out the QR enough that jsQR sees it
inverted. attemptBoth tries both polarities per frame; the cost is
~2x decode time but jsQR is fast enough that scan stays interactive.
2. getUserMedia now requests 1280x720 (with downgrade allowed). The
default 640x480 only gives ~5 pixels per QR module on a typical
phone-to-sticker distance — borderline for jsQR. 720p doubles
that and makes detection near-instant.
3. The status line is now LIVE, updating every 400ms with:
Decoder: jsqr · frames N · attempts M · video WxH rsN
So when an operator says "scan does nothing" we can immediately see
whether the loop is running, whether the camera is feeding frames,
whether jsQR is being called, and at what resolution. No Web
Inspector required.
Version: shopfloor 19.0.19 -> 19.0.20.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>