@genex-ai/cli-demo 0.62.0-dev.144 → 0.63.0-dev.149
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/index.js +8 -4
- package/package.json +1 -1
- package/templates/skills/genex-explore/SKILL.md +23 -3
- package/templates/skills/genex-threejs-character-controller/SKILL.md +24 -10
- package/templates/skills/genex-threejs-character-controller/references/animations.md +15 -5
- package/templates/skills/genex-threejs-embed-auth/SKILL.md +4 -0
- package/templates/skills/genex-threejs-game-content/SKILL.md +5 -0
- package/templates/skills/genex-threejs-multiplayer/SKILL.md +6 -3
- package/templates/skills/genex-threejs-multiplayer/references/host-physics.md +6 -2
- package/templates/skills/genex-threejs-skill-router/references/routing-map.md +8 -1
package/dist/index.js
CHANGED
|
@@ -12357,15 +12357,19 @@ var CONTROLLER_FILE_SETS = {
|
|
|
12357
12357
|
...INPUT_AND_CAMERA,
|
|
12358
12358
|
NOTICE
|
|
12359
12359
|
],
|
|
12360
|
-
// The
|
|
12360
|
+
// The FALLBACK VRM is written to public/assets/avatar.vrm at install time by
|
|
12361
12361
|
// installOwnerAvatar (owner's avatar, or the bundled default) — so it is NOT
|
|
12362
|
-
// a static manifest asset
|
|
12363
|
-
//
|
|
12362
|
+
// a static manifest asset; at runtime the game loads the playing user's own
|
|
12363
|
+
// avatar (user.avatarUrl from the embed identity, AG-804) and this file
|
|
12364
|
+
// covers local dev + load failures. animation-library.glb (the 12-clip core)
|
|
12365
|
+
// still is a manifest asset; extra clips arrive via `genex controller anims`
|
|
12366
|
+
// into public/assets/anims/.
|
|
12364
12367
|
assets: ["assets/animation-library.glb"],
|
|
12365
12368
|
skill: "genex-threejs-character-controller",
|
|
12366
12369
|
sketch: [
|
|
12367
12370
|
`const physics = await PhysicsWorld.create();`,
|
|
12368
|
-
`const {
|
|
12371
|
+
`const { user } = await waitForPlayer(); // @genex-ai/embed-sdk \u2014 the player's own avatar`,
|
|
12372
|
+
`const { scene, vrm } = await loadVrm(user.avatarUrl ?? "./assets/avatar.vrm").catch(() => loadVrm("./assets/avatar.vrm"));`,
|
|
12369
12373
|
`const clips = await loadCharacterClips(vrm); // core library + every genex-controller-anims pack`,
|
|
12370
12374
|
`const character = new CharacterController(physics.world, camera, { ...characterPresets["default"].options, ...capsuleFromModel(scene), position: { x: 0, y: 2, z: 0 } });`,
|
|
12371
12375
|
`character.root.add(scene); const anims = new CharacterAnimations(scene, clips);`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genex-ai/cli-demo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.63.0-dev.149",
|
|
4
4
|
"description": "Set up your project's agent workspace (.claude/.codex/.cursor in the game folder), authorize, create a game project, generate AI assets, and publish (genex CLI).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: genex-explore
|
|
3
|
-
description: Search the curated Genex community gallery with `npx genex explore` before hand-writing hard
|
|
3
|
+
description: Search the curated Genex community gallery with `npx genex explore` — once at the planning stage (the plan sweep, browse the catalog against the game plan and state reuse decisions) and again before hand-writing any hard system. Use when planning a new game, or when it needs terrain, grass, water, vehicles, buildings, dungeons, flocking, or advanced shaders — proven open-source Three.js implementations to clone or borrow from, credits included.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Genex Explore — proven building blocks from the community gallery
|
|
@@ -11,9 +11,29 @@ advanced shader effects. The curated community gallery holds **faithful ports of
|
|
|
11
11
|
proven open-source Three.js projects** — playable, cloneable, and licensed for
|
|
12
12
|
reuse. Search it before hand-writing one of those systems.
|
|
13
13
|
|
|
14
|
-
##
|
|
14
|
+
## The plan sweep — once per game, right after the plan is written
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
The moment the game contract (and the content contract, when there is one) is
|
|
17
|
+
on the table, run the catalog against it ONCE:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx genex explore
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
No query — the catalog is small and every entry is proven, so one browse
|
|
24
|
+
covers the whole plan at once. Then walk the plan's systems (terrain, grass,
|
|
25
|
+
water, vehicles, combat feel, buildings, dungeons…) and for each one that a
|
|
26
|
+
catalog entry serves, state a reuse decision in the plan, one line each:
|
|
27
|
+
**clone as the base** / **borrow parts** (see below) / **build fresh, because
|
|
28
|
+
X**. Not deciding is the failure — a session that hand-builds a grass field
|
|
29
|
+
while a proven grass system sits in the catalog wasted its minutes on a
|
|
30
|
+
solved problem. If the catalog comes back empty on this stand, say so in one
|
|
31
|
+
line and move on — the sweep costs one command either way.
|
|
32
|
+
|
|
33
|
+
## When to use again — before any hard system
|
|
34
|
+
|
|
35
|
+
Later in the build, before hand-writing a hard visual/physics system the plan
|
|
36
|
+
didn't foresee, run:
|
|
17
37
|
|
|
18
38
|
```bash
|
|
19
39
|
npx genex explore "<what you need>"
|
|
@@ -19,10 +19,12 @@ animation retargeting, capsule auto-fit, foot IK) and the 12-clip core
|
|
|
19
19
|
~1.3 MB) into `public/assets/`. Need more — swords, pistols, magic, climbing,
|
|
20
20
|
swimming, emotes? Install exactly what the game uses with
|
|
21
21
|
`npx genex controller anims <tags|clip names…>` (see Animations below). The
|
|
22
|
-
default command also writes
|
|
22
|
+
default command also writes a fallback avatar to `public/assets/avatar.vrm` —
|
|
23
23
|
**your** avatar when you're signed in,
|
|
24
24
|
otherwise a bundled CC0 default (attribution in `src/controllers/NOTICE.md`).
|
|
25
|
-
|
|
25
|
+
At runtime the character plays as the **visiting player's own** picked avatar
|
|
26
|
+
(`user.avatarUrl` from the embed identity — see the wiring below); the baked
|
|
27
|
+
file is only the fallback for local dev and load failures. The copied files are then owned by the game —
|
|
26
28
|
edit them freely; re-running skips existing files unless `--force`. Do not write
|
|
27
29
|
a character controller from scratch and do not swap in a kinematic-controller
|
|
28
30
|
tutorial: this one is a real dynamic body that pushes crates, rides moving
|
|
@@ -89,12 +91,20 @@ import { FollowCamera } from "./controllers/character/follow-camera.ts";
|
|
|
89
91
|
import { KeyboardInput } from "./controllers/character/keyboard-input.ts";
|
|
90
92
|
import { loadVrm } from "./controllers/character/vrm/vrm-loader.ts";
|
|
91
93
|
import { capsuleFromModel } from "./controllers/character/vrm/capsule-fit.ts";
|
|
94
|
+
import { waitForPlayer } from "@genex-ai/embed-sdk";
|
|
92
95
|
|
|
93
96
|
const physics = await PhysicsWorld.create(); // nothing RAPIER-related may run before this resolves
|
|
94
97
|
|
|
95
|
-
// Load the
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
+
// Load the PLAYING user's avatar — every visitor plays as the avatar THEY
|
|
99
|
+
// picked on their genex profile (guests get a per-session one), not the
|
|
100
|
+
// creator's. `user.avatarUrl` comes from the embed identity
|
|
101
|
+
// ($genex-threejs-embed-auth boots before this); the baked
|
|
102
|
+
// `./assets/avatar.vrm` is the fallback for local dev, old APIs, and load
|
|
103
|
+
// failures. Then load every animation the game has (the bundled core library +
|
|
104
|
+
// any packs installed by `genex controller anims`), retargeted onto the VRM.
|
|
105
|
+
const { user } = await waitForPlayer(); // from "@genex-ai/embed-sdk"
|
|
106
|
+
const { scene: avatar, vrm } = await loadVrm(user.avatarUrl ?? "./assets/avatar.vrm")
|
|
107
|
+
.catch(() => loadVrm("./assets/avatar.vrm")); // network failure → bundled fallback
|
|
98
108
|
const clips = await loadCharacterClips(vrm);
|
|
99
109
|
|
|
100
110
|
const fit = capsuleFromModel(avatar); // collider fits THIS avatar's bounds
|
|
@@ -266,11 +276,15 @@ and the style-matching rules live in `$genex-threejs-touch-controls`.
|
|
|
266
276
|
|
|
267
277
|
**The local player is physics-authoritative; remote players are interpolated
|
|
268
278
|
visuals only.** Exactly one `CharacterController` exists — yours. For every
|
|
269
|
-
remote player:
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
279
|
+
remote player: load **that player's own avatar** —
|
|
280
|
+
`loadVrm(p.avatarUrl || "./assets/avatar.vrm")` (the multiplayer SDK's
|
|
281
|
+
`player.avatarUrl` is their verified profile pick; fall back to the baked file
|
|
282
|
+
when it's empty or fails to load, and `VRMUtils.deepDispose` the model when
|
|
283
|
+
they leave) — move it with the interpolator from `$genex-threejs-multiplayer`,
|
|
284
|
+
and **never** create a rigid body, a `CharacterController`, or any physics for
|
|
285
|
+
it. Simulating remote players' physics locally guarantees divergence — every
|
|
286
|
+
client would compute a different world. Never render every remote with your
|
|
287
|
+
own avatar file: players picked their looks, show them.
|
|
274
288
|
|
|
275
289
|
- Publish your own `currPos` + `currQuat` as a four-number quaternion on the fixed 10–20 Hz tick,
|
|
276
290
|
not per frame. Never reduce multiplayer rotation to scalar yaw.
|
|
@@ -10,8 +10,10 @@ clips only on the exact matching generated rig revision.
|
|
|
10
10
|
|
|
11
11
|
`npx genex controller character` sets the game up to play as a **VRM avatar**:
|
|
12
12
|
|
|
13
|
-
- `public/assets/avatar.vrm` — the
|
|
14
|
-
bundled CC0 default). Always present; always one path.
|
|
13
|
+
- `public/assets/avatar.vrm` — the FALLBACK avatar (yours when signed in, else a
|
|
14
|
+
bundled CC0 default). Always present; always one path. At runtime the game
|
|
15
|
+
loads the visiting player's own picked avatar instead (`user.avatarUrl` from
|
|
16
|
+
the embed identity) — this file covers local dev and load failures.
|
|
15
17
|
- `public/assets/animation-library.glb` (~1.3 MB) — the 12-clip core
|
|
16
18
|
(idle/walk/jog/sprint, the jump trio, crouch idle+move, hit, death, interact)
|
|
17
19
|
on a shared Quaternius rig (provenance in `src/controllers/NOTICE.md`).
|
|
@@ -35,8 +37,13 @@ import { capsuleFromModel } from "./controllers/character/vrm/capsule-fit.ts";
|
|
|
35
37
|
import { CharacterController } from "./controllers/character/character-controller.ts";
|
|
36
38
|
import { CharacterAnimations } from "./controllers/character/character-animations.ts";
|
|
37
39
|
import { characterPresets } from "./controllers/character/presets.ts";
|
|
40
|
+
import { waitForPlayer } from "@genex-ai/embed-sdk";
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
// The playing user's OWN avatar (their profile pick; per-session for guests) —
|
|
43
|
+
// the baked file is only the local-dev / failure fallback.
|
|
44
|
+
const { user } = await waitForPlayer();
|
|
45
|
+
const { scene, vrm } = await loadVrm(user.avatarUrl ?? "./assets/avatar.vrm")
|
|
46
|
+
.catch(() => loadVrm("./assets/avatar.vrm"));
|
|
40
47
|
const clips = await loadCharacterClips(vrm); // core + every installed pack, retargeted
|
|
41
48
|
|
|
42
49
|
// capsuleFromModel derives the collider from the avatar's bounds — no manual
|
|
@@ -365,8 +372,11 @@ resolves correctly (a missing flag reads as not-crouched).
|
|
|
365
372
|
|
|
366
373
|
The mixer crossfades exactly as it does locally, so remote players animate
|
|
367
374
|
correctly without simulating anything. Use the same visual lane as the owner:
|
|
368
|
-
|
|
369
|
-
|
|
375
|
+
for a VRM game load **that remote player's own avatar** —
|
|
376
|
+
`loadVrm(p.avatarUrl || "./assets/avatar.vrm")` (the multiplayer SDK's verified
|
|
377
|
+
per-player field; empty means fall back) + retargeted UAL clips, call
|
|
378
|
+
`vrm.update(delta)` per remote, and `VRMUtils.deepDispose` the model on leave —
|
|
379
|
+
or `loadMeshyCharacter` for a Meshy game. Relay one-shot events (punch,
|
|
370
380
|
hit, validated planar-action start) alongside the flags and call the matching
|
|
371
381
|
`remoteAnims.playOneShot(...)` on receipt. Never run `MotionActionDriver` for a
|
|
372
382
|
remote: its smoothed owner-authored transform is the sole movement authority.
|
|
@@ -78,6 +78,10 @@ import { waitForPlayer, waitForAuth, getColyseusAuth, getEmbedToken } from "@gen
|
|
|
78
78
|
// everything wants.
|
|
79
79
|
const { user, guest } = await waitForPlayer();
|
|
80
80
|
// user.id / user.name — real account identity, or guest:<id> / "Guest-1234"
|
|
81
|
+
// user.avatarUrl — the player's OWN VRM avatar (profile pick; per-session for
|
|
82
|
+
// guests). Load it for the local player's visual in a VRM-lane game, with the
|
|
83
|
+
// baked ./assets/avatar.vrm as the fallback (absent on old APIs / local test
|
|
84
|
+
// mode). Peers see each other's via the multiplayer SDK's player.avatarUrl.
|
|
81
85
|
|
|
82
86
|
// ACCOUNT gate — resolves ONLY for signed-in players (stays pending for
|
|
83
87
|
// guests; resolves later if they sign in mid-game). Use ONLY for /state
|
|
@@ -53,6 +53,11 @@ Rules that make the contract real:
|
|
|
53
53
|
- **Minute ten is the design test.** If the honest answer is "the same sixty
|
|
54
54
|
seconds, again", the contract needs another beat (a new area unlocks, a
|
|
55
55
|
quest chain escalates, a build comes online) before any polish work.
|
|
56
|
+
- **Close it with the reuse sweep.** Run `npx genex explore` once (no query)
|
|
57
|
+
and map the contract's systems against the curated catalog — proven ports
|
|
58
|
+
of terrain, grass, water, vehicles, combat feel, buildings, dungeons exist
|
|
59
|
+
there to clone or borrow with credits (`$genex-explore` has the steps). One
|
|
60
|
+
reuse line per matched system; an empty catalog is a one-line note.
|
|
56
61
|
|
|
57
62
|
## Data-driven, or you won't finish in one session
|
|
58
63
|
|
|
@@ -46,7 +46,7 @@ npm i @genex-ai/multiplayer@^0.11.0
|
|
|
46
46
|
> landed in 0.10; confirmed object controls, snaps, host-tick teardown, and reconnect rebasing
|
|
47
47
|
> in 0.9. An older resolve does not have those.
|
|
48
48
|
|
|
49
|
-
This skill targets `@genex-ai/multiplayer` **≥ 0.
|
|
49
|
+
This skill targets `@genex-ai/multiplayer` **≥ 0.12.0** (`objects`/`host` since 0.4; verified per-player `avatarUrl` since 0.12;
|
|
50
50
|
`matchmake()` since 0.5; private lobbies since 0.7; auto-reconnect + `inputs`/`onHostTick`
|
|
51
51
|
since 0.8; soft ownership handoff since 0.8.4; confirmed controls, snap epochs, and host-tick
|
|
52
52
|
lifecycle guarantees since 0.9; regional relay selection via `getColyseusUrls()` since 0.10;
|
|
@@ -519,6 +519,7 @@ of five kinds — put each on its channel and the game just works:
|
|
|
519
519
|
| Slow agreed facts (score, round, wave, seed) | `shared` | the **host** (`isHost`) |
|
|
520
520
|
| One-off actions (shot, emote, hit, chat) | `send` + `on` | whoever did it |
|
|
521
521
|
| Discrete per-player values (hp, ammo, flags) | in `me.set`, read via `stateRaw` | you |
|
|
522
|
+
| Which avatar MODEL a player is (VRM look) | already on `players` as `p.avatarUrl` — sync nothing | the **relay** (verified identity) |
|
|
522
523
|
|
|
523
524
|
Getting the channel right is the whole game. A ball on `shared` stutters (not smoothed) and
|
|
524
525
|
fights (many writers). A ball on `objects` glides and has one owner. That's the difference.
|
|
@@ -531,9 +532,11 @@ fights (many writers). A ball on `objects` glides and has one owner. That's the
|
|
|
531
532
|
- `room.me.snap(state)` — respawn/teleport/mode edge. Publishes a discontinuity epoch so remotes
|
|
532
533
|
hard-reseed instead of interpolating from the old pose. Never use for ordinary movement.
|
|
533
534
|
- `room.players` — fresh `Map` each read, **includes you** (skip `id === room.id`). Each value is
|
|
534
|
-
`{ id, name, connected, state, stateRaw }`: `state` is auto-smoothed (remotes) / live (you);
|
|
535
|
+
`{ id, name, avatarUrl, connected, state, stateRaw }`: `state` is auto-smoothed (remotes) / live (you);
|
|
535
536
|
`stateRaw` is the raw latest (hit-tests, discrete values). A reconnect-grace seat remains in this
|
|
536
|
-
map with `connected: false`.
|
|
537
|
+
map with `connected: false`. `avatarUrl` is that player's verified VRM pick (server-set, `''`
|
|
538
|
+
when unknown) — in a VRM-lane game render each remote with
|
|
539
|
+
`loadVrm(p.avatarUrl || "./assets/avatar.vrm")`; never publish avatar URLs through `me.set`.
|
|
537
540
|
- `room.activePlayers` — the connected-only subset of `room.players`; use its size for live quorum.
|
|
538
541
|
- `room.objects` — shared objects nobody owns until claimed (a ball, an NPC):
|
|
539
542
|
- `claim(id)` — **legacy** optimistic request. It flips local ownership immediately and is corrected
|
|
@@ -274,8 +274,12 @@ room.me.set({
|
|
|
274
274
|
});
|
|
275
275
|
|
|
276
276
|
// Remote players: a VISUAL-ONLY avatar — NO Rapier body, NO controller instance for remotes.
|
|
277
|
-
//
|
|
278
|
-
//
|
|
277
|
+
// Build each remote's visual from THEIR OWN model: in a VRM-lane game that is
|
|
278
|
+
// loadVrm(pl.avatarUrl || "./assets/avatar.vrm") — the verified per-player pick the relay
|
|
279
|
+
// replicates ('' = unknown → fall back; deepDispose the model on 'leave'). Never reuse your
|
|
280
|
+
// own avatar file for every remote. Position/rotation from smoothed state; animation from the
|
|
281
|
+
// synced flags via the avatar's own update(flags, dt). The character-controller skill's
|
|
282
|
+
// animations reference owns the flag set.
|
|
279
283
|
const pl = room.players.get(id)!;
|
|
280
284
|
remoteAvatar.group.position.set(pl.state.x, pl.state.y, pl.state.z);
|
|
281
285
|
remoteAvatar.group.quaternion.fromArray(pl.state.q);
|
|
@@ -31,7 +31,14 @@ Three.js release or branch, and do not blindly copy demo architecture.
|
|
|
31
31
|
fogged plane. Scope belongs to the user: shipping fewer or smaller than
|
|
32
32
|
the ask requires their explicit OK through a structured question — a
|
|
33
33
|
"vertical slice first" is a build order, never a license to shrink the
|
|
34
|
-
destination silently.
|
|
34
|
+
destination silently. **Close the contract with the reuse sweep:** run
|
|
35
|
+
`npx genex explore` once (no query) and map the plan's systems against the
|
|
36
|
+
curated catalog — proven ports of terrain, grass, water, vehicles, combat
|
|
37
|
+
feel, buildings, dungeons exist there to clone or borrow (credits carried,
|
|
38
|
+
`$genex-explore` has the integration steps). One reuse line per matched
|
|
39
|
+
system in the plan (clone as base / borrow parts / build fresh because X);
|
|
40
|
+
hand-building a system the catalog already proves is the waste this sweep
|
|
41
|
+
exists to prevent. An empty catalog is a one-line note, not a blocker.
|
|
35
42
|
2. Wire player identity before any boot code: `$genex-threejs-embed-auth` is
|
|
36
43
|
mandatory for every game (`initEmbed(...)` + the `waitForPlayer()` gate) —
|
|
37
44
|
saves, leaderboards, and multiplayer auth all come from it.
|