A fully production-grade, single-file educational website that explains the complete engineering lifecycle of a barcode scanner β from laser photons to decoded product numbers β with a live real-time camera scanner built in.
Open barcode-scanner.html in any modern browser (Chrome or Edge recommended).
| Section | Description |
|---|---|
| Hero | Animated scanner illustration with live laser beam + decoded output cycling |
| How It Works | 6-step process breakdown with hover cards |
| Reflection Demo | Live bar strip + analog waveform canvas animation |
| Live Decoder | Type any UPC-A code β full digit-by-digit binary decode |
| EAN-13 Anatomy | Visual digit map with colour-coded zones |
| Signal Flow | Animated 6-node pipeline diagram |
| Data Structures | 4 code cards with real implementation examples |
| Components | 6 hardware component cards with specs |
| π· Live Camera Scanner | Real-time barcode detection via webcam/phone camera |
- Full 6-step scan process: Laser β Reflection β Photodiode β ADC β Decoder β POS
- Physics layer: visual bar strip with animated laser cursor and live photodiode waveform
- EAN-13 digit structure breakdown (Country / Manufacturer / Product / Check Digit)
- Signal flow pipeline with animated data chips at each hardware stage
- Enter any 12-digit UPC-A code
- Renders the barcode visually using real L-code / R-code encoding
- Decodes each digit's 7-bit binary pattern in a table
- Validates the Mod-10 checksum in real time
- Updates on every keystroke
- Real-time camera feed with animated laser sweep and corner bracket targeting UI
- Dual detection engine:
- ZXing (
@zxing/library) β primary, wide format support - Native
BarcodeDetectorAPI β hardware-accelerated fallback (Chrome/Edge)
- ZXing (
- Supported formats: EAN-13, EAN-8, UPC-A, UPC-E, Code 39, Code 128, ITF, QR Code, DataMatrix, Codabar
- Green bounding box drawn on detected barcode location
- Audio beep on successful scan
- Full digit-by-digit breakdown for numeric barcodes (EAN/UPC)
- Scan history (last 8 scans) with click-to-replay
- Front/back camera switch
- Pre-flight
navigator.permissions.query({ name: 'camera' })check on page load - Contextual step-by-step fix guide shown inside the viewfinder for each error type:
| Error | Shown Guide |
|---|---|
NotAllowedError |
Chrome address bar β π icon β Camera β Allow |
file:// protocol |
Instructs to serve via localhost using a local server |
NotFoundError |
"No camera hardware found" message |
NotReadableError |
Lists apps to close (Zoom, Teams, Meet) |
| Unsupported browser | Chrome/Edge recommendation |
- β» Retry Camera button resets and retries
getUserMediawithout page reload - Info note below controls updates dynamically with permission state
| Structure | Used For |
|---|---|
| HashMap / Lookup Table | UPC digit encoding (7-bit pattern β decimal) |
| Ring Buffer (Array) | ADC bitstream circular buffer |
| Stack | Guard pattern detector (start / middle / end guards) |
| Array + Modular Arithmetic | Mod-10 checksum validator |
barcode-scanner.html β Entire project β single self-contained file
README.md β This file
The entire application is a single HTML file with no build step, no bundler, no framework. CSS, JS, and HTML are all inline.
# Just double-click barcode-scanner.html
# OR open it via your browser's File menu
β οΈ Camera will be blocked by Chrome onfile://β use Option 2 for the live scanner.
Python (built-in):
python3 -m http.server 8080
# Then open: http://localhost:8080/barcode-scanner.htmlNode.js (npx):
npx serve .
# Then open the URL shown in terminalVS Code:
Install the Live Server extension β right-click barcode-scanner.html β Open with Live Server
| Browser | Camera Scanner | Decoder | Animations |
|---|---|---|---|
| Chrome 88+ | β Full support | β | β |
| Edge 88+ | β Full support | β | β |
| Firefox | β | β | |
| Safari 17+ | β | β | |
| Mobile Chrome | β (back camera) | β | β |
The live scanner requires HTTPS or localhost. It will not work over plain
http://on remote servers due to browser security policy.
All loaded via CDN β no local installation needed.
| Library | Version | Purpose |
|---|---|---|
@zxing/library |
0.21.3 |
Primary barcode detection engine |
JetBrains Mono |
Google Fonts | Monospace code/data typography |
Syne |
Google Fonts | Display/heading typography |
Camera Feed (getUserMedia)
β
βΌ
Frame Capture (canvas drawImage every ~300ms)
β
ββββΊ ZXing BrowserMultiFormatReader.decodeFromCanvas()
β ββ Tries all formats in hints map
β
ββββΊ BarcodeDetector.detect(canvas) [fallback]
ββ Native browser API, hardware-accelerated
β
βΌ
onBarcodeDetected(code, format, cornerPoints)
β
ββ Debounce: skip if same code seen < 2 seconds ago
ββ drawDetectionBox(cornerPoints) β canvas overlay
ββ playBeep() β AudioContext oscillator
ββ setScannerState('success') β UI feedback
ββ showDecodedResult(code, format)
ββ drawBreakdown(code) β digit grid + checksum
ββ addToHistory(code, format)
// Left-side L-code (digits 1β6 of UPC-A)
const UPC_L = {
0: '0001101', 1: '0011001', 2: '0010011',
3: '0111101', 4: '0100011', 5: '0110001',
6: '0101111', 7: '0111011', 8: '0110111',
9: '0001011'
};
// Right-side R-code (digits 7β12 of UPC-A) β complement of L-code
const UPC_R = {
0: '1110010', 1: '1100110', 2: '1101100',
3: '1000010', 4: '1011100', 5: '1001110',
6: '1010000', 7: '1000100', 8: '1001000',
9: '1110100'
};function validateChecksum(digits) {
const weights = [3,1,3,1,3,1,3,1,3,1,3]; // alternating for UPC-A
let sum = 0;
for (let i = 0; i < 11; i++) sum += digits[i] * weights[i];
return (10 - (sum % 10)) % 10 === digits[11];
}| Token | Value | Usage |
|---|---|---|
--bg |
#050a0e |
Page background |
--laser |
#00ff88 |
Primary accent, laser green |
--laser2 |
#00e5ff |
Secondary accent, cyan |
--red-laser |
#ff3c3c |
Laser beam colour, errors |
--gold |
#ffd166 |
Warnings, highlights |
--muted |
#6b8fa0 |
Secondary text |
Fonts: Syne (headings/UI) + JetBrains Mono (code/data)
| Concept | Where Covered |
|---|---|
| Laser physics (650nm, Class 2) | Hero section + Components |
| Photodiode + TIA amplifier | Signal Flow node 3 |
| ADC + Schmitt trigger | Signal Flow node 4 + Step 4 |
| Guard patterns (101, 01010, 101) | Data Structures β Stack card |
| Module width timing | Step 5 β Pattern Decoding |
| USB HID keyboard emulation | Step 6 + Signal Flow node 6 |
| EAN-13 vs UPC-A structure | EAN-13 Anatomy section |
| Mod-10 check digit | Data Structures β Checksum card |
Change the hero barcode pattern:
// In the script section, edit heroPattern array
const heroPattern = [2,1,2,1,1,3,1,2,1,1,1,2,3,...];Add more barcode formats to ZXing:
const formats = [
ZXing.BarcodeFormat.EAN_13,
ZXing.BarcodeFormat.PDF_417, // add PDF-417
ZXing.BarcodeFormat.AZTEC, // add Aztec
// ...
];Adjust scan throttle rate (default 300ms):
if (now - lastScan < 300) return; // change 300 to desired msBuilt for educational purposes. Free to use, share, and modify.
BARCODELAB β From photons to product codes.