Send the whole box, peer-to-peer.
π Live app β Β Β·Β
π¦ Download
Drop as many files as you like (or paste some text), get one share link β a 4-character code + QR β and it travels directly from your browser to the recipient's over WebRTC. Nothing is stored on any server.
Inspired by the delightful simplicity of FilePizza β rebuilt as a 100% static site so it can be hosted anywhere (GitHub Pages, Netlify, an S3 bucket, or just opened locally).
- Multi-file by default β send any number of files together in one link.
- Drag & drop files or whole folders (folders are flattened automatically).
- Text / snippet mode β share a message, link, or code block instead of files.
- True peer-to-peer β bytes go browser β browser over an encrypted WebRTC data channel (DTLS). Only a tiny signaling handshake uses the free public PeerJS broker.
- No server storage, no size caps, no sign-up.
- Password protection (optional) β gate a box behind a password before the file list is even revealed.
- Stream huge files straight to disk β using the File System Access API:
- πΎ Save an individual file directly to disk (no memory buildup).
- πΎ Save all to folder β streams every file into a folder you pick, ideal for large batches.
- Graceful
.zipfallback (in-memory, via JSZip) on browsers without the API (Firefox/Safari).
- Live transfer stats β speed, ETA, and overall progress on both the sender and receiver side, plus per-file progress bars.
- Share how you like β copy the link, share the 4-char code, or scan the QR.
- Nice touches β light/dark theme, Screen Wake Lock so transfers don't stall when the screen sleeps, a connect notification (toast + beep) when a receiver joins, and multi-receiver support.
- Self-contained β PeerJS, JSZip and the QR library are vendored into
libs/, so there are no runtime CDN dependencies.
- Sender picks files (or text) β the app registers a short peer ID on the public broker and shows a link/code/QR.
- Receiver opens the link (or types the code) β their browser opens a direct WebRTC connection to the sender. If the box is password-protected, they unlock it first.
- The sender streams the requested files in 64 KB chunks straight to the receiver, who either saves them to disk on the fly or reassembles them and zips them.
Both tabs must stay open during the transfer β that's the nature of true P2P, and it's why nothing ever touches a server.
Any static file server works, e.g.:
# Python
python3 -m http.server 8000
# or Node
npx serve .Then open http://localhost:8000. Open a second tab/device with the generated link to receive.
WebRTC + PeerJS need a secure context.
localhostcounts as secure, and so does anyhttps://host β which is why GitHub Pages works out of the box. The File System Access "save to disk" features are Chromium-only (Chrome/Edge/Opera); other browsers automatically fall back to the in-memory.zipdownload.
This repo ships with .github/workflows/deploy.yml. Just:
- Push the project to a GitHub repo (
mainbranch). - Go to Settings β Pages β Build and deployment β Source = GitHub Actions.
- Every push to
mainnow builds and deploys automatically. Your app lands athttps://<you>.github.io/<repo>/.
- Push the contents of this folder to a repo.
- Settings β Pages, set Source = Deploy from a branch, Branch =
main/root, save.
Either way there's no build step and no backend. (.nojekyll is included so nothing gets filtered by Jekyll.)
git init
git add .
git commit -m "PizzaBox"
git branch -M main
git remote add origin https://github.com/<you>/<repo>.git
git push -u origin mainindex.html # markup + all views (compose / send / receive / join)
css/styles.css # styling & theme
js/app.js # sender + receiver logic, WebRTC transfer, streaming, zip
libs/ # vendored peerjs, jszip, qrcode (no CDN needed)
.github/workflows/deploy.yml # auto-deploy to GitHub Pages
.nojekyll # tell Pages to serve files as-is
LICENSE # MIT
- Files/text are transferred directly and encrypted in transit (WebRTC/DTLS). They never pass through PizzaBox's or GitHub's servers.
- The public PeerJS broker only relays the initial connection handshake, never your data.
- Password protection gates access to the box over the encrypted channel β good for casual protection, but it isn't a zero-knowledge scheme.
- The zip fallback assembles files in the receiver's memory; for multi-GB batches prefer "Save all to folder" (Chromium), which streams to disk with no memory buildup.
- Want zero third-party signaling? Run your own PeerJS server and point
PEER_OPTSinjs/app.jsat it.
Made with π and WebRTC.
