
# Ronark — developer and agent guide

Ronark hosts browser games and supplies accounts, signed game identity, saves,
reviewed assets, and Multiplayer v4. This document describes the
current supported product. Use the documented SDK and multiplayer project
workflow rather than inventing additional multiplayer APIs.

## 1. Fast path

The game already exists before you start. The human creates it at
https://ronark.com (Studio -> New game): they name it, reserve its web
address, and pay for its plan there. That flow ends by handing them ONE
command, which they paste to you:

```bash
curl -fsSL https://ronark.com/cli/ronark.mjs -o ronark.mjs && node ronark.mjs connect <slug> <key>
```

Run it verbatim in the project folder before spending time on the game. It
authenticates, writes a ronark.json that matches the registered game, records
the platform in the project's AGENTS.md (don't add a duplicate note), and
prints the game's plan and your next steps. Then:

```bash
node ronark.mjs deploy --promote
node ronark.mjs publish
```

`login <key>` and `init <slug>` exist separately when you need the pieces.

The connect command carries no game description. What to build arrives as
ordinary conversation from your human, before or after you connect — ask if
you don't have it yet.

With no key, stop and ask your human for the block from
Studio -> your game -> Connect AI. `ronark login` takes a key argument and has
no browser flow, so there is nothing to bootstrap yourself: do not create an
account, a studio, or a game on their behalf.

Environment overrides:

- `RONARK_API_KEY`: bearer API key, preferred for CI.
- `RONARK_API_URL`: API origin override.

Useful commands:

- `ronark deploy [dir] [--promote]`
- `ronark promote <build_id> [--channel live]`
- `ronark rollback [--channel live]`
- `ronark history [--channel live]`
- `ronark dev-token [--sub id] [--name name]`
- `ronark logs`
- `ronark plan` (bare = show the current plan; naming a tier CHANGES the
  subscription — never name one just to check state)
- `ronark whoami`

Published keeps a static game live. Starter and Pro add Multiplayer v4 CCU;
room count is not a plan quota. One game has one subscription; changing tiers
updates it.

`ACTIVATION_REQUIRED` (upload) and `FEE_REQUIRED` (publish) both mean the game
has no plan. This is the one situation that needs the human: they pick a plan
in Studio, then you re-run the command. Do not block waiting on them.

## 2. ronark.json

The manifest lives at the uploaded bundle root. Fields that are present remain
owned by the repository; omitted store metadata remains owned by Studio.

```json
{
  "$schema": "https://ronark.com/schemas/ronark.v1.json",
  "slug": "my-game",
  "title": "My Game",
  "entry": "index.html",
  "engine": "three",
  "cross_origin_isolation": false,
  "orientation": "landscape",
  "maturity": "everyone",
  "pricing": { "type": "free" },
  "skus": [],
  "sitelock": { "frame_ancestors": [] },
  "multiplayer": {
    "version": 4,
    "default_profile": "default",
    "profiles": {
      "default": {},
      "npcs": {
        "server": "src/room-server.ts",
        "server_required": true,
        "server_tick_ms": 50
      }
    }
  }
}
```

Omit `multiplayer` for a non-multiplayer game. Relay profiles need no artifact.
The CLI bundles each declared server entrypoint to private, immutable ESM; its
source is never part of the public game build.

Each facet invocation has a Cloudflare-enforced 10ms CPU budget, eight
subrequests, and no outbound networking. Ronark adds a two-second wall
watchdog so unresolved asynchronous hooks cannot hold a room indefinitely.
Required facet failures close the room; optional failures disable that facet
while the relay remains available.

These limits apply per invocation; they are not an aggregate spend ceiling or
a hostile-code compartment. Facets remain a trusted, explicitly allowlisted
beta until cumulative usage metering and background-task containment ship.

Build limits: 100 MB compressed, 500 MB uncompressed, 10,000 files. Do not
include symlinks, nested archives, secrets, `.git`, or `node_modules`.

## 3. Game SDK

Hosted SDK entry points:

- `https://ronark.com/sdk/v4.js`
- `https://ronark.com/sdk/v4.mjs`
- `https://ronark.com/sdk/v4.d.ts`

```js
const ronark = await Ronark.init();

ronark.user; // stable per-game sub, display name, or null outside Ronark
const save = await ronark.storage.get();
await ronark.storage.set({ level: 3 });
```

