@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.
- package/README.md +18 -0
- package/dist/blender-mcp-Q6PSFYSE.js +241 -0
- package/dist/blender-serve-BF4FZ55Z.js +244 -0
- package/dist/chunk-2COG4P3T.js +968 -0
- package/dist/chunk-HYCSNWYX.js +126 -0
- package/dist/index.js +4759 -2830
- package/package.json +3 -3
- package/templates/blender-service/demo/castle.py +117 -0
- package/templates/blender-service/gpu_witness.py +245 -0
- package/templates/blender-service/ops.py +225 -0
- package/templates/blender-service/pool.py +910 -0
- package/templates/blender-service/server.py +611 -0
- package/templates/blender-service/supervisor.py +221 -0
- package/templates/blender-service/views.py +281 -0
- package/templates/controllers/character/follow-camera.ts +16 -1
- package/templates/controllers/character/meshy/meshy-loader.ts +3 -2
- package/templates/controllers/quality/deadline.ts +117 -0
- package/templates/controllers/quality/pick-asset.ts +49 -16
- package/templates/controllers/shared/physics-world.ts +6 -4
- package/templates/skills/genex-ai-character/SKILL.md +77 -15
- package/templates/skills/genex-ai-menu/SKILL.md +15 -11
- package/templates/skills/genex-ai-model/SKILL.md +45 -7
- package/templates/skills/genex-ai-texture/SKILL.md +1 -1
- package/templates/skills/genex-ai-video/SKILL.md +75 -17
- package/templates/skills/genex-blender-scene/SKILL.md +243 -0
- package/templates/skills/genex-game-director/SKILL.md +112 -46
- package/templates/skills/genex-game-director/references/design-contract.md +13 -5
- package/templates/skills/genex-game-director/references/routing-map.md +30 -45
- package/templates/skills/genex-getting-started/SKILL.md +2 -2
- package/templates/skills/genex-lane-card/SKILL.md +78 -0
- package/templates/skills/genex-threejs-adaptive-quality/SKILL.md +21 -0
- package/templates/skills/genex-threejs-character-controller/SKILL.md +17 -5
- package/templates/skills/genex-threejs-creatures/SKILL.md +8 -1
- package/templates/skills/genex-threejs-embed-auth/SKILL.md +8 -0
- package/templates/skills/genex-threejs-game-ui/SKILL.md +55 -6
- package/templates/skills/genex-threejs-procedural-assets/SKILL.md +17 -10
- package/templates/skills/genex-threejs-visual-validation/SKILL.md +12 -2
- package/templates/skills/genex-tool-audio/SKILL.md +3 -2
- package/templates/skills/genex-tool-character/SKILL.md +36 -5
- package/templates/skills/genex-tool-image/SKILL.md +4 -2
- package/templates/skills/genex-tool-model/SKILL.md +32 -6
- package/templates/skills/genex-tool-publish/SKILL.md +100 -0
- package/templates/skills/genex-tool-texture/SKILL.md +1 -1
- package/templates/skills/genex-tool-video/SKILL.md +28 -5
- package/templates/skills/genex-tool-workflow/SKILL.md +4 -1
- 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
|
-
|
|
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
|
-
|
|
215
|
-
|
|
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
|
|
105
|
-
front, back, left, and right views and
|
|
106
|
-
Preserve that model in R2.
|
|
107
|
-
high-detail source—is rigged and
|
|
108
|
-
the remesh directly; when the player
|
|
109
|
-
ask for their explicit approval
|
|
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
|
|
126
|
-
|
|
127
|
-
idle/walk/run/crouch/jump controller pack, and stores the source,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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) —
|
|
443
|
-
|
|
444
|
-
- `--resolution <
|
|
445
|
-
`--frame` menu route included. `
|
|
446
|
-
|
|
447
|
-
(`--loop`) ignore it (that model has no resolution
|
|
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
|
+
~2× 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
|
|
13
|
-
sword, a spaceship, an animal
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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@
|
|
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,
|
|
41
|
-
> for anything the player looks at directly.
|
|
42
|
-
> genuinely needs to be longer (
|
|
43
|
-
>
|
|
44
|
-
>
|
|
45
|
-
>
|
|
46
|
-
>
|
|
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
|
|
137
|
-
genuinely needs more —
|
|
138
|
-
- `--resolution
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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@
|
|
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
|