cd /news/developer-tools/show-hn-shadowcat-file-transfer-thro… · home topics developer-tools article
[ARTICLE · art-8698] src=github.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Show HN: ShadowCat – file transfer through QR Codes in a Browser

ShadowCat is a fully offline, single-file HTML page that enables data transfer between two devices by encoding files into a sequence of QR codes, designed for old phones with working cameras and browsers but non-functional radios. The sender encodes a file into chunks displayed as QR codes at a chosen frame rate, while the receiver scans them via camera, tracks missing chunks, and verifies the file's CRC before allowing download. The tool supports adjustable chunk size, FPS, and error correction, with a typical transfer speed of about 0.83 KB/s raw data, requiring one to two loops for a 100 KB file.

read2 min views14 publishedMay 22, 2026

A fully offline, single-file HTML page for moving data between two devices via QR codes — intended for old phones whose radios (BLE, NFC, etc.) arevdead but whose cameras and browsers still work.

  • Generate — encode text into a single QR code.
  • Scan — decode a single QR via the camera.
  • Send file — pick a file, choose chunk size / FPS / ECC, hit Start. Cycles through [header, chunk1…chunkN] forever at the chosen FPS. / Resume / Stop. - Start from — begin the loop at a chosen frame index; it then continues forward and wraps back to the header normally.
  • Show frame + Show / − / + — display exactly one frame static, for resending a specific missing chunk. The number matches the chunk index shown in the receiver's missing-chunks grid (0 = header).
  • Receive file — start the camera and point at the sender. Header autodetects, progress bar fills in, missing-chunks grid shows which ones haven't arrived yet. When complete, the file's CRC is verified and a Download button appears.
- Header:
QRX1|H|<total>|<filename>|<sizeBytes>|<crc32hex>
- Data:
QRX1|D|<idx>|<base64chunk>
(1-indexed) - Base64 alphabet has no

| , so parsing is justsplit('|') . - Receiver tracks chunks by index, ignores duplicates, dedupes header by CRC.

  • Camera needs HTTPS or localhost — file:// won't grantgetUserMedia permission. Serve withpython3 -m http.server 8000 and visithttp://<your-laptop-ip>:8000/qrcode.html over the local network. iOS Safari additionally requires HTTPS for cross-device access — for a LAN setup,caddy or a self-signed cert helps. - If render fails on a frame ("code length overflow"), drop chunk size or drop ECC level.
  • 500 chars × 3 fps ≈ 1.1 KB/s base64 ≈ 0.83 KB/s raw. A 100 KB file is roughly 2 minutes per loop; receiver typically needs 1-2 loops.
  • If old devices struggle to decode: lower FPS, raise ECC to Q, shrink chunk to ~300 chars — produces smaller, less dense QRs.
── more in #developer-tools 4 stories · sorted by recency
── more on @shadowcat 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-shadowcat-fi…] indexed:0 read:2min 2026-05-22 ·