@genex-ai/cli-demo 1.36.15 → 1.36.16-dev.1041
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{blender-mcp-QVEGHE5L.js → blender-mcp-WSURPZET.js} +2 -2
- package/dist/{blender-serve-66OHC4ML.js → blender-serve-EH2MOW3U.js} +1 -1
- package/dist/{chunk-4BBTPRJW.js → chunk-EABIVAGT.js} +2 -2
- package/dist/{chunk-QI7FIYBY.js → chunk-K4EHXOZK.js} +1 -1
- package/dist/index.js +489 -239
- package/package.json +1 -1
- package/templates/skills/genex-game-director/SKILL.md +3 -3
- package/templates/skills/genex-getting-started/SKILL.md +2 -2
- package/templates/skills/genex-items/SKILL.md +27 -10
- package/templates/skills/genex-llm-in-games/SKILL.md +210 -73
- package/templates/skills/genex-llm-in-games/references/pricing.md +126 -85
- package/templates/skills/genex-monetization/SKILL.md +114 -86
- package/templates/skills/genex-tool-llm/SKILL.md +11 -9
- package/templates/skills/genex-updates/SKILL.md +1 -1
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
# Calibrate, then declare
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
3
|
+
An in-game call is paid from the player's Genex credits and **billed as used**:
|
|
4
|
+
its real provider cost plus the platform fee. The game declares no price. It
|
|
5
|
+
declares a per-call **ceiling** — `maxCredits` on `generate()`,
|
|
6
|
+
`perCallMaxCredits` on a standing budget — and no call is ever billed past it.
|
|
7
|
+
|
|
8
|
+
The ceiling is still a number with two jobs, and both punish a guess:
|
|
9
|
+
|
|
10
|
+
- **It bounds the cost.** A budget's worst case, shown to the player beside
|
|
11
|
+
your own estimate, is built from `perCallMaxCredits`. A ceiling far above what
|
|
12
|
+
a call really costs asks the player to approve money the game will never
|
|
13
|
+
spend, and makes the sheet look like a withdrawal.
|
|
14
|
+
- **It sizes the answer.** Each call's room to answer is funded from its
|
|
15
|
+
ceiling, so a ceiling below what the answer needs cuts it off — and a cut-off
|
|
16
|
+
attempt is still billed for the work it did.
|
|
17
|
+
|
|
18
|
+
There is one honest way to pick it: run the real prompt on your own credits,
|
|
19
|
+
read what it really cost, and declare the numbers the benchmark prints.
|
|
20
|
+
|
|
21
|
+
Never derive them from a model vendor's published rates. Three layers sit
|
|
22
|
+
between that rate and what the player is billed — the provider's cost for YOUR
|
|
23
|
+
prompt, the platform fee, and the headroom a ceiling needs — and only the
|
|
24
|
+
benchmark sees the first. The other two come from the server; a number worked
|
|
25
|
+
out from the vendor's page drops at least one of them.
|
|
14
26
|
|
|
15
27
|
## 1. Freeze the prompt first
|
|
16
28
|
|
|
@@ -22,7 +34,7 @@ that the real game then cannot fund.
|
|
|
22
34
|
If the feature returns structured data, write the schema to a file now
|
|
23
35
|
(`./answer.schema.json`) and benchmark with it. Schema'd JSON and free text do
|
|
24
36
|
not cost the same, and shipping without a schema is the commonest way a call is
|
|
25
|
-
|
|
37
|
+
billed for an unusable result.
|
|
26
38
|
|
|
27
39
|
## 2. Run the benchmark
|
|
28
40
|
|
|
@@ -33,89 +45,105 @@ npx genex llm bench "<the frozen prompt, one real example filled in>" \
|
|
|
33
45
|
--model <id from the line above> \
|
|
34
46
|
--schema ./answer.schema.json \
|
|
35
47
|
--samples 3 \
|
|
36
|
-
--max-
|
|
48
|
+
--max-credits <n> --user-approved
|
|
37
49
|
```
|
|
38
50
|
|
|
39
|
-
- It spends **your**
|
|
40
|
-
credential. Nothing here runs in a shipped build.
|
|
41
|
-
|
|
51
|
+
- It spends **your** credits, on the development lane, through the CLI's own
|
|
52
|
+
credential. Nothing here runs in a shipped build. The build's asset allowance
|
|
53
|
+
does not count it, which is why it has its own gate.
|
|
54
|
+
- `--max-credits <n> --user-approved` is a hard gate, refused before any network
|
|
42
55
|
call. That is the same shape as every other spend approval in the CLI: you
|
|
43
|
-
state the ceiling for this run, out loud, once.
|
|
56
|
+
state the ceiling for this run, out loud, once. Your spendable balance has to
|
|
57
|
+
cover one attempt at it, or the run is refused before it starts.
|
|
58
|
+
`--max-coins` is the old name of the same flag and still works.
|
|
44
59
|
- `--samples 3` is the floor. The same prompt costs different amounts on
|
|
45
60
|
different runs, because the model's own output length varies.
|
|
46
61
|
- `npx genex llm price` re-prints the last run's recommendation without spending
|
|
47
|
-
anything again.
|
|
62
|
+
anything again. A file from before credits is reprinted as history, with a
|
|
63
|
+
request to re-run.
|
|
48
64
|
|
|
49
65
|
## 3. Read the output
|
|
50
66
|
|
|
51
|
-
Each sample prints
|
|
52
|
-
max of
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
dispatch. Re-running the bench into the same refusal spends nothing and
|
|
67
|
+
Each sample prints its real cost and the whole credits it was charged. The
|
|
68
|
+
aggregate prints p50, p95 and max of both **over the samples that succeeded and
|
|
69
|
+
settled**. A sample that failed is printed with its code and stays out of the
|
|
70
|
+
numbers; a sample the provider refused at its door (`provider_http_<status>`)
|
|
71
|
+
ran no inference, cost nothing, and prints the provider's own message under its
|
|
72
|
+
row — on a 401 or 403 that is the stand's provider configuration refusing the
|
|
73
|
+
model, which is the operator's to fix. A sample refused as `generation_limit`
|
|
74
|
+
never started and ends the run: the account's three ad-hoc calls are open or
|
|
75
|
+
recently stopped with a pending bill. `npx genex llm status` lists them with
|
|
76
|
+
what each holds; `npx genex llm cancel <id>` stops an active one; a stopped one
|
|
77
|
+
frees on its own once its bill resolves, and stops holding a slot ten minutes
|
|
78
|
+
after dispatch. Re-running the bench into the same refusal spends nothing and
|
|
64
79
|
learns nothing.
|
|
65
80
|
|
|
66
81
|
A sample the model had to stop writing (`provider_token_limit`) was cut off at
|
|
67
|
-
your `--max-
|
|
68
|
-
unknown — so the run recommends no
|
|
69
|
-
`--max-
|
|
70
|
-
answer is longer than one call there may produce; no
|
|
82
|
+
your `--max-credits`: it was billed, it is not a sample, and its real length is
|
|
83
|
+
unknown — so the run recommends no ceiling and asks you to re-run with a higher
|
|
84
|
+
`--max-credits`. When the stand itself cannot hold the answer, the run says the
|
|
85
|
+
answer is longer than one call there may produce; no ceiling fixes that, a
|
|
71
86
|
shorter answer does.
|
|
72
87
|
|
|
73
88
|
- **p50** is what a typical call costs. It is the number to reason about when
|
|
74
|
-
you ask "can the game afford this loop?"
|
|
75
|
-
minute you are about to disclose.
|
|
89
|
+
you ask "can the game afford this loop?".
|
|
76
90
|
- **p95** is what a bad-but-normal call costs: a long answer, a model that
|
|
77
|
-
reasons its way around. It is the
|
|
78
|
-
|
|
79
|
-
mid-session.
|
|
91
|
+
reasons its way around. It is what the **ceiling** has to cover, because a
|
|
92
|
+
ceiling below it cuts the unlucky calls off.
|
|
80
93
|
- **max** is diagnostic. When max sits far above p95, the prompt has an
|
|
81
94
|
unbounded branch in it — usually an unconstrained list or a missing schema.
|
|
82
95
|
Fix the prompt rather than declaring a bigger number.
|
|
83
96
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
the
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
Then the run prints what to declare:
|
|
98
|
+
|
|
99
|
+
- **`Declare maxCredits`** — the p95 real cost with the platform fee and the
|
|
100
|
+
**server's own recommended headroom** applied, in whole credits. It also
|
|
101
|
+
covers the answer's **length**: it is never below the smallest ceiling that
|
|
102
|
+
leaves room for the benchmarked answer, and when the length is what set it
|
|
103
|
+
the run says so in one sentence. A ceiling built from cost alone can cut the
|
|
104
|
+
answer off in the game while the bench — run under a larger `--max-credits`
|
|
105
|
+
— never saw it.
|
|
106
|
+
- **`Grant perCallMaxCredits`** — the same over the worst sample, never below
|
|
107
|
+
the line above it. It is emphatically NOT the benchmark's `max` of charged
|
|
108
|
+
credits: that number carries neither the headroom nor the answer's length,
|
|
109
|
+
so a ceiling set from it lands under the call ceiling and the budget's calls
|
|
110
|
+
are refused (`grant_price_unreasonable`).
|
|
111
|
+
- **`Per-call estimate: about … credits per call`** — the measured average,
|
|
112
|
+
fee included, no headroom: a fraction of a credit for a short call. It is the
|
|
113
|
+
honest figure for the disclosure.
|
|
114
|
+
- **`Grant perCallEstimateCredits`** — that average rounded up to a whole
|
|
115
|
+
credit.
|
|
116
|
+
|
|
117
|
+
Declare each verbatim:
|
|
93
118
|
|
|
94
119
|
```ts
|
|
95
|
-
const
|
|
96
|
-
const
|
|
120
|
+
const NPC_CALL_MAX = <Declare maxCredits>; // from `npx genex llm bench`, <date>
|
|
121
|
+
const NPC_GRANT_MAX = <Grant perCallMaxCredits>; // same run — budgets only
|
|
122
|
+
const NPC_CALL_ESTIMATE = <Grant perCallEstimateCredits>; // same run — budgets only
|
|
123
|
+
const NPC_CALL_AVERAGE = <the "about … credits per call" figure>; // same run
|
|
97
124
|
```
|
|
98
125
|
|
|
99
|
-
Write the benchmark date and the model id beside
|
|
100
|
-
person knows what the
|
|
101
|
-
|
|
126
|
+
Write the benchmark date and the model id beside them in `DESIGN.md`, so the
|
|
127
|
+
next person knows what the numbers describe. Do not add a margin of your own on
|
|
128
|
+
top, and do not round them down to look cheaper.
|
|
102
129
|
|
|
103
|
-
|
|
104
|
-
`perCallMaxCoins`. Declare that one verbatim too, and do not work it out by
|
|
105
|
-
hand. It is emphatically NOT the benchmark's `max`: p95 is nearest-rank, so at
|
|
106
|
-
the sample counts a benchmark actually takes, p95 and max are the same figure —
|
|
107
|
-
a ceiling set from `max` therefore lands *below* the recommended price, and
|
|
108
|
-
`requestSpendGrant()` refuses that pair before the request ever leaves the page.
|
|
109
|
-
|
|
110
|
-
The invariant, which the SDK and the server both enforce:
|
|
130
|
+
The invariants, which the SDK and the server both enforce:
|
|
111
131
|
|
|
112
132
|
```
|
|
113
|
-
|
|
133
|
+
perCallEstimateCredits ≤ perCallMaxCredits ≤ the limit the player approves
|
|
134
|
+
maxCredits on each call ≤ perCallMaxCredits
|
|
114
135
|
```
|
|
115
136
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
137
|
+
A ceiling is not a second price: a call is billed the real cost of the work it
|
|
138
|
+
did plus the fee (a one-time call rounded up to a whole credit), and never past
|
|
139
|
+
its ceiling.
|
|
140
|
+
|
|
141
|
+
**One-time calls round up; budgets do not.** A one-time `generate()` is captured
|
|
142
|
+
rounded UP to a whole credit when it settles, so a call that really costs a
|
|
143
|
+
fraction of a credit still costs the player one whole credit each time. Under a
|
|
144
|
+
budget each call adds its exact fraction and the player's credits move one
|
|
145
|
+
whole credit at a time. That is one more reason a repeated call belongs under a
|
|
146
|
+
budget.
|
|
119
147
|
|
|
120
148
|
## 4. Turn the game's loop into the disclosure
|
|
121
149
|
|
|
@@ -129,27 +157,39 @@ from the loop you wrote, counted honestly:
|
|
|
129
157
|
3. **Multiply, and pick the period that makes the number legible.** Five NPCs at
|
|
130
158
|
one call per thirty seconds is ten calls a minute, so `periodLabel: 'minute'`
|
|
131
159
|
and `estimatedCallsPerPeriod: 10`.
|
|
132
|
-
4. **
|
|
133
|
-
`
|
|
134
|
-
|
|
160
|
+
4. **Credits per period is calls × the measured average, rounded up** —
|
|
161
|
+
`estimatedCreditsPerPeriod: Math.ceil(10 * NPC_CALL_AVERAGE)`. Not the
|
|
162
|
+
ceiling: a call is billed what it uses, so the honest estimate is what calls
|
|
163
|
+
really average.
|
|
135
164
|
|
|
136
165
|
```ts
|
|
166
|
+
perCallMaxCredits: NPC_GRANT_MAX,
|
|
167
|
+
perCallEstimateCredits: NPC_CALL_ESTIMATE,
|
|
137
168
|
disclosure: {
|
|
138
169
|
periodLabel: 'minute',
|
|
139
170
|
estimatedCallsPerPeriod: 10,
|
|
140
|
-
|
|
171
|
+
estimatedCreditsPerPeriod: Math.ceil(10 * NPC_CALL_AVERAGE),
|
|
141
172
|
}
|
|
142
173
|
```
|
|
143
174
|
|
|
144
175
|
The player sees this attributed to your game — "the game estimates about …" —
|
|
145
|
-
beside the platform's own worst case computed from `
|
|
176
|
+
beside the platform's own worst case computed from `perCallMaxCredits`. The two
|
|
146
177
|
being far apart is normal; the estimate being far below what the game really
|
|
147
178
|
does is what breaks trust and burns the grant mid-session.
|
|
148
179
|
|
|
149
|
-
**Batching changes this arithmetic more than any
|
|
180
|
+
**Batching changes this arithmetic more than any tuning can.** Five NPCs
|
|
150
181
|
answered by one call that returns five decisions is two calls a minute, not ten,
|
|
151
|
-
and one
|
|
152
|
-
|
|
182
|
+
and one benchmark of the batched prompt replaces five of the unbatched one. Do
|
|
183
|
+
that before you reach for a cheaper model.
|
|
184
|
+
|
|
185
|
+
## Old code
|
|
186
|
+
|
|
187
|
+
`estimateCoins`, `perCallMaxCoins`, `perCallEstimateCoins` and
|
|
188
|
+
`disclosure.estimatedCoinsPerPeriod` are the names from before credits. The
|
|
189
|
+
server still accepts them and reads them as the same numbers in credits, but
|
|
190
|
+
they are deprecated: rename them to `maxCredits`, `perCallMaxCredits`,
|
|
191
|
+
`perCallEstimateCredits` and `estimatedCreditsPerPeriod` when you touch the
|
|
192
|
+
code, and re-benchmark — a number measured as a Nex price is not a ceiling.
|
|
153
193
|
|
|
154
194
|
## Worked example
|
|
155
195
|
|
|
@@ -160,20 +200,21 @@ speech). The prompt carries the NPC's memory and the last two player lines.
|
|
|
160
200
|
1. Freeze the prompt with a full memory and a long player line. Write
|
|
161
201
|
`./answer.schema.json` with the two fields.
|
|
162
202
|
2. `npx genex llm bench "<that prompt>" --schema ./answer.schema.json
|
|
163
|
-
--samples 3 --max-
|
|
164
|
-
3. Read: p50 `<p50>`, p95 `<p95>`, max `<max>`, and the
|
|
165
|
-
|
|
166
|
-
`
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
203
|
+
--samples 3 --max-credits <ceiling> --user-approved`.
|
|
204
|
+
3. Read: p50 `<p50>`, p95 `<p95>`, max `<max>`, and the printed lines —
|
|
205
|
+
`Declare maxCredits: <call ceiling>`, `Grant perCallMaxCredits: <grant ceiling>`,
|
|
206
|
+
`Per-call estimate: about <average> credits per call` and
|
|
207
|
+
`Grant perCallEstimateCredits: <estimate>`.
|
|
208
|
+
4. Declare `NPC_CALL_MAX`, `NPC_GRANT_MAX`, `NPC_CALL_ESTIMATE` and
|
|
209
|
+
`NPC_CALL_AVERAGE`, each verbatim from the line that printed it.
|
|
210
|
+
5. Unbatched, the loop is ten calls a minute, so the disclosure is `10` calls
|
|
211
|
+
and `Math.ceil(10 * NPC_CALL_AVERAGE)` credits per minute.
|
|
171
212
|
6. Batch the five NPCs into one call — benchmark the batched prompt separately,
|
|
172
213
|
because it is a different prompt — and the disclosure becomes two calls a
|
|
173
|
-
minute at the batched
|
|
214
|
+
minute at the batched average.
|
|
174
215
|
7. Re-run steps 1–4 whenever the prompt, the schema or the model changes. A
|
|
175
|
-
prompt edit
|
|
216
|
+
prompt edit changes the ceiling; treat it like one.
|
|
176
217
|
|
|
177
218
|
Every `<placeholder>` above is read off your own benchmark run. None of these
|
|
178
219
|
figures is a platform constant, and none of them should be copied from another
|
|
179
|
-
game — a different prompt has a different
|
|
220
|
+
game — a different prompt has a different cost.
|
|
@@ -1,24 +1,48 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: genex-monetization
|
|
3
|
-
description:
|
|
3
|
+
description: Sell things in a Genex game for Nex, the currency players buy with real money — fixed-price Genex store items (`genex shop add`) by default, dynamic payment requests only for amounts decided while playing. Use when the player asks to sell things, add a shop, monetize, or make the game earn. Carries the hard rules: no paid randomness, no gambling, no donation mechanics, and a real-money price beside every Nex price.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Genex Monetization
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
Genex's own currency is **Nex**: players buy it with real money and spend it in
|
|
9
|
+
the Genex store. Spending it inside a game is a ledger movement the game never
|
|
10
|
+
touches. You design what is for sale; the platform owns the wallet, the
|
|
11
|
+
confirmation, and the money. Nex is a name: "1,200 Nex", never "Nexes".
|
|
12
12
|
|
|
13
13
|
Load this when the user asks to sell something or add payments. Build the game
|
|
14
|
-
loop before adding commerce
|
|
14
|
+
loop before adding commerce.
|
|
15
|
+
|
|
16
|
+
## Which currency the person means
|
|
17
|
+
|
|
18
|
+
- **A price in Nex means a Genex store item.** Build the thing into the game,
|
|
19
|
+
then list it with `npx genex shop add … --json` without asking, before or
|
|
20
|
+
after the first publish (a folder with no linked game keeps a local draft).
|
|
21
|
+
Price it from the store's grid: `npx genex shop list` prints it, and a price
|
|
22
|
+
off the grid is refused with `price_off_grid`. The person puts it on sale.
|
|
23
|
+
`$genex-items` owns the steps.
|
|
24
|
+
- **A price in coins, gold, gems or any other name is a currency of the game's
|
|
25
|
+
own**, earned by playing (see the per-game currency note below). If the
|
|
26
|
+
person also says it is for real money, ask once whether they mean Nex.
|
|
27
|
+
- **Selling something for real money with no currency named** ("paid
|
|
28
|
+
characters", "sell skins") means Nex store items.
|
|
29
|
+
|
|
30
|
+
## Store items first, payment requests for amounts decided in play
|
|
31
|
+
|
|
32
|
+
Anything with a fixed Nex price is a **store item** (`$genex-items`): a sword,
|
|
33
|
+
a skin, a character, a level pack, a boost. The store draws its card, its
|
|
34
|
+
purchase sheet and its receipt; the game delivers it from `getEntitlements()`.
|
|
35
|
+
|
|
36
|
+
A **dynamic payment request** (`requestPayment()`, below) is only for an amount
|
|
37
|
+
decided while playing: a player-approved action whose price the run sets, or a
|
|
38
|
+
top-up of a size the player picks. Never wrap a fixed-price item in one.
|
|
15
39
|
|
|
16
40
|
## The hard rules, and the test that generalizes them
|
|
17
41
|
|
|
18
42
|
Before you build ANY purchasable thing, run this test:
|
|
19
43
|
|
|
20
|
-
> **Does the player pay?** (with
|
|
21
|
-
> directly or indirectly, including a per-game token or key that
|
|
44
|
+
> **Does the player pay?** (with Nex, or with anything bought with Nex —
|
|
45
|
+
> directly or indirectly, including a per-game token or key that Nex bought.)
|
|
22
46
|
> **Is the outcome uncertain when they pay?**
|
|
23
47
|
> **Is there a prize** — an item, currency, or advantage they wanted?
|
|
24
48
|
>
|
|
@@ -30,12 +54,12 @@ catches mechanics that do not exist yet — which a list of banned names cannot.
|
|
|
30
54
|
Four things are never built, whatever the request:
|
|
31
55
|
|
|
32
56
|
1. **No paid randomness.** No loot boxes, gacha, mystery boxes, crates, packs,
|
|
33
|
-
prize wheels, raffles, "spin for a bonus", "chance to double your
|
|
57
|
+
prize wheels, raffles, "spin for a bonus", "chance to double your Nex".
|
|
34
58
|
Directly or indirectly.
|
|
35
|
-
2. **No gambling in
|
|
36
|
-
slot mechanics denominated in
|
|
59
|
+
2. **No gambling in Nex.** No wagering, staking, betting, coinflips, casino or
|
|
60
|
+
slot mechanics denominated in Nex or in anything Nex buys.
|
|
37
61
|
3. **No donation or begging mechanics.** No "donate to me" prompts, tip jars, or
|
|
38
|
-
player-to-player
|
|
62
|
+
player-to-player Nex transfers. Nex buys goods; it never just moves.
|
|
39
63
|
4. **No pressure.** No countdown timers, "ends in", "limited time", "only N
|
|
40
64
|
left", or stock counters anywhere in the shop.
|
|
41
65
|
|
|
@@ -67,10 +91,10 @@ once and build the compliant version. There is no escalation path.
|
|
|
67
91
|
| They asked for | Build |
|
|
68
92
|
| --- | --- |
|
|
69
93
|
| Loot box, crate, mystery box, card pack | A direct-purchase shop: every item listed at a fixed price, contents visible. For the collecting feel, add a **visible catalog with a completion track** — any purchase advances a meter to a stated milestone reward. |
|
|
70
|
-
| Gacha, banner, pull, summon | A **deterministic unlock**: the character costs a fixed price, or unlocks at a stated number of runs.
|
|
94
|
+
| Gacha, banner, pull, summon | A **deterministic unlock**: the character costs a fixed price, or unlocks at a stated number of runs. Nex may buy a stated, visible number of those points. |
|
|
71
95
|
| Prize wheel, spin-to-win, slot machine | A **free spin earned by finishing a run** (never bought), or a **"pick one of three"** screen where all three are visible and the player chooses. Keeps the moment, drops the wager. |
|
|
72
|
-
| Casino game, blackjack, poker, roulette | The same game with **chips that are granted free each session, reset on restart, cannot be bought and cannot become
|
|
73
|
-
| Coinflip, double-or-nothing, wager my
|
|
96
|
+
| Casino game, blackjack, poker, roulette | The same game with **chips that are granted free each session, reset on restart, cannot be bought and cannot become Nex**. It becomes a card game. Sell cosmetics — table felt, card backs — for Nex. |
|
|
97
|
+
| Coinflip, double-or-nothing, wager my Nex | A **skill-based risk/reward inside the run**: a harder route with a bigger payout, staking the run's own score, which was never purchasable. |
|
|
74
98
|
| Betting on matches, PvP wagers | **Leaderboards with a fixed cosmetic reward for placement**, paid by the game. Nobody's balance goes down. |
|
|
75
99
|
| Donate button, tip jar, "pls donate" | A **gift that is a purchase**: they buy a specific item at a stated price and give it. Or a **supporter cosmetic** — a badge or aura at a normal price, where what's delivered is visible. |
|
|
76
100
|
| Pay to remove a wait / energy gate | **Delete the gate** and sell a permanent upgrade or a cosmetic. Pace with difficulty, not with a timer. |
|
|
@@ -94,36 +118,71 @@ Nine checks. Each one is answerable about your actual design.
|
|
|
94
118
|
shop, remove the annoyance instead of selling the cure.
|
|
95
119
|
5. **Everything sold is reachable free.** Spending is a shortcut or a
|
|
96
120
|
decoration, never the only path.
|
|
97
|
-
6. **A
|
|
98
|
-
|
|
99
|
-
|
|
121
|
+
6. **A purchase has one clear price and promised result.** A store item's
|
|
122
|
+
price is on the server's grid (`genex shop list`), or Free. A dynamic
|
|
123
|
+
payment's `amountCoins` is a positive whole number of Nex from 1 to 100000,
|
|
124
|
+
further bounded by the platform surface, and needs no grid.
|
|
100
125
|
7. **Every price shows real money next to it.** The platform confirmation
|
|
101
126
|
shows the server-frozen `priceDisplayUsdCents`. If rendering a receipt or
|
|
102
|
-
|
|
127
|
+
store price in the game, render that value too; never invent an exchange
|
|
103
128
|
rate. A button can simply say “Unlock” and let Genex show the price.
|
|
104
|
-
8. **One currency layer between money and goods.**
|
|
105
|
-
earned currency buys per-game upgrades. They never
|
|
129
|
+
8. **One currency layer between money and goods.** Nex buys items. A per-game
|
|
130
|
+
earned currency (coins, gold, gems) buys per-game upgrades. They never
|
|
131
|
+
convert into each other.
|
|
106
132
|
9. **Paid ownership survives a reinstall.** Receipts live on the server; the
|
|
107
133
|
game recovers them on every boot and restores the promised state. A
|
|
108
134
|
confirmation can expire; a paid receipt does not expire with it.
|
|
109
135
|
|
|
110
|
-
For a per-game earned currency,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
136
|
+
For a per-game earned currency (coins, gold, gems: earned by playing, never
|
|
137
|
+
bought), the load-bearing number is **minutes of play per unit earned**. Set
|
|
138
|
+
it, then price the cheapest meaningful item at one to three sessions of
|
|
139
|
+
earning. Everything else follows. Spend sinks come in three kinds — permanent
|
|
140
|
+
upgrades, refills, cosmetics — and cosmetics are what absorbs late-game
|
|
114
141
|
currency without touching balance.
|
|
115
142
|
|
|
116
|
-
##
|
|
143
|
+
## Store items (the default)
|
|
117
144
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
145
|
+
Every fixed-price item is a Genex store item. `$genex-items` owns making one —
|
|
146
|
+
its picture, its description, the draft the person puts on sale, items other
|
|
147
|
+
games can use, and adding another creator's item. Its rules add to these; they
|
|
148
|
+
never replace them.
|
|
121
149
|
|
|
122
150
|
```bash
|
|
123
|
-
|
|
151
|
+
npx genex shop list # the price grid in Nex, and this game's items
|
|
152
|
+
npx genex shop add "Iron Key" --price 100 --type durable --json
|
|
153
|
+
npx genex shop test <sku-id> # owner-only free entitlement; no Nex moves
|
|
124
154
|
```
|
|
125
155
|
|
|
126
|
-
|
|
156
|
+
List the item once it works in the game, without asking. When the Genex
|
|
157
|
+
store is on, `genex shop add` makes a draft: `getShop()` leaves it out of the
|
|
158
|
+
live game and `buy()` cannot sell it until the person puts it on sale. `--json`
|
|
159
|
+
makes the Genex app show its **Put on sale** card; never put it on sale
|
|
160
|
+
yourself. Before the game is published, items can be made all the same: they
|
|
161
|
+
wait as local drafts and go up as drafts with `genex publish`; still, only the
|
|
162
|
+
person puts one on sale. With the store off, the item is on sale at once:
|
|
163
|
+
tell the person so.
|
|
164
|
+
|
|
165
|
+
`getShop()` reads store items even for guests and preview builds;
|
|
166
|
+
`buy({ skuId })` requests their platform confirmation. Prices follow the grid
|
|
167
|
+
printed by `genex shop list`. Render `name`, `iconUrl`, `priceCoins` (the price
|
|
168
|
+
in Nex) and `priceDisplayUsdCents`; use an image of the actual item for its
|
|
169
|
+
icon. `genex shop set` edits a listing and `genex shop remove` retires it
|
|
170
|
+
without removing a buyer's ownership.
|
|
171
|
+
|
|
172
|
+
Re-list `getEntitlements({ excludeConsumed: true })` on boot. Branch on
|
|
173
|
+
`skuType` (`consumable`/`durable`), never `type` (purchase/gift/test/free).
|
|
174
|
+
For a consumable, await `consumeEntitlement(id)` BEFORE applying its effect
|
|
175
|
+
and skip `alreadyConsumed: true`. This prevents repeated delivery but a crash
|
|
176
|
+
between consume and save can lose that effect; do not promise atomic game-state
|
|
177
|
+
delivery. A durable ownership unlock is never consumed: restore it from the
|
|
178
|
+
entitlement on every boot. Dynamic receipts do not use this consumption API.
|
|
179
|
+
|
|
180
|
+
## Dynamic payment requests (amounts decided in play)
|
|
181
|
+
|
|
182
|
+
Only for an amount the run decides — a player-approved action whose price play
|
|
183
|
+
sets, a top-up of a size the player picks. A fixed price is a store item
|
|
184
|
+
(above). From `@genex-ai/embed-sdk`, after `initEmbed()` and player identity
|
|
185
|
+
are ready:
|
|
127
186
|
|
|
128
187
|
```ts
|
|
129
188
|
import { requestPayment, getPayment, getPayments } from '@genex-ai/embed-sdk';
|
|
@@ -134,7 +193,7 @@ const order = {
|
|
|
134
193
|
orderId: 'unlock-iron-gate-run-42',
|
|
135
194
|
title: 'Open the iron gate',
|
|
136
195
|
description: 'Unlock the shortcut for this run.',
|
|
137
|
-
amountCoins: 75,
|
|
196
|
+
amountCoins: 75, // Nex, set by this run: the gate's toll grows with depth
|
|
138
197
|
};
|
|
139
198
|
|
|
140
199
|
buyButton.addEventListener('click', async () => {
|
|
@@ -152,15 +211,16 @@ buyButton.addEventListener('click', async () => {
|
|
|
152
211
|
});
|
|
153
212
|
```
|
|
154
213
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
The game never supplies a recipient: the platform uses the game's
|
|
158
|
-
This API is for
|
|
159
|
-
consent flow (`$genex-llm-in-games`), not a payment wrapped around
|
|
214
|
+
A payment request needs no `genex shop add`, SKU id or item icon: it buys a
|
|
215
|
+
described game action whose amount was decided in play. The hard rules above
|
|
216
|
+
still apply. The game never supplies a recipient: the platform uses the game's
|
|
217
|
+
own split. This API is for Nex commerce; in-game LLM requests use their own
|
|
218
|
+
funding and consent flow (`$genex-llm-in-games`), not a payment wrapped around
|
|
219
|
+
a model call.
|
|
160
220
|
|
|
161
221
|
The server freezes `title`, `description`, `amountCoins` and the real-money
|
|
162
222
|
value before Genex asks the player. **Creating a request neither debits nor
|
|
163
|
-
reserves
|
|
223
|
+
reserves Nex.** Only the player's explicit confirmation on the platform
|
|
164
224
|
surface can move money. The game cannot draw, skin or confirm that sheet.
|
|
165
225
|
|
|
166
226
|
An `orderId` belongs to this player in this game. The same id with the same
|
|
@@ -182,7 +242,7 @@ and `pending`. A timeout or uncertain response is `pending`: it is not proof of
|
|
|
182
242
|
failure and not permission to apply the action or charge again. `canceled` is
|
|
183
243
|
ordinary player choice; do not show an error for it.
|
|
184
244
|
|
|
185
|
-
**Your game cannot read the player's
|
|
245
|
+
**Your game cannot read the player's Nex balance, and no HUD should show one.**
|
|
186
246
|
The wallet spans the platform; let Genex show the balance and handle consent.
|
|
187
247
|
Only fulfil a payment whose authoritative receipt says `succeeded`.
|
|
188
248
|
|
|
@@ -194,10 +254,10 @@ The surface depends on the shell (`$genex-threejs-embed-auth`,
|
|
|
194
254
|
pointer lock before it asks. Treat payment like a pause; re-enter fullscreen
|
|
195
255
|
and pointer lock from the player's next Resume click.
|
|
196
256
|
- **The Genex app has no purchase surface yet.** `requestPayment()` fails
|
|
197
|
-
without opening a sheet
|
|
257
|
+
without opening a sheet, and `buy()` resolves
|
|
198
258
|
`failed` without opening anything too. When `getShell()` from `@genex-ai/embed-sdk` is `"app"`,
|
|
199
259
|
hide payment buttons or make the shop browse-only; do not show a failure toast.
|
|
200
|
-
- Local test mode has no wallet. Preview builds cannot spend real
|
|
260
|
+
- Local test mode has no wallet. Preview builds cannot spend real Nex either.
|
|
201
261
|
Verify layout and delivery with game-owned test fixtures; a real payment needs
|
|
202
262
|
a published build, a signed-in player and explicit platform consent.
|
|
203
263
|
|
|
@@ -239,53 +299,20 @@ response and a canceled order. Also check concurrent fulfillment if the game
|
|
|
239
299
|
permits multiple tabs; two read-modify-write saves are not a transaction.
|
|
240
300
|
Do not make a real-money purchase automatically to test the feature.
|
|
241
301
|
|
|
242
|
-
## Existing catalog items
|
|
243
|
-
|
|
244
|
-
Catalog APIs remain supported for published games and items that need platform
|
|
245
|
-
entitlements or resale. They are optional, not a prerequisite for dynamic
|
|
246
|
-
payments:
|
|
247
|
-
|
|
248
|
-
```bash
|
|
249
|
-
npx genex shop add "Iron Key" --price 100 --type durable
|
|
250
|
-
npx genex shop list
|
|
251
|
-
npx genex shop test <sku-id> # owner-only free entitlement; no coin moves
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
`getShop()` reads catalog items even for guests and preview builds;
|
|
255
|
-
`buy({ skuId })` requests their platform confirmation. These prices must follow
|
|
256
|
-
the grid printed by `genex shop list`. Render `name`, `iconUrl`, `priceCoins`
|
|
257
|
-
and `priceDisplayUsdCents`; use an image of the actual item for its icon.
|
|
258
|
-
`genex shop set` edits a listing and `genex shop remove` retires it without
|
|
259
|
-
removing a buyer's ownership. When the Genex store is on, `genex shop add`
|
|
260
|
-
makes a draft: `getShop()` leaves it out of the live game and `buy()` cannot
|
|
261
|
-
sell it until the person puts it on sale. Add `--json` so the Genex app shows
|
|
262
|
-
its **Put on sale** card, and never put it on sale yourself. Before the game
|
|
263
|
-
is published, items can be made all the same: they wait as local drafts and go
|
|
264
|
-
up as drafts with `genex publish`; still, only the person puts one on sale.
|
|
265
|
-
|
|
266
|
-
Items for the Genex store — a picture, a description, a draft the person puts
|
|
267
|
-
on sale, items other games can use, and adding another creator's item — are
|
|
268
|
-
`$genex-items`. Its rules add to these; they never replace them.
|
|
269
|
-
|
|
270
|
-
Re-list `getEntitlements({ excludeConsumed: true })` on boot. Branch on
|
|
271
|
-
`skuType` (`consumable`/`durable`), never `type` (purchase/gift/test/free).
|
|
272
|
-
For a consumable, await `consumeEntitlement(id)` BEFORE applying its effect
|
|
273
|
-
and skip `alreadyConsumed: true`. This prevents repeated delivery but a crash
|
|
274
|
-
between consume and save can lose that effect; do not promise atomic game-state
|
|
275
|
-
delivery. A durable ownership unlock is never consumed: restore it from the
|
|
276
|
-
entitlement on every boot. Dynamic receipts do not use this consumption API.
|
|
277
|
-
|
|
278
302
|
## Checklist
|
|
279
303
|
|
|
280
304
|
- [ ] The game has a worthwhile loop before commerce
|
|
281
|
-
- [ ]
|
|
282
|
-
|
|
283
|
-
- [ ]
|
|
305
|
+
- [ ] Every fixed Nex price is a store item: built first, listed with
|
|
306
|
+
`genex shop add … --json` at a grid price, left for the person to put on sale
|
|
307
|
+
- [ ] A dynamic payment carries only an amount decided in play; its saved order
|
|
308
|
+
binds one stable id, exact terms and promised action
|
|
309
|
+
- [ ] `buy()` and `requestPayment()` start directly from a click/tap
|
|
310
|
+
- [ ] Genex shows the frozen Nex and real-money price and receives consent
|
|
284
311
|
- [ ] No payment buttons in the Genex app
|
|
285
312
|
- [ ] Cancellation is silent; uncertain outcomes remain pending
|
|
286
|
-
- [ ] Recovery reads receipts before applying any paid action
|
|
313
|
+
- [ ] Recovery reads entitlements and receipts before applying any paid action
|
|
287
314
|
- [ ] Fulfillment is idempotent, including reload and concurrent-tab cases
|
|
288
|
-
- [ ] No paid randomness,
|
|
315
|
+
- [ ] No paid randomness, Nex wagering, donation prompt or pressure timer
|
|
289
316
|
- [ ] Nothing sold is unreachable without paying
|
|
290
317
|
|
|
291
318
|
## Troubleshooting
|
|
@@ -314,8 +341,9 @@ a published build for an explicitly approved real purchase.
|
|
|
314
341
|
**`surface_cap`** — the amount exceeds the server's limit for this confirmation
|
|
315
342
|
surface. Do not split it into smaller hidden charges to bypass the limit.
|
|
316
343
|
|
|
317
|
-
**`price_off_grid`** —
|
|
318
|
-
|
|
344
|
+
**`price_off_grid`** — a store item's price is not on the grid. The refusal
|
|
345
|
+
prints it (so does `genex shop list`); pick a price from it, or 0 for Free.
|
|
346
|
+
Dynamic payments accept whole amounts subject to their own caps.
|
|
319
347
|
|
|
320
|
-
**Everything
|
|
321
|
-
|
|
348
|
+
**Everything Nex-related 404s** — Nex commerce is off on this stand. Build
|
|
349
|
+
the rest and report the unavailable lane.
|