Multiplayer.
Without networking.

Write multiplayer like React state.
Martini keeps clients in sync, across engines and transports.

Declarative like React Phaser helper today Transport agnostic Swap without refactors

Why Martini

Phaser helper available now • Godot adapter in development • More engines on deck

Declarative like React

Define setup, actions, and ticks like components/hooks for networked state. Martini handles validation and sync.

Fewer race conditions, no manual diffing.

Before vs After

Move from brittle socket plumbing to a declarative API. Martini handles validation, ordering, and sync so you keep focus on the game.

Before (manual)
// Manual sockets + reconnection + routing
const socket = new WebSocket(url);
const handlers = {
  move: ({ id, y }) => {
    const p = players[id];
    if (p) p.y = y;
  },
  join: ({ id }) => players[id] = { id, y: 0 },
  leave: ({ id }) => delete players[id],
};

socket.onopen = () => socket.send(JSON.stringify({ type: "join" }));
socket.onclose = () => setTimeout(() => reconnect(), 1000);

socket.onmessage = (msg) => {
  try {
    const { type, ...payload } = JSON.parse(msg.data);
    handlers[type]?.(payload);
  } catch (e) { console.error(e); }
};

function move(y) {
  socket.send(JSON.stringify({ type: "move", y, t: Date.now() }));
}
  • Manual parsing and routing
  • Race conditions and missing reconnection logic
  • No shared structure for engines or transports
  • Protocol rewrites per transport
After (with Martini)
import { defineGame } from "@martini/core";

const game = defineGame({
  setup: () => ({ players: [] }),
  actions: {
    move: (state, id, y) => {
      const player = state.players.find((p) => p.id === id);
      if (player) player.y = y;
    },
  },
  tick: (state) => { /* game loop */ },
});
  • Declarative setup/actions/tick
  • Swap WebSockets ↔ WebRTC/P2P without refactoring
  • Phaser helper today; Godot adapter in development
  • Ordering, validation, reconnection handled

Quick Start

1

Install

npm install @martini/core @martini/phaser
2

Declare Your Game (~15 lines)

Plain objects for state, actions mutate directly. No classes, no RPC wrappers, no serialization chores.

Step 1

Describe state and actions

Declare setup, actions, and tick with plain objects. No RPC or serialization boilerplate.

setup + actions + tick // declarative game spec
Step 2

Martini syncs it

Validation, diffing, ordering, and reconnects handled across WebSockets or WebRTC/P2P.

transport: websocket | webrtc
Step 3

Clients stay in lockstep

Render with Phaser helper today. Godot adapter is in development, with more engines planned.

onChange(state => render(state))
game.ts
import { defineGame } from '@martini/core';

const game = defineGame({
  setup: () => ({
    players: [],
    ball: { x: 400, y: 300, dx: 2, dy: 2 }
  }),

  actions: {
    move: (state, playerId, y) => {
      const player = state.players.find(p => p.id === playerId);
      if (player) player.y = y;
    }
  },

  tick: (state, dt) => {
    state.ball.x += state.ball.dx;
    state.ball.y += state.ball.dy;
  }
});
3

Pick Engine & Transport

Use the Phaser helper today. Godot and other engine adapters are on the way. Swap WebSockets or P2P without refactoring.

4

Develop faster

First-class DX: web IDE, live previews, and built-in dev tools today, with more helpers coming soon.

Comparison Snapshot

FeatureMartini (Phaser today)ColyseusPhotonRuneManual
Declarative game logicRPC / manualRPC / manualCustomx
Engine helper✓ (Phaser)~Per-engine SDKsP2P SDKx
Transport choiceServer WSServer UDP/WSP2P onlyx
Reconnect & orderingManualManualManualx
Bandwidth optimizedFull state / manualManualBatchedx
Optimistic updatesManualManualManualx
Interpolation/reconciliation helpersManualManualManualx
Swap transports without refactorServer onlyServer onlyP2P onlyx
Host-authoritative or P2PServer onlyServer onlyP2P onlyx
Schema-free stateManualManualManualx
Plugin adapters (Godot planned)~~~x
Open sourceVariesNoNox
Local-first friendlyServer onlyServer onlyP2P onlyx

Build in minutes

Ready to build multiplayer?

Ship real-time games with clean, readable code. Declarative logic, flexible transport, and a Phaser helper today (more adapters coming).