@genex-ai/cli-demo 1.31.1 → 1.32.0-dev.650

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 (46) hide show
  1. package/README.md +18 -0
  2. package/dist/blender-mcp-Q6PSFYSE.js +241 -0
  3. package/dist/blender-serve-BF4FZ55Z.js +244 -0
  4. package/dist/chunk-2COG4P3T.js +968 -0
  5. package/dist/chunk-HYCSNWYX.js +126 -0
  6. package/dist/index.js +4759 -2830
  7. package/package.json +3 -3
  8. package/templates/blender-service/demo/castle.py +117 -0
  9. package/templates/blender-service/gpu_witness.py +245 -0
  10. package/templates/blender-service/ops.py +225 -0
  11. package/templates/blender-service/pool.py +910 -0
  12. package/templates/blender-service/server.py +611 -0
  13. package/templates/blender-service/supervisor.py +221 -0
  14. package/templates/blender-service/views.py +281 -0
  15. package/templates/controllers/character/follow-camera.ts +16 -1
  16. package/templates/controllers/character/meshy/meshy-loader.ts +3 -2
  17. package/templates/controllers/quality/deadline.ts +117 -0
  18. package/templates/controllers/quality/pick-asset.ts +49 -16
  19. package/templates/controllers/shared/physics-world.ts +6 -4
  20. package/templates/skills/genex-ai-character/SKILL.md +77 -15
  21. package/templates/skills/genex-ai-menu/SKILL.md +15 -11
  22. package/templates/skills/genex-ai-model/SKILL.md +45 -7
  23. package/templates/skills/genex-ai-texture/SKILL.md +1 -1
  24. package/templates/skills/genex-ai-video/SKILL.md +75 -17
  25. package/templates/skills/genex-blender-scene/SKILL.md +243 -0
  26. package/templates/skills/genex-game-director/SKILL.md +112 -46
  27. package/templates/skills/genex-game-director/references/design-contract.md +13 -5
  28. package/templates/skills/genex-game-director/references/routing-map.md +30 -45
  29. package/templates/skills/genex-getting-started/SKILL.md +2 -2
  30. package/templates/skills/genex-lane-card/SKILL.md +78 -0
  31. package/templates/skills/genex-threejs-adaptive-quality/SKILL.md +21 -0
  32. package/templates/skills/genex-threejs-character-controller/SKILL.md +17 -5
  33. package/templates/skills/genex-threejs-creatures/SKILL.md +8 -1
  34. package/templates/skills/genex-threejs-embed-auth/SKILL.md +8 -0
  35. package/templates/skills/genex-threejs-game-ui/SKILL.md +55 -6
  36. package/templates/skills/genex-threejs-procedural-assets/SKILL.md +17 -10
  37. package/templates/skills/genex-threejs-visual-validation/SKILL.md +12 -2
  38. package/templates/skills/genex-tool-audio/SKILL.md +3 -2
  39. package/templates/skills/genex-tool-character/SKILL.md +36 -5
  40. package/templates/skills/genex-tool-image/SKILL.md +4 -2
  41. package/templates/skills/genex-tool-model/SKILL.md +32 -6
  42. package/templates/skills/genex-tool-publish/SKILL.md +100 -0
  43. package/templates/skills/genex-tool-texture/SKILL.md +1 -1
  44. package/templates/skills/genex-tool-video/SKILL.md +28 -5
  45. package/templates/skills/genex-tool-workflow/SKILL.md +4 -1
  46. package/templates/skills/genex-updates/SKILL.md +1 -1
@@ -9,6 +9,7 @@
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';
12
13
 
13
14
  // Host-agnostic on purpose: each stand serves generated assets from its own
14
15
  // domain (prod assets.genex.technology, dev assets.auras.cc), and baking one
@@ -56,23 +57,28 @@ export async function loadTextureWithFallback<T>(
56
57
  url: string,
57
58
  tier: QualityTier,
58
59
  load: (resolvedUrl: string) => Promise<T>,
59
- opts?: { ktx2Load?: (resolvedUrl: string) => Promise<T> },
60
+ opts?: { ktx2Load?: (resolvedUrl: string) => Promise<T>; deadlineMs?: number },
60
61
  ): 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;
61
67
  const picked = pickAsset(url, tier);
62
68
  if (picked !== url && opts?.ktx2Load) {
63
69
  try {
64
- return await opts.ktx2Load(`${picked}.ktx2`);
70
+ return await withDeadline(opts.ktx2Load(`${picked}.ktx2`), rungMs, `ktx2 texture ${picked}`);
65
71
  } catch {
66
- console.warn(`[genex-quality] ktx2 variant missing for ${picked} — using the browser-decodable rung`);
72
+ console.warn(`[genex-quality] ktx2 variant missing or too slow for ${picked} — using the browser-decodable rung`);
67
73
  }
68
74
  }
