@genex-ai/cli-demo 1.30.0-dev.645 → 1.31.0

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.
Files changed (47) hide show
  1. package/README.md +0 -18
  2. package/dist/index.js +2839 -4768
  3. package/package.json +3 -3
  4. package/templates/controllers/character/follow-camera.ts +1 -16
  5. package/templates/controllers/character/meshy/meshy-loader.ts +2 -3
  6. package/templates/controllers/quality/pick-asset.ts +16 -49
  7. package/templates/controllers/shared/physics-world.ts +4 -6
  8. package/templates/skills/genex-ai-character/SKILL.md +15 -77
  9. package/templates/skills/genex-ai-menu/SKILL.md +11 -15
  10. package/templates/skills/genex-ai-model/SKILL.md +7 -45
  11. package/templates/skills/genex-ai-texture/SKILL.md +1 -1
  12. package/templates/skills/genex-ai-video/SKILL.md +17 -75
  13. package/templates/skills/genex-game-director/SKILL.md +46 -112
  14. package/templates/skills/genex-game-director/references/design-contract.md +5 -13
  15. package/templates/skills/genex-game-director/references/routing-map.md +45 -30
  16. package/templates/skills/genex-getting-started/SKILL.md +2 -2
  17. package/templates/skills/genex-monetization/SKILL.md +171 -0
  18. package/templates/skills/genex-threejs-adaptive-quality/SKILL.md +0 -21
  19. package/templates/skills/genex-threejs-character-controller/SKILL.md +5 -17
  20. package/templates/skills/genex-threejs-creatures/SKILL.md +1 -8
  21. package/templates/skills/genex-threejs-embed-auth/SKILL.md +52 -8
  22. package/templates/skills/genex-threejs-game-ui/SKILL.md +6 -55
  23. package/templates/skills/genex-threejs-procedural-assets/SKILL.md +10 -17
  24. package/templates/skills/genex-threejs-visual-validation/SKILL.md +2 -12
  25. package/templates/skills/genex-tool-audio/SKILL.md +2 -3
  26. package/templates/skills/genex-tool-character/SKILL.md +5 -36
  27. package/templates/skills/genex-tool-image/SKILL.md +2 -4
  28. package/templates/skills/genex-tool-model/SKILL.md +6 -32
  29. package/templates/skills/genex-tool-texture/SKILL.md +1 -1
  30. package/templates/skills/genex-tool-video/SKILL.md +5 -28
  31. package/templates/skills/genex-tool-workflow/SKILL.md +1 -4
  32. package/templates/skills/genex-updates/SKILL.md +1 -1
  33. package/dist/blender-mcp-Q6PSFYSE.js +0 -241
  34. package/dist/blender-serve-BF4FZ55Z.js +0 -244
  35. package/dist/chunk-2COG4P3T.js +0 -968
  36. package/dist/chunk-HYCSNWYX.js +0 -126
  37. package/templates/blender-service/demo/castle.py +0 -117
  38. package/templates/blender-service/gpu_witness.py +0 -245
  39. package/templates/blender-service/ops.py +0 -225
  40. package/templates/blender-service/pool.py +0 -910
  41. package/templates/blender-service/server.py +0 -611
  42. package/templates/blender-service/supervisor.py +0 -221
  43. package/templates/blender-service/views.py +0 -281
  44. package/templates/controllers/quality/deadline.ts +0 -117
  45. package/templates/skills/genex-blender-scene/SKILL.md +0 -243
  46. package/templates/skills/genex-lane-card/SKILL.md +0 -78
  47. package/templates/skills/genex-tool-publish/SKILL.md +0 -100
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/cli-demo",
3
- "version": "1.30.0-dev.645",
3
+ "version": "1.31.0",
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": {
@@ -40,10 +40,10 @@
40
40
  "pngjs": "^7.0.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@dimforge/rapier3d-compat": "^0.20.0",
44
- "@genex-ai/multiplayer": "workspace:*",
43
+ "@dimforge/rapier3d-compat": "^0.19.3",
45
44
  "@genex/meshy-animation-catalog": "workspace:*",
46
45
  "@genex/mobile-scan": "workspace:*",
46
+ "@genex-ai/multiplayer": "workspace:*",
47
47
  "@pixiv/three-vrm": "^3.5.4",
48
48
  "@types/pngjs": "^6.0.5",
49
49
  "@types/three": "^0.185.0",
