@genex-ai/cli-demo 0.2.0 → 0.3.0

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/README.md CHANGED
@@ -5,13 +5,20 @@ This is the `cli` app of the [genex monorepo](../../README.md).
5
5
 
6
6
  ```bash
7
7
  genex init <name> # authorize + create the draft project
8
- genex publish # push the built game + list it in the gallery
8
+ genex preview # build + push to the hosted draft URL (unlisted)
9
+ genex publish # build + push, then list the game in the gallery
9
10
  genex model "<prompt>" # generate a 3D model → assets/models/
10
11
  genex skybox "<prompt>" # generate a 360° sky → assets/skybox/
11
12
  genex sfx "<prompt>" # generate a sound fx → assets/sfx/
12
13
  genex texture "<prompt>" # generate a texture → assets/textures/
13
14
  ```
14
15
 
16
+ > **Invoking it.** First-time setup runs via `npx @genex-ai/cli-demo@latest init`.
17
+ > The scaffold then adds `@genex-ai/cli-demo` as a project dev dependency, so the
18
+ > rest run as **`npx genex <cmd>`** from the project dir (resolving to this CLI,
19
+ > never a different global `genex`). `genex <cmd>` works too if you install it
20
+ > globally. The bare command forms below name the command; prefix with `npx` to run.
21
+
15
22
  `genex init` does four things:
16
23
 
17
24
  1. **Scaffolds your workspace** — copies the bundled templates (skills, agents,
@@ -27,11 +34,21 @@ genex texture "<prompt>" # generate a texture → assets/textures/
27
34
  `sshUrl`, urls) in `./.genex/project.json`. The game shows up in your
28
35
  dashboard's **My games** immediately.
29
36
 
30
- `genex publish` reads that metadata, pushes the built game to GitHub over the
31
- deploy key (best-effort `index.html` must be at the repo root), then flips the
32
- project to **published** so it appears in the public gallery. `git push` (updates
33
- the live Pages site) and the gallery flag are independent; `--no-push` skips the
34
- push. Defaults: API `https://demo-api.glotech.world`, auth site
37
+ `genex preview` and `genex publish` share a build-aware deploy core: each runs
38
+ `npm run build` (when the project has a build script), then pushes the built
39
+ `dist/` **as the repo root** over the deploy key no copying files or swapping
40
+ `index.html` by hand. A `.nojekyll` marker is written so GitHub Pages serves the
41
+ bundle verbatim, and the deploy never stages `genex_key` (the private key can't
42
+ leak). Pass `--no-build` to deploy whatever is already built.
43
+
44
+ - **`genex preview`** pushes the current build to the project's hosted draft URL
45
+ (`https://<user>.github.io/<slug>/`) without listing it publicly — re-run it
46
+ after each change to update the shareable draft.
47
+ - **`genex publish`** does the same deploy, then flips the project to
48
+ **published** so it appears in the public gallery. The deploy and the gallery
49
+ flag are independent; `--no-push` flips the flag only.
50
+
51
+ Defaults: API `https://demo-api.glotech.world`, auth site
35
52
  `https://demo-web.glotech.world` — override with `--api-url` / `--auth-url` (or
36
53
  `GENEX_API_URL` / `GENEX_AUTH_URL`) for local dev.
37
54
 
@@ -77,11 +94,12 @@ pnpm --filter @genex-ai/cli-demo start init
77
94
  Once published, end users run it with `npx`:
78
95
 
79
96
  ```bash
80
- npx @genex-ai/cli-demo init
97
+ npx @genex-ai/cli-demo@latest init
81
98
  ```
82
99
 
