ROCK is a programmable runtime for Lua-scripted multiplayer worlds.
Start with the scripting guide:
ROCK is a multiplayer runtime for building online worlds with Lua. The runtime owns the boring hard parts: sockets, sessions, entity replication, persistence, async work, timers, and event routing. Your gamemode stays close to the thing you actually want to write.
The Lua DSL is inspired by SA-MP Pawn gamemodes and ReactiveX:
on.player.online()
:each(function(p)
print("player connected", p:id())
end)
on.player.input()
:bind_action("Jump")
:skip(2)
:take(1)
:each(function(p)
print("third jump goes higher")
end)ROCK is early, but already usable for small multiplayer worlds.
Today, you can build:
- SA-MP-style Lua gamemodes;
- multiplayer websites where every visitor is connected by default;
- live rooms with presence, shared state, custom entities, and server-driven events;
- persistent social spaces backed by SQLite memory;
- reactive event systems with filters, throttles, timers, and one-shot handlers;
- Farcaster-connected experiences that react to casts, users or webhooks;
- prototypes for bots, live events, multiplayer toys, dashboards, games, and tiny virtual spaces.
ROCK is not a renderer, physics engine, or full game editor. It's the server-side runtime.
Bring your own lens. ROCK gives it a shared world to connect to.
- Rust toolchain
- SQLite is used internally through the runtime dependencies
- A Lua gamemode file in
gamemodes/
From the repository root:
cargo build --releaseROCK reads config.toml, gamemodes/, geodes/, assets/, and db/ from the current working directory. In practice, build the binary and run it from the directory that contains your server files.
rock genesis my_gamemodeOr copy the included example:
mkdir -p gamemodes
cp /path/to/rock/examples/freeroam.lua gamemodes/freeroam.luaFor the copied example, set name = "freeroam" in config.toml.
This creates:
gamemodes/my_gamemode.lua
config.toml
assets/Minimal config.toml:
[gamemode]
name = "my_gamemode"rock igniteBy default, the server listens on 127.0.0.1:3000.
Clients connect via WebSocket:
ws://127.0.0.1:3000A sample gamemode is available at:
examples/freeroam.luaTiny example:
local player_bp = entity.blueprint()
:name("player")
:position({ x = 0, y = 0 })
:custom({ health = 100 })
player_bp:sync()
:only(function(c) return { c.position, "health" } end)
:commit()
on.player.online()
:each(function(p)
local ent = player_bp:spawn():room("world")
ent:owned_by(p:id())
p:vision():attach(ent)
p:signal("Identity"):data({ pid = p:id(), room = "world" }):send()
end)- Entities and components: build world objects from position, sprites, ownership, custom data, and more.
- Rooms and vision: players receive only the world slice visible through their attached vision anchors.
- Reactive events: chain
:where,:select,:take,:throttle, and friends over runtime events. - Scenes: write async work like database reads or network requests as straightforward Lua code.
- Memory: persist arbitrary gamemode state through the
memoryplugin backed by SQLite. - Geodes: package reusable Lua modules and systems.
ROCK supports optional provider-based authentication:
- ROCK tickets (JWT)
- Farcaster Quick Auth
When auth providers are configured, clients authenticate WebSocket sessions with the configured session cookie. If only one provider is configured, ROCK selects it automatically. If multiple providers are configured, clients must choose one:
ws://127.0.0.1:3000/?auth=ticket
ws://127.0.0.1:3000/?auth=farcasterWithout auth configuration, sessions are anonymous.
ROCK exposes a live-code endpoint, POST /impromptu, for local development and debugging. It is disabled unless ROCK_IMPROMPTU_TOKEN is set, and requests must include:
X-Rock-Impromptu-Token: ...Cookie-authenticated WebSocket sessions should also set ROCK_ALLOWED_ORIGINS to prevent browser-based cross-site WebSocket hijacking.
See DOCS.md for the full security-related setup.
ROCK is inspired by the feeling of writing SA-MP Pawn gamemodes: small scripts that could turn a plain multiplayer sandbox into a living world. The goal is to keep that direct gamemode-authoring loop, but give it a modern runtime underneath.
