@genex-ai/cli-demo 1.34.3-dev.705 → 1.34.4-dev.706
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
CHANGED
|
@@ -18,6 +18,7 @@ genex texture "<prompt>" # generate a texture → prints an asset URL
|
|
|
18
18
|
genex image "<prompt>" # generate an image → prints an asset URL
|
|
19
19
|
genex video "<prompt>" # generate a video → prints an asset URL
|
|
20
20
|
genex character "<brief>" # generate 3 neutral-A-pose concept candidates
|
|
21
|
+
genex character --image ./front.jpg --image ./back.jpg # Meshy from your own views
|
|
21
22
|
genex character preview <concept-id> --candidate 1 --user-approved
|
|
22
23
|
genex character finalize <preview-id> --user-approved --approve-remesh 10000
|
|
23
24
|
genex character animate <id> --action <action-id> # add a same-rig Meshy action
|
|
@@ -164,6 +165,20 @@ one call (`image-main` + `image-alt-N` URLs) — pick the best instead of re-rol
|
|
|
164
165
|
|
|
165
166
|
## Meshy characters and animations
|
|
166
167
|
|
|
168
|
+
Use your own reference images directly with Meshy:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
genex character --image ./front.jpg --image ./back.jpg --texture 8k --polycount 100000 --pose t-pose --no-wait
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Repeat `--image` for 1-4 PNG/JPEG views of the same character, one view per
|
|
175
|
+
image. Local files may total up to 4 MB; Genex asset URLs are also accepted.
|
|
176
|
+
This starts a one-shot rigged character, skipping concept generation. An
|
|
177
|
+
optional brief labels the ledger entry; Meshy's image endpoints do not use it
|
|
178
|
+
as text conditioning. `creature --image` works with the same references and
|
|
179
|
+
keeps creature defaults (no controller pack). Do not combine `--image` with
|
|
180
|
+
`--direct-text`, guided subcommands or their approval flags.
|
|
181
|
+
|
|
167
182
|
The default Meshy lane is an approval-gated, three-command workflow through the
|
|
168
183
|
same authenticated credit, BullMQ/Redis, and R2 generation pipeline:
|
|
169
184
|
|
|
@@ -187,8 +202,9 @@ horizontal root/hip translation may be normalized for Rapier ownership.
|
|
|
187
202
|
`finalize`; requested actions run only after the controller pack succeeds.
|
|
188
203
|
`--height` and `--no-wait` carry through the approval flow. The guided lane
|
|
189
204
|
always installs neutral-v3. `genex character "<prompt>" --direct-text` is the
|
|
190
|
-
explicit compatibility path
|
|
191
|
-
`--no-controller-pack`,
|
|
205
|
+
explicit text-only compatibility path. Both one-shot paths (`--direct-text`
|
|
206
|
+
and `--image`) accept `--polycount` and `--no-controller-pack`, with a default
|
|
207
|
+
polycount of 10,000.
|
|
192
208
|
|
|
193
209
|
Search before spending:
|
|
194
210
|
|
package/dist/index.js
CHANGED
|
@@ -8748,6 +8748,14 @@ function buildGenOptions(kind, opts) {
|
|
|
8748
8748
|
}
|
|
8749
8749
|
async function runGenerate(kind, opts) {
|
|
8750
8750
|
const log = createLogger({ quiet: opts.quiet || opts.json });
|
|
8751
|
+
if (kind === "model" && opts.imageUrls !== void 0) {
|
|
8752
|
+
if (opts.imageUrls.length > 1) {
|
|
8753
|
+
log.error("genex model accepts one --image reference. Use character --image for multiple character views.");
|
|
8754
|
+
process.exitCode = 1;
|
|
8755
|
+
return;
|
|
8756
|
+
}
|
|
8757
|
+
opts = { ...opts, imageUrl: opts.imageUrls[0] ?? opts.imageUrl };
|
|
8758
|
+
}
|
|
8751
8759
|
let typedPrompt = opts.prompt?.trim();
|
|
8752
8760
|
if (!typedPrompt && kind === "model" && opts.imageUrl) {
|
|
8753
8761
|
const ref = opts.imageUrl.startsWith("data:") ? "local image" : opts.imageUrl;
|
|
@@ -20079,6 +20087,7 @@ async function resolveAdoptTarget(selector) {
|
|
|
20079
20087
|
return { ok: true, characterId, from: file };
|
|
20080
20088
|
}
|
|
20081
20089
|
async function runCharacterAdopt(opts) {
|
|
20090
|
+
if (refuseSubcommandImages(opts)) return;
|
|
20082
20091
|
const log = createLogger({ quiet: opts.quiet || opts.json });
|
|
20083
20092
|
const target = await resolveAdoptTarget(opts.characterId);
|
|
20084
20093
|
if (!target.ok) {
|
|
@@ -20139,6 +20148,7 @@ async function runCharacterAdopt(opts) {
|
|
|
20139
20148
|
});
|
|
20140
20149
|
}
|
|
20141
20150
|
async function runCharacterImport(opts) {
|
|
20151
|
+
if (refuseSubcommandImages(opts)) return;
|
|
20142
20152
|
const log = createLogger({ quiet: opts.quiet || opts.json });
|
|
20143
20153
|
const filePath = opts.importPath?.trim();
|
|
20144
20154
|
if (!filePath) {
|
|
@@ -20215,17 +20225,67 @@ async function runCharacterImport(opts) {
|
|
|
20215
20225
|
});
|
|
20216
20226
|
}
|
|
20217
20227
|
async function runCharacter(opts) {
|
|
20228
|
+
const references = opts.imageUrls ?? (opts.imageUrl === void 0 ? [] : [opts.imageUrl]);
|
|
20229
|
+
if (references.length > 0) {
|
|
20230
|
+
if (opts.directText) {
|
|
20231
|
+
fail2(opts, "--image cannot be combined with --direct-text. Omit --direct-text to build from the supplied references.");
|
|
20232
|
+
return;
|
|
20233
|
+
}
|
|
20234
|
+
if (opts.candidate !== void 0 || opts.userApproved !== void 0 || opts.approveRemesh !== void 0) {
|
|
20235
|
+
fail2(opts, "--image starts a one-shot character. --candidate / --user-approved / --approve-remesh belong to the guided preview/finalize flow; use --polycount for the reference character's face budget.");
|
|
20236
|
+
return;
|
|
20237
|
+
}
|
|
20238
|
+
const prepared = await prepareCharacterImages(references);
|
|
20239
|
+
if (!prepared.ok) {
|
|
20240
|
+
fail2(opts, prepared.error);
|
|
20241
|
+
return;
|
|
20242
|
+
}
|
|
20243
|
+
await runOneShotCharacter(opts, prepared.imageUrls);
|
|
20244
|
+
return;
|
|
20245
|
+
}
|
|
20218
20246
|
if (opts.directText) {
|
|
20219
|
-
await
|
|
20247
|
+
await runOneShotCharacter(opts);
|
|
20220
20248
|
return;
|
|
20221
20249
|
}
|
|
20222
20250
|
await runCharacterConcept(opts);
|
|
20223
20251
|
}
|
|
20252
|
+
async function prepareCharacterImages(references) {
|
|
20253
|
+
if (references.length > 4) return { ok: false, error: "--image accepts 1-4 references to the same character, one view per image." };
|
|
20254
|
+
const imageUrls = [];
|
|
20255
|
+
let inlineBytes = 0;
|
|
20256
|
+
for (const reference of references) {
|
|
20257
|
+
let image = reference.trim();
|
|
20258
|
+
if (!image) return { ok: false, error: "--image needs a PNG/JPEG file or asset URL." };
|
|
20259
|
+
if (!/^(https?:\/\/|data:)/i.test(image)) {
|
|
20260
|
+
if (!/\.(png|jpe?g)$/i.test(image)) return { ok: false, error: "Character --image references must be PNG or JPEG files." };
|
|
20261
|
+
const inlined = await inlineLocalImage(image, "--image");
|
|
20262
|
+
if (!inlined.ok) return inlined;
|
|
20263
|
+
image = inlined.dataUri;
|
|
20264
|
+
}
|
|
20265
|
+
if (/^data:/i.test(image)) {
|
|
20266
|
+
const match = /^data:image\/(png|jpeg);base64,([A-Za-z0-9+/]+={0,2})$/.exec(image);
|
|
20267
|
+
if (!match || match[2].length % 4 !== 0) return { ok: false, error: "Character --image data must be a base64 PNG or JPEG." };
|
|
20268
|
+
const bytes = Buffer.from(match[2], "base64");
|
|
20269
|
+
const isPng2 = bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]));
|
|
20270
|
+
const isJpeg = bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255;
|
|
20271
|
+
if (!(match[1] === "png" ? isPng2 : isJpeg)) return { ok: false, error: "Character --image contents must match their PNG/JPEG format." };
|
|
20272
|
+
inlineBytes += bytes.length;
|
|
20273
|
+
if (inlineBytes > 4 * 1024 * 1024) return { ok: false, error: "--image references exceed the combined 4 MB inline limit. Compress them or use Genex asset URLs." };
|
|
20274
|
+
}
|
|
20275
|
+
imageUrls.push(image);
|
|
20276
|
+
}
|
|
20277
|
+
return { ok: true, imageUrls };
|
|
20278
|
+
}
|
|
20224
20279
|
function fail2(opts, message, kind = "character") {
|
|
20225
20280
|
if (opts.json) writeJson({ kind, status: "failed", error: message });
|
|
20226
20281
|
else createLogger({ quiet: opts.quiet }).error(message);
|
|
20227
20282
|
process.exitCode = 1;
|
|
20228
20283
|
}
|
|
20284
|
+
function refuseSubcommandImages(opts) {
|
|
20285
|
+
if (opts.imageUrl === void 0 && !opts.imageUrls?.length) return false;
|
|
20286
|
+
fail2(opts, "--image starts a new reference character; it cannot be combined with a character subcommand.");
|
|
20287
|
+
return true;
|
|
20288
|
+
}
|
|
20229
20289
|
function requestedBuild(opts, actionIds) {
|
|
20230
20290
|
return {
|
|
20231
20291
|
actionIds,
|
|
@@ -20310,15 +20370,15 @@ async function runCharacterConcept(opts) {
|
|
|
20310
20370
|
return;
|
|
20311
20371
|
}
|
|
20312
20372
|
if (opts.polycount !== void 0) {
|
|
20313
|
-
fail2(opts, "--polycount is only available with --direct-text. The approval flow takes its face budget on `character finalize --approve-remesh <faces>`.", "character_concept");
|
|
20373
|
+
fail2(opts, "--polycount is only available with --direct-text or --image. The approval flow takes its face budget on `character finalize --approve-remesh <faces>`.", "character_concept");
|
|
20314
20374
|
return;
|
|
20315
20375
|
}
|
|
20316
20376
|
if (opts.texture !== void 0 || opts.ultra === false || opts.pose !== void 0) {
|
|
20317
|
-
fail2(opts, "--texture / --no-ultra / --pose apply to the paid mesh call: pass them to `character preview` (guided) or `character --direct-text` / `creature` (one shot). Concepts are images.", "character_concept");
|
|
20377
|
+
fail2(opts, "--texture / --no-ultra / --pose apply to the paid mesh call: pass them to `character preview` (guided) or `character --direct-text` / `character --image` / `creature` (one shot). Concepts are images.", "character_concept");
|
|
20318
20378
|
return;
|
|
20319
20379
|
}
|
|
20320
20380
|
if (opts.controllerPack === false) {
|
|
20321
|
-
fail2(opts, "--no-controller-pack is only available with --direct-text. The guided Meshy parity flow always installs neutral-v3.", "character_concept");
|
|
20381
|
+
fail2(opts, "--no-controller-pack is only available with --direct-text or --image. The guided Meshy parity flow always installs neutral-v3.", "character_concept");
|
|
20322
20382
|
return;
|
|
20323
20383
|
}
|
|
20324
20384
|
const resolved = resolveActionSelectors(opts.actions ?? []);
|
|
@@ -20363,13 +20423,26 @@ async function runCharacterConcept(opts) {
|
|
|
20363
20423
|
})
|
|
20364
20424
|
});
|
|
20365
20425
|
}
|
|
20366
|
-
async function
|
|
20426
|
+
async function runOneShotCharacter(opts, imageUrls) {
|
|
20367
20427
|
const log = createLogger({ quiet: opts.quiet || opts.json });
|
|
20368
|
-
const prompt = opts.prompt?.trim();
|
|
20428
|
+
const prompt = opts.prompt?.trim() || (imageUrls ? "Character from supplied reference images" : void 0);
|
|
20369
20429
|
if (!prompt) {
|
|
20370
20430
|
fail2(opts, 'Missing prompt. Usage: genex character "<prompt>" --direct-text.');
|
|
20371
20431
|
return;
|
|
20372
20432
|
}
|
|
20433
|
+
const badTexture = badCharacterTexture(opts);
|
|
20434
|
+
if (badTexture) {
|
|
20435
|
+
fail2(opts, badTexture);
|
|
20436
|
+
return;
|
|
20437
|
+
}
|
|
20438
|
+
if (opts.polycount !== void 0 && (!Number.isInteger(opts.polycount) || opts.polycount < REMESH_TARGET_MIN || opts.polycount > REMESH_TARGET_MAX)) {
|
|
20439
|
+
fail2(opts, `--polycount must be an integer between ${REMESH_TARGET_MIN} and ${REMESH_TARGET_MAX}.`);
|
|
20440
|
+
return;
|
|
20441
|
+
}
|
|
20442
|
+
if (opts.pose !== void 0 && !["a-pose", "t-pose"].includes(opts.pose)) {
|
|
20443
|
+
fail2(opts, "--pose must be a-pose or t-pose.");
|
|
20444
|
+
return;
|
|
20445
|
+
}
|
|
20373
20446
|
const resolved = resolveActionSelectors(opts.actions ?? []);
|
|
20374
20447
|
if (!resolved.ok) {
|
|
20375
20448
|
showAmbiguity(resolved.selector, resolved.candidates, log, opts.json);
|
|
@@ -20381,16 +20454,26 @@ async function runDirectTextCharacter(opts) {
|
|
|
20381
20454
|
return;
|
|
20382
20455
|
}
|
|
20383
20456
|
const controllerPack = opts.controllerPack !== false;
|
|
20384
|
-
const
|
|
20457
|
+
const generationOptions = {
|
|
20385
20458
|
actionIds: resolved.actionIds,
|
|
20386
|
-
controllerPack
|
|
20387
|
-
|
|
20459
|
+
controllerPack,
|
|
20460
|
+
...opts.height === void 0 ? {} : { heightMeters: opts.height },
|
|
20461
|
+
targetPolycount: opts.polycount ?? 1e4,
|
|
20462
|
+
...meshyQualityOptions(opts),
|
|
20463
|
+
...opts.pose === void 0 ? {} : { poseMode: opts.pose },
|
|
20464
|
+
...imageUrls === void 0 ? {} : { imageUrls }
|
|
20465
|
+
};
|
|
20466
|
+
const price = await quote(`${ctx.apiUrl}/api/characters/quote`, ctx.token, generationOptions);
|
|
20388
20467
|
if (!price) {
|
|
20389
20468
|
process.exitCode = 1;
|
|
20390
20469
|
return;
|
|
20391
20470
|
}
|
|
20471
|
+
if (imageUrls && price.referenceImageCount !== imageUrls.length) {
|
|
20472
|
+
fail2(opts, "This server did not confirm support for all character reference images. No generation was started. Update the Genex API to a version supporting character --image, then run this command.");
|
|
20473
|
+
return;
|
|
20474
|
+
}
|
|
20392
20475
|
if (!opts.json) {
|
|
20393
|
-
log.plain(c.bold("Direct-text character quote"));
|
|
20476
|
+
log.plain(c.bold(imageUrls ? "Reference character quote" : "Direct-text character quote"));
|
|
20394
20477
|
log.plain(` ${price.credits} Genex credits = base ${price.baseCredits} + actions ${price.animationCredits}`);
|
|
20395
20478
|
if (price.controllerPackKey) {
|
|
20396
20479
|
const version = price.controllerPackVersion === void 0 ? "" : ` v${price.controllerPackVersion}`;
|
|
@@ -20408,14 +20491,7 @@ async function runDirectTextCharacter(opts) {
|
|
|
20408
20491
|
token: ctx.token,
|
|
20409
20492
|
apiUrl: ctx.apiUrl,
|
|
20410
20493
|
quotedCredits: price.credits,
|
|
20411
|
-
generationOptions
|
|
20412
|
-
actionIds: resolved.actionIds,
|
|
20413
|
-
controllerPack,
|
|
20414
|
-
...opts.height === void 0 ? {} : { heightMeters: opts.height },
|
|
20415
|
-
targetPolycount: opts.polycount ?? 1e4,
|
|
20416
|
-
...meshyQualityOptions(opts),
|
|
20417
|
-
...opts.pose === void 0 ? {} : { poseMode: opts.pose }
|
|
20418
|
-
}
|
|
20494
|
+
generationOptions
|
|
20419
20495
|
});
|
|
20420
20496
|
}
|
|
20421
20497
|
var CHARACTER_TEXTURE_SIZES = ["2k", "4k", "8k"];
|
|
@@ -20433,6 +20509,7 @@ function badCharacterTexture(opts) {
|
|
|
20433
20509
|
return `--texture ${opts.texture} is a \`genex model\` tier. A character takes a texture SIZE: ${CHARACTER_TEXTURE_SIZES.join("|")} (default 4k).`;
|
|
20434
20510
|
}
|
|
20435
20511
|
async function runCharacterPreview(opts) {
|
|
20512
|
+
if (refuseSubcommandImages(opts)) return;
|
|
20436
20513
|
const log = createLogger({ quiet: opts.quiet || opts.json });
|
|
20437
20514
|
const conceptId = opts.conceptId?.trim();
|
|
20438
20515
|
if (!conceptId) {
|
|
@@ -20486,6 +20563,7 @@ async function runCharacterPreview(opts) {
|
|
|
20486
20563
|
});
|
|
20487
20564
|
}
|
|
20488
20565
|
async function runCharacterFinalize(opts) {
|
|
20566
|
+
if (refuseSubcommandImages(opts)) return;
|
|
20489
20567
|
const log = createLogger({ quiet: opts.quiet || opts.json });
|
|
20490
20568
|
const previewId = opts.previewId?.trim();
|
|
20491
20569
|
if (!previewId) {
|
|
@@ -20513,7 +20591,7 @@ async function runCharacterFinalize(opts) {
|
|
|
20513
20591
|
return;
|
|
20514
20592
|
}
|
|
20515
20593
|
if (opts.controllerPack === false) {
|
|
20516
|
-
fail2(opts, "--no-controller-pack is only available with --direct-text. Guided finalization requires neutral-v3.");
|
|
20594
|
+
fail2(opts, "--no-controller-pack is only available with --direct-text or --image. Guided finalization requires neutral-v3.");
|
|
20517
20595
|
return;
|
|
20518
20596
|
}
|
|
20519
20597
|
const resolved = resolveActionSelectors(opts.actions ?? []);
|
|
@@ -20583,6 +20661,7 @@ async function runCharacterFinalize(opts) {
|
|
|
20583
20661
|
});
|
|
20584
20662
|
}
|
|
20585
20663
|
async function runCharacterAnimate(opts) {
|
|
20664
|
+
if (refuseSubcommandImages(opts)) return;
|
|
20586
20665
|
const log = createLogger({ quiet: opts.quiet || opts.json });
|
|
20587
20666
|
const characterId = opts.characterId?.trim();
|
|
20588
20667
|
if (!characterId) {
|
|
@@ -23803,6 +23882,7 @@ ${c.bold("Usage")}
|
|
|
23803
23882
|
genex image "<prompt>" [options] Generate an image (PNG); prints a public asset URL.
|
|
23804
23883
|
genex video "<prompt>" [options] Generate a video (mp4); prints a public asset URL.
|
|
23805
23884
|
genex character "<brief>" Generate 3 character concepts for user selection.
|
|
23885
|
+
genex character --image <path|url> Build directly from 1-4 supplied views (repeat --image).
|
|
23806
23886
|
genex character preview <concept-id>
|
|
23807
23887
|
Generate an unremeshed Meshy 7 preview of one
|
|
23808
23888
|
explicitly user-approved concept candidate.
|
|
@@ -24050,6 +24130,10 @@ ${c.bold("Options for `list`")}
|
|
|
24050
24130
|
--auth-url <url> Override the auth site (used only if sign-in is needed).
|
|
24051
24131
|
|
|
24052
24132
|
${c.bold("Options for `character` / `animations search`")}
|
|
24133
|
+
--image <path|url> Build from supplied PNG/JPEG references; repeat up to 4 times.
|
|
24134
|
+
One view per image, same character; local files total \u22644 MB,
|
|
24135
|
+
or Genex asset URLs. Brief optional (ledger label only).
|
|
24136
|
+
Starts one shot; cannot combine with --direct-text or guided flags.
|
|
24053
24137
|
--animation <id|q> (character/finalize) add an action; repeatable. Ambiguous queries print
|
|
24054
24138
|
ranked action IDs instead of choosing silently.
|
|
24055
24139
|
--candidate <1|2|3> (character preview) selected concept candidate.
|
|
@@ -24060,15 +24144,15 @@ ${c.bold("Options for `character` / `animations search`")}
|
|
|
24060
24144
|
hero). The number IS the approval.
|
|
24061
24145
|
--direct-text One-shot path: skip concept/preview approval and generate
|
|
24062
24146
|
directly from text (defaults to a 10,000-face target).
|
|
24063
|
-
--no-controller-pack (character
|
|
24147
|
+
--no-controller-pack (character one shot) skip the validated locomotion pack.
|
|
24064
24148
|
--height <meters> (character) target character height, 0.5-3 meters.
|
|
24065
|
-
--polycount <count> (character
|
|
24149
|
+
--polycount <count> (character one shot / creature) target 10000-100000 polygons.
|
|
24066
24150
|
--texture <res> (character/creature/preview) texture size 2k | 4k (default) | 8k
|
|
24067
24151
|
(+5 credits). Meshy 7 on every lane.
|
|
24068
24152
|
--no-ultra (character/creature/preview) skip Meshy Ultra (\u22125 credits, less
|
|
24069
24153
|
surface detail).
|
|
24070
24154
|
--pose <a-pose|t-pose>
|
|
24071
|
-
(character
|
|
24155
|
+
(character one shot / creature) preferred rest pose; the
|
|
24072
24156
|
other stays the QA fallback.
|
|
24073
24157
|
--no-fingers (character import) skip finger joints in the Uthana rig.
|
|
24074
24158
|
--no-wait (character/preview/finalize/animate) enqueue and return a generation id.
|
|
@@ -24141,6 +24225,7 @@ ${c.bold("Examples")}
|
|
|
24141
24225
|
genex character preview <concept-id> --candidate 2 --user-approved
|
|
24142
24226
|
genex character finalize <preview-id> --user-approved --approve-remesh 10000 --animation 466
|
|
24143
24227
|
genex character "stylized sci-fi courier" --direct-text --no-wait
|
|
24228
|
+
genex character --image ./front.jpg --image ./back.jpg --texture 8k --polycount 100000 --no-wait
|
|
24144
24229
|
genex character animate <character-id> --action <action-id>
|
|
24145
24230
|
genex character animate <character-id> "overhead slam" "parry and recover" --no-wait
|
|
24146
24231
|
genex character animate <character-id> --locomotion --no-wait
|
|
@@ -24193,6 +24278,7 @@ ${c.bold("Characters")}
|
|
|
24193
24278
|
The rigged, game-ready character. ${cr("character_finalize")}
|
|
24194
24279
|
genex character "<brief>" --direct-text
|
|
24195
24280
|
One shot, no approval steps. ${cr("character")}
|
|
24281
|
+
genex character --image <path|url> One shot from 1-4 supplied PNG/JPEG views.
|
|
24196
24282
|
genex creature "<desc>" A rigged enemy (biped-shaped bodies). ${String(CREATURE_TYPICAL_CREDITS).padStart(3)} cr
|
|
24197
24283
|
genex character import <file.glb> Your own humanoid mesh (or a genex model), ${cr("character_import")}
|
|
24198
24284
|
auto-rigged by Uthana; the upload is free.
|
|
@@ -24253,6 +24339,11 @@ ${c.bold("Make one")}
|
|
|
24253
24339
|
genex character finalize <preview-id> --user-approved --approve-remesh <faces>
|
|
24254
24340
|
The rigged, game-ready character (step 3).
|
|
24255
24341
|
genex character "<brief>" --direct-text One shot, no approval steps.
|
|
24342
|
+
genex character --image <path|url> [--image \u2026] One shot from 1-4 supplied PNG/JPEG views.
|
|
24343
|
+
Local files total \u22644 MB or Genex asset URLs.
|
|
24344
|
+
One view per image, same character. Optional
|
|
24345
|
+
brief is a ledger label, not text conditioning.
|
|
24346
|
+
Do not combine with --direct-text or guided flags.
|
|
24256
24347
|
genex creature "<desc>" The one-shot lane with enemy defaults (no controller pack).
|
|
24257
24348
|
genex character import <file.glb> [--height <m>] [--no-fingers]
|
|
24258
24349
|
Your own humanoid mesh \u2014 or a \`genex model\` GLB \u2014
|
|
@@ -24748,6 +24839,22 @@ function parseArgs(argv) {
|
|
|
24748
24839
|
}
|
|
24749
24840
|
}
|
|
24750
24841
|
}
|
|
24842
|
+
const imageCount = parsed.options.imageUrls?.length ?? 0;
|
|
24843
|
+
if (imageCount > 0) {
|
|
24844
|
+
if (parsed.command === "model" && imageCount > 1) {
|
|
24845
|
+
parsed.error = "genex model accepts one --image reference. Use character --image for multiple character views.";
|
|
24846
|
+
} else if (parsed.command === "character" || parsed.command === "creature") {
|
|
24847
|
+
if (["preview", "finalize", "import", "animate", "motions", "adopt"].includes(parsed.options.name ?? "")) {
|
|
24848
|
+
parsed.error = "--image starts a new reference character; it cannot be combined with a character subcommand.";
|
|
24849
|
+
} else if (imageCount > 4) {
|
|
24850
|
+
parsed.error = "--image accepts 1-4 references to the same character, one view per image.";
|
|
24851
|
+
} else if (parsed.options.directText) {
|
|
24852
|
+
parsed.error = "--image cannot be combined with --direct-text. Omit --direct-text to build from the supplied references.";
|
|
24853
|
+
} else if (parsed.options.candidate !== void 0 || parsed.options.userApproved !== void 0 || parsed.options.approveRemesh !== void 0) {
|
|
24854
|
+
parsed.error = "--image cannot be combined with guided --candidate / --user-approved / --approve-remesh flags. Use --polycount for the reference character's face budget.";
|
|
24855
|
+
}
|
|
24856
|
+
}
|
|
24857
|
+
}
|
|
24751
24858
|
return parsed;
|
|
24752
24859
|
}
|
|
24753
24860
|
function applyValueFlag(options, flag, value) {
|
|
@@ -25025,7 +25132,9 @@ function applyValueFlag(options, flag, value) {
|
|
|
25025
25132
|
options.refs = [...options.refs ?? [], value];
|
|
25026
25133
|
break;
|
|
25027
25134
|
case "--image":
|
|
25135
|
+
if (!value.trim() || value.startsWith("--")) throw new Error("Missing value for --image");
|
|
25028
25136
|
options.imageUrl = value;
|
|
25137
|
+
(options.imageUrls ??= []).push(value);
|
|
25029
25138
|
break;
|
|
25030
25139
|
case "--texture":
|
|
25031
25140
|
if (!TEXTURE_FLAG_VALUES.includes(value)) {
|
|
@@ -25267,7 +25376,7 @@ async function main() {
|
|
|
25267
25376
|
await runCharacter({
|
|
25268
25377
|
...parsed.options,
|
|
25269
25378
|
prompt: parsed.options.name,
|
|
25270
|
-
directText: true,
|
|
25379
|
+
directText: parsed.options.imageUrls?.length ? parsed.options.directText : true,
|
|
25271
25380
|
controllerPack: false
|
|
25272
25381
|
});
|
|
25273
25382
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genex-ai/cli-demo",
|
|
3
|
-
"version": "1.34.
|
|
3
|
+
"version": "1.34.4-dev.706",
|
|
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": {
|
|
@@ -52,6 +52,24 @@ no code to rewrite, which is exactly why there is no excuse to skip it.
|
|
|
52
52
|
selection, then an explicit approval of the separate 10,000-face
|
|
53
53
|
remesh. Never compress these two stops for a user-initiated ask.
|
|
54
54
|
|
|
55
|
+
## Build from supplied reference images
|
|
56
|
+
|
|
57
|
+
When the user supplies a character reference to reproduce, use it directly:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx genex character --image ./front.jpg --image ./back.jpg --texture 8k --polycount 100000 --pose t-pose --no-wait
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Repeat `--image` for 1-4 PNG/JPEG views of the same character, one view per
|
|
64
|
+
image. Split a contact sheet into individual views first. Local files total
|
|
65
|
+
at most 4 MB; Genex asset URLs also work. Meshy uses these images directly,
|
|
66
|
+
skipping concept generation, then remeshes and rigs the result. An optional
|
|
67
|
+
brief is only a ledger label, not text conditioning. Do not combine with
|
|
68
|
+
`--direct-text`, guided subcommands or their approval flags. One-shot quality,
|
|
69
|
+
pose, face-budget and controller options apply; `creature --image` omits the
|
|
70
|
+
controller pack by default. The following guided flow is for a new look from
|
|
71
|
+
text, when no supplied images already define the character.
|
|
72
|
+
|
|
55
73
|
## Generate a controller-ready character
|
|
56
74
|
|
|
57
75
|
Before generating a Meshy character, discuss two or three visual directions.
|
|
@@ -172,8 +190,8 @@ npx genex wait <generation-id>
|
|
|
172
190
|
```
|
|
173
191
|
|
|
174
192
|
`--animation <id-or-query>` is repeatable on `finalize`.
|
|
175
|
-
`--no-controller-pack` is available
|
|
176
|
-
|
|
193
|
+
`--no-controller-pack` is available with the one-shot `--direct-text` and
|
|
194
|
+
`--image` paths. The guided parity workflow always installs neutral-v3.
|
|
177
195
|
`--no-wait` returns a generation id for `genex wait`; it does not create a
|
|
178
196
|
second paid request. In the default lane, `--user-approved` and
|
|
179
197
|
`--approve-remesh <faces>` record the pick you made and announced after showing
|
|
@@ -12,9 +12,26 @@ For a prop, vehicle or building, use `$genex-tool-model`. For a non-humanoid
|
|
|
12
12
|
body plan (quadruped, flier, serpent) use that skill's `model rig` lane — this
|
|
13
13
|
one produces biped-shaped bodies.
|
|
14
14
|
|
|
15
|
+
## From the user's reference images
|
|
16
|
+
|
|
17
|
+
When the user supplies a character reference, send those images to Meshy:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx genex character --image ./front.jpg --image ./back.jpg --texture 8k --polycount 100000 --pose t-pose --no-wait
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`--image` is repeatable, 1-4 PNG/JPEG views of the same character, one view per
|
|
24
|
+
image. Local files must total at most 4 MB; Genex asset URLs also work. Split a
|
|
25
|
+
contact sheet into individual views first. This is one shot: it skips concept
|
|
26
|
+
generation and rigs the reference-derived mesh. An optional brief is only a
|
|
27
|
+
ledger label, not text conditioning. Do not add `--direct-text`, guided
|
|
28
|
+
subcommands or their approval flags. Ultra is on by default; select texture
|
|
29
|
+
size and face budget for the requested quality. `creature --image` uses this
|
|
30
|
+
same route without the player controller pack.
|
|
31
|
+
|
|
15
32
|
## The guided flow (three steps, one approval each)
|
|
16
33
|
|
|
17
|
-
Use this when
|
|
34
|
+
Use this when creating a new look from text and a person is choosing it:
|
|
18
35
|
|
|
19
36
|
```bash
|
|
20
37
|
npx genex character "stylized sci-fi courier, practical layered clothing"
|