@genex-ai/cli-demo 0.81.0-dev.214 → 0.84.0-dev.215
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 +780 -80
- package/package.json +1 -1
- package/templates/controllers/character/first-person.ts +54 -0
- package/templates/controllers/character/follow-camera.ts +35 -1
- package/templates/skills/genex-ai-character/SKILL.md +25 -5
- package/templates/skills/genex-ai-hud/SKILL.md +130 -36
- package/templates/skills/genex-ai-hud/references/masked-fill.md +19 -13
- package/templates/skills/genex-ai-hud/references/stage2-prompt-template.md +2 -2
- package/templates/skills/genex-ai-image/SKILL.md +40 -2
- package/templates/skills/genex-ai-menu/SKILL.md +35 -17
- package/templates/skills/genex-ai-model/SKILL.md +8 -0
- package/templates/skills/genex-ai-music/SKILL.md +142 -0
- package/templates/skills/genex-ai-skybox/SKILL.md +21 -5
- package/templates/skills/genex-ai-video/SKILL.md +13 -7
- package/templates/skills/genex-ai-voice/SKILL.md +151 -0
- package/templates/skills/genex-game-director/SKILL.md +128 -44
- package/templates/skills/genex-game-director/references/design-contract.md +7 -2
- package/templates/skills/genex-game-director/references/routing-map.md +4 -1
- package/templates/skills/genex-threejs-camera-direction/SKILL.md +4 -1
- package/templates/skills/genex-threejs-character-controller/SKILL.md +6 -1
- package/templates/skills/genex-threejs-character-controller/references/wiring.md +13 -2
- package/templates/skills/genex-threejs-creatures/SKILL.md +193 -0
- package/templates/skills/genex-threejs-game-ui/SKILL.md +5 -1
- package/templates/skills/genex-threejs-multiplayer/SKILL.md +6 -1
|
@@ -45,10 +45,31 @@ missing.
|
|
|
45
45
|
|
|
46
46
|
## 3. The design contract — DESIGN.md
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
**First, the design interview — before DESIGN.md is written.** Ask the
|
|
49
|
+
player 2–4 build-forking questions, batched in ONE round — use your
|
|
50
|
+
structured question / ask tool if your harness has one, with answer options
|
|
51
|
+
for the user. Ask only what genuinely forks the build:
|
|
52
|
+
|
|
53
|
+
- the one-line pitch, confirmed or corrected ("a co-op scythe hunt in a
|
|
54
|
+
ruined cathedral — right?");
|
|
55
|
+
- the solo / co-op / versus shape (it decides netcode and scope);
|
|
56
|
+
- scope ambition, when the request could honestly be read small or large
|
|
57
|
+
(compact arena vs. open world);
|
|
58
|
+
- any real ambiguity in the request itself.
|
|
59
|
+
|
|
60
|
+
Never ask about SDKs, engines, renderers, file layout, or anything
|
|
61
|
+
technical — those are your decisions. If the player is silent or has no way
|
|
62
|
+
to answer, proceed on your own stated assumptions and write each one into
|
|
63
|
+
DESIGN.md → Decisions as "assumed — player didn't answer"; the build never
|
|
64
|
+
stalls on the interview.
|
|
65
|
+
|
|
66
|
+
Then, before rendering code, write `DESIGN.md` at the project root from
|
|
67
|
+
[references/design-contract.md](references/design-contract.md). The moment
|
|
68
|
+
the file lands, post a 5–6 line summary of the contract in chat — pitch,
|
|
69
|
+
core loop, content counts, screens, multiplayer shape, what you build
|
|
70
|
+
first — and keep building immediately: the summary is information, not a
|
|
71
|
+
gate (the plan-message duties from `$genex-threejs-game-ui` fold into this
|
|
72
|
+
file plus that summary). The file is the single source of truth:
|
|
52
73
|
sub-agents build against it, and after any long break it is how work resumes.
|
|
53
74
|
Keep it current — decisions land in its log the moment they're made.
|
|
54
75
|
|
|
@@ -65,13 +86,24 @@ steps live in each owning skill — load it when its lane fires:
|
|
|
65
86
|
outdoors → `$genex-ai-skybox`
|
|
66
87
|
- `npx genex sfx "<prompt>"` — the core verb and every impact →
|
|
67
88
|
`$genex-ai-sfx`
|
|
89
|
+
- `npx genex music "<prompt>"` — ONE looping instrumental gameplay track
|
|
90
|
+
(~90 s default; the menu reuses it quieter; settings gets Music + SFX
|
|
91
|
+
sliders) → `$genex-ai-music`
|
|
92
|
+
- `npx genex voice "<line>"` — short spoken lines: NPC barks, narrator
|
|
93
|
+
beats, tutorial VO (curated cast via `--voice`; keep lines short,
|
|
94
|
+
subtitled, skippable) → `$genex-ai-voice`
|
|
68
95
|
- `npx genex image "<prompt>"` — posters, signs, sprites, decals, HUD art
|
|
69
|
-
(`--transparent` for anything laid on a surface
|
|
96
|
+
(`--transparent` for anything laid on a surface; `--glass` for real-
|
|
97
|
+
translucency glass panels) → `$genex-ai-image`,
|
|
70
98
|
`$genex-ai-hud`
|
|
71
|
-
- `npx genex video "<prompt>"` — in-world screens
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
99
|
+
- `npx genex video "<prompt>"` — in-world screens and billboards (`--loop`
|
|
100
|
+
for a seamless in-world loop) → `$genex-ai-video`; the animated menu
|
|
101
|
+
backdrop is its own lane — `$genex-ai-menu`'s `--frame` flow, never `--loop`
|
|
102
|
+
- `npx genex character "<prompt>"` — the game's themed character (approval
|
|
103
|
+
flow — §7) → `$genex-ai-character`
|
|
104
|
+
- `npx genex creature "<desc>"` — a rigged enemy/creature in one shot
|
|
105
|
+
(biped-shaped bodies only — the creatures skill routes the rest to
|
|
106
|
+
static + procedural) → `$genex-threejs-creatures`
|
|
75
107
|
- `npx genex controller character|car|drone|touch|quality` and
|
|
76
108
|
`npx genex animations search "<intent>"` — ready-made, tuned movement and
|
|
77
109
|
motion; never write movement physics from scratch →
|
|
@@ -89,6 +121,12 @@ variation); prefer these generators for concrete, describable, photoreal
|
|
|
89
121
|
assets — they complement each other. Assets you didn't plan don't exist: if
|
|
90
122
|
the menu has a lane this game needs, put a row in the Assets table.
|
|
91
123
|
|
|
124
|
+
**No eternal `proposed`.** At every preview and publish, walk the Assets
|
|
125
|
+
table and resolve every `proposed` row — promote it to `planned` (and
|
|
126
|
+
enqueue it when its turn comes) or cancel it, saying which in one visible
|
|
127
|
+
line ("cancelled: UI hover sfx — out of scope for v1"). A row parked at
|
|
128
|
+
`proposed` across a whole session is a decision you didn't make.
|
|
129
|
+
|
|
92
130
|
**Generate a core asset set by default — don't wait to be asked.** For any
|
|
93
131
|
game that needs concrete objects or surfaces, decide a small core set from the
|
|
94
132
|
game IDEA — and from the Content lines when there are any (locations and the
|
|
@@ -102,7 +140,9 @@ each in as it lands, with a procedural placeholder until then:
|
|
|
102
140
|
- the **hero model** the player controls or chases (`npx genex model`),
|
|
103
141
|
- one key **texture** for the ground/main surface (`--terrain` for ground),
|
|
104
142
|
- a **skybox** when the scene is outdoors,
|
|
105
|
-
- a **sfx** or two for the core action and its feedback
|
|
143
|
+
- a **sfx** or two for the core action and its feedback,
|
|
144
|
+
- one looping **music** track for the gameplay bed (`npx genex music`,
|
|
145
|
+
~90 s; the menu reuses it at lower volume).
|
|
106
146
|
|
|
107
147
|
Skip generation only for purely abstract/geometric games. For three.js
|
|
108
148
|
questions no skill covers, use the official three.js documentation
|
|
@@ -207,36 +247,59 @@ agent: you stay the director.
|
|
|
207
247
|
enqueues. (Whoever wires the HUD after a worker finishes follows
|
|
208
248
|
`$genex-ai-hud`'s handoff rule: read the produced mask/bbox JSON from disk,
|
|
209
249
|
never wire from a prose summary.)
|
|
210
|
-
- Do NOT spawn workers to write extra test suites
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
250
|
+
- Do NOT spawn workers to write extra test suites, audits, or verification
|
|
251
|
+
passes — the per-milestone smoke pass is yours, the director's, and it is
|
|
252
|
+
ONE pass (§8; the scaffold prompt owns the ceilings).
|
|
253
|
+
- If you build a module the table planned for a sub-agent inline, say why in
|
|
254
|
+
one line in chat ("built enemies inline — the arena worker was still
|
|
255
|
+
holding the only free slot"). The table is accountability, not ceremony —
|
|
256
|
+
inline can be the right call.
|
|
257
|
+
|
|
258
|
+
## 7. The game's character (Meshy) — themed by default
|
|
259
|
+
|
|
260
|
+
**A themed character is the DEFAULT for any game whose protagonist is
|
|
261
|
+
VISIBLE** — third-person, or first-person with co-op/remote players who see
|
|
262
|
+
each other. Put its row in the Assets table up front and install the
|
|
263
|
+
VRM + UAL controller (`npx genex controller character`) as the instant
|
|
264
|
+
placeholder. The VRM stays the FINAL character only for games with no
|
|
265
|
+
themed protagonist to sell (a generic exploration toy, a faceless solo
|
|
266
|
+
first-person game — say which in one line). A capsule or hand-built
|
|
267
|
+
primitive standing in for a person is never a shipped state, for the local
|
|
268
|
+
player or a remote one.
|
|
269
|
+
|
|
270
|
+
**The default lane has ONE user stop, and it rides the concept review.**
|
|
271
|
+
When the user names a visual reference, inspect references before writing
|
|
272
|
+
the concept prompt. Generate exactly three concepts, all neutral A-pose;
|
|
273
|
+
never use a dynamic concept pose or silently fall back to T-pose. Warn that
|
|
274
|
+
held, slung, or overlapping props and straps can fuse into the body or
|
|
275
|
+
obscure limbs, and recommend separate gameplay props. Show the actual
|
|
276
|
+
images in the SAME beat as the game-concept keep-or-change question — one
|
|
277
|
+
review, two picks. The player's pick carries the lane end to end:
|
|
278
|
+
`npx genex character preview <concept-id> --candidate <1|2|3> --user-approved`,
|
|
279
|
+
then finalize below. **If the player hasn't picked by the time the
|
|
280
|
+
character blocks progress (or ~10 minutes), pick the strongest candidate
|
|
281
|
+
yourself, say which and why in chat, and proceed** — this auto-proceed is
|
|
282
|
+
owner-ratified platform policy (2026-07-23), not an agent liberty; record
|
|
283
|
+
it in DESIGN.md → Decisions ("auto-picked candidate 2 — cleanest
|
|
284
|
+
silhouette; player away").
|
|
230
285
|
|
|
231
286
|
Meshy Image-to-3D first produces an unremeshed high-detail model. Show its
|
|
232
|
-
front, back, left, and right views and report its measured face count.
|
|
233
|
-
that model in R2.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
287
|
+
front, back, left, and right views and report its measured face count.
|
|
288
|
+
Preserve that model in R2. The 10,000-face triangle remesh—not the
|
|
289
|
+
high-detail source—is rigged and animated. In the default lane the remesh
|
|
290
|
+
proceeds on the same authorization as the pick (say it plainly: "building
|
|
291
|
+
the 10,000-face rigging copy now"):
|
|
237
292
|
`npx genex character finalize <preview-id> --user-approved --approve-remesh 10000 [--animation <action-id>…]`.
|
|
238
|
-
|
|
239
|
-
|
|
293
|
+
Keep every pre-animation generation in the selected neutral A-pose.
|
|
294
|
+
|
|
295
|
+
**When the user themselves asked for a custom character** (an explicit
|
|
296
|
+
custom-character request, not the game default), the ceremony is two
|
|
297
|
+
separate stops and the approvals are the product: do not start Image-to-3D
|
|
298
|
+
until they explicitly select a candidate, and before rigging ask them to
|
|
299
|
+
approve the separate 10,000-face triangle remesh — wait for that explicit
|
|
300
|
+
approval before finalize. (`npx genex character "<prompt>" --direct-text`
|
|
301
|
+
is the explicit legacy one-shot path, not a substitute for these
|
|
302
|
+
approvals.)
|
|
240
303
|
|
|
241
304
|
Load `$genex-ai-character`, search Meshy actions first with
|
|
242
305
|
`npx genex animations search "<intent>" --json`, and use returned action IDs;
|
|
@@ -248,13 +311,34 @@ Before handoff, visibly check idle, walk, run, crouch-idle, crouch-move, and
|
|
|
248
311
|
jump — shoulders, elbows, wrists, hands, both leg cycles, and feet — and press
|
|
249
312
|
every control the HUD advertises.
|
|
250
313
|
|
|
251
|
-
## 8.
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
314
|
+
## 8. Verification — the smoke pass's captures grow with the build
|
|
315
|
+
|
|
316
|
+
The per-milestone smoke pass and its ceilings belong to the scaffold prompt
|
|
317
|
+
(ONE pass per milestone, never test suites, never re-verify after cosmetic
|
|
318
|
+
tweaks) — this section only defines WHAT that one pass captures once the
|
|
319
|
+
relevant piece exists:
|
|
320
|
+
|
|
321
|
+
- **Always:** the gameplay screenshot + the main controls responding the
|
|
322
|
+
right way (the scaffold prompt's baseline).
|
|
323
|
+
- **Once the generated HUD is wired:** take the gameplay screenshot AFTER
|
|
324
|
+
taking damage once, with an enemy in frame facing the player. A full-HP
|
|
325
|
+
shot cannot show a broken meter (a painted trough hides behind a 100%
|
|
326
|
+
fill), and an enemy you never faced head-on may be looking sideways at
|
|
327
|
+
everyone.
|
|
328
|
+
- **Once the menu video is wired:** watch one full loop cycle as rendered
|
|
329
|
+
(`$genex-ai-menu`'s seam check). A metadata probe can't see a seam, a
|
|
330
|
+
hidden video, or a leftover panel covering it.
|
|
331
|
+
|
|
332
|
+
Judge each capture against DESIGN.md once, fix only what is visibly broken,
|
|
333
|
+
and move on — the captures are eyes, not a test suite.
|
|
334
|
+
|
|
335
|
+
**Fresh eyes before publish.** The pre-publish check is just the last
|
|
336
|
+
milestone's pass, plus this: take the game's current screenshots (desktop
|
|
337
|
+
and phone sizes) and hand them, with DESIGN.md only, to a fresh reviewer —
|
|
338
|
+
a sub-agent if you have one, otherwise re-read them yourself adversarially,
|
|
339
|
+
looking to refute "it's done": untextured surfaces, a bare HUD, missing
|
|
340
|
+
screens, Content lines not in the game, Assets rows never flipped to
|
|
341
|
+
`wired`, `proposed` rows never resolved. Fix or honestly report what it
|
|
258
342
|
finds; never publish over an unacknowledged gap.
|
|
259
343
|
|
|
260
344
|
## 9. Say it straight
|
|
@@ -13,7 +13,10 @@ Rules the director enforces about this file:
|
|
|
13
13
|
sections as decisions land and keep it current (stale is worse than short).
|
|
14
14
|
- **The Modules table is the delegation contract**: one row per independent
|
|
15
15
|
lane, and a row's "Owns files" set never overlaps another row's. One writer
|
|
16
|
-
per file.
|
|
16
|
+
per file. "Sub-agent when available" stays flexible — but if a
|
|
17
|
+
planned-sub-agent module gets built inline, the agent says why in one line.
|
|
18
|
+
Verification is never a module row: the milestone smoke pass belongs to the
|
|
19
|
+
director (the scaffold prompt owns its ceilings).
|
|
17
20
|
- **The Assets table is the budget**: the asset list falls out of Content
|
|
18
21
|
(enemies → models, an arena → a ground texture, outdoors → a skybox).
|
|
19
22
|
Status flow per row: `proposed → planned → generating (id) → landed (URL) →
|
|
@@ -22,6 +25,8 @@ Rules the director enforces about this file:
|
|
|
22
25
|
flips statuses and never enqueues. Re-rolls follow the player's notes only.
|
|
23
26
|
The `Wired?` column exists because "generated but never wired in" is the
|
|
24
27
|
most common way finished art gets lost — a row isn't done at `landed`.
|
|
28
|
+
And no eternal `proposed`: at every preview/publish, every `proposed` row
|
|
29
|
+
gets promoted or cancelled with one visible line — never silently parked.
|
|
25
30
|
- Shrinking any Content line is a question to the player first, never a
|
|
26
31
|
silent cut.
|
|
27
32
|
|
|
@@ -63,6 +68,7 @@ References: <2–3 named games> · Menu archetype: <name>
|
|
|
63
68
|
| Concept + HUD | image | landed → <URL> (candidate <n>) | n/a |
|
|
64
69
|
| <main surface> | texture | generating (<id>) | — |
|
|
65
70
|
| <hero model> | model | planned | — |
|
|
71
|
+
| Background music | music | planned (one ~90s looping track)| — |
|
|
66
72
|
| Menu still+video | image+video | blocked on concept yes → queued | — |
|
|
67
73
|
Status flow: proposed → planned → generating (id) → landed (URL) → wired.
|
|
68
74
|
(Optionally note the prompt gist per row — it makes style-change re-rolls one
|
|
@@ -84,7 +90,6 @@ click (when a Play screen exists).
|
|
|
84
90
|
| Quests & dialogue data | src/content/** | sub-agent when available | counts match Content lines |
|
|
85
91
|
| Enemies/AI | src/enemies/** | sub-agent when available | roster matches Content |
|
|
86
92
|
| HUD chain (style-dependent) | src/ui/** | sub-agent AFTER concept yes | all screens from Screens & UI |
|
|
87
|
-
| Verification | (no source files) | one sub-agent max | smoke check notes per milestone |
|
|
88
93
|
|
|
89
94
|
## Decisions & changes
|
|
90
95
|
- <date> — <one-liner per decision, including anything the player said no or
|
|
@@ -21,7 +21,9 @@ Three.js release or branch, and do not blindly copy demo architecture.
|
|
|
21
21
|
| --- | --- |
|
|
22
22
|
| shot composition, chase/side/orbit rigs, camera handoffs, projection ownership, pointer look, mouse-aimed action (shooter, FPS/first-person, sniper, turret, crosshair/reticle), mouse-look, hand-rolled steering/pan/look input signs (screen-direction contract), floating origins | `$genex-threejs-camera-direction` |
|
|
23
23
|
| on-foot player movement: walk/run/jump/crouch, third-person character, slopes, stairs, moving platforms, personal VRM animation, directional locomotion, transitions, action motion | `$genex-threejs-character-controller` |
|
|
24
|
-
|
|
|
24
|
+
| the game's themed character — the DEFAULT whenever the protagonist is visible (third-person, or first-person with co-op/remote players); one user stop riding the concept review, owner-ratified auto-pick on silence (director §7) — or Meshy animation coverage beyond UAL: reference-informed A-pose concepts, exact action IDs, same-rig adapter | `$genex-ai-character` + `$genex-threejs-character-controller` |
|
|
25
|
+
| remote player bodies in multiplayer — NEVER hand-built primitives: the themed character model in themed games, the player's `p.avatarUrl` VRM otherwise | `$genex-threejs-multiplayer` + `$genex-threejs-character-controller` |
|
|
26
|
+
| the game has enemies, NPCs, or creatures — **load whenever an enemy roster exists**: rigged bipeds via `npx genex creature`, static + procedural motion for other body shapes, plus the mechanical floor every enemy owes (collider, verified facing, hit reaction, death moment) | `$genex-threejs-creatures` |
|
|
25
27
|
| the player drives or flies something: cars, drones, vehicle physics, gearbox, enter/exit between character and vehicle | `$genex-threejs-vehicle-controllers` |
|
|
26
28
|
| playable on phones: touch/mobile input for any game — joystick, virtual buttons, drag zones, per-genre touch recipes, rotate-device overlay — wired by default for every NEW game when a recipe fits (skip with a one-line reason) | `$genex-threejs-touch-controls` |
|
|
27
29
|
| phone-survivable rendering — device tiers, DPR/shadow/post budgets, the runtime quality governor, per-tier asset rungs for generated skyboxes/textures, the Quality picker, dispose-on-swap discipline — **mandatory for every game at boot wiring** | `$genex-threejs-adaptive-quality` |
|
|
@@ -53,6 +55,7 @@ Three.js release or branch, and do not blindly copy demo architecture.
|
|
|
53
55
|
| the 2D interface — HUD, menus, pause/win/lose screens, loaders, lobby, on-screen text and buttons, UI state flow — **mandatory for every game**, and its "Plan the UI first" gate runs right after the concept is locked | `$genex-threejs-game-ui` |
|
|
54
56
|
| a cinematic menu — main menu/title/pause/victory/defeat/lobby/credits with a looping generated video backdrop behind DOM buttons | `$genex-ai-menu` |
|
|
55
57
|
| a cohesive art-directed HUD — generated sprite set (matched frames, masks, icons in one style) wired with masked fills | `$genex-ai-hud` |
|
|
58
|
+
| background music — the looping instrumental track under gameplay and menu (default ONE ~90 s track; Music + SFX sliders in settings) | `$genex-ai-music` |
|
|
56
59
|
| the game works but feels flat, floaty, or unresponsive: input response, acceleration curves, camera shake, hit feedback, hitstop, cooldowns, difficulty ramp, fail/retry loop | `$genex-threejs-game-feel` |
|
|
57
60
|
| realtime multiplayer: movement sync, a shared ball/NPC, host-run scores/enemies, shots/emotes, persistence | `$genex-threejs-multiplayer` |
|
|
58
61
|
| player identity, sign-in, guests, saves/progress, per-player state, a shared persistent world, leaderboards — **mandatory for every game** | `$genex-threejs-embed-auth` |
|
|
@@ -45,7 +45,10 @@ the build plan:
|
|
|
45
45
|
- **MANDATORY** — first-person of any kind (FPS, walking sim, horror) and any
|
|
46
46
|
mouse-aimed action (third-person shooter, turret/range). Lock is on by default;
|
|
47
47
|
leave it on. Shipping this unlocked is a defect, not a style choice — validation
|
|
48
|
-
fails it.
|
|
48
|
+
fails it. For first-person on the bundled controller, use the REAL mode —
|
|
49
|
+
`firstPerson: true` on `FollowCamera` (eye-height target, no zoom, no
|
|
50
|
+
collision pullback) + `setFirstPersonBody()` to hide the local body while
|
|
51
|
+
keeping its shadow — never a pinned tiny follow distance.
|
|
49
52
|
- **HIGHLY RECOMMENDED** — third-person free-camera action/adventure (the default
|
|
50
53
|
`genex controller character` game). On by default; leave it on. Opt out with
|
|
51
54
|
`pointerLockAim: false` only for a stated reason (a cursor-heavy UI at the core
|
|
@@ -316,7 +316,12 @@ they leave) — move it with the interpolator from `$genex-threejs-multiplayer`,
|
|
|
316
316
|
and **never** create a rigid body, a `CharacterController`, or any physics for
|
|
317
317
|
it. Simulating remote players' physics locally guarantees divergence — every
|
|
318
318
|
client would compute a different world. Never render every remote with your
|
|
319
|
-
own avatar file: players picked their looks, show them.
|
|
319
|
+
own avatar file: players picked their looks, show them. And a remote player's
|
|
320
|
+
body is **never hand-built primitives** (no capsule-plus-cone "person"): in a
|
|
321
|
+
themed game remotes wear the SAME themed character model the local player
|
|
322
|
+
uses; otherwise they wear their `p.avatarUrl` VRM. First-person games are not
|
|
323
|
+
exempt — the local player may be invisible to themselves
|
|
324
|
+
(`setFirstPersonBody`), but every remote is a full character on screen.
|
|
320
325
|
|
|
321
326
|
- **Publish `character.netState()`** on the fixed 10–20 Hz tick (never per frame):
|
|
322
327
|
`room.me.set(character.netState())`. It bundles the network-safe position, a four-number
|
|
@@ -118,8 +118,19 @@ Rules that matter:
|
|
|
118
118
|
non-recursive) and must never include the character or vehicle meshes — the
|
|
119
119
|
rays start at the character's head and would hit them every frame. The array
|
|
120
120
|
is public — mutate it after level loads.
|
|
121
|
-
-
|
|
122
|
-
|
|
121
|
+
- **First-person is a real mode, not a zoom trick**: pass
|
|
122
|
+
`firstPerson: true` (or flip the public `followCam.firstPerson` field at
|
|
123
|
+
runtime) — the camera sits AT the follow target and looks out along the
|
|
124
|
+
aim direction, wheel zoom is ignored, and collision pullback is skipped.
|
|
125
|
+
Feed the follow target the character's EYE height (~1.6–1.7 m up the
|
|
126
|
+
capsule, not the head-top orbit anchor), hide the local body with
|
|
127
|
+
`setFirstPersonBody(model, true)` (`first-person.ts` — keeps the shadow,
|
|
128
|
+
clones materials so shared remote-player materials are untouched), and
|
|
129
|
+
parent the viewmodel (held weapon/hands) to the CAMERA so it moves with
|
|
130
|
+
the view. Pointer lock stays mandatory (`$genex-threejs-camera-direction`).
|
|
131
|
+
Do NOT fake first-person by pinning a tiny follow distance — the old
|
|
132
|
+
0.02-min-distance trick leaves collision pullback and zoom live, and both
|
|
133
|
+
fight the player.
|
|
123
134
|
- Feel: `smoothTime` (0.05 snappy → 0.25 cinematic, default 0.1),
|
|
124
135
|
`initialDistance` (default 4), `initialAzimuthAngle` (default `Math.PI` —
|
|
125
136
|
camera starts behind a +Z-facing character).
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: genex-threejs-creatures
|
|
3
|
+
description: Build enemies and creatures that hold up in play — rigged Meshy bipeds via `npx genex creature` or static models with procedural motion, plus the mechanical floor every enemy owes the player regardless of rigging - a physics collider (no walking through bodies), verified facing, hit reactions, and a death moment. Load whenever the game has enemies, NPCs, or creatures.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Genex Three.js · Creatures & Enemies
|
|
7
|
+
|
|
8
|
+
An enemy the player can walk through, that faces sideways, and that dies by
|
|
9
|
+
vanishing is the fastest way for a finished-looking game to feel broken. This
|
|
10
|
+
skill owns the enemy-quality floor: which generation lane each creature takes,
|
|
11
|
+
and the four mechanical rules that apply to ALL of them.
|
|
12
|
+
|
|
13
|
+
## Choose the lane per creature — by body shape
|
|
14
|
+
|
|
15
|
+
**Meshy rigs biped-shaped bodies only.** This is a measured platform limit
|
|
16
|
+
(live-tested 2026-07-23), and it starts at the MODEL stage: a prompt for a
|
|
17
|
+
four-legged stance comes back standing upright, and wings get no bones (they
|
|
18
|
+
skin to the spine/arms and move rigidly — a wing flap is impossible through
|
|
19
|
+
the rig). Route by silhouette:
|
|
20
|
+
|
|
21
|
+
- **Biped-shaped** (werewolf, orc, skeleton, gargoyle, zombie, knight — two
|
|
22
|
+
legs, two arms, upright): the **rigged lane** below. Real skeleton, real
|
|
23
|
+
library animations. This is the DEFAULT for every enemy that fits it.
|
|
24
|
+
- **Everything else** (true quadrupeds, serpents, swarms, fliers mid-flight,
|
|
25
|
+
blobs): the **static + procedural lane** — `npx genex model` for the body,
|
|
26
|
+
motion authored in code. Say it honestly in the Assets table:
|
|
27
|
+
`hound: static + procedural — Meshy rigs bipeds only`. Never pretend a
|
|
28
|
+
procedural creature is rigged.
|
|
29
|
+
|
|
30
|
+
## The rigged lane — `npx genex creature`
|
|
31
|
+
|
|
32
|
+
One shot, no approval ceremony (an enemy is production scenery, not the
|
|
33
|
+
player's identity piece — the themed PLAYER character keeps its review beat,
|
|
34
|
+
`$genex-ai-character`):
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# 1. Find real clip ids first — never invent them:
|
|
38
|
+
npx genex animations search "zombie walk" --json
|
|
39
|
+
npx genex animations search "melee attack" --json
|
|
40
|
+
npx genex animations search "death backward" --json
|
|
41
|
+
|
|
42
|
+
# 2. One command: model → rig → bind those clips (enqueue and keep building):
|
|
43
|
+
npx genex creature "hulking bone seraph, tattered wing membranes, upright stance" \
|
|
44
|
+
--animation <walk-id> --animation <attack-id> --animation <death-id> --no-wait
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Each creature is one Assets-table row (visible spend — the usual budget
|
|
48
|
+
rules). The result is a rigged GLB whose clips play on a standard
|
|
49
|
+
`THREE.AnimationMixer`; Meshy limb rotations play unchanged — never apply
|
|
50
|
+
post-mixer limb corrections. Prompt the body UPRIGHT and unpropped (held
|
|
51
|
+
props fuse into bodies); prompt "facing the viewer" but never trust it —
|
|
52
|
+
facing is verified below.
|
|
53
|
+
|
|
54
|
+
### State → clip wiring (one mixer per creature)
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import * as THREE from "three";
|
|
58
|
+
|
|
59
|
+
interface CreatureRig {
|
|
60
|
+
root: THREE.Object3D;
|
|
61
|
+
mixer: THREE.AnimationMixer;
|
|
62
|
+
actions: Record<"walk" | "attack" | "hit" | "death", THREE.AnimationAction>;
|
|
63
|
+
current?: THREE.AnimationAction;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function play(rig: CreatureRig, name: keyof CreatureRig["actions"], fade = 0.18): void {
|
|
67
|
+
const next = rig.actions[name];
|
|
68
|
+
if (rig.current === next) return;
|
|
69
|
+
next.reset();
|
|
70
|
+
if (name === "attack" || name === "hit" || name === "death") {
|
|
71
|
+
next.setLoop(THREE.LoopOnce, 1);
|
|
72
|
+
next.clampWhenFinished = true; // death holds its last frame
|
|
73
|
+
}
|
|
74
|
+
if (rig.current) next.crossFadeFrom(rig.current, fade, false);
|
|
75
|
+
next.play();
|
|
76
|
+
rig.current = next;
|
|
77
|
+
}
|
|
78
|
+
// drive from the enemy state machine: chase → play(rig, "walk");
|
|
79
|
+
// windup+strike → play(rig, "attack"); damaged → play(rig, "hit");
|
|
80
|
+
// hp <= 0 → play(rig, "death") and only AFTER the clip finishes, run the
|
|
81
|
+
// death VFX moment (embers/dissolve) — animation first, particles second.
|
|
82
|
+
// mixer.update(dt) every frame; one mixer per creature, clips cloned per
|
|
83
|
+
// instance (THREE.AnimationUtils / SkeletonUtils.clone for shared GLBs).
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## The mechanical floor — ALL enemies, rigged or not
|
|
87
|
+
|
|
88
|
+
### 1. A collider — the player never walks through a body
|
|
89
|
+
|
|
90
|
+
An enemy that is only a `THREE.Group` is a ghost. Give every enemy a physics
|
|
91
|
+
presence. The recipe (Rapier, matching `$genex-threejs-physics-rapier` and
|
|
92
|
+
the bundled character controller):
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import RAPIER from "@dimforge/rapier3d-compat";
|
|
96
|
+
|
|
97
|
+
/** One kinematic capsule per enemy: the CONTROLLER collides with it (no
|
|
98
|
+
* walk-through) but the enemy's own movement stays script-driven — AI code
|
|
99
|
+
* keeps teleport-free authority via setNextKinematicTranslation. */
|
|
100
|
+
function addEnemyCollider(world: RAPIER.World, e: { root: THREE.Object3D; halfHeight: number; radius: number }) {
|
|
101
|
+
const body = world.createRigidBody(
|
|
102
|
+
RAPIER.RigidBodyDesc.kinematicPositionBased().setTranslation(
|
|
103
|
+
e.root.position.x, e.root.position.y + e.halfHeight + e.radius, e.root.position.z,
|
|
104
|
+
),
|
|
105
|
+
);
|
|
106
|
+
world.createCollider(RAPIER.ColliderDesc.capsule(e.halfHeight, e.radius), body);
|
|
107
|
+
return body;
|
|
108
|
+
}
|
|
109
|
+
// every frame AFTER the AI moves the root:
|
|
110
|
+
// body.setNextKinematicTranslation({ x, y: y + halfHeight + radius, z });
|
|
111
|
+
// Size from the model's real bounding box (new THREE.Box3().setFromObject),
|
|
112
|
+
// not guessed numbers. Gameplay range tests (aggro, melee reach) keep using
|
|
113
|
+
// your own distance math — the collider exists so BODIES are solid.
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
If the game has no physics world at all, the minimal honest fallback is a
|
|
117
|
+
controller-side overlap resolve: each frame, push the player out of each
|
|
118
|
+
enemy's XZ radius (`if (dist < r) player.position.addScaledVector(away, r - dist)`).
|
|
119
|
+
Solid beats elegant.
|
|
120
|
+
|
|
121
|
+
### 2. Verified facing — walk in front of each enemy type once
|
|
122
|
+
|
|
123
|
+
Generated models are NOT reliably authored front-toward-+Z, and a
|
|
124
|
+
`lookAt`-driven enemy with a sideways-authored model walks sideways forever —
|
|
125
|
+
invisible from behind-the-player camera angles, glaring head-on. Two steps:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
/** Wrap the GLB so +Z is the FORWARD your code can trust: rotate the child
|
|
129
|
+
* inside the wrapper until its face agrees, then aim only the wrapper. */
|
|
130
|
+
function wrapForward(model: THREE.Object3D, yawCorrection: number): THREE.Group {
|
|
131
|
+
const wrapper = new THREE.Group();
|
|
132
|
+
model.rotation.y = yawCorrection; // 0, ±Math.PI/2, or Math.PI — per MODEL, found by looking
|
|
133
|
+
wrapper.add(model);
|
|
134
|
+
return wrapper; // enemy code does wrapper.lookAt(...) / aims the wrapper only
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The verification is human and takes ten seconds per enemy TYPE: stand in
|
|
139
|
+
front of it once — it must face you. This is part of the milestone smoke
|
|
140
|
+
pass once enemies exist (an enemy in frame, facing the player). Set the
|
|
141
|
+
`yawCorrection` constant per model and move on.
|
|
142
|
+
|
|
143
|
+
### 3. Hit reaction — damage reads on the body
|
|
144
|
+
|
|
145
|
+
Rigged: the `hit` clip above. Procedural: a 100–150 ms flinch — scale pulse
|
|
146
|
+
(`1 → 0.92 → 1`), a brief emissive/color flash, and a small recoil along the
|
|
147
|
+
hit direction. Pair it with the HUD hit marker; a bullet that changes nothing
|
|
148
|
+
on the body reads as a miss even when the numbers moved.
|
|
149
|
+
|
|
150
|
+
### 4. A death moment — never blink out of existence
|
|
151
|
+
|
|
152
|
+
Rigged: play `death`, hold the final frame (~0.5 s), THEN dissolve/embers and
|
|
153
|
+
remove. Procedural: collapse (scale Y toward 0 with a topple rotation) into
|
|
154
|
+
the same dissolve. Either way the death VFX is a `$genex-threejs-procedural-vfx`
|
|
155
|
+
moment that EARNS its beat (the target dissolves and awards score) — one
|
|
156
|
+
pooled burst, not a particle bath.
|
|
157
|
+
|
|
158
|
+
## Procedural motion recipes (the static lane, done well)
|
|
159
|
+
|
|
160
|
+
Give an unrigged body three layered motions — enough life that "static +
|
|
161
|
+
procedural" is a real choice, not a downgrade: a **gait bob** (body
|
|
162
|
+
`position.y += sin(t * stride) * 0.05` with a slight roll for quadrupeds), a
|
|
163
|
+
**lunge stretch** (scale Z up 8% during attack windup, snap back on strike),
|
|
164
|
+
and an **idle sway** (low-amplitude yaw/pitch noise so nothing stands
|
|
165
|
+
morgue-still). Author them against the wrapper from rule 2 so facing math
|
|
166
|
+
stays clean. `$genex-threejs-procedural-animation` has the timeline tools for
|
|
167
|
+
anything staged.
|
|
168
|
+
|
|
169
|
+
## Multiplayer
|
|
170
|
+
|
|
171
|
+
Enemies are host-simulated shared objects (`$genex-threejs-multiplayer` —
|
|
172
|
+
the host owns `room.objects` for every enemy; remotes render interpolated
|
|
173
|
+
state). The collider rule applies on every client — bodies are solid locally
|
|
174
|
+
even when the HOST owns the movement; clip/state changes ride the shared
|
|
175
|
+
object's state field, never a per-frame broadcast.
|
|
176
|
+
|
|
177
|
+
## Troubleshooting
|
|
178
|
+
|
|
179
|
+
- **"Out of credits" (`insufficient_credits`)** — tell the user the facts the
|
|
180
|
+
CLI printed (balance, cost, refill), continue with a procedural-placeholder
|
|
181
|
+
enemy body, and mark the spot with
|
|
182
|
+
`// TODO(genex): regenerate when credits refill`. Do not stop the session.
|
|
183
|
+
- **"Email not verified" (`email_verification_required`)** — hand over the
|
|
184
|
+
verify link the CLI printed, wait, re-run.
|
|
185
|
+
- **The creature came back standing when you wanted four legs** — that is the
|
|
186
|
+
documented platform limit, not a bad roll: re-rolling the prompt will not
|
|
187
|
+
produce a rigged quadruped. Switch that creature to the static + procedural
|
|
188
|
+
lane and say so in the Assets table.
|
|
189
|
+
- **Clips look wrong on the body** (arms clip the torso on a bulky model) —
|
|
190
|
+
pick a different library action id (`animations search`); never patch limbs
|
|
191
|
+
post-mixer.
|
|
192
|
+
- **Every instance animates in sync** — you shared one mixer or one clip
|
|
193
|
+
instance; clone per creature (`SkeletonUtils.clone` + a fresh mixer each).
|
|
@@ -27,7 +27,7 @@ in another.
|
|
|
27
27
|
| Pause | always — opens on the Escape key | 1 — menu backdrop under a dark overlay |
|
|
28
28
|
| Fail / retry | always | 1 — a *graded* variant of the menu screen |
|
|
29
29
|
| Win / next | always | 1 — graded variant, warm |
|
|
30
|
-
| Settings | always — every game carries the Quality picker (Auto/Low/Medium/High, `$genex-threejs-adaptive-quality`), plus whatever else it has to set | 1 |
|
|
30
|
+
| Settings | always — every game carries the Quality picker (Auto/Low/Medium/High, `$genex-threejs-adaptive-quality`), and any game with generated audio carries **Music + SFX volume sliders** (persisted, applied live; music default 0.30, sfx ~0.7 — `$genex-ai-music`; a paid track with no volume control is a failure mode), plus whatever else it has to set | 1 |
|
|
31
31
|
| Lobby / waiting | multiplayer only | 1 over the menu backdrop |
|
|
32
32
|
| HUD | always | 2 — generated sprite HUD (`$genex-ai-hud`), enqueued at this gate for EVERY game; plain CSS is the placeholder until the sprites land, never the final HUD |
|
|
33
33
|
|
|
@@ -531,6 +531,10 @@ architecture and consume the shared style brief.
|
|
|
531
531
|
text or padding, a lost focus ring or glow, a jagged aliased edge, or a
|
|
532
532
|
border/frame that stops at the cut instead of following it — the
|
|
533
533
|
technique is fine; the sloppy cut is the defect.
|
|
534
|
+
- A plate shaped by `npx genex ui plate` (the frame's traced silhouette as
|
|
535
|
+
the plate's `mask-image`) is the fix for shaped backing — see
|
|
536
|
+
`$genex-ai-hud`'s silhouette-plate rule; a bare rounded rectangle behind
|
|
537
|
+
generated art is the defect below.
|
|
534
538
|
- A rectangular semi-transparent plate protruding past an opaque/angular
|
|
535
539
|
widget frame — a dark box floating over the scene. The frame's own art is
|
|
536
540
|
the backing; a plate is only for bare-text/outline widgets and stays inside
|
|
@@ -541,7 +541,12 @@ fights (many writers). A ball on `objects` glides and has one owner. That's the
|
|
|
541
541
|
`loadVrmClone(p.avatarUrl || "./assets/avatar.vrm")` (the vendored loader's shared-GPU clone:
|
|
542
542
|
N remotes share one set of geometry/textures instead of re-parsing per player — retarget
|
|
543
543
|
clips once on `loadVrmClone.base(url)` and play them on each clone's own mixer); never
|
|
544
|
-
publish avatar URLs through `me.set`.
|
|
544
|
+
publish avatar URLs through `me.set`. **A remote player's body is NEVER hand-built
|
|
545
|
+
primitives** (no capsule + cone "person" — the single most common shipped co-op defect):
|
|
546
|
+
a themed game renders remotes with the SAME themed character model the local player
|
|
547
|
+
uses; everything else renders `p.avatarUrl` VRMs. This applies with full force to
|
|
548
|
+
first-person games — the local player may be invisible to themselves, but every
|
|
549
|
+
remote hunter/partner is a full character on screen. On phone tiers, animate and fully draw only the
|
|
545
550
|
nearest `tier.remoteAvatarCap` remotes (`$genex-threejs-adaptive-quality`) — freeze the
|
|
546
551
|
mixer and billboard or hide the rest; a room allows up to 64 players and 64 live avatars
|
|
547
552
|
is a real phone memory kill on its own.
|