@genex-ai/cli-demo 1.36.6 → 1.36.7-dev.889
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 +448 -216
- package/package.json +1 -1
- package/templates/skills/genex-game-director/SKILL.md +1 -1
- package/templates/skills/genex-getting-started/SKILL.md +2 -2
- package/templates/skills/genex-llm-in-games/SKILL.md +209 -72
- package/templates/skills/genex-llm-in-games/references/pricing.md +126 -85
- package/templates/skills/genex-monetization/SKILL.md +160 -222
- package/templates/skills/genex-tool-llm/SKILL.md +11 -9
- package/templates/skills/genex-updates/SKILL.md +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: genex-monetization
|
|
3
|
-
description:
|
|
3
|
+
description: Add dynamic coin payments for game goods or actions — platform consent, recoverable receipts, and idempotent delivery without a required product catalog. 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 in coin, no donation mechanics, and a real-money price beside every coin price.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Genex Monetization
|
|
@@ -10,8 +10,8 @@ buys coin with real money once; spending it inside a game is a ledger movement
|
|
|
10
10
|
the game never touches. You design what is for sale; the platform owns the
|
|
11
11
|
wallet, the confirmation, and the money.
|
|
12
12
|
|
|
13
|
-
Load this when the
|
|
14
|
-
|
|
13
|
+
Load this when the user asks to sell something or add payments. Build the game
|
|
14
|
+
loop before adding commerce; no shop screen or product catalog is required.
|
|
15
15
|
|
|
16
16
|
## The hard rules, and the test that generalizes them
|
|
17
17
|
|
|
@@ -94,15 +94,18 @@ Nine checks. Each one is answerable about your actual design.
|
|
|
94
94
|
shop, remove the annoyance instead of selling the cure.
|
|
95
95
|
5. **Everything sold is reachable free.** Spending is a shortcut or a
|
|
96
96
|
decoration, never the only path.
|
|
97
|
-
6. **
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
7. **Every price shows real money next to it.** The
|
|
101
|
-
|
|
97
|
+
6. **A payment has one clear price and promised result.** `amountCoins` is a
|
|
98
|
+
positive whole number from 1 to 100000, further bounded by the platform
|
|
99
|
+
surface. Dynamic payments do not use the legacy catalog price grid.
|
|
100
|
+
7. **Every price shows real money next to it.** The platform confirmation
|
|
101
|
+
shows the server-frozen `priceDisplayUsdCents`. If rendering a receipt or
|
|
102
|
+
catalog price in the game, render that value too; never invent an exchange
|
|
103
|
+
rate. A button can simply say “Unlock” and let Genex show the price.
|
|
102
104
|
8. **One currency layer between money and goods.** Coin buys items. A per-game
|
|
103
105
|
earned currency buys per-game upgrades. They never convert into each other.
|
|
104
|
-
9. **
|
|
105
|
-
|
|
106
|
+
9. **Paid ownership survives a reinstall.** Receipts live on the server; the
|
|
107
|
+
game recovers them on every boot and restores the promised state. A
|
|
108
|
+
confirmation can expire; a paid receipt does not expire with it.
|
|
106
109
|
|
|
107
110
|
For a per-game earned currency, the load-bearing number is **minutes of play per
|
|
108
111
|
unit earned**. Set it, then price the cheapest meaningful item at one to three
|
|
@@ -110,257 +113,192 @@ sessions of earning. Everything else follows. Spend sinks come in three kinds
|
|
|
110
113
|
permanent upgrades, refills, cosmetics — and cosmetics are what absorbs late-game
|
|
111
114
|
currency without touching balance.
|
|
112
115
|
|
|
113
|
-
##
|
|
116
|
+
## Dynamic payment requests
|
|
114
117
|
|
|
115
|
-
|
|
116
|
-
and the game names them by id — which is what stops a game inventing its own
|
|
117
|
-
items or repricing them.
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
npx genex shop add "Iron Key" --price 100 --type durable
|
|
121
|
-
# → id: sku_a1b2c3 ← what the game passes to buy()
|
|
122
|
-
|
|
123
|
-
npx genex shop list # what this game sells, and the valid prices
|
|
124
|
-
npx genex shop set sku_a1b2c3 --price 200
|
|
125
|
-
npx genex shop remove sku_a1b2c3 # retires it; players who bought it keep it
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
`--type consumable` (default) is spent on use; `durable` is owned permanently.
|
|
129
|
-
|
|
130
|
-
**Prices come off a fixed grid** — `genex shop list` prints it, and an off-grid
|
|
131
|
-
price is refused. The grid exists so every coin pack divides evenly by the
|
|
132
|
-
cheapest item, which is what stops a player being left holding change too small
|
|
133
|
-
to spend. Pick the nearest grid price rather than working around it.
|
|
134
|
-
|
|
135
|
-
Record the ids in `DESIGN.md` next to what each item does. They are the one
|
|
136
|
-
thing the game's code cannot regenerate for itself.
|
|
137
|
-
|
|
138
|
-
## Item art
|
|
139
|
-
|
|
140
|
-
**Every item ships with a picture.** `--icon` is optional to the command and not
|
|
141
|
-
optional to the product: a SKU with no icon renders as a coloured plate with a
|
|
142
|
-
generic box on it, in your shop and on the platform's resale market, where it
|
|
143
|
-
sits next to other games' items that do have art.
|
|
144
|
-
|
|
145
|
-
**It has to be the item.** Not "a fantasy key" — *this* key, the one the player
|
|
146
|
-
just picked up, in this game's light and this game's palette. An icon that shows
|
|
147
|
-
a different object than the world does is worse than the plate, because the
|
|
148
|
-
plate at least does not claim anything.
|
|
149
|
-
|
|
150
|
-
So if the item exists as an asset — a generated model, a sprite, a texture —
|
|
151
|
-
generate the art FROM it. Point the camera at the model in the game, or use the
|
|
152
|
-
asset image, and feed that frame in as the reference:
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
# 1. capture the real item -> ./iron-key-ref.png (crop it SQUARE, see below)
|
|
156
|
-
npx genex image "shop item art of the exact object in the reference image: an ornate iron key, centred, lit from above with a soft rim light, on a clean dark backdrop, no text, no watermark, no interface" \
|
|
157
|
-
--edit ./iron-key-ref.png --quality high
|
|
158
|
-
# -> https://assets.genex.technology/generations/<id>/image-main
|
|
159
|
-
|
|
160
|
-
# 2. attach it
|
|
161
|
-
npx genex shop add "Iron Key" --price 100 --type durable --icon <that url>
|
|
162
|
-
npx genex shop set sku_a1b2c3 --icon <that url> # or fix one later
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
`--edit` takes a **local file** (≤ 4 MB) as well as an asset URL, so a screenshot
|
|
166
|
-
goes straight in. Two things about that lane:
|
|
167
|
-
|
|
168
|
-
- **It keeps the reference's shape**, so `--aspect` does nothing here — crop the
|
|
169
|
-
reference square before you pass it, or you will get a wide icon in a square
|
|
170
|
-
cell.
|
|
171
|
-
- It is a different model from the plain text lane, and a better one for this
|
|
172
|
-
job, because the reference is what makes the picture the item and not a
|
|
173
|
-
picture of the idea.
|
|
174
|
-
|
|
175
|
-
No asset yet? Same prompt without `--edit`, anchored on the item's name and on
|
|
176
|
-
**the game's own vibe words** — take them from `DESIGN.md` rather than inventing
|
|
177
|
-
a style, and generate the whole shop in one sitting with the same style clause
|
|
178
|
-
so the shelf reads as one set.
|
|
179
|
-
|
|
180
|
-
Prompt shape, and every clause earns its place: one object, centred, on a clean
|
|
181
|
-
simple backdrop, lit the way the game lights things, closing with *no text, no
|
|
182
|
-
watermark, no interface*. Say what you want, never what you don't — an image
|
|
183
|
-
model reads "no swords" as "swords", so a ban only works when the thing is
|
|
184
|
-
absent from the prompt entirely.
|
|
185
|
-
|
|
186
|
-
## The API
|
|
187
|
-
|
|
188
|
-
From `@genex-ai/embed-sdk`, already installed. `initEmbed()` must have run.
|
|
118
|
+
From `@genex-ai/embed-sdk`, after `initEmbed()` and player identity are ready:
|
|
189
119
|
|
|
190
120
|
```ts
|
|
191
|
-
import {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
much a player can spend. Show what you *can* know — what they own, from
|
|
208
|
-
`getEntitlements()` — and let `buy()` report `insufficient_balance` if it comes
|
|
209
|
-
to that.
|
|
210
|
-
|
|
211
|
-
### Buying
|
|
212
|
-
|
|
213
|
-
```ts
|
|
214
|
-
buyButton.addEventListener('click', async () => { // must be a real click
|
|
215
|
-
const result = await buy({ skuId: item.id });
|
|
216
|
-
if (result.status === 'canceled') return; // normal — say nothing
|
|
217
|
-
if (result.status !== 'succeeded') {
|
|
218
|
-
showMessage(result.message ?? 'That did not go through.');
|
|
121
|
+
import { requestPayment, getPayment, getPayments } from '@genex-ai/embed-sdk';
|
|
122
|
+
|
|
123
|
+
// Prepare and save this order AND its promised action before enabling the button.
|
|
124
|
+
// Generate its id once. Keep the same id and terms across retries and reloads.
|
|
125
|
+
const order = {
|
|
126
|
+
orderId: 'unlock-iron-gate-run-42',
|
|
127
|
+
title: 'Open the iron gate',
|
|
128
|
+
description: 'Unlock the shortcut for this run.',
|
|
129
|
+
amountCoins: 75,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
buyButton.addEventListener('click', async () => {
|
|
133
|
+
const result = await requestPayment(order); // first async operation in the click
|
|
134
|
+
if (result.status === 'canceled') return;
|
|
135
|
+
if (result.status === 'succeeded' && result.payment) {
|
|
136
|
+
await applyPaidOrderOnce(result.payment); // your saved, idempotent game action
|
|
219
137
|
return;
|
|
220
138
|
}
|
|
221
|
-
|
|
139
|
+
if (result.status === 'pending') {
|
|
140
|
+
showMessage('Payment is still being checked.');
|
|
141
|
+
return; // recover this order; do not create a replacement charge
|
|
142
|
+
}
|
|
143
|
+
showMessage('Purchase did not complete.');
|
|
222
144
|
});
|
|
223
145
|
```
|
|
224
146
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
147
|
+
No `genex shop add`, SKU id, catalog card or item icon is needed. A payment can
|
|
148
|
+
buy a described game action, unlock or item. The hard rules above still apply.
|
|
149
|
+
The game never supplies a recipient: the platform uses the game's own split.
|
|
150
|
+
This API is for coin commerce; in-game LLM requests use their own funding and
|
|
151
|
+
consent flow (`$genex-llm-in-games`), not a payment wrapped around a model call.
|
|
228
152
|
|
|
229
|
-
|
|
230
|
-
|
|
153
|
+
The server freezes `title`, `description`, `amountCoins` and the real-money
|
|
154
|
+
value before Genex asks the player. **Creating a request neither debits nor
|
|
155
|
+
reserves coin.** Only the player's explicit confirmation on the platform
|
|
156
|
+
surface can move money. The game cannot draw, skin or confirm that sheet.
|
|
231
157
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
158
|
+
An `orderId` belongs to this player in this game. The same id with the same
|
|
159
|
+
terms returns the same payment, including a terminal result. Changing its terms
|
|
160
|
+
returns `payment_conflict`. After an order is canceled or expired, a deliberate
|
|
161
|
+
new purchase gets a new id; a network retry never does. Do not generate ids
|
|
162
|
+
inside a retry loop or replace them just because the SDK stopped waiting.
|
|
236
163
|
|
|
237
|
-
|
|
238
|
-
(`$genex-threejs-embed-auth`, `references/shells.md`), and two of them change
|
|
239
|
-
what the game does:
|
|
164
|
+
### Confirmation and results
|
|
240
165
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
a purchase like a pause: re-enter fullscreen and re-lock the pointer from
|
|
246
|
-
the player's next Resume click, never by yourself.
|
|
247
|
-
- **The Genex app has no purchase surface yet.** There `buy()` resolves
|
|
248
|
-
`failed` without opening anything. That is the app, not an error: when
|
|
249
|
-
`getShell()` from `@genex-ai/embed-sdk` is `"app"`, show the shop as
|
|
250
|
-
browse-only or leave the buy buttons out, and never show a failure message
|
|
251
|
-
for it.
|
|
166
|
+
**Call `requestPayment()` synchronously from the click handler.** On the game's
|
|
167
|
+
own origin it reserves a popup while the user gesture is live, then fills it
|
|
168
|
+
with the platform confirmation. Awaiting a save or fetch first can block it;
|
|
169
|
+
prepare and persist the order before enabling its purchase button.
|
|
252
170
|
|
|
253
|
-
|
|
171
|
+
The result has `status`, optional `payment` (the receipt), and optional `message`.
|
|
172
|
+
Statuses are `succeeded`, `canceled`, `expired`, `insufficient_balance`, `failed`
|
|
173
|
+
and `pending`. A timeout or uncertain response is `pending`: it is not proof of
|
|
174
|
+
failure and not permission to apply the action or charge again. `canceled` is
|
|
175
|
+
ordinary player choice; do not show an error for it.
|
|
176
|
+
|
|
177
|
+
**Your game cannot read the player's coin balance, and no HUD should show one.**
|
|
178
|
+
The wallet spans the platform; let Genex show the balance and handle consent.
|
|
179
|
+
Only fulfil a payment whose authoritative receipt says `succeeded`.
|
|
180
|
+
|
|
181
|
+
The surface depends on the shell (`$genex-threejs-embed-auth`,
|
|
182
|
+
`references/shells.md`):
|
|
183
|
+
|
|
184
|
+
- **On the game's Genex page the sheet is drawn above the game.** To show it,
|
|
185
|
+
the page leaves fullscreen first, and the SDK lets go of the
|
|
186
|
+
pointer lock before it asks. Treat payment like a pause; re-enter fullscreen
|
|
187
|
+
and pointer lock from the player's next Resume click.
|
|
188
|
+
- **The Genex app has no purchase surface yet.** `requestPayment()` fails
|
|
189
|
+
without opening a sheet; the legacy `buy()` resolves
|
|
190
|
+
`failed` without opening anything too. When `getShell()` from `@genex-ai/embed-sdk` is `"app"`,
|
|
191
|
+
hide payment buttons or make the shop browse-only; do not show a failure toast.
|
|
192
|
+
- Local test mode has no wallet. Preview builds cannot spend real coin either.
|
|
193
|
+
Verify layout and delivery with game-owned test fixtures; a real payment needs
|
|
194
|
+
a published build, a signed-in player and explicit platform consent.
|
|
195
|
+
|
|
196
|
+
### Receipts and delivery after a restart
|
|
254
197
|
|
|
255
198
|
```ts
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if (alreadyConsumed) continue; // someone got there first
|
|
266
|
-
applyItem(e.skuId); // AFTER the consume
|
|
267
|
-
await savePlayerState(currentSave());
|
|
268
|
-
}
|
|
269
|
-
}
|
|
199
|
+
const payment = await getPayment(savedOrderId); // null only when not found
|
|
200
|
+
if (payment?.status === 'succeeded') await applyPaidOrderOnce(payment);
|
|
201
|
+
|
|
202
|
+
let cursor: string | undefined;
|
|
203
|
+
do {
|
|
204
|
+
const page = await getPayments({ cursor, limit: 100 });
|
|
205
|
+
for (const receipt of page.payments) await applyPaidOrderOnce(receipt);
|
|
206
|
+
cursor = page.nextCursor ?? undefined;
|
|
207
|
+
} while (cursor);
|
|
270
208
|
```
|
|
271
209
|
|
|
272
|
-
|
|
210
|
+
`getPayment()` returns any status for one order; read/network errors throw and
|
|
211
|
+
are not absence. `getPayments()` lists successful receipts, scoped to the
|
|
212
|
+
current player and game. Follow `nextCursor` to completion. Use the per-order
|
|
213
|
+
read for a known pending request, and scan receipts on boot before purchases
|
|
214
|
+
can affect play.
|
|
273
215
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
216
|
+
A receipt has `id`, `orderId`, `title`, `description`, `amountCoins`,
|
|
217
|
+
`priceDisplayUsdCents`, `status`, `failureCode`, `createdAt`, `paidAt` and
|
|
218
|
+
`expiresAt`. It proves payment, **not delivery of the promised game action**.
|
|
219
|
+
It creates no platform entitlement and nothing the resale market can list.
|
|
278
220
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
221
|
+
`applyPaidOrderOnce` is game code, not an SDK helper. Bind the saved `orderId`
|
|
222
|
+
to the promised action before requesting payment. For an unlock, set the same
|
|
223
|
+
ownership flag every time. For a one-time quantity change, save the changed
|
|
224
|
+
state and the fulfilled receipt id together; replaying the receipt must be a
|
|
225
|
+
no-op. A game with its own backend should enforce the receipt's unique id in
|
|
226
|
+
that backend's transaction. Never use receipt titles as executable instructions
|
|
227
|
+
or apply an effect just because the confirmation window closed.
|
|
282
228
|
|
|
283
|
-
|
|
229
|
+
Test recovery after closing the tab, a repeated success receipt, a delayed
|
|
230
|
+
response and a canceled order. Also check concurrent fulfillment if the game
|
|
231
|
+
permits multiple tabs; two read-modify-write saves are not a transaction.
|
|
232
|
+
Do not make a real-money purchase automatically to test the feature.
|
|
284
233
|
|
|
285
|
-
|
|
286
|
-
effect is ownership — a cosmetic, a skin, an unlock — do **not** consume it: the
|
|
287
|
-
row's presence in the list IS the ownership, it survives reinstalls, and there is
|
|
288
|
-
no local save to drift out of sync. Only consume a durable when it grants
|
|
289
|
-
something once and non-idempotently (a permanent +100 gold), and then record it
|
|
290
|
-
in the player's save, because re-applying that on every boot would be a bug.
|
|
234
|
+
## Existing catalog items
|
|
291
235
|
|
|
292
|
-
|
|
236
|
+
Catalog APIs remain supported for published games and items that need platform
|
|
237
|
+
entitlements or resale. They are optional, not a prerequisite for dynamic
|
|
238
|
+
payments:
|
|
293
239
|
|
|
294
240
|
```bash
|
|
295
|
-
npx genex shop
|
|
241
|
+
npx genex shop add "Iron Key" --price 100 --type durable
|
|
242
|
+
npx genex shop list
|
|
243
|
+
npx genex shop test <sku-id> # owner-only free entitlement; no coin moves
|
|
296
244
|
```
|
|
297
245
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
246
|
+
`getShop()` reads catalog items even for guests and preview builds;
|
|
247
|
+
`buy({ skuId })` requests their platform confirmation. These prices must follow
|
|
248
|
+
the grid printed by `genex shop list`. Render `name`, `iconUrl`, `priceCoins`
|
|
249
|
+
and `priceDisplayUsdCents`; use an image of the actual item for its icon.
|
|
250
|
+
`genex shop set` edits a listing and `genex shop remove` retires it without
|
|
251
|
+
removing a buyer's ownership.
|
|
252
|
+
|
|
253
|
+
Re-list `getEntitlements({ excludeConsumed: true })` on boot. Branch on
|
|
254
|
+
`skuType` (`consumable`/`durable`), never `type` (purchase/gift/test/free).
|
|
255
|
+
For a consumable, await `consumeEntitlement(id)` BEFORE applying its effect
|
|
256
|
+
and skip `alreadyConsumed: true`. This prevents repeated delivery but a crash
|
|
257
|
+
between consume and save can lose that effect; do not promise atomic game-state
|
|
258
|
+
delivery. A durable ownership unlock is never consumed: restore it from the
|
|
259
|
+
entitlement on every boot. Dynamic receipts do not use this consumption API.
|
|
305
260
|
|
|
306
261
|
## Checklist
|
|
307
262
|
|
|
308
|
-
- [ ]
|
|
309
|
-
- [ ]
|
|
310
|
-
- [ ]
|
|
311
|
-
- [ ]
|
|
312
|
-
- [ ]
|
|
313
|
-
- [ ]
|
|
314
|
-
- [ ]
|
|
315
|
-
|
|
316
|
-
- [ ]
|
|
317
|
-
- [ ] `deliverPending()` runs on every boot, before the player can act
|
|
318
|
-
- [ ] `consumeEntitlement()` is awaited BEFORE the effect is applied
|
|
319
|
-
- [ ] `alreadyConsumed: true` skips the effect
|
|
320
|
-
- [ ] Durable purchases are written to the player's save
|
|
321
|
-
- [ ] No timer, "limited", "ends in", or stock counter anywhere
|
|
263
|
+
- [ ] The game has a worthwhile loop before commerce
|
|
264
|
+
- [ ] The saved order binds one stable id, exact terms and promised action
|
|
265
|
+
- [ ] `requestPayment()` starts directly from a click/tap
|
|
266
|
+
- [ ] Genex shows the frozen coin and real-money price and receives consent
|
|
267
|
+
- [ ] No payment buttons in the Genex app
|
|
268
|
+
- [ ] Cancellation is silent; uncertain outcomes remain pending
|
|
269
|
+
- [ ] Recovery reads receipts before applying any paid action
|
|
270
|
+
- [ ] Fulfillment is idempotent, including reload and concurrent-tab cases
|
|
271
|
+
- [ ] No paid randomness, coin wagering, donation prompt or pressure timer
|
|
322
272
|
- [ ] Nothing sold is unreachable without paying
|
|
323
|
-
- [ ] No paid randomness, no coin wagering, no donation prompt
|
|
324
273
|
|
|
325
274
|
## Troubleshooting
|
|
326
275
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
**The purchase succeeded but the player got nothing** — the game applied the
|
|
332
|
-
effect without consuming, or never ran `deliverPending()` on boot. The
|
|
333
|
-
entitlement is still there; re-list it.
|
|
334
|
-
|
|
335
|
-
**The player got the item twice** — the effect was applied before consuming, or
|
|
336
|
-
`alreadyConsumed` was ignored. Both are the same bug.
|
|
276
|
+
**The confirmation window was blocked** — an `await` ran before
|
|
277
|
+
`requestPayment()`, or there was no click. Persist the order earlier and make
|
|
278
|
+
the payment request the click handler's first async operation.
|
|
337
279
|
|
|
338
|
-
**`
|
|
339
|
-
|
|
280
|
+
**`payment_conflict`** — the same order id was reused with different terms.
|
|
281
|
+
Recover its original request; create a new id only for a new purchase.
|
|
340
282
|
|
|
341
|
-
**`
|
|
342
|
-
|
|
283
|
+
**`pending` or an interrupted tab** — use `getPayment(orderId)`. Never assume
|
|
284
|
+
failure, issue a replacement charge, or deliver while the status is uncertain.
|
|
343
285
|
|
|
344
|
-
|
|
345
|
-
|
|
286
|
+
**Payment succeeded but nothing happened** — find the saved order's action and
|
|
287
|
+
recover its receipt. The platform records payment; the game owns fulfillment.
|
|
346
288
|
|
|
347
|
-
|
|
348
|
-
|
|
289
|
+
**The player got the effect twice** — delivery did not deduplicate by receipt
|
|
290
|
+
id or the save update raced. Fix fulfillment; do not change the order id.
|
|
349
291
|
|
|
350
|
-
**`
|
|
351
|
-
list` prints the valid ones; pick the nearest.
|
|
292
|
+
**`guest_no_wallet`** — ask the player to sign in before purchase.
|
|
352
293
|
|
|
353
|
-
|
|
354
|
-
|
|
294
|
+
**`staging_no_purchase`** — previews cannot spend; verify layout there and use
|
|
295
|
+
a published build for an explicitly approved real purchase.
|
|
355
296
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
preview or published build.
|
|
297
|
+
**`surface_cap`** — the amount exceeds the server's limit for this confirmation
|
|
298
|
+
surface. Do not split it into smaller hidden charges to bypass the limit.
|
|
359
299
|
|
|
360
|
-
**`
|
|
361
|
-
|
|
362
|
-
(`getShell() === "app"`).
|
|
300
|
+
**`price_off_grid`** — this applies to legacy catalog SKUs only. Dynamic
|
|
301
|
+
payments accept whole amounts subject to their own caps.
|
|
363
302
|
|
|
364
|
-
**
|
|
365
|
-
|
|
366
|
-
has to be visible to show it. Re-enter from the player's next click.
|
|
303
|
+
**Everything coin-related 404s** — coin commerce is disabled on this stand.
|
|
304
|
+
Build the rest and report the unavailable lane.
|
|
@@ -13,11 +13,12 @@ model has to run for the player.
|
|
|
13
13
|
## What the platform does
|
|
14
14
|
|
|
15
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**:
|
|
17
|
-
from their Genex
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
and get back text or JSON. **The player pays and the player approves**: credits
|
|
17
|
+
from their Genex account, billed as each call is used and never past the
|
|
18
|
+
per-call ceiling the game declares, or their own Claude / ChatGPT subscription,
|
|
19
|
+
chosen on an approval sheet Genex draws that the game cannot render, skin or
|
|
20
|
+
bypass. Either one call at a time, or one standing budget the player approves
|
|
21
|
+
once and the game then spends against without another popup. The game holds no provider
|
|
21
22
|
key, sees no credential, and never talks to a model vendor.
|
|
22
23
|
|
|
23
24
|
That is the whole reason this is a platform feature and not something you wire
|
|
@@ -40,9 +41,9 @@ Any of these means a model at PLAY time, however it is phrased:
|
|
|
40
41
|
Say this and stop:
|
|
41
42
|
|
|
42
43
|
> A model running while people play is built into the Genex platform — the
|
|
43
|
-
> player pays, with Genex
|
|
44
|
-
> approves it on a Genex sheet; your game just calls
|
|
45
|
-
> that way?
|
|
44
|
+
> player pays, with their Genex credits or their own Claude/ChatGPT
|
|
45
|
+
> subscription, and approves it on a Genex sheet; your game just calls
|
|
46
|
+
> `generate()`. Want it that way?
|
|
46
47
|
|
|
47
48
|
Wait for the answer. Do not start building either version first, and do not
|
|
48
49
|
expand the offer into a pitch — one line, one question.
|
|
@@ -64,7 +65,8 @@ expand the offer into a pitch — one line, one question.
|
|
|
64
65
|
ask before you do if you have not already.
|
|
65
66
|
3. Load `$genex-llm-in-games` — it arrives with the conversion and owns the
|
|
66
67
|
build: the SDK surface, one-time calls versus a standing budget, measuring
|
|
67
|
-
the
|
|
68
|
+
the per-call ceiling before the game declares it, and honest handling of
|
|
69
|
+
every refusal.
|
|
68
70
|
|
|
69
71
|
**The game has to be a static browser build.** A hosted game is files served
|
|
70
72
|
from the edge; there is no server of yours inside it. So the familiar pattern —
|
|
@@ -38,7 +38,7 @@ update, so update immediately.)
|
|
|
38
38
|
Run exactly the command the nudge printed, from the game project root:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
npm i -D @genex-ai/cli-demo@
|
|
41
|
+
npm i -D @genex-ai/cli-demo@dev # the genex CLI (a dev dependency)
|
|
42
42
|
npm i @genex-ai/embed-sdk@latest # identity/saves SDK (ships inside the game)
|
|
43
43
|
npm i @genex-ai/multiplayer@latest # multiplayer SDK (only if the game uses it)
|
|
44
44
|
```
|