# Okona
> Okona is a curated catalog of phone-controlled multiplayer games, played in the Okona app on a shared screen. A developer (or an AI coding assistant) builds an HTML5 or Unity WebGL game, tests it on real phones in a private sandbox, and submits it for review; Okona approves it into the catalog or sends it back with what to change. There are no public game links: games play only inside Okona. Up to six players scan a code on the screen and their phones become gamepads: the Okona app shows the code and keeps phones paired from game to game, so players are usually seated before a game loads. Developer accounts are free, by invitation or request.
## Three ways to build
- HTML5, any engine: a folder with `index.html` at its root plus one script tag, `` (always the absolute URL). Start with `npm create okona-game
` — a lobby, a join code, six seats and a `game.js` with start/update/draw hooks; no build step and no `package.json`; open `index.html` in a browser and the keyboard is P1.
- Unity: import OkonaPad.unitypackage (https://okonaonline.com/developers/OkonaPad.unitypackage); phones arrive as standard Input System `Gamepad` devices. Unity 6, Input System 1.17+, WebGL with Compression Format = Brotli.
- With an AI coding assistant: the skill + the docs MCP server + the CLI below. The assistant scaffolds, tests locally, pushes to the sandbox, and submits for review only when the human says so.
## For AI coding assistants
- Skill (Agent Skills format): https://github.com/earthcrosser/okona-game-skill — `git clone` it into your agent's skills directory (Claude Code: `.claude/skills/okona-game`), or unzip https://okonaonline.com/developers/okona-skill.zip (root folder `okona-game/`). The SDK contract, TV/phone design rules, the submit workflow and a complete example game in one place.
- Live documentation over MCP (Streamable HTTP, no auth): https://okonaonline.com/mcp — tools `list_doc_sections`, `read_doc_section`, `search_docs`. Claude Code: `claude mcp add --transport http okona-docs https://okonaonline.com/mcp`.
- Starter: `npm create okona-game ` (Node 18.17+).
- CLI: npm package `okona-cli`, command `okona` — `npx okona-cli login` (prints a URL + 8-char code; a person signed in to the developer portal approves it) → `npx okona-cli create --title … --description … --runtime html5 [--controller basic|full|xl]` (or `npx okona-cli controller full` — the phone pad's layout: the game picks the controls its phones show; Full if it reads sticks or triggers) → `npx okona-cli check ` → `npx okona-cli push --game --icon icon.png --sandbox` (real phones in your private sandbox) → `… --publish` (= submit for review: Okona approves it into the catalog or sends it back with a reason). Everything the portal's editor sets is also a command: `npx okona-cli update --title … --description … --genre … --keywords "a, b" --youtube URL --players 2-6 --play-time under-5 --icon icon.png --screenshots [--clear-screenshots] [--publish]` (the screenshot list is declarative — it replaces what is there, in that order; up to six) and `npx okona-cli game ` reads the record back. An `okona.json` next to the build (`game`, `title`, `description`, `genre`, `keywords`, `youtubeUrl`, `controller`, `playersMin`, `playersMax`, `playTime`, `icon`, `screenshots`, `build`; the starter writes one) lets `okona create` fill the record and `okona push .` sync fields + icon + screenshots + build in one command. `--json` on every command; `OKONA_API_KEY` for unattended use. (CLI versions before 0.4.0 still say "Published"; the server submits for review either way.)
- Local testing: opening `index.html` gives keyboard + USB pads. The optional dev harness (https://okonaonline.com/developers/okona-harness.zip, Python 3.7+) runs the real Okona shell with scripted phone players and a performance grade; real phones need the sandbox.
## Docs (one page, grouped by path)
- Start here — introduction and choose your path: https://okonaonline.com/developers/docs.html#introduction
- Set up your development environment: https://okonaonline.com/developers/docs.html#setup
- HTML5 quick start: https://okonaonline.com/developers/docs.html#html5
- JavaScript SDK reference: https://okonaonline.com/developers/docs.html#js-sdk
- Unity requirements and quick start (OkonaPad SDK): https://okonaonline.com/developers/docs.html#requirements · https://okonaonline.com/developers/docs.html#quickstart
- Players joining, leaving, identity on the phone (Unity; the model applies to HTML5): https://okonaonline.com/developers/docs.html#players
- Phone pairing in a Unity game: https://okonaonline.com/developers/docs.html#in-game-pairing
- Build with an AI coding assistant: https://okonaonline.com/developers/docs.html#ai-assistants
- Designing for the TV and the phone: https://okonaonline.com/developers/docs.html#design
- Testing (dev harness + sandbox): https://okonaonline.com/developers/docs.html#testing
- Submit to the Okona catalog (review, Build tab, Controller tab, updating): https://okonaonline.com/developers/docs.html#publishing
- Publish API and CLI: https://okonaonline.com/developers/docs.html#publish-api
- Troubleshooting: https://okonaonline.com/developers/docs.html#troubleshooting
## The SDK in one paragraph
`` defines `Okona`. `Okona.pads()` returns six pad objects (call it exactly once per frame and keep the array — a second call, or `Okona.pad(i)`, resets `justPressed`; `rumble` and `setIdentity` take a plain seat index instead): `connected`, `parked` (controller away, seat held), `kind`, `buttons.{a,b,x,y,lb,rb,lt,rt,select,start,l3,r3,up,down,left,right,home}`, `justPressed(name)`, `axes.{lx,ly,rx,ry}` (−1..1, +Y down), `triggers.{lt,rt}`. Events: `Okona.on('join'|'leave'|'park'|'resume'|'pairing'|'ready'|'menu', fn)` (`menu`: the Okona app's menu opened/closed over the game; pads already read neutral, pause if you like); `Okona.mode` is `'live'`, `'sandbox'` or `'standalone'` once `ready` has fired (`'hosted'` before that). Start and Home never reach a game in the Okona app: Start opens the Okona menu (Resume, Controllers with the join code, Back to games; the TV remote's Back does too) and Home goes to the TV's home screen. Begin a round on A, never "Press Start". When a game starts with nobody connected the app shows the join code over it until a player starts; the game gets the `menu` event whenever the menu opens or closes. A game can draw the join code too, with `Okona.drawQr(canvas)` in its lobby: optional, it lets people join mid-game without the menu covering the game, and it is the only way a phone joins in the sandbox (redraw on every `pairing` event; it paints a placeholder when no code exists). `Okona.players.setIdentity(pad, {name, icon, accent})` puts a name/emoji/colour on the player's phone. `Okona.rumble(pad, low, high)`; `Okona.track(name, props)`. Opened outside Okona the SDK falls back to the keyboard (P1) and USB gamepads. Inside Okona `navigator.getGamepads()` is empty on purpose; dialogs and popups are blocked; builds are ≤50 MB and ≤500 files with no dotfiles.
## Links
- Developer portal: https://okonaonline.com/developers/
- Support: support@okonaonline.com