@genex-ai/cli-demo 1.19.0-dev.601 → 1.21.0-dev.603
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{blender-mcp-FQJFZETR.js → blender-mcp-PWOUSXK4.js} +1 -1
- package/dist/{chunk-YSMZVFJM.js → chunk-HEDRWUVP.js} +7 -0
- package/dist/index.js +542 -170
- package/package.json +1 -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 +27 -15
- package/templates/skills/genex-ai-character/SKILL.md +67 -15
- package/templates/skills/genex-ai-model/SKILL.md +32 -0
- package/templates/skills/genex-game-director/SKILL.md +18 -10
- package/templates/skills/genex-lane-card/SKILL.md +60 -0
- package/templates/skills/genex-threejs-character-controller/SKILL.md +2 -1
- package/templates/skills/genex-threejs-creatures/SKILL.md +8 -1
- package/templates/skills/genex-threejs-visual-validation/SKILL.md +2 -1
- package/templates/skills/genex-tool-character/SKILL.md +36 -5
- package/templates/skills/genex-tool-model/SKILL.md +16 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genex-ai/cli-demo",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0-dev.603",
|
|
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": {
|
|
@@ -23,7 +23,8 @@ export interface MeshyCharacterManifest {
|
|
|
23
23
|
characterId: string;
|
|
24
24
|
revision: number;
|
|
25
25
|
manifestVersion: number;
|
|
26
|
-
|
|
26
|
+
/** `meshy-biped`, or `uthana-biped` for a body imported with `genex character import` (same manifest shape). */
|
|
27
|
+
rig: "meshy-biped" | "uthana-biped";
|
|
27
28
|
controllerPack?: {
|
|
28
29
|
key: string;
|
|
29
30
|
version: number;
|
|
@@ -95,7 +96,7 @@ function validateManifest(value: unknown): MeshyCharacterManifest {
|
|
|
95
96
|
if (
|
|
96
97
|
!manifest ||
|
|
97
98
|
manifest.schema !== 1 ||
|
|
98
|
-
manifest.rig !== "meshy-biped" ||
|
|
99
|
+
(manifest.rig !== "meshy-biped" && manifest.rig !== "uthana-biped") ||
|
|
99
100
|
!manifest.model?.url ||
|
|
100
101
|
!manifest.model.skeletonSignature ||
|
|
101
102
|
!Array.isArray(manifest.clips) ||
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Genex adaptive-quality: BOUNDED loading.
|
|
2
|
+
//
|
|
3
|
+
// WHY THIS EXISTS. Before 2026-09-07 there was no timeout anywhere in the
|
|
4
|
+
// vendored kits — `grep -rn "setTimeout|AbortController|AbortSignal|timeout"`
|
|
5
|
+
// across quality/ and character/ returned NOTHING. Every fallback in
|
|
6
|
+
// `pick-asset.ts` lives inside a `catch`, so it advances on a REJECTION and
|
|
7
|
+
// never on silence: a rung that hangs rather than 404s parks the boot forever,
|
|
8
|
+
// and the player watches a black canvas with no error in the console. The one
|
|
9
|
+
// local Opus run that shipped had to hand-write its own `withDeadline` in
|
|
10
|
+
// `src/main.ts` to get around exactly this, which is the clearest possible
|
|
11
|
+
// signal that the kit owed it.
|
|
12
|
+
//
|
|
13
|
+
// WHAT THIS BOUNDS, HONESTLY. `withDeadline` bounds the WAIT, not the fetch.
|
|
14
|
+
// The abandoned request keeps running in the background until the browser gives
|
|
15
|
+
// up on it; what changes is that the fallback chain ADVANCES instead of
|
|
16
|
+
// stalling, which is the failure being fixed. Real cancellation needs the
|
|
17
|
+
// caller to own the request (`fetchArrayBufferWithDeadline` below is that door,
|
|
18
|
+
// for callers that can hand bytes to `loader.parse`).
|
|
19
|
+
//
|
|
20
|
+
// Zero dependencies and browser-only APIs, because this ships inside a player's
|
|
21
|
+
// game bundle.
|
|
22
|
+
|
|
23
|
+
/** Thrown when a load outlives its deadline. Distinct so a caller can tell a
|
|
24
|
+
* timeout from a genuine 404 — they mean different things about the asset. */
|
|
25
|
+
export class DeadlineError extends Error {
|
|
26
|
+
readonly label: string;
|
|
27
|
+
readonly ms: number;
|
|
28
|
+
constructor(label: string, ms: number) {
|
|
29
|
+
super(`[genex-quality] ${label} exceeded ${ms}ms`);
|
|
30
|
+
this.name = "DeadlineError";
|
|
31
|
+
this.label = label;
|
|
32
|
+
this.ms = ms;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Resolve `work`, or reject with `DeadlineError` after `ms`.
|
|
38
|
+
*
|
|
39
|
+
* The timer is always cleared, including on the success path: a pending timer
|
|
40
|
+
* keeps a closure over the promise alive, and twenty of them per boot is a leak
|
|
41
|
+
* a long session notices.
|
|
42
|
+
*/
|
|
43
|
+
export function withDeadline<T>(work: Promise<T>, ms: number, label: string): Promise<T> {
|
|
44
|
+
if (!(ms > 0) || !Number.isFinite(ms)) return work;
|
|
45
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
46
|
+
const bell = new Promise<never>((_resolve, reject) => {
|
|
47
|
+
timer = setTimeout(() => reject(new DeadlineError(label, ms)), ms);
|
|
48
|
+
});
|
|
49
|
+
return Promise.race([work, bell]).finally(() => {
|
|
50
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
51
|
+
}) as Promise<T>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A budget shared across a boot, so N slow assets cannot SERIALISE into a wait
|
|
56
|
+
* no per-attempt deadline would ever catch.
|
|
57
|
+
*
|
|
58
|
+
* A per-attempt deadline alone is not enough and the arithmetic is the reason:
|
|
59
|
+
* twenty props at a 15 s rung deadline is five minutes of black screen, with
|
|
60
|
+
* every individual attempt inside its limit. `remaining()` is what makes the
|
|
61
|
+
* ceiling the BOOT's rather than each asset's.
|
|
62
|
+
*
|
|
63
|
+
* Never returns a negative, and `expired()` is the honest question to ask
|
|
64
|
+
* before starting more optional work.
|
|
65
|
+
*/
|
|
66
|
+
export function createBootBudget(totalMs: number, now: () => number = () => Date.now()) {
|
|
67
|
+
const startedAt = now();
|
|
68
|
+
return {
|
|
69
|
+
remaining(): number {
|
|
70
|
+
return Math.max(0, totalMs - (now() - startedAt));
|
|
71
|
+
},
|
|
72
|
+
expired(): boolean {
|
|
73
|
+
return now() - startedAt >= totalMs;
|
|
74
|
+
},
|
|
75
|
+
/** The deadline to give the next attempt: its own cap, clipped to what is
|
|
76
|
+
* left of the boot. */
|
|
77
|
+
slice(attemptMs: number): number {
|
|
78
|
+
return Math.min(attemptMs, Math.max(0, totalMs - (now() - startedAt)));
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* REAL cancellation, for a caller that can parse bytes itself:
|
|
85
|
+
*
|
|
86
|
+
* const buf = await fetchArrayBufferWithDeadline(url, 15000);
|
|
87
|
+
* const gltf = await loader.parseAsync(buf, "");
|
|
88
|
+
*
|
|
89
|
+
* Safe for OUR generated rungs specifically, because they embed their textures
|
|
90
|
+
* — a GLB with external resources would lose its base URL this way, which is
|
|
91
|
+
* why the loaders do NOT use this by default.
|
|
92
|
+
*/
|
|
93
|
+
export async function fetchArrayBufferWithDeadline(
|
|
94
|
+
url: string,
|
|
95
|
+
ms: number,
|
|
96
|
+
label = url,
|
|
97
|
+
): Promise<ArrayBuffer> {
|
|
98
|
+
const controller = new AbortController();
|
|
99
|
+
const timer = setTimeout(() => controller.abort(), ms);
|
|
100
|
+
try {
|
|
101
|
+
const res = await fetch(url, { signal: controller.signal });
|
|
102
|
+
if (!res.ok) throw new Error(`[genex-quality] ${label} → HTTP ${res.status}`);
|
|
103
|
+
return await res.arrayBuffer();
|
|
104
|
+
} catch (err) {
|
|
105
|
+
// An abort is a deadline, and the caller must be able to tell the two apart.
|
|
106
|
+
if (err instanceof Error && err.name === "AbortError") throw new DeadlineError(label, ms);
|
|
107
|
+
throw err;
|
|
108
|
+
} finally {
|
|
109
|
+
clearTimeout(timer);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Per-attempt defaults. A rung is small by construction; the original is the
|
|
114
|
+
* archival asset and is allowed to be slower, because reaching it at all means
|
|
115
|
+
* every rung already failed. */
|
|
116
|
+
export const RUNG_DEADLINE_MS = 15_000;
|
|
117
|
+
export const ORIGINAL_DEADLINE_MS = 30_000;
|
|
@@ -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
|
|
|
@@ -130,22 +136,28 @@ export async function loadModelWithFallback<T>(
|
|
|
130
136
|
url: string,
|
|
131
137
|
tier: QualityTier,
|
|
132
138
|
load: (resolvedUrl: string) => Promise<T>,
|
|
133
|
-
opts?: { ktx2?: boolean },
|
|
139
|
+
opts?: { ktx2?: boolean; deadlineMs?: number },
|
|
134
140
|
): Promise<T> {
|
|
141
|
+
// See the note in `loadTextureWithFallback`: without a deadline a hung rung
|
|
142
|
+
// never reaches these `catch` blocks and the boot never finishes. The
|
|
143
|
+
// original gets a longer one — reaching it at all means every rung failed,
|
|
144
|
+
// and it is the archival asset.
|
|
145
|
+
const rungMs = opts?.deadlineMs ?? RUNG_DEADLINE_MS;
|
|
146
|
+
const originalMs = opts?.deadlineMs ?? ORIGINAL_DEADLINE_MS;
|
|
135
147
|
const withKtx2 = pickModel(url, tier, opts);
|
|
136
148
|
const universal = pickModel(url, tier, { ktx2: false });
|
|
137
149
|
if (withKtx2 !== universal) {
|
|
138
150
|
try {
|
|
139
|
-
return await load(withKtx2);
|
|
151
|
+
return await withDeadline(load(withKtx2), rungMs, `ktx2 model rung ${withKtx2}`);
|
|
140
152
|
} catch {
|
|
141
|
-
console.warn(`[genex-quality] ktx2 model rung missing for ${url} — trying the universal rung`);
|
|
153
|
+
console.warn(`[genex-quality] ktx2 model rung missing or too slow for ${url} — trying the universal rung`);
|
|
142
154
|
}
|
|
143
155
|
}
|
|
144
|
-
if (universal === url) return load(url);
|
|
156
|
+
if (universal === url) return withDeadline(load(url), originalMs, `model ${url}`);
|
|
145
157
|
try {
|
|
146
|
-
return await load(universal);
|
|
158
|
+
return await withDeadline(load(universal), rungMs, `model rung ${universal}`);
|
|
147
159
|
} catch {
|
|
148
|
-
console.warn(`[genex-quality] model rung missing for ${url} — loading the original`);
|
|
149
|
-
return load(url);
|
|
160
|
+
console.warn(`[genex-quality] model rung missing or too slow for ${url} — loading the original`);
|
|
161
|
+
return withDeadline(load(url), originalMs, `model ${url}`);
|
|
150
162
|
}
|
|
151
163
|
}
|
|
@@ -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
|
|
@@ -66,6 +66,26 @@ URL passes through. The prompt becomes optional (it's recorded for the ledger,
|
|
|
66
66
|
the provider works from the image alone). A clear, single-object image on a
|
|
67
67
|
plain background converts best.
|
|
68
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
|
+
|
|
69
89
|
## Split into parts (`model segment`)
|
|
70
90
|
|
|
71
91
|
```bash
|
|
@@ -256,6 +276,18 @@ scene is a ghost: players and objects pass straight through it.
|
|
|
256
276
|
|
|
257
277
|
- `--image <path|url>` — build from a reference image (local file ≤4 MB, or a
|
|
258
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), `--parts` (+20, separated named parts at
|
|
287
|
+
generation — cheaper than `model segment` when you know up front you need
|
|
288
|
+
doors, wheels, magazines), `--face-limit <n>` (1000-2000000, default
|
|
289
|
+
150000; the raw cap — the game still loads the @2048/@1024 rungs),
|
|
290
|
+
`--auto-size` (real-world metres by AI estimate).
|
|
259
291
|
- `--granularity simple|balanced|detailed` — (`model segment`) part granularity.
|
|
260
292
|
- `--type <plan>` — (`model rig`) body plan; omit to let the free rig-check pick.
|
|
261
293
|
- `--preset walk[,run,…]` — (`model animate`) clips to retarget; billed per clip.
|
|
@@ -119,11 +119,12 @@ vendored code from memory of another engine.
|
|
|
119
119
|
|
|
120
120
|
| Work needed | Load |
|
|
121
121
|
| --- | --- |
|
|
122
|
+
| **your first `npx genex model` or `npx genex character` this session** — the command, what comes back, how to scale and ground it, and what to do when a lane is dead. One page, thirty seconds. The full lanes below are long; measured across 105 generation-lane invocations, 94% ran without the owning skill open, and placement is where that showed | `$genex-lane-card` |
|
|
122
123
|
| shot composition, chase/side/orbit rigs, camera handoffs, projection ownership, pointer look, mouse-aimed action, mouse-look, the screen-direction contract for hand-rolled steering/pan/look input signs, floating origins | `$genex-threejs-camera-direction` |
|
|
123
124
|
| on-foot player movement: walk/run/jump/crouch, third-person character, slopes, stairs, moving platforms, the player's body loader, directional locomotion, transitions, action motion | `$genex-threejs-character-controller` |
|
|
124
125
|
| **attacking, casting, aiming or reloading WHILE moving** — any action the legs must keep running under; a weapon carry stance over stock locomotion; a wind-up the character holds while walking | `$genex-threejs-character-controller` (`references/animations.md`, upper-body layering) |
|
|
125
126
|
| dash, dodge, roll, blink, backstep, a lunging attack — any burst that moves the character itself | `$genex-threejs-character-controller` (`references/tuning-and-presets.md`, dash recipe) |
|
|
126
|
-
| the game's own generated character—the player's body wherever a human body appears—or Meshy animation coverage beyond the stock pack: reference-informed A-pose concepts, exact action IDs, same-rig adapter | `$genex-ai-character` + `$genex-threejs-character-controller` |
|
|
127
|
+
| the game's own generated character—the player's body wherever a human body appears—or Meshy animation coverage beyond the stock pack: reference-informed A-pose concepts, exact action IDs, same-rig adapter | `$genex-ai-character` + `$genex-threejs-character-controller` (first time this session: `$genex-lane-card`) |
|
|
127
128
|
| a character/enemy needs motion the catalog lacks—a signature move, boss telegraph, death, full 8-way set, or the player's footage; free plan before spend | `$genex-ai-character` motion section + `references/motion-generation.md` |
|
|
128
129
|
| remote player bodies in multiplayer—never hand-built primitives: the game's generated character when it has one, otherwise the player's `p.avatarUrl` VRM | `$genex-threejs-multiplayer` + `$genex-threejs-character-controller` |
|
|
129
130
|
| enemies, NPCs, or creatures: rigged bipeds via `npx genex creature`; non-biped body plans (quadruped, flier, serpent, aquatic, multi-leg) via `npx genex model rig` + `model animate`; static plus procedural motion only for shapes with no body plan; collider, facing, hit reaction, death | `$genex-threejs-creatures` |
|
|
@@ -139,7 +140,8 @@ vendored code from memory of another engine.
|
|
|
139
140
|
| stable large-world shadows, cascades, clipmaps, cached updates | `$genex-threejs-shadow-systems` |
|
|
140
141
|
| eye adaptation, tone mapping, output color, LUT grading, and proven static grain | `$genex-threejs-exposure-color-grading` |
|
|
141
142
|
| fixed-view screenshots, input direction, facing, temporal and budget evidence | `$genex-threejs-visual-validation` |
|
|
142
|
-
|
|
|
143
|
+
| **a model the player already has** — a `.glb` they exported, bought or made elsewhere: it is IMPORTED, never rebuilt. `npx genex model import <file.glb>` (free) for props and non-biped bodies (then `model rig`/`model animate`), `npx genex character import <file.glb>` for a humanoid that should walk (Uthana auto-rig, then `character animate --locomotion`) | `$genex-ai-model` · `$genex-ai-character` |
|
|
144
|
+
| the default for a concrete object the player looks at up close: a generated GLB for a prop, vehicle, building, or object — from text or a reference image (`--image`); split into named parts (`model segment`); rig + animate any mesh (`model rig` / `model animate`). A space routed to code above does NOT settle these: a village's ground plan can be code while the forge you walk up to is generated | `$genex-ai-model` (first time this session: `$genex-lane-card`) |
|
|
143
145
|
| generated surface or terrain texture with real-world UV scale | `$genex-ai-texture` |
|
|
144
146
|
| sky, skybox, horizon, time of day, weather mood, night or space backdrop | build it in code in the scene—there is no sky command and no owning skill, so pick the technique this game needs |
|
|
145
147
|
| poster, sign, sprite, decal, reference sheet, or other 2D art | `$genex-ai-image` |
|
|
@@ -195,9 +197,14 @@ its local path for code-built ones — the table is where the per-object decisio
|
|
|
195
197
|
lives, and a table with no generated row records
|
|
196
198
|
`Generation: none — <why code alone reaches the bar here>` beside it. Mixing
|
|
197
199
|
both in one scene is the normal way to build, never a fallback. In focused
|
|
198
|
-
work, stay inside the touched scope.
|
|
199
|
-
|
|
200
|
-
|
|
200
|
+
work, stay inside the touched scope. Generate in batches you can finish. The first
|
|
201
|
+
batch is the smallest set that makes the scene read — the player's body,
|
|
202
|
+
whatever the request names, and the first thing they walk up to — enqueued
|
|
203
|
+
together with `--no-wait` while you scaffold. Before a second batch starts,
|
|
204
|
+
every id in the first is collected with `npx genex wait --all`, loaded from a
|
|
205
|
+
file in `src/`, and seen in a capture. A batch begun while the previous one is
|
|
206
|
+
still uncollected is how a game ends up with an asset library and an empty
|
|
207
|
+
world. Preserve every id, URL and wiring state across a compaction.
|
|
201
208
|
|
|
202
209
|
## 5. Execute by working mode
|
|
203
210
|
|
|
@@ -355,13 +362,14 @@ your pick. The announced pick carries the lane:
|
|
|
355
362
|
|
|
356
363
|
`npx genex character preview <concept-id> --candidate <1|2|3> --user-approved`
|
|
357
364
|
|
|
358
|
-
Meshy Image-to-3D first produces an unremeshed high-detail model. Show its
|
|
365
|
+
Meshy 7 Image-to-3D first produces an unremeshed high-detail model. Show its
|
|
359
366
|
front, back, left, and right views and report its measured face count.
|
|
360
|
-
Preserve that model in R2.
|
|
361
|
-
|
|
362
|
-
|
|
367
|
+
Preserve that model in R2. A triangle remesh at the face budget you approve
|
|
368
|
+
(10000-100000; 10000 for crowds, 20000-30000 for a third-person player
|
|
369
|
+
body)—not the high-detail source—is rigged and animated. In the default lane,
|
|
370
|
+
the pick authorizes that remesh:
|
|
363
371
|
|
|
364
|
-
`npx genex character finalize <preview-id> --user-approved --approve-remesh
|
|
372
|
+
`npx genex character finalize <preview-id> --user-approved --approve-remesh <faces> [--animation <action-id>…]`
|
|
365
373
|
|
|
366
374
|
When the player explicitly requested a custom character, keep the existing
|
|
367
375
|
two stops: wait for their explicit candidate selection before Image-to-3D,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: genex-lane-card
|
|
3
|
+
description: The asset belt on one page — the command, what comes back, how to place it so it is not a speck or a wall, and what to do when a lane is dead. Read this before your first `npx genex model` or `npx genex character`. The full lanes are `$genex-ai-model` and `$genex-ai-character`; this card is what you need to not get it wrong.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Genex · Lane card
|
|
7
|
+
|
|
8
|
+
## Object → mesh
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npx genex model "weathered oak barrel, iron bands, damp staves" --no-wait
|
|
12
|
+
npx genex wait --all # prints every id this project enqueued, with its URL
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
A specific prompt beats a noun: "barrel" gives you a barrel-shaped guess, the
|
|
16
|
+
line above gives you the one in your scene. The URL is permanent — paste it into
|
|
17
|
+
the loader, never download it into the repo.
|
|
18
|
+
|
|
19
|
+
## Player body → character
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx genex character "stylized desert courier, layered dust-worn cloth"
|
|
23
|
+
npx genex character preview <concept-id> --candidate 1 --user-approved
|
|
24
|
+
npx genex character finalize <preview-id> --user-approved --approve-remesh 10000
|
|
25
|
+
npx genex controller character --character <id> # the whole integration
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Look at the three concepts, pick the strongest yourself, say which and why, and
|
|
29
|
+
keep going. Never foreground-`wait` on a character stage — they take minutes.
|
|
30
|
+
|
|
31
|
+
## Place it — a GLB arrives at any scale, with any origin
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
const o = gltf.scene;
|
|
35
|
+
const box = new THREE.Box3().setFromObject(o);
|
|
36
|
+
const size = new THREE.Vector3();
|
|
37
|
+
box.getSize(size);
|
|
38
|
+
o.scale.multiplyScalar(TARGET_HEIGHT_M / size.y); // the metres you want
|
|
39
|
+
box.setFromObject(o); // re-measure, then ground it
|
|
40
|
+
o.position.y -= box.min.y;
|
|
41
|
+
scene.add(o);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Skip this and the mesh is a speck or a wall — it is the single most common way a
|
|
45
|
+
generated asset ships broken. Rigged bodies mismeasure here; those go through
|
|
46
|
+
the controller's own boot path, not this snippet.
|
|
47
|
+
|
|
48
|
+
## The one rule
|
|
49
|
+
|
|
50
|
+
An asset is not done when the command exits. It is done when something in
|
|
51
|
+
`src/` loads it, you have run the game, and you have LOOKED at it. A generation
|
|
52
|
+
nobody wired is money spent on nothing — `npx genex wait --all` marks a row
|
|
53
|
+
`wired` only once its URL appears in your source.
|
|
54
|
+
|
|
55
|
+
## When a lane is dead
|
|
56
|
+
|
|
57
|
+
A lane whose provider wallet is empty fails every call and refunds every one.
|
|
58
|
+
`npx genex doctor` prints each lane live/mock/paused with its credit state. If a
|
|
59
|
+
lane is red: **build that thing in code and move on** — do not re-run it, and do
|
|
60
|
+
not stall the game waiting for it. Say in chat what you fell back to.
|
|
@@ -85,7 +85,8 @@ npx genex controller character --character <character-id>
|
|
|
85
85
|
|
|
86
86
|
Meshy Image-to-3D first produces an unremeshed high-detail model. Show its
|
|
87
87
|
front, back, left, and right views and report its measured face count. Preserve
|
|
88
|
-
that model in R2. The
|
|
88
|
+
that model in R2. The triangle remesh at the approved face budget (10,000
|
|
89
|
+
by default; up to 100,000 for a hero)—not the high-detail
|
|
89
90
|
source—is rigged and animated. In the default lane proceed to it directly;
|
|
90
91
|
for a player-requested custom character, ask for their explicit approval
|
|
91
92
|
first (question tool when you have one; a short numbered list in chat
|
|
@@ -29,6 +29,10 @@ the rig). Route by silhouette:
|
|
|
29
29
|
locomotion clips for exactly the shapes Meshy refuses — see
|
|
30
30
|
`$genex-ai-model` for the full flow, presets, and honest limits (avian rigs
|
|
31
31
|
have no preset clips; drive those bones in code).
|
|
32
|
+
- **A mesh the player already has** (their own creature file): `npx genex
|
|
33
|
+
model import <file.glb>` first — free — then the same routing by
|
|
34
|
+
silhouette: biped → `npx genex character import` (Uthana auto-rig),
|
|
35
|
+
anything else → `npx genex model rig`. Never rebuild what they handed you.
|
|
32
36
|
- **Everything outside both** (swarms, blobs, amorphous things — no body plan
|
|
33
37
|
to rig): the **static + procedural lane** — `npx genex model` for the body,
|
|
34
38
|
motion authored in code. Say it honestly in the Assets table:
|
|
@@ -53,7 +57,10 @@ npx genex creature "hulking bone seraph, tattered wing membranes, upright stance
|
|
|
53
57
|
```
|
|
54
58
|
|
|
55
59
|
Each creature is one Assets-table row (visible spend — the usual budget
|
|
56
|
-
rules).
|
|
60
|
+
rules). It runs Meshy 7 like the player body; the knobs are yours: a crowd
|
|
61
|
+
enemy is `--polycount 10000 --no-ultra --texture 2k`, a boss seen in close-up
|
|
62
|
+
`--polycount 30000` (`--texture 8k` if the camera lingers), `--pose t-pose`
|
|
63
|
+
when a rig keeps failing structural QA in a-pose. The result is a rigged GLB whose clips play on a standard
|
|
57
64
|
`THREE.AnimationMixer`; Meshy limb rotations play unchanged — never apply
|
|
58
65
|
post-mixer limb corrections. Prompt the body UPRIGHT and unpropped (held
|
|
59
66
|
props fuse into bodies); prompt "facing the viewer" but never trust it —
|
|
@@ -37,7 +37,8 @@ overlapping props or straps can fuse into the character or hide a limb.
|
|
|
37
37
|
|
|
38
38
|
Meshy Image-to-3D first produces an unremeshed high-detail model. Show its
|
|
39
39
|
front, back, left, and right views and report its measured face count. Preserve
|
|
40
|
-
that model in R2. The
|
|
40
|
+
that model in R2. The triangle remesh at the approved face budget (10,000
|
|
41
|
+
by default; up to 100,000 for a hero)—not the high-detail
|
|
41
42
|
source—is rigged and animated. In the default lane the remesh proceeds
|
|
42
43
|
directly; for a player-requested custom character, wait for their explicit
|
|
43
44
|
approval first (question tool when you have one; a short numbered list in
|
|
@@ -24,13 +24,28 @@ npx genex character preview <concept-id> --candidate 2 --user-approved
|
|
|
24
24
|
# → a 3D preview of that one, four views. Show it; wait for approval.
|
|
25
25
|
|
|
26
26
|
npx genex character finalize <preview-id> --user-approved --approve-remesh 10000
|
|
27
|
-
# → the rigged, game-ready character.
|
|
27
|
+
# → the rigged, game-ready character at that face budget.
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
Each step needs the previous step's generation id. The approval flags are not
|
|
31
31
|
ceremony: they record that a person actually looked and chose, and each step
|
|
32
32
|
costs credits.
|
|
33
33
|
|
|
34
|
+
## The knobs (Meshy 7 on every lane)
|
|
35
|
+
|
|
36
|
+
Ultra and 4k textures are the defaults; every knob is priced in the quote.
|
|
37
|
+
Pick per role and say so in one line:
|
|
38
|
+
|
|
39
|
+
- `--approve-remesh <faces>` (finalize) / `--polycount <faces>` (one shot):
|
|
40
|
+
the rigging copy's face budget, 10000-100000 — 10000 for crowds and
|
|
41
|
+
distance, 20000-30000 for a third-person player body, 50000+ only for a
|
|
42
|
+
close-up hero. Moves no cost.
|
|
43
|
+
- `--texture 2k|4k|8k` (preview / one shot): 8k is +5 credits, for close-ups.
|
|
44
|
+
- `--no-ultra` (preview / one shot): −5 credits, less surface detail — stand-ins
|
|
45
|
+
and crowd enemies.
|
|
46
|
+
- `--pose a-pose|t-pose` (one shot): the preferred rest pose.
|
|
47
|
+
- `--height <metres>`: 0.5-3, default 1.7.
|
|
48
|
+
|
|
34
49
|
## One shot
|
|
35
50
|
|
|
36
51
|
When nobody is choosing — a background NPC, a quick test:
|
|
@@ -41,7 +56,21 @@ npx genex creature "hulking bone seraph, upright stance"
|
|
|
41
56
|
```
|
|
42
57
|
|
|
43
58
|
`creature` is the same lane with enemy defaults: no approval steps, no player
|
|
44
|
-
controller pack. Biped-shaped bodies only.
|
|
59
|
+
controller pack (and priced without one). Biped-shaped bodies only. The knobs
|
|
60
|
+
above apply: a crowd enemy is `--polycount 10000 --no-ultra --texture 2k`.
|
|
61
|
+
|
|
62
|
+
## Import a character the user already has
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx genex character import ./knight.glb --height 1.8 # free upload + Uthana auto-rig (finger joints; --no-fingers skips them)
|
|
66
|
+
npx genex character animate <id> --locomotion # then the walk/run set — an import has no clips yet
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Biped humanoid, T- or A-pose, feet on the ground, facing +Z, `.glb` ≤ 30 MB.
|
|
70
|
+
**Never rebuild a mesh the user gives you** — import it. The result is a
|
|
71
|
+
Uthana-rigged body: verbs, `--locomotion` and `--video` work; the Meshy
|
|
72
|
+
catalog and controller pack do not. Non-biped bodies: `npx genex model
|
|
73
|
+
import` + `npx genex model rig`.
|
|
45
74
|
|
|
46
75
|
## Animating it
|
|
47
76
|
|
|
@@ -75,9 +104,11 @@ look here first — a library clip costs nothing to generate.
|
|
|
75
104
|
|
|
76
105
|
## Cost
|
|
77
106
|
|
|
78
|
-
Typical: **
|
|
79
|
-
character · **
|
|
80
|
-
|
|
107
|
+
Typical: **32** concept · **41** preview · **29** finalize · **64** one-shot
|
|
108
|
+
character · **46** creature · **18** import (Uthana auto-rig; the upload is
|
|
109
|
+
free) · **46 per clip** for a generated move · **free** for a library search
|
|
110
|
+
(1 credit = $0.01). `--texture 8k` adds 6, `--no-ultra`
|
|
111
|
+
takes 6 off. Live prices and your balance: `npx genex doctor`.
|
|
81
112
|
|
|
82
113
|
## Waiting
|
|
83
114
|
|