@genex-ai/cli-demo 0.44.0 → 0.45.0-dev.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -69,9 +69,12 @@ built.
69
69
  **published** so it appears in the public gallery. The deploy and the gallery
70
70
  flag are independent; `--no-push` flips the flag only.
71
71
 
72
- Defaults: API `https://demo-api.glotech.world`, auth site
73
- `https://demo-web.glotech.world` — override with `--api-url` / `--auth-url` (or
74
- `GENEX_API_URL` / `GENEX_AUTH_URL`) for local dev.
72
+ Defaults: API `https://api.genex.games`, auth site
73
+ `https://genex.games` — override with `--api-url` / `--auth-url` (or
74
+ `GENEX_API_URL` / `GENEX_AUTH_URL`) for local dev. Those are the `@latest`
75
+ (prod) channel's defaults; the `@dev` dist-tag ships the same CLI built for the
76
+ dev stand (`api-dev` / `dev` / `relay-dev` `.genex.games`) — the channel is
77
+ baked at build time via `GENEX_CLI_CHANNEL` (see `src/config.ts`).
75
78
 
76
79
  ## Generating assets
77
80
 
@@ -135,7 +138,7 @@ Options
135
138
  --agents <list> Agents to install for: claude,codex,cursor (default: auto-detect)
136
139
  --dir <path> Single destination workspace (overrides --agents)
137
140
  --env <path> Token env file (default: ~/.genex/env)
