What you are building
Understand the destination before you build it: you are building the movement core of the Arena Shooter sample, a top-down arena where the server moves your fighter and every client sees it move.
The thing you will build
The Arena Shooter sample is a top-down co-op arena: fighters move, aim, and shoot; matchmaking fills empty slots with bots; boons drop, players vote on a modifier between rounds, and a kills leaderboard tracks who is winning. You will build only the movement core. The full sample layers shooting, bots, boons, round voting, and the leaderboard on top of exactly this.
An arena. One fighter. Every connected client sees the same arena and your fighter at the same position.
A player presses a movement key. The client does not move the fighter. It sends the input to the server as an intent, a move_x/move_y delta. The server decides where the fighter goes and broadcasts the new position. Every client redraws.
That is the whole track. Each step adds one piece and ends with a checkpoint you run to see it work. By the end you have a real backend: guests, stored state, matches, and worlds, all around this one arena.
The two pieces
1. A server bundle. A directory of Lua scripts that holds your game logic - who joins, what an input does, where the fighter ends up. You deploy this bundle; you do not run a server codebase. Asobi runs it for you.
2. A client. Your game, using an Asobi SDK (Defold, Godot, Unity, Unreal, Dart, JavaScript, or LOVE). The client draws the arena, sends inputs, and renders whatever state the server sends back.
The client never owns the truth. It sends intent; it renders state.
The one rule: server-authoritative
client input ---> server decides ---> server broadcasts ---> every client rendersThe fighter's position lives on the server. A client cannot place the fighter; it can only ask. This is what stops two players disagreeing about the game, and it is why the interesting code is in Lua, not in the client.
Two ways to deploy (chosen later)
The same bundle runs on both paths. You pick one when you deploy; the choice does not change any game logic.
Cloud - the managed platform at console.asobi.dev, deployed with asobi deploy. Your per-environment Postgres database is provisioned for you, and the guest-auth pepper is generated per environment. You write no config file; you set a few environment knobs. See the configuration guide.
Self-hosted - your own release of asobi + asobi_lua against your own Postgres. You configure it with ASOBI_* environment variables (the Docker image) or sys.config (an embedded Erlang release), and you supply your own secrets. See the self-host and configuration guides.
Every step in this track flags where Cloud and Self-hosted differ, labelled Cloud and Self-hosted. Where a step is identical - all game logic, and every SDK call except the base server URL - it is written once and says so.
Checkpoint
You do not deploy anything yet. Confirm your chosen path is reachable, so the later deploy step just works.
Cloud - log in to the platform:
asobi login
The device-code prompt should complete and report you as authenticated.
Self-hosted - pull the runtime image:
docker pull ghcr.io/widgrensit/asobi_lua:latest
The pull should finish without error. You are ready when one of these succeeds.
Next: Step 1 - Your backend bundle and folder layout
What a Lua bundle actually contains, and how to boot it locally.