69
- if (picked === url) return load(url);
75
+ if (picked === url) return withDeadline(load(url), opts?.deadlineMs ?? ORIGINAL_DEADLINE_MS, `texture ${url}`);
70
76
  try {
71
- return await load(picked);
77
+ return await withDeadline(load(picked), rungMs, `texture rung ${picked}`);
72
78
  } catch {
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);
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}`);
76
82
  }
77
83
  }
78
84
 
@@ -90,7 +96,28 @@ export async function loadTextureWithFallback<T>(
90
96
  function modelBudgetFor(tier: QualityTier): number {
91
97
  return tier.name === "phone" || tier.name === "phone-low" ? 1024 : 2048;
92
98
  }
93
- const MODEL_ROLE_RE = /^(model-glb|character-rigged(-a\d+)?-glb(-r\d+)?)$/;
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)$/;
94
121
 
95
122
  /** Resolve the model URL a THIS-tier device should load. `ktx2: true` (from
96
123
  * createGltfLoader) upgrades to the GPU-compressed sibling. */
@@ -115,22 +142,28 @@ export async function loadModelWithFallback<T>(
115
142
  url: string,
116
143
  tier: QualityTier,
117
144
  load: (resolvedUrl: string) => Promise<T>,
118
- opts?: { ktx2?: boolean },
145
+ opts?: { ktx2?: boolean; deadlineMs?: number },
119
146
  ): 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;
120
153
  const withKtx2 = pickModel(url, tier, opts);
121
154
  const universal = pickModel(url, tier, { ktx2: false });
122
155
  if (withKtx2 !== universal) {
123
156
  try {
124
- return await load(withKtx2);
157
+ return await withDeadline(load(withKtx2), rungMs, `ktx2 model rung ${withKtx2}`);
125
158
  } catch {
126
- console.warn(`[genex-quality] ktx2 model rung missing for ${url} — trying the universal rung`);
159
+ console.warn(`[genex-quality] ktx2 model rung missing or too slow for ${url} — trying the universal rung`);
127
160
  }
128
161
  }
129
- if (universal === url) return load(url);
162
+ if (universal === url) return withDeadline(load(url), originalMs, `model ${url}`);
130
163
  try {
131
- return await load(universal);
164
+ return await withDeadline(load(universal), rungMs, `model rung ${universal}`);
132
165
  } catch {
133
- console.warn(`[genex-quality] model rung missing for ${url} — loading the original`);
134
- return load(url);
166
+ console.warn(`[genex-quality] model rung missing or too slow for ${url} — loading the original`);
167
+ return withDeadline(load(url), originalMs, `model ${url}`);
135
168
  }
136
169
  }
@@ -59,8 +59,6 @@ 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;
64
62
  /** Max CCD substeps. Default 1. */
65
63
  maxCcdSubsteps?: number;
66
64
  /** Contact softness frequency (Hz). Default 30. */
@@ -211,8 +209,12 @@ export class PhysicsWorld {
211
209
  options.numInternalPgsIterations ?? 1;
212
210
  this.world.integrationParameters.normalizedAllowedLinearError =
213
211
  options.allowedLinearError ?? 0.001;
214
- this.world.integrationParameters.minIslandSize =
215
- options.minIslandSize ?? 128;
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.
216
218
  this.world.integrationParameters.maxCcdSubsteps =
217
219
  options.maxCcdSubsteps ?? 1;
218
220
  this.world.integrationParameters.normalizedPredictionDistance =
@@ -101,12 +101,13 @@ 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 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
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
110
111
  your question tool when you have one; if you have none, a short numbered list
111
112
  in chat.)
112
113
 
@@ -122,10 +123,10 @@ npx genex character finalize <preview-id> \
122
123
  --animation <action-id>
123
124
  ```
124
125
 
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
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
129
130
  quote before enqueueing. The Meshy API key remains server-side; never ask the
130
131
  user for one or call Meshy directly from game code.
131
132
 
@@ -133,18 +134,40 @@ Meshy's public API performs automatic rigging. The manual joint-marker step
133
134
  shown in Meshy Web is not exposed through that API, so do not claim that this
134
135
  part of the hosted workflow is reproduced.
135
136
 
136
- The legacy one-shot text workflow is explicit and does not masquerade as the
137
- reviewed image-first path:
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:
138
140
 
139
141
  ```bash
140
142
  npx genex character "compact fantasy knight" --direct-text
141
143
  ```
142
144
 
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
+
143
164
  Useful options:
144
165
 
145
166
  ```bash
146
- npx genex character finalize <preview-id> --user-approved --approve-remesh 10000 --height 1.7
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
147
169
  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
148
171
  npx genex wait <generation-id>
149
172
  ```
150
173
 
@@ -153,10 +176,10 @@ npx genex wait <generation-id>
153
176
  compatibility path. The guided parity workflow always installs neutral-v3.
154
177
  `--no-wait` returns a generation id for `genex wait`; it does not create a
155
178
  second paid request. In the default lane, `--user-approved` and
