Puppeteer: Multiplayer Movement & Sync Library (JavaScript)
Puppeteer is a modular, extensible JavaScript library designed to support multiplayer game development using 3D frameworks like Three.js. It includes networking, interpolation, prediction, and movement handling, and is structured to scale up to competitive or simulation-heavy multiplayer games.
Get StartedInstallation
Install Puppeteer using npm:
npm install puppeteer-js
Or using a script tag:
<script src="https://cdn.example.com/puppeteer/latest/puppeteer.min.js"></script>
Project Structure
Core Concepts
Puppeteer provides a complete system for handling multiplayer interactions in 3D space. Here are the key components:
Vector3 & Quaternion
Core math utilities for 3D space operations.
const vec = new Puppeteer.Vector3(x, y, z)
Creates a new three-dimensional vector with x, y, and z coordinates. Provides methods for vector math operations including addition, subtraction, multiplication, normalization, dot products, and cross products.
// Create and manipulate vectors
const position = new Puppeteer.Vector3(0, 0, 0);
position.add(new Puppeteer.Vector3(1, 2, 3));
const distance = position.distanceTo(new Puppeteer.Vector3(5, 5, 5));
const rotation = new Puppeteer.Quaternion()
Represents rotations in 3D space, avoiding gimbal lock issues common with Euler angles. Used for smooth interpolation between orientations.
// Create and use quaternions for rotation
const rotation = new Puppeteer.Quaternion();
rotation.setFromAxisAngle(new Puppeteer.Vector3(0, 1, 0), Math.PI / 2);
rotation.multiply(anotherQuaternion);
Transform
const transform = new Puppeteer.Transform(position, rotation)
Combines position and rotation into a single object. Represents the complete spatial state of an object in 3D space.
// Create a transform representing position and rotation
const transform = new Puppeteer.Transform(
new Puppeteer.Vector3(10, 0, 5),
new Puppeteer.Quaternion().setFromAxisAngle(new Puppeteer.Vector3(0, 1, 0), Math.PI)
);
Snapshot
const snapshot = new Puppeteer.Snapshot(transform, timestamp)
Stores a Transform with a timestamp. Used to record the state of an object at a specific point in time for networking and interpolation.
// Create a snapshot of an object's state at the current time
const snapshot = new Puppeteer.Snapshot(
playerTransform,
Puppeteer.Utils.Clock.now()
);
Interpolator
const interpolator = new Puppeteer.Interpolator(options)
Computes smooth transitions between snapshots. Essential for visual smoothing of network updates.
// Create an interpolator with custom settings
const interpolator = new Puppeteer.Interpolator({
maxSnapshots: 10,
interpolationDelay: 100 // ms
});
// Add snapshots as they arrive from the network
interpolator.addSnapshot(snapshot1);
interpolator.addSnapshot(snapshot2);
// Get the interpolated transform to render
const renderTransform = interpolator.computeTransformAtTime(Puppeteer.Utils.Clock.now());
RoomClient
const client = new Puppeteer.Net.RoomClient(serverUrl)
Handles WebSocket client networking. Connects to a RoomHost and synchronizes object states.
// Connect to a multiplayer room
const client = new Puppeteer.Net.RoomClient("wss://game.example.com/room/12345");
client.on("connect", () => {
console.log("Connected to room!");
});
client.on("playerJoined", (playerId) => {
console.log(`Player ${playerId} joined the room`);
});
// Send player updates
client.sendTransform(myPlayerTransform);
RoomHost
const host = new Puppeteer.Net.RoomHost(options)
Hosts a WebSocket server for multiplayer rooms. Manages connections and object ownership.
// Server-side code to host a room
const host = new Puppeteer.Net.RoomHost({
port: 8080,
maxPlayers: 16,
tickRate: 30
});
host.on("playerJoin", (client) => {
console.log(`Player joined with ID: ${client.id}`);
});
host.start();
MovementController
const controller = new Puppeteer.Movement.MovementController(transform, options)
Moves a player in a specific direction based on speed and deltaTime. Handles physics-based movement.
// Create a movement controller for a player
const controller = new Puppeteer.Movement.MovementController(playerTransform, {
speed: 5,
rotationSpeed: 2,
gravity: 9.8
});
// Update during game loop
function gameLoop(deltaTime) {
// Move based on input
if (keys.forward) {
controller.moveForward(deltaTime);
}
if (keys.right) {
controller.rotate(deltaTime);
}
// Apply physics updates
controller.update(deltaTime);
}
Basic Usage (in Browser)
Here's a simple example of integrating Puppeteer with Three.js:
import Puppeteer from './puppeteer/index.js';
// Set up Three.js scene
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Create a player with Puppeteer
const playerTransform = new Puppeteer.Transform(
new Puppeteer.Vector3(0, 0, 0),
new Puppeteer.Quaternion()
);
// Create Three.js representation
const playerGeometry = new THREE.BoxGeometry(1, 2, 1);
const playerMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const playerMesh = new THREE.Mesh(playerGeometry, playerMaterial);
scene.add(playerMesh);
// Connect to multiplayer room
const client = new Puppeteer.Net.RoomClient("wss://example.com/game");
client.on("playerUpdate", (playerId, playerSnapshot) => {
if (playerId !== client.id) {
// Update other player's position (simplified)
otherPlayers[playerId].addSnapshot(playerSnapshot);
}
});
// Movement controller
const movement = new Puppeteer.Movement.MovementController(playerTransform);
// Game loop
function animate() {
requestAnimationFrame(animate);
// Update player movement based on input
movement.update(0.016); // Approx 60fps
// Apply transform to Three.js mesh
playerMesh.position.set(
playerTransform.position.x,
playerTransform.position.y,
playerTransform.position.z
);
playerMesh.quaternion.set(
playerTransform.rotation.x,
playerTransform.rotation.y,
playerTransform.rotation.z,
playerTransform.rotation.w
);
// Send updates to server
client.sendTransform(playerTransform);
// Render scene
renderer.render(scene, camera);
}
animate();
Advanced Examples
Prediction & Reconciliation
Puppeteer supports client-side prediction and server reconciliation for responsive multiplayer gameplay:
// Client-side prediction
const inputQueue = [];
let lastProcessedInput = 0;
function processInput(input) {
// Apply input locally
movement.applyInput(input);
// Save input for reconciliation
inputQueue.push(input);
// Send to server
client.sendInput(input);
}
// When server confirms state
client.on("serverState", (serverSnapshot, lastInputId) => {
// Remove confirmed inputs
inputQueue = inputQueue.filter(input => input.id > lastInputId);
// Reset to server state
playerTransform.copy(serverSnapshot.transform);
// Reapply remaining inputs
for (const input of inputQueue) {
movement.applyInput(input);
}
});
API Reference
See the full API reference for detailed documentation of all methods and classes.
Core Module
- Vector3 - 3D vector representation
- Quaternion - Rotation representation
- Transform - Combined position and rotation
Interpolation Module
- Snapshot - Timestamped transform
- Interpolator - Smooth transitions between states
Networking Module
- RoomClient - WebSocket client networking
- RoomHost - WebSocket server for multiplayer
Movement Module
- MovementController - Physics & directional movement
- CollisionSystem - Handle object collisions