@genex-ai/cli-demo 1.35.0-dev.736 → 1.35.0-dev.737
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/index.js
CHANGED
|
@@ -916,12 +916,18 @@ var TOOLS_CONTRACT_OFFER = `5. **When the game is built and playable \u2014 neve
|
|
|
916
916
|
var TOOLS_CONTRACT_HOSTED_LAWS = `5. **This game is hosted on Genex now, and publishing is glue \u2014 never a rebuild.** The game ships exactly as the user built it: \`initEmbed()\` first in the boot code (the \`genex-threejs-embed-auth\` card has the call; the renderer draws before any \`await waitForPlayer()\`), a static build into \`dist/\` with relative asset paths, then \`npx genex preview\`. Never restructure, reformat or "improve" the game to ship it, never scaffold a new app around it, and never start a design document or a build plan for it \u2014 the user's own process is theirs. Load the \`genex-tool-publish\` card before the first preview; it owns the vocabulary, the links and the limits.
|
|
917
917
|
6. **Ship first, then report.** \`preview\` prints a preflight \u2014 phone memory, a missing volume slider, an asset nobody wired, a viewport line. It never blocks a deploy, so push the build as it is, hand over the link, THEN relay each preflight line to the user in one plain sentence with an offer to fix it, and fix one only on their yes. The preflight is a report for the user, not a to-do list for you.
|
|
918
918
|
7. **The link is the game's page, and there are two versions.** After every preview give the user \`<dashboard>/draft/<slug>\` \u2014 \`dashboardOrigins[0]\` and \`slug\` from \`.genex/project.json\` \u2014 never localhost, a file path or the bare play origin. \`preview\` updates the draft and never touches what players are on; the first release is \`npx genex publish\` (it lists the game); after that "publish it", "update it" and "yes" all mean \`npx genex promote\` \u2014 the exact draft build, no rebuild. Ask once per round of work, in one line, and keep working while you wait.`;
|
|
919
|
+
var TOOLS_CONTRACT_LLM_OFFER = `A model running while people play is built into the Genex platform \u2014 the player pays, with Genex coins or their own Claude/ChatGPT subscription, and approves it on a Genex sheet; your game just calls \`generate()\`. Want it that way?`;
|
|
920
|
+
function toolsContractLlmLaw(n, hosted) {
|
|
921
|
+
const onYes = hosted ? "On a yes, load `$genex-tool-llm` and then `$genex-llm-in-games`, which owns the build." : "On a yes, load `$genex-tool-llm`, which owns the rest: it checks the lane with `npx genex llm models` first, then runs `npx genex init --convert` (a hosted game is a static browser build \u2014 a local server holding a key can never ship).";
|
|
922
|
+
return `${n}. **A model running while people PLAY is a platform feature \u2014 never something you wire onto the user's own meter.** When a request implies one (NPCs that talk or decide in their own words, content written from what the player types, a prompt box in the game, "let the player pick a model"), recognise it, say in ONE line: "${TOOLS_CONTRACT_LLM_OFFER}" \u2014 then ASK and wait. ${onYes} On a no, build the authored version instead. Either way, never ship a game that calls a model on a key or an account of the user's own: every visitor would spend their money with nobody approving it, and the credential is readable in the bundle. Player-funded generation is text and JSON only \u2014 3D, images, video and audio stay the asset lanes above, on the user's meter.`;
|
|
923
|
+
}
|
|
919
924
|
function toolsContractBlock(opts) {
|
|
920
925
|
return `${CONTRACT_BEGIN}
|
|
921
926
|
${TOOLS_CONTRACT_HEAD}${opts.hosted ? " This game is also hosted on Genex: `preview` \xB7 `promote` \xB7 `publish` \xB7 `rollback` \xB7 `rename` work here (the `genex-tool-publish` card owns them)." : ""}
|
|
922
927
|
|
|
923
928
|
${TOOLS_CONTRACT_LAWS_1_TO_4}
|
|
924
929
|
${opts.hosted ? TOOLS_CONTRACT_HOSTED_LAWS : TOOLS_CONTRACT_OFFER}
|
|
930
|
+
${toolsContractLlmLaw(opts.hosted ? 8 : 6, opts.hosted)}
|
|
925
931
|
${CONTRACT_END}
|
|
926
932
|
`;
|
|
927
933
|
}
|
|
@@ -1227,13 +1233,18 @@ async function hasGenexSkills(skillsDir) {
|
|
|
1227
1233
|
}
|
|
1228
1234
|
}
|
|
1229
1235
|
var TOOL_SKILL_PREFIX = "genex-tool-";
|
|
1230
|
-
var HOSTED_TOOL_SKILLS = [
|
|
1236
|
+
var HOSTED_TOOL_SKILLS = [
|
|
1237
|
+
"genex-tool-publish",
|
|
1238
|
+
"genex-threejs-embed-auth",
|
|
1239
|
+
"genex-llm-in-games"
|
|
1240
|
+
];
|
|
1231
1241
|
var REMIX_EXCLUDED_SKILLS = [
|
|
1232
1242
|
"genex-game-director",
|
|
1233
1243
|
"genex-getting-started",
|
|
1234
1244
|
"genex-tool-audio",
|
|
1235
1245
|
"genex-tool-character",
|
|
1236
1246
|
"genex-tool-image",
|
|
1247
|
+
"genex-tool-llm",
|
|
1237
1248
|
"genex-tool-model",
|
|
1238
1249
|
"genex-tool-publish",
|
|
1239
1250
|
"genex-tool-texture",
|
|
@@ -23278,8 +23289,13 @@ import fs33 from "fs/promises";
|
|
|
23278
23289
|
import path34 from "path";
|
|
23279
23290
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
23280
23291
|
var SUBS3 = ["models", "bench", "price"];
|
|
23281
|
-
var LLM_BENCH_APPROVAL_REQUIRED = "STOP: `genex llm bench` runs the real model and spends
|
|
23292
|
+
var LLM_BENCH_APPROVAL_REQUIRED = "STOP: `genex llm bench` runs the real model and spends YOUR OWN coin \u2014 your wallet, not a player's, and one this build's asset allowance cannot see. Re-run with --max-coins <n> --user-approved only after the person at the keyboard agreed to the number.";
|
|
23282
23293
|
var LLM_LANE_OFF_LINE = "The runtime LLM lane is off on this stand \u2014 in-game generate() answers 404 here, and nothing can be benchmarked.";
|
|
23294
|
+
var LLM_TOOLS_CONVERT_HINT = [
|
|
23295
|
+
"In-game model calls need a hosted game. This folder is a Genex Tools workspace, so nothing here",
|
|
23296
|
+
"can call a model at play time yet \u2014 and the player, not you, is who pays for one that does.",
|
|
23297
|
+
"Ask the user first; on their yes run `npx genex init --convert`, then load the genex-tool-llm card."
|
|
23298
|
+
];
|
|
23283
23299
|
var LLM_BENCH_FILE = ".genex/llm-bench.json";
|
|
23284
23300
|
var DEFAULT_BENCH_SAMPLES = 3;
|
|
23285
23301
|
var DEFAULT_SAMPLE_TIMEOUT_SEC = 180;
|
|
@@ -23345,6 +23361,8 @@ async function runLlm(opts = {}) {
|
|
|
23345
23361
|
await reportSavedPrice(cwd, opts, log);
|
|
23346
23362
|
return;
|
|
23347
23363
|
}
|
|
23364
|
+
const ws = await resolveWorkspace(cwd);
|
|
23365
|
+
const toolsOnly = ws.mode === "tools" && !ws.hosted;
|
|
23348
23366
|
if (sub === "bench") {
|
|
23349
23367
|
if (opts.maxCoins === void 0 || opts.userApproved !== true) {
|
|
23350
23368
|
fail4("llm bench", LLM_BENCH_APPROVAL_REQUIRED);
|
|
@@ -23362,10 +23380,13 @@ async function runLlm(opts = {}) {
|
|
|
23362
23380
|
fail4("llm bench", "Pass --json-output or --text, not both.");
|
|
23363
23381
|
return;
|
|
23364
23382
|
}
|
|
23365
|
-
|
|
23366
|
-
if (ws.mode === "tools" && !ws.hosted) {
|
|
23383
|
+
if (toolsOnly) {
|
|
23367
23384
|
if (opts.json) writeJsonLine({ command: "llm bench", status: "failed", error: "`genex llm bench` is not part of Genex Tools." });
|
|
23368
|
-
else
|
|
23385
|
+
else {
|
|
23386
|
+
reportPlatformRefused(log, "llm bench");
|
|
23387
|
+
log.plain(` ${c.cyan("\u2192")} A model that runs while people PLAY is a platform feature: the player pays and approves it.`);
|
|
23388
|
+
log.plain(` Ask the user, and on their yes: ${c.cyan("npx genex init --convert")} \u2014 then the ${c.cyan("genex-tool-llm")} card.`);
|
|
23389
|
+
}
|
|
23369
23390
|
process.exitCode = 1;
|
|
23370
23391
|
return;
|
|
23371
23392
|
}
|
|
@@ -23408,12 +23429,12 @@ async function runLlm(opts = {}) {
|
|
|
23408
23429
|
await writeUserToken(token, opts.envPath, apiUrl);
|
|
23409
23430
|
}
|
|
23410
23431
|
if (sub === "models") {
|
|
23411
|
-
await reportModels(apiUrl, token, opts, log);
|
|
23432
|
+
await reportModels(apiUrl, token, opts, log, toolsOnly);
|
|
23412
23433
|
return;
|
|
23413
23434
|
}
|
|
23414
23435
|
await runBench({ apiUrl, token, projectId: meta.id, cwd, opts, log });
|
|
23415
23436
|
}
|
|
23416
|
-
async function reportModels(apiUrl, token, opts, log) {
|
|
23437
|
+
async function reportModels(apiUrl, token, opts, log, toolsOnly = false) {
|
|
23417
23438
|
const probe = await apiFetch(`${apiUrl}/api/runtime/models`, {
|
|
23418
23439
|
headers: { Authorization: `Bearer ${token}` }
|
|
23419
23440
|
}).catch(() => null);
|
|
@@ -23435,7 +23456,8 @@ async function reportModels(apiUrl, token, opts, log) {
|
|
|
23435
23456
|
enabled: null,
|
|
23436
23457
|
models: null,
|
|
23437
23458
|
externalProviders: null,
|
|
23438
|
-
recommendedDeclaredHeadroomBps: null
|
|
23459
|
+
recommendedDeclaredHeadroomBps: null,
|
|
23460
|
+
convertHint: toolsOnly ? LLM_TOOLS_CONVERT_HINT.join(" ") : null
|
|
23439
23461
|
});
|
|
23440
23462
|
}
|
|
23441
23463
|
process.exitCode = 1;
|
|
@@ -23450,22 +23472,33 @@ async function reportModels(apiUrl, token, opts, log) {
|
|
|
23450
23472
|
enabled: lane.state === "live",
|
|
23451
23473
|
models: lane.models,
|
|
23452
23474
|
externalProviders: lane.externalProviders,
|
|
23453
|
-
recommendedDeclaredHeadroomBps: lane.recommendedDeclaredHeadroomBps
|
|
23475
|
+
recommendedDeclaredHeadroomBps: lane.recommendedDeclaredHeadroomBps,
|
|
23476
|
+
// Always present, `null` off a tools workspace — the same
|
|
23477
|
+
// every-key-always-present rule the other keys follow, so a reader can
|
|
23478
|
+
// tell "no hint" from "a CLI that predates the hint".
|
|
23479
|
+
convertHint: toolsOnly ? LLM_TOOLS_CONVERT_HINT.join(" ") : null
|
|
23454
23480
|
});
|
|
23455
23481
|
if (lane.state === "unknown") process.exitCode = 1;
|
|
23456
23482
|
return;
|
|
23457
23483
|
}
|
|
23484
|
+
const printConvertHint = () => {
|
|
23485
|
+
if (!toolsOnly) return;
|
|
23486
|
+
log.plain("");
|
|
23487
|
+
for (const line of LLM_TOOLS_CONVERT_HINT) log.dim(` ${line}`);
|
|
23488
|
+
};
|
|
23458
23489
|
log.plain(c.bold("genex llm models"));
|
|
23459
23490
|
log.dim(` ${apiUrl}`);
|
|
23460
23491
|
log.plain("");
|
|
23461
23492
|
if (lane.state === "off") {
|
|
23462
23493
|
log.plain(` ${LLM_LANE_OFF_LINE}`);
|
|
23463
23494
|
log.dim(" Build the feature without an in-game model, or ask the operator to turn the lane on.");
|
|
23495
|
+
printConvertHint();
|
|
23464
23496
|
return;
|
|
23465
23497
|
}
|
|
23466
23498
|
if (lane.state === "unavailable") {
|
|
23467
23499
|
log.warn(" This stand has the lane on but cannot serve its model list.");
|
|
23468
23500
|
log.dim(" That is a server configuration problem, not yours \u2014 nothing here can be benchmarked yet.");
|
|
23501
|
+
printConvertHint();
|
|
23469
23502
|
return;
|
|
23470
23503
|
}
|
|
23471
23504
|
if (lane.state === "unknown" || !lane.models) {
|
|
@@ -23490,6 +23523,10 @@ async function reportModels(apiUrl, token, opts, log) {
|
|
|
23490
23523
|
} else {
|
|
23491
23524
|
log.dim(` Recommended headroom over benchmarked coins on this stand: ${lane.recommendedDeclaredHeadroomBps} bps.`);
|
|
23492
23525
|
}
|
|
23526
|
+
if (toolsOnly) {
|
|
23527
|
+
printConvertHint();
|
|
23528
|
+
return;
|
|
23529
|
+
}
|
|
23493
23530
|
log.dim(" Those per-million rates are the PROVIDER's; what your game is charged is the platform");
|
|
23494
23531
|
log.dim(` tariff on top, which only a real call reveals: ${c.cyan('genex llm bench "<prompt>" --max-coins <n> --user-approved')}`);
|
|
23495
23532
|
}
|
|
@@ -23935,7 +23972,7 @@ async function runDoctor(opts = {}) {
|
|
|
23935
23972
|
}
|
|
23936
23973
|
rows.push(termsRow(authState, legal));
|
|
23937
23974
|
rows.push(creditsRow(authState, credits));
|
|
23938
|
-
rows.push(runtimeRow(authState, runtime));
|
|
23975
|
+
rows.push(runtimeRow(authState, runtime, mode === "tools"));
|
|
23939
23976
|
if (opts.json) {
|
|
23940
23977
|
process.stdout.write(
|
|
23941
23978
|
JSON.stringify(
|
|
@@ -24096,15 +24133,16 @@ function creditsRow(state, info) {
|
|
|
24096
24133
|
fix: info.balance <= 0 ? "Out of credits \u2014 generation is refused until the refill or a top-up." : void 0
|
|
24097
24134
|
};
|
|
24098
24135
|
}
|
|
24099
|
-
function runtimeRow(state, lane) {
|
|
24136
|
+
function runtimeRow(state, lane, toolsOnly = false) {
|
|
24100
24137
|
if (state !== "ok") return { label: "Runtime", value: "\u2014 (sign in first)" };
|
|
24138
|
+
const convertFix = "In-game calls need a hosted game, and the PLAYER pays for them \u2014 ask the user, then `npx genex init --convert`; the genex-tool-llm card has the offer to make.";
|
|
24101
24139
|
switch (lane?.state) {
|
|
24102
24140
|
case "live": {
|
|
24103
24141
|
const n = lane.models?.length ?? 0;
|
|
24104
24142
|
return {
|
|
24105
24143
|
label: "Runtime",
|
|
24106
24144
|
value: `in-game LLM lane live \xB7 ${n} model${n === 1 ? "" : "s"}`,
|
|
24107
|
-
fix: 'Price a call before a game declares one: `npx genex llm bench "<prompt>" --max-coins <n> --user-approved`.'
|
|
24145
|
+
fix: toolsOnly ? convertFix : 'Price a call before a game declares one: `npx genex llm bench "<prompt>" --max-coins <n> --user-approved`.'
|
|
24108
24146
|
};
|
|
24109
24147
|
}
|
|
24110
24148
|
case "off":
|
|
@@ -26729,8 +26767,8 @@ ${c.bold("Usage")}
|
|
|
26729
26767
|
Run the real model <n> times through the development
|
|
26730
26768
|
lane and report what each attempt was CHARGED. Refused
|
|
26731
26769
|
without both flags, before any network call: this spends
|
|
26732
|
-
COIN, a wallet the build's asset allowance
|
|
26733
|
-
Needs a folder linked to a game you own.
|
|
26770
|
+
YOUR OWN COIN, a wallet the build's asset allowance
|
|
26771
|
+
cannot see. Needs a folder linked to a game you own.
|
|
26734
26772
|
genex llm price [--json] The recommendation from the last bench in this folder.
|
|
26735
26773
|
Reads a file; spends nothing.
|
|
26736
26774
|
|
|
@@ -26739,8 +26777,9 @@ ${c.bold("Bench options")}
|
|
|
26739
26777
|
--samples <n> How many real attempts (default ${DEFAULT_BENCH_SAMPLES}). More samples, better p95.
|
|
26740
26778
|
--schema <file> A JSON file holding the output schema; implies JSON output.
|
|
26741
26779
|
--json-output Ask for JSON without a schema. --text Ask for text (the default).
|
|
26742
|
-
--max-coins <n> The per-attempt ceiling
|
|
26743
|
-
|
|
26780
|
+
--max-coins <n> The per-attempt ceiling YOU approved \u2014 a bench runs on your own coin,
|
|
26781
|
+
never a player's. The run's worst case is that number times --samples,
|
|
26782
|
+
and it is printed before anything starts.
|
|
26744
26783
|
--timeout <seconds> Bounds the wait for each attempt.
|
|
26745
26784
|
--json One machine-readable object; every key is always present, null when
|
|
26746
26785
|
the CLI could not learn it.
|
|
@@ -26749,10 +26788,12 @@ ${c.bold("Why a benchmark and not an estimate")}
|
|
|
26749
26788
|
\`estimateCoins\` is a PRICE, not a guess: declaring it charges it, in full, even when the
|
|
26750
26789
|
attempt fails, is cancelled, or stops at its budget. And three layers sit between the
|
|
26751
26790
|
provider's rate card and that number \u2014 the provider's cost, the platform's tariff (already
|
|
26752
|
-
inside every charged coin), and your headroom.
|
|
26753
|
-
|
|
26754
|
-
|
|
26755
|
-
|
|
26791
|
+
inside every charged coin), and your headroom. The bench itself is billed to YOU, on the
|
|
26792
|
+
development lane; the player-funded lane is what the published game uses. Adding a margin
|
|
26793
|
+
to the provider's rate silently drops the tariff and under-prices every call, so the
|
|
26794
|
+
recommendation is built from CHARGED COINS and the headroom comes from the server. A stand
|
|
26795
|
+
that serves no headroom gets no recommendation, because the multiplier is not the CLI's to
|
|
26796
|
+
invent.
|
|
26756
26797
|
|
|
26757
26798
|
Results land in ${LLM_BENCH_FILE} \u2014 gitignored, machine-local, re-read by \`genex llm price\`.
|
|
26758
26799
|
`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genex-ai/cli-demo",
|
|
3
|
-
"version": "1.35.0-dev.
|
|
3
|
+
"version": "1.35.0-dev.737",
|
|
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": {
|
|
@@ -243,11 +243,15 @@ Nothing to fix in the game: ship the fallback and say so.
|
|
|
243
243
|
**Nothing opens when the player clicks** — an `await` ran before `generate()`
|
|
244
244
|
and the gesture was lost. Move the call to the first line of the handler.
|
|
245
245
|
|
|
246
|
-
**`
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
246
|
+
**`player_wallet_required`** — ONE code for the two early dead ends: the lane
|
|
247
|
+
refuses a guest and a PREVIEW build on the same line. `waitForPlayer()` tells
|
|
248
|
+
them apart. `guest: true` — guests play but hold no wallet, so show the feature
|
|
249
|
+
as sign-in-to-use rather than hiding it (`$genex-threejs-embed-auth`). Signed
|
|
250
|
+
in and still refused — this is a `genex preview` draft, which never spends:
|
|
251
|
+
check the layout there, and the call itself only after `genex promote`. The
|
|
252
|
+
SDK's stock sentence for this code is "Sign in to Genex to use this", which is
|
|
253
|
+
right for the guest and wrong on a draft, so write the in-fiction line per
|
|
254
|
+
cause rather than showing it for both.
|
|
251
255
|
|
|
252
256
|
**`grant_price_unreasonable`** — the declared per-call price is far above what
|
|
253
257
|
that prompt can cost on that model. Re-benchmark and declare what it prints.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: genex-tool-llm
|
|
3
|
+
description: A language model running while somebody PLAYS the finished game — an NPC that answers in its own words, a quest written from what the player typed, a prompt box in the game. On Genex the player pays and approves it, so this is a platform feature, never a key on the author's meter. Read this the moment a request implies a model at play time, before building anything.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Genex Tools · Models at play time
|
|
7
|
+
|
|
8
|
+
This card is about a model that runs **while somebody plays the finished game**
|
|
9
|
+
— not about generating art while you build it. "Make me a picture, a model, a
|
|
10
|
+
voice line" is the asset belt: use the lane card for it and stay here only if a
|
|
11
|
+
model has to run for the player.
|
|
12
|
+
|
|
13
|
+
## What the platform does
|
|
14
|
+
|
|
15
|
+
A game hosted on Genex can call a language model from inside the running game
|
|
16
|
+
and get back text or JSON. **The player pays and the player approves**: coins
|
|
17
|
+
from their Genex wallet, or their own Claude / ChatGPT subscription, chosen on
|
|
18
|
+
an approval sheet Genex draws that the game cannot render, skin or bypass.
|
|
19
|
+
Either one call at a time, or one standing budget the player approves once and
|
|
20
|
+
the game then spends against without another popup. The game holds no provider
|
|
21
|
+
key, sees no credential, and never talks to a model vendor.
|
|
22
|
+
|
|
23
|
+
That is the whole reason this is a platform feature and not something you wire
|
|
24
|
+
up here: an unhosted folder has nowhere to put a key that is not the author's
|
|
25
|
+
own.
|
|
26
|
+
|
|
27
|
+
## Recognise the request
|
|
28
|
+
|
|
29
|
+
Any of these means a model at PLAY time, however it is phrased:
|
|
30
|
+
|
|
31
|
+
- NPCs that talk, answer, argue, or decide in their own words
|
|
32
|
+
- anything written from what the player types — a name, a wish, a command, a question
|
|
33
|
+
- a prompt box, a chat panel, an "ask the oracle" widget inside the game
|
|
34
|
+
- quests, items, dialogue, or levels generated per save or per run
|
|
35
|
+
- "let the player choose a model", "use my API key in the game", "hook a chatbot into it"
|
|
36
|
+
- a judge, a grader, or a referee that reads free-form player input
|
|
37
|
+
|
|
38
|
+
## Offer it in one line, then ASK
|
|
39
|
+
|
|
40
|
+
Say this and stop:
|
|
41
|
+
|
|
42
|
+
> A model running while people play is built into the Genex platform — the
|
|
43
|
+
> player pays, with Genex coins or their own Claude/ChatGPT subscription, and
|
|
44
|
+
> approves it on a Genex sheet; your game just calls `generate()`. Want it
|
|
45
|
+
> that way?
|
|
46
|
+
|
|
47
|
+
Wait for the answer. Do not start building either version first, and do not
|
|
48
|
+
expand the offer into a pitch — one line, one question.
|
|
49
|
+
|
|
50
|
+
## On a yes
|
|
51
|
+
|
|
52
|
+
1. `npx genex llm models` — whether this stand serves the lane at all, and
|
|
53
|
+
which models. It answers in this folder as it is, before anything is
|
|
54
|
+
converted, so it comes first: if it says the lane is off, in-game calls
|
|
55
|
+
answer 404 here — tell the user so plainly, build the graceful fallback, and
|
|
56
|
+
do not convert a folder for a feature the stand does not serve.
|
|
57
|
+
2. `npx genex init --convert` — it connects this folder to a hosted Genex game
|
|
58
|
+
in place. The code, the files and this toolkit stay exactly as they are, and
|
|
59
|
+
generations still land in `./assets`. It is the user's yes that runs it, so
|
|
60
|
+
ask before you do if you have not already.
|
|
61
|
+
3. Load `$genex-llm-in-games` — it arrives with the conversion and owns the
|
|
62
|
+
build: the SDK surface, one-time calls versus a standing budget, measuring
|
|
63
|
+
the price before the game declares it, and honest handling of every refusal.
|
|
64
|
+
|
|
65
|
+
**The game has to be a static browser build.** A hosted game is files served
|
|
66
|
+
from the edge; there is no server of yours inside it. So the familiar pattern —
|
|
67
|
+
a small local Express/Flask app that holds a key and proxies the model — works
|
|
68
|
+
on your machine and can never ship. Calling `generate()` from the browser is
|
|
69
|
+
the shipping shape of that idea.
|
|
70
|
+
|
|
71
|
+
## On a no
|
|
72
|
+
|
|
73
|
+
Then build nothing that calls a model at play time. Not a key in `.env`, not a
|
|
74
|
+
local proxy, not the author's own account behind a fetch. A shipped game
|
|
75
|
+
carrying the author's credential means every visitor spends the author's money,
|
|
76
|
+
with nobody approving anything and no limit on it — and the credential is
|
|
77
|
+
readable in the bundle. Say that in one plain sentence, then build the authored
|
|
78
|
+
version instead: a written dialogue tree, a table of lines, a rule-based
|
|
79
|
+
director. Those are not consolation prizes; they are what most good games use.
|
|
80
|
+
|
|
81
|
+
## The honest boundary — text and JSON only
|
|
82
|
+
|
|
83
|
+
Player-funded generation returns **text or JSON**. Nothing else.
|
|
84
|
+
|
|
85
|
+
- **"The player types anything and gets a 3D model, paid by them"** is not a
|
|
86
|
+
thing on this platform. Say so plainly instead of half-building it.
|
|
87
|
+
- 3D models, images, textures, video, music, voice and characters are the ASSET
|
|
88
|
+
lanes of this toolkit: you generate them while you build, on the user's own
|
|
89
|
+
meter, and they download into `./assets` and ship inside the game. What is
|
|
90
|
+
live and what it costs: `npx genex doctor`.
|
|
91
|
+
- The shape that does work is **JSON parameters, then render**: the model
|
|
92
|
+
returns a structured description and the game builds it from assets and code
|
|
93
|
+
you already shipped — a creature assembled from parts you generated, a room
|
|
94
|
+
laid out from a list of prefab ids, a palette, a stat block, a line delivered
|
|
95
|
+
from pre-generated voice clips. Offer that when somebody asks for the
|
|
96
|
+
impossible version.
|
|
@@ -8,6 +8,9 @@ description: How Genex Tools works across every lane — `npx genex doctor` to c
|
|
|
8
8
|
The rules that apply to every lane. The per-lane cards are
|
|
9
9
|
`$genex-tool-model`, `$genex-tool-image`, `$genex-tool-video`,
|
|
10
10
|
`$genex-tool-texture`, `$genex-tool-audio`, `$genex-tool-character`.
|
|
11
|
+
`$genex-tool-llm` is the odd one out: it is not a generation lane at all but
|
|
12
|
+
the door for a model that runs while somebody PLAYS the finished game — read it
|
|
13
|
+
the moment a request implies one.
|
|
11
14
|
|
|
12
15
|
## Check before you promise
|
|
13
16
|
|
|
@@ -92,8 +95,10 @@ tiling floor and three paid assets nobody loaded.
|
|
|
92
95
|
|
|
93
96
|
Hosting, publishing, multiplayer, remixing and custom domains are the Genex
|
|
94
97
|
platform, not this toolkit — those commands are refused in this folder by
|
|
95
|
-
design, and the refusal says where they live.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
design, and the refusal says where they live. So is a model that runs while
|
|
99
|
+
somebody plays the finished game: that one is player-funded and needs a hosted
|
|
100
|
+
game, and `$genex-tool-llm` owns how to offer it. This workspace generates
|
|
101
|
+
assets for a game you build and ship yourself. When the user wants that game
|
|
102
|
+
live on Genex with its own URL, the AGENTS.md rules say how to offer it; on a
|
|
103
|
+
yes the folder is connected to a hosted game in place — same cards, same rules
|
|
104
|
+
— and the `$genex-tool-publish` card arrives with the publishing commands.
|