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, provides fnv1a hashing and splitmix32 PRNG.
  • 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 via requestVideoFrameCallback.
  • 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 nextcaptureFramemakeFrame. 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.ts is the most connected internal module (12 functions, 3 types) and is imported by both sender and receiver.
  • shared/protocol.ts is imported by three files and defines the only cross‑module functions (packFrame, parseFrame).
  • receive/main.ts and send/main.ts each 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 Renovatepackage.json is 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/workflows or other pipeline definition; builds and linting are manual.
  • Low – License presentLICENSE exists, 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.