Sender
Receiver
Camera input is processed locally in your browser only and is not uploaded to any server.
Protocol QRT1
Each QR code encodes one UTF-8 text frame. Fields are separated by |.
Header frame
QRT1|H|<sid>|<totalChunks>|<fileSize>|<chunkSize>|<mime>|<base64Name>|<colorLevels>
Data frame
QRT1|D|<sid>|<index>|<base64Data>
- sid: 6-char random session id, prevents mixing transfers.
- index: 0-based chunk index.
- base64Data: standard base64-encoded raw bytes of the chunk.
- base64Name: base64-encoded UTF-8 filename.
- colorLevels: brightness levels per RGB channel used by the sender —
1= B&W,2= 8-color (3 frames/image),4= 64-color (6 frames/image). Optional for backward compatibility; missing =1.
The sender loops continuously through all chunks and re-emits the header every 8 frames so the receiver can join at any time and recover from missed frames.
Color QR mode
To increase per-image capacity, the sender can pack multiple QRT1 frames into one image by writing each frame into a separate bit-plane of the RGB channels.
- 8 colors — each channel has 2 levels (dark / light). One QR per channel → 3 frames per image. Colors: white, black, cyan, magenta, yellow, red, green, blue.
- 64 colors — each channel has 4 brightness levels (0, 85, 170, 255). Two QRs per channel (high bit + low bit) → 6 frames per image. Requires reasonably accurate camera color reproduction.
All QRs in one image share the same version/module grid so they align pixel-for-pixel. The receiver splits each captured frame back into per-channel grayscale images (using adaptive min/max thresholding so screen brightness and camera white balance can drift), reconstructs the bit-planes, and decodes each binary QR independently. Plain B&W QRs still decode in color mode because R=G=B.