
This is the shortest AuraJS multiplayer path right now.
auramaxx create my-room-game --template multiplayer
cd my-room-game
npm run dev
# second terminal
npm run join -- AURA2P
That is the default room-code multiplayer loop:
npm run dev hostsnpm run join -- CODE joinsjoin("CODE") can fall back to coordinator lookupIf you want the smallest copyable example before scaffolding your own game, use
examples/multiplayer-party.
Local-first:
cd packages/aurascript/examples/multiplayer-party
auramaxx run .
# second terminal
auramaxx run . PARTY4
That example keeps host and join in one project and also shows:
Keep the same host/join commands and add a relay host in aura.config.json:
{
"multiplayer": {
"relay": "relay.aurajs.gg"
}
}
Or keep the project untouched and launch with:
AURA_MULTIPLAYER_RELAY_HOST=relay.aurajs.gg npm run dev
AURA_MULTIPLAYER_RELAY_HOST=relay.aurajs.gg npm run join -- AURA2P
When a relay host or explicit relay URLs are present, the room uses internet
auto mode:
If you also want one shareable web join page, add the launcher base URL:
{
"multiplayer": {
"relay": "relay.aurajs.gg",
"launcherBaseUrl": "https://auralauncher.gg"
}
}
Then the multiplayer starter HUD can surface a link like:
https://auralauncher.gg/join/AURA2P
If you want relay-only behavior, set:
{
"multiplayer": {
"mode": "relay",
"relay": "relay.aurajs.gg"
}
}
The minimum host-authoritative loop is:
aura.multiplayer.configure({ maxPlayers: 2, tickRate: 20 });
function startHost() {
return aura.multiplayer.host({
roomCode: "AURA2P",
maxPlayers: 2,
internetMode: "local",
});
}
function hostTick(localInput) {
aura.multiplayer.setState("player_0", stepPlayer(aura.multiplayer.getState("player_0"), localInput));
const inputs = aura.multiplayer.getAllPlayerInputs() || {};
for (const [playerId, input] of Object.entries(inputs)) {
const key = `player_${playerId}`;
aura.multiplayer.setState(key, stepPlayer(aura.multiplayer.getState(key), input));
}
}
function clientTick(input) {
if (aura.multiplayer.isConnected()) {
aura.multiplayer.sendInput(input);
}
}
Mental model:
getAllPlayerInputs()setState(...)getState() / getAllState()getInterpolatedState() / getInterpolatedAllState() for drawnpm run join -- CODE or aura.multiplayer.join("CODE")AuraJS now also ships an advanced Stage 174 lane for explicit public-network recovery and supported rollback gameplay reads.
const localKey = `player_${aura.multiplayer.getLocalId()}`;
aura.multiplayer.configureRollbackLane({
key: localKey,
speed: 220,
historyLimit: 16,
bounds: { minX: 32, maxX: 608, minY: 96, maxY: 352 },
});
function draw() {
const players = aura.multiplayer.isHost()
? (aura.multiplayer.getAllState() || {})
: (aura.multiplayer.getRollbackAllState()
|| aura.multiplayer.getInterpolatedAllState()
|| aura.multiplayer.getAllState()
|| {});
const rollback = aura.multiplayer.getRollbackDiagnostics(localKey);
const network = aura.multiplayer.getNetworkDiagnostics();
}
Use that lane when your local gameplay state fits the runtime-supported rollback model:
configureRollbackLane(...) currently supports the built-in axis2d lanegetRollbackState() / getRollbackAllState() are rollback-aware gameplay
reads for that supported lanegetRoomInfo() and getNetworkDiagnostics() surface reason-coded recovery
states such as resume_pending and resumedconfigureNetworkImpairment(...) / clearNetworkImpairment() exist for
deterministic latency, jitter, loss, and short-outage testingTruthful limit:
../../multiplayer-internet-hardening-and-rollback-grade-feel-contract-v1.mdUse aura.config.json -> multiplayer for project-level defaults:
{
"multiplayer": {
"roomCode": "AURA2P",
"roomName": "My Room",
"mode": "local",
"relay": null,
"coordinatorUrl": null,
"relayUrl": null,
"launcherBaseUrl": null,
"showDiagnostics": true,
"chatEnabled": true,
"chatHistoryLimit": 6
}
}
Use that block for:
Use config/gameplay/local-multiplayer.config.js for local gameplay tuning: