Skip to main content

P2P Sync (Yjs)

WEFA uses Yjs CRDTs for realtime multiplayer sync. Documents are small and scoped to game sessions.

Transport Modes

ModeProviderUse Case
webrtcy-webrtcLocal network play (peer discovery)
websocketWebSocket relayGlobal play via relay server
hybridBothWorld mode: WebRTC with WebSocket fallback

Transport resolution:

// From src/modules/yjs.ts
function resolveYjsTransport(mode: GameMode): TransportConfig {
if (mode === 'device') return null; // no sync needed
if (mode === 'local') return 'webrtc';
if (mode === 'world') return 'hybrid'; // graceful degradation
}

Yjs Document Structure

Each game session creates a Y.Doc with:

Y.Doc
├── Y.Map('game')
│ ├── type: string (game type)
│ ├── turn: number
│ ├── status: string
│ └── board: Y.Map (game-specific state)
├── Y.Array('players')
│ └── [{ id, name, creature, seat }]
├── Y.Array('moves')
│ └── [{ player, move, timestamp }]
└── Y.Map('setup')
├── p0: { playerId, creatureId, ready }
├── p1: { playerId, creatureId, ready }
├── gameType: string
└── startSignal: boolean

Setup State Sync

Before a match starts, the setup state syncs:

  1. Seat claim: Host claims p0, guest claims p1
  2. Game type sync: Host sets game type, guest reads it
  3. Creature selection: Each player sets their own seat's creature
  4. Start signal: Host signals when both players are ready

Seat takeover protection prevents a second peer from claiming an occupied seat.

Move Validation

All incoming remote moves are validated through the rules engine before being accepted into local state. Invalid moves are rejected.

Persistence

y-indexeddb provides offline persistence for Yjs documents, allowing interrupted sessions to resume.

Signaling

The Fly.io API server (packages/api) includes a WebSocket signaling relay for y-webrtc peer discovery. The endpoint is configurable via VITE_SIGNALING_URLS.

Key Files

  • src/modules/yjs.ts - Session creation, transport resolution, setup sync
  • src/modules/yjs.test.ts - Transport and sync tests
  • src/hooks/yjs/useYjsSession.ts - React hook for session management
  • src/config.ts - config.yjs transport configuration