138
- --auth-url <url> Override the auth site (default: https://demo-web.glotech.world)
141
+ --auth-url <url> Override the auth site (default: https://genex.games)
139
142
  --no-auth Only scaffold templates; skip authorization
140
143
  --force Overwrite existing files (default: never overwrite)
141
144
  --timeout <seconds> How long to wait for the auth redirect (default: 300)
@@ -166,7 +169,7 @@ genex init --auth-url http://localhost:3000
166
169
 
167
170
  The auth site URL is a single configurable value:
168
171
 
169
- - **Default:** `https://demo-web.glotech.world` (the `DEFAULT_AUTH_URL` constant
172
+ - **Default:** `https://genex.games` (the `DEFAULT_AUTH_URL` constant
170
173
  in [`src/config.ts`](src/config.ts)).
171
174
  - **Override at runtime:** set `GENEX_AUTH_URL`, or pass `--auth-url`.
172
175
 
@@ -174,6 +177,11 @@ The auth site URL is a single configurable value:
174
177
  GENEX_AUTH_URL=https://staging.genex.dev genex init
175
178
  ```
176
179
 
180
+ The token env file path is configurable the same way: `--env <path>` per
181
+ command, or `GENEX_ENV_FILE=<path>` for a whole session (an explicit `--env`
182
+ still wins). Useful for running as a second account — a curator or a test
183
+ runner — without touching the default `~/.genex/env`.
184
+
177
185
  To control which browser is launched, set `GENEX_BROWSER` (or the conventional
178
186
  `BROWSER`) to an opener command. It's parsed like a shell command, so arguments
179
187
  work and paths containing spaces should be quoted:
package/dist/index.js CHANGED
@@ -8,9 +8,10 @@ import fs from "fs";
8
8
  import os from "os";
9
9
  import path from "path";
10
10
  import { fileURLToPath } from "url";
11
- var DEFAULT_AUTH_URL = "https://demo-web.glotech.world";
12
- var DEFAULT_API_URL = "https://demo-api.glotech.world";
13
- var DEFAULT_COLYSEUS_URL = "wss://demo-colyseus.glotech.world";
11
+ var RAW_CHANNEL = "dev";
12
+ var CLI_CHANNEL = RAW_CHANNEL === "dev" ? "dev" : "latest";
13
+ var DEFAULT_AUTH_URL = CLI_CHANNEL === "dev" ? "https://dev.genex.games" : "https://genex.games";
14
+ var DEFAULT_API_URL = CLI_CHANNEL === "dev" ? "https://api-dev.genex.games" : "https://api.genex.games";
14
15
  var DEFAULT_ANIMS_BASE = "https://cdn.genex.technology/anims/ual1/v1/";
15
16
  var ANIMS_BASE_ENV = "GENEX_ANIMS_BASE";
16
17
  function getAnimsBase(override) {
@@ -23,7 +24,7 @@ function getAnimsCacheDir() {
23
24
  var ENV_TOKEN_KEY = "GENEX_TOKEN";
24
25
  var AUTH_URL_ENV = "GENEX_AUTH_URL";
25
26
  var API_URL_ENV = "GENEX_API_URL";
26
- var COLYSEUS_URL_ENV = "GENEX_COLYSEUS_URL";
27
+ var ENV_FILE_ENV = "GENEX_ENV_FILE";
27
28
  function getAuthUrl(override) {
28
29
  const raw = override || process.env[AUTH_URL_ENV] || DEFAULT_AUTH_URL;
29
30
  return raw.replace(/\/+$/, "");
@@ -32,15 +33,13 @@ function getApiUrl(override) {
32
33
  const raw = override || process.env[API_URL_ENV] || DEFAULT_API_URL;
33
34
  return raw.replace(/\/+$/, "");
34
35
  }
35
- function getColyseusUrl(override) {
36
- const raw = override || process.env[COLYSEUS_URL_ENV] || DEFAULT_COLYSEUS_URL;
37
- return raw.replace(/\/+$/, "");
38
- }
39
36
  function getGenexDir() {
40
37
  return path.join(os.homedir(), ".genex");
41
38
  }
42
39
  function getGenexEnvPath(override) {
43
40
  if (override) return path.resolve(override);
41
+ const fromEnv = process.env[ENV_FILE_ENV];
42
+ if (fromEnv) return path.resolve(fromEnv);
44
43
  return path.join(getGenexDir(), "env");
45
44
  }
46
45
  function getTemplatesDir() {
@@ -162,7 +161,7 @@ if (sentryEnabled) {
162
161
  // release aligns with the AG-757 `x-genex-cli-version` telemetry stream so
163
162
  // the two correlate; environment is prod unless pointed at a non-default API.
164
163
  release: `@genex-ai/cli-demo@${getCliVersion()}`,
165
- environment: getApiUrl() === DEFAULT_API_URL ? "production" : "development",
164
+ environment: CLI_CHANNEL === "dev" ? "development" : getApiUrl() === DEFAULT_API_URL ? "production" : "development",
166
165
  // A short-lived CLI has no meaningful tracing workload — errors only.
167
166
  tracesSampleRate: 0,
168
167
  // No IP / user auto-collection (opposite of the server apps' `userInfo: true`).
@@ -385,6 +384,7 @@ async function reportUpdateNudges(check, log, cwd = process.cwd()) {
385
384
  const lines = [];
386
385
  let whatsNew = null;
387
386
  for (const pkg of PUBLISHED_PACKAGES) {
387
+ if (pkg.name === "@genex-ai/cli-demo" && CLI_CHANNEL === "dev") continue;
388
388
  const latest = cache.latest[pkg.name];
389
389
  if (!latest) continue;
390
390
  const installed = pkg.name === "@genex-ai/cli-demo" ? getCliVersion() : await installedPackageVersion(cwd, pkg.name);
@@ -670,7 +670,7 @@ var c = {
670
670
  // src/lib/api.ts
671
671
  var CLI_VERSION_HEADER = "x-genex-cli-version";
672
672
  function formatUpdateRequired(body) {
673
- const action = body.action ?? "npm i -D @genex-ai/cli-demo@latest";
673
+ const action = body.action ?? `npm i -D @genex-ai/cli-demo@${CLI_CHANNEL}`;
674
674
  const message = body.message ?? `Genex CLI ${body.clientVersion ?? getCliVersion()} is below the minimum supported version${body.minVersion ? ` ${body.minVersion}` : ""}.`;
675
675
  return [`${c.red("\u2717")} ${message}`, ` Update now \u2014 run: ${action} (then re-run this command)`];
676
676
  }
@@ -766,7 +766,7 @@ async function fetchSignedInEmail(apiUrl, token) {
766
766
  // src/lib/project.ts
767
767
  import crypto2 from "crypto";
768
768
  async function createDraftProject(opts) {
769
- const { apiUrl, token, colyseusUrl, dashboardUrl, log } = opts;
769
+ const { apiUrl, token, dashboardUrl, log } = opts;
770
770
  log.step("Creating your project\u2026");
771
771
  const names = [opts.name, `${opts.name}-${randomSuffix()}`];
772
772
  for (let i = 0; i < names.length; i++) {
@@ -817,7 +817,6 @@ async function createDraftProject(opts) {
817
817
  slug: project.slug,
818
818
  cloneUrl: project.cloneUrl,
819
819
  apiUrl,
820
- colyseusUrl,
821
820
  playUrl: project.playUrl ?? void 0,
822
821
  status: "draft",
823
822
  // Derived client-side from the auth/web origin the CLI just authorized
@@ -946,7 +945,7 @@ async function writeUserToken(token, envPath) {
946
945
  async function readUserToken(envPath) {
947
946
  const fromGenex = await readTokenFromFile(getGenexEnvPath(envPath));
948
947
  if (fromGenex) return fromGenex;
949
- if (!envPath) {
948
+ if (!envPath && !process.env[ENV_FILE_ENV]) {
950
949
  return readTokenFromFile(path6.join(process.cwd(), ".env"));
951
950
  }
952
951
  return null;
@@ -1000,7 +999,6 @@ function renderGenexConfig() {
1000
999
  export const GENEX = {
1001
1000
  slug: import.meta.env.VITE_GENEX_SLUG as string,
1002
1001
  apiUrl: (import.meta.env.VITE_GENEX_API_URL as string | undefined) ?? "${DEFAULT_API_URL}",
1003
- colyseusUrl: (import.meta.env.VITE_GENEX_COLYSEUS_URL as string | undefined) ?? "${DEFAULT_COLYSEUS_URL}",
1004
1002
  dashboardOrigins: ((import.meta.env.VITE_GENEX_DASHBOARD_ORIGINS as string | undefined) ?? "${DEFAULT_DASHBOARD_ORIGIN}").split(","),
1005
1003
  } as const;
1006
1004
  `;
@@ -1014,9 +1012,6 @@ function renderDevOverrides(meta) {
1014
1012
  const dashboardOrigins = meta.dashboardOrigins?.join(",") ?? DEFAULT_DASHBOARD_ORIGIN;
1015
1013
  const overrides = [];
1016
1014
  if (meta.apiUrl !== DEFAULT_API_URL) overrides.push(`VITE_GENEX_API_URL=${meta.apiUrl}`);
1017
- if (meta.colyseusUrl !== DEFAULT_COLYSEUS_URL) {
1018
- overrides.push(`VITE_GENEX_COLYSEUS_URL=${meta.colyseusUrl}`);
1019
- }
1020
1015
  if (dashboardOrigins !== DEFAULT_DASHBOARD_ORIGIN) {
1021
1016
  overrides.push(`VITE_GENEX_DASHBOARD_ORIGINS=${dashboardOrigins}`);
1022
1017
  }
@@ -1121,7 +1116,6 @@ async function runInit(opts) {
1121
1116
  }
1122
1117
  await writeGitignore(process.cwd(), log);
1123
1118
  const apiUrl = getApiUrl(opts.apiUrl);
1124
- const colyseusUrl = getColyseusUrl(opts.colyseusUrl);
1125
1119
  const signedInEmail = await fetchSignedInEmail(apiUrl, token);
1126
1120
  if (signedInEmail) log.plain(` signed in as ${c.cyan(signedInEmail)}`);
1127
1121
  const projectName = opts.name?.trim() || path8.basename(process.cwd());
@@ -1132,7 +1126,6 @@ async function runInit(opts) {
1132
1126
  repoUrl: opts.repo?.trim() || void 0,
1133
1127
  private: opts.private,
1134
1128
  remixedFromSlug: opts.remixedFrom?.trim() || void 0,
1135
- colyseusUrl,
1136
1129
  dashboardUrl: authBaseUrl,
1137
1130
  log
1138
1131
  });
@@ -1196,7 +1189,6 @@ async function runLink(opts) {
1196
1189
  slug: project.slug,
1197
1190
  cloneUrl: project.cloneUrl ?? "",
1198
1191
  apiUrl,
1199
- colyseusUrl: getColyseusUrl(opts.colyseusUrl),
1200
1192
  playUrl: project.playUrl ?? void 0,
1201
1193
  status: project.status ?? "draft",
1202
1194
  dashboardOrigins: [new URL(authBaseUrl).origin]
@@ -2743,7 +2735,6 @@ ${c.bold("Options for `init`")}
2743
2735
  --env <path> Token env file (default: ~/.genex/env).
2744
2736
  --auth-url <url> Override the auth site (default: ${DEFAULT_AUTH_URL}).
2745
2737
  --api-url <url> Override the API base URL (default: ${DEFAULT_API_URL}).
2746
- --colyseus-url <url> Override the multiplayer URL (stored in project metadata).
2747
2738
  --no-auth Only scaffold templates; skip authorization.
2748
2739
  --force Overwrite existing files (default: never overwrite).
2749
2740
  --timeout <seconds> How long to wait for the auth redirect (default: 300).
@@ -2754,7 +2745,6 @@ ${c.bold("Options for `link`")}
2754
2745
  --env <path> Token env file (default: ~/.genex/env).
2755
2746
  --auth-url <url> Override the auth site (used only if sign-in is needed).
2756
2747
  --api-url <url> Override the API base URL.
2757
- --colyseus-url <url> Override the multiplayer URL (stored in project metadata).
2758
2748
  --timeout <seconds> How long to wait for the auth redirect (default: 300).
2759
2749
 
2760
2750
  ${c.bold("Options for `preview` / `publish`")}
@@ -2788,7 +2778,6 @@ ${c.bold("Global")}
2788
2778
  ${c.bold("Environment")}
2789
2779
  GENEX_AUTH_URL Overrides the default auth site URL.
2790
2780
  GENEX_API_URL Overrides the default API base URL.
2791
- GENEX_COLYSEUS_URL Overrides the default multiplayer URL.
2792
2781
  GENEX_BROWSER Command used to open the browser (falls back to BROWSER).
2793
2782
  GENEX_TELEMETRY Set to 0 to disable anonymous crash reporting (Sentry).
2794
2783
  DO_NOT_TRACK Standard opt-out; any value disables crash reporting.
@@ -2826,7 +2815,6 @@ function parseArgs(argv) {
2826
2815
  "--env",
2827
2816
  "--auth-url",
2828
2817
  "--api-url",
2829
- "--colyseus-url",
2830
2818
  "--agents",
2831
2819
  "--name",
2832
2820
  "--repo",
@@ -2941,9 +2929,6 @@ function applyValueFlag(options, flag, value) {
2941
2929
  case "--api-url":
2942
2930
  options.apiUrl = value;
2943
2931
  break;
2944
- case "--colyseus-url":
2945
- options.colyseusUrl = value;
2946
- break;
2947
2932
  case "--agents":
2948
2933
  options.agents = value.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
2949
2934
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/cli-demo",
3
- "version": "0.44.0",
3
+ "version": "0.45.0-dev.61",
4
4
  "description": "Set up your ~/.claude workspace, authorize, create a game project, generate AI assets, and publish (genex CLI).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -172,7 +172,7 @@ See `$genex-threejs-multiplayer` for the `shared` channel rules and the room API
172
172
 
173
173
  ## Troubleshooting
174
174
 
175
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
175
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
176
176
  - **"Prompt rejected"** — the provider's content-safety filter blocked the prompt.
177
177
  This is non-retryable; retrying the same wording fails again. Rewrite the prompt.
178
178
  - **Decal is an opaque rectangle** — the image has no alpha. Regenerate with
@@ -107,7 +107,7 @@ scene is a ghost: players and objects pass straight through it.
107
107
 
108
108
  ## Troubleshooting
109
109
 
110
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
110
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
111
111
  - **"Out of credits" (`insufficient_credits`)** — the account has no credits left for
112
112
  this model generation. Tell the user the facts the CLI printed: their balance, this
113
113
  generation's cost, and when their credits refill. Then offer to continue the build
@@ -72,7 +72,7 @@ Reuse one loaded `buffer` across many plays; create a fresh `Audio`/`PositionalA
72
72
 
73
73
  ## Troubleshooting
74
74
 
75
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
75
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
76
76
  - **"Out of credits" (`insufficient_credits`)** — the account has no credits left for
77
77
  this sound generation. Tell the user the facts the CLI printed: their balance, this
78
78
  generation's cost, and when their credits refill. Then offer to continue the build
@@ -76,7 +76,7 @@ scene.background = texture; // keep the raw texture for the visible sky
76
76
 
77
77
  ## Troubleshooting
78
78
 
79
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
79
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
80
80
  - **"Out of credits" (`insufficient_credits`)** — the account has no credits left for
81
81
  this skybox generation. Tell the user the facts the CLI printed: their balance, this
82
82
  generation's cost, and when their credits refill. Then offer to continue the build
@@ -81,7 +81,7 @@ scene.add(ground);
81
81
 
82
82
  ## Troubleshooting
83
83
 
84
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
84
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
85
85
  - **"Out of credits" (`insufficient_credits`)** — the account has no credits left for
86
86
  this texture generation. Tell the user the facts the CLI printed: their balance,
87
87
  this generation's cost, and when their credits refill. Then offer to continue the
@@ -138,7 +138,7 @@ See `$genex-threejs-multiplayer` for the `shared` channel rules and the room API
138
138
 
139
139
  ## Troubleshooting
140
140
 
141
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
141
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
142
142
  - **"Prompt rejected"** — the provider's content-safety filter blocked the prompt.
143
143
  This is non-retryable; retrying the same wording fails again. Rewrite the prompt.
144
144
  - **Nothing plays / black surface** — the first `video.play()` must run inside a user
@@ -43,7 +43,7 @@ Add `--json` for machine-readable output.
43
43
  **As a NEW game (start from the whole project):**
44
44
 
45
45
  1. `git clone <clone URL from the output> <name>` — pick a short one-word name.
46
- 2. `cd <name>`, then `npx @genex-ai/cli-demo@latest init <name>` — never use
46
+ 2. `cd <name>`, then `npx @genex-ai/cli-demo@dev init <name>` — never use
47
47
  `--force`. This creates your own project; the original is untouched.
48
48
  3. `npm install`, keep `base: './'` in `vite.config`, then build your changes
49
49
  and ship with `npx genex preview`.
@@ -122,7 +122,7 @@ and re-link the clone to the same live game:
122
122
  ```bash
123
123
  git clone <the game's repo url> my-game && cd my-game
124
124
  npm install
125
- npx @genex-ai/cli-demo@latest link <slug> # slug = the name in the play URL
125
+ npx @genex-ai/cli-demo@dev link <slug> # slug = the name in the play URL
126
126
  ```
127
127
 
128
128
  `link` never creates a project: it signs in if needed (the browser opens once)
@@ -145,7 +145,7 @@ Safe to run any time — genex-owned skills are refreshed to the latest version,
145
145
  and your own files are never touched:
146
146
 
147
147
  ```bash
148
- npx @genex-ai/cli-demo@latest init
148
+ npx @genex-ai/cli-demo@dev init
149
149
  ```
150
150
 
151
151
  Use `--force` only if you intentionally want your own existing files overwritten
@@ -34,17 +34,17 @@ example, the shared-object/ball code, rotation, and host usage. Read
34
34
  ## Install
35
35
 
36
36
  ```bash
37
- npm i @genex-ai/multiplayer@^0.9.0
37
+ npm i @genex-ai/multiplayer@^0.10.0
38
38
  ```
39
39
 
40
- > Pin `@^0.9.0` (not a bare `npm i`): confirmed object controls, discontinuity snaps, host-tick
41
- > teardown, and reconnect rebasing landed in 0.9. An older resolve does not have
42
- > `room.objects.claimConfirmed` or `room.me.snap`.
40
+ > Pin `@^0.10.0` (not a bare `npm i`): regional relay selection (`getColyseusUrls()` + `urls`)
41
+ > landed in 0.10; confirmed object controls, snaps, host-tick teardown, and reconnect rebasing
42
+ > in 0.9. An older resolve does not have those.
43
43
 
44
- This skill targets `@genex-ai/multiplayer` **≥ 0.9.0** (`objects`/`host` since 0.4;
44
+ This skill targets `@genex-ai/multiplayer` **≥ 0.10.0** (`objects`/`host` since 0.4;
45
45
  `matchmake()` since 0.5; private lobbies since 0.7; auto-reconnect + `inputs`/`onHostTick`
46
46
  since 0.8; soft ownership handoff since 0.8.4; confirmed controls, snap epochs, and host-tick
47
- lifecycle guarantees since 0.9).
47
+ lifecycle guarantees since 0.9; regional relay selection via `getColyseusUrls()` since 0.10).
48
48
 
49
49
  ## Trust model (say it plainly in your game's copy)
50
50
 
@@ -68,7 +68,7 @@ HUD from `mm.matchmaking` (its `status`, `queue.position`, `players`/`opponents`
68
68
  // requeue) over a session, and embed tokens rotate (~10 min). A function is read fresh each (re)join;
69
69
  // a static object goes stale and gets rejected mid-session.
70
70
  await waitForPlayer(); // identity gate first (guest OR signed-in) — same rule as connect()
71
- const mm = await matchmake<MyState>({ url, room: slug, auth: () => getColyseusAuth() });
71
+ const mm = await matchmake<MyState>({ urls, room: slug, auth: () => getColyseusAuth() });
72
72
  mm.on('matched', () => {/* session is live — start the game */});
73
73
  // each frame: if (mm.session) renderGame(mm.session); else renderSearchingHud(mm.matchmaking);
74
74
  mm.on('matchEnded', ({ winnerId, scores, draw }) => {/* result screen */});
@@ -182,10 +182,10 @@ and friends join it; the lobby is persistent (rounds replay, nobody is evicted):
182
182
 
183
183
  ```ts
184
184
  import { createPrivate, joinPrivate } from "@genex-ai/multiplayer";
185
- const lobby = await createPrivate<MyState>({ url, room: slug, auth: () => getColyseusAuth() }); // live NOW
185
+ const lobby = await createPrivate<MyState>({ urls, room: slug, auth: () => getColyseusAuth() }); // live NOW
186
186
  showCode(lobby.code); // share this
187
187
  // a friend, elsewhere:
188
- const lobby = await joinPrivate<MyState>(code, { url, room: slug, auth: () => getColyseusAuth() });
188
+ const lobby = await joinPrivate<MyState>(code, { urls, room: slug, auth: () => getColyseusAuth() });
189
189
  // same handle API as matchmake(): lobby.session, lobby.matchmaking, eliminated()/score()/finish(), cancel()
190
190
  ```
191
191
 
@@ -202,13 +202,13 @@ pending for guests and would keep them out of multiplayer forever:
202
202
 
203
203
  ```ts
204
204
  import { connect } from "@genex-ai/multiplayer";
205
- import { waitForPlayer, getColyseusAuth } from "@genex-ai/embed-sdk";
205
+ import { waitForPlayer, getColyseusAuth, getColyseusUrls } from "@genex-ai/embed-sdk";
206
206
 
207
207
  type State = { x: number; z: number; q: number[] }; // YOUR per-player state (rotation as quaternion)
208
208
 
209
209
  const { user } = await waitForPlayer(); // player gate (guest OR signed-in) — rejects only if blocked
210
210
  const room = await connect<State>({
211
- url: GENEX.colyseusUrl, // e.g. "wss://demo-colyseus.glotech.world" see config wiring below
211
+ urls: getColyseusUrls(), // regional relays for this session (server-owned); SDK joins the fastest
212
212
  room: GENEX.slug, // the project slug — everyone with this id shares a room
213
213
  name: user.name, // display name — the server prefers the verified identity's name
214
214
  auth: getColyseusAuth()!, // REQUIRED — tokenless joins are rejected. Read fresh each connect; NEVER log it.
@@ -483,7 +483,7 @@ it; never hardcode a URL or edit the file:
483
483
 
484
484
  ```ts
485
485
  import { GENEX } from "./genex.config";
486
- // GENEX.slug / GENEX.colyseusUrl / GENEX.apiUrl / GENEX.dashboardOrigins
486
+ // GENEX.slug / GENEX.apiUrl / GENEX.dashboardOrigins
487
487
  ```
488
488
 
489
489
  See the `genex-threejs-embed-auth` skill's "Config wiring" section for the full
@@ -531,7 +531,7 @@ host-driven saving works as long as ANY account is in the room.
531
531
 
532
532
  ## Checklist
533
533
 
534
- - [ ] `npm i @genex-ai/multiplayer@^0.9.0` (confirmed controls, snap epochs, reconnect-safe host ticks); config wired into the build.
534
+ - [ ] `npm i @genex-ai/multiplayer@^0.10.0` (confirmed controls, snap epochs, reconnect-safe host ticks); config wired into the build.
535
535
  - [ ] `reconnecting`/`reconnected`/`disconnect` render an overlay (don't tear the scene down).
536
536
  - [ ] Numbers rounded (~2 decimals) before `me.set`/`objects.set`.
537
537
  - [ ] Pushable/ownable objects (ball, box, prop) use claim-on-touch + a Rapier proxy (the soft handoff glides the handoff); only a genuine simultaneous tug-of-war (sumo) uses the host-authoritative pattern. See host-physics.md.
@@ -27,7 +27,7 @@ type S = { x: number; z: number; q: number[]; hp: number };
27
27
 
28
28
  const { user } = await waitForPlayer(); // player gate (guest OR signed-in) — never waitForAuth()
29
29
  const room = await connect<S>({
30
- url: GENEX.colyseusUrl,
30
+ urls: getColyseusUrls(),
31
31
  room: GENEX.slug,
32
32
  name: user.name,
33
33
  auth: getColyseusAuth()!, // REQUIRED — tokenless joins are rejected. Read fresh each connect; NEVER log it.
@@ -38,7 +38,7 @@ update, so update immediately.)
38
38
  Run exactly the command the nudge printed, from the game project root:
39
39
 
40
40
  ```bash
41
- npm i -D @genex-ai/cli-demo@latest # the genex CLI (a dev dependency)
41
+ npm i -D @genex-ai/cli-demo@dev # the genex CLI (a dev dependency)
42
42
  npm i @genex-ai/embed-sdk@latest # identity/saves SDK (ships inside the game)
43
43
  npm i @genex-ai/multiplayer@latest # multiplayer SDK (only if the game uses it)
44
44
  ```