How it works
Copy-paste signaling
Before a direct connection exists, each side must hand the other a
short description of how to reach it (WebRTC session-setup text, packed
here to a couple hundred characters). That exchange is the two of you:
the invite link carries the sender's offer in its #fragment
— the part of a URL that browsers never send to any server —
and the reply link carries the answer back the same way. When the sender
clicks the reply link, the newly opened tab hands the answer to the
still-open invite tab over a same-origin BroadcastChannel
and can then be closed — two clicks, one connection. This requires
both clicks to happen in the same browser; otherwise scan, or paste the
code. Each side waits until it has finished mapping its network routes
before producing its code, so a single code carries everything and the
exchange happens exactly once per side.
Phone-to-phone by QR
Because a format-2 code is only a few hundred characters, the invite
and reply links fit in a scannable QR. The sender shows the invite QR; the
recipient scans it with their camera app, which opens the reply page;
that page shows a reply QR; the sender taps Scan reply to open an
in-page camera preview (getUserMedia) and reads it, feeding the
answer straight to the connection — no second tab, no
BroadcastChannel. Decoding uses the browser's native
BarcodeDetector where present and falls back to a bundled
decoder on Safari. Laptops have cameras too; a camera-less desktop keeps the
link/paste paths, which never go away.
Same-room by sound
The same codes can travel as audio: Play invite as sound encodes
the code into a few seconds of tones (4.5–7.3 kHz, four tones at
a time, with error correction and a checksum), and the other device's
Listen button decodes it from the microphone — works speaker to
mic between any two devices in the same room, in either direction, one at a
time. A received signal identifies itself as an invite or a reply, so the
listener always routes it correctly. Like every path here, sound only
carries the setup code; the file itself still moves over the encrypted
WebRTC channel.
Peer-to-peer transfer
Files stream over the resulting data channel, DTLS-encrypted, in
64 KB chunks with backpressure. Every file is SHA-256 hashed before
sending and verified on arrival; a mismatch is discarded. Transfers are
capped at 2 GB (assembled in memory). Incoming files must be accepted
before any bytes flow.
On a phone the 2 GB cap is theoretical: mobile Safari's per-tab
memory ceiling makes a few hundred MB the practical limit for a single
file, since the receiver holds the whole thing in RAM before saving. The
page also requests a screen wake lock while a QR is showing or a
transfer is running (Safari 16.4+, Chrome, others) so the display does
not sleep mid-scan or mid-transfer; if the lock is refused, just keep the
screen on manually.
Scope and trust
No peer discovery, no rooms, one connection per page: you connect to
exactly the person you exchanged codes with — the trust boundary is
whatever channel carried the code. One caution: the code contains your
machine's network addresses, so only send invites to people you would
tell your IP address.