83
- > Requires **Node 24** (the CLI is executed as TypeScript via Node's native
84
- > type stripping, matching the rest of the monorepo).
100
+ > The published package ships a bundled `dist/` (built with tsup) and runs on
101
+ > **Node 20**. Running from *source* in the monorepo needs **Node ≥ 24** (the
102
+ > source is executed as TypeScript via Node's native type stripping).
85
103
 
86
104
  ## Usage
87
105
 
@@ -90,8 +108,8 @@ genex init [options]
90
108
 
91
109
  Options
92
110
  --dir <path> Destination workspace (default: ~/.claude)
93
- --env <path> Path to the .env file to write (default: ./.env)
94
- --auth-url <url> Override the auth site (default: https://genex.dev)
111
+ --env <path> Token env file (default: ~/.genex/env)
112
+ --auth-url <url> Override the auth site (default: https://demo-web.glotech.world)
95
113
  --no-auth Only scaffold templates; skip authorization
96
114
  --force Overwrite existing files (default: never overwrite)
97
115
  --timeout <seconds> How long to wait for the auth redirect (default: 300)
@@ -122,8 +140,8 @@ genex init --auth-url http://localhost:3000
122
140
 
123
141
  The auth site URL is a single configurable value:
124
142
 
125
- - **Default:** `https://genex.dev` (the `DEFAULT_AUTH_URL` constant in
126
- [`src/config.ts`](src/config.ts)).
143
+ - **Default:** `https://demo-web.glotech.world` (the `DEFAULT_AUTH_URL` constant
144
+ in [`src/config.ts`](src/config.ts)).
127
145
  - **Override at runtime:** set `GENEX_AUTH_URL`, or pass `--auth-url`.
128
146
 
129
147
  ```bash
@@ -168,8 +186,8 @@ The CLI uses a loopback-redirect flow (the same pattern as `gh auth login` and
168
186
  > the exact `state` it received. A missing or mismatched `state` is rejected
169
187
  > (CSRF protection).
170
188
 
171
- 3. The CLI verifies `state`, writes `GENEX_TOKEN=<TOKEN>` to `.env`, and shows a
172
- success page in the browser.
189
+ 3. The CLI verifies `state`, writes `GENEX_TOKEN=<TOKEN>` to `~/.genex/env`, and
190
+ shows a success page in the browser.
173
191
 
174
192
  If the browser can't be opened, the URL is printed and — when run in an
175
193
  interactive terminal — a pasted token is also accepted.
@@ -236,9 +254,9 @@ templates/ copied into ~/.claude by `genex init`
236
254
 
237
255
  ## Publishing
238
256
 
239
- The package ships its TypeScript source (no bundle); consumers run it on
240
- Node ≥ 24. The published tarball includes only `src/`, `templates/`, `README.md`,
241
- and `LICENSE` (see the `files` field in `package.json`).
257
+ The package ships a bundled `dist/` (built with tsup via `prepack`); consumers
258
+ run it on Node ≥ 20. The published tarball includes `dist/`, `templates/`,
259
+ `README.md`, and `LICENSE` (see the `files` field in `package.json`).
242
260
 
243
261
  ```bash
244
262
  pnpm --filter @genex-ai/cli-demo publish --access public
package/dist/index.js CHANGED
@@ -396,7 +396,7 @@ async function createDraftProject(opts) {
396
396
  return null;
397
397
  }
398
398
  log.success(`Created project ${c.cyan(project.slug)}.`);
399
- if (project.playUrl) log.dim(` play (after publish): ${project.playUrl}`);
399
+ if (project.playUrl) log.dim(` play (after preview/publish): ${project.playUrl}`);
400
400
  log.dim(` dashboard: ${dashboardUrl}/dashboard`);
401
401
  return {
402
402
  id: project.id,
@@ -701,9 +701,10 @@ async function runInit(opts) {
701
701
  log.success("All set. \u{1F680}");
702
702
  }
703
703
 
704
- // src/commands/publish.ts
704
+ // src/lib/deploy.ts
705
705
  import { spawn as spawn4 } from "child_process";
706
706
  import fs5 from "fs/promises";
707
+ import os2 from "os";
707
708
  import path7 from "path";
708
709
  function run(cmd, args, env) {
709
710
  return new Promise((resolve) => {
@@ -722,6 +723,113 @@ function run(cmd, args, env) {
722
723
  child.on("close", (code2) => resolve({ code: code2 ?? -1, out, err }));
723
724
  });
724
725
  }
726
+ async function deployGame(sshUrl, opts, log) {
727
+ const cwd = process.cwd();
728
+ if (!opts.noBuild && await hasBuildScript(cwd)) {
729
+ log.step("Building the production bundle\u2026");
730
+ const built = await run("npm", ["run", "build"]);
731
+ if (built.code !== 0) {
732
+ log.error("Build failed \u2014 your game was NOT deployed.");
733
+ const tail = (built.err || built.out).trim().split("\n").slice(-12).join("\n");
734
+ if (tail) log.dim(tail);
735
+ return false;
736
+ }
737
+ log.success("Built.");
738
+ }
739
+ const distDir = path7.join(cwd, "dist");
740
+ const siteDir = await isDir(distDir) ? distDir : cwd;
741
+ if (siteDir === cwd) {
742
+ await writeGitignore(cwd, log);
743
+ }
744
+ const rel = path7.relative(cwd, siteDir) || ".";
745
+ try {
746
+ await fs5.access(path7.join(siteDir, "index.html"));
747
+ } catch {
748
+ log.warn(`No index.html in ${rel} \u2014 GitHub Pages needs one to serve the game.`);
749
+ }
750
+ await warnIfAbsolutePaths(siteDir, log);
751
+ await fs5.writeFile(path7.join(siteDir, ".nojekyll"), "");
752
+ const keyPath = path7.resolve(cwd, KEY_NAME);
753
+ if (!await fileExists(keyPath)) {
754
+ log.warn(`No deploy key (${KEY_NAME}) here \u2014 run \`genex init\` in this folder first.`);
755
+ return false;
756
+ }
757
+ const gitDir = await fs5.mkdtemp(path7.join(os2.tmpdir(), "genex-deploy-"));
758
+ const gitEnv = { GIT_DIR: gitDir, GIT_WORK_TREE: siteDir };
759
+ try {
760
+ if ((await run("git", ["init", "-q"], gitEnv)).code !== 0) {
761
+ log.warn("git init failed \u2014 the game was not pushed.");
762
+ return false;
763
+ }
764
+ await run("git", ["add", "-A"], gitEnv);
765
+ const tracked = await run("git", ["ls-files"], gitEnv);
766
+ if (/(^|\/)genex_key(\.pub)?$/m.test(tracked.out)) {
767
+ log.error(`Refusing to deploy: ${KEY_NAME} is staged. Add it to .gitignore and retry.`);
768
+ return false;
769
+ }
770
+ const commit = await run(
771
+ "git",
772
+ ["-c", "user.email=agent@genex.local", "-c", "user.name=genex", "commit", "-q", "-m", "build"],
773
+ gitEnv
774
+ );
775
+ if (commit.code !== 0 && !/nothing to commit/i.test(commit.out + commit.err)) {
776
+ log.warn("Nothing to commit \u2014 the build produced no files.");
777
+ return false;
778
+ }
779
+ log.step("Pushing your game over SSH\u2026");
780
+ const push = await run("git", ["push", "-q", sshUrl, "+HEAD:main"], {
781
+ ...gitEnv,
782
+ GIT_SSH_COMMAND: `ssh -i ${keyPath} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new`
783
+ });
784
+ if (push.code === 0) {
785
+ log.success("Pushed.");
786
+ return true;
787
+ }
788
+ log.warn("git push failed \u2014 your live game was NOT updated.");
789
+ const tail = push.err.trim().split("\n").slice(-2).join(" ");
790
+ if (tail) log.dim(` ${tail}`);
791
+ return false;
792
+ } finally {
793
+ await fs5.rm(gitDir, { recursive: true, force: true }).catch(() => {
794
+ });
795
+ }
796
+ }
797
+ async function hasBuildScript(cwd) {
798
+ try {
799
+ const pkg = JSON.parse(await fs5.readFile(path7.join(cwd, "package.json"), "utf8"));
800
+ return Boolean(pkg.scripts?.build);
801
+ } catch {
802
+ return false;
803
+ }
804
+ }
805
+ async function isDir(p) {
806
+ try {
807
+ return (await fs5.stat(p)).isDirectory();
808
+ } catch {
809
+ return false;
810
+ }
811
+ }
812
+ async function fileExists(p) {
813
+ try {
814
+ await fs5.access(p);
815
+ return true;
816
+ } catch {
817
+ return false;
818
+ }
819
+ }
820
+ async function warnIfAbsolutePaths(siteDir, log) {
821
+ let html;
822
+ try {
823
+ html = await fs5.readFile(path7.join(siteDir, "index.html"), "utf8");
824
+ } catch {
825
+ return;
826
+ }
827
+ if (/(?:src|href)="\/(?!\/)/.test(html)) {
828
+ log.warn("Built index.html uses absolute paths \u2014 set `base: './'` in vite.config so assets load under the Pages subpath.");
829
+ }
830
+ }
831
+
832
+ // src/commands/publish.ts
725
833
  async function runPublish(opts) {
726
834
  const log = createLogger({ quiet: opts.quiet });
727
835
  log.plain(c.bold("genex publish"));
@@ -741,11 +849,11 @@ async function runPublish(opts) {
741
849
  const apiUrl = getApiUrl(opts.apiUrl ?? meta.apiUrl);
742
850
  let pushed = null;
743
851
  if (opts.noPush) {
744
- log.info("Skipping git push (--no-push).");
852
+ log.info("Skipping build + git push (--no-push).");
745
853
  } else {
746
- pushed = await pushGame(meta.sshUrl, log);
854
+ pushed = await deployGame(meta.sshUrl, { noBuild: opts.noBuild }, log);
747
855
  }
748
- log.step("Publishing to the gallery\u2026");
856
+ log.step("Listing it in the gallery\u2026");
749
857
  let res;
750
858
  try {
751
859
  const body = {};
@@ -771,7 +879,7 @@ async function runPublish(opts) {
771
879
  log.warn(
772
880
  "Listed in the gallery, but the game wasn't pushed \u2014 the play URL won't work until the push succeeds."
773
881
  );
774
- log.dim(" Fix the push error above and re-run `genex publish`.");
882
+ log.dim(" Fix the error above and re-run `genex publish`.");
775
883
  } else {
776
884
  log.success("Published. \u{1F389}");
777
885
  }
@@ -780,37 +888,30 @@ async function runPublish(opts) {
780
888
  if (pushed === true) log.dim(" (GitHub Pages rebuilds ~30\u201390s after a push.)");
781
889
  }
782
890
  }
783
- async function pushGame(sshUrl, log) {
784
- try {
785
- await fs5.access(path7.join(process.cwd(), "index.html"));
786
- } catch {
787
- log.warn("No index.html at the project root \u2014 GitHub Pages needs one to serve the game.");
788
- }
789
- const isRepo = (await run("git", ["rev-parse", "--git-dir"])).code === 0;
790
- if (!isRepo) {
791
- log.step("Initializing git\u2026");
792
- if ((await run("git", ["init"])).code !== 0) {
793
- log.warn("git init failed \u2014 the game was not pushed (use `genex publish --no-push` to silence).");
794
- return false;
795
- }
891
+
892
+ // src/commands/preview.ts
893
+ async function runPreview(opts) {
894
+ const log = createLogger({ quiet: opts.quiet });
895
+ log.plain(c.bold("genex preview"));
896
+ log.plain("");
897
+ const meta = await readProject();
898
+ if (!meta) {
899
+ log.error("No genex project here. Run `genex init` in this directory first.");
900
+ process.exitCode = 1;
901
+ return;
796
902
  }
797
- await run("git", ["add", "-A"]);
798
- const commit = await run("git", ["commit", "-m", "build"]);
799
- if (commit.code !== 0 && !/nothing to commit/i.test(commit.out + commit.err)) {
800
- log.dim(" (no new commit to push)");
903
+ const pushed = await deployGame(meta.sshUrl, { noBuild: opts.noBuild }, log);
904
+ log.plain("");
905
+ if (!pushed) {
906
+ log.warn("Preview not updated \u2014 see the error above.");
907
+ process.exitCode = 1;
908
+ return;
801
909
  }
802
- log.step("Pushing your game over SSH\u2026");
803
- const push = await run("git", ["push", sshUrl, "+HEAD:main"], {
804
- GIT_SSH_COMMAND: `ssh -i ./${KEY_NAME} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new`
805
- });
806
- if (push.code === 0) {
807
- log.success("Pushed to main.");
808
- return true;
910
+ log.success("Preview deployed. \u{1F310}");
911
+ if (meta.playUrl) {
912
+ log.dim(` ${meta.playUrl}`);
913
+ log.dim(" (GitHub Pages rebuilds ~30\u201390s after a push; it stays an unlisted draft until you publish.)");
809
914
  }
810
- log.warn("git push failed \u2014 your live game was NOT updated.");
811
- const tail = push.err.trim().split("\n").slice(-2).join(" ");
812
- if (tail) log.dim(` ${tail}`);
813
- return false;
814
915
  }
815
916
 
816
917
  // src/commands/generate.ts
@@ -981,7 +1082,8 @@ var HELP = `${c.bold("genex")} \u2014 set up your ~/.claude workspace, authorize
981
1082
 
982
1083
  ${c.bold("Usage")}
983
1084
  genex init [<name>] [options] Scaffold + authorize + create the draft project.
984
- genex publish [options] Push the built game and list it in the gallery.
1085
+ genex preview [options] Build + push to the hosted draft URL (unlisted).
1086
+ genex publish [options] Build + push, then list the game in the gallery.
985
1087
  genex model "<prompt>" [options] Generate a 3D model (GLB) into ./assets/models.
986
1088
  genex skybox "<prompt>" [options] Generate a skybox (equirect) into ./assets/skybox.
987
1089
  genex sfx "<prompt>" [options] Generate a sound effect (mp3) into ./assets/sfx.
@@ -1006,11 +1108,12 @@ ${c.bold("Options for `init`")}
1006
1108
  --force Overwrite existing files (default: never overwrite).
1007
1109
  --timeout <seconds> How long to wait for the auth redirect (default: 300).
1008
1110
 
1009
- ${c.bold("Options for `publish`")}
1010
- --no-push Skip the git push; only flip the gallery flag.
1011
- --title <title> Gallery title.
1012
- --description <text> Gallery description.
1013
- --api-url <url> Override the API base URL.
1111
+ ${c.bold("Options for `preview` / `publish`")}
1112
+ --no-build Skip the build step; deploy whatever is already built.
1113
+ --no-push (publish) Skip build + push; only flip the gallery flag.
1114
+ --title <title> (publish) Gallery title.
1115
+ --description <text> (publish) Gallery description.
1116
+ --api-url <url> (publish) Override the API base URL.
1014
1117
  --env <path> Token env file (default: ~/.genex/env).
1015
1118
 
1016
1119
  ${c.bold("Global")}
@@ -1027,6 +1130,7 @@ ${c.bold("Environment")}
1027
1130
  ${c.bold("Examples")}
1028
1131
  genex init my-game
1029
1132
  genex init my-game --api-url http://localhost:3000 --auth-url http://localhost:5173
1133
+ genex preview
1030
1134
  genex publish
1031
1135
  genex publish --no-push --title "My Game"
1032
1136
  genex model "weathered wooden barrel with iron bands"
@@ -1072,6 +1176,9 @@ function parseArgs(argv) {
1072
1176
  case "--no-push":
1073
1177
  parsed.options.noPush = true;
1074
1178
  break;
1179
+ case "--no-build":
1180
+ parsed.options.noBuild = true;
1181
+ break;
1075
1182
  case "--no-wait":
1076
1183
  parsed.options.noWait = true;
1077
1184
  break;
@@ -1188,6 +1295,9 @@ async function main() {
1188
1295
  case "init":
1189
1296
  await runInit(parsed.options);
1190
1297
  break;
1298
+ case "preview":
1299
+ await runPreview(parsed.options);
1300
+ break;
1191
1301
  case "publish":
1192
1302
  await runPublish(parsed.options);
1193
1303
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/cli-demo",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Set up your ~/.claude workspace, authorize, create a game project, generate AI assets, and publish (genex CLI).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,6 +15,14 @@
15
15
  "engines": {
16
16
  "node": ">=20"
17
17
  },
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "prepack": "pnpm build",
21
+ "start": "node src/index.ts",
22
+ "dev": "node --watch src/index.ts",
23
+ "typecheck": "tsc --noEmit",
24
+ "test": "node --test test/*.test.ts"
25
+ },
18
26
  "keywords": [
19
27
  "cli",
20
28
  "claude",
@@ -38,12 +46,5 @@
38
46
  "bugs": {
39
47
  "url": "https://github.com/me-ai-org/genex-demo/issues"
40
48
  },
41
- "homepage": "https://github.com/me-ai-org/genex-demo/tree/main/apps/cli#readme",
42
- "scripts": {
43
- "build": "tsup",
44
- "start": "node src/index.ts",
45
- "dev": "node --watch src/index.ts",
46
- "typecheck": "tsc --noEmit",
47
- "test": "node --test test/*.test.ts"
48
- }
49
- }
49
+ "homepage": "https://github.com/me-ai-org/genex-demo/tree/main/apps/cli#readme"
50
+ }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: genex-ai-model
3
- description: Generate a real 3D model (GLB mesh) from a text prompt with `genex model`, then load it into the Three.js scene. Use when the user wants a specific prop, item, character, vehicle, building, or any concrete object as an actual mesh ("add a wooden barrel", "I need a spaceship", "generate a sword") rather than a procedurally-coded shape.
3
+ description: Generate a real 3D model (GLB mesh) from a text prompt with `npx genex model`, then load it into the Three.js scene. Use when the user wants a specific prop, item, character, vehicle, building, or any concrete object as an actual mesh ("add a wooden barrel", "I need a spaceship", "generate a sword") rather than a procedurally-coded shape.
4
4
  ---
5
5
 
6
6
  # Genex AI · Model
@@ -9,7 +9,7 @@ Turn a text prompt into a real, game-ready **GLB** and drop it into the project.
9
9
 
10
10
  ## When to use this vs. procedural geometry
11
11
 
12
- - **Use `genex model`** for a specific, recognizable object — a barrel, a chair, a
12
+ - **Use `npx genex model`** for a specific, recognizable object — a barrel, a chair, a
13
13
  sword, a spaceship, an animal. You get a real textured mesh.
14
14
  - **Use `$genex-threejs-procedural-geometry`** for parametric/abstract shapes,
15
15
  terrain, or anything you want to generate in code (infinite variations, no files).
@@ -17,7 +17,7 @@ Turn a text prompt into a real, game-ready **GLB** and drop it into the project.
17
17
  ## Run
18
18
 
19
19
  ```bash
20
- genex model "<prompt>"
20
+ npx genex model "<prompt>"
21
21
  ```
22
22
 
23
23
  Write a specific prompt — "weathered wooden barrel with rusted iron bands" beats
@@ -28,7 +28,7 @@ assets/models/<slug>.glb
28
28
  ```
29
29
 
30
30
  `<slug>` is derived from the prompt (e.g. `weathered-wooden-barrel.glb`). The file
31
- is **committed by `genex publish`**, so it ships inside your published game.
31
+ is **committed by `npx genex publish`**, so it ships inside your published game.
32
32
 
33
33
  ## Load it into the scene
34
34
 
@@ -55,7 +55,7 @@ To place many copies, `model.clone()` per instance. For animated GLBs, drive
55
55
  (`/assets/...`) — GitHub Pages serves the game at a subpath.
56
56
  - Set `base: "./"` in `vite.config.ts` before `npm run build` (see the scaffold
57
57
  prompt's publish step).
58
- - Commit the `assets/` folder — `genex publish` pushes it with the game.
58
+ - Commit the `assets/` folder — `npx genex publish` pushes it with the game.
59
59
 
60
60
  ## Options
61
61
 
@@ -65,6 +65,6 @@ To place many copies, `model.clone()` per instance. For animated GLBs, drive
65
65
 
66
66
  ## Troubleshooting
67
67
 
68
- - **"Not authorized"** — run `genex init` first (it writes your `GENEX_TOKEN`).
68
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
69
69
  - **The mesh looks low-detail / wrong** — make the prompt more specific
70
70
  (materials, style, parts) and regenerate; each run is a fresh asset.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: genex-ai-sfx
3
- description: Generate a real sound effect (mp3) from a text prompt with `genex sfx`, then play it in Three.js (positional or global audio). Use when the user wants a specific sound — a gunshot, footstep, pickup chime, explosion, engine hum, UI click, whoosh — triggered on a game event.
3
+ description: Generate a real sound effect (mp3) from a text prompt with `npx genex sfx`, then play it in Three.js (positional or global audio). Use when the user wants a specific sound — a gunshot, footstep, pickup chime, explosion, engine hum, UI click, whoosh — triggered on a game event.
4
4
  ---
5
5
 
6
6
  # Genex AI · SFX
@@ -10,8 +10,8 @@ Turn a prompt into a real **mp3** sound effect and wire it to a game event.
10
10
  ## Run
11
11
 
12
12
  ```bash
13
- genex sfx "<prompt>"
14
- genex sfx "punchy laser zap, short and dry" --duration 2
13
+ npx genex sfx "<prompt>"
14
+ npx genex sfx "punchy laser zap, short and dry" --duration 2
15
15
  ```
16
16
 
17
17
  `--duration <sec>` (0.5–22) sets a target length; omit it to let the model pick.
@@ -21,7 +21,7 @@ Blocks until ready, then saves:
21
21
  assets/sfx/<slug>.mp3
22
22
  ```
23
23
 
24
- Committed by `genex publish`, so it ships with your game.
24
+ Committed by `npx genex publish`, so it ships with your game.
25
25
 
26
26
  ## Play it in Three.js
27
27
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: genex-ai-skybox
3
- description: Generate a real 360° skybox (equirectangular panorama) from a text prompt with `genex skybox`, then load it as the scene background + environment lighting in Three.js. Use when the user wants a specific photoreal/painted sky or backdrop ("sunset over the ocean", "alien purple nebula", "foggy pine forest") as an image, rather than a procedural/shader sky.
3
+ description: Generate a real 360° skybox (equirectangular panorama) from a text prompt with `npx genex skybox`, then load it as the scene background + environment lighting in Three.js. Use when the user wants a specific photoreal/painted sky or backdrop ("sunset over the ocean", "alien purple nebula", "foggy pine forest") as an image, rather than a procedural/shader sky.
4
4
  ---
5
5
 
6
6
  # Genex AI · Skybox
@@ -10,7 +10,7 @@ also lights it (image-based lighting).
10
10
 
11
11
  ## When to use this vs. a procedural sky
12
12
 
13
- - **Use `genex skybox`** for a specific, recognizable sky/backdrop you can
13
+ - **Use `npx genex skybox`** for a specific, recognizable sky/backdrop you can
14
14
  describe — "golden hour over misty mountains", "stormy alien sky", "city at
15
15
  night". You get a real image.
16
16
  - **Use `$genex-threejs-atmosphere-aerial-perspective`** (or
@@ -20,7 +20,7 @@ also lights it (image-based lighting).
20
20
  ## Run
21
21
 
22
22
  ```bash
23
- genex skybox "<prompt>"
23
+ npx genex skybox "<prompt>"
24
24
  ```
25
25
 
26
26
  Blocks until ready, then saves:
@@ -29,7 +29,7 @@ Blocks until ready, then saves:
29
29
  assets/skybox/<slug>.jpg
30
30
  ```
31
31
 
32
- The JPG is **committed by `genex publish`**, so it ships with your game.
32
+ The JPG is **committed by `npx genex publish`**, so it ships with your game.
33
33
 
34
34
  ## Load it as background + environment
35
35
 
@@ -63,7 +63,7 @@ texture.dispose; // (dispose the PMREM source later if you stop using it)
63
63
 
64
64
  - Use the **relative** path `./assets/skybox/...` (GitHub Pages serves at a subpath).
65
65
  - `base: "./"` in `vite.config.ts` before `npm run build`.
66
- - Commit `assets/` — `genex publish` pushes it with the game.
66
+ - Commit `assets/` — `npx genex publish` pushes it with the game.
67
67
 
68
68
  ## Troubleshooting
69
69
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: genex-ai-texture
3
- description: Generate a real photoreal surface texture (PBR base-color image) from a text prompt with `genex texture`, then apply it as a tiling material on meshes or terrain in Three.js. Use `--terrain` for seamless ground. Use when the user wants a specific photoreal material on a surface ("rusty metal floor", "mossy cobblestone path", "grassy terrain") rather than a procedural/shader material.
3
+ description: Generate a real photoreal surface texture (PBR base-color image) from a text prompt with `npx genex texture`, then apply it as a tiling material on meshes or terrain in Three.js. Use `--terrain` for seamless ground. Use when the user wants a specific photoreal material on a surface ("rusty metal floor", "mossy cobblestone path", "grassy terrain") rather than a procedural/shader material.
4
4
  ---
5
5
 
6
6
  # Genex AI · Texture
@@ -10,7 +10,7 @@ material on a primitive, a mesh, or terrain.
10
10
 
11
11
  ## When to use this vs. procedural materials
12
12
 
13
- - **Use `genex texture`** for a specific photoreal surface you can describe —
13
+ - **Use `npx genex texture`** for a specific photoreal surface you can describe —
14
14
  "weathered Roman cobblestone", "cracked desert clay", "oak planks". You get a
15
15
  real raster image.
16
16
  - **Use `$genex-threejs-procedural-materials`** for stylized/abstract or
@@ -20,8 +20,8 @@ material on a primitive, a mesh, or terrain.
20
20
  ## Run
21
21
 
22
22
  ```bash
23
- genex texture "<prompt>"
24
- genex texture "lush green grass" --terrain # seamless tiling for ground/terrain
23
+ npx genex texture "<prompt>"
24
+ npx genex texture "lush green grass" --terrain # seamless tiling for ground/terrain
25
25
  ```
26
26
 
27
27
  Blocks until ready, then saves:
@@ -30,7 +30,7 @@ Blocks until ready, then saves:
30
30
  assets/textures/<slug>/basecolor.<ext>
31
31
  ```
32
32
 
33
- Committed by `genex publish`, so it ships with your game.
33
+ Committed by `npx genex publish`, so it ships with your game.
34
34
 
35
35
  > **Scope:** v1 generates the **base-color (albedo)** map only. Normal / roughness
36
36
  > / AO are a planned follow-up — for now set sensible `roughness`/`metalness`
@@ -27,12 +27,15 @@ Beyond procedural code, Genex can generate **real, AI-made assets** from a promp
27
27
  and drop them into `./assets/` (committed when you publish):
28
28
 
29
29
  ```bash
30
- genex model "weathered wooden barrel" # a 3D mesh (GLB)
31
- genex skybox "golden hour over mountains" # a 360° sky + lighting
32
- genex sfx "punchy laser zap" --duration 2 # a sound effect (mp3)
33
- genex texture "mossy cobblestone" --terrain # a tiling surface texture
30
+ npx genex model "weathered wooden barrel" # a 3D mesh (GLB)
31
+ npx genex skybox "golden hour over mountains" # a 360° sky + lighting
32
+ npx genex sfx "punchy laser zap" --duration 2 # a sound effect (mp3)
33
+ npx genex texture "mossy cobblestone" --terrain # a tiling surface texture
34
34
  ```
35
35
 
36
+ (Run them inside your project — the `@genex-ai/cli-demo` dev dependency makes
37
+ `npx genex` resolve to the right CLI.)
38
+
36
39
  Each has a focused skill with the exact loader code — `$genex-ai-model`,
37
40
  `$genex-ai-skybox`, `$genex-ai-sfx`, `$genex-ai-texture`.
38
41
 
@@ -43,7 +46,7 @@ Your existing files were left untouched. `genex init` only adds what is missing.
43
46
  Safe to run any time; it never overwrites your files:
44
47
 
45
48
  ```bash
46
- npx genex init
49
+ npx @genex-ai/cli-demo@latest init
47
50
  ```
48
51
 
49
52
  Use `--force` only if you intentionally want to overwrite installed templates
@@ -51,6 +54,6 @@ with the latest versions.
51
54
 
52
55
  ## Authorization
53
56
 
54
- `genex init` opens the auth site, then writes a `GENEX_TOKEN` into your
55
- project's `.env`. If the browser doesn't open, copy the printed URL into a
56
- browser manually to finish authorizing.
57
+ `genex init` opens the auth site, then saves your token to `~/.genex/env`
58
+ (reused across projects). If the browser doesn't open, copy the printed URL into
59
+ a browser manually to finish authorizing.
@@ -37,23 +37,25 @@ map, execution order, and acceptance gate.
37
37
  | render-target ownership, pass ordering, depth/normal/history signals | `$genex-threejs-image-pipeline` |
38
38
  | fixed-view captures, seed sweeps, browser and GPU evidence | `$genex-threejs-visual-validation` |
39
39
 
40
- ## Real (AI-generated) assets — `genex` commands
40
+ ## Real (AI-generated) assets — `npx genex` commands
41
41
 
42
42
  When the user wants a **specific, recognizable asset** (a named object, a described
43
43
  sky, a particular sound or surface) rather than something authored in code, generate
44
- it with a `genex` command. Each drops a real file into `./assets/` (committed by
45
- `genex publish`), and its skill has the exact Three.js loader code.
44
+ it with an `npx genex` command (run inside the project, where the `@genex-ai/cli-demo`
45
+ dev dependency makes `genex` resolve to the right CLI). Each drops a real file into
46
+ `./assets/` (committed by `npx genex publish`), and its skill has the exact Three.js
47
+ loader code.
46
48
 
47
49
  | Work needed | Generate with | Skill |
48
50
  | --- | --- | --- |
49
- | a specific prop / item / character / vehicle as a real mesh | `genex model "<prompt>"` | `$genex-ai-model` |
50
- | a described 360° sky / backdrop + image-based lighting | `genex skybox "<prompt>"` | `$genex-ai-skybox` |
51
- | a specific sound effect tied to an event | `genex sfx "<prompt>"` | `$genex-ai-sfx` |
52
- | a photoreal surface/material on a mesh or terrain | `genex texture "<prompt>" [--terrain]` | `$genex-ai-texture` |
51
+ | a specific prop / item / character / vehicle as a real mesh | `npx genex model "<prompt>"` | `$genex-ai-model` |
52
+ | a described 360° sky / backdrop + image-based lighting | `npx genex skybox "<prompt>"` | `$genex-ai-skybox` |
53
+ | a specific sound effect tied to an event | `npx genex sfx "<prompt>"` | `$genex-ai-sfx` |
54
+ | a photoreal surface/material on a mesh or terrain | `npx genex texture "<prompt>" [--terrain]` | `$genex-ai-texture` |
53
55
 
54
56
  Prefer the **procedural** skills above for abstract/parametric/animated systems
55
57
  (geometry, materials, sky, water, VFX) — no files, infinite variation. Prefer the
56
- **`genex` generators** for concrete, describable, photoreal assets. They complement
58
+ **`npx genex` generators** for concrete, describable, photoreal assets. They complement
57
59
  each other.
58
60
 
59
61
  ## Routing rules