#Adding a game
Every game lives in its own directory under games/<slug>/, fully isolated from the
others: its own dependencies, its own toolchain, its own build. The only contract is
game.json.
New to the repo? Getting started gets the arcade running first. Want an AI to write the game? Build a game with AI.
#1. Scaffold
npm run new-game -- my-game --template vite # Vite + TypeScript
npm run new-game -- my-game --template vanilla # plain HTML/JS, no build step
The slug becomes the directory name and the URL: the game is served at
/games/my-game/. Lowercase letters, digits, and hyphens only.
#2. Fill in game.json
{
"$schema": "../../schema/game.schema.json", // editor autocomplete + validation
"name": "My Game",
"slug": "my-game", // must equal the directory name
"description": "Shown on the arcade landing page.",
"authors": ["Your Name"], // display names, shown on the game card
"thumbnail": "thumbnail.png", // optional, 16:9 recommended
"addedAt": "2026-06-12",
"status": "live", // "hidden" = deployed but not listed
"genre": "Action", // free text, builds the arcade's genre filter
"navBar": "expanded", // "collapsed" parks the arcade bar behind a handle
"build": {
"command": "npm install && npm run build", // run with cwd = your game dir
"outputDir": "dist" // deployed verbatim to /games/my-game/
},
"version": "1.0.0", // optional, shown on the game card
"updatedAt": "2026-06-21", // optional, shown on the game card
// Informational landing-page chips. Any of: singlePlayer, multiplayer, invites, achievements, leaderboard.
// (achievements is set for you when you ship an achievements.json; see §5.)
"features": { "singlePlayer": true, "leaderboard": true },
// Optional: named leaderboards rendered on the arcade profile (your backend writes them; see §6).
"leaderboards": [{ "id": "score", "name": "Top Score" }]
}
Rules enforced at build time:
slugmust match the directory name.- After your build command runs,
outputDirmust exist and contain anindex.html. - Every directory under
games/must have agame.json.
#3. Pick any toolchain
- Node-based (Vite, Phaser, React, whatever): declare your build in
build.command. Yourpackage.json/lockfile live inside your game dir and never conflict with other games. - Godot / Unity / other exports: export the web build into a folder (e.g.
public/), commit it, and set"command": null, "outputDir": "public". CI doesn't need your engine installed, because the export is the artifact. Two export settings do need changing from their defaults, and there's an SDK bridge per engine: shipping an engine export · Godot · Unity. - Plain HTML/JS: same as above, with no build, just committed files.
Keep your game's URLs relative (Vite template sets base: "./") so it works when
served from /games/<slug>/.
#4. Use the shared SDK (optional)
Load the SDK with one script tag. There is no npm dependency:
<script src="/sdk/v1/arcade.js"></script>
Arcade.init(); // slug auto-detected from the URL
await Arcade.leaderboard.submit(1234); // attributed to the signed-in user
const top = await Arcade.leaderboard.top(10); // [{ player, score, at }, ...]
const user = await Arcade.auth.getUser(); // { email, name, picture } | null
if (!user) Arcade.auth.login(); // shared arcade sign-in
Leaderboard calls reject with ArcadeOfflineError when the API is unreachable, so
catch and carry on.
Multiplayer? The same SDK also gives you realtime rooms + presence (Arcade.realtime),
player-to-player invites (Arcade.invites), a player typeahead (Arcade.players), and a
drop-in notifications bell (Arcade.notifications.mount).
Details: accounts · leaderboards · achievements · multiplayer.
#5. (Optional) Add achievements
Drop an achievements.json beside your game.json, worth up to 1000 GS
(Gamesight Score) spread across your achievements, then unlock them with one call:
await Arcade.achievements.unlock("first-flight"); // no-op if already earned
The popup, the chime, the player's score, and the browse page at /achievements/<slug>/
all come for free. Regenerate the API's copy with npm run gen-achievements
after editing the file. Full guide: achievements.
#6. (Optional) Give your game its own backend
Need persistent data (saves, collections, progress), or server-authoritative
multiplayer? Declare a backend block in game.json and add a server module: the arcade
provisions your DynamoDB tables and routes /api/<slug>/* to you. The same module can also
export realtimeMatch(ctx, data) to validate + apply PvP moves server-side (and write named
leaderboards). Full walkthroughs: saving game data ·
multiplayer.
#7. Test the whole arcade locally
npm run build # builds SDK + every game + landing page into dist/
npm run preview # http://localhost:8002 (auto-increments if busy), production-style routing + /api
Your game should appear on the landing page and be playable at
http://localhost:8002/games/my-game/. Sign-in works locally with no Google; see
accounts.
#8. Ship it
Open a PR against main from a game/<slug> branch. CI runs validation and a
build check with no AWS access. Anthony Kinson or Robert Syvarth reviews every
game before it goes live; merging deploys automatically. Full walkthrough:
submitting your game.
How it all works underneath: architecture and ../infra/README.md.