Skip to content

Latest commit

 

History

611 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Magnetite

MAGNETITE

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.

License: MIT Rust WASM Decentralized Self-hostable

VulOS Part of VulOS — the open, self-hostable web OS & app suite. Runs standalone, or as an app hosted by the Vulos OS.


Magnetite — the decentralized, self-hostable Rust game platform

What is magnetite?

The sharpest claim here: every match is reproducible. The server records one ReplayLog per match — inputs plus a state_hash per tick (backend/magnetite-sdk/src/authority.rs:1093) — and anyone can re-run it through verify_replay (authority.rs:1205) to get back the same hashes or a named Divergence. That is not an aspiration: a unit test tampers with a recorded hash and asserts verify_replay catches it (authority.rs:1534, "tampered hash must yield Divergence at tick 3"), and an end-to-end test drives real, varying, non-empty inputs from four players through both a native and a WASM-sandboxed executor and asserts every tick's hash matches between them (magnetite-e2e/tests/wasm_end_to_end.rs, wasm_sandbox_parity_with_native) — deliberately not the empty-input version of that test that used to pass while hiding a guest bug that discarded every input frame. A match log is not a black box; it is a claim anyone holding it can check.

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


Part of VulOS

magnetite is an independent VulOS product — a game platform, not the OS itself. It runs fully standalone: the magnetite binary needs no Vulos account, no Vulos infrastructure, and no network beyond whatever seams you choose to enable. It can also be hosted as an app inside the Vulos OS shell, the same way any other VulOS product is.

VulOS publishes one thing outright — the OS — free and open source (MIT OR Apache-2.0). There is no managed hosting and nothing sold or operated by Vulos; every product, magnetite included, is self-provisioned and self-paid for by whoever runs it. See vulos.org for the rest of the suite.


The moat — one Rust game, jam to AAA

Nobody gives an open, Rust-native "same code, jam-to-AAA, authoritative + sandboxed + anti-cheat + one-command-deploy" primitive. That's what this is.

Scale primitive — identical game code, topology auto-selected

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.

Wasmtime sandbox — untrusted game logic, deterministic by construction

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 clockrandom_get and clock_time_get return ENOSYS. The only randomness source is StepCtx.rng (DeterministicRng, xoshiro256**), derived per tick from (MatchConfig::seed, tick) — so RNG position is implied by the tick rather than carried as hidden state a snapshot cannot capture.

Result: same (state, ordered commands, tick, seed) always produces the same result, on any host.

The guest boundary is a documented, language-agnostic contract — eight C-ABI exports and length-prefixed JSON, nothing Rust-specific — see site/docs/sandbox-abi.md. cargo run -p magnetite-sandbox --bin mag-conformance -- your.wasm checks any module against it.

Anti-cheat by construction — server-authoritative + deterministic replay verification

  1. Clients send inputs; the server runs AuthoritativeGame::validate to reject illegal actions, then AuthoritativeGame::step to advance state. Clients never send state.
  2. The runtime records a ReplayLog (every tick's inputs + state_hash). verify_replay re-simulates from scratch; any divergence is tamper evidence or a determinism bug.
  3. magnetite-anticheat adds composable Validators (aimbot snap, position teleport, fire-rate flood) and a TrustScoreMap (Warn → Kick → Ban escalation with decay).

Exercised end to end by magnetite-e2e (19 passing tests): WasmExecutor and NativeExecutor produce identical state_hash on every tick under non-empty, varying inputs from four players, a snapshot taken mid-match resumes the same trajectory in a fresh sandboxed executor, 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.

The emphasis is load-bearing. The parity test used to step both executors with an empty input list, which agrees perfectly on an idle physics loop and hid a guest bug that discarded every input frame. Parity over no inputs is not parity.


Decentralized by seam, not by rewrite

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) SolanaPaymentRail (real, wired into backend, never run against a validator); magnetite-stellar-rail (real, standalone, not yet wired into backend) — neither has ever settled a payment itself

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.


Screenshots

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.

Server browser — nodes self-advertise; discovery is a phonebook, never an authority Wallet — non-custodial: an address you control plus signed receipts
Magnetite server browser — discovered sessions with game content hash, node, capacity, ping and price Magnetite non-custodial wallet — linked address and signed receipts
Developer revenue — receipt-backed, paid straight to your wallet Game detail — signed-build provenance; non-custodial checkout, no platform cut
Magnetite developer revenue — signed receipts Magnetite game detail — signed-build / replay provenance and non-custodial, wallet-to-wallet checkout
Architecture — node / discovery / payment / comms diagram Comms — pluggable Matrix / Jitsi / LiveKit integrations
Magnetite architecture docs Magnetite comms docs
Hosting a server — capacity-elastic node model Payments — non-custodial crypto
Magnetite hosting-a-server docs Magnetite payments docs

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 throwaway vite dev server with VITE_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.


