cat through a QR code stream. Send files from your terminal to your iOS.
Inspired by @buckberi
iPhone: install and run QRCat app
qrcat is a Node.js CLI and companion iOS app for display-to-camera transfer. The default mode fills your terminal with a live QR sequence. The iOS receiver can scan that stream and reconstruct the original file.
- Fountain codes: qrcat emits extra packets that are XOR combinations of source chunks. If the receiver is missing a chunk, it can use the fountain packets to recover without needing a resend.
- Payload whitening: qrcat XORs the payload with a pseudorandom byte stream to break up long runs of zeros that would cause decoding failures.
- Deflate compression: qrcat compresses the payload when it makes the transfer smaller. The receiver inflates it back to the original bytes and verifies SHA-256 before writing the restored file.
Run directly with npm:
npx qrcat <file>Or install it globally:
npm install -g qrcat
qrcat <file>Node.js is required. MP4 output and video restore additionally require ffmpeg in PATH.
The iOS app lives in ios/QRCat.
open ios/QRCat/QRCat.xcodeprojRun it on an iPhone, point the camera at a qrcat terminal display or QR video, and share the restored file when reconstruction completes.
Show a file as QR frames in the terminal:
npx qrcat demo.pngSend stdin while preserving the restored file name:
cat demo.png | npx qrcat - --name demo.pngGenerate an MP4 QR video:
npx qrcat demo.png -o out.mp4Restore from a captured video:
npx qrcat restore captured.mp4 -o restored/Without -o, qrcat starts an interactive terminal display. Defaults are tuned for trying the iOS scanner quickly:
--fps 24--ecc L// L (Low), M (Medium), Q (Quartile), H (High) error correction levels--chunk-sizeauto-sized from the current terminal--fountain-ratio 0.2--loops 0, meaning run until stopped
Controls:
</>: adjust FPSf: enter a missing chunk number and show rescue QR framesspace: resume normal playback from a held chunkq: quit
If the terminal is too small, use fullscreen, reduce the font size, lower ECC, or pass a smaller --chunk-size.
Use -o to write an MP4:
npx qrcat demo.png -o out.mp4Video defaults:
--chunk-size 700--fps 3--ecc M--loops 1--size 1080--fountain-ratio 0
Video output uses ffmpeg. Terminal display does not.
Write one loop of QR PNG frames:
npx qrcat demo.png --debugWrite one loop as terminal-rendered PNGs, useful for checking what the terminal camera view should decode:
npx qrcat demo.png --debug-terminal --terminal-cols 120 --terminal-rows 40The iOS app lives in ios/QRCat.
open ios/QRCat/QRCat.xcodeprojRun it on an iPhone, point the camera at a qrcat terminal display or QR video, and share the restored file when reconstruction completes.
Each QR contains one binary QRC2 packet. qrcat emits source chunks plus optional fountain packets, then the receiver solves the collected equations over GF(2). The manifest is sent as logical chunk 0, so the file name, MIME type, original length, compression mode, and SHA-256 hashes are part of the recoverable stream.
The sender deflates the payload when it makes the transfer smaller. The receiver inflates it back to the original bytes and verifies SHA-256 before writing the restored file.
See design.md for the packet format and implementation notes.
Install dependencies and run tests:
npm install
npm testBuild and smoke-test the npm package:
./build.shThe package is pure Node.js and is tested on Linux, macOS, and Windows in GitHub Actions.
