The Problem
Transferring a binary file between two devices without any network link is difficult when only a screen and a camera are available. Conventional QR‑code approaches require a full handshake or repeated scans, and any dropped frame forces a full retransmission, leading to low throughput and fragile user experience.
What This Does
decimen-optical-transfer implements a proof‑of‑concept optical link that streams a file as an endless sequence of animated QR codes. The sender (send/main.ts) encodes each frame with a fountain‑code payload, while the receiver (receive/main.ts) captures video, decodes frames in a Web‑Worker (receive/worker.ts), and reconstructs the file using the robust‑soliton distribution defined in shared/fountain.ts.
Key files:
shared/protocol.ts– packs and parses the 20‑byte frame header, providesfnv1ahashing andsplitmix32PRNG.shared/fountain.ts– implements the soliton CDF, frame seed generation, XOR mixing (xorInto), and frame index calculation.send/main.ts– entry point for the sender UI, creates the canvas, builds frames (makeFrame) and streams them viarequestVideoFrameCallback.receive/main.ts– entry point for the receiver UI, starts the camera, schedules frame capture (scheduleFrame), and drives the decoding pipeline (onDecoded).
The project uses Vite (vite.config.ts) for a HTTPS dev server (required for getUserMedia) and TypeScript for all code.
How It Is Wired
Execution start – Opening https://localhost:5173/send/ loads send/index.html, which runs send/main.ts (line 43). The main function creates the UI, calls loadPayload (selects a 512 KB or 2 MB image) and invokes startStream.
startStream (called from two places) builds a frame loop: it repeatedly calls scheduleFrame, which in turn calls next → captureFrame → makeFrame. makeFrame uses shared/fountain.ts functions frameSeed, frameIndices, and xorInto to XOR a random subset of file blocks, then calls shared/protocol.ts packFrame to prepend the header. The resulting canvas image is painted for the camera to see.
On the receiving side, opening receive/index.html runs receive/main.ts. The start button triggers start, which obtains a video stream and registers scheduleFrame. Each animation frame calls next, which calls captureFrame to grab a video frame and forwards it to the Web‑Worker (receive/worker.ts). The worker runs ZXing‑WASM; when a QR code is decoded it posts a message that invokes onDecoded in receive/main.ts.
onDecoded parses the header with shared/protocol.ts parseFrame, validates the hash (fnv1a), and then calls a chain of functions: addFrame, assemble, xorInto, frameIndices, and finally fnv1a again to verify integrity. Successful reconstruction triggers finish, which presents the recovered image.
Call‑graph hot spots –
shared/fountain.tsis the most connected internal module (12 functions, 3 types) and is imported by both sender and receiver.shared/protocol.tsis imported by three files and defines the only cross‑module functions (packFrame,parseFrame).receive/main.tsandsend/main.tseach have an instability of 1 (they only import but are not imported), indicating they are leaf entry points.
No circular dependencies exist, so changing a utility in shared/fountain.ts will propagate predictably to both directions.
How To Use It
# Clone the repository
git clone https://github.com/moses-y/decimen-optical-transfer
cd decimen-optical-transfer
# Install dependencies
npm install
# Start the HTTPS dev server (self‑signed cert)
npm run dev
Open a browser on the sending device at https://localhost:5173/send/. The UI starts streaming immediately.
Open a browser on the receiving device (phone on the same LAN) at the URL printed by Vite, e.g. https://<lan‑ip>:5173/receive/. Tap Start camera, grant permission, and point the camera at the screen. The receiver will display “Transfer Complete!” and show the reconstructed image.
No additional configuration files, environment variables, or build steps are required.
Real‑World Use
A field technician could deploy this on a rugged laptop to transmit firmware updates to a handheld scanner that lacks Wi‑Fi but has a camera. The technician runs the sender UI, points the scanner’s camera at the laptop screen, and the scanner reconstructs the binary without any network credentials.
Code Health & Issues
- Medium – Enable Dependabot or Renovate –
package.jsonis the only manifest; no update bot is configured. - Medium – No test suite – repository contains zero test files, leaving code paths unverified.
- Medium – No CI/CD – no
.github/workflowsor other pipeline definition; builds and linting are manual. - Low – License present –
LICENSEexists, but no explicit contribution guidelines.
All findings are derived from static analysis; no hidden secrets or Docker artefacts were detected.
The Bottom Line
The repo delivers a compact, functional optical file‑transfer demo with a clear separation between encoding (send/) and decoding (receive/). The core fountain‑code logic is well‑encapsulated in shared/, making it the primary target for extension or bug fixes. However, the lack of automated tests, CI, and dependency‑update tooling means any production use would require additional engineering effort to ensure reliability and maintainability. Suitable for research, demos, or low‑volume field deployments where the novelty outweighs the operational overhead.