Skip to content

BUILD MULTIPLAYER WITHOUT A SERVER

A relay mesh for chat, voice, games and shared state. Your clients send; every client gets the same stream in the same order. 100 GB/month free.

ARRR

Powered by ARRR ​

Live games running on the public network right now. Their worlds, voices and characters come down the same mesh anyone can build on.

Shipped something on the network? Tell us and it goes on this page.

Users served today

—

Loading the last 14 days…

What you can build ​

Chat and feeds

An ordered log with join and leave events nobody can fake.

Voice rooms

One upload per talker, a bounded download per listener, any room size.

Collaborative tools

Same operations, same order, on every client. No merge step.

Multiplayer games

Inputs batched into ticks. Snapshots for late joiners, desync detection built in.

Live data

Anything with a WebSocket can publish. Every subscriber reads the same sequence.

Anything else

JSON, bytes or audio. What it means is yours.

Quick Example ​

One connect(), then read the stream as messages, ticks, or voice.

javascript
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' });
javascript
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 } });
javascript
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
html
<script src="https://www.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>

send() takes JSON or a Uint8Array. The API key comes from the console; see API Keys.

Two ways to take part ​

Build an app

Create an app in the console and pass its API key to connect(). The network hosts your rooms.

Provide a node

Mint a node token in the console and run arrr-node with it. Your node joins the mesh and hosts rooms.

How It Works ​

How a room works on the ARRR networkClients ask the cloud service which node hosts their room, then connect to that node over a WebSocket. Messages reach the room's authority node, which numbers them in arrival order and batches them into ticks. Each tick is broadcast to the authority's own clients and, over a peer link, to every replica node's clients, so every client receives the same messages in the same order.Cloud servicecloud.arrr.funthe directory: which nodehosts this room?Authority nodenumbers messages as they arrive,batches them into one tick,broadcasts the tickReplica nodemirrors the room, forwards itsclients' messages upstream,takes over if the authority diespeer linkClient Ayour app+ the SDKClient Byour app+ the SDKClient Cyour app+ the SDKwhich node?node + join tokenmessages upordered ticks downmessages upordered ticks down1234
One room, two nodes, three clients. Dashed: the one question a client asks before it sends.
  1. Find the room. 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.
  2. Send. The client opens a WebSocket to that node and sends. A room lives on an authority node and is mirrored on replicas, which forward to the authority.
  3. One order. The authority numbers messages as they arrive and batches each tick into one delivery. Numbering happens in one place, so no two clients can disagree.
  4. Same tick everywhere. The authority broadcasts to its clients and, over the peer link, to every replica's. 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.