@ericrisco/rsc 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +6 -3
  2. package/manifest.json +43 -22
  3. package/package.json +1 -1
  4. package/scripts/lib/default-skill-floor.js +5 -1
  5. package/scripts/lib/domains.js +2 -2
  6. package/scripts/lib/retired-skills.js +4 -0
  7. package/skills/design/SKILL.md +4 -3
  8. package/skills/design/evals/cases.yaml +2 -2
  9. package/skills/react/SKILL.md +2 -1
  10. package/skills/suggest/SKILL.md +12 -8
  11. package/skills/suggest/evals/cases.yaml +6 -0
  12. package/skills/ux/SKILL.md +149 -0
  13. package/skills/ux/THIRD_PARTY.md +32 -0
  14. package/skills/ux/evals/cases.yaml +40 -0
  15. package/skills/ux/references/flows.md +124 -0
  16. package/skills/ux/upstream/UPSTREAM.json +59 -0
  17. package/skills/ux/upstream/ux-designer/GUIDE.md +180 -0
  18. package/skills/ux/upstream/ux-designer/LICENSE +21 -0
  19. package/skills/ux/upstream/ux-designer/references/01-core-principles.md +251 -0
  20. package/skills/ux/upstream/ux-designer/references/02-laws-of-ux.md +330 -0
  21. package/skills/ux/upstream/ux-designer/references/03-accessibility.md +411 -0
  22. package/skills/ux/upstream/ux-designer/references/04-visual-design.md +433 -0
  23. package/skills/ux/upstream/ux-designer/references/05-information-architecture.md +432 -0
  24. package/skills/ux/upstream/ux-designer/references/06-interaction-design.md +495 -0
  25. package/skills/ux/upstream/ux-designer/references/07-forms-and-inputs.md +491 -0
  26. package/skills/ux/upstream/ux-designer/references/08-mobile-ux.md +539 -0
  27. package/skills/ux/upstream/ux-designer/references/09-ux-writing.md +493 -0
  28. package/skills/ux/upstream/ux-designer/references/10-user-research.md +533 -0
  29. package/skills/ux/upstream/ux-designer/references/11-design-systems.md +618 -0
  30. package/skills/ux/upstream/ux-designer/references/12a-presence-awareness.md +395 -0
  31. package/skills/ux/upstream/ux-designer/references/12b-conflict-resolution-sync.md +420 -0
  32. package/skills/ux/upstream/ux-designer/references/13a-canvas-navigation.md +388 -0
  33. package/skills/ux/upstream/ux-designer/references/13b-canvas-objects-performance.md +559 -0
  34. package/skills/ux/upstream/ux-designer/references/14-ai-ux-patterns.md +511 -0
  35. package/skills/ux/upstream/ux-designer/references/15-ethical-design.md +419 -0
  36. package/skills/ux/upstream/ux-designer/references/16-onboarding.md +430 -0
  37. package/skills/ux/upstream/ux-designer/references/17-notifications.md +461 -0
  38. package/skills/ux/upstream/ux-designer/references/18-data-visualization.md +453 -0
  39. package/skills/ux/upstream/ux-designer/references/19-search-ux.md +479 -0
  40. package/skills/ux/upstream/ux-designer/references/20-emotional-design.md +382 -0
  41. package/skills/ux/upstream/ux-designer/references/21-data-tables.md +629 -0
  42. package/skills/ux/upstream/ux-designer/references/22-performance-ux.md +626 -0
  43. package/skills/ux/upstream/ux-designer/references/23-internationalization.md +347 -0
  44. package/skills/ux/upstream/ux-designer/references/24-voice-and-multimodal.md +308 -0
  45. package/skills/ux/upstream/ux-designer/references/25a-barcode-camera-scanning.md +342 -0
  46. package/skills/ux/upstream/ux-designer/references/25b-barcode-scanner-workflows.md +412 -0
  47. package/skills/ux/upstream/ux-designer/references/25c-barcode-display.md +277 -0
  48. package/skills/ux/upstream/ux-usability-foundations/GUIDE.md +285 -0
  49. package/skills/ux/upstream/ux-usability-foundations/LICENSE +21 -0
  50. package/skills/ux/upstream/ux-usability-foundations/references/anti-patterns.md +267 -0
  51. package/skills/ux/upstream/ux-usability-foundations/references/checklists.md +130 -0
  52. package/skills/ux/upstream/ux-usability-foundations/references/decision-prompts.md +340 -0
  53. package/skills/ux/upstream/ux-usability-foundations/references/principle-cards.md +449 -0
  54. package/targets/clone-bootstrap.mjs +1 -1
  55. package/skills/ui-engineering/SKILL.md +0 -113
  56. package/skills/ui-engineering/evals/cases.yaml +0 -38
