gamesteel 0.5.3 → 0.5.4

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.
@@ -33402,7 +33402,7 @@ interface Purchases {
33402
33402
  restore(): void
33403
33403
  }
33404
33404
 
33405
- /** The game's own server, for a game whose Online tab turned it on (the guide's online topic). Each ask goes to the
33405
+ /** The game's own server, for a game whose Server page turned it on (the guide's online topic). Each ask goes to the
33406
33406
  * server through the page; what comes back reaches every script on a later tick as onEvent('online', heard), where
33407
33407
  * heard is { kind: 'answer', id, name, result, data?, reason? } (result 'ok', 'error', 'busy', 'resting' or 'refused'),
33408
33408
  * { kind: 'message', room, data }, or { kind: 'joined' | 'left' | 'full', room }. A tick never waits on the network. */
@@ -33759,7 +33759,7 @@ interface Game {
33759
33759
  /** An event every onEvent hears on the next tick; it also counts as the tick's event. */
33760
33760
  emit(name: string, data?: Plain): void
33761
33761
  /** The game's seeded random number in [0, 1); Math.random is the same stream. Each
33762
- * play in the Game tab starts from a seed of its own; a playtest starts from seed 1,
33762
+ * play in the editor starts from a seed of its own; a playtest starts from seed 1,
33763
33763
  * so its runs repeat. */
33764
33764
  random(): number
33765
33765
  /** A whole number from lo to hi, both included. */
@@ -33814,7 +33814,7 @@ interface Game {
33814
33814
  /** Opens the game's privacy policy, as a game on the app stores must from inside itself: call it when the player
33815
33815
  * taps the game's own Privacy button. The page knows where the policy is; with none yet, nothing opens. */
33816
33816
  openPrivacy(): void
33817
- /** Kept across restarts and levels, and between plays in the Game tab (in that
33817
+ /** Kept across restarts and levels, and between plays in the editor (in that
33818
33818
  * browser). A playtest starts with nothing saved. */
33819
33819
  save(key: string, value: Plain): void
33820
33820
  load(key: string): Plain
@@ -32019,7 +32019,7 @@ interface Purchases {
32019
32019
  restore(): void
32020
32020
  }
32021
32021
 
32022
- /** The game's own server, for a game whose Online tab turned it on (the guide's online topic). Each ask goes to the
32022
+ /** The game's own server, for a game whose Server page turned it on (the guide's online topic). Each ask goes to the
32023
32023
  * server through the page; what comes back reaches every script on a later tick as onEvent('online', heard), where
32024
32024
  * heard is { kind: 'answer', id, name, result, data?, reason? } (result 'ok', 'error', 'busy', 'resting' or 'refused'),
32025
32025
  * { kind: 'message', room, data }, or { kind: 'joined' | 'left' | 'full', room }. A tick never waits on the network. */
@@ -32376,7 +32376,7 @@ interface Game {
32376
32376
  /** An event every onEvent hears on the next tick; it also counts as the tick's event. */
32377
32377
  emit(name: string, data?: Plain): void
32378
32378
  /** The game's seeded random number in [0, 1); Math.random is the same stream. Each
32379
- * play in the Game tab starts from a seed of its own; a playtest starts from seed 1,
32379
+ * play in the editor starts from a seed of its own; a playtest starts from seed 1,
32380
32380
  * so its runs repeat. */
32381
32381
  random(): number
32382
32382
  /** A whole number from lo to hi, both included. */
@@ -32431,7 +32431,7 @@ interface Game {
32431
32431
  /** Opens the game's privacy policy, as a game on the app stores must from inside itself: call it when the player
32432
32432
  * taps the game's own Privacy button. The page knows where the policy is; with none yet, nothing opens. */
32433
32433
  openPrivacy(): void
32434
- /** Kept across restarts and levels, and between plays in the Game tab (in that
32434
+ /** Kept across restarts and levels, and between plays in the editor (in that
32435
32435
  * browser). A playtest starts with nothing saved. */
32436
32436
  save(key: string, value: Plain): void
32437
32437
  load(key: string): Plain
@@ -32019,7 +32019,7 @@ interface Purchases {
32019
32019
  restore(): void
32020
32020
  }
32021
32021
 
32022
- /** The game's own server, for a game whose Online tab turned it on (the guide's online topic). Each ask goes to the
32022
+ /** The game's own server, for a game whose Server page turned it on (the guide's online topic). Each ask goes to the
32023
32023
  * server through the page; what comes back reaches every script on a later tick as onEvent('online', heard), where
32024
32024
  * heard is { kind: 'answer', id, name, result, data?, reason? } (result 'ok', 'error', 'busy', 'resting' or 'refused'),
32025
32025
  * { kind: 'message', room, data }, or { kind: 'joined' | 'left' | 'full', room }. A tick never waits on the network. */
@@ -32376,7 +32376,7 @@ interface Game {
32376
32376
  /** An event every onEvent hears on the next tick; it also counts as the tick's event. */
32377
32377
  emit(name: string, data?: Plain): void
32378
32378
  /** The game's seeded random number in [0, 1); Math.random is the same stream. Each
32379
- * play in the Game tab starts from a seed of its own; a playtest starts from seed 1,
32379
+ * play in the editor starts from a seed of its own; a playtest starts from seed 1,
32380
32380
  * so its runs repeat. */
32381
32381
  random(): number
32382
32382
  /** A whole number from lo to hi, both included. */
@@ -32431,7 +32431,7 @@ interface Game {
32431
32431
  /** Opens the game's privacy policy, as a game on the app stores must from inside itself: call it when the player
32432
32432
  * taps the game's own Privacy button. The page knows where the policy is; with none yet, nothing opens. */
32433
32433
  openPrivacy(): void
32434
- /** Kept across restarts and levels, and between plays in the Game tab (in that
32434
+ /** Kept across restarts and levels, and between plays in the editor (in that
32435
32435
  * browser). A playtest starts with nothing saved. */
32436
32436
  save(key: string, value: Plain): void
32437
32437
  load(key: string): Plain
@@ -25332,7 +25332,7 @@ interface Purchases {
25332
25332
  restore(): void
25333
25333
  }
25334
25334
 
25335
- /** The game's own server, for a game whose Online tab turned it on (the guide's online topic). Each ask goes to the
25335
+ /** The game's own server, for a game whose Server page turned it on (the guide's online topic). Each ask goes to the
25336
25336
  * server through the page; what comes back reaches every script on a later tick as onEvent('online', heard), where
25337
25337
  * heard is { kind: 'answer', id, name, result, data?, reason? } (result 'ok', 'error', 'busy', 'resting' or 'refused'),
25338
25338
  * { kind: 'message', room, data }, or { kind: 'joined' | 'left' | 'full', room }. A tick never waits on the network. */
@@ -25689,7 +25689,7 @@ interface Game {
25689
25689
  /** An event every onEvent hears on the next tick; it also counts as the tick's event. */
25690
25690
  emit(name: string, data?: Plain): void
25691
25691
  /** The game's seeded random number in [0, 1); Math.random is the same stream. Each
25692
- * play in the Game tab starts from a seed of its own; a playtest starts from seed 1,
25692
+ * play in the editor starts from a seed of its own; a playtest starts from seed 1,
25693
25693
  * so its runs repeat. */
25694
25694
  random(): number
25695
25695
  /** A whole number from lo to hi, both included. */
@@ -25744,7 +25744,7 @@ interface Game {
25744
25744
  /** Opens the game's privacy policy, as a game on the app stores must from inside itself: call it when the player
25745
25745
  * taps the game's own Privacy button. The page knows where the policy is; with none yet, nothing opens. */
25746
25746
  openPrivacy(): void
25747
- /** Kept across restarts and levels, and between plays in the Game tab (in that
25747
+ /** Kept across restarts and levels, and between plays in the editor (in that
25748
25748
  * browser). A playtest starts with nothing saved. */
25749
25749
  save(key: string, value: Plain): void
25750
25750
  load(key: string): Plain
@@ -75796,7 +75796,7 @@ var SCRIPTS_PRIMER = [
75796
75796
  " and sets that language and game.languages lists them. The HUD, the end screens and the menus write @hello for a",
75797
75797
  " key's text. The person picks the language in the player's menu; the edit operation game.setStrings writes the tables.",
75798
75798
  "- The person exports a game from the toolbar's Export: a zip whose page plays it from the disk or any web host and",
75799
- " installs on a phone, playing as the Game tab does, saves in the browser and all.",
75799
+ " installs on a phone, playing as the editor does, saves in the browser and all.",
75800
75800
  "- Mix freely: rules and scripts run in the same game, and a script may read what a rule changed.",
75801
75801
  "",
75802
75802
  "A kind's script:",
@@ -76741,7 +76741,7 @@ interface GameRequest {
76741
76741
  json(): Json
76742
76742
  }
76743
76743
 
76744
- /** Players' files and the game's own, in the game's storage (turned on in its Online tab, with its database): a
76744
+ /** Players' files and the game's own, in the game's storage (turned on, on its Server page, with its database): a
76745
76745
  * player's under players/<their id>/, so "Delete my online data" reaches them, the game's under game/. */
76746
76746
  interface Files {
76747
76747
  /** An address the player's page uploads exactly size bytes to, for 15 minutes or the seconds given: at most the
@@ -76757,7 +76757,7 @@ interface Files {
76757
76757
  list(prefix: string): Promise<Array<{ key: string; size: number }>>
76758
76758
  }
76759
76759
 
76760
- /** Notifications to players' phones, through the game's own Firebase project (turned on in its Online tab, with its
76760
+ /** Notifications to players' phones, through the game's own Firebase project (turned on, on its Server page, with its
76761
76761
  * database). A player is reached once their app asked them (game.online.askPush) and they said yes. Each push costs
76762
76762
  * one event. Never required to play, never an ad without the player's consent, never a reward for saying yes. */
76763
76763
  interface Push {
@@ -76767,7 +76767,7 @@ interface Push {
76767
76767
 
76768
76768
  /** What every function of the server is given. */
76769
76769
  interface Ctx {
76770
- /** The game's own database (Postgres): turned on in its Online tab. Keep each player's rows with a player_id column,
76770
+ /** The game's own database (Postgres): turned on, on its Server page. Keep each player's rows with a player_id column,
76771
76771
  * so "Delete my online data" reaches them. */
76772
76772
  readonly db: { query(sql: string, params?: readonly Json[]): Promise<{ rows: Record<string, Json>[] }> }
76773
76773
  /** Live rooms: send to everyone in a room, or to one player in it. Who is in a room is room.players, in its hooks. */
@@ -77191,7 +77191,7 @@ var SOUND_TOPIC = [
77191
77191
  "a noise layer, a brighter wave, a filter opened. It is muddy: highpass it, or lower the body. A click at its end: a",
77192
77192
  "longer release. A loop jumps at its seam: end on notes that lead back. Compare two of the game's own with listen",
77193
77193
  "{ names: ['own:hit', 'own:hit-heavy'] }. A playtest plays no audio, so the readout is how you hear it; the person",
77194
- "hears it in the Game tab."
77194
+ "hears it when they play it in the editor."
77195
77195
  ];
77196
77196
 
77197
77197
  // ../agent/dist/sight.js
@@ -77603,7 +77603,7 @@ var PLAYTEST_TOOLS = [
77603
77603
  },
77604
77604
  {
77605
77605
  name: "playtest_look",
77606
- description: "a picture of the game now, as the person sees it in the Game tab, and the data of the objects you name; or, with frames, a strip of moments side by side in one picture, each labelled with its time. Pictures cost money: look at the moments that matter, not after every step.",
77606
+ description: "a picture of the game now, as the person sees it when they play it in the editor, and the data of the objects you name; or, with frames, a strip of moments side by side in one picture, each labelled with its time. Pictures cost money: look at the moments that matter, not after every step.",
77607
77607
  inputSchema: object({
77608
77608
  game: GAME,
77609
77609
  scene: SCENE,
@@ -78474,7 +78474,7 @@ var FILM = [
78474
78474
  " second, its sound mixed from the ticks that asked for it. Nobody watches it live as it renders, so a film too",
78475
78475
  " heavy to play smoothly live comes out as smooth as a light one.",
78476
78476
  "- Each later answer about the game says how the render goes, then how it ended. With no editor open, ask the person",
78477
- " to open the game and press Render video in the Game tab's Films.",
78477
+ " to open the game and press Render video in Upload \u203A Films.",
78478
78478
  "- The exported game plays a film's video in the film's place, in the player's language, with pause, chapters and",
78479
78479
  " skip; a film with no video in that language plays live. After any edit a video is older than the game: render it",
78480
78480
  " again before the person exports.",
@@ -78487,11 +78487,11 @@ var FILM = [
78487
78487
  var PUBLISH = [
78488
78488
  "# Publishing a game",
78489
78489
  "",
78490
- "A finished game goes out from the editor's Upload menu. Every account it goes to is the person's own: their GitHub,",
78490
+ "A finished game goes out from the editor's Upload page. Every account it goes to is the person's own: their GitHub,",
78491
78491
  "their Google Play and App Store developer accounts, their AdMob. Gamesteel makes the files and walks them through each",
78492
78492
  "step; the stores' clicks, checkboxes and agreements are theirs.",
78493
78493
  "",
78494
- "## The Upload menu",
78494
+ "## The Upload page",
78495
78495
  "",
78496
78496
  "- Export: a zip whose index.html plays the game from the disk, and installs as an app once any website serves it.",
78497
78497
  "- GitHub: one repo per game, in the person's own GitHub account, which they connect in the menu; each save can go to it.",
@@ -78524,7 +78524,7 @@ var PUBLISH = [
78524
78524
  "",
78525
78525
  "A game going to the App Store or Google Play opens its privacy policy from inside itself: add a small Privacy button on",
78526
78526
  "its title or pause menu, drawn like its other buttons, that calls this.game.openPrivacy() (the scripts topic shows",
78527
- "one). The person writes and confirms the policy in the editor's Upload menu, in the App Store's wizard or Google",
78527
+ "one). The person writes and confirms the policy in the editor's Upload page, in the App Store's wizard or Google",
78528
78528
  "Play's. A game with ads gets an ads part in the policy's draft, and the policy is confirmed again whenever the",
78529
78529
  "game's ads change. A game with its own server gets an online part, and its Privacy button offers Delete my online",
78530
78530
  "data: the online topic has it. A game that sells gets a purchases part: the purchases topic has it.",
@@ -78549,7 +78549,7 @@ var PUBLISH = [
78549
78549
  " It warns of a break while the player is in the middle of play, and of a banner beside one of the game's buttons.",
78550
78550
  "- In a store app, the Privacy button also opens Ad choices, where Google's consent asks for them: the player's ad",
78551
78551
  " choices, which the law asks they can change.",
78552
- "- A game whose audience includes children under 13 (the App tab asks) is made for children: it shows no ads, every",
78552
+ "- A game whose audience includes children under 13 (Upload \u203A App asks) is made for children: it shows no ads, every",
78553
78553
  " ad is refused, and its builds carry no ad library. Never place ads in a game for children.",
78554
78554
  "- An APK to try and the Xcode project download show Google's test ads, whatever ids the person gave; a release shows",
78555
78555
  " their real ones. Tell the person never to tap their own real ads, even to test: AdMob can close the account. They",
@@ -78574,7 +78574,7 @@ var ONLINE = () => [
78574
78574
  "",
78575
78575
  "A game's own server does what one device can't: a leaderboard, a save that follows the player, players together, an",
78576
78576
  "outside service with a secret key. It is the person's choice and money: the person turns it on, sizes it, pays for it",
78577
- "and publishes it in the editor's Online tab. You write its code; you never turn it on, resize it, spend or publish.",
78577
+ "and publishes it on the editor's Server page. You write its code; you never turn it on, resize it, spend or publish.",
78578
78578
  "",
78579
78579
  "## The code",
78580
78580
  "",
@@ -78585,7 +78585,7 @@ var ONLINE = () => [
78585
78585
  " is given the player (an anonymous id, checked before the code runs), the data the game sent, and ctx; what it returns",
78586
78586
  " is the answer's data, and what it throws the answer's error, in its words.",
78587
78587
  "- ctx.db is the game's own Postgres database, once the person turns it on. ctx.secrets holds the game's secrets by",
78588
- " name, whose values the person sets in the Online tab: never write a key in code. The rest of ctx is below.",
78588
+ " name, whose values the person sets on the Server page: never write a key in code. The rest of ctx is below.",
78589
78589
  "- Check every field a player sends, its type and its range, as the patterns do.",
78590
78590
  "",
78591
78591
  "The server API, exactly as server code is checked against it:",
@@ -78609,16 +78609,16 @@ var ONLINE = () => [
78609
78609
  "",
78610
78610
  "- Every table keeps the player's id in a player_id column. Delete my online data, behind the game's Privacy button,",
78611
78611
  " deletes every row whose player_id is the player's, then runs onForget, where the code deletes anything else it keeps",
78612
- " of them. The Online tab marks a table with no player_id.",
78612
+ " of them. The Server page marks a table with no player_id.",
78613
78613
  "- The privacy policy and the store forms follow the game's online, as they follow its ads: the person confirms them",
78614
- " again in the Upload menu's wizards when its server, database, live rooms, files, push or purchases change (the",
78614
+ " again in the Upload page's wizards when its server, database, live rooms, files, push or purchases change (the",
78615
78615
  " publish topic).",
78616
78616
  "- onPurchase, onRevoke and onReward hear what players buy and the ads they watch for a reward, each checked first",
78617
78617
  " with its store or AdMob: the purchases topic has them.",
78618
78618
  "",
78619
78619
  "## Players' files",
78620
78620
  "",
78621
- "- ctx.files keeps the game's files beside its database, once the person turns them on in the Online tab: a player's",
78621
+ "- ctx.files keeps the game's files beside its database, once the person turns them on, on the Server page: a player's",
78622
78622
  " under players/<their id>/, the game's own under game/; a key is at most 512 bytes, with no '..'.",
78623
78623
  "- this.game.online.upload('saveLevel', file, data) sends a file of plain data (at most 1,000,000 bytes as JSON);",
78624
78624
  " uploadScreen('saveShot', data) sends the frame as a PNG. The page asks that call with { size, type, data }; the call",
@@ -78639,15 +78639,15 @@ var ONLINE = () => [
78639
78639
  "- Ask after a moment that shows why (a match ended, a level shared), never at launch. Push is never needed to play,",
78640
78640
  " never an ad the player didn't agree to, never a reward for saying yes (App Store Review Guideline 4.5.4, Google",
78641
78641
  " Play's notifications policy).",
78642
- "- The person's steps, in their own Firebase project, which the Online tab says: add the game's Android and Apple apps;",
78642
+ "- The person's steps, in their own Firebase project, which the Server page says: add the game's Android and Apple apps;",
78643
78643
  " Apple's push key goes into Project settings \u203A Cloud Messaging; the service account and the two app files go into",
78644
- " the Online tab, and each app build carries its own.",
78644
+ " the Server page, and each app build carries its own.",
78645
78645
  "",
78646
78646
  "## Test and live",
78647
78647
  "",
78648
- "- The editor's Game tab plays the game against its test server, and players against live. Each save that changes the",
78648
+ "- Playing in the editor runs the game against its test server, and players against live. Each save that changes the",
78649
78649
  " server code goes to test a moment later; the person sends test's code to players with Publish to players in the",
78650
- " Online tab, and can undo it there. Test and live each have their own database and secrets: test's data is never",
78650
+ " Server page, and can undo it there. Test and live each have their own database and secrets: test's data is never",
78651
78651
  " players'.",
78652
78652
  "- Old apps keep calling: ctx.version says which, so a change can answer them the old way.",
78653
78653
  "",
@@ -78667,13 +78667,13 @@ var ONLINE = () => [
78667
78667
  " person turns on, and where.",
78668
78668
  "- app online_logs reads the server's logs, stage test or live.",
78669
78669
  "- app online_query reads the game's data with one read-only SQL statement: here, where playtests write it, unless",
78670
- " stage says test, or live once the person allows it in the Online tab.",
78670
+ " stage says test, or live once the person allows it on the Server page.",
78671
78671
  "",
78672
78672
  "## What it costs",
78673
78673
  "",
78674
78674
  `- Online is paid by use from the workspace's wallet, apart from its plan: the person adds credit on the Plan page, and`,
78675
78675
  ` it turns on with $10 or more there. A small game's month (about 10,000 calls a day, its database awake two hours a`,
78676
- ` day) costs about ${dollars(priceOf(TYPICAL_MONTH))}; the Online tab and the Plan page give every price.`,
78676
+ ` day) costs about ${dollars(priceOf(TYPICAL_MONTH))}; the Server page and the Plan page give every price.`,
78677
78677
  "- Each size holds its ceilings (calls a second, players at once, work a call, the database's compute and data); a call",
78678
78678
  " past them answers busy.",
78679
78679
  "- When the wallet runs out, the game's server pauses: the game keeps running, its calls answer resting, and nothing",
@@ -78681,8 +78681,8 @@ var ONLINE = () => [
78681
78681
  "",
78682
78682
  "## Games made for children",
78683
78683
  "",
78684
- "- A game made for children (the App tab asks) keeps its live rooms, player files and push off until the person confirms,",
78685
- " in the Online tab, that each is designed to be safe. Design them so: no free text between players, only preset",
78684
+ "- A game made for children (Upload \u203A App asks) keeps its live rooms, player files and push off until the person confirms,",
78685
+ " on the Server page, that each is designed to be safe. Design them so: no free text between players, only preset",
78686
78686
  " phrases, emotes and moves; no name a player types; nothing that says who or where a player is; files only the game",
78687
78687
  " makes, like a level; notifications that never sell and never reward.",
78688
78688
  "- Keep no more of anyone than the game needs.",
@@ -78788,10 +78788,10 @@ var PURCHASES = [
78788
78788
  "- Google's check uses the workspace's Play key file, the one that uploads: its account needs View financial data and",
78789
78789
  " Manage orders in Play Console \u203A Users and permissions. Until the workspace's owner adds it under Store access,",
78790
78790
  " Google's purchases are checked on the phone.",
78791
- "- Refunds and renewals reach the game's own addresses, which the Online tab gives. Apple's: the App Store wizard's",
78791
+ "- Refunds and renewals reach the game's own addresses, which the Server page gives. Apple's: the App Store wizard's",
78792
78792
  " Purchases step sets it. Google's: the person makes a Pub/Sub topic in their Google Cloud project, names it in Play",
78793
78793
  " Console \u203A Monetize \u203A Monetization setup, and adds a push subscription to the game's address, authenticating as the",
78794
- " service account of the workspace's Play key file; a notice sent as anyone else is refused. The Online tab says each",
78794
+ " service account of the workspace's Play key file; a notice sent as anyone else is refused. The Server page says each",
78795
78795
  " step.",
78796
78796
  "",
78797
78797
  "## Checked rewards",
@@ -78801,7 +78801,7 @@ var PURCHASES = [
78801
78801
  " reward, ctx) hears it once: { placement, amount, item, transaction }. Give the reward there; the game asks its",
78802
78802
  " server for it.",
78803
78803
  "- The person pastes that address into each rewarded ad unit in AdMob, under Advanced settings \u203A Server-side",
78804
- " verification; the Online tab gives it. Only rewards from the game's own rewarded ad units (Upload \u203A Ads) count: AdMob",
78804
+ " verification; the Server page gives it. Only rewards from the game's own rewarded ad units (Upload \u203A Ads) count: AdMob",
78805
78805
  " signs every account's alike. AdMob's call can come a few seconds after the ad ends: ask when the ad says rewarded,",
78806
78806
  " and once more a moment later.",
78807
78807
  "- The server keeps each reward under the player's id, which Delete my online data deletes too.",
@@ -78818,7 +78818,7 @@ var PURCHASES = [
78818
78818
  "",
78819
78819
  "## Testing",
78820
78820
  "",
78821
- "- In the editor's Game tab each buy is a card the person answers: Bought, Cancelled or Pending. With the test server",
78821
+ "- When the person plays in the editor, each buy is a card they answer: Bought, Cancelled or Pending. With the test server",
78822
78822
  " granting purchases, Bought reaches its onPurchase as a test purchase, and a reward watched reaches its onReward.",
78823
78823
  "- A playtest buys by itself, granted as a test purchase, and a restore finds nothing owned; with onPurchase, the buy",
78824
78824
  " goes to the server on this machine first. The answer lists each, like purchases: buy coins_100 granted at 1.2 s,",
@@ -79033,7 +79033,7 @@ var GUIDE_TOPICS = [
79033
79033
  { name: "model", about: "art model: 3D art Blender builds from a script, when asked for 3D", text: () => MODEL.join("\n") },
79034
79034
  { name: "team", about: "working beside teammates and their agents: board, parts, claims, notes", text: () => TEAM.join("\n") },
79035
79035
  { name: "film", about: "films: levels that play themselves, cutscenes, chapters, render to MP4", text: () => FILM.join("\n") },
79036
- { name: "publish", about: "the Upload menu: export, GitHub, app builds, stores, privacy, ads", text: () => PUBLISH.join("\n") },
79036
+ { name: "publish", about: "the Upload page: export, GitHub, app builds, stores, privacy, ads", text: () => PUBLISH.join("\n") },
79037
79037
  { name: "online", about: "a game's own server: code, database, live rooms, test and live, costs", text: () => ONLINE().join("\n") },
79038
79038
  { name: "purchases", about: "selling in store apps, and ad rewards the server verifies", text: () => PURCHASES.join("\n") }
79039
79039
  ];
@@ -85255,7 +85255,7 @@ function readArt(args, ctx) {
85255
85255
 
85256
85256
  ${painting}` : modelled !== null ? `${head}, modelled in 3D.${earlier} its model, to change with art model's edit or give whole again, or to render again with art model and its name alone:
85257
85257
 
85258
- ${modelled}` : by === "code" ? `${head}, made with code in the Art tab (the person's Make with code).${earlier} paint it with art paint for a finished look` : `${head}, imported, not painted: the person's own, never replaced`;
85258
+ ${modelled}` : by === "code" ? `${head}, made with code in the Art view (the person's Make with code).${earlier} paint it with art paint for a finished look` : `${head}, imported, not painted: the person's own, never replaced`;
85259
85259
  const shown2 = answer(body, { name: `own:${name}`, kind: entry.kind, painted: painting !== null, modelled: modelled !== null });
85260
85260
  return { ...shown2, content: [...shown2.content, ...picture4] };
85261
85261
  }
@@ -85713,7 +85713,7 @@ var APP_TOOLS = [
85713
85713
  },
85714
85714
  {
85715
85715
  name: "app_online",
85716
- description: "the game's own server (guide online): sizes, today's calls and errors, cost and wallet, versions in use; what the person turns on in the editor's Online tab.",
85716
+ description: "the game's own server (guide online): sizes, today's calls and errors, cost and wallet, versions in use; what the person turns on, on the editor's Server page.",
85717
85717
  inputSchema: object({ game: GAME }, ["game"]),
85718
85718
  handle: (args, ctx) => sent(args, ctx, { action: "online" }, ONLINE2)
85719
85719
  },
@@ -85725,7 +85725,7 @@ var APP_TOOLS = [
85725
85725
  },
85726
85726
  {
85727
85727
  name: "app_online_query",
85728
- description: "one read-only SQL statement on its data: here (playtests'), test, or live once the person allows it in the Online tab.",
85728
+ description: "one read-only SQL statement on its data: here (playtests'), test, or live once the person allows it in the Server page.",
85729
85729
  inputSchema: object({
85730
85730
  game: GAME,
85731
85731
  sql: { type: "string", minLength: 1, maxLength: 4e3, description: "one statement, like select player_id, score from scores" },
@@ -85870,7 +85870,7 @@ var GITHUB_TOOLS = [
85870
85870
  // ../agent/dist/film-tools.js
85871
85871
  var NEEDS_PROGRAM8 = "rendering video runs in the Gamesteel program on your machine, which asks the editor with the game open: add it to your agent with npx gamesteel@latest connect <agent>";
85872
85872
  var STARTED = "Rendering started in the editor where the game is open. It renders each film with no video, or an old one, once for each of the game's languages, and keeps the videos with the game; each answer about the game says how it goes, and how it ended.";
85873
- var NONE = "No editor has this game open: ask the person to open it in the editor and press Render video in the Game tab's Films, or to keep it open and ask you again.";
85873
+ var NONE = "No editor has this game open: ask the person to open it in the editor and press Render video in Upload \u203A Films, or to keep it open and ask you again.";
85874
85874
  var FILM_TOOLS = [
85875
85875
  {
85876
85876
  name: "render_video",
@@ -91719,6 +91719,108 @@ var EDIT_OPS = Object.keys(OP_FIELDS);
91719
91719
  // ../core/dist/render/index.js
91720
91720
  init_sounds();
91721
91721
 
91722
+ // ../design/dist/tokens.js
91723
+ var PALETTE2 = {
91724
+ "bg": "#050607",
91725
+ /** A panel's solid stand-in, and what the scene canvas reads. */
91726
+ "surface": "#101216",
91727
+ /** Raised, solid: banners, and floating glass where blur is missing. */
91728
+ "surface-2": "#181B20",
91729
+ /** The code editor's well. */
91730
+ "field": "#08090B",
91731
+ /** The scene canvas's grid and frame; glass draws its hairlines in white. */
91732
+ "line": "#232833",
91733
+ "line-strong": "#2E3440",
91734
+ "text": "#F3F5F8",
91735
+ "text-2": "#B0B6C0",
91736
+ "text-3": "#999FAA",
91737
+ /** The editor's mint. The renderer's palette and the chrome still agree. */
91738
+ "accent": "#5ED3A0",
91739
+ /** The top of the primary button's gradient, where light catches it. */
91740
+ "accent-hi": "#8EF2C7",
91741
+ /** Words on an accent fill. */
91742
+ "accent-ink": "#06281A",
91743
+ /** Accent chips, solid. */
91744
+ "accent-soft": "#163A2C",
91745
+ /** The AI's colour in the editor: its edits, its outlines, its entries in
91746
+ * the console. Reserved for it, so a person always knows which changes
91747
+ * were not theirs. */
91748
+ "ai": "#8EAEFF",
91749
+ /** The forge's red: the landing page's room glows in it (the owner, 2026-10-12: "put the glow on red"), and it is
91750
+ * the site's accent where the editor has its mint. */
91751
+ "forge": "#EC1B1C",
91752
+ /** The forge's red, light enough to read as words: the site's code and its accent text. */
91753
+ "forge-hi": "#FF6B5E",
91754
+ /** Words on a forge fill. */
91755
+ "forge-ink": "#2B0705",
91756
+ /** The forge's red as the editor's words: lighter than forge-hi, so it reads at 4.5:1 on the editor's lightest
91757
+ * grounds (a hovered row, the selection and the glass over a picture, in a lit room). */
91758
+ "forge-text": "#FF867B",
91759
+ /** What is well and live: the editor's Server with a version live, a teammate in the editor (2026-10-27). */
91760
+ "good": "#6EDB9A",
91761
+ "warn": "#F2B65E",
91762
+ "warn-soft": "#3A2C14",
91763
+ "bad": "#F28A92",
91764
+ "bad-soft": "#3D1D22"
91765
+ };
91766
+ var SPARK = {
91767
+ white: "#FFF3D6",
91768
+ yellow: "#FFC24A",
91769
+ orange: "#FF7A1C",
91770
+ red: "#B8320F"
91771
+ };
91772
+ var CHROME = [
91773
+ [0, "#FFFFFF"],
91774
+ [14, "#FFFFFF"],
91775
+ [30, "#E6E9EE"],
91776
+ [44, "#A9AFB9"],
91777
+ [50, "#3D4148"],
91778
+ [56, "#5D636C"],
91779
+ [66, "#C7CCD4"],
91780
+ [74, "#F0D2B6"],
91781
+ [84, "#FF9A4A"],
91782
+ [100, SPARK.orange]
91783
+ ];
91784
+ var GRAIN_ALPHA = 0.06;
91785
+ var GRAIN = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 ${String(GRAIN_ALPHA)} 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E")`;
91786
+ var ICON = (paths) => `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E${paths}%3C/svg%3E")`;
91787
+ var ICON_ALERT = ICON("%3Cpath d='m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3'/%3E%3Cpath d='M12 9v4'/%3E%3Cpath d='M12 17h.01'/%3E");
91788
+ var ICON_CHECK = ICON("%3Cpath d='M20 6 9 17l-5-5'/%3E");
91789
+ var CHEVRON = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23${PALETTE2["text-2"].slice(1)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")`;
91790
+
91791
+ // ../studio/dist/loading-mark.js
91792
+ var LOADING_MARK = ["svg", { class: "ed-loading-mark", viewBox: "0 0 160 100", width: "160", height: "100", "aria-hidden": "true", focusable: "false" }, [
91793
+ ["defs", {}, [
91794
+ [
91795
+ "linearGradient",
91796
+ { id: "ed-loading-chrome", gradientUnits: "userSpaceOnUse", x1: "0", y1: "28", x2: "0", y2: "72" },
91797
+ CHROME.map(([at2, hex3]) => ["stop", { offset: `${String(at2)}%`, "stop-color": hex3 }])
91798
+ ],
91799
+ ["radialGradient", { id: "ed-loading-heat" }, [
91800
+ ["stop", { offset: "0%", "stop-color": SPARK.orange, "stop-opacity": "0.75" }],
91801
+ ["stop", { offset: "55%", "stop-color": SPARK.red, "stop-opacity": "0.25" }],
91802
+ ["stop", { offset: "100%", "stop-color": SPARK.red, "stop-opacity": "0" }]
91803
+ ]],
91804
+ ["filter", { id: "ed-loading-melt", filterUnits: "userSpaceOnUse", x: "0", y: "0", width: "160", height: "100" }, [
91805
+ ["feGaussianBlur", { in: "SourceGraphic", stdDeviation: "4.5" }],
91806
+ ["feColorMatrix", { values: "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -8" }]
91807
+ ]]
91808
+ ]],
91809
+ ["ellipse", { class: "ed-loading-heat", cx: "80", cy: "78", rx: "58", ry: "12", fill: "url(#ed-loading-heat)" }],
91810
+ ["g", { filter: "url(#ed-loading-melt)", fill: "url(#ed-loading-chrome)" }, [
91811
+ ["circle", { class: "ed-loading-drop is-left", cx: "67", cy: "50", r: "20" }],
91812
+ ["circle", { class: "ed-loading-drop is-right", cx: "95", cy: "51", r: "16" }]
91813
+ ]],
91814
+ ["ellipse", { class: "ed-loading-shine is-left", cx: "60", cy: "39", rx: "7", ry: "2.6", fill: "#FFFFFF" }],
91815
+ ["ellipse", { class: "ed-loading-shine is-right", cx: "90", cy: "42", rx: "5", ry: "2", fill: "#FFFFFF" }]
91816
+ ]];
91817
+ var attribute = (text3) => text3.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
91818
+ function markupOf([tag, attributes, inside2 = []]) {
91819
+ const named2 = Object.entries(attributes).map(([name, value]) => ` ${name}="${attribute(value)}"`).join("");
91820
+ return inside2.length === 0 ? `<${tag}${named2}/>` : `<${tag}${named2}>${inside2.map(markupOf).join("")}</${tag}>`;
91821
+ }
91822
+ var LOADING_PAGE = `<div class="ed-loading"><span class="ed-loading-art">${markupOf(LOADING_MARK)}</span><div class="ed-loading-words"></div><div class="ed-loading-bar"></div><div class="ed-loading-slow"></div></div>`;
91823
+
91722
91824
  // ../studio/dist/server/http.js
91723
91825
  var MAX_BODY_BYTES = 2 * 1024 * 1024;
91724
91826
 
@@ -5331,7 +5331,7 @@ function said(error) {
5331
5331
  const found = FULL.exec(message);
5332
5332
  if (found === null) return error;
5333
5333
  const gb = Math.max(1, Math.round(Number(found[1]) * 1048576 / 1e9));
5334
- return new Error(`this game's database is full: its size holds ${String(gb)} GB. Delete some of its data, or make the database bigger in its Online tab`);
5334
+ return new Error(`this game's database is full: its size holds ${String(gb)} GB. Delete some of its data, or make the database bigger on its Server page`);
5335
5335
  }
5336
5336
  function bindingDb(binding) {
5337
5337
  return {
@@ -5713,7 +5713,7 @@ function guessServiceRegion(url, headers) {
5713
5713
  }
5714
5714
 
5715
5715
  // worker/files.ts
5716
- var NO_FILES_WORDS = "this game has no files: turn them on in its Online tab (they need its database)";
5716
+ var NO_FILES_WORDS = "this game has no files: turn them on, on its Server page (they need its database)";
5717
5717
  var NO_FILES = {
5718
5718
  uploadUrl: () => Promise.reject(new Error(NO_FILES_WORDS)),
5719
5719
  downloadUrl: () => Promise.reject(new Error(NO_FILES_WORDS)),
@@ -5741,7 +5741,7 @@ function uploadOf(key, options, cap) {
5741
5741
  keyed(key);
5742
5742
  const { size } = options;
5743
5743
  if (!Number.isInteger(size) || size < 1) throw new Error("an upload's size is a whole number of bytes, at least 1");
5744
- if (size > cap) throw new Error(`a file is at most ${grouped(cap)} bytes on this server's size, and this is ${grouped(size)}: make the server bigger in the game's Online tab`);
5744
+ if (size > cap) throw new Error(`a file is at most ${grouped(cap)} bytes on this server's size, and this is ${grouped(size)}: make the server bigger in the game's Server page`);
5745
5745
  const seconds = secondsOf(options.seconds, UPLOAD_SECONDS, `an upload's address lasts at most ${String(UPLOAD_SECONDS)} seconds`);
5746
5746
  return { size, contentType: options.contentType ?? "application/octet-stream", seconds };
5747
5747
  }
@@ -5834,7 +5834,7 @@ function filesOf(config, cap, fetcher = fetch) {
5834
5834
  // src/firebase.ts
5835
5835
  var TOKEN_URL = "https://oauth2.googleapis.com/token";
5836
5836
  var FCM_SCOPE = "https://www.googleapis.com/auth/firebase.messaging";
5837
- var FOR_PUSH = { scope: FCM_SCOPE, unusable: "the game's Firebase service account has no usable private key: add its JSON again in the Online tab" };
5837
+ var FOR_PUSH = { scope: FCM_SCOPE, unusable: "the game's Firebase service account has no usable private key: add its JSON again on the Server page" };
5838
5838
  var base64url = (bytes) => {
5839
5839
  let text = "";
5840
5840
  for (const byte of bytes) text += String.fromCharCode(byte);
@@ -5874,7 +5874,7 @@ async function accessToken(account, fetcher, now, purpose = FOR_PUSH) {
5874
5874
 
5875
5875
  // worker/push.ts
5876
5876
  var PLATFORMS = ["ios", "android"];
5877
- var NO_PUSH_WORDS = "this game has no push: turn it on in its Online tab, with its Firebase project (it needs its database)";
5877
+ var NO_PUSH_WORDS = "this game has no push: turn it on, on its Server page, with its Firebase project (it needs its database)";
5878
5878
  var NO_PUSH = {
5879
5879
  send: () => Promise.reject(new Error(NO_PUSH_WORDS)),
5880
5880
  register: () => Promise.reject(new Error(NO_PUSH_WORDS))
@@ -6443,7 +6443,7 @@ async function factsOf(deps, body, app) {
6443
6443
  async function purchase(deps, body, effects) {
6444
6444
  const refused = (reason) => ({ result: "refused", reason, effects: effects() });
6445
6445
  if (deps.onPurchase === void 0) return refused("this game's server code has no onPurchase");
6446
- if (deps.app === null || Object.keys(deps.app.products).length === 0) return refused("this game sells nothing: its products are in its Upload menu");
6446
+ if (deps.app === null || Object.keys(deps.app.products).length === 0) return refused("this game sells nothing: its products are in its Upload page");
6447
6447
  let facts;
6448
6448
  try {
6449
6449
  const found = await factsOf(deps, body, deps.app);
@@ -6472,9 +6472,9 @@ async function purchase(deps, body, effects) {
6472
6472
  }
6473
6473
  async function notice(deps, body) {
6474
6474
  const app = deps.app;
6475
- if (app === null) return deps.log("a store's notice reached this game, which sells nothing: its products are in its Upload menu");
6475
+ if (app === null) return deps.log("a store's notice reached this game, which sells nothing: its products are in its Upload page");
6476
6476
  if (body.store === "apple") {
6477
- if (app.bundleId === null) return deps.log("an App Store notice reached this game, which has no iOS app: its id is in the App tab");
6477
+ if (app.bundleId === null) return deps.log("an App Store notice reached this game, which has no iOS app: its id is in Upload \u203A App");
6478
6478
  const heard2 = await appleNotice(body.payload, { ...deps.apple, bundleId: app.bundleId, stage: body.stage });
6479
6479
  if (heard2.type === "TEST") return deps.log("Apple's test notification reached the game");
6480
6480
  const facts2 = heard2.transaction;
@@ -6524,7 +6524,7 @@ async function reward(deps, body) {
6524
6524
  if (given.transaction === "") throw new Error("AdMob's reward has no transaction");
6525
6525
  const unit = given.adUnit ?? "";
6526
6526
  const ours = body.stage === "test" && unit === "test" ? true : unit !== "" && unit !== "test" && (deps.app?.rewardUnits ?? []).some((id) => id === unit || id.slice(id.lastIndexOf("/") + 1) === unit);
6527
- if (!ours) return deps.log(`a reward from an ad unit that is not this game's (${unit === "" ? "none named" : unit}) was refused: its reward ad units are in its Upload menu`);
6527
+ if (!ours) return deps.log(`a reward from an ad unit that is not this game's (${unit === "" ? "none named" : unit}) was refused: its reward ad units are in its Upload page`);
6528
6528
  if (!await once(deps, "admob", given.transaction)) return;
6529
6529
  const kept = { placement: given.placement ?? "", amount: given.amount, item: given.item, transaction: given.transaction };
6530
6530
  try {
@@ -6549,7 +6549,7 @@ function bound(text) {
6549
6549
  return null;
6550
6550
  }
6551
6551
  }
6552
- var NO_DATABASE = "this game has no database: turn it on in its Online tab";
6552
+ var NO_DATABASE = "this game has no database: turn it on, on its Server page";
6553
6553
  var noDb = { query: () => Promise.reject(new Error(NO_DATABASE)) };
6554
6554
  var words2 = (error) => error instanceof Error ? error.message : String(error);
6555
6555
  var answer = (body) => new Response(JSON.stringify(body), { headers: { "content-type": "application/json" } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gamesteel",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "The Gamesteel program your AI agent starts, and the command that sets it up in Claude Code, Codex, Gemini CLI, Cursor, VS Code and 25 more. The work runs on your machine; the website keeps your games.",
5
5
  "keywords": [
6
6
  "gamesteel",
@@ -39,23 +39,23 @@
39
39
  "@modelcontextprotocol/sdk": "^1.0.0",
40
40
  "esbuild": "0.28.2",
41
41
  "miniflare": "4.20260730.0",
42
+ "@gamesteel/agent": "0.1.0",
42
43
  "@gamesteel/accounts": "0.1.0",
43
44
  "@gamesteel/builder": "0.1.0",
45
+ "@gamesteel/edit": "0.1.0",
46
+ "@gamesteel/i18n": "0.1.0",
44
47
  "@gamesteel/billing": "0.1.0",
45
- "@gamesteel/agent": "0.1.0",
46
- "@gamesteel/connect": "0.1.0",
48
+ "@gamesteel/core": "0.1.0",
47
49
  "@gamesteel/cloud": "0.1.0",
48
- "@gamesteel/i18n": "0.1.0",
49
- "@gamesteel/edit": "0.1.0",
50
+ "@gamesteel/connect": "0.1.0",
51
+ "@gamesteel/design": "0.1.0",
50
52
  "@gamesteel/model": "0.1.0",
51
- "@gamesteel/core": "0.1.0",
53
+ "@gamesteel/github": "0.1.0",
52
54
  "@gamesteel/service": "0.1.0",
55
+ "@gamesteel/store": "0.1.0",
53
56
  "@gamesteel/online": "0.1.0",
54
- "@gamesteel/studio": "0.1.0",
55
57
  "@gamesteel/stores": "0.1.0",
56
- "@gamesteel/github": "0.1.0",
57
- "@gamesteel/design": "0.1.0",
58
- "@gamesteel/store": "0.1.0"
58
+ "@gamesteel/studio": "0.1.0"
59
59
  },
60
60
  "scripts": {
61
61
  "pretest": "pnpm --filter \"gamesteel^...\" --filter \"!@gamesteel/studio\" build && pnpm --filter @gamesteel/studio exec tsc -p tsconfig.json && pnpm build",