Inspiration
I'm a huge anime fan and I watch on my phone all day. At home, a small phone screen feels silly next to a TV or laptop. Getting the file across meant a USB cable and 10 to 15 minutes of copying for 3 GB, a cloud upload for two devices sitting two feet apart, or screen mirroring that stutters and drains the battery. At 2 AM, watching a progress bar, I asked: why wait for the whole file when my phone already has the bytes and my router is idle?
What it does
Veltrix moves files across your own Wi-Fi with no cloud and no account. Files are cut into chunks and hashed with SHA-256 as they stream, so corrupt data is rejected immediately, and a file is only renamed to its final name after its hash matches. As a second feature, a video can start playing on another screen while it is still being served over HTTP 206 range requests. Pause on one screen, switch, and it resumes at the same second. Your position is saved to disk on pause, so nothing keeps running in the background.
How I planned it
I followed the hackathon's plan-first workflow and wrote PROJECT_PLAN.md and ENGINE_PLAN.md before the code. The plan set four rules I kept to:
- Engine first: the Rust core had to work as a command-line tool before any UI existed.
- Measure first: no speed claim without a benchmark.
- Honest about networks: detect isolated Wi-Fi and fall back to direct IP or QR instead of pretending it works.
- Never invent crypto or formats: standard SHA-256 and simple length-prefixed framing.
Because of that order, the engine had 14 passing integration tests (chunk boundaries, corrupted bytes, dropped sockets, version mismatches) before I built the web app. The main thing I cut was Android testing: I don't own an Android device, so the APK is built but unverified on real hardware. I scoped the project around what I can prove on my laptop, with file transfer first and video streaming second.
How it's built
- Rust core (Tokio, Postcard, SHA-2): 4-byte length-prefixed framing with a 16 MiB cap, a versioned handshake, bounded 1 MiB chunks with backpressure so memory stays flat, and a
.part/.part.manifestscheme for resumable transfers. - Filename safety: names are sanitized so
../paths and Windows reserved names likeCONandNULare rejected. - Web app (vanilla JS, Vite): drag-and-drop transfer, video streaming, and the phone and TV views, kept in sync with Server-Sent Events.
- Capacitor packages the Android APK.
Challenges
- Audio echo: 30 to 150 ms of network jitter made two devices play the same audio. Fix: strict single-audio routing, sender muted, receiver as the only speaker.
- iOS Safari autoplay rules:
playsinline, one video element, and a tap-to-unmute step. - 10-bit HEVC MKV files: browsers play the audio over a frozen frame. I standardized on H.264/AAC MP4/WebM and added format warnings, but 10-bit HEVC still doesn't play.
- Routers and client isolation: dynamic IPs and isolated guest networks broke simple discovery, so I built several connection paths.
What I measured
On my own hardware, the Rust engine moved 100 MB at 73.15 MB/s and 1 GB at 71.93 MB/s with a verified SHA-256 and memory use under 25 MB. The web app's LAN slice path reached about 78 MB/s. Logs are in benchmarks/. These are results from my setup, not a comparison with AirDrop or Quick Share.
What I learned
Planning first and building the engine before the UI kept the project from turning into a pile of screens on top of a shaky core. Streaming byte ranges also changed what "transfer" means: playback doesn't need the whole file. And real networks and browser codecs can say no in many ways.
What's next
TLS encryption (rustls), folder transfer, native TV apps, and testing the Android APK on a real device.
Built With
- a-15-minute-copy
- android
- capacitor
- css3
- github
- html5
- http-206
- javascript
- jsqr
- or-a-cloud-upload.-veltrix-lets-me-start-playback-on-my-tv-from-my-phone-almost-instantly-and-resume-at-the-exact-second-i-paused.-it-also-replaced-the-"which-app-do-i-use-to-move-this-file"-problem-for-apks
- qrcode
- rust
- server-sent-events
- sha-256
- tokio
- vite

Log in or sign up for Devpost to join the conversation.