099d637815241b79666f819304272af3cb8426ed
The custom pointer-capture + frozen-camera drag math was fragile and felt worse than before. Konva handles the drag gesture itself; the "me" node's screen position stays pinned to the stage center via dragBoundFunc + a worldLayer offset that recenters on every dragmove, so the world pans under the avatar instead of the avatar drifting off center. Grid, peers, and the audible-range circle all live in the same world-space layer so they pan together. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
gibbz voice — POC
Discord-clone proof of concept: peer-to-peer WebRTC voice chat + screen sharing with position-based spatial audio and pluggable STUN/TURN.
Run (Node 18+, only dep is ws):
npm install
PORT=8081 npm start
# open http://localhost:8081, click a voice channel, allow mic
What works
- Mesh WebRTC voice (perfect negotiation; lowest peer id initiates)
- Screen share with audio (mic is spatialized, screen audio plays direct)
- Spatial audio: drag your avatar on the plane; remote mics run through a
PannerNode(HRTF, inverse distance). Positions sync over signaling. - Custom STUN/TURN: gear icon → JSON override in
localStorage, applied on next join. Server default comes from env (below). - Mute (M), deafen (D), per-peer volume, speaking indicators.
ICE configuration (server side)
| Env var | Meaning |
|---|---|
STUN_URLS |
comma-separated stun: urls (Google defaults) |
TURN_URLS |
comma-separated turn:/turns: urls |
TURN_USERNAME / TURN_CREDENTIAL |
static TURN creds |
ICE_SERVERS_JSON |
full {"iceServers":[...]} override, wins over the above |
PORT / HOST |
listen address (default 8081 / 0.0.0.0) |
Example with coturn:
TURN_URLS='turn:turn.example.com:3478?transport=udp,turns:turn.example.com:5349' \
TURN_USERNAME=mats TURN_CREDENTIAL=secret npm start
POC shortcuts (productionize later)
- No auth, no reconnection, rooms are in-memory, signaling is unencrypted ws behind the preview ingress (use wss/TLS in front for real deploys).
- No media server: N² mesh — fine for small rooms, needs SFU (mediasoup/livekit) beyond ~6–8 participants.
- Text channels are decorative. No persistence, no rate limiting.
- Screen-share negotiation storms on join/leave are expected at small scale.
Languages
JavaScript
75.1%
CSS
16.2%
HTML
7.5%
Makefile
0.9%
Dockerfile
0.3%