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

unprovable1 pts1 comments

GitHub - unprovable/ShadowCat: Single file optical file transfer using a browser · GitHub

/" data-turbo-transient="true" />

Skip to content

Search or jump to...

Search code, repositories, users, issues, pull requests...

-->

Search

Clear

Search syntax tips

Provide feedback

--><br>We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Cancel

Submit feedback

Saved searches

Use saved searches to filter your results more quickly

-->

Name

Query

To see all available qualifiers, see our documentation.

Cancel

Create saved search

Sign in

/;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up

Appearance settings

Resetting focus

You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

{{ message }}

unprovable

ShadowCat

Public

Notifications<br>You must be signed in to change notification settings

Fork

Star

main

BranchesTags

Go to file

CodeOpen more actions menu

Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit

History<br>3 Commits<br>3 Commits

README.md

README.md

shadowcat.html

shadowcat.html

View all files

Repository files navigation

ShadowCat

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.

Tabs

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. Pause / 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.

Protocol

Header: QRX1|H||||

Data: QRX1|D|| (1-indexed)

Base64 alphabet has no |, so parsing is just split('|').

Receiver tracks chunks by index, ignores duplicates, dedupes header by CRC.

Practical notes for old phones

Camera needs HTTPS or localhost — file:// won't grant getUserMedia permission. Serve with python3 -m http.server 8000 and visit http://: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.

About

Single file optical file transfer using a browser

Resources

Readme

Uh oh!

There was an error while loading. Please reload this page.

Activity

Stars

stars

Watchers

watching

Forks

forks

Report repository

Releases

No releases published

Packages

Uh oh!

There was an error while loading. Please reload this page.

Contributors

Uh oh!

There was an error while loading. Please reload this page.

Languages

HTML<br>100.0%

You can’t perform that action at this time.

file header shadowcat reload single search

Related Articles