Skip to main content

Overview

Hyperscape is a real-time multiplayer game using WebSocket connections for low-latency communication between clients and the authoritative server.

Network Architecture

Server Authority

The server is the single source of truth:
Clients predict movement locally but server corrects if needed.

Entity Synchronization

Sync Flow

  1. Server processes game tick (600ms)
  2. Entity changes collected via markNetworkDirty()
  3. Delta updates sent to clients at 20 Hz
  4. Clients apply updates and interpolate

Entity Network Data

Sync Data

Equipment Synchronization

Equipment visibility is synchronized across all players with proper VRM avatar loading:
Equipment Sync Flow:
  1. On player join: Server sends existing players’ equipment to joiner
  2. On player join: Server broadcasts joiner’s equipment to all other players
  3. On equipment change: Server broadcasts update to all nearby players
  4. On reconnect: Server re-sends all equipment (packets may be lost during disconnect)
VRM Avatar Loading: Equipment is cached and replayed when VRM avatars finish loading:
Equipment Slot Coverage: The system now uses all 11 equipment slots instead of hardcoded 6:
Avatar Helper: The getAvatar() helper resolves VRM from both PlayerLocal and PlayerRemote:
This ensures equipment visuals work correctly for both local and remote players.

Position Synchronization

Player positions are synchronized with spatial index updates to ensure proper network visibility:
Spatial Index Integration: The spatial index tracks player positions for efficient sendToNearby() queries:
Critical Fixes (PR #875):
  • Spatial index now updated after teleport (fixes invisible combat movement in duels)
  • Spatial index updated after respawn (fixes missing entity broadcasts)
  • Authoritative position broadcast to all players on join (fixes initial transform sync)

Remote Avatar Transform Sync

Remote player avatars are positioned and animated before being made visible to prevent T-pose flashing:
Before Fix: VRM avatar set to visible=true before instance.move() positioned it, causing one frame of T-pose at (0,0,0) After Fix: Avatar positioned and animated into idle pose before visibility enabled Quaternion Sync: Remote player quaternions are now properly synced to prevent sideways-facing avatars:
Before Fix: base.quaternion not synced, causing remote players to face sideways After Fix: Both position and quaternion synced to base transform for correct orientation

WebSocket Protocol

Connection

Message Types

Persistence

Database Schema

Player data stored in PostgreSQL using Drizzle ORM:

Save Strategy

  • Immediate: Critical changes (item transactions)
  • Periodic: Stats, position (every 30 seconds)
  • On disconnect: Full state save

Authentication

Using Privy for identity:
  1. Client authenticates with Privy
  2. JWT token sent to server
  3. Server validates token
  4. Session established
Without Privy credentials, each session creates a new anonymous identity.

LiveKit Integration

Optional voice chat via LiveKit:
  • Spatial audio based on position
  • Push-to-talk or voice activation
  • Server-managed rooms
Configure with LIVEKIT_API_KEY and LIVEKIT_API_SECRET.

Scalability

Current Architecture

  • Single server instance
  • All players in shared world
  • SQLite for development, PostgreSQL for production

Future Considerations

  • Multiple server instances
  • Zone-based sharding
  • Load balancing

Network Files