Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
Multiplayer motion-controlled saber duel game with 3D combat, physics, mobile phone controller, and solo practice mode.
GamesTypeScript · CSSGitHub @e-yang6OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗A 3D lightsaber dueling game. Two players each bring their own laptop + phone — the phone is the sword controller, the laptop renders a first-person view with head-coupled parallax.
Player 1's Phone ──┐ ┌── Player 1's Laptop (first-person view)
(gyro sword) ├── Server ────┤
Player 2's Phone ──┘ (authoritative)└── Player 2's Laptop (first-person view)
(gyro sword) game state
npm install
npm run dev
Player 1 opens http://localhost:3000/player/ on their laptop. Player 2 opens the same URL (or the tunnel URL if remote). Each player scans the QR code on their laptop with their phone.
iOS Safari requires HTTPS for DeviceOrientation/DeviceMotion.
# In a second terminal:
npm run tunnel
This runs cloudflared tunnel --url http://localhost:3000 and gives you a temporary HTTPS URL. Both players open that URL on their laptops — the QR codes will point phones to the tunnel.
Install cloudflared: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
# In a second terminal:
npx ngrok http 3000
Gives you an HTTPS URL like https://xxxx.ngrok-free.app. Open that on your laptop instead of localhost — QR codes will point phones to the tunnel.
Note: ngrok free tier shows a "Visit Site" interstitial page. On your phone, you may need to open the base tunnel URL first, tap "Visit Site", then scan the QR code.
mkcert -install
mkcert localhost 192.168.x.x # your LAN IP
SSL_CERT=./localhost+1.pem SSL_KEY=./localhost+1-key.pem npm run dev
Safari can't do proper vibration on iPhone, so mobile/ is an Expo app version of the phone controller with layered Taptic haptics: a metallic clang on blade clashes, a thud that scales with swing power on hits, and a long rumble on smashes. It runs inside the free Expo Go app; no Xcode, Mac, or Apple developer account needed.
cd mobile
npm install
npx expo start # scan the QR it prints with your iPhone camera (opens Expo Go)
Then in the app, scan the QR code on your laptop. Phone and laptop must be on the same Wi-Fi as the game server (the app talks to it over plain ws:// on port 3000, so no certificate setup). Tunnel URLs work too.
Notes:
/player/ on their laptop| Class | Ability | Cooldown | Description |
|---|---|---|---|
| Guardian | Shockwave Push | 12s | Short-range blast that knocks opponent back |
| Striker | Overcharge | 15s | 4s of double knockback + longer blade |
| Mystic | Barrier | 18s | 3s bubble that auto-blocks everything |
| Phantom | Blink | 8s | Instant short dash in saber direction |
Add ?test to the player URL: http://localhost:3000/player/?test
Add ?debug to the player URL: http://localhost:3000/player/?debug
In src/shared/constants.ts:
export const FEATURES = {
HEAD_TRACKING: true, // Webcam head tracking for parallax
PARALLAX_CAMERA: true, // Off-axis head-coupled perspective
};
src/
├── server/
│ ├── index.ts # Express + Vite + WebSocket server (single port)
│ ├── session.ts # Game session: 2 slots, token-based phone linking
│ └── GameServer.ts # Authoritative game engine (physics, combat, rounds)
├── shared/
│ ├── protocol.ts # All message types (controller↔server↔player)
│ ├── math.ts # Vec3/Quat classes (no Three.js, used server-side)
│ ├── collision.ts # Segment/capsule collision (shared math)
│ ├── classes.ts # Class configs (stats, abilities)
│ └── constants.ts # Game constants + feature flags
└── client/
├── player/
│ ├── index.html # Player laptop page
│ ├── styles.css
│ ├── main.ts # Entry: lobby, QR, networking, game init
│ ├── network.ts # WebSocket client (role=player)
│ ├── FakeController.ts # Debug keyboard/mouse controller
│ ├── HeadTracker.ts # MediaPipe face tracking → parallax
│ └── game/
│ ├── GameRenderer.ts # First-person Three.js renderer
│ ├── Arena.ts # 3D arena: platform, water, sky, lighting
│ ├── Fighter.ts # Render-only character (snapshot interpolation)
│ ├── Saber.ts # Saber with glow, bloom, motion trail
│ ├── VFX.ts # Particles, sparks, hit flashes, screen shake
│ └── Audio.ts # Web Audio: sample SFX from public/sfx, synth hum + fallbacks
└── controller/
├── index.html # Phone controller page
├── styles.css
├── main.ts # Entry: permissions, token linking, UI, streaming
├── network.ts # WebSocket client (role=controller)
├── orientation.ts # DeviceOrientation → quaternion math
└── haptics.ts # Layered haptics (vibrate / iOS switch / flash)
ws WebSocket on a single portsrc/client/public/sfx/): CC0 packs from Kenney and OpenGameArt; per-file sources in src/client/public/sfx/CREDITS.txtsrc/client/public/models/golden-gate.glb; its built-in water slab is hidden at load)