{"id":50115354,"url":"https://github.com/widgrensit/asobi_lua","last_synced_at":"2026-05-23T14:34:10.022Z","repository":{"id":350021559,"uuid":"1204886452","full_name":"widgrensit/asobi_lua","owner":"widgrensit","description":"Lua scripting runtime for Asobi — game logic in Lua, powered by Luerl on BEAM","archived":false,"fork":false,"pushed_at":"2026-05-14T13:01:27.000Z","size":1563,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-14T15:07:43.118Z","etag":null,"topics":["asobi","beam","docker","erlang","game-backend","gamedev","lua","luerl","multiplayer","otp","runtime","scripting"],"latest_commit_sha":null,"homepage":null,"language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/widgrensit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-08T12:34:03.000Z","updated_at":"2026-05-14T13:01:30.000Z","dependencies_parsed_at":"2026-05-14T15:03:11.376Z","dependency_job_id":null,"html_url":"https://github.com/widgrensit/asobi_lua","commit_stats":null,"previous_names":["widgrensit/asobi_lua"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/widgrensit/asobi_lua","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widgrensit%2Fasobi_lua","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widgrensit%2Fasobi_lua/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widgrensit%2Fasobi_lua/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widgrensit%2Fasobi_lua/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/widgrensit","download_url":"https://codeload.github.com/widgrensit/asobi_lua/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widgrensit%2Fasobi_lua/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33400247,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T04:15:53.637Z","status":"ssl_error","status_checked_at":"2026-05-23T04:15:53.242Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asobi","beam","docker","erlang","game-backend","gamedev","lua","luerl","multiplayer","otp","runtime","scripting"],"created_at":"2026-05-23T14:34:09.277Z","updated_at":"2026-05-23T14:34:10.009Z","avatar_url":"https://github.com/widgrensit.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"asobi\" src=\"https://raw.githubusercontent.com/widgrensit/asobi/main/docs/logo.png\" height=\"96\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003easobi_lua\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003eOpen-source game backend. Write it in Lua. Hot-reload without restart. Apache-2.\u003c/b\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/widgrensit/asobi_lua/pkgs/container/asobi_lua\"\u003e\u003cimg alt=\"Docker\" src=\"https://img.shields.io/badge/ghcr.io-asobi__lua-2496ed?logo=docker\u0026logoColor=white\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/widgrensit/asobi_lua/releases\"\u003e\u003cimg alt=\"Release\" src=\"https://img.shields.io/github/v/release/widgrensit/asobi_lua?sort=semver\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/widgrensit/asobi_lua/actions\"\u003e\u003cimg alt=\"CI\" src=\"https://github.com/widgrensit/asobi_lua/actions/workflows/ci.yml/badge.svg\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg alt=\"License\" src=\"https://img.shields.io/badge/license-Apache--2.0-blue\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://asobi.dev/docs\"\u003eDocs\u003c/a\u003e •\n  \u003ca href=\"https://asobi.dev/demo\"\u003eLive demo\u003c/a\u003e •\n  \u003ca href=\"https://discord.gg/vYSfYYyXpu\"\u003eDiscord\u003c/a\u003e •\n  \u003ca href=\"https://github.com/widgrensit/asobi_lua/issues\"\u003eIssues\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/media/hotreload-demo.gif\" alt=\"asobi_lua hot-reload: edit a Lua file, save, live match updates — no restart\" width=\"800\"\u003e\n  \u003cbr\u003e\n  \u003cem\u003eEdit a Lua file. Save. Live match updates. No restart. \u003ca href=\"https://github.com/widgrensit/asobi/tree/main/examples/hotreload-demo\"\u003eTry it.\u003c/a\u003e\u003c/em\u003e\n\u003c/p\u003e\n\n---\n\n## What is asobi_lua?\n\nA batteries-included multiplayer game backend you write in Lua, packaged as\na single Docker image. You get auth, matchmaking, rooms, leaderboards, economy,\nchat, tournaments, voting, parties, phases and seasons, reconnection, and\nWebSocket + REST out of the box — and SDKs for Godot, Defold, Unity, Unreal,\nJS/TS, and Flutter.\n\nNo Erlang knowledge required. Your match logic is a `.lua` file. Save it and\nconnected clients see the change — no restart, no redeploy.\n\n```lua\n-- lua/match.lua\nmatch_size = 2\n\nfunction init(config)\n  return { players = {}, tick_count = 0 }\nend\n\nfunction join(player_id, state)\n  state.players[player_id] = { x = 400, y = 300, hp = 100 }\n  return state\nend\n\nfunction handle_input(player_id, input, state)\n  local p = state.players[player_id]\n  if input.right then p.x = p.x + 5 end\n  if input.left  then p.x = p.x - 5 end\n  if input.shoot then\n    game.broadcast(\"shot\", { by = player_id, at = input.aim })\n  end\n  return state\nend\n\nfunction tick(state)\n  state.tick_count = state.tick_count + 1\n  return state\nend\n```\n\nThat's a full playable room. Save the file, the match reloads in place.\n\n## Quick Start\n\n**1. Create the project layout**\n\n```bash\nmkdir my_game \u0026\u0026 cd my_game\nmkdir -p lua\n# paste the match.lua above into lua/match.lua\n```\n\n**2. Bring up Postgres + asobi_lua**\n\n```yaml\n# docker-compose.yml\nservices:\n  postgres:\n    image: postgres:17\n    environment: { POSTGRES_USER: postgres, POSTGRES_PASSWORD: postgres, POSTGRES_DB: my_game }\n    healthcheck: { test: [\"CMD-SHELL\", \"pg_isready -U postgres\"], interval: 5s }\n\n  asobi:\n    image: ghcr.io/widgrensit/asobi_lua:latest\n    depends_on: { postgres: { condition: service_healthy } }\n    ports: [\"8080:8080\"]\n    volumes: [\"./lua:/app/game:ro\"]\n    environment: { ASOBI_DB_HOST: postgres, ASOBI_DB_NAME: my_game }\n```\n\n```bash\ndocker compose up -d\n```\n\n**3. Register a player and join a match**\n\n```bash\n# Register\ncurl -s localhost:8080/api/v1/auth/register \\\n  -H 'content-type: application/json' \\\n  -d '{\"username\":\"alice\",\"password\":\"hunter2!\"}'\n# → { \"username\": \"alice\", \"player_id\": \"019de3...\", \"session_token\": \"wRqvop92/...\" }\n\n# Queue for matchmaking\ncurl -s localhost:8080/api/v1/matchmaker \\\n  -H 'content-type: application/json' \\\n  -H 'authorization: Bearer wRqvop92/...' \\\n  -d '{\"mode\":\"default\",\"properties\":{},\"party\":[\"019de3...\"]}'\n# → { \"status\": \"pending\", \"ticket_id\": \"019de3...\" }\n```\n\nConnect the WebSocket from any SDK below and the client is live. Edit\n`lua/match.lua`, save, and the running match picks up the change — players\nstay connected, state is preserved.\n\n## Why asobi\n\n- ⚡ **Hot-reload Lua** — push a fix at 11pm, your live match keeps playing. No restart, no dropped sockets.\n- 🎮 **Every engine** — first-class SDKs for Godot, Defold, Unity, Unreal, plus JS/TS and Flutter.\n- 🧠 **Batteries included** — matchmaker (fill + skill), rooms, economy, inventory, leaderboards, tournaments, chat, social, notifications, IAP, **voting with 4 methods** (plurality, ranked, approval, weighted), **phases**, **seasons**, reconnection.\n- 🗺️ **Large-world ready** — spatial zones, lazy zone loading, terrain chunks, adaptive tick rates. Single-node by design; shard at the app level.\n- 🚀 **83,000 msg/sec** sustained at 3,500 concurrent WebSockets, 4.4ms p50 RTT — see [benchmarks](https://github.com/widgrensit/asobi/blob/main/guides/benchmarks.md).\n- 🛡️ **Apache-2, self-host** — use commercially, fork it, run it yourself. We will never relicense. [Exit guaranteed →](https://github.com/widgrensit/asobi/blob/main/guides/exit.md)\n- 🇪🇺 **Made in the EU** — GDPR-ready, NIS2-aware, no US cloud lock-in.\n- 🔒 **OTP fault tolerance** — one match crashing never touches any other match. No GC pauses during gameplay.\n\n## Client SDKs\n\n| Engine | Install | Docs | Sample |\n|---|---|---|---|\n| **Godot 4.x** | [widgrensit/asobi-godot](https://github.com/widgrensit/asobi-godot) | [guide](https://github.com/widgrensit/asobi-godot#readme) | [asobi-godot-demo](https://github.com/widgrensit/asobi-godot-demo) |\n| **Defold** | [widgrensit/asobi-defold](https://github.com/widgrensit/asobi-defold) | [guide](https://github.com/widgrensit/asobi-defold#readme) | [asobi-defold-demo](https://github.com/widgrensit/asobi-defold-demo) |\n| **Unity 2021.3+** | `com.asobi.sdk` (UPM via git URL) | [guide](https://github.com/widgrensit/asobi-unity#readme) | [asobi-unity-demo](https://github.com/widgrensit/asobi-unity-demo) |\n| **Unreal 5** | [widgrensit/asobi-unreal](https://github.com/widgrensit/asobi-unreal) | [guide](https://github.com/widgrensit/asobi-unreal#readme) | — |\n| **JS / TS** | [widgrensit/asobi-js](https://github.com/widgrensit/asobi-js) | [guide](https://github.com/widgrensit/asobi-js#readme) | — |\n| **Flutter** | `dart pub add asobi` | [guide](https://github.com/widgrensit/asobi-dart#readme) | [asobi-flame-demo](https://github.com/widgrensit/asobi-flame-demo) |\n| **Flame (Flutter)** | [widgrensit/flame_asobi](https://github.com/widgrensit/flame_asobi) | [guide](https://github.com/widgrensit/flame_asobi#readme) | [asobi-flame-demo](https://github.com/widgrensit/asobi-flame-demo) |\n\n## How it works\n\n```\n  your Lua scripts (mounted at /app/game)\n        │\n        ▼\n  asobi_lua          ── Luerl VM + bridge modules + bot runtime\n        │\n        ▼\n  asobi (library)    ── OTP supervision, pg groups, rate limits, sessions\n        │\n        ▼\n  Nova + Kura + PostgreSQL\n```\n\nEvery match and world runs as its own BEAM process under a supervisor.\nLuerl executes your Lua inside the BEAM — no sub-process, no GC pauses. The\nscript runs in a hardened state with `os.execute`, `os.exit`, `dofile`,\n`loadfile`, `load`, `loadstring`, `io`, and `package` removed; `require/1`\nis replaced by an asobi_lua-controlled implementation that resolves names\nrelative to your `/app/game` directory and rejects `..` traversal. Every\ncallback runs under a wall-clock timeout so a runaway script can't wedge\nthe match loop. See [SECURITY.md](SECURITY.md#sandbox-model) for the full\nsandbox contract. Hot reload swaps the Luerl module while match state stays\nin the process heap.\n\n\u003e [!NOTE]\n\u003e asobi_lua is pre-1.0. The API is stabilising; expect minor breaking changes\n\u003e until 1.0. We ship in lockstep with the [asobi library](https://github.com/widgrensit/asobi)\n\u003e (Hex.pm) and version SDKs against server tags.\n\n## Self-host, today\n\nRun the image wherever you like — Hetzner, Scaleway, Fly, Clever, a Raspberry\nPi, your laptop. The image is **~120MB**, cold starts in **\u003c3s**, and holds\nthousands of WebSockets on a single vCPU. Full deployment guide at\n[asobi.dev/docs/deploy](https://asobi.dev/docs/deploy).\n\nA managed cloud at **asobi.dev** is opening later in 2026 — same binary, flat\nper-container pricing, never CCU-based. [Learn more →](https://asobi.dev/cloud).\n\n## Migrating?\n\n- [**from Hathora**](https://github.com/widgrensit/asobi/blob/main/guides/migrate-from-hathora.md) — rooms → matches, serverless processes → container. Hathora shuts down 2026-05-05.\n- [**from PlayFab**](https://github.com/widgrensit/asobi/blob/main/guides/migrate-from-playfab.md) — Titles, CloudScript, Virtual Currency mapped.\n- [**from Nakama self-host**](https://github.com/widgrensit/asobi/blob/main/guides/migrate-from-nakama.md) — keep your Lua runtime, lose CockroachDB.\n\n## Documentation\n\n- [**Lua Scripting Guide**](guides/lua-scripting.md) — callbacks, state, modules, voting, world mode\n- [**Bot AI Guide**](guides/lua-bots.md) — write bots that fill matches\n- [**Self-hosting**](guides/self-hosting.md) — production deployment patterns: bake-into-image vs. atomic-rename live updates\n- [**asobi engine docs**](https://github.com/widgrensit/asobi#readme) — architecture, REST API, WebSocket protocol, benchmarks\n\n## Community\n\n- 💬 [Discord](https://discord.gg/vYSfYYyXpu) — chat with the team and other devs\n- 🗣️ [GitHub Discussions](https://github.com/widgrensit/asobi_lua/discussions) — Q\u0026A, show-and-tell, RFCs\n- 🐛 [Issues](https://github.com/widgrensit/asobi_lua/issues) — bug reports and feature requests\n- 📦 [Releases](https://github.com/widgrensit/asobi_lua/releases) — changelog and release notes\n\n## Using asobi_lua as an Erlang library\n\nIf you're already writing Erlang/OTP and want Lua scripting as a dep:\n\n```erlang\n%% rebar.config\n{deps, [\n    {asobi_lua, {git, \"https://github.com/widgrensit/asobi_lua.git\", {tag, \"v0.1.0\"}}}\n]}.\n```\n\nConfigure game modes in your `sys.config` — see [guides/lua-scripting.md](guides/lua-scripting.md#using-with-erlang-projects).\n\nGame-server authors writing Erlang directly should depend on the core library at\n[widgrensit/asobi](https://github.com/widgrensit/asobi) instead.\n\n## License\n\nApache-2.0. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwidgrensit%2Fasobi_lua","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwidgrensit%2Fasobi_lua","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwidgrensit%2Fasobi_lua/lists"}