The Multiplayer Framework Developers Love
Open-source, battle-tested, and built for real-time games. Free forever.
npm create kidsgames-app@latest ./my-server Supports your favorite engine & platform
- Cheat-proof by design
- Built-in matchmaking
- Real-time sync that just works
- Scale from 10 to 10,000+ CCU
- Self-host or use KidsGames Cloud
- Use tools you already know
- Free forever (MIT License)
Как это работает
От нуля до мультиплеера
Опишите комнаты, синхронизируйте состояние, подключайте клиентов. Полноценный мультиплеерный сервер в несколько строк кода.
import { Room } from "kidsgames";
class MyRoom extends Room { maxClients = 4; onCreate(options) {/* your code */} onAuth(client, options) {/* your code */} onJoin(client, options) {/* your code */} onLeave(client) {/* your code */} onDispose() {/* your code */}}import { defineServer, defineRoom } from "kidsgames";import { MyRoom } from "./MyRoom";
export default defineServer({ rooms: { my_room: defineRoom(MyRoom), },});import { type, Schema, MapSchema, ArraySchema } from "@kidsgames/schema";
export class Player extends Schema { @type("string") name: string; @type("number") position: number;}
export class MyState extends Schema { @type({map: Player}) players = new MapSchema<Player>(); @type(["number"]) board = new ArraySchema<number>([0, 0, 0, 0, 0, 0, 0, 0, 0]); @type("string") currentTurn: string;}import { Room } from "kidsgames";import { MyState } from "./MyState";
export class MyRoom extends Room { state = new MyState();
onCreate() { // room has been created }
onJoin(client, options) { // new client joined the room this.state.players.set(client.sessionId, new Player()); this.state.currentTurn = client.sessionId; }
onLeave() { // client left the room this.state.players.delete(client.sessionId); }}import { Client } from "@kidsgames/sdk";
// Initialize SDKconst client = new Client("https://0.0.0.0:2567");
// Connect to a roomconst room = await client.joinOrCreate("my_room");import { Client, Callbacks } from "@kidsgames/sdk";
const client = new Client("https://0.0.0.0:2567");const room = await client.joinOrCreate("my_room", { /* client options */});
const callbacks = Callbacks.get(room);
// on player added/joincallbacks.onAdd("players", (player, sessionId) => { console.log("Player added!", player, sessionId); // on player "position" change callbacks.listen(player, "position", (position, previousPosition) => { console.log("player position changed!", { position, previousPosition }); });});
// on player removed/leftcallbacks.onRemove("players", (player, sessionId) => { console.log("Player removed!", player, sessionId);});
// on "board" changecallbacks.onChange("board", (value, index) => { console.log("board item changed to", value, "at", index);});
// on "currentTurn" changecallbacks.listen("currentTurn", (currentTurn, previousValue) => { console.log("currentTurn:", currentTurn); console.log("currentPlayer:", room.state.players.get(currentTurn));});Опишите комнату (Room)
Комнаты — основной строительный блок. Каждая комната выполняет игровую логику, обрабатывает соединения и управляет состоянием. Опишите хуки жизненного цикла: подключение, отключение и получение сообщений от игроков.
Откройте для матчмейкинга
Зарегистрируйте тип комнаты одной строкой. Остальное берёт на себя KidsGames — создаёт новые экземпляры по мере необходимости, заполняет их и направляет игроков в нужную комнату.
Опишите состояние (state)
Опишите игровое состояние с помощью классов схемы с декораторами. KidsGames отслеживает изменения и синхронизирует их со всеми клиентами, используя бинарную дельта-компрессию.
Меняйте состояние
Просто изменяйте объекты состояния как обычный JavaScript. KidsGames обнаруживает изменения и рассылает подключённым клиентам только дельты.
Подключитесь с клиента
Подключитесь к серверу и войдите в комнату в несколько строк кода. Если свободной комнаты нет, сервер создаёт её автоматически.
Слушайте изменения состояния
Реагируйте на изменения состояния через точечные колбэки. Точно знайте, когда игроки подключаются, отключаются или обновляется любое состояние.
Опишите комнату (Room)
Комнаты — основной строительный блок. Опишите хуки жизненного цикла: подключение, отключение и получение сообщений от игроков.
import { Room } from "kidsgames";
class MyRoom extends Room { maxClients = 4; onCreate(options) {/* your code */} onAuth(client, options) {/* your code */} onJoin(client, options) {/* your code */} onLeave(client) {/* your code */} onDispose() {/* your code */}}Откройте для матчмейкинга
Зарегистрируйте тип комнаты одной строкой. Остальное берёт на себя KidsGames.
import { defineServer, defineRoom } from "kidsgames";import { MyRoom } from "./MyRoom";
export default defineServer({ rooms: { my_room: defineRoom(MyRoom), },});Опишите состояние (state)
Опишите игровое состояние с помощью классов схемы с декораторами. KidsGames отслеживает и синхронизирует изменения автоматически.
import { type, Schema, MapSchema, ArraySchema } from "@kidsgames/schema";
export class Player extends Schema { @type("string") name: string; @type("number") position: number;}
export class MyState extends Schema { @type({map: Player}) players = new MapSchema<Player>(); @type(["number"]) board = new ArraySchema<number>([0, 0, 0, 0, 0, 0, 0, 0, 0]); @type("string") currentTurn: string;}Меняйте состояние
Просто изменяйте объекты состояния. KidsGames обнаруживает изменения и рассылает дельты.
import { Room } from "kidsgames";import { MyState } from "./MyState";
export class MyRoom extends Room { state = new MyState();
onCreate() { // room has been created }
onJoin(client, options) { // new client joined the room this.state.players.set(client.sessionId, new Player()); this.state.currentTurn = client.sessionId; }
onLeave() { // client left the room this.state.players.delete(client.sessionId); }}Подключитесь с клиента
Войдите в комнату в несколько строк кода. Если свободной нет, сервер создаёт её сам.
import { Client } from "@kidsgames/sdk";
// Initialize SDKconst client = new Client("https://0.0.0.0:2567");
// Connect to a roomconst room = await client.joinOrCreate("my_room");Слушайте изменения состояния
Реагируйте на изменения состояния через точечные колбэки.
import { Client, Callbacks } from "@kidsgames/sdk";
const client = new Client("https://0.0.0.0:2567");const room = await client.joinOrCreate("my_room", { /* client options */});
const callbacks = Callbacks.get(room);
// on player added/joincallbacks.onAdd("players", (player, sessionId) => { console.log("Player added!", player, sessionId); // on player "position" change callbacks.listen(player, "position", (position, previousPosition) => { console.log("player position changed!", { position, previousPosition }); });});
// on player removed/leftcallbacks.onRemove("players", (player, sessionId) => { console.log("Player removed!", player, sessionId);});
// on "board" changecallbacks.onChange("board", (value, index) => { console.log("board item changed to", value, "at", index);});
// on "currentTurn" changecallbacks.listen("currentTurn", (currentTurn, previousValue) => { console.log("currentTurn:", currentTurn); console.log("currentPlayer:", room.state.players.get(currentTurn));});Клиентские SDK
Разрабатывайте на любой платформе
Подключайтесь к серверу KidsGames из любого движка, фреймворка или языка. Синхронизация состояния работает одинаково везде.
import { Client, Callbacks } from "@kidsgames/sdk";
const client = new Client("https://your-server.com");const room = await client.joinOrCreate("game_room");const callbacks = Callbacks.get(room);
callbacks.onAdd("players", (player, key) => { addSpriteForPlayer(player); callbacks.onChange(player, () => moveSprite(key, player.x, player.y));});
callbacks.onRemove("players", (player, key) => removeSpriteForPlayer(key));
room.send("move", { x: 10, y: 20 });import { Client } from "@kidsgames/sdk";import { useRoom, useRoomState } from "@kidsgames/react";
const client = new Client("https://your-server.com");
function Game() { const { room, isConnecting } = useRoom( () => client.joinOrCreate("game_room"), ); const state = useRoomState(room);
if (isConnecting) return <p>Connecting...</p>;
return ( <ul> {state?.players.map((player, key) => ( <li key={key}>Player at {player.x}, {player.y}</li> ))} </ul> );}using KidsGames;using KidsGames.Schema;
var client = new Client("https://your-server.com");var room = await client.JoinOrCreate<GameState>("game_room");var callbacks = Callbacks.Get(room);
callbacks.OnAdd(state => state.players, (sessionId, player) => { AddSpriteForPlayer(player); callbacks.OnChange(player, () => MoveSprite(sessionId, player.x, player.y));});
callbacks.OnRemove(state => state.players, (sessionId, player) => RemoveSpriteForPlayer(sessionId));
await room.Send("move", new { x = 10, y = 20 });var client: KidsGamesClient = KidsGames.create_client()client.set_endpoint("wss://your-server.com")var room: KidsGamesRoom = client.join_or_create("game_room")
room.joined.connect(func(): var callbacks = KidsGames.callbacks(room)
callbacks.on_add("players", func(player, key): add_sprite_for_player(player) callbacks.on_change(player, func(): move_sprite(key, player.x, player.y) ) )
callbacks.on_remove("players", func(player, key): remove_sprite_for_player(key) )
room.send("move", {"x": 10, "y": 20}))client = new KidsGamesClient("https://your-server.com");room = client.join_or_create("game_room");callbacks = KidsGamesCallbacks(room);
callbacks.on_add("players", function(player, key) { add_sprite_for_player(player); callbacks.on_change(player, function() { move_sprite(key, player.x, player.y); });});
callbacks.on_remove("players", function(player, key) { remove_sprite_for_player(key);});
room.send("move", { x: 10, y: 20 });local KidsGamesSDK = require "kidsgames.sdk"
local client = KidsGamesSDK.Client("https://your-server.com")client:join_or_create("game_room", function(room) local callbacks = KidsGamesSDK.callbacks(room)
callbacks:on_add("players", function(player, key) add_sprite_for_player(player) callbacks:on_change(player, function() move_sprite(key, player.x, player.y) end) end)
callbacks:on_remove("players", function(player, key) remove_sprite_for_player(key) end)
room:send("move", { x = 10, y = 20 })end)import io.kidsgames.Client;import io.kidsgames.schema.Callbacks;
var client = new Client("https://your-server.com");client.joinOrCreate("game_room", [], MyRoomState, function(err, room) { var callbacks = Callbacks.get(room);
callbacks.onAdd("players", (player, key) -> { addSpriteForPlayer(player); callbacks.onChange(player, () -> moveSprite(key, player.x, player.y)); });
callbacks.onRemove("players", (player, key) -> removeSpriteForPlayer(key));
room.send("move", {x: 10, y: 20});});#include "kidsgames.h"
kidsgames_client_t* client = kidsgames_client_new("https://your-server.com");kidsgames_room_t* room = kidsgames_join_or_create(client, "game_room");kidsgames_callbacks_t* callbacks = kidsgames_callbacks_get(room);
void on_player_add(kidsgames_state_t* player, const char* key) { add_sprite_for_player(player); kidsgames_on_change(callbacks, player, on_player_change, (void*)key);}
void on_player_change(kidsgames_state_t* player, void* ctx) { float x = kidsgames_get_float(player, "x"); float y = kidsgames_get_float(player, "y"); move_sprite((const char*)ctx, x, y);}
kidsgames_on_add(callbacks, "players", on_player_add, NULL);kidsgames_on_remove(callbacks, "players", on_player_remove, NULL);kidsgames_room_send(room, "move", data, data_len);const client = new KidsGames.Client("https://your-server.com");const room = await client.joinOrCreate("game_room");const callbacks = KidsGames.Callbacks.get(room);
callbacks.onAdd("players", (player, key) => { const sprite = runtime.objects.Player.createInstance("Game", player.x, player.y); callbacks.onChange(player, () => { sprite.x = player.x; sprite.y = player.y; });});
callbacks.onRemove("players", (player, key) => { // destroy sprite instance});
room.send("move", { x: 10, y: 20 });Under the Hood
Architecture / Stack
A solid stack so you can focus on your game instead of re-inventing the wheel.
Node.js Runtime
Asynchronous event-driven JavaScript runtime, designed to build scalable network applications.
Networking Transport
WebSockets as transport layer, with WebTransport support in our public roadmap.
Room-Based System
On-demand, stateful rooms are spawned per client request.
Message Serialization
Binary delta serialization for state sync, and the fastest MessagePack serializer for everything else.
Web / API Routes
Define your own custom API routes via Express or better-call.
Database / Auth
Bring your favorite Node.js tools. You choose which database or authentication provider to use.
Scale with Confidence
Scalability
Simple yet powerful scaling strategy
- Distribute rooms across servers and/or processes
- Allow cluster-wide match-making
- Leverage all your available CPUs
- Connect clients directly to their requested rooms
- Stateful processes keep track of their own rooms
Developer Experience
Tooling
Built-in tools that accompany you from development to production.
Client-side Playground
Create client connections and inspect data exchanged with the server.
Realtime Room Inspector
View and inspect the list of rooms spawned by the server.
Unit Testing
Utility methods for testing your rooms with your favorite testing framework.
Load Testing
Evaluate how your server behaves under high traffic.
Node.js ecosystem
Bring your favorite tools to your KidsGames server.
Trusted by
Trusted by game studios
Indie developers and studios build real-time multiplayer games on KidsGames.
Become a partnerBecome a Sponsor
The sustainability of KidsGames relies on KidsGames Cloud subscriptions and sponsorships.
If you benefit from the project but are not yet using KidsGames Cloud, please consider sponsoring it.




