Instantly add multiplayer to your app without buying a server. FREE 10 GB/month bandwidth.
make a 2D top-down shooter using arrr.fun's test tier
Netcode, player accounts and save data come in one SDK. Ship your game as static files: there is no server to write, host or keep alive.
room.send()Rooms, ordered ticks, snapshots for late joiners, desync detection and positional voice.
Replacesidentity.login()One ARRR sign-in works in every game. Keys are made and unlocked on the player's device, so no node ever sees a password.
Replacesvault.open()One document per player, per game, kept on the mesh. Nodes hold it but cannot read it.
Replacesconnect(). Read it your way.Read the same stream as messages, fixed ticks or positional voice. send() takes JSON or a Uint8Array. Get your key from the console, or get a test room: no registration required.
import { connect } from 'arrr-network';
const room = await connect('support-42', {
appId: 'my-app',
apiKey: 'arrr_…', // console → Apps
user: { id: 'alice' },
onMessage(data, seq) { // same order on every client
log.append(seq, data);
}
});
room.send({ text: 'hello' });import { connect } from 'arrr-network';
const room = await connect('duel-42', {
appId: 'my-app',
apiKey: 'arrr_…', // console → Apps
user: { id: 'alice' },
onTick(frame, inputs) { // one batch per tick, identical everywhere
for (const input of inputs) world.apply(input.data);
world.step();
}
});
room.send({ move: { x: 1, y: 0 } });import { connect } from 'arrr-network';
const room = await connect('lounge', {
appId: 'my-app',
apiKey: 'arrr_…', // console → Apps
user: { id: 'alice' },
onVoice(from, seq, x, y, z, frame) {
speakers.play(from, frame); // one encoded frame from a nearby talker
}
});
room.sendVoice(x, y, z, opusFrame); // while talking
room.sendVoice(x, y, z); // every 500 ms while quiet: position only<script src="https://arrr.fun/sdk/arrr-network.iife.js"></script>
<script>
(async () => {
const room = await arrrNetwork.connect('support-42', {
appId: 'my-app',
apiKey: 'arrr_…', // console → Apps
user: { id: 'alice' },
onMessage(data, seq) { log.append(seq, data); }
});
room.send({ text: 'hello' });
})();
</script>Inputs batched into ticks. Snapshots for late joiners, desync detection built in.
One upload per talker, a bounded download per listener, any room size.
An ordered log with join and leave events nobody can fake.
Same operations, same order, on every client. No merge step.
Anything with a WebSocket can publish. Every subscriber reads the same sequence.
JSON, bytes or audio. What it means is yours.
Nodes only number and relay; payloads are opaque to them. Every room is mirrored across nodes, so the load is spread out and a room outlives the node it started on.
The client asks the cloud service which node hosts the room and gets a node and a join token. The service never sees a message.
The client opens a WebSocket to that node and sends. Replicas forward to the room's authority node.
The authority numbers messages as they arrive and batches each tick. Numbering happens in one place, so no two clients can disagree.
The tick goes to every client on every node. Read it with onMessage or onTick; what it means is your code's business.
Voice skips the queue. Audio rides its own channel on the same socket, unordered, forwarded to the nearest listeners by position. Nothing waits for a tick.
One request gets you a test room for an hour, up to 10 players. No registration required. Or ask your coding agent to build on the test tier.
Create an app in the console and pass its API key to connect(). The network hosts your rooms.
Coming soon. Run arrr-node on your own machine and host rooms for the network.