
Product
Socket Now Protects the Firefox Extension Ecosystem
Socket is bringing experimental protection to Firefox, scanning 97,000+ extensions in Mozilla's official directory for malware and risky updates.
@playertwo/transport-colyseus
Advanced tools
Colyseus transport adapter for playertwo multiplayer SDK
Colyseus room adapter for playertwo multiplayer SDK. Use Colyseus for matchmaking, rooms, and server infrastructure while using playertwo's declarative API for game logic.
Best of Both Worlds:
Perfect For:
pnpm add @playertwo/core @playertwo/transport-colyseus colyseus.js
import { Client } from 'colyseus.js';
import { defineGame, GameRuntime } from '@playertwo/core';
import { ColyseusTransport } from '@playertwo/transport-colyseus';
// Define your game logic with playertwo
const game = defineGame({
minPlayers: 2,
maxPlayers: 4,
setup: () => ({
players: {},
score: {}
}),
actions: {
move: (state, playerId, input) => {
state.players[playerId] = input.position;
},
updateScore: (state, playerId, points) => {
state.score[playerId] = (state.score[playerId] || 0) + points;
}
}
});
// Connect to Colyseus
const client = new Client('ws://localhost:2567');
const room = await client.joinOrCreate('my_game_room');
// Create playertwo transport from Colyseus room
const transport = new ColyseusTransport(room);
// Create game runtime
const runtime = new GameRuntime(game, transport, {
isHost: room.sessionId === '...' // Determine host via Colyseus
});
// Use playertwo's clean API
runtime.submitAction('move', { position: { x: 10, y: 20 } });
Create a Colyseus room that relays playertwo messages:
import { Room, Client } from '@colyseus/core';
export class playertwoGameRoom extends Room {
private hostId: string | null = null;
onCreate(options: any) {
console.log('playertwoGameRoom created');
// Handle playertwo messages
this.onMessage('playertwo', (client, message) => {
// Relay to all clients or targeted client
if (message.targetId) {
const targetClient = Array.from(this.clients).find(
c => c.sessionId === message.targetId
);
targetClient?.send('playertwo', message);
} else {
// Broadcast to all except sender
this.broadcast('playertwo', message, { except: client });
}
});
}
onJoin(client: Client, options: any) {
console.log(client.sessionId, 'joined');
// Elect first player as host
if (!this.hostId) {
this.hostId = client.sessionId;
this.broadcast('playertwo', {
type: 'host_announce',
hostId: this.hostId,
senderId: 'server'
});
}
// Notify all clients of new player
this.broadcast('playertwo', {
type: 'player_join',
payload: { playerId: client.sessionId },
senderId: 'server'
});
// Send current peers list to new player
const peers = Array.from(this.clients).map(c => c.sessionId);
client.send('playertwo', {
type: 'peers_list',
payload: { peers },
senderId: 'server'
});
}
onLeave(client: Client, consented: boolean) {
console.log(client.sessionId, 'left');
// Notify remaining clients
this.broadcast('playertwo', {
type: 'player_leave',
payload: { playerId: client.sessionId },
senderId: 'server'
});
// Elect new host if needed
if (client.sessionId === this.hostId && this.clients.length > 0) {
this.hostId = Array.from(this.clients)[0].sessionId;
this.broadcast('playertwo', {
type: 'host_announce',
hostId: this.hostId,
senderId: 'server'
});
}
}
}
new ColyseusTransport(room: Room)Create a playertwo transport from a Colyseus room.
Parameters:
room: A connected Colyseus room instanceExample:
const room = await client.joinOrCreate('game_room');
const transport = new ColyseusTransport(room);
All standard playertwo Transport methods are supported:
send(message: WireMessage, targetId?: string): voidSend a message through the Colyseus room.
transport.send({
type: 'action',
payload: { action: 'move', x: 10, y: 20 }
});
// Send to specific player
transport.send({
type: 'state_sync',
payload: { state: {...} }
}, 'player-123');
onMessage(handler: (message, senderId) => void): () => voidListen for messages from other players.
const unsubscribe = transport.onMessage((message, senderId) => {
console.log('Received message from:', senderId, message);
});
// Stop listening
unsubscribe();
onPeerJoin(handler: (peerId: string) => void): () => voidListen for players joining.
transport.onPeerJoin((peerId) => {
console.log('Player joined:', peerId);
});
onPeerLeave(handler: (peerId: string) => void): () => voidListen for players leaving.
transport.onPeerLeave((peerId) => {
console.log('Player left:', peerId);
});
getPlayerId(): stringGet your player ID (same as room.sessionId).
const myId = transport.getPlayerId();
getPeerIds(): string[]Get list of all connected players (excluding yourself).
const peers = transport.getPeerIds();
console.log('Connected players:', peers);
isHost(): booleanCheck if you are the current host.
if (transport.isHost()) {
console.log('I am the host');
}
onError(handler: (error: Error) => void): () => voidListen for connection errors.
transport.onError((error) => {
console.error('Transport error:', error);
});
disconnect(): voidLeave the Colyseus room and clean up.
transport.disconnect();
getRoom(): RoomGet the underlying Colyseus room (for advanced use cases).
const room = transport.getRoom();
console.log('Room ID:', room.id);
console.log('Room state:', room.state);
The transport uses a 'playertwo' message type on the Colyseus room. All playertwo messages are wrapped in this format:
{
type: 'action' | 'state_sync' | 'player_join' | 'player_leave' | 'host_announce' | ...,
payload?: any,
senderId: string,
targetId?: string // For targeted messages
}
The server should send these control messages:
player_join{
type: 'player_join',
payload: { playerId: string },
senderId: 'server'
}
player_leave{
type: 'player_leave',
payload: { playerId: string },
senderId: 'server'
}
host_announce{
type: 'host_announce',
hostId: string,
senderId: 'server'
}
peers_list{
type: 'peers_list',
payload: { peers: string[] },
senderId: 'server'
}
Use the client/server snippets above as a starting point. For end-to-end demos, see the examples overview and adapt the patterns to your Colyseus rooms.
// ❌ Imperative, verbose
room.onMessage('move', (message) => {
const player = players.get(message.playerId);
player.x = message.x;
player.y = message.y;
// Sync to other clients...
// Handle edge cases...
// Validate input...
});
// ✅ Declarative, concise
const game = defineGame({
actions: {
move: (state, playerId, input) => {
state.players[playerId] = input.position;
}
}
});
Use Colyseus for Infrastructure
Use playertwo for Game Logic
Host Election
host_announce messagesError Handling
'playertwo' messagesonMessage('playertwo', ...) is set up on the serversenderIdhost_announce messageshostId matches a client's sessionIdplayer_join/player_leave messagespeers_list message on joincolyseus.js is installedimport type { Room } from 'colyseus.js'MIT
FAQs
Colyseus transport adapter for playertwo multiplayer SDK
We found that @playertwo/transport-colyseus demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket is bringing experimental protection to Firefox, scanning 97,000+ extensions in Mozilla's official directory for malware and risky updates.

Research
/Security News
Three compromised Rust crates pulled in a malicious dependency that downloaded and executed cross-platform malware during Cargo builds.

Research
/Security News
Socket uncovered 77 linked Firefox extensions, including 40 that steal wallet secrets or credentials and 37 deceptive sports-score shells.