e50aee1e62e94b36f1b41e5d9ccd2e37cf76bc4a
surf.nathan.rip
Momentum Mod surf replay hosting - video + .mtv replay files with automatic map tier badges, stage splits, and PB history.
Architecture
| Layer | Stack |
|---|---|
| Frontend | React + Vite + Tailwind CSS v4 |
| Backend | ElysiaJS (Bun) |
| Storage | RustFS (S3-compatible) |
| Database | SQLite |
How it works
- Upload a video +
.mtvreplay file via the auth-gated upload page - Backend parses the
.mtvbinary header for metadata (map, player, time, Steam ID, stage splits) - Map tier and thumbnail are fetched from the Momentum Mod API
- Video uploads go directly to RustFS via presigned URLs (no size limit)
- If a better time is uploaded for the same map+player, the PB is updated and the old run is archived as a previous PB
Setup
# Backend
cd backend
cp .env.example .env # edit with your credentials
bun install
bun run dev
# Frontend
cd frontend
bun install
bun run dev
The frontend dev server proxies /api to localhost:3001.
Environment variables
| Variable | Required | Description |
|---|---|---|
ADMIN_TOKEN |
Yes | Bearer token for upload/delete auth |
RUSTFS_ENDPOINT |
No | S3 endpoint (default: http://localhost:9000) |
RUSTFS_ACCESS_KEY |
No | S3 access key |
RUSTFS_SECRET_KEY |
No | S3 secret key |
RUSTFS_BUCKET |
No | S3 bucket name (default: surf) |
RUSTFS_PUBLIC |
No | Public read access (default: true) |
PORT |
No | Server port (default: 3001) |
DB_PATH |
No | SQLite path (default: ./data/surf.db) |
STATIC_DIR |
No | Frontend static files (default: ./public) |
RustFS setup
- Create a bucket called
surfin your RustFS instance - Set bucket to public read for direct video URLs
- Configure CORS on the bucket to allow
PUTfrom your frontend origin (required for presigned video uploads) - Create an IAM policy with
s3:ListBucket,s3:GetObject,s3:PutObject,s3:DeleteObjectonsurf/*
.mtv file format
195-byte binary header followed by JSON stats and LZMA-compressed replay data.
| Offset | Size | Field |
|---|---|---|
| 0x00 | 4 | Magic (MMTV = 0x56544D4D) |
| 0x04 | 4 | Version |
| 0x10 | 64 | Map name (null-terminated) |
| 0x50 | 41 | Map hash |
| 0x7B | 4 | Tick interval (float) |
| 0x7F | 8 | Steam ID (uint64) |
| 0x87 | 32 | Player name (null-terminated) |
| 0xA9 | 8 | Run time (double) |
| 0xB1 | 4 | Total ticks |
Description
Languages
TypeScript
98.7%
CSS
0.5%
Dockerfile
0.4%
HTML
0.4%