Skip to content

widgrensit/asobi

Repository files navigation

Asobi

Hex.pm CI

Open-source game backend platform built on Erlang/OTP and the Nova ecosystem.

Asobi Arena Demo
Try the live demo

Asobi provides everything you need to build and run multiplayer games: authentication, player management, real-time multiplayer, matchmaking, leaderboards, virtual economy, social features, and background jobs -- all in a single BEAM release.

Features

  • Authentication -- register, login, session tokens via nova_auth
  • Player Management -- profiles, stats, metadata
  • Real-Time Multiplayer -- WebSocket transport, server-authoritative game loop with configurable tick rate
  • Matchmaking -- query-based matching with skill windows and party support
  • Leaderboards -- ETS-backed for microsecond reads, PostgreSQL for persistence
  • Virtual Economy -- wallets, transactions, item definitions, store, inventory
  • Social -- friends, groups/guilds, chat channels, presence, notifications
  • Tournaments -- scheduled competitions with entry fees and rewards
  • Cloud Saves -- per-slot save data with optimistic concurrency
  • Generic Storage -- key-value storage with permissions (public/owner/none)
  • Background Jobs -- powered by Shigoto
  • Admin Dashboard -- real-time LiveView console via Arizona

Quick Start with Lua (Docker)

No Erlang needed. Just Lua scripts and Docker.

mkdir my_game && cd my_game
mkdir -p lua/bots

Write your game logic in Lua:

-- lua/match.lua
match_size = 2
max_players = 4
strategy = "fill"

function init(config)
    return { players = {} }
end

function join(player_id, state)
    state.players[player_id] = { x = 400, y = 300, hp = 100 }
    return state
end

function leave(player_id, state)
    state.players[player_id] = nil
    return state
end

function handle_input(player_id, input, state)
    local p = state.players[player_id]
    if not p then return state end
    if input.right then p.x = p.x + 5 end
    if input.left  then p.x = p.x - 5 end
    return state
end

function tick(state)
    return state
end

function get_state(player_id, state)
    return { players = state.players }
end

Add a docker-compose.yml:

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: my_game_dev
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

  asobi:
    image: ghcr.io/widgrensit/asobi_lua:latest
    depends_on:
      postgres: { condition: service_healthy }
    ports:
      - "8080:8080"
    volumes:
      - ./lua:/app/game:ro
    environment:
      ASOBI_DB_HOST: postgres
      ASOBI_DB_NAME: my_game_dev
docker compose up -d

That's it. Your game backend is running with authentication, matchmaking, WebSocket transport, and everything else handled by Asobi.

Quick Start with Erlang

For Erlang/OTP developers who want full control, add asobi as a dependency:

{deps, [
    {asobi, "~> 0.1"}
]}.

Implement the asobi_match behaviour:

-module(my_arena_game).
-behaviour(asobi_match).

-export([init/1, join/2, leave/2, handle_input/3, tick/1, get_state/2]).

init(_Config) ->
    {ok, #{players => #{}}}.

join(PlayerId, #{players := Players} = State) ->
    {ok, State#{players => Players#{PlayerId => #{x => 0, y => 0}}}}.

leave(PlayerId, #{players := Players} = State) ->
    {ok, State#{players => maps:remove(PlayerId, Players)}}.

handle_input(_PlayerId, _Input, State) ->
    {ok, State}.

tick(State) ->
    {ok, State}.

get_state(_PlayerId, #{players := Players}) ->
    Players.

Register it in sys.config and start with rebar3 shell. See the Getting Started guide for the full walkthrough.

Stack

Layer Technology
HTTP / REST Nova (Cowboy)
WebSocket Nova WebSocket (Cowboy)
Database / ORM Kura (PostgreSQL via pgo)
Real-time UI Arizona
Authentication nova_auth
Background Jobs Shigoto
Pub/Sub OTP pg module

Why BEAM?

The BEAM VM is uniquely suited for game backends:

  • Per-process GC -- no global pauses; one match collecting garbage never affects another
  • Fault tolerance -- OTP supervision restarts crashed matches without affecting others
  • Hot code upgrade -- deploy game logic changes without disconnecting players
  • Native clustering -- distributed Erlang handles cross-node messaging with no external coordination
  • 500K+ connections per node -- dramatically lower infrastructure costs
  • No external state stores -- ETS replaces Redis, pg replaces pub/sub services

Documentation

Full documentation is available on HexDocs.

License

Apache-2.0

About

Game backend platform built on Nova/OTP

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors