unity-multiplayer-mobile-webgl — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited unity-multiplayer-mobile-webgl (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
This skill guides you through building real-time multiplayer Unity games that ship to both mobile (iOS/Android) and WebGL2 browsers. The two primary server frameworks covered are Colyseus (automatic state sync, room-based) and Nakama (full game backend with auth, storage, matchmaking).
Pick Colyseus when:
Pick Nakama when:
→ For Colyseus details: read references/colyseus-integration.md → For Nakama details: read references/nakama-integration.md
WebGL builds cannot use raw TCP/UDP sockets, cannot use C# threads, and cannot host servers. All networking must go through WebSocket (or WebRTC). In production, HTTPS pages require wss:// connections.
The standard cross-platform pattern:
#if UNITY_WEBGL && !UNITY_EDITOR
// WebSocket transport only — no UDP, no threads
m_Driver = NetworkDriver.Create(new WebSocketNetworkInterface());
#else
// Native platforms can use UDP for lower latency
m_Driver = NetworkDriver.Create(new UDPNetworkInterface());
#endif→ Full constraints and workarounds: read references/webgl2-constraints.md
| Library | Cost | WebGL | Key strength |
|---|---|---|---|
| NativeWebSocket | Free | ✅ | Bundled with Colyseus SDK, v2.x auto-dispatches to main thread |
| Best WebSockets | ~€18 | ✅ | WSS, compression, profiler integration |
| unity-websocket | Free | ✅ | MonoBehaviour API, built-in ping/RTT, zero WebGL code changes |
| Unity Transport (UTP) | Free | ✅ | Official Unity package, dual UDP+WebSocket listen |
Avoid WebSocketSharp — it uses System.Net.Sockets and does not work in WebGL builds.
→ Full comparison and code examples: read references/websocket-networking.md
| Genre | Pattern | What syncs |
|---|---|---|
| FPS / Action | Client-side prediction + server rewind | State + input |
| MMO / RPG | Snapshot interpolation | State only |
| RTS / Fighting | Deterministic lockstep / rollback | Input only |
| Turn-based | Request-response | Actions only |
| Casual / Social | Colyseus auto-sync or Nakama relay | State or messages |
→ Deep dive on each pattern: read references/architecture-patterns.md
Server (TypeScript):
import { defineServer, defineRoom, Schema, type, MapSchema } from "colyseus";
class Player extends Schema {
@type("number") x: number = 0;
@type("number") y: number = 0;
}
class GameState extends Schema {
@type({ map: Player }) players = new MapSchema<Player>();
}
class GameRoom {
onCreate() { this.setState(new GameState()); }
onJoin(client) {
this.state.players.set(client.sessionId, new Player());
}
onMessage(client, type, message) {
const player = this.state.players.get(client.sessionId);
if (type === "move") { player.x = message.x; player.y = message.y; }
}
onLeave(client) { this.state.players.delete(client.sessionId); }
}
defineServer({ rooms: { game: defineRoom(GameRoom) } });Unity Client (C#):
using Colyseus;
var client = new Client("ws://localhost:2567");
var room = await client.JoinOrCreate<GameState>("game");
// Listen to player additions
var callbacks = Callbacks.Get(room);
callbacks.OnAdd(state => state.players, (sessionId, player) => {
SpawnPlayer(sessionId, player);
callbacks.Listen(player, p => p.x, (val, prev) => MovePlayer(sessionId));
});
// Send input
await room.Send("move", new { x = transform.position.x, y = transform.position.z });→ Full Colyseus integration guide: references/colyseus-integration.md → Server template: assets/colyseus-room-template.ts → Client template: assets/unity-colyseus-manager.cs
Server (TypeScript runtime):
const matchInit: nkruntime.MatchInitFunction = (ctx, logger, nk, params) => {
return { state: { players: {}, tick: 0 }, tickRate: 20, label: "" };
};
const matchLoop: nkruntime.MatchLoopFunction = (ctx, logger, nk, dispatcher, tick, state, messages) => {
for (const msg of messages) {
const data = JSON.parse(new TextDecoder().decode(msg.data));
state.players[msg.sender.userId] = { x: data.x, y: data.y };
}
dispatcher.broadcastMessage(1, JSON.stringify(state.players));
return { state };
};Unity Client (C#):
using Nakama;
var client = new Client("http", "127.0.0.1", 7350, "defaultkey",
UnityWebRequestAdapter.Instance);
var session = await client.AuthenticateDeviceAsync(SystemInfo.deviceUniqueIdentifier);
var socket = client.NewSocket(useMainThread: true);
await socket.ConnectAsync(session);
var match = await socket.CreateMatchAsync();
// Send state
await socket.SendMatchStateAsync(match.Id, 0,
System.Text.Encoding.UTF8.GetBytes(JsonUtility.ToJson(position)));
// Receive state
socket.ReceivedMatchState += (matchState) => {
var data = System.Text.Encoding.UTF8.GetString(matchState.State);
ApplyState(matchState.UserPresence.UserId, JsonUtility.FromJson<Position>(data));
};→ Full Nakama integration guide: references/nakama-integration.md → Server template: assets/nakama-match-handler-template.ts → Client template: assets/unity-nakama-manager.cs
When optimizing for mobile + WebGL2, follow this priority order:
NetworkVariable for persistent state, RPCs for events.→ Detailed optimization guide: references/performance-optimization.md
Both Colyseus and Nakama deploy via Docker. For production:
wss://)→ Full deployment guides: references/deployment-guides.md
Read these as needed — don't load all at once:
| File | When to read |
|---|---|
references/architecture-patterns.md | Choosing network topology, state sync strategy, or ECS networking |
references/colyseus-integration.md | Setting up Colyseus server, Unity SDK, rooms, schema, matchmaking |
references/nakama-integration.md | Setting up Nakama server, Unity SDK, auth, multiplayer, storage |
references/websocket-networking.md | Choosing/configuring WebSocket library, reconnection logic |
references/webgl2-constraints.md | Understanding WebGL2 limitations, conditional compilation patterns |
references/performance-optimization.md | Network bandwidth, serialization, GC, mobile battery, object pooling |
references/deployment-guides.md | Docker, Nginx, SSL, Redis, scaling, managed hosting options |
| File | Purpose |
|---|---|
assets/colyseus-room-template.ts | Production-ready Colyseus room with auth, reconnection, clock sync |
assets/nakama-match-handler-template.ts | Authoritative Nakama match with tick loop, presence tracking |
assets/unity-colyseus-manager.cs | Unity singleton managing Colyseus connection, room join, state callbacks |
assets/unity-nakama-manager.cs | Unity singleton managing Nakama client, socket, auth, match lifecycle |
assets/unity-websocket-client.cs | Standalone WebSocket client with exponential backoff reconnection |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.