@@ -0,0 +1,342 @@
1
+ # Camera Barcode & QR Scanning
2
+
3
+ Scanning with a phone or laptop camera in consumer and prosumer apps: product lookup,
4
+ adding items, filling a form from a code, joining Wi-Fi, following a QR link, redeeming
5
+ a voucher. The camera is an **accelerator for typing, never the only path**. Most scanner
6
+ UX failures come from the states around the decode: permissions, aiming, feedback, and
7
+ what happens after a hit. The decode itself is rarely the problem.
8
+
9
+ > Dedicated scanner hardware and scan-driven work apps: [25b-barcode-scanner-workflows.md](25b-barcode-scanner-workflows.md).
10
+ > Showing a code for someone else to scan: [25c-barcode-display.md](25c-barcode-display.md).
11
+ > Symbology primer (in 25b), short version: enable only the formats you expect (QR for links,
12
+ > EAN/UPC for retail products, DataMatrix for pharma/GS1). Fewer formats scan faster and
13
+ > misread less. GS1 barcodes need parsing, and the app must verify check digits.
14
+
15
+ ---
16
+
17
+ ## Contents
18
+
19
+ - When to Offer Scanning
20
+ - Entry Points & System Scanners
21
+ - Camera Permission
22
+ - The Viewfinder
23
+ - Live States & Guidance
24
+ - Hard Conditions: Light, Focus, Zoom
25
+ - Multiple Codes & Continuous Scanning
26
+ - Feedback: Visual, Haptic, Sound
27
+ - After the Scan: Auto-Act vs. Confirm
28
+ - QR Safety (Quishing)
29
+ - Scanning from an Image
30
+ - Accessibility
31
+ - Web Specifics
32
+ - Platform Notes
33
+ - Quick Checklist
34
+ - Common Mistakes
35
+ - Sources
36
+
37
+ ---
38
+
39
+ ## When to Offer Scanning
40
+
41
+ - Offer scanning where it replaces typing a long or error-prone value: product lookup, a
42
+ form field, event details, Wi-Fi, a contact (Material "Barcode scanning" pattern).
43
+ - **Always pair it with manual entry.** Scanning disappears when permission is denied, the
44
+ device has no camera (desktop web), the code is damaged, Google Play services are
45
+ missing, or the browser lacks support. Android's permission guidance says to promote
46
+ alternatives when a feature is unavailable.
47
+ - **Hide scan entry points on devices that can't scan** (iOS `DataScannerViewController.isSupported`
48
+ requires an A12 chip or later, and a desktop may have no camera).
49
+ - Don't ask people to scan a code shown **on the same phone**. Give them a link instead, or
50
+ scan-from-image (NN/g).
51
+
52
+ ## Entry Points & System Scanners
53
+
54
+ - Put the entry point **where the value is needed**: a scan icon inside a search field, a
55
+ "Scan" button beside a form field. A dedicated tab only makes sense for scan-centric apps.
56
+ This also puts the permission request in context.
57
+ - **Where results go** (Material):
58
+
59
+ | Task | After a hit |
60
+ |---|---|
61
+ | Browse products in a store | Stay in the scanner, result in a bottom sheet over the camera |
62
+ | Add a contact / save something | Stay until saved, via a bottom sheet or full-screen dialog |
63
+ | Complete a form | Return to the form with the fields filled in |
64
+
65
+ - **You may not need a scanner at all.** The iOS Camera app, the Control Center "Scan Code"
66
+ control, the Android camera, the Quick Settings "Scan QR code" tile, and Google Lens all read
67
+ QR codes. If your codes are HTTPS URLs set up as Universal Links / App Links, the system
68
+ scanner opens your app directly.
69
+ - NCSC (UK) and the FBI advise consumers to use the phone's built-in scanner and not download
70
+ scanner apps. Don't make "download our app to scan" a prerequisite for a generic QR.
71
+ - First run: a one-screen animated hint showing how to hold the device, plus a Help entry
72
+ (angle, distance, light). Not a multi-step tour.
73
+
74
+ ## Camera Permission
75
+
76
+ - Ask **when the user taps Scan**, never at launch (Apple HIG, Android).
77
+ - Purpose string: a specific, complete sentence ("Scan barcodes to add products to your
78
+ list"), not "needed for a better experience".
79
+ - **Pre-permission screens differ by platform.** Apple's HIG says a single "Continue"
80
+ button that leads to the system alert, with no cancel and no "Allow" label. Android says
81
+ to include a "No thanks" that keeps the app usable. Don't unify them.
82
+ - **Denied state** (Android guidance, which applies everywhere):
83
+ - Don't block the UI with a full-screen warning, and don't nag.
84
+ - Explain the loss where results would appear, and offer manual entry and "Choose from photos".
85
+ - After a permanent denial (Android: denied twice), deep-link to Settings.
86
+ - **Check before opening the camera:** iOS `isAvailable` is false when access is denied
87
+ or restricted (Screen Time). On the web, `navigator.permissions.query({name:'camera'})`
88
+ (Chrome, Safari 16+, Firefox 132+) lets you show recovery steps instead of failing.
89
+ - **Permission-free options:**
90
+
91
+ | Platform | Option | Trade-off |
92
+ |---|---|---|
93
+ | Android | **Google Code Scanner** (ML Kit): no camera permission; Google Play services runs the camera | No custom UI; needs GMS (not Huawei or de-Googled devices); module may download on first use. Has `allowManualInput` and `enableAutoZoom` options |
94
+ | Android / iOS | Photo Picker / PHPicker + still-image decode | Not live; no media permission |
95
+ | iOS | System Camera / Control Center handoff | Only for URL codes; no in-app live scanner without permission |
96
+ | Web | `<input type="file" accept="image/*" capture="environment">` | A still photo, not live; desktop shows a file picker |
97
+
98
+ ## The Viewfinder
99
+
100
+ - **Full-bleed camera, controls on the edges.** Put exit, torch, and Help in a top bar with a
101
+ scrim, keep overlays translucent, and leave the centre clear (Material).
102
+ - **Frame shaped for the expected code:** wide for 1D, square for QR. A single-code frame
103
+ also tells the user that one code is read at a time.
104
+ - **Region of interest:** decode only inside the frame. A smaller region with fewer formats
105
+ processes faster (vendor docs; iOS `regionOfInterest`).
106
+ - **Size the frame so the lens can focus.** On Pro iPhones a small code that fills a big
107
+ frame pulls the phone inside the minimum focus distance (12–15 cm), and the image blurs.
108
+ Apple's fix (WWDC21) is to apply zoom automatically (`minimumFocusDistance`) so people
109
+ hold the phone farther away.
110
+ - Don't lock orientation. Decoders read codes at any rotation (ML Kit), and WCAG 1.3.4
111
+ applies on the web.
112
+ - **Inline or mini scanners** (a small camera preview docked over a list, as in self-checkout
113
+ or stock counting) keep the context visible. Full-screen suits one-off scans.
114
+
115
+ ## Live States & Guidance
116
+
117
+ Material's pattern is **sense → recognize → communicate**:
118
+
119
+ | State | Frame | Text |
120
+ |---|---|---|
121
+ | Sensing | Pulsing border | "Point your camera at a barcode" |
122
+ | Too small / far | Partial border | "Move closer" (or "Move back", see focus above) |
123
+ | Detected | Border turns solid; **camera feed pauses** | — |
124
+ | Looking up | Progress indicator across the frame | "Searching…" |
125
+ | Error | Border turns dotted (not only red) | **Banner** with the reason and actions (Retry, Help) |
126
+
127
+ - **Pause the feed on detection** so the user doesn't scan a second code by accident.
128
+ - **Tooltips describe the state only.** No action verbs in non-actionable hints, and errors
129
+ never go in a tooltip (Material).
130
+ - **Debounce 1D misreads:** act only after the same value has decoded several frames in a
131
+ row (ML Kit).
132
+ - **Design the post-decode failures:** a code from an unrelated source ("not a product
133
+ code"), no network during lookup, a product not in the database. Each needs manual
134
+ search and a retry.
135
+ - **No-detection hint:** no primary source gives a timing. Show help ("Add light", "Hold
136
+ steady", "Try manual entry") after roughly 5–10 s without a detection, as a heuristic.
137
+ - **Idle camera:** pausing after ~8–10 s of inactivity saves battery (vendor advice). Pause
138
+ with a one-tap "Resume scanning" and never discard state (WCAG 2.2.1 on the web).
139
+
140
+ ## Hard Conditions: Light, Focus, Zoom
141
+
142
+ - **Torch toggle** is always in the top bar when the camera supports it. Hide it otherwise
143
+ (desktop webcams, Firefox): check `track.getCapabilities().torch`.
144
+ - **Help copy** (Google Pixel's wording): hold steady, add light, avoid glare, clean the lens,
145
+ keep the whole code visible. For **glare on curved or shiny packaging**: tilt or rotate the
146
+ item.
147
+ - **Tiny codes:** use a higher-accuracy mode (VisionKit `qualityLevel = .accurate`) and zoom.
148
+ For small or dense codes, use camera input of 1280×720–1920×1080. ML Kit needs the
149
+ smallest module to cover about 2 camera pixels or more, and an EAN-13 about 190 px wide.
150
+ - **Zoom:** VisionKit supports pinch-to-zoom by default, and Google Code Scanner and ML Kit
151
+ offer auto-zoom for distant codes. If you implement pinch zoom yourself, add **zoom
152
+ buttons or a slider** as the single-pointer alternative (WCAG 2.5.1).
153
+ - **Damaged codes** fall back to manual entry. Some vendor SDKs add OCR of the printed digits.
154
+
155
+ ## Multiple Codes & Continuous Scanning
156
+
157
+ - **Single mode** (the default): pick the code nearest the centre, and let a **tap choose a
158
+ different one** (VisionKit behaviour).
159
+ - **Multi mode:** highlight every detected code with overlays that track movement (keep
160
+ high-frame-rate tracking on), and tap to act on one. ML Kit returns at most 10 codes
161
+ per frame.
162
+ - **Continuous or batch** (scanning a shelf, a cart): keep the camera running, list results
163
+ as they arrive, show a running count, and allow undo of the last item.
164
+ - **Duplicate suppression** has no standard. Vendor defaults range from 0.5 to 3 s, or "until
165
+ the code leaves the frame". Single-scan flows should simply pause after a hit.
166
+
167
+ ## Feedback: Visual, Haptic, Sound
168
+
169
+ - **Visual first:** the frame locks, the feed freezes, and the result appears. Use shape as
170
+ well as colour for success and error.
171
+ - **Haptics:** iOS `UINotificationFeedbackGenerator` `.success` / `.error`. Android
172
+ `HapticFeedbackConstants.CONFIRM` / `REJECT`. Don't reuse one pattern for opposite
173
+ meanings, and prefer no haptics to buzzy ones (Android). Apple warns that haptics must not
174
+ disrupt the camera, so fire them **after** the frame is captured.
175
+ - **Sound:** no platform guideline says on or off. Vendor SDKs default to on. A short beep is
176
+ fine if it respects silent mode, is toggleable, and is never the only signal. On iOS,
177
+ play it with the **`.ambient`** audio session. The default `soloAmbient` stops the
178
+ user's music.
179
+ - **Web:** `navigator.vibrate` does nothing on iOS and Firefox Android, so never rely on it.
180
+ Create or resume the `AudioContext` inside the "Start scanning" tap, so later beeps pass
181
+ autoplay rules.
182
+
183
+ ## After the Scan: Auto-Act vs. Confirm
184
+
185
+ | Code | Action |
186
+ |---|---|
187
+ | Your own app's payload or a known product ID | Auto-act: look it up and show the result sheet |
188
+ | Arbitrary URL | **Preview, then the user taps to open** (as the iOS and Android system scanners do) |
189
+ | Structured payload (Wi-Fi, contact, calendar, phone, SMS, geo) | Type-specific preview (SSID, name, number), then a confirm action |
190
+ | Login / "link a device" QR | Say exactly what happens ("Sign in on a new device: Chrome on Windows, Berlin") and require explicit confirmation |
191
+ | Payment QR | Show merchant name and amount before confirming ([25c](25c-barcode-display.md)) |
192
+
193
+ ML Kit and VisionKit already parse the common structured types. Use their typed results
194
+ rather than re-parsing strings.
195
+
196
+ ## QR Safety (Quishing)
197
+
198
+ Attackers put stickers over real codes (parking, restaurants), send QR codes in email to
199
+ get past link scanners, and use "link a device" codes to hijack messaging accounts (CISA,
200
+ Nov 2025). Risk is highest for codes in email and in open public spaces (NCSC UK). The
201
+ "Gone Quishing" field study found 67% of participants handed over Google or Facebook
202
+ credentials after a QR pretext.
203
+
204
+ When your app opens scanned URLs:
205
+ - **Show a URL preview before opening.** Follow Chromium's URL display rules:
206
+ - Highlight the **registrable domain** (eTLD+1).
207
+ - Elide long hostnames **from the front** so the real domain stays visible.
208
+ - Never show `user:pass@`.
209
+ - Show punycode (`xn--`) for confusable internationalized domains.
210
+ - Flag link shorteners, non-HTTPS URLs, and domains that don't match the context (a
211
+ "parking" code going to an unrelated domain).
212
+ - Don't auto-open app installs or payment pages from arbitrary QR codes. The FBI says to
213
+ install apps from the store and type known payment URLs.
214
+ - For account linking or login by QR, see the table above and
215
+ [25c](25c-barcode-display.md#qr-login--device-pairing).
216
+
217
+ ## Scanning from an Image
218
+
219
+ Codes arrive in screenshots, PDFs, and emails, and a phone can't point its camera at its
220
+ own screen.
221
+ - Put **"Choose from photos"** in the scanner and in the permission-denied state.
222
+ - iOS: PHPicker (no library permission) + VisionKit `ImageAnalyzer`. Android: Photo Picker
223
+ (no media permission) + ML Kit on a still image. Web: `BarcodeDetector.detect()` or the
224
+ polyfill on an image or blob.
225
+ - "No code found in this image" offers a retry with another image and manual entry.
226
+
227
+ ## Accessibility
228
+
229
+ - **Visual aiming excludes blind users.** Proven research patterns (Smith-Kettlewell BLaDE):
230
+ - Audio cues where **volume = distance** and **tone continuity = centring**.
231
+ - Feedback about **one code at a time**.
232
+ - A target size of 60–80% of the frame for 1D codes.
233
+ - Seeing AI and Google Lookout use beeps or spoken guidance and **auto-capture** with no
234
+ shutter button.
235
+ - **Auto-capture** also helps users with motor impairments. Never require a tap while aiming.
236
+ - **Announce the result.** On iOS, post a `UIAccessibility` announcement. On Android,
237
+ `announceForAccessibility` is **deprecated since API 36**: move focus to the result, or use
238
+ a live region or pane title instead.
239
+ - Label the torch, zoom, exit, and manual-entry controls. Make the targets large and reachable
240
+ one-handed.
241
+ - Success and error use shape and text, not just colour (Material switches the frame from a
242
+ solid to a dotted stroke).
243
+ - Zoom has a single-pointer alternative (WCAG 2.5.1). No short camera timeouts without a
244
+ resume option (2.2.1).
245
+
246
+ ## Web Specifics
247
+
248
+ - **`BarcodeDetector` is not Baseline** (MDN compat data, Sept 2026):
249
+
250
+ | Browser | Support |
251
+ |---|---|
252
+ | Chrome Android | Yes |
253
+ | Chrome / Edge desktop | macOS and ChromeOS only, **not Windows or Linux** |
254
+ | Safari (macOS, iOS) | Behind a flag only; broken on iOS 18+ (WebKit bug 281848) |
255
+ | Firefox | No |
256
+
257
+ All iOS browsers use WebKit, so there's effectively no native detector on iOS web.
258
+ - **Fallback:** the `barcode-detector` polyfill (on zxing-wasm / ZXing-C++). It only
259
+ registers when native support is missing. Feature-detect `'BarcodeDetector' in window`
260
+ **and** check `getSupportedFormats()` for your formats. Load the WASM **lazily** when the
261
+ scanner opens, and self-host the `.wasm` for CSP or offline use. ZXing Java and
262
+ `@zxing/library` are in maintenance mode.
263
+ - **HTTPS only.** `navigator.mediaDevices` is undefined on insecure origins. In iframes,
264
+ add `allow="camera"`.
265
+ - **Camera constraints:** use `facingMode: 'environment'`, not `{exact: ...}`, which throws
266
+ on laptops. Feature-detect `torch`, `zoom`, and `focusMode` through `getCapabilities()`.
267
+ Torch works in iOS Safari only from about iOS 17, despite older claims.
268
+ - **Map `getUserMedia` errors to UI:**
269
+
270
+ | Error | Meaning |
271
+ |---|---|
272
+ | `NotAllowedError` | Denied or policy-blocked. Show recovery steps |
273
+ | `NotFoundError` | No camera. Hide scan, show manual entry |
274
+ | `NotReadableError` | Camera in use by another app |
275
+ | `OverconstrainedError` | Constraints too strict. Retry with looser ones |
276
+
277
+ - **Stop the tracks** (`track.stop()`) when the scanner closes or pauses, so the camera
278
+ indicator goes off.
279
+ - **iOS Home Screen web apps** historically forget the camera decision and re-prompt. Since
280
+ iOS 26, *every* site added to the Home Screen opens as a web app by default, so plan for
281
+ repeated prompts with brief in-context priming each time.
282
+ - **Hybrid apps:** WKWebView needs `requestMediaCapturePermissionFor` (iOS 15+), or users see
283
+ a web prompt on top of the native one. Android WebView needs `onPermissionRequest` plus
284
+ the app's CAMERA permission. Many in-app browsers fail silently here.
285
+
286
+ ## Platform Notes
287
+
288
+ - **iOS — VisionKit `DataScannerViewController`** (iOS 16+, A12+):
289
+ - Built in: guidance labels ("Slow down"), tap-to-focus, pinch-to-zoom, tap-to-select, and
290
+ optional highlighting.
291
+ - Restrict `recognizedDataTypes` to the symbologies you need, and pick a `qualityLevel`.
292
+ - For full control, use AVFoundation `AVCaptureMetadataOutput` (see the AVCamBarcode sample
293
+ for focus-distance zoom).
294
+ - **Android — ML Kit** (on-device, offline): Codabar, Code 39/93/128, EAN, ITF, UPC, Aztec,
295
+ DataMatrix, PDF417, QR. Use CameraX `STRATEGY_KEEP_ONLY_LATEST`, ≤ 2 MP input, and throttle
296
+ the detector. **Google Code Scanner** gives a no-permission, no-custom-UI alternative.
297
+ - **Web:** native `BarcodeDetector` where available, the zxing-wasm polyfill elsewhere. See
298
+ above.
299
+
300
+ ---
301
+
302
+ ## Quick Checklist
303
+
304
+ - [ ] Manual entry and "Choose from photos" beside every scan entry point
305
+ - [ ] Scan entry hidden when the device can't scan
306
+ - [ ] Permission asked on tap, with a specific purpose string; denied state is non-blocking and links to Settings
307
+ - [ ] Frame matches the code shape; torch, exit, and Help in the top bar
308
+ - [ ] Only the needed symbologies enabled; region of interest set
309
+ - [ ] Sensing → detected → lookup → error states designed; feed pauses on a hit
310
+ - [ ] Errors in a banner with a reason and actions, not a tooltip; not colour-only
311
+ - [ ] Focus-distance zoom on iOS; zoom buttons if custom pinch
312
+ - [ ] Haptic after capture; beep toggleable, respects silent mode (`.ambient` on iOS)
313
+ - [ ] Arbitrary URLs previewed (registrable domain highlighted) before opening
314
+ - [ ] Login and device-link codes state what they authorize and require confirmation
315
+ - [ ] Result announced to screen readers; auto-capture without a shutter tap
316
+ - [ ] Web: feature-detect `BarcodeDetector` + formats, lazy WASM fallback, HTTPS, tracks stopped on close
317
+
318
+ ## Common Mistakes
319
+
320
+ - Scan as the only way to enter a code
321
+ - Asking for camera permission at app launch
322
+ - A permission-denied dead end with no manual path
323
+ - Auto-opening any URL a QR code contains
324
+ - Leaving the camera live after a hit, so a second code gets scanned by mistake
325
+ - "Move closer" hints on phones where closer means out of focus
326
+ - Errors shown as a red tint or a tooltip only
327
+ - A beep that stops the user's music
328
+ - Relying on `navigator.vibrate` or native `BarcodeDetector` on iOS
329
+ - Loading a large WASM decoder on page load instead of when the scanner opens
330
+ - Enabling every symbology "just in case"
331
+
332
+ ---
333
+
334
+ ## Sources
335
+
336
+ - [Material Design (M2) — Barcode scanning pattern](https://m2.material.io/design/machine-learning/barcode-scanning.html)
337
+ - [Apple VisionKit — DataScannerViewController](https://developer.apple.com/documentation/visionkit/datascannerviewcontroller) · [WWDC22 — Capture machine-readable codes and text with VisionKit](https://developer.apple.com/videos/play/wwdc2022/10025/) · [WWDC21 — What's new in camera capture](https://developer.apple.com/videos/play/wwdc2021/10047/) · [HIG — Privacy](https://developer.apple.com/design/human-interface-guidelines/privacy) · [HIG — Playing haptics](https://developer.apple.com/design/human-interface-guidelines/playing-haptics) · [AVAudioSession ambient](https://developer.apple.com/documentation/avfaudio/avaudiosession/category-swift.struct/ambient) · [iPhone — Scan a QR code](https://support.apple.com/guide/iphone/scan-a-qr-code-iphe8bda8762/ios)
338
+ - [ML Kit barcode scanning](https://developers.google.com/ml-kit/vision/barcode-scanning) · [Android guide](https://developers.google.com/ml-kit/vision/barcode-scanning/android) · [Google Code Scanner](https://developers.google.com/ml-kit/vision/barcode-scanning/code-scanner) · [Android — Request permissions](https://developer.android.com/training/permissions/requesting) · [HapticFeedbackConstants](https://developer.android.com/reference/android/view/HapticFeedbackConstants) · [Photo Picker](https://developer.android.com/training/data-storage/shared/photo-picker)
339
+ - [MDN — BarcodeDetector](https://developer.mozilla.org/en-US/docs/Web/API/BarcodeDetector) · [WICG Shape Detection API](https://wicg.github.io/shape-detection-api/) · [WebKit bug 281848](https://bugs.webkit.org/show_bug.cgi?id=281848) · [barcode-detector polyfill](https://github.com/Sec-ant/barcode-detector) · [MDN — getUserMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia) · [W3C MediaStream Image Capture](https://www.w3.org/TR/image-capture/) · [WebKit — Safari 26.0 features](https://webkit.org/blog/17333/webkit-features-in-safari-26-0/)
340
+ - [FTC — QR code scams](https://consumer.ftc.gov/consumer-alerts/2023/12/scammers-hide-harmful-links-qr-codes-steal-your-information) · [FBI IC3 PSA](https://www.ic3.gov/PSA/2022/PSA220118) · [NCSC UK — QR codes: what's the real risk?](https://www.ncsc.gov.uk/blog-post/qr-codes-whats-real-risk) · [NCSC Ireland — QR phishing](https://www.ncsc.gov.ie/pdfs/Quick_Guide_QR_Code_Phishing_Scams.pdf) · [CISA — messaging app targeting (Nov 2025)](https://www.cisa.gov/news-events/alerts/2025/11/24/spyware-allows-cyber-threat-actors-target-users-messaging-applications) · [Chromium URL display guidelines](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/url_display_guidelines/url_display_guidelines.md) · ["Gone Quishing" (arXiv 2204.04086)](https://arxiv.org/abs/2204.04086)
341
+ - [Smith-Kettlewell BLaDE](https://www.ski.org/project/blade/) · [Google Lookout](https://support.google.com/accessibility/android/answer/9031274) · [NN/g — QR code guidelines](https://www.nngroup.com/articles/qr-code-guidelines/)
342
+ - [WCAG 2.2 — 1.3.4 Orientation](https://www.w3.org/WAI/WCAG22/Understanding/orientation.html) · [2.5.1 Pointer Gestures](https://www.w3.org/WAI/WCAG22/Understanding/pointer-gestures.html) · [2.2.1 Timing Adjustable](https://www.w3.org/WAI/WCAG22/Understanding/timing-adjustable.html)