@genex-ai/cli-demo 0.81.0-dev.214 → 0.85.0-dev.216
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 +9 -7
- package/dist/index.js +2623 -1684
- 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 +175 -63
- package/templates/skills/genex-ai-hud/references/masked-fill.md +19 -13
- package/templates/skills/genex-ai-hud/references/stage1-prompt-template.md +42 -5
- package/templates/skills/genex-ai-hud/references/stage2-prompt-template.md +7 -3
- package/templates/skills/genex-ai-image/SKILL.md +40 -2
- package/templates/skills/genex-ai-menu/SKILL.md +47 -22
- 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 +183 -58
- package/templates/skills/genex-game-director/references/design-contract.md +40 -10
- package/templates/skills/genex-game-director/references/routing-map.md +44 -29
- package/templates/skills/genex-threejs-camera-direction/SKILL.md +4 -1
- package/templates/skills/genex-threejs-character-controller/SKILL.md +25 -1
- package/templates/skills/genex-threejs-character-controller/references/wiring.md +13 -2
- package/templates/skills/genex-threejs-creatures/SKILL.md +201 -0
- package/templates/skills/genex-threejs-game-ui/SKILL.md +79 -71
- package/templates/skills/genex-threejs-multiplayer/SKILL.md +6 -1
- package/templates/skills/genex-threejs-visual-validation/SKILL.md +9 -4
|
@@ -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` |
|
|
@@ -85,24 +88,28 @@ Three.js release or branch, and do not blindly copy demo architecture.
|
|
|
85
88
|
decided silently. FIRST of all art, generate the gate's **concept mockup** —
|
|
86
89
|
a playable-moment shot (verb + threat + objective in frame, per the
|
|
87
90
|
game-ui gate) WITH the full HUD composited over it: the `$genex-ai-hud`
|
|
88
|
-
Stage-1 image,
|
|
89
|
-
HUD blueprint (never a separate UI-free concept first
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
91
|
+
Stage-1 image, ONE generation serving as concept, style checkpoint, and
|
|
92
|
+
HUD blueprint (never a separate UI-free concept first, and no candidate
|
|
93
|
+
variants unless the player asks for them). **The moment it lands, the
|
|
94
|
+
cheap style chain fires — nothing waits for the player here**: decide the
|
|
95
|
+
HUD lane as art director and record the `HUD lane:` line in DESIGN.md
|
|
96
|
+
(director §5), then enqueue with `--no-wait` the `$genex-ai-hud` Stage-2
|
|
97
|
+
sheet, the `$genex-ai-menu` still (the menu is the default for every
|
|
98
|
+
game — "it's only a draft" is not a reason to decide no), and the
|
|
99
|
+
logotype. THEN show the player the frame and ask keep-or-change through
|
|
100
|
+
your question tool (a short numbered list in chat when you have none) —
|
|
101
|
+
the answer is INFORMATION, never a gate: silence means the concept
|
|
102
|
+
stands; "change" loops the concept with their notes and the chain re-runs
|
|
103
|
+
from the new frame (image-priced — cheap by design; the game-ui skill
|
|
104
|
+
owns the re-anchor loop). Only the menu VIDEO waits, for the FIRST of:
|
|
105
|
+
the player's yes · the next `genex preview` after the menu still landed ·
|
|
106
|
+
style work being the only work left — and never while a player objection
|
|
107
|
+
is open (two failed videos → ship the still). Later `--edit`-able
|
|
108
|
+
generations anchor to the standing frame for STYLE while the game
|
|
109
|
+
contract owns content. Everything concept-independent — scaffold, boot
|
|
110
|
+
wiring, the core loop, the worker lanes — keeps building in parallel.
|
|
111
|
+
Skipping this enqueue is the #1 way a finished game ships an ugly HUD —
|
|
112
|
+
by step 12 there is nothing to swap in.
|
|
106
113
|
4. Lock the visual direction — the same plan-first logic as the UI gate, in
|
|
107
114
|
the same plan block, before any rendering code:
|
|
108
115
|
- **camera**: the rig type and the pointer bucket
|
|
@@ -247,12 +254,15 @@ Three.js release or branch, and do not blindly copy demo architecture.
|
|
|
247
254
|
`$genex-threejs-game-ui` (HUD, pause on Escape, fail/retry, win, and the
|
|
248
255
|
full loading state grown from the step-6 loader), then `npx genex wait`
|
|
249
256
|
the step-3 UI generations and wire them in — the sprite HUD replaces the
|
|
250
|
-
placeholder CSS
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
257
|
+
placeholder CSS (or the recorded `HUD lane: CSS` build lands finished to
|
|
258
|
+
its brief), the menu video replaces the still frame (wired with the menu
|
|
259
|
+
skill's loop crossfade), the logotype lands on the menu and loader, and
|
|
260
|
+
the scene's planned generated models replace their placeholder
|
|
261
|
+
primitives — a shipped wave of enemies may not be untextured boxes. This
|
|
262
|
+
swap is a completion gate, not an option: a game still on the
|
|
263
|
+
placeholder CSS HUD (with no recorded CSS lane), without the menu video
|
|
264
|
+
playing (or its recorded still fallback), or without a working Escape
|
|
265
|
+
pause, is not done. Then run a feel pass via
|
|
256
266
|
`$genex-threejs-game-feel` (input response, camera, impact feedback,
|
|
257
267
|
retry speed).
|
|
258
268
|
13. Validate in a real browser with fixed seeds, captures, interaction checks,
|
|
@@ -261,8 +271,9 @@ Three.js release or branch, and do not blindly copy demo architecture.
|
|
|
261
271
|
## Delegation
|
|
262
272
|
|
|
263
273
|
Fan-out is owned by the director: sub-agents own DESIGN.md Modules rows,
|
|
264
|
-
concept-DEPENDENT lanes
|
|
265
|
-
|
|
274
|
+
concept-DEPENDENT lanes launch the moment the concept lands (only the menu
|
|
275
|
+
video waits for its event triple — step 3), one writer per file, workers
|
|
276
|
+
never spawn workers, and the Assets table is the budget —
|
|
266
277
|
the full rules and the worker prompt shape live in the Delegate section of
|
|
267
278
|
`$genex-game-director`. This map adds no separate delegation rules; it is the
|
|
268
279
|
routing source the director and its workers read.
|
|
@@ -282,7 +293,9 @@ routing source the director and its workers read.
|
|
|
282
293
|
done = a screenshot plus an interaction smoke check (load the page, press each
|
|
283
294
|
control, assert a visible response in its labeled direction — `$genex-threejs-visual-validation` has the
|
|
284
295
|
procedure), **plus the UI floor from `$genex-threejs-game-ui` (the generated
|
|
285
|
-
sprite HUD wired in — not the CSS placeholder —
|
|
296
|
+
sprite HUD wired in — not the CSS placeholder — or the DESIGN.md-recorded
|
|
297
|
+
`HUD lane: CSS` build finished to its brief; the menu video playing, or its
|
|
298
|
+
recorded still fallback; the logotype placed; pause on Escape, the branded
|
|
286
299
|
loader with its key-art background, the brief's font pair actually loaded)
|
|
287
300
|
and the look floor (the step-4 renderer baseline + named post stack actually
|
|
288
301
|
built; every placed 2D/media piece — decals, posters, in-world screens —
|
|
@@ -320,7 +333,9 @@ A routed Genex scene is incomplete until it exposes:
|
|
|
320
333
|
## Publish and multiplayer awareness
|
|
321
334
|
|
|
322
335
|
**Publishing IS calling it done.** Before `npx genex publish`, every completion
|
|
323
|
-
gate above must pass — sprite HUD wired
|
|
336
|
+
gate above must pass — sprite HUD wired (or the recorded CSS lane finished),
|
|
337
|
+
the menu video playing (or its recorded still fallback), the logotype placed,
|
|
338
|
+
Escape pause working, branded loader
|
|
324
339
|
with its key art, fonts loaded, renderer baseline + one built post effect
|
|
325
340
|
(tier-aware), the adaptive-quality tier wired at boot, world dressing placed
|
|
326
341
|
or validly waived, and the content contract's countables present or
|
|
@@ -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
|
|
@@ -334,6 +339,25 @@ own avatar file: players picked their looks, show them.
|
|
|
334
339
|
- Load `$genex-threejs-multiplayer` before writing any networking code; it is
|
|
335
340
|
mandatory for any 2+ player game.
|
|
336
341
|
|
|
342
|
+
## Placing rigs outside the controller — facing is explicit
|
|
343
|
+
|
|
344
|
+
The vendored controller owns the local player's facing. Any rig you place
|
|
345
|
+
YOURSELF — a duel opponent, an NPC, a fighter in a side-view game — obeys
|
|
346
|
+
three hard rules:
|
|
347
|
+
|
|
348
|
+
- **Meshy / Mixamo / VRM rigs rest facing +Z** — from a side camera that
|
|
349
|
+
means straight at the lens. Set the yaw explicitly from the character's
|
|
350
|
+
ROLE the moment you place it (`model.rotation.y = …`); never leave the
|
|
351
|
+
rest pose and assume it reads right.
|
|
352
|
+
- **Never mirror a SkinnedMesh with negative scale.** `scale.x = -1` is a
|
|
353
|
+
2D-sprite trick: on a 3D rig it flips triangle winding and normals
|
|
354
|
+
(broken lighting and culling) and does NOT turn the character. Turning is
|
|
355
|
+
always a yaw rotation.
|
|
356
|
+
- **Duel / side-view / two-character scenes: the combatants face EACH
|
|
357
|
+
OTHER along the duel axis.** Two fighters staring into the camera is a
|
|
358
|
+
bug, not a pose — verify it in the milestone smoke capture (an enemy in
|
|
359
|
+
frame facing the player's CHARACTER, never the lens).
|
|
360
|
+
|
|
337
361
|
## If the user asks for ecctrl
|
|
338
362
|
|
|
339
363
|
ecctrl is a React / React Three Fiber component; a Genex game is plain
|
|
@@ -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,201 @@
|
|
|
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
|
+
Two hard rules alongside it: **never mirror a rig with negative scale** —
|
|
144
|
+
`scale.x = -1` is a 2D-sprite trick that flips winding and normals on a
|
|
145
|
+
SkinnedMesh and does NOT turn a 3D body; turning is always a yaw
|
|
146
|
+
(`rotation.y`), set explicitly from the creature's role. And in any
|
|
147
|
+
**duel / side-view / two-character scene**, the combatants face EACH OTHER
|
|
148
|
+
along the duel axis — a fighter staring into the camera is a bug, not a
|
|
149
|
+
pose, and the smoke capture is where it gets caught.
|
|
150
|
+
|
|
151
|
+
### 3. Hit reaction — damage reads on the body
|
|
152
|
+
|
|
153
|
+
Rigged: the `hit` clip above. Procedural: a 100–150 ms flinch — scale pulse
|
|
154
|
+
(`1 → 0.92 → 1`), a brief emissive/color flash, and a small recoil along the
|
|
155
|
+
hit direction. Pair it with the HUD hit marker; a bullet that changes nothing
|
|
156
|
+
on the body reads as a miss even when the numbers moved.
|
|
157
|
+
|
|
158
|
+
### 4. A death moment — never blink out of existence
|
|
159
|
+
|
|
160
|
+
Rigged: play `death`, hold the final frame (~0.5 s), THEN dissolve/embers and
|
|
161
|
+
remove. Procedural: collapse (scale Y toward 0 with a topple rotation) into
|
|
162
|
+
the same dissolve. Either way the death VFX is a `$genex-threejs-procedural-vfx`
|
|
163
|
+
moment that EARNS its beat (the target dissolves and awards score) — one
|
|
164
|
+
pooled burst, not a particle bath.
|
|
165
|
+
|
|
166
|
+
## Procedural motion recipes (the static lane, done well)
|
|
167
|
+
|
|
168
|
+
Give an unrigged body three layered motions — enough life that "static +
|
|
169
|
+
procedural" is a real choice, not a downgrade: a **gait bob** (body
|
|
170
|
+
`position.y += sin(t * stride) * 0.05` with a slight roll for quadrupeds), a
|
|
171
|
+
**lunge stretch** (scale Z up 8% during attack windup, snap back on strike),
|
|
172
|
+
and an **idle sway** (low-amplitude yaw/pitch noise so nothing stands
|
|
173
|
+
morgue-still). Author them against the wrapper from rule 2 so facing math
|
|
174
|
+
stays clean. `$genex-threejs-procedural-animation` has the timeline tools for
|
|
175
|
+
anything staged.
|
|
176
|
+
|
|
177
|
+
## Multiplayer
|
|
178
|
+
|
|
179
|
+
Enemies are host-simulated shared objects (`$genex-threejs-multiplayer` —
|
|
180
|
+
the host owns `room.objects` for every enemy; remotes render interpolated
|
|
181
|
+
state). The collider rule applies on every client — bodies are solid locally
|
|
182
|
+
even when the HOST owns the movement; clip/state changes ride the shared
|
|
183
|
+
object's state field, never a per-frame broadcast.
|
|
184
|
+
|
|
185
|
+
## Troubleshooting
|
|
186
|
+
|
|
187
|
+
- **"Out of credits" (`insufficient_credits`)** — tell the user the facts the
|
|
188
|
+
CLI printed (balance, cost, refill), continue with a procedural-placeholder
|
|
189
|
+
enemy body, and mark the spot with
|
|
190
|
+
`// TODO(genex): regenerate when credits refill`. Do not stop the session.
|
|
191
|
+
- **"Email not verified" (`email_verification_required`)** — hand over the
|
|
192
|
+
verify link the CLI printed, wait, re-run.
|
|
193
|
+
- **The creature came back standing when you wanted four legs** — that is the
|
|
194
|
+
documented platform limit, not a bad roll: re-rolling the prompt will not
|
|
195
|
+
produce a rigged quadruped. Switch that creature to the static + procedural
|
|
196
|
+
lane and say so in the Assets table.
|
|
197
|
+
- **Clips look wrong on the body** (arms clip the torso on a bulky model) —
|
|
198
|
+
pick a different library action id (`animations search`); never patch limbs
|
|
199
|
+
post-mixer.
|
|
200
|
+
- **Every instance animates in sync** — you shared one mixer or one clip
|
|
201
|
+
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
|
|
|
@@ -71,66 +71,62 @@ and how the space reads (route, scale) — plus the brief's palette,
|
|
|
71
71
|
materials, and light. A beautiful empty vista with nothing to fight and
|
|
72
72
|
nowhere to go is a FAILED concept; so is one that invents mechanics the
|
|
73
73
|
game doesn't have (a lap counter in a game without laps). Generate it
|
|
74
|
-
`--size 2560x1440 --quality high --
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
(the verb), what threatens the player, what they chase,
|
|
80
|
-
and the brief's palette / materials / light /
|
|
81
|
-
weighing a stated direction, not guessing at a
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
user
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
menu
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
user still gets a walkable first version, and the instant they say yes the
|
|
113
|
-
style pipeline launches against the frame they approved. (A user who vanishes
|
|
114
|
-
entirely leaves the LOOK pending, not the game — the deliberate trade for
|
|
115
|
-
never committing a style behind their back.)
|
|
74
|
+
`--size 2560x1440 --quality high --no-wait`, enqueued FIRST of all art —
|
|
75
|
+
ONE image, no candidate variants unless the user asks; its URL goes into
|
|
76
|
+
the style-brief comment.
|
|
77
|
+
|
|
78
|
+
**Describe the concept in words while it renders.** Lay it out in chat —
|
|
79
|
+
the playable moment (the verb), what threatens the player, what they chase,
|
|
80
|
+
how the space reads, and the brief's palette / materials / light /
|
|
81
|
+
references — so the user is weighing a stated direction, not guessing at a
|
|
82
|
+
picture.
|
|
83
|
+
|
|
84
|
+
**The moment the mockup lands, the style chain fires — then the user sees
|
|
85
|
+
the frame.** In this order, no waiting between the steps: decide the HUD
|
|
86
|
+
lane as art director and record the `HUD lane:` line in DESIGN.md
|
|
87
|
+
(`$genex-game-director` §5 owns the criteria), enqueue the style-dependent
|
|
88
|
+
chain `--no-wait` — the HUD Stage-2 deconstruct (from the mockup), the menu
|
|
89
|
+
still (`--edit`-anchored to it), and the logotype — and THEN show the frame:
|
|
90
|
+
pick it up with `genex wait <id> --open` (or generate with `--open`) so it
|
|
91
|
+
opens in the user's browser AND prints the link, and paste the URL as a
|
|
92
|
+
clickable link — a URL is invisible in a terminal, and "do you like it?"
|
|
93
|
+
with no picture in front of the user is the #1 way this checkpoint fails.
|
|
94
|
+
|
|
95
|
+
**Ask keep-or-change with your question tool — as INFORMATION, never a
|
|
96
|
+
gate.** The one that shows clickable options; a short numbered list in chat
|
|
97
|
+
only where there is none. ONE question — "this is roughly how the game and
|
|
98
|
+
its HUD will look — keep this direction, or change something?" — with
|
|
99
|
+
concrete keep / change options. The chain is already running while they
|
|
100
|
+
read it: silence means the concept stands; nothing except the menu VIDEO
|
|
101
|
+
ever waits for the answer. The user still gets a real say — a "change" at
|
|
102
|
+
any time loops the concept with their notes at image prices (below). The
|
|
103
|
+
menu video (the one expensive item) fires at the FIRST of: the user's yes ·
|
|
104
|
+
the next `genex preview` after the menu still landed · style work being the
|
|
105
|
+
only work left — and never while a user objection is open
|
|
106
|
+
(`$genex-ai-menu` owns the trigger). (The core asset set — hero model,
|
|
107
|
+
ground texture, skybox, sfx — is prompted from the game IDEA, not the
|
|
108
|
+
image, and mostly survives a style change: launch it up front with
|
|
109
|
+
placeholders. Everything style-independent — scaffold, boot wiring, the
|
|
110
|
+
core loop, the gameplay-LOGIC subagent modules — keeps moving at full speed
|
|
111
|
+
in parallel throughout.)
|
|
116
112
|
|
|
117
113
|
**Change reopens the loop, same shape.** If the user picks "change" — or
|
|
118
114
|
comes back with notes immediately or an hour later — re-run Stage 1 (the
|
|
119
|
-
concept mockup itself) with their exact notes
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
re-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
115
|
+
concept mockup itself) with their exact notes, open + link the new frame,
|
|
116
|
+
ask again the same structured way, and re-run the cheap chain from the new
|
|
117
|
+
frame (image-priced — that is the design: the correction lane is cheap
|
|
118
|
+
because the expensive item waited). Carry every note forward so each round
|
|
119
|
+
compounds; if two rounds don't converge, offer 2–3 distinct directions
|
|
120
|
+
(that's the one moment `--candidates` earns its place) instead of
|
|
121
|
+
re-rolling blind. Each standing frame is the working style. When the style
|
|
122
|
+
changes after downstream art already ran, re-anchor it: the menu still is
|
|
123
|
+
re-edited (`--edit`) against the new mockup and its video re-run once from
|
|
124
|
+
the new still (`$genex-ai-menu` — a user-driven style change re-opens its
|
|
125
|
+
one-video rule), and the HUD deconstruct (Stage 2 onward, `$genex-ai-hud`)
|
|
126
|
+
restarts from the new mockup. Style-neutral assets (most textures, sfx,
|
|
127
|
+
models) usually survive — judge each in one line. The same "open it + paste
|
|
128
|
+
the link" rule covers every image the user weighs in on — the menu still,
|
|
129
|
+
the HUD mockup.
|
|
134
130
|
|
|
135
131
|
**The concept anchors STYLE, not truth.** Palette, materials, light, and
|
|
136
132
|
register come from the frame; CONTENT comes from the game contract. This
|
|
@@ -165,13 +161,16 @@ rule explicitly does not apply to this one message):
|
|
|
165
161
|
```
|
|
166
162
|
UI plan
|
|
167
163
|
• Screens: <list with tiers — loader / menu / pause (Esc) / win/lose / …>
|
|
168
|
-
• Style: <4–5 named hues> · fonts <display> / <body>
|
|
164
|
+
• Style: <4–5 named hues> · fonts <display> / <body> (from $genex-ai-menu's
|
|
165
|
+
genre table, or a one-line reason)
|
|
169
166
|
• References: <2–3 AAA games — one line on what's borrowed>
|
|
170
167
|
• Menu: <archetype + button treatment, one-line reason from the brief>
|
|
171
|
-
•
|
|
172
|
-
•
|
|
173
|
-
|
|
174
|
-
|
|
168
|
+
• HUD lane: <sprites (…) | CSS (…, one-line justification)> — recorded in DESIGN.md
|
|
169
|
+
• Concept (HUD mockup): <generation id> — shown for keep / change
|
|
170
|
+
(informational — the chain below is already queued; silence = it stands)
|
|
171
|
+
• Queued on concept landing: HUD sheet (Stage 2) · menu still · logotype
|
|
172
|
+
<or "skipped: reason">; menu VIDEO waits for: your yes / the next preview
|
|
173
|
+
after the still lands / style work being all that's left <or "no menu: reason">
|
|
175
174
|
• Building now (style-independent): <core loop · logic modules already moving>
|
|
176
175
|
• Deferred from mockup: <widgets the image invented but the game lacks — or "none">
|
|
177
176
|
```
|
|
@@ -190,8 +189,9 @@ A message missing any line means the gate did not run — go back and run it.
|
|
|
190
189
|
every game), and the generated **logotype** — one `--transparent` wordmark
|
|
191
190
|
in the brief's display register (`$genex-ai-menu`'s logotype step), default
|
|
192
191
|
YES for every game with a menu; skipping it needs a one-line stated reason.
|
|
193
|
-
Enqueue this chain the instant the
|
|
194
|
-
|
|
192
|
+
Enqueue this chain the instant the concept mockup LANDS (`--no-wait`) —
|
|
193
|
+
the keep/change answer never gates it; only the menu VIDEO waits, for its
|
|
194
|
+
event triple (`$genex-ai-menu`) — then
|
|
195
195
|
keep building, pick results up with `npx genex wait <id>`, swap them in as
|
|
196
196
|
they land. **Tier 2 must never block a playable v0 — but the game is NOT
|
|
197
197
|
DONE until its Tier-2 assets have landed and been wired in** (the only
|
|
@@ -200,7 +200,9 @@ A message missing any line means the gate did not run — go back and run it.
|
|
|
200
200
|
Run `npx genex wait` on every enqueued ID before any publish and before
|
|
201
201
|
the final handoff of a session — never park landed assets for "later".
|
|
202
202
|
Shipping the placeholder CSS HUD as the final HUD is a failure, not a
|
|
203
|
-
tier choice.
|
|
203
|
+
tier choice — the ONE exception is a DESIGN.md-recorded `HUD lane: CSS`
|
|
204
|
+
decision (`$genex-game-director` §5), where the CSS build, finished to
|
|
205
|
+
its brief, IS the production HUD.
|
|
204
206
|
- **Tier 3 — offer, don't build.** Video layers over the HUD, 9-slice panel
|
|
205
207
|
sprites, animated menu sprites. Offer in one line
|
|
206
208
|
after the player has seen Tier 1+2 working; build on request.
|
|
@@ -522,15 +524,21 @@ architecture and consume the shared style brief.
|
|
|
522
524
|
- Hard-cut phase swaps, a menu whose elements just appear, numbers that
|
|
523
525
|
teleport.
|
|
524
526
|
- A silent menu; a bare "Loading…" over black.
|
|
525
|
-
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
527
|
+
- The style chain parked behind the keep/change question — the HUD Stage-2
|
|
528
|
+
sheet, menu still, and logotype enqueue the moment the mockup LANDS, and
|
|
529
|
+
silence means the concept stands; OR the menu VIDEO fired while a user
|
|
530
|
+
objection was still open (its event triple is the only wait in the lane);
|
|
531
|
+
OR the whole build stalled on the concept at all, when concept-INDEPENDENT
|
|
532
|
+
work (scaffold, core loop, logic subagents) must keep moving in parallel
|
|
533
|
+
throughout.
|
|
530
534
|
- A CSS-cut corner (`clip-path`/`mask`) that shears its own content — clipped
|
|
531
535
|
text or padding, a lost focus ring or glow, a jagged aliased edge, or a
|
|
532
536
|
border/frame that stops at the cut instead of following it — the
|
|
533
537
|
technique is fine; the sloppy cut is the defect.
|
|
538
|
+
- A plate shaped by `npx genex ui plate` (the frame's traced silhouette as
|
|
539
|
+
the plate's `mask-image`) is the fix for shaped backing — see
|
|
540
|
+
`$genex-ai-hud`'s silhouette-plate rule; a bare rounded rectangle behind
|
|
541
|
+
generated art is the defect below.
|
|
534
542
|
- A rectangular semi-transparent plate protruding past an opaque/angular
|
|
535
543
|
widget frame — a dark box floating over the scene. The frame's own art is
|
|
536
544
|
the backing; a plate is only for bare-text/outline widgets and stays inside
|