Quick start

# 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.org

magnetite 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.

Repo development (this checkout)

There is no root Cargo.toml — this repo is 14 standalone crates linked by path dependencies, each with its own manifest, on purpose (see the comment at the top of magnetite-seams/Cargo.toml). A bare cargo build --workspace at the repo root fails with "could not find Cargo.toml"; .github/workflows/ci.yml builds and tests each crate from its own directory via the matrix in ci/rust-crates.json, and local development follows the same shape:

# Frontend (pre-decentralization marketplace UI, being rebuilt against the seams)
npm install
npm run dev          # http://localhost:5173

# Any Rust crate — cd into it first, e.g.:
cd magnetite-runtime && cargo build && cargo test
cd magnetite-seams && cargo build --all-features && cargo test --all-features

# Every crate, the same way CI does it:
jq -c '.[]' ci/rust-crates.json | while read -r c; do
  dir=$(echo "$c" | jq -r .dir); flags=$(echo "$c" | jq -r .flags)
  (cd "$dir" && cargo test --locked $flags)
done

# Authoritative runtime standalone (smoke-test mode, no wasm required)
cd magnetite-runtime && cargo run --bin serve

Architecture

Player 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 map

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
magnetite-web-host Serves a content-addressed three.js/Godot/Unity/Bevy-web build over HTTP with an entitlement check — no tick loop, no authority, deliberately not a game host
magnetite-solana-rail Real SPL-USDC-on-Solana PaymentRail; wired into backend behind --features solana / PAYMENT_RAIL=solana; never run against a validator
magnetite-stellar-rail Real native-USDC-on-Stellar PaymentRail; standalone (no patala dependency); landed but not yet wired into backend's rail selector, and never run against Horizon — see docs/payments.md
magnetite-kotva A narrow, unselected binding of the Identity/Naming seams to the kotva substrate — demonstrates the seams are bindable; nothing in the default build depends on it
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

SDK quick-start

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 / Sharded

See backend/magnetite-sdk/ and game-templates/arcade/ for the full starter, and game-templates/authoritative/ for the canonical AuthoritativeGame reference implementation.


Configuration

The node binary (magnetite serve / magnetite node) is configured entirely by CLI flags — --wasm, --advertise, --cluster-peer, --handoff-addr — see Quick start and docs/hosting-a-server.md. There is no config file and no environment variable it reads: capacity (shard count, player budget) is measured from the box's own cores and RAM, not set.

The pre-redesign backend and legacy React marketplace frontend (Postgres, Redis, JWT, OAuth) still read .env — copy .env.example to .env and fill in the values before running docker-compose.yml or npm run dev. That surface predates the decentralized redesign; see docs/self-hosting/index.md for what still depends on it.


Documentation

Guide File
Overview docs/overview.md
Getting started docs/getting-started.md
Roadmap (reference games) ROADMAP.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.


Development

Prerequisites: Rust 1.91+ (with wasm32-wasip1 target), Node.js 18+. backend/'s locked dependency tree (AWS SDK crates) currently requires rustc 1.91.1 or newer to even parse — verified by building backend with pinned toolchains; anything below that fails before compilation starts.

rustup target add wasm32-wasip1

# No root Cargo.toml (14 standalone crates) — build/test/lint per crate, e.g.:
cd magnetite-seams && cargo build --all-features && cargo test --all-features && cargo clippy --all-features -- -D warnings
cd ../magnetite-sandbox && cargo build && cargo test && cargo clippy -- -D warnings
# ...or every crate exactly as CI does it, see ci/rust-crates.json + .github/workflows/ci.yml

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.


Brand

The mark in brand/ is the source of truth. Every icon this repo ships — favicon, PWA and app icons, the mark in the README and on the site — is rendered from brand/logo.svg rather than redrawn, so there is one approved drawing and no second copy to drift.

Copy it outward, never edit a derived copy, and never edit brand/ to match something downstream.

Contributing

See CONTRIBUTING.md.

License

MIT OR Apache-2.0 — © VulOS. Magnetite is a VulOS project; source and issues at github.com/vul-os/magnetite. Platform, SDK, and game templates are all dual-licensed.


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.

---

vulos
vulos — open by design

About

Decentralized, self-hostable Rust game platform — bring any server and it scales to your hardware, content-addressed games, non-custodial crypto payments, pluggable decentralized comms (Matrix/Jitsi). No cloud required.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages