@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/cli-demo",
3
- "version": "1.19.0-dev.601",
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
- rig: "meshy-biped";
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 first produces an unremeshed high-detail model. Show its
105
- front, back, left, and right views and report its measured face count.
106
- Preserve that model in R2. The 10,000-face triangle remesh—not the
107
- high-detail source—is rigged and animated. In the default lane, proceed to
108
- the remesh directly; when the player explicitly requested a custom character,
109
- ask for their explicit approval first. (For the custom lane's approvals, use
104
+ Meshy 7 Image-to-3D (Ultra, 4k textures by default) first produces an
105
+ unremeshed high-detail model. Show its front, back, left, and right views and
106
+ report its measured face count. Preserve that model in R2. A triangle remesh
107
+ at the face budget you approve—not the high-detail source—is rigged and
108
+ animated. In the default lane, proceed to the remesh directly; when the player
109
+ explicitly requested a custom character, ask for their explicit approval
110
+ first. (For the custom lane's approvals, use
110
111
  your question tool when you have one; if you have none, a short numbered list
111
112
  in chat.)
112
113
 
@@ -122,10 +123,10 @@ npx genex character finalize <preview-id> \
122
123
  --animation <action-id>
123
124
  ```
124
125
 
125
- `--animation` is repeatable. Finalization uses Meshy 6, creates the approved
126
- 10k triangle remesh, rigs it, adds the immutable preview-reviewed neutral-v3
127
- idle/walk/run/crouch/jump controller pack, and stores the source, remesh, rig,
128
- and clips at permanent Genex asset URLs. It prints the complete Genex-credit
126
+ `--animation` is repeatable. Finalization creates the approved triangle
127
+ remesh from the Meshy 7 preview, rigs it, adds the immutable preview-reviewed
128
+ neutral-v3 idle/walk/run/crouch/jump controller pack, and stores the source,
129
+ remesh, rig, and clips at permanent Genex asset URLs. It prints the complete Genex-credit
129
130
  quote before enqueueing. The Meshy API key remains server-side; never ask the
130
131
  user for one or call Meshy directly from game code.
131
132
 
@@ -133,18 +134,40 @@ Meshy's public API performs automatic rigging. The manual joint-marker step
133
134
  shown in Meshy Web is not exposed through that API, so do not claim that this
134
135
  part of the hosted workflow is reproduced.
135
136
 
136
- The legacy one-shot text workflow is explicit and does not masquerade as the
137
- reviewed image-first path:
137
+ The one-shot text workflow is explicit and does not masquerade as the
138
+ reviewed image-first path. It runs the same Meshy 7 (Ultra, 4k) — the only
139
+ thing it skips is the review:
138
140
 
139
141
  ```bash
140
142
  npx genex character "compact fantasy knight" --direct-text
141
143
  ```
142
144
 
145
+ ## The quality knobs are yours to set
146
+
147
+ Every lane runs Meshy 7 with Ultra and 4k textures unless you say otherwise,
148
+ and every knob is priced in the quote the command prints before enqueueing.
149
+ Choose per role, and say the choice in one line of chat:
150
+
151
+ - `--approve-remesh <faces>` (finalize) / `--polycount <faces>` (one shot):
152
+ the rigging copy's face budget, 10000-100000. **10000** for anything seen
153
+ in a crowd or at a distance; **20000-30000** for the player's body in a
154
+ third-person game; **50000+** only for a hero seen in close-up cutscenes.
155
+ Mobile budgets favour the low end. The number moves no cost.
156
+ - `--texture 2k|4k|8k` (preview / one shot): 4k is the default; 8k (+5
157
+ credits) only for a body the camera sits on in close-up; 2k for crowds.
158
+ - `--no-ultra` (preview / one shot): −5 credits and less surface detail —
159
+ crowd enemies and stand-ins, never the player's body.
160
+ - `--pose a-pose|t-pose` (one shot): the preferred rest pose; the other
161
+ stays the structural-QA fallback.
162
+ - `--height <metres>`: 0.5-3, default 1.7.
163
+
143
164
  Useful options:
144
165
 
145
166
  ```bash
146
- npx genex character finalize <preview-id> --user-approved --approve-remesh 10000 --height 1.7
167
+ npx genex character preview <concept-id> --candidate 2 --user-approved --texture 8k
168
+ npx genex character finalize <preview-id> --user-approved --approve-remesh 30000 --height 1.7
147
169
  npx genex character finalize <preview-id> --user-approved --approve-remesh 10000 --animation 466 --no-wait
170
+ npx genex character "market guard" --direct-text --polycount 10000 --no-ultra --texture 2k
148
171
  npx genex wait <generation-id>
149
172
  ```
150
173
 
@@ -153,10 +176,10 @@ npx genex wait <generation-id>
153
176
  compatibility path. The guided parity workflow always installs neutral-v3.
154
177
  `--no-wait` returns a generation id for `genex wait`; it does not create a
155
178
  second paid request. In the default lane, `--user-approved` and
156
- `--approve-remesh 10000` record the pick you made and announced after showing
179
+ `--approve-remesh <faces>` record the pick you made and announced after showing
157
180
  the real images. When the player explicitly requested a custom character,
158
181
  never add `--user-approved` until they have actually seen and selected the
159
- candidate, and never add `--approve-remesh 10000` until they have seen the
182
+ candidate, and never add `--approve-remesh <faces>` until they have seen the
160
183
  four high-detail views and measured face count.
161
184
 
162
185
  Before handoff, capture idle, walk, run, crouch-idle, crouch-move, and jump.
@@ -165,6 +188,35 @@ shrugging palms-up poses, permanently raised elbows, or a gait whose
165
188
  upper-body style contradicts the requested character. “No T-pose” is not
166
189
  an animation-quality check.
167
190
 
191
+ ## Import a character the player already has (`character import`)
192
+
193
+ When the player hands you a humanoid mesh — their own Blender character, a
194
+ bought asset, an export from another tool — **import it, never regenerate
195
+ it**. The upload is free; Uthana then auto-rigs it (one paid call, finger
196
+ joints included) and it becomes a character of theirs:
197
+
198
+ ```bash
199
+ npx genex character import ./assets/knight.glb --height 1.8
200
+ npx genex character animate <character-id> --locomotion --no-wait # the 16-clip walk/run set
201
+ npx genex controller character --character <character-id> # once locomotion lands
202
+ ```
203
+
204
+ What Uthana needs: a **biped humanoid** in a **T- or A-pose, feet on the
205
+ ground, facing +Z**, as a `.glb` under **30 MB** (textures are the bulk —
206
+ shrink them, not the mesh). Non-biped bodies go through `npx genex model
207
+ import` + `npx genex model rig` (7 body plans) instead. `--no-fingers` skips
208
+ finger joints when the hands are blobs (Uthana warns poor finger geometry
209
+ lowers rig quality).
210
+
211
+ An imported character is **Uthana-rigged**: `character animate` in plain
212
+ words, `--locomotion` and `--video` all work on it, and the manifest reads
213
+ `rig: "uthana-biped"`. The Meshy catalog (`--animation <id>`) and the
214
+ neutral-v3 controller pack do **not** apply — those are Meshy-rig clips — so
215
+ run `--locomotion` before installing the controller, or the body stands
216
+ still. `--texture`, `--no-ultra`, `--pose` and `--polycount` are Meshy
217
+ generation knobs and are refused here: an import keeps the mesh exactly as it
218
+ is.
219
+
168
220
  ## Search first; use action IDs
169
221
 
170
222
  ```bash
@@ -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
- | 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` |
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. Run independent planned generations with
199
- `--no-wait`, scaffold while they land, and preserve their IDs, URLs, and
200
- wiring state.
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. The 10,000-face triangle remesh—not the high-detail
361
- source—is rigged and animated. In the default lane, the pick authorizes that
362
- remesh:
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 10000 [--animation <action-id>…]`
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 10,000-face triangle remesh—not the high-detail
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). The result is a rigged GLB whose clips play on a standard
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 10,000-face triangle remesh—not the high-detail
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: **15** concept · **20** preview · **30** finalize · **50** one-shot
79
- character · **26 per clip** for a generated move · **free** for a library
80
- search. Live prices and your balance: `npx genex doctor`.
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