156
- `--approve-remesh 10000` record the pick you made and announced after showing
179
+ `--approve-remesh <faces>` record the pick you made and announced after showing
157
180
  the real images. When the player explicitly requested a custom character,
158
181
  never add `--user-approved` until they have actually seen and selected the
159
- candidate, and never add `--approve-remesh 10000` until they have seen the
182
+ candidate, and never add `--approve-remesh <faces>` until they have seen the
160
183
  four high-detail views and measured face count.
161
184
 
162
185
  Before handoff, capture idle, walk, run, crouch-idle, crouch-move, and jump.
@@ -165,6 +188,35 @@ shrugging palms-up poses, permanently raised elbows, or a gait whose
165
188
  upper-body style contradicts the requested character. “No T-pose” is not
166
189
  an animation-quality check.
167
190
 
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
+
168
220
  ## Search first; use action IDs
169
221
 
170
222
  ```bash
@@ -305,6 +357,16 @@ game with a generated character, every remote wears it — one
305
357
  `Player character: VRM — out of credits` in DESIGN.md, and mark the spot with
306
358
  `// TODO(genex): regenerate when credits refill`. Do not stop the session over
307
359
  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.
308
370
  - **"Email not verified" (`email_verification_required`)** — generation credits
309
371
  unlock after the account's email is verified. Give the user the verify link the
310
372
  CLI printed, wait for them to confirm, then re-run the command.
@@ -406,12 +406,15 @@ 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 1080p by default — leave it alone.** Every video
409
+ - **The menu video renders 768p by default — leave it alone.** Every video
410
410
  path, the frame-conditioned (`--frame`) menu route included, defaults to
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.
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.
415
418
  - **Pause/victory/defeat variants reuse the same video — as GRADES.** Same
416
419
  `<video>` element or URL, different emotion via CSS `filter` on the
417
420
  background: pause = a plain dark overlay (`rgba(0,0,0,0.55)`); defeat =
@@ -439,12 +442,13 @@ fight — the title in the display font is a finished title, not a stand-in:
439
442
  frame: the seamless-loop mode. The URL must be one printed by `npx genex image`.
440
443
  - `--first-frame <url>` / `--last-frame <url>` (video) — two-frame mode for a
441
444
  genuine state change; expect a loop seam.
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).
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).
448
452
  - `--aspect 16:9 --quality high` (image) — the right settings for a menu frame.
449
453
  - `--no-wait` — enqueue and return immediately with the generation id; pick
450
454
  the result up later with `npx genex wait <id>` (safe to re-run — it attaches
@@ -9,13 +9,17 @@ 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 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.
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.
19
23
 
20
24
  **The output is a STATIC, unrigged mesh by default — no skeleton, no animation
21
25
  clips.** A "wolf" or "guard" from this command can be posed and moved as one
@@ -62,6 +66,26 @@ URL passes through. The prompt becomes optional (it's recorded for the ledger,
62
66
  the provider works from the image alone). A clear, single-object image on a
63
67
  plain background converts best.
64
68
 
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
+
65
89
  ## Split into parts (`model segment`)
66
90
 
67
91
  ```bash
@@ -252,6 +276,20 @@ scene is a ghost: players and objects pass straight through it.
252
276
 
253
277
  - `--image <path|url>` — build from a reference image (local file ≤4 MB, or a
254
278
  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).
255
293
  - `--granularity simple|balanced|detailed` — (`model segment`) part granularity.
256
294
  - `--type <plan>` — (`model rig`) body plan; omit to let the free rig-check pick.
257
295
  - `--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@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
@@ -37,13 +37,18 @@ 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, 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).
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).
47
52
 
48
53
  ## Play it in Three.js
49
54
 
@@ -133,15 +138,32 @@ See `$genex-threejs-multiplayer` for the `shared` channel rules and the room API
133
138
  ## Options
134
139
 
135
140
  - `--loop` — a seamless loop (for screens, ambient backdrops, video decals).
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).
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`.
145
167
  - `--no-wait` — enqueue and return immediately, without the URL. Fire-and-forget
146
168
  only: re-running the command creates (and bills) a NEW video.
147
169
  - `--api-url <url>` — override the API base (local dev).
@@ -149,11 +171,47 @@ See `$genex-threejs-multiplayer` for the `shared` channel rules and the room API
149
171
  Menu backdrops belong to `$genex-ai-menu`; a cohesive art-directed HUD sprite
150
172
  set belongs to `$genex-ai-hud` — both build on `npx genex image`/`video`.
151
173
 
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
+
152
204
  ## Troubleshooting
153
205
 
154
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
206
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
155
207
  - **"Prompt rejected"** — the provider's content-safety filter blocked the prompt.
156
208
  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.
157
215
  - **Nothing plays / black surface** — the first `video.play()` must run inside a user
158
216
  gesture (click/keydown); confirm it's called and its promise rejection is logged.
159
217
  - **Tainted-source / security error** — set `video.crossOrigin = "anonymous"` before