From 4d82c5a7049ac22a7e1e63b99d4a57dbac22bad0 Mon Sep 17 00:00:00 2001 From: Duane Irvin Date: Thu, 7 May 2026 11:14:08 +0200 Subject: [PATCH 1/4] Update gxgames meta description --- src/commands/gxgames/command.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/commands/gxgames/command.ts b/src/commands/gxgames/command.ts index 1879a5f..b49d99a 100644 --- a/src/commands/gxgames/command.ts +++ b/src/commands/gxgames/command.ts @@ -124,8 +124,7 @@ const gxgamesMetaCommand = buildCommand({ brief: "Set or update game metadata required for publishing", fullDescription: "Set or update metadata for your GX.Games game. " + - "Run without flags for an interactive prompt, or pass flags to set specific fields. " + - "All flags are optional — omit any flag to be prompted for it interactively.", + "Each flag overrides the corresponding field; omitted flags keep their current server value.", }, }); From 45f2547ac80ff604c309d698432ff74eb6f7143a Mon Sep 17 00:00:00 2001 From: Duane Irvin Date: Thu, 7 May 2026 11:17:02 +0200 Subject: [PATCH 2/4] Use age-rating instead of agerating param --- src/commands/gxgames/command.ts | 3 ++- src/commands/gxgames/commands/meta-impl.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/commands/gxgames/command.ts b/src/commands/gxgames/command.ts index b49d99a..1099f1a 100644 --- a/src/commands/gxgames/command.ts +++ b/src/commands/gxgames/command.ts @@ -70,6 +70,7 @@ const gxgamesUploadCommand = buildCommand({ brief: "Upload a game bundle to GX.Games", fullDescription: "Uploads a zip bundle to GX.Games. " + + "Produce the zip with `gm-cli package --target operagx`. " + "Prompts for the version number if --version is not provided.", }, }); @@ -85,7 +86,7 @@ const gxgamesMetaCommand = buildCommand({ brief: "Game title", optional: true, }, - agerating: { + ageRating: { kind: "parsed", parse: String, brief: diff --git a/src/commands/gxgames/commands/meta-impl.ts b/src/commands/gxgames/commands/meta-impl.ts index f769eae..7f58dd5 100644 --- a/src/commands/gxgames/commands/meta-impl.ts +++ b/src/commands/gxgames/commands/meta-impl.ts @@ -29,7 +29,7 @@ import type { interface MetaFlags { title?: string; - agerating?: string; + ageRating?: string; description?: string; platforms?: string; cover?: string; @@ -59,7 +59,7 @@ export default async function ( title: flags.title ?? game.title, shortDescription: flags.description ?? game.shortDescription, ageRating: - (flags.agerating?.toUpperCase() as + (flags.ageRating?.toUpperCase() as | GameDevUpdateGameRequestAgeRatingEnum | undefined) ?? (game.ageRating as GameDevUpdateGameRequestAgeRatingEnum), From 405e31e5e4b0caaf9d6304f61b1e3dde911f6cfe Mon Sep 17 00:00:00 2001 From: Duane Irvin Date: Thu, 7 May 2026 11:17:53 +0200 Subject: [PATCH 3/4] Validate version number --- src/commands/gxgames/commands/upload-impl.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/commands/gxgames/commands/upload-impl.ts b/src/commands/gxgames/commands/upload-impl.ts index f076959..685b30a 100644 --- a/src/commands/gxgames/commands/upload-impl.ts +++ b/src/commands/gxgames/commands/upload-impl.ts @@ -24,6 +24,12 @@ import type { ProjectPath } from "~/project"; import { LinkStorage } from "../api"; +const VERSION_RE = /^\d+\.\d+\.\d+\.\d+$/; +const validateVersion = (v: string | undefined): string | undefined => + v && VERSION_RE.test(v) + ? undefined + : "Version must be X.Y.Z.B (e.g. 1.0.0.0)"; + export default async function ( this: Context, flags: { file: string; version?: string }, @@ -49,12 +55,17 @@ export default async function ( let version: string; if (flags.version != null) { + const err = validateVersion(flags.version); + if (err) { + throw new KnownError(err); + } version = flags.version; } else { const v = await p.text({ message: "Version", placeholder: "0.0.1.0", defaultValue: previousVersion, + validate: validateVersion, }); if (p.isCancel(v)) { return process.exit(0); From a07a4b4e64f5fda091cc2f731c155f6e4fd55d04 Mon Sep 17 00:00:00 2001 From: Duane Irvin Date: Thu, 7 May 2026 11:30:32 +0200 Subject: [PATCH 4/4] Update readme --- README.md | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b1ee97c..09087f4 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,40 @@ npx @gamemaker/gm-cli@latest login gm-cli manual open "sprites" --language=es ``` +### Publish to GX.Games +Use `gm-cli gxgames` to publish a game to [gx.games](https://gx.games). Run `gm-cli gxgames --help` for the full list of subcommands. + +The flow: + +1. **Package** the game as an OperaGX zip: + ```sh + npx @gamemaker/gm-cli@latest package --target=operagx --output=game.zip + ``` +2. **Link** the project to a studio and game (opens the browser to sign in on first use): + ```sh + npx @gamemaker/gm-cli@latest gxgames link --studioid= --gameid= + ``` + Omit the flags to pick interactively. +3. **Upload** the zip (prompts for a `X.Y.Z.B` version if `--version` is omitted): + ```sh + npx @gamemaker/gm-cli@latest gxgames upload --file=game.zip --version=1.0.0.0 + ``` +4. **Set metadata** required for publishing — title (must be unique across GX.Games), description, age rating, platforms, 16:9 cover, and 16:9 screenshot. Cover and graphic must have an **exact** 16:9 aspect ratio (e.g. 1920×1080): + ```sh + npx @gamemaker/gm-cli@latest gxgames meta \ + --title="My Game" \ + --description="A short description" \ + --age-rating=EVERYONE \ + --platforms=DESKTOP,MOBILE \ + --cover=cover_1920x1080.png \ + --graphic=screenshot_1920x1080.png + ``` + Each flag overrides one field; omitted flags keep the current server value. +5. **Publish** to make the game public (opens the published page on success): + ```sh + npx @gamemaker/gm-cli@latest gxgames publish + ``` + ## Near future > Note: The GameMaker CLI is made for the community and we welcome your feedback! Please suggest features or tell us about any issues you are having. @@ -81,10 +115,6 @@ The `ask` subcommand displays an article directly in your terminal, gm-cli manual ask "data structures" ``` -### Publishing games to the web - -Direct integration with [gx.games](https://gx.games) to share your games! - ### A library to make your own tools `gm-cli` will expose its internals as a TypeScript library that you can use to more easily make your own editor tools.