@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.
- package/README.md +0 -18
- package/dist/index.js +2839 -4768
- package/package.json +3 -3
- package/templates/controllers/character/follow-camera.ts +1 -16
- package/templates/controllers/character/meshy/meshy-loader.ts +2 -3
- package/templates/controllers/quality/pick-asset.ts +16 -49
- package/templates/controllers/shared/physics-world.ts +4 -6
- package/templates/skills/genex-ai-character/SKILL.md +15 -77
- package/templates/skills/genex-ai-menu/SKILL.md +11 -15
- package/templates/skills/genex-ai-model/SKILL.md +7 -45
- package/templates/skills/genex-ai-texture/SKILL.md +1 -1
- package/templates/skills/genex-ai-video/SKILL.md +17 -75
- package/templates/skills/genex-game-director/SKILL.md +46 -112
- package/templates/skills/genex-game-director/references/design-contract.md +5 -13
- package/templates/skills/genex-game-director/references/routing-map.md +45 -30
- package/templates/skills/genex-getting-started/SKILL.md +2 -2
- package/templates/skills/genex-monetization/SKILL.md +171 -0
- package/templates/skills/genex-threejs-adaptive-quality/SKILL.md +0 -21
- package/templates/skills/genex-threejs-character-controller/SKILL.md +5 -17
- package/templates/skills/genex-threejs-creatures/SKILL.md +1 -8
- package/templates/skills/genex-threejs-embed-auth/SKILL.md +52 -8
- package/templates/skills/genex-threejs-game-ui/SKILL.md +6 -55
- package/templates/skills/genex-threejs-procedural-assets/SKILL.md +10 -17
- package/templates/skills/genex-threejs-visual-validation/SKILL.md +2 -12
- package/templates/skills/genex-tool-audio/SKILL.md +2 -3
- package/templates/skills/genex-tool-character/SKILL.md +5 -36
- package/templates/skills/genex-tool-image/SKILL.md +2 -4
- package/templates/skills/genex-tool-model/SKILL.md +6 -32
- package/templates/skills/genex-tool-texture/SKILL.md +1 -1
- package/templates/skills/genex-tool-video/SKILL.md +5 -28
- package/templates/skills/genex-tool-workflow/SKILL.md +1 -4
- package/templates/skills/genex-updates/SKILL.md +1 -1
- package/dist/blender-mcp-Q6PSFYSE.js +0 -241
- package/dist/blender-serve-BF4FZ55Z.js +0 -244
- package/dist/chunk-2COG4P3T.js +0 -968
- package/dist/chunk-HYCSNWYX.js +0 -126
- package/templates/blender-service/demo/castle.py +0 -117
- package/templates/blender-service/gpu_witness.py +0 -245
- package/templates/blender-service/ops.py +0 -225
- package/templates/blender-service/pool.py +0 -910
- package/templates/blender-service/server.py +0 -611
- package/templates/blender-service/supervisor.py +0 -221
- package/templates/blender-service/views.py +0 -281
- package/templates/controllers/quality/deadline.ts +0 -117
- package/templates/skills/genex-blender-scene/SKILL.md +0 -243
- package/templates/skills/genex-lane-card/SKILL.md +0 -78
- 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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
64
|
+
return await opts.ktx2Load(`${picked}.ktx2`);
|
|
71
65
|
} catch {
|
|
72
|
-
console.warn(`[genex-quality] ktx2 variant missing
|
|
66
|
+
console.warn(`[genex-quality] ktx2 variant missing for ${picked} — using the browser-decodable rung`);
|
|
73
67
|
}
|
|
74
68
|
}
|
|
75
|
-
if (picked === url) return
|
|
69
|
+
if (picked === url) return load(url);
|
|
76
70
|
try {
|
|
77
|
-
return await
|
|
71
|
+
return await load(picked);
|
|
78
72
|
} catch {
|
|
79
|
-
// Missing
|
|
80
|
-
console.warn(`[genex-quality] rung missing
|
|
81
|
-
return
|
|
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
|
-
|
|
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
|
|
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
|
|
124
|
+
return await load(withKtx2);
|
|
158
125
|
} catch {
|
|
159
|
-
console.warn(`[genex-quality] ktx2 model rung missing
|
|
126
|
+
console.warn(`[genex-quality] ktx2 model rung missing for ${url} — trying the universal rung`);
|
|
160
127
|
}
|
|
161
128
|
}
|
|
162
|
-
if (universal === url) return
|
|
129
|
+
if (universal === url) return load(url);
|
|
163
130
|
try {
|
|
164
|
-
return await
|
|
131
|
+
return await load(universal);
|
|
165
132
|
} catch {
|
|
166
|
-
console.warn(`[genex-quality] model rung missing
|
|
167
|
-
return
|
|
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
|
-
|
|
213
|
-
|
|
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
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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) —
|
|
446
|
-
|
|
447
|
-
- `--resolution <
|
|
448
|
-
|
|
449
|
-
~
|
|
450
|
-
|
|
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
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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@
|
|
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,
|
|
41
|
-
>
|
|
42
|
-
>
|
|
43
|
-
>
|
|
44
|
-
>
|
|
45
|
-
>
|
|
46
|
-
>
|
|
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
|
|
142
|
-
genuinely needs more — clips
|
|
143
|
-
- `--resolution
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
-
|
|
148
|
-
|
|
149
|
-
|
|
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@
|
|
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
|