@genex-ai/cli-demo 0.92.0 → 0.93.0-dev.235

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/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import fs from "fs";
8
8
  import os from "os";
9
9
  import path from "path";
10
10
  import { fileURLToPath } from "url";
11
- var RAW_CHANNEL = "latest";
11
+ var RAW_CHANNEL = "dev";
12
12
  var CLI_CHANNEL = RAW_CHANNEL === "dev" ? "dev" : "latest";
13
13
  var STANDS = {
14
14
  prod: { api: "https://api.genex.games", dashboard: "https://genex.games" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/cli-demo",
3
- "version": "0.92.0",
3
+ "version": "0.93.0-dev.235",
4
4
  "description": "Set up your project's agent workspace (.claude/.codex/.cursor in the game folder), authorize, create a game project, generate AI assets, and publish (genex CLI).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -116,7 +116,7 @@ scene.background = texture; // keep the raw texture for the visible sky
116
116
 
117
117
  ## Troubleshooting
118
118
 
119
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
119
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
120
120
  - **"Out of credits" (`insufficient_credits`)** — the account has no credits left for
121
121
  this skybox generation. Tell the user the facts the CLI printed: their balance, this
122
122
  generation's cost, and when their credits refill. Then offer to continue the build
@@ -225,7 +225,7 @@ first one is the one a screenshot of the whole arena will not show you.
225
225
 
226
226
  ## Troubleshooting
227
227
 
228
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
228
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
229
229
  - **"Out of credits" (`insufficient_credits`)** — the account has no credits left for
230
230
  this texture generation. Tell the user the facts the CLI printed: their balance,
231
231
  this generation's cost, and when their credits refill. Then offer to continue the
@@ -151,7 +151,7 @@ set belongs to `$genex-ai-hud` — both build on `npx genex image`/`video`.
151
151
 
152
152
  ## Troubleshooting
153
153
 
154
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
154
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
155
155
  - **"Prompt rejected"** — the provider's content-safety filter blocked the prompt.
156
156
  This is non-retryable; retrying the same wording fails again. Rewrite the prompt.
157
157
  - **Nothing plays / black surface** — the first `video.play()` must run inside a user
@@ -131,7 +131,7 @@ and re-link the clone to the same live game:
131
131
  ```bash
132
132
  git clone <the game's repo url> my-game && cd my-game
133
133
  npm install
134
- npx @genex-ai/cli-demo@latest link <slug> # slug = the name in the play URL
134
+ npx @genex-ai/cli-demo@dev link <slug> # slug = the name in the play URL
135
135
  ```
136
136
 
137
137
  Don't know the slug? **`npx genex list`** prints every game on your account —
@@ -158,7 +158,7 @@ Safe to run any time — genex-owned skills are refreshed to the latest version,
158
158
  and your own files are never touched:
159
159
 
160
160
  ```bash
161
- npx @genex-ai/cli-demo@latest init
161
+ npx @genex-ai/cli-demo@dev init
162
162
  ```
163
163
 
164
164
  Use `--force` only if you intentionally want your own existing files overwritten
@@ -331,6 +331,23 @@ halves of this rule are non-negotiable:
331
331
  `minPlayers: 2, maxPlayers: 2`: the instant the second player joins). If it doesn't close on
332
332
  both, the lobby is broken — fix it; do not ship a waiting room you haven't watched close.
333
333
 
334
+ **While `status === 'searching'` the roster is EMPTY — count the queue, not `players`.** The
335
+ matchmaker never parks a searcher in a room as a non-player: until it can seat you, you are in the
336
+ search line and in no room at all, so `players`/`connectedPlayers` are `[]`. A pre-match screen that
337
+ counts `players.length` there shows `0 / 2` to a player who is sitting in it, forever. Use the queue
338
+ count — it includes YOU, so it reads `1 / 2` when you are alone — and switch to the roster the moment
339
+ you are seated:
340
+
341
+ ```ts
342
+ const v = mm.matchmaking;
343
+ const lobbyCount = v.status === "searching" ? Math.max(v.queue.size, 1) : v.connectedPlayers.length;
344
+ ```
345
+
346
+ This bites hardest in the commonest co-op shape: with `minPlayers === maxPlayers` (e.g. `2` and `2`)
347
+ the room can only be formed once BOTH searchers exist, so you go `searching → playing` and **never
348
+ pass through `waiting`** — the screen the player stares at is the SEARCHING screen, and driving it
349
+ off `players.length` pins it at `0 / target` for its entire life.
350
+
334
351
  Two ways to present the lobby:
335
352
 
336
353
  - **A) UI lobby (Dota-style).** While `status === 'waiting'`, render an OVERLAY from `mm.matchmaking`
@@ -552,6 +569,35 @@ fights (many writers). A ball on `objects` glides and has one owner. That's the
552
569
  nearest `tier.remoteAvatarCap` remotes (`$genex-threejs-adaptive-quality`) — freeze the
553
570
  mixer and billboard or hide the rest; a room allows up to 64 players and 64 live avatars
554
571
  is a real phone memory kill on its own.
572
+ - **Build each remote's body exactly ONCE — reserve the id BEFORE the first `await`.** You read
573
+ `room.players` every frame, but loading a body is async and slow (seconds). If the only guard is
574
+ the map you fill *after* the await, every frame in that window passes it: you spawn one body per
575
+ frame, each stranded where it spawned — a trail of frozen clones behind the moving player — plus
576
+ dozens of wasted loads. Mark the id synchronously, and drop the body if that player left mid-load:
577
+
578
+ ```ts
579
+ const bodies = new Map<string, Body>();
580
+ const loading = new Set<string>(); // the seat reservation
581
+ function ensureBody(p: Player) {
582
+ if (bodies.has(p.id) || loading.has(p.id)) return; // BOTH — checked before any await
583
+ loading.add(p.id);
584
+ void (async () => {
585
+ try {
586
+ const body = await loadVrmClone(p.avatarUrl || "./assets/avatar.vrm");
587
+ if (!room.activePlayers.has(p.id)) return; // left while loading — never add it
588
+ scene.add(body.scene);
589
+ bodies.set(p.id, body);
590
+ } finally { loading.delete(p.id); } // always release, success or throw
591
+ })();
592
+ }
593
+ // Each frame: ensureBody for every remote, then drop bodies whose id is gone.
594
+ for (const [id, body] of bodies) {
595
+ if (!room.activePlayers.has(id)) { scene.remove(body.scene); bodies.delete(id); }
596
+ }
597
+ ```
598
+
599
+ The same rule covers anything else you lazily load per player or per object (nameplates, weapon
600
+ models, audio): a check that straddles an `await` is not a guard.
555
601
  - `room.activePlayers` — the connected-only subset of `room.players`; use its size for live quorum.
556
602
  - `room.objects` — shared objects nobody owns until claimed (a ball, an NPC):
557
603
  - `claim(id)` — **legacy** optimistic request. It flips local ownership immediately and is corrected
@@ -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
  ```