HELIX 3 Docs
Guides

Build your first multiplayer world

A complete walkthrough — join an instance, exchange events, and run one server-authoritative interaction.

This builds a tiny but real multiplayer world: players see each other, can wave, and can press a button that the server validates before rewarding. Uses Instances & Events and the server authority rule.

1. Boot and join

src/client.ts
import { Helix } from '@helix/sdk';

await Helix.init({
  worldId: window.HELIX_WORLD_ID,
  launchTicket: window.HELIX_LAUNCH_TICKET,
});

const instance = await Helix.instance.join();

instance.onPlayerJoined((p) => spawnAvatar(p));
instance.onPlayerLeft((p) => removeAvatar(p));
for (const p of instance.getPlayers()) spawnAvatar(p);

2. A cosmetic event (client-trusted)

Waving doesn't affect value, so the client can drive it.

src/client.ts
Helix.network.on('wave', ({ from }) => playWave(from));

document.querySelector('#wave')!.addEventListener('click', () => {
  Helix.network.send('wave', {});
});
src/server.ts
import { HelixInstance } from '@helix/server-sdk';

export default class MyWorld extends HelixInstance {
  async onEvent(player, event) {
    if (event === 'wave') this.broadcast('wave', { from: player.id });
  }
}

3. A value event (server-authoritative)

A "daily bonus" button grants LIX-adjacent value — so the server decides, enforces the once-per-day rule, and grants. The client only asks.

src/client.ts
const res = await Helix.network.request('claim-bonus', {});
if (res.ok) showToast(`+${res.amount} coins!`);
else showToast(res.reason);
src/server.ts
export default class MyWorld extends HelixInstance {
  async onEvent(player, event) {
    if (event === 'wave') this.broadcast('wave', { from: player.id });
  }

  // request/response handler
  async onRequest(player, event) {
    if (event !== 'claim-bonus') return;

    const key = `bonus:${player.id}:${today()}`;
    const already = await Helix.cloudSave.get<boolean>(key);
    if (already) return { ok: false, reason: 'Already claimed today' };

    await Helix.cloudSave.set(key, true);        // durable, authoritative
    await this.grantCoins(player.id, 50);        // server-side grant
    return { ok: true, amount: 50 };
  }
}

Why this split matters

If the client could grant its own bonus, players would script infinite coins. The wave is harmless client-side; the bonus is decided server-side and recorded in Cloud Save. That's the golden rule in two handlers.

4. Publish

helix validate && helix deploy

Share the link. Open it in two browsers — you'll see two players, waves replicate, and the bonus is claimable once per day per player.

Next

On this page