Live Multiplayer · WebSocket Architecture

ETERNALCHESS.

A real-time multiplayer chess game powered by WebSockets. Server validates moves, broadcasts state to all connected players instantly. Persistent. Live. No page reloads.

How to Play

This is a shared, persistent chess game. There is one board, and everyone in the world plays on it together. The game continues even after you close your browser.

Click a piece to select it, then click a destination square to move. You can also type moves in standard notation (e.g. e4, Nf3, O-O) in the input box below the board.

When 1-2 people are online, anyone can make a move at any time.

When 3 or more people are online, a queue system activates. Each person makes one move, then goes to the back of the line. The page will notify you when it's your turn.

Your queue position is shown above the board.

Total Moves
Latency ms
Protocol WebSocket
Connected 0 viewers
Live Board
WHITE TO MOVE
Live Server Telemetry
Server Status CONNECTING
Current FEN loading...
Move Number
Game Result IN PROGRESS
Commit History
Move Log (PGN)
Waiting for game state...
System Architecture

The WebSocket Pipeline

Every chess move flows through a persistent WebSocket connection. The server validates, updates state, and broadcasts to all connected clients in real time.

Step 01 User Move SAN notation input
Step 02 WS Send socket.send(move)
Step 03 Server Validate python-chess referee
Step 04 Broadcast WS push to all clients
Step 05 Board Refresh onmessage → render
WebSocket message flow
// Client → Server (move)
socket.send(JSON.stringify({
  "move": "e4"
}));

// Server → All Clients (broadcast)
{
  "type":  "move",
  "move":  "e4",
  "fen":   "rnbqkbnr/pppppppp/8/...",
  "turn":  "b"
}
Under the Hood

Implementation

server.py
FastAPI
from fastapi import FastAPI, WebSocket
import chess, json

app = FastAPI()
board = chess.Board()
clients: list[WebSocket] = []

@app.websocket("/ws")
async def ws(socket: WebSocket):
    await socket.accept()
    clients.append(socket)

    # Send current state
    await socket.send_json({
        "type": "init",
        "fen": board.fen()
    })

    async for data in socket.iter_json():
        move = board.parse_san(data["move"])
        board.push(move)
        for c in clients:
            await c.send_json({
                "type": "move",
                "fen": board.fen()
            })
client.js
JavaScript
const socket = new WebSocket(
  'ws://{YOUR_SERVER}:8000/ws'
);

socket.onopen = () => {
  console.log('Connected');
};

socket.onmessage = (event) => {
  const data = JSON.parse(event.data);

  if (data.type === 'init') {
    board.load(data.fen);
    renderBoard();
  }

  if (data.type === 'move') {
    board.load(data.fen);
    renderBoard();  // all viewers
  }
};

// Send a move
socket.send(JSON.stringify({
  "move": "e4"
}));
chess.js python-chess WebSocket Real-Time Multiplayer FastAPI Vanilla JS Persistent State