`ronark.getToken()` returns an ES256 game JWT. Verify it with
`https://ronark.com/.well-known/ronark-jwks.json` and check issuer, expiry, and
audience, or call `POST /v1/sdk/verify`. Never trust a client-supplied player id
instead of the signed `sub`.

Games run on their own origin in a sandboxed iframe. They may use fetch,
WebSockets, IndexedDB/localStorage, pointer lock, fullscreen, gamepad, and
optional cross-origin isolation. Camera, microphone, modal browser dialogs,
and arbitrary popups are not part of the game sandbox contract.

## 4. Multiplayer SDK V4

V4 is a reliable ordered relay by default. Rooms expose master-client election,
transient messages, shallow revisioned room/player properties, and replicated
entities. A build profile may layer managed Durable Object facet hooks onto the
same room. Relay traffic and selective server authority therefore coexist.

Use `createRoom`, `joinRoom`, `joinOrCreateRoom`, or `matchRoom`. Send to
`all`, `others`, `master`, selected players, or `server`. Replies are normal
messages linked by `replyTo`; there is no PUN-style object RPC or buffered RPC
history. Late joiners and reconnects receive current properties/entities.

Only the facet creates server-owned entities, making them suitable for NPCs,
trusted pickups, and hazards. Player-, master-, and server-owned entities can
coexist. Optional client interpolation clamps between authoritative samples and
never extrapolates or predicts.

The deployed build pins profile code, whether failure closes the room, and an
optional tick of 50..1000ms. Clients may select a declared profile at creation
or matchmaking but cannot change its code/tick/authority. Event-driven rooms
hibernate; ticked hooks run only while at least one player is active.

Relay-only projects need no compiler dependency. A custom server profile
requires game-project `esbuild`; keep server-only imported modules under
`.ronark/server/`, which the CLI reserves and removes from the public upload.

```js
const ronark = await Ronark.init();
const room = await ronark.multiplayer.joinOrCreateRoom("match-1", {
  playerProperties: { team: "blue" },
  create: { profile: "default", maxPlayers: 16 },
});

room.on("message", ({ type, payload }) => handle(type, payload));
room.send("emote", { id: "wave" }, { to: "others" });
room.send("buyItem", { sku: "potion" }, { to: "server" });
```

The SDK automatically resumes a reserved seat (30 seconds by default), installs
a full snapshot, then emits `reconnected`. Transient messages missed while
offline are not replayed. Room size defaults to 16 and is capped at 32. Starter
includes 100 CCU and Pro 400; reservations in reconnect grace count as CCU.

The playable relay-and-facet reference game is
https://ronark.com/g/ronark-snowball-arena.
The complete copyable text starter is
https://ronark.com/multiplayer-v4-starter.txt.

## 5. Multiplayer authentication

V4 room acquisition uses the signed game identity automatically. Game code
calls `joinRoom()`/`joinOrCreateRoom()` and does not handle the short one-time
WebSocket ticket or resume credential itself.

## 6. Saves, data, and leaderboards

Client cloud saves are available through `ronark.storage`. Leaderboards and
authoritative player data are read-only from game clients; trusted writes use
your own backend with an S2S key. V4 facet hooks deliberately receive no
database binding or outbound network capability in the initial beta. Treat
values as bounded JSON, use salted game `sub` values as player keys, and keep
durable economic actions idempotent.

## 7. World assets

Ronark-owned games may query reviewed world assets with
`ronark.assets.search()` and resolve approved runtime URLs with
`ronark.assets.getMany()`. Agent/tool adapters should receive only
`ronark.assets.forLevelDesign()`, which exposes metadata and placement/collision
hints but not raw asset bytes or signed runtime URLs.

## 8. CI

Set `RONARK_API_KEY`, download the single-file CLI, run the project's build and
tests, then run `ronark deploy --promote`. Treat any failed command as a failed
CI run.

Useful URLs:

- Store: `https://ronark.com/g/{slug}`
- Live game: `https://{slug}.ronarkusercontent.com/`
- Human docs: `https://ronark.com/docs`
- Agent guide: `https://ronark.com/llms-full.txt`
- JWKS: `https://ronark.com/.well-known/ronark-jwks.json`