@@ -376,22 +376,7 @@ export class FollowCamera {
376
376
  if (this._aimState === "unlocked" && e.pointerType === "mouse" && e.button === 0) {
377
377
  this._requestLock();
378
378
  }
379
- // Capture may be REFUSED, and a refusal must not throw out of the
380
- // handler. MEASURED 2026-09-04 across five graded games (`Uncaught
381
- // InvalidStateError: Failed to execute 'setPointerCapture'`): the click
382
- // above requests pointer lock, and once the lock lands Chromium retires
383
- // the pointer, so the capture call on that same pointerdown throws — an
384
- // uncaught exception on the first click of every game with this camera,
385
- // which failed the eval prober's no-errors check while the drag path
386
- // beneath it still worked. Same guard the touch kit uses (drag-zone.ts).
387
- if (typeof this._domElement.setPointerCapture === "function") {
388
- try {
389
- this._domElement.setPointerCapture(e.pointerId);
390
- } catch {
391
- // the pointer is already gone (pointer lock took it, or it was released
392
- // between the event and the call) — the drag works without capture
393
- }
394
- }
379
+ this._domElement.setPointerCapture(e.pointerId);
395
380
  this._pointers.set(e.pointerId, { x: e.clientX, y: e.clientY });
396
381
  if (this._pointers.size === 1) {
397
382
  this._orbiting = true;
@@ -23,8 +23,7 @@ export interface MeshyCharacterManifest {
23
23
  characterId: string;
24
24
  revision: number;
25
25
  manifestVersion: number;
26
- /** `meshy-biped`, or `uthana-biped` for a body imported with `genex character import` (same manifest shape). */
27
- rig: "meshy-biped" | "uthana-biped";
26
+ rig: "meshy-biped";
28
27
  controllerPack?: {
29
28
  key: string;
30
29
  version: number;
@@ -96,7 +95,7 @@ function validateManifest(value: unknown): MeshyCharacterManifest {
96
95
  if (
97
96
  !manifest ||
98
97
  manifest.schema !== 1 ||
99
- (manifest.rig !== "meshy-biped" && manifest.rig !== "uthana-biped") ||
98
+ manifest.rig !== "meshy-biped" ||
100
99
  !manifest.model?.url ||
101
100
  !manifest.model.skeletonSignature ||
102
101
  !Array.isArray(manifest.clips) ||
@@ -9,7 +9,6 @@
9
9
  // whose backfill hasn't run). loadTextureWithFallback retries the bare URL on
10
10
  // a rung failure, so the worst case is today's behavior — never a broken boot.
11
11
  import type { QualityTier } from './tier.ts';
12
- import { withDeadline, RUNG_DEADLINE_MS, ORIGINAL_DEADLINE_MS } from './deadline.ts';
13
12
 
14
13
  // Host-agnostic on purpose: each stand serves generated assets from its own
15
14
  // domain (prod assets.genex.technology, dev assets.auras.cc), and baking one
@@ -57,28 +56,23 @@ export async function loadTextureWithFallback<T>(
57
56
  url: string,
58
57
  tier: QualityTier,
59
58
  load: (resolvedUrl: string) => Promise<T>,
60
- opts?: { ktx2Load?: (resolvedUrl: string) => Promise<T>; deadlineMs?: number },
59
+ opts?: { ktx2Load?: (resolvedUrl: string) => Promise<T> },
61
60
  ): Promise<T> {
62
- // EVERY RUNG IS BOUNDED. The fallbacks below live in `catch`, so they advance
63
- // on a rejection and never on silence — a rung that HANGS rather than 404s
64
- // parked the boot forever, with no error in the console. `deadlineMs: 0`
65
- // opts out.
66
- const rungMs = opts?.deadlineMs ?? RUNG_DEADLINE_MS;
67
61
  const picked = pickAsset(url, tier);
68
62
  if (picked !== url && opts?.ktx2Load) {
69
63
  try {
70
- return await withDeadline(opts.ktx2Load(`${picked}.ktx2`), rungMs, `ktx2 texture ${picked}`);
64
+ return await opts.ktx2Load(`${picked}.ktx2`);
71
65
  } catch {
72
- console.warn(`[genex-quality] ktx2 variant missing or too slow for ${picked} — using the browser-decodable rung`);
66
+ console.warn(`[genex-quality] ktx2 variant missing for ${picked} — using the browser-decodable rung`);
73
67
  }
74
68
  }
75
- if (picked === url) return withDeadline(load(url), opts?.deadlineMs ?? ORIGINAL_DEADLINE_MS, `texture ${url}`);
69
+ if (picked === url) return load(url);
76
70
  try {
77
- return await withDeadline(load(picked), rungMs, `texture rung ${picked}`);
71
+ return await load(picked);
78
72
  } catch {
79
- // Missing or hung rung (old asset, un-backfilled env) — degrade to the original.
80
- console.warn(`[genex-quality] rung missing or too slow for ${url} — loading the original`);
81
- return withDeadline(load(url), opts?.deadlineMs ?? ORIGINAL_DEADLINE_MS, `texture ${url}`);
73
+ // Missing rung (old asset, un-backfilled env) — degrade to the original.
74
+ console.warn(`[genex-quality] rung missing for ${url} — loading the original`);
75
+ return load(url);
82
76
  }
83
77
  }
84
78
 
@@ -96,28 +90,7 @@ export async function loadTextureWithFallback<T>(
96
90
  function modelBudgetFor(tier: QualityTier): number {
97
91
  return tier.name === "phone" || tier.name === "phone-low" ? 1024 : 2048;
98
92
  }
99
- /** Which roles the server actually ladders. This MIRRORS `MODEL_RUNGS` in
100
- * apps/api/src/generation/model-rungs.ts and the two move together: a role
101
- * the writer emits but this list misses is a rung computed, stored and never
102
- * requested — every tier silently fetches the provider-raw original instead,
103
- * which is the one thing the ladder exists to prevent. Mirroring the writer
104
- * is always the safe side of the error, because a rung that turns out not to
105
- * exist just warns and falls back (see loadModelWithFallback below).
106
- *
107
- * Second line = the AG-908 Tripo mesh lanes: `genex model segment` (a static
108
- * prop, simplified like model-glb), `genex model rig`, and `genex model
109
- * animate` — one `model-anim-<preset>-glb` per clip plus the
110
- * `model-animations-glb` bundle. Animation-only clip GLBs from the character
111
- * lane (`character-motion-*-glb`) are deliberately NOT here: the rung
112
- * pipeline would prune away the sampler data that IS the clip. */
113
- // `rigged-character.glb` is the role the GUIDED character lane actually writes —
114
- // reversed words and a dot extension, unlike every other entry here. Until
115
- // 2026-09-07 neither this regex nor the server's rung writer knew it, so every
116
- // generated character was fetched provider-raw (measured: 23.85 MB, and its
117
- // texture failed to decode into a white body). The dot is safe: the rung URL is
118
- // built by appending `@<width>`, so it lands as `rigged-character.glb@2048`.
119
- const MODEL_ROLE_RE =
120
- /^(model-glb|character-rigged(-a\d+)?-glb(-r\d+)?|rigged-character\.glb|model-segmented-glb|model-rigged-glb|model-animations-glb|model-anim-.+-glb)$/;
93
+ const MODEL_ROLE_RE = /^(model-glb|character-rigged(-a\d+)?-glb(-r\d+)?)$/;
121
94
 
122
95
  /** Resolve the model URL a THIS-tier device should load. `ktx2: true` (from
123
96
  * createGltfLoader) upgrades to the GPU-compressed sibling. */
@@ -142,28 +115,22 @@ export async function loadModelWithFallback<T>(
142
115
  url: string,
143
116
  tier: QualityTier,
144
117
  load: (resolvedUrl: string) => Promise<T>,
145
- opts?: { ktx2?: boolean; deadlineMs?: number },
118
+ opts?: { ktx2?: boolean },
146
119
  ): Promise<T> {
147
- // See the note in `loadTextureWithFallback`: without a deadline a hung rung
148
- // never reaches these `catch` blocks and the boot never finishes. The
149
- // original gets a longer one — reaching it at all means every rung failed,
150
- // and it is the archival asset.
151
- const rungMs = opts?.deadlineMs ?? RUNG_DEADLINE_MS;
152
- const originalMs = opts?.deadlineMs ?? ORIGINAL_DEADLINE_MS;
153
120
  const withKtx2 = pickModel(url, tier, opts);
154
121
  const universal = pickModel(url, tier, { ktx2: false });
155
122
  if (withKtx2 !== universal) {
156
123
  try {
157
- return await withDeadline(load(withKtx2), rungMs, `ktx2 model rung ${withKtx2}`);
124
+ return await load(withKtx2);
158
125
  } catch {
159
- console.warn(`[genex-quality] ktx2 model rung missing or too slow for ${url} — trying the universal rung`);
126
+ console.warn(`[genex-quality] ktx2 model rung missing for ${url} — trying the universal rung`);
160
127
  }
161
128
  }
162
- if (universal === url) return withDeadline(load(url), originalMs, `model ${url}`);
129
+ if (universal === url) return load(url);
163
130
  try {
164
- return await withDeadline(load(universal), rungMs, `model rung ${universal}`);
131
+ return await load(universal);
165
132
  } catch {
166
- console.warn(`[genex-quality] model rung missing or too slow for ${url} — loading the original`);
167
- return withDeadline(load(url), originalMs, `model ${url}`);
133
+ console.warn(`[genex-quality] model rung missing for ${url} — loading the original`);
134
+ return load(url);
168
135
  }
169
136
  }
@@ -59,6 +59,8 @@ export interface PhysicsWorldOptions {
59
59
  allowedLinearError?: number;
60
60
  /** Contact prediction distance (length units). Default 0.002. */
61
61
  predictionDistance?: number;
62
+ /** Minimum island size for parallelism. Default 128. */
63
+ minIslandSize?: number;
62
64
  /** Max CCD substeps. Default 1. */
63
65
  maxCcdSubsteps?: number;
64
66
  /** Contact softness frequency (Hz). Default 30. */
@@ -209,12 +211,8 @@ export class PhysicsWorld {
209
211
  options.numInternalPgsIterations ?? 1;
210
212
  this.world.integrationParameters.normalizedAllowedLinearError =
211
213
  options.allowedLinearError ?? 0.001;
212
- // `minIslandSize` is deliberately NOT set. Rapier 0.20.0 (2026-08-08)
213
- // removed it from `IntegrationParameters`, and the skill installs the
214
- // package unpinned — so a game that set it failed `tsc` on its first build
215
- // (measured on a hosted session 2026-09-03) and the agent patched this
216
- // vendored file by hand. The knob only tuned island parallelism, which the
217
- // JS build never had.
214
+ this.world.integrationParameters.minIslandSize =
215
+ options.minIslandSize ?? 128;
218
216
  this.world.integrationParameters.maxCcdSubsteps =
219
217
  options.maxCcdSubsteps ?? 1;
220
218
  this.world.integrationParameters.normalizedPredictionDistance =
@@ -101,13 +101,12 @@ they crop well to a portrait and read as one set across the cast.
101
101
  npx genex character preview <concept-id> --candidate <1|2|3> --user-approved
102
102
  ```
103
103
 
104
- Meshy 7 Image-to-3D (Ultra, 4k textures by default) first produces an
105
- unremeshed high-detail model. Show its front, back, left, and right views and
106
- report its measured face count. Preserve that model in R2. A triangle remesh
107
- at the face budget you approve—not the high-detail source—is rigged and
108
- animated. In the default lane, proceed to the remesh directly; when the player
109
- explicitly requested a custom character, ask for their explicit approval
110
- first. (For the custom lane's approvals, use
104
+ Meshy Image-to-3D first produces an unremeshed high-detail model. Show its
105
+ front, back, left, and right views and report its measured face count.
106
+ Preserve that model in R2. The 10,000-face triangle remesh—not the
107
+ high-detail source—is rigged and animated. In the default lane, proceed to
108
+ the remesh directly; when the player explicitly requested a custom character,
109
+ ask for their explicit approval first. (For the custom lane's approvals, use
111
110
  your question tool when you have one; if you have none, a short numbered list
112
111
  in chat.)
113
112
 
@@ -123,10 +122,10 @@ npx genex character finalize <preview-id> \
123
122
  --animation <action-id>
124
123
  ```
125
124
 
126
- `--animation` is repeatable. Finalization creates the approved triangle
127
- remesh from the Meshy 7 preview, rigs it, adds the immutable preview-reviewed
128
- neutral-v3 idle/walk/run/crouch/jump controller pack, and stores the source,
129
- remesh, rig, and clips at permanent Genex asset URLs. It prints the complete Genex-credit
125
+ `--animation` is repeatable. Finalization uses Meshy 6, creates the approved
126
+ 10k triangle remesh, rigs it, adds the immutable preview-reviewed neutral-v3
127
+ idle/walk/run/crouch/jump controller pack, and stores the source, remesh, rig,
128
+ and clips at permanent Genex asset URLs. It prints the complete Genex-credit
130
129
  quote before enqueueing. The Meshy API key remains server-side; never ask the
131
130
  user for one or call Meshy directly from game code.
132
131
 
@@ -134,40 +133,18 @@ Meshy's public API performs automatic rigging. The manual joint-marker step
134
133
  shown in Meshy Web is not exposed through that API, so do not claim that this
135
134
  part of the hosted workflow is reproduced.
136
135
 
137
- The one-shot text workflow is explicit and does not masquerade as the
138
- reviewed image-first path. It runs the same Meshy 7 (Ultra, 4k) — the only
139
- thing it skips is the review:
136
+ The legacy one-shot text workflow is explicit and does not masquerade as the
137
+ reviewed image-first path:
140
138
 
141
139
  ```bash
142
140
  npx genex character "compact fantasy knight" --direct-text
143
141
  ```
144
142
 
145
- ## The quality knobs are yours to set
146
-
147
- Every lane runs Meshy 7 with Ultra and 4k textures unless you say otherwise,
148
- and every knob is priced in the quote the command prints before enqueueing.
149
- Choose per role, and say the choice in one line of chat:
150
-
151
- - `--approve-remesh <faces>` (finalize) / `--polycount <faces>` (one shot):
152
- the rigging copy's face budget, 10000-100000. **10000** for anything seen
153
- in a crowd or at a distance; **20000-30000** for the player's body in a
154
- third-person game; **50000+** only for a hero seen in close-up cutscenes.
155
- Mobile budgets favour the low end. The number moves no cost.
156
- - `--texture 2k|4k|8k` (preview / one shot): 4k is the default; 8k (+5
157
- credits) only for a body the camera sits on in close-up; 2k for crowds.
158
- - `--no-ultra` (preview / one shot): −5 credits and less surface detail —
159
- crowd enemies and stand-ins, never the player's body.
160
- - `--pose a-pose|t-pose` (one shot): the preferred rest pose; the other
161
- stays the structural-QA fallback.
162
- - `--height <metres>`: 0.5-3, default 1.7.
163
-
164
143
  Useful options:
165
144
 
166
145
  ```bash
167
- npx genex character preview <concept-id> --candidate 2 --user-approved --texture 8k
168
- npx genex character finalize <preview-id> --user-approved --approve-remesh 30000 --height 1.7
146
+ npx genex character finalize <preview-id> --user-approved --approve-remesh 10000 --height 1.7
169
147
  npx genex character finalize <preview-id> --user-approved --approve-remesh 10000 --animation 466 --no-wait
170
- npx genex character "market guard" --direct-text --polycount 10000 --no-ultra --texture 2k
171
148
  npx genex wait <generation-id>
172
149
  ```
173
150
 
@@ -176,10 +153,10 @@ npx genex wait <generation-id>
176
153
  compatibility path. The guided parity workflow always installs neutral-v3.
177
154
  `--no-wait` returns a generation id for `genex wait`; it does not create a
178
155
  second paid request. In the default lane, `--user-approved` and
179
- `--approve-remesh <faces>` record the pick you made and announced after showing
156
+ `--approve-remesh 10000` record the pick you made and announced after showing
180
157
  the real images. When the player explicitly requested a custom character,
181
158
  never add `--user-approved` until they have actually seen and selected the
182
- candidate, and never add `--approve-remesh <faces>` until they have seen the
159
+ candidate, and never add `--approve-remesh 10000` until they have seen the
183
160
  four high-detail views and measured face count.
184
161
 
185
162
  Before handoff, capture idle, walk, run, crouch-idle, crouch-move, and jump.
@@ -188,35 +165,6 @@ shrugging palms-up poses, permanently raised elbows, or a gait whose
188
165
  upper-body style contradicts the requested character. “No T-pose” is not
189
166
  an animation-quality check.
190
167
 
191
- ## Import a character the player already has (`character import`)
192
-
193
- When the player hands you a humanoid mesh — their own Blender character, a
194
- bought asset, an export from another tool — **import it, never regenerate
195
- it**. The upload is free; Uthana then auto-rigs it (one paid call, finger
196
- joints included) and it becomes a character of theirs:
197
-
198
- ```bash
199
- npx genex character import ./assets/knight.glb --height 1.8
200
- npx genex character animate <character-id> --locomotion --no-wait # the 16-clip walk/run set
201
- npx genex controller character --character <character-id> # once locomotion lands
202
- ```
203
-
204
- What Uthana needs: a **biped humanoid** in a **T- or A-pose, feet on the
205
- ground, facing +Z**, as a `.glb` under **30 MB** (textures are the bulk —
206
- shrink them, not the mesh). Non-biped bodies go through `npx genex model
207
- import` + `npx genex model rig` (7 body plans) instead. `--no-fingers` skips
208
- finger joints when the hands are blobs (Uthana warns poor finger geometry
209
- lowers rig quality).
210
-
211
- An imported character is **Uthana-rigged**: `character animate` in plain
212
- words, `--locomotion` and `--video` all work on it, and the manifest reads
213
- `rig: "uthana-biped"`. The Meshy catalog (`--animation <id>`) and the
214
- neutral-v3 controller pack do **not** apply — those are Meshy-rig clips — so
215
- run `--locomotion` before installing the controller, or the body stands
216
- still. `--texture`, `--no-ultra`, `--pose` and `--polycount` are Meshy
217
- generation knobs and are refused here: an import keeps the mesh exactly as it
218
- is.
219
-
220
168
  ## Search first; use action IDs
221
169
 
222
170
  ```bash
@@ -357,16 +305,6 @@ game with a generated character, every remote wears it — one
357
305
  `Player character: VRM — out of credits` in DESIGN.md, and mark the spot with
358
306
  `// TODO(genex): regenerate when credits refill`. Do not stop the session over
359
307
  this, and do not hand-build a stand-in humanoid.
360
- - **"The character provider is out of credit on this stand"** (the line `npx genex
361
- wait` / `npx genex character` prints when the VENDOR refused for money — Meshy
362
- "Insufficient funds", Tripo code 2010) — this is the platform's own provider
363
- account, not your prompt and not the user's credits (the charge auto-refunds),
364
- and no re-run changes it. Take the same fallback: keep the profile VRM avatar,
365
- tell the user in one plain line that the game is wearing the platform avatar
366
- because the character lane is unavailable on this stand, record
367
- `Player character: VRM — provider out of credit` in DESIGN.md, and mark the spot
368
- with `// TODO(genex): regenerate when credits refill`. `npx genex doctor` shows
369
- the lane as OUT OF CREDIT while it lasts.
370
308
  - **"Email not verified" (`email_verification_required`)** — generation credits
371
309
  unlock after the account's email is verified. Give the user the verify link the
372
310
  CLI printed, wait for them to confirm, then re-run the command.
@@ -406,15 +406,12 @@ fight — the title in the display font is a finished title, not a stand-in:
406
406
  re-prompt the still against the new direction (or `--edit` it against the
407
407
  new reference) and re-run the video from the new still. Agent-initiated
408
408
  polish never does.
409
- - **The menu video renders 768p by default — leave it alone.** Every video
409
+ - **The menu video renders 1080p by default — leave it alone.** Every video
410
410
  path, the frame-conditioned (`--frame`) menu route included, defaults to
411
- 768p the model's top NATIVE mode; `--resolution 2k` is an upscale of the
412
- same base at ~2× the cost, worth it only if the menu still reads soft on a
413
- large desktop. Don't opt DOWN: `--resolution 480p` exists for clips that are
414
- genuinely incidental — never the main menu.
415
- - **The clip ships with a native audio track — keep the menu `<video>` muted.**
416
- Autoplay requires `muted` anyway; menu music stays the `npx genex music`
417
- track under the Music volume slider, not the clip's baked-in audio.
411
+ 1080p: the menu clip is full-screen key art, and 720p stretched across a
412
+ desktop reads soft. Don't pass a resolution flag at all; `--resolution 720p`
413
+ exists only as a deliberate cost opt-down for clips that are genuinely
414
+ incidental — never the main menu.
418
415
  - **Pause/victory/defeat variants reuse the same video — as GRADES.** Same
419
416
  `<video>` element or URL, different emotion via CSS `filter` on the
420
417
  background: pause = a plain dark overlay (`rgba(0,0,0,0.55)`); defeat =
@@ -442,13 +439,12 @@ fight — the title in the display font is a finished title, not a stand-in:
442
439
  frame: the seamless-loop mode. The URL must be one printed by `npx genex image`.
443
440
  - `--first-frame <url>` / `--last-frame <url>` (video) — two-frame mode for a
444
441
  genuine state change; expect a loop seam.
445
- - `--duration <sec>` (video) — 5–15 for frame-conditioned clips; default 8
446
- (menu loops read better long).
447
- - `--resolution <480p|768p|2k|4k>` (video) — every path defaults to **768p**
448
- (the top native mode), the `--frame` menu route included. `2k` upscales for
449
- ~ the cost; `480p` is the cost opt-down for incidental clips — not for the
450
- menu. Loop clips (`--loop`) ignore it (that model has no resolution
451
- parameter).
442
+ - `--duration <sec>` (video) — 4, 6, or 8 for frame-conditioned clips;
443
+ default 8.
444
+ - `--resolution <720p|1080p>` (video) — every path defaults to **1080p**, the
445
+ `--frame` menu route included. `720p` is the deliberate cost opt-down
446
+ (~half the credits) for incidental clips — not for the menu. Loop clips
447
+ (`--loop`) ignore it (that model has no resolution parameter).
452
448
  - `--aspect 16:9 --quality high` (image) — the right settings for a menu frame.
453
449
  - `--no-wait` — enqueue and return immediately with the generation id; pick
454
450
  the result up later with `npx genex wait <id>` (safe to re-run — it attaches
@@ -9,17 +9,13 @@ Turn a text prompt into a real, game-ready **GLB** and drop it into the project.
9
9
 
10
10
  ## When to use this vs. procedural geometry
11
11
 
12
- - **Use `npx genex model`** for a specific, recognizable object the player will
13
- look at — a barrel, a chair, a sword, a spaceship, an animal, a named
14
- building, the thing the request asked for. You get a real textured mesh, and
15
- this is the default route whenever code would not honestly make the object
16
- read as itself.
17
- - **Use `$genex-threejs-procedural-assets`** for what is structural, repeated,
18
- distant, or parametric — modular kits, fences, walls, paving, terrain,
19
- anything placed many times with variation (editable, seeded, no GLB file) —
20
- and for a close-up object only when the code result meets the same bar and
21
- you have checked it in a capture. Mixing both in one scene is the normal way
22
- to build a detailed world.
12
+ - **Use `npx genex model`** for a specific, recognizable object a barrel, a chair, a
13
+ sword, a spaceship, an animal. You get a real textured mesh.
14
+ - **Use `$genex-threejs-procedural-assets`** when code is the more efficient
15
+ engine: structures and buildings, modular kits, and anything placed many
16
+ times with variation (editable, seeded, no GLB file). Mixing both in one
17
+ scene is the normal way to build a detailed world — generated hero pieces
18
+ over procedural dressing.
23
19
 
24
20
  **The output is a STATIC, unrigged mesh by default — no skeleton, no animation
25
21
  clips.** A "wolf" or "guard" from this command can be posed and moved as one
@@ -66,26 +62,6 @@ URL passes through. The prompt becomes optional (it's recorded for the ledger,
66
62
  the provider works from the image alone). A clear, single-object image on a
67
63
  plain background converts best.
68
64
 
69
- ## Bring your own mesh (`model import`)
70
-
71
- A model the player already has — a Blender export, a bought asset, a file
72
- from another tool — is **imported, never rebuilt**. Importing is free and
73
- makes it a model of theirs, so every id-only lane works on it: `model rig`,
74
- `model animate`, `model segment`, `blender import`, and "Use in game" on the
75
- dashboard.
76
-
77
- ```bash
78
- npx genex model import ./assets/hero-cart.glb
79
- ```
80
-
81
- - `.glb` only (binary glTF 2.0), up to 64 MB. A `.gltf` + `.bin` pair or an
82
- FBX is exported as one `.glb` first — in Blender, File → Export → glTF 2.0
83
- with format "glTF Binary".
84
- - The file is checked (magic, version, triangle geometry) before the row
85
- completes; a bad file is refused and nothing is charged.
86
- - A humanoid that should walk goes through `$genex-ai-character`'s
87
- `character import` instead — same upload, plus a Uthana auto-rig.
88
-
89
65
  ## Split into parts (`model segment`)
90
66
 
91
67
  ```bash
@@ -276,20 +252,6 @@ scene is a ghost: players and objects pass straight through it.
276
252
 
277
253
  - `--image <path|url>` — build from a reference image (local file ≤4 MB, or a
278
254
  generated-asset URL); the prompt becomes optional.
279
- - **Quality knobs** (Tripo H3.1; each is priced in the quote, choose per
280
- asset and say it in one line): `--texture standard|detailed|none` (detailed
281
- is the default and +10 credits over standard; `none` is geometry only, for
282
- something you texture in code), `--geometry detailed` (+20 — a hero prop
283
- the camera sits on; never for a crate), `--quad` (+5, quad-dominant mesh
284
- for anything you will deform or edit further; face limit ≤150000),
285
- `--low-poly` (+10, smart low-poly topology — the game-ready choice for
286
- props that appear in numbers; it holds `--face-limit` to 1000-20000,
287
- 500-10000 with `--quad` — omit the flag to take 20000 — and runs a
288
- post-process after the mesh, so allow up to 30 minutes), `--parts` (+20, separated named parts at
289
- generation — cheaper than `model segment` when you know up front you need
290
- doors, wheels, magazines), `--face-limit <n>` (1000-2000000, default
291
- 150000; the raw cap — the game still loads the @2048/@1024 rungs),
292
- `--auto-size` (real-world metres by AI estimate).
293
255
  - `--granularity simple|balanced|detailed` — (`model segment`) part granularity.
294
256
  - `--type <plan>` — (`model rig`) body plan; omit to let the free rig-check pick.
295
257
  - `--preset walk[,run,…]` — (`model animate`) clips to retarget; billed per clip.
@@ -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@dev init` first (it writes your `GENEX_TOKEN`).
228
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest 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
@@ -37,18 +37,13 @@ The clip lives in Genex storage (R2) and loads straight from that URL — you do
37
37
  download it and nothing is committed to your repo. The URL is permanent (local dev,
38
38
  published game, and remixes alike).
39
39
 
40
- > **Cost & length:** the default is a **5-second, 768p** clip (MiniMax H3's top
41
- > native mode) — the right default for anything the player looks at directly.
42
- > Only pass `--duration` when the content genuinely needs to be longer (5–15s;
43
- > a cutscene), `--resolution 2k`/`4k` only for hero shots (they upscale the
44
- > same native base, run on an older and pricier model, and cost roughly 3–4×),
45
- > and `--resolution 480p` only when
46
- > the clip is genuinely incidental (a small in-world screen seen from a
47
- > distance). Every clip carries a **native stereo audio track** (score, foley,
48
- > even dialogue) — in-game `<video>` elements autoplay muted, so unmute it only
49
- > when the sound is the point (a cutscene) and route it through the SFX volume
50
- > slider. mp4 has **no alpha channel**, so a video is always a full rectangle
51
- > (there are no transparent video decals).
40
+ > **Cost & length:** the default is a **5-second, 1080p** clip the right default
41
+ > for anything the player looks at directly. Only pass `--duration` when the content
42
+ > genuinely needs to be longer (a cutscene), and `--resolution 720p` only when the
43
+ > clip is genuinely incidental (a small in-world screen seen from a distance): it
44
+ > halves the cost, but 720p stretched across the whole screen reads soft. mp4 has
45
+ > **no alpha channel**, so a video is always a full rectangle (there are no
46
+ > transparent video decals).
52
47
 
53
48
  ## Play it in Three.js
54
49
 
@@ -138,32 +133,15 @@ See `$genex-threejs-multiplayer` for the `shared` channel rules and the room API
138
133
  ## Options
139
134
 
140
135
  - `--loop` — a seamless loop (for screens, ambient backdrops, video decals).
141
- - `--duration <sec>` — clip length 5–15; default 5. Only raise it when the content
142
- genuinely needs more — clips bill per second.
143
- - `--resolution 480p|768p|2k|4k` — output resolution (default **768p**, the top
144
- native mode). `2k`/`4k` upscale the same base for hero shots at ~2–3× the
145
- cost; `480p` is the cost opt-down for genuinely incidental clips. `--loop`
146
- clips ignore it (model default).
147
- - `--frame <url|file>` — one generated image (or a local file ≤4 MB) as BOTH
148
- first and last frame — the seamless-loop mode (motion must return to its
149
- start; the seam is mathematically exact).
150
- - `--start-frame <url|file>` — continue from this frame, no end anchor — the
151
- clip-chaining primitive (see below). Local files inline like `--frame`.
152
- - `--first-frame <url|file>` / `--last-frame <url|file>` — two-frame motion
153
- between two stills (a genuine state change — a door opens, day turns to
154
- night). `--first-frame` alone means `--start-frame`.
155
-
156
- **Frame anchors are compositional guidance, not pixel-pinning.** The model
157
- repaints every anchor — the clip's first frame lands near the supplied image
158
- (same scene, same composition) but not ON it, and regenerating doesn't change
159
- that; it is how the mode works. Plan for it: chains stay coherent when each
160
- clip starts from the previous clip's REAL frame (below), and a supplied
161
- `--last-frame` steers where motion ends rather than guaranteeing the exact
162
- pixels.
163
- - `--ref <url|file>` — repeatable, up to 9 subject/style reference images.
164
- Cite each in the prompt by its order: "Image 1 is the hero — she walks into
165
- frame…". This is how the SAME character or art style holds across many clips
166
- (a cutscene series, an episodic story). Cannot combine with `--frame`/`--loop`.
136
+ - `--duration <sec>` — clip length 1–15; default 5. Only raise it when the content
137
+ genuinely needs more — longer clips cost more and take longer.
138
+ - `--resolution 720p|1080p` — output resolution (default **1080p**). `--resolution
139
+ 720p` halves the cost use it only when quality genuinely doesn't matter (a small
140
+ far-away in-world screen). `--loop` clips ignore it (model default).
141
+ - `--frame <url>` one generated image as BOTH first and last frame — the
142
+ seamless-loop mode (motion must return to its start).
143
+ - `--first-frame <url>` / `--last-frame <url>` two-frame motion between two
144
+ stills (a genuine state change; expect a loop seam).
167
145
  - `--no-wait` — enqueue and return immediately, without the URL. Fire-and-forget
168
146
  only: re-running the command creates (and bills) a NEW video.
169
147
  - `--api-url <url>` — override the API base (local dev).
@@ -171,47 +149,11 @@ pixels.
171
149
  Menu backdrops belong to `$genex-ai-menu`; a cohesive art-directed HUD sprite
172
150
  set belongs to `$genex-ai-hud` — both build on `npx genex image`/`video`.
173
151
 
174
- ## Interactive video games
175
-
176
- Clips are cheap and fast enough to be a game's PRIMARY content, not just set
177
- dressing — an interactive movie (Detroit-style branching story), a generated-
178
- evidence detective game, a video-book. The pattern that makes it hold together:
179
-
180
- - **Branching scenes**: generate one clip per story node at build time, ship
181
- the mp4 URLs in a scene-graph JSON, play them full-screen with DOM choice
182
- buttons; preload the clips reachable from the current node while it plays.
183
- - **Visual continuity — chain from REAL frames**: extract the previous clip's
184
- actual last frame and seed the next clip with it:
185
-
186
- ```bash
187
- ffmpeg -sseof -0.2 -i prev.mp4 -update 1 -q:v 1 last.png
188
- npx genex video "she turns and walks toward the far door" --start-frame last.png
189
- ```
190
-
191
- Never chain from the image you WISHED the clip ended on — anchors are
192
- repainted (above), so the wish and the clip disagree and every join jumps.
193
- Chaining from the real frame keeps drift from accumulating; the residual
194
- repaint at each cut is small, and a ~200 ms crossfade between the two
195
- `<video>` elements hides it entirely. Write chained prompts as CHANGE ONLY
196
- ("she turns…", "the light flickers out") — the start frame already says
197
- everything else.
198
- - **Cast consistency**: give every scene the same `--ref` images of your
199
- protagonist and key locations — the single biggest quality lever for any
200
- multi-clip story.
201
- - Keep hard facts (dialogue you must control, exact text) in subtitles and
202
- `npx genex voice` lines layered on top; the clip's own audio is atmosphere.
203
-
204
152
  ## Troubleshooting
205
153
 
206
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
154
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
207
155
  - **"Prompt rejected"** — the provider's content-safety filter blocked the prompt.
208
156
  This is non-retryable; retrying the same wording fails again. Rewrite the prompt.
209
- The measured false-positive class is anatomy being pierced or entered
210
- (cables/wires/needles into a body — biomech and cyberpunk vocabulary trips
211
- it). Describe the object or machine instead of the anatomy: "a statue-like
212
- figure threaded into the wall" passes where "cables entering her spine"
213
- fails. Word it that way on the FIRST try — each rejection still ends a
214
- billed-then-refunded round trip.
215
157
  - **Nothing plays / black surface** — the first `video.play()` must run inside a user
216
158
  gesture (click/keydown); confirm it's called and its promise rejection is logged.
217
159
  - **Tainted-source / security error** — set `video.crossOrigin = "anonymous"` before