Fe₃O₄ — magnetic, grounded
The decentralized, self-hostable Rust game platform.
Bring any server. It scales to your hardware. No cloud required.
Content-addressed games, deterministic WASM sandboxing, replay-verified anti-cheat, and non-custodial crypto payments.
Part of Vulos — the open, self-hostable web OS & app suite. Runs perfectly standalone; no Vulos account required.
Magnetite is a decentralized, self-hostable Rust game platform: write a game once against a deterministic authoritative-server SDK, and run it anywhere from a laptop to a fleet you own — no central cloud, no fiat custody, and no home-grown chat/voice/streaming stack standing between a player and the person hosting them.
A game is a content-addressed portable object. A node is generic compute that fills its own hardware. The chain is the wallet. Discovery is a phonebook, not an authority. Everything social — chat, voice, video, streaming — is a pluggable integration, not something we build.
Anyone runs the single magnetite node binary. Identity is a keypair.
Payments are non-custodial crypto. Comms are provided by existing
decentralized systems (Matrix/Element, Jitsi, LiveKit, Owncast/PeerTube)
through one adapter seam. The game runtime — authoritative simulation, WASM
sandbox, deterministic replay and anti-cheat — is the one thing Magnetite
owns outright, and it was decentralization-ready from day one. See
DECENTRALIZATION.md for the full redesign spec.
GitHub · Quick start · Docs · Architecture · License
Nobody gives an open, Rust-native "same code, jam-to-AAA, authoritative + sandboxed + anti-cheat + one-command-deploy" primitive. That's what this is.
Write your game once against magnetite-sdk::authority::AuthoritativeGame.
The platform runs it at any scale:
| Topology | Player count | How |
|---|---|---|
SingleRoom |
up to ~16 | 1 process, broadcast-all |
Dedicated |
up to ~256 | authoritative server, interest-filtered snapshots |
Sharded |
AAA / unbounded | spatial shards + cross-shard handoff |
MatchConfig::auto(n) escalates topology by player count. Your game code is
identical across all three.
Perf numbers (debug build, single-threaded in-proc, magnetite-e2e scale bench):
| Scenario | ticks/sec | μs/tick |
|---|---|---|
| SingleRoom (4 players) | 203,116 | 4.92 |
| SingleRoom (16 players) | 185,399 | 5.39 |
| Dedicated (32 players) | 151,388 | 6.61 |
| Dedicated (64 players) | 114,215 | 8.76 |
| Dedicated (128 players) | 78,950 | 12.67 |
| Dedicated (256 players) | 50,591 | 19.77 |
A release build is ~3–5× faster. The smoke-check assertion ticks/sec ≥ 1,000
is met with large margin.
Game logic compiles to wasm32-wasip1 and runs inside a WasmExecutor with
hard guarantees:
- Fuel budget per tick (
fuel_per_step) — runaway loops cannot stall the server. - Memory cap (
max_memory_bytes) — guest cannot exhaust host RAM. - Epoch interrupt (
epoch_tick_ms × max_epochs_per_step) — wall-clock timeout per step. - No OS randomness, no wall clock —
random_getandclock_time_getreturnENOSYS. The only randomness source isStepCtx.rng(seededDeterministicRng, xoshiro256**).
Result: same (state, ordered commands, tick, seed) always produces the same result, on any host.
- Clients send inputs; the server runs
AuthoritativeGame::validateto reject illegal actions, thenAuthoritativeGame::stepto advance state. Clients never send state. - The runtime records a
ReplayLog(every tick's inputs +state_hash).verify_replayre-simulates from scratch; any divergence is tamper evidence or a determinism bug. magnetite-anticheatadds composableValidators (aimbot snap, position teleport, fire-rate flood) and aTrustScoreMap(Warn → Kick → Ban escalation with decay).
Proved end to end by magnetite-e2e (9 passing tests): WasmExecutor and
NativeExecutor produce identical state_hash on every tick, verify_replay
returns Clean, cheating inputs are rejected and escalate the trust score,
and a full-stack WebSocket test with 3 real clients confirms convergence.
Everything provider-specific plugs in behind six traits (magnetite-seams).
The game runtime, scheduler, and payment path never name a provider type —
only the seam. Every seam ships a working, non-custodial, non-cloud default.
| Seam | Purpose | Default | Optional |
|---|---|---|---|
Identity / AuthProvider |
keypair identity, sign-a-challenge login | RawKeypairAuth (Ed25519) |
DmtapAuth (decentralized login) |
Naming |
human name ↔ raw key, display layer only | HashNaming |
DmtapNaming (name@domain ladder) |
BlobStore |
content-addressed games and assets | LocalBlobStore + HttpBlobStore |
DmtapPubBlobStore (MOTE); Iroh/BitTorrent |
Discovery |
the phonebook — never an authority | TrackerDiscovery + LanDiscovery (mDNS) |
DHT adapter |
CommsProvider |
chat / voice / video / streaming | BuiltinProvider (fallback) |
Matrix, Jitsi, LiveKit, Owncast/PeerTube |
PaymentRail |
non-custodial crypto checkout, hosting fees, wagers | MockPaymentRail (CI-safe) |
on-chain rail (USDC on L2, or Solana) |
No fiat, no custody, no platform-held balances anywhere in the payment path — see docs/payments.md. No home-grown chat/voice/streaming stack a game is forced to depend on — see docs/comms.md. No central server registry to poll for capacity — see docs/hosting-a-server.md.
The landing page and docs viewer share Magnetite's own dark, near-black
"lodestone" identity — a magnetic violet→magenta accent (#7b61ff →
#ff4d9d) evoking a magnetic field, over a graphite base darker than any
other Vulos product.
Regenerate anytime with
npm run screenshotter(alias:npm run screenshots) — it serves the static site with a tiny built-in Node server, boots the app on a throwawayvitedev server withVITE_USE_MOCKS=true, and captures every surface in light and dark at retina. No backend, database or wasm build required. See docs/screenshots.md for the full gallery.
# install once
cargo install magnetite-cli
# scaffold a crate implementing AuthoritativeGame
magnetite new my-game
cd my-game
# cargo build --release --target wasm32-wasip1 → game.wasm
magnetite build
# build → WasmExecutor → SingleRoom server, ZERO backend
magnetite dev
# ws://127.0.0.1:<port> — play it right now
# bring your own box: measures its hardware, advertises
# capacity, joins the discovery mesh
magnetite serve --wasm path/to/game.wasm --advertise tracker.example.orgmagnetite dev already runs a game with zero backend, and magnetite serve
already takes an arbitrary box you own — there is no cloud account to create
and no capacity to request. See Getting started
for the full walkthrough.
The Rust workspace and the legacy React marketplace frontend still build the same way as before:
# Frontend (pre-decentralization marketplace UI, being rebuilt against the seams)
npm install
npm run dev # http://localhost:5173
# Rust workspace
cargo build --workspace
cargo test --workspace
# Authoritative runtime standalone (smoke-test mode, no wasm required)
cargo run --package magnetite-runtime --bin servePlayer keypair (Identity)
│
▼
Discovery (TrackerDiscovery + LanDiscovery) ──announce/find──► magnetite node
│ │ ├─ Capacity measurement
│ │ ├─ ShardScheduler
▼ │ ├─ AuthoritativeGame (WASM sandbox)
SessionAd (game hash, capacity, price, rooms) │ ├─ ReplayLog / verify_replay
│ └─ BlobStore (content-addressed)
│
┌───────────────────────┼───────────────────────┐
▼ ▼
PaymentRail (non-custodial) CommsProvider (pluggable)
checkout · open_channel · escrow Matrix · Jitsi/LiveKit · Owncast
Full diagram (mermaid) + the seam trait signatures: docs/architecture.md.
Full redesign spec + program backlog: DECENTRALIZATION.md.
| Crate | Role |
|---|---|
magnetite-seams |
The six seam traits + non-custodial, non-cloud default implementations |
backend/magnetite-sdk (::authority) |
Frozen traits: AuthoritativeGame, GameExecutor, NativeExecutor, Validator, ReplayLog, verify_replay, Topology, MatchConfig, DeterministicRng |
magnetite-runtime |
Authoritative game-server host: tick loop, WebSocket connection mgmt, interest-filtered delta/snapshot fan-out, ShardManager seam; magnetite-serve binary |
magnetite-sandbox |
WasmExecutor — Wasmtime host implementing GameExecutor; fuel/memory/epoch limits; WASI stubs (no clock, no rng) |
magnetite-anticheat |
Composable validators, TrustScoreMap, ReplayVerifier |
magnetite-cli |
magnetite new|build|dev|deploy|serve binary |
magnetite-web-client |
JS web client speaking ClientNet/ServerNet; prediction buffer; canvas renderer; in-browser replay playback |
game-template-authoritative |
Reference game (top-down arena shooter) implementing AuthoritativeGame; canonical wasm ABI exports behind --features wasm |
game-client-bevy |
Bevy client with prediction/reconciliation (PredictionBuffer + ClientPredictor) wired to ServerNet |
magnetite-e2e |
Integration tests: convergence + verify_replay clean + anti-cheat WS rejection + wasm parity vs native + full-stack WS + scale bench |
use magnetite_sdk::{
export_game,
game::{GameLogic, GameMetadata},
input::{Action, Input},
state::{GameState, PlayerId, Snapshot},
};
struct MyGame { state: GameState }
impl GameLogic for MyGame {
fn new() -> Self { MyGame { state: GameState::default() } }
fn handle_input(&mut self, _pid: PlayerId, _input: Input) -> Action { Action::None }
fn tick(&mut self) { self.state.tick += 1; }
fn state(&self) -> &GameState { &self.state }
fn players(&self) -> Vec<PlayerId> { vec![] }
fn metadata(&self) -> GameMetadata { GameMetadata::default() }
fn snapshot(&self) -> Snapshot { Snapshot::new(self.state.tick, self.state.clone()) }
fn restore(&mut self, snap: Snapshot) { self.state = snap.state; }
}
export_game!(MyGame);For the server-authoritative path:
use magnetite_sdk::authority::{AuthoritativeGame, Topology, MatchConfig};
// Implement AuthoritativeGame, then:
let cfg = MatchConfig::auto(player_count); // SingleRoom / Dedicated / ShardedSee backend/magnetite-sdk/ and
game-templates/arcade/ for the full starter, and
game-templates/authoritative/ for the
canonical AuthoritativeGame reference implementation.
| Guide | File |
|---|---|
| Overview | docs/overview.md |
| Getting started | docs/getting-started.md |
| Architecture (seams + planes, mermaid diagram) | docs/architecture.md |
| Hosting a server (capacity-elastic nodes) | docs/hosting-a-server.md |
| Payments (non-custodial crypto) | docs/payments.md |
| Comms (Matrix / Jitsi / LiveKit / Owncast) | docs/comms.md |
| Screenshots | docs/screenshots.md |
| Decentralization spec + backlog | DECENTRALIZATION.md |
| MOAT Architecture | docs/MOAT-ARCHITECTURE.md |
| MOAT Scaling (topology + bench) | docs/moat/scaling.md |
| Replay & Spectator | docs/moat/replay-spectator.md |
| Developer Quickstart (SDK) | docs/for-developers/quickstart.md |
| Self-Hosting Guide | docs/self-hosting/index.md |
| Security & Sandboxing | docs/security/index.md |
Interactive docs site (static, no build step): open
site/docs.html, or the landing page.
Prerequisites: Rust 1.82+ (with wasm32-wasip1 target), Node.js 18+.
rustup target add wasm32-wasip1
cargo build --workspace
cargo test --workspace
cargo clippy --workspace
npm install
npm run dev # legacy marketplace frontend (Vite, :5173)
npm run lint
npm run test:run # Vitest
npm run screenshotter # regenerate docs/screenshots/ (alias: npm run screenshots)Frozen invariant: the game runtime, scheduler, and payment path never name a provider-specific type — every provider integration goes through
magnetite-seams. See DECENTRALIZATION.md § 6.
MIT — see LICENSE. Platform, SDK, and game templates are all MIT.
See CONTRIBUTING.md.
GitHub · Issues · Decentralization spec
Magnetite is a free, open-source, self-hostable, decentralized Rust game platform.
Built as an alternative to Nakama, PlayFab, and Roblox — without the custody, without the cloud lock-in.







