@genex-ai/cli-demo 0.71.0-dev.186 → 0.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +8 -354
- package/package.json +1 -2
- package/templates/controllers/character/vrm/vrm-loader.ts +11 -74
- package/templates/skills/genex-ai-hud/SKILL.md +2 -8
- package/templates/skills/genex-ai-menu/SKILL.md +2 -14
- package/templates/skills/genex-ai-skybox/SKILL.md +4 -15
- package/templates/skills/genex-ai-texture/SKILL.md +1 -1
- package/templates/skills/genex-ai-video/SKILL.md +1 -1
- package/templates/skills/genex-explore/SKILL.md +1 -1
- package/templates/skills/genex-getting-started/SKILL.md +2 -2
- package/templates/skills/genex-threejs-bloom/SKILL.md +1 -4
- package/templates/skills/genex-threejs-bloom/references/bloom.md +1 -1
- package/templates/skills/genex-threejs-camera-direction/SKILL.md +8 -48
- package/templates/skills/genex-threejs-camera-direction/references/camera-rigs.md +0 -62
- package/templates/skills/genex-threejs-embed-auth/SKILL.md +1 -4
- package/templates/skills/genex-threejs-game-feel/SKILL.md +1 -4
- package/templates/skills/genex-threejs-game-ui/SKILL.md +26 -90
- package/templates/skills/genex-threejs-game-ui/references/style-capsules.md +1 -2
- package/templates/skills/genex-threejs-image-pipeline/SKILL.md +0 -5
- package/templates/skills/genex-threejs-image-pipeline/references/image-pipeline.md +1 -1
- package/templates/skills/genex-threejs-lighting-design/SKILL.md +1 -5
- package/templates/skills/genex-threejs-multiplayer/SKILL.md +1 -7
- package/templates/skills/genex-threejs-multiplayer/references/host-physics.md +3 -6
- package/templates/skills/genex-threejs-physics-rapier/references/colliders-from-assets.md +0 -1
- package/templates/skills/genex-threejs-screen-space-ambient-occlusion/references/ambient-occlusion.md +1 -1
- package/templates/skills/genex-threejs-shadow-systems/SKILL.md +0 -6
- package/templates/skills/genex-threejs-shadow-systems/references/shadow-systems.md +1 -1
- package/templates/skills/genex-threejs-skill-router/SKILL.md +5 -26
- package/templates/skills/genex-threejs-skill-router/references/routing-map.md +9 -25
- package/templates/skills/genex-threejs-spectral-ocean/references/spectral-ocean.md +1 -1
- package/templates/skills/genex-threejs-touch-controls/SKILL.md +0 -11
- package/templates/skills/genex-threejs-visual-validation/SKILL.md +12 -29
- package/templates/skills/genex-threejs-water-optics/references/water-optics.md +1 -1
- package/templates/skills/genex-updates/SKILL.md +1 -1
- package/templates/controllers/quality/governor.ts +0 -147
- package/templates/controllers/quality/pick-asset.ts +0 -57
- package/templates/controllers/quality/tier.ts +0 -170
- package/templates/skills/genex-threejs-adaptive-quality/SKILL.md +0 -141
- package/templates/skills/genex-threejs-adaptive-quality/references/adaptive-quality.md +0 -105
|
@@ -35,23 +35,15 @@ in local dev, the published game, and remixes).
|
|
|
35
35
|
|
|
36
36
|
## Load it as background + environment
|
|
37
37
|
|
|
38
|
-
Load the equirect JPG
|
|
39
|
-
|
|
40
|
-
The bare URL is an 8192×4096 original — ~178 MB decoded, over half a phone's
|
|
41
|
-
GPU budget in one texture — so phones must load the downscale rung the platform
|
|
42
|
-
stores next to every skybox (`$genex-threejs-adaptive-quality`):
|
|
38
|
+
Load the equirect JPG, mark it equirectangular, and use it for both the visible
|
|
39
|
+
background and the lighting:
|
|
43
40
|
|
|
44
41
|
```ts
|
|
45
42
|
import * as THREE from "three";
|
|
46
|
-
import { detectTier } from "./controllers/quality/tier.ts";
|
|
47
|
-
import { loadTextureWithFallback } from "./controllers/quality/pick-asset.ts";
|
|
48
43
|
|
|
49
44
|
// the URL `npx genex skybox` printed (R2 sends CORS headers, so cross-origin works):
|
|
50
45
|
const SKYBOX_URL = "https://assets.genex.technology/generations/<id>/skybox-equirect";
|
|
51
|
-
const
|
|
52
|
-
const texture = await loadTextureWithFallback(SKYBOX_URL, tier, (u) =>
|
|
53
|
-
new THREE.TextureLoader().loadAsync(u),
|
|
54
|
-
);
|
|
46
|
+
const texture = await new THREE.TextureLoader().loadAsync(SKYBOX_URL);
|
|
55
47
|
texture.mapping = THREE.EquirectangularReflectionMapping;
|
|
56
48
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
57
49
|
|
|
@@ -59,9 +51,6 @@ scene.background = texture; // visible sky
|
|
|
59
51
|
scene.environment = texture; // image-based lighting on PBR materials
|
|
60
52
|
```
|
|
61
53
|
|
|
62
|
-
Desktop gets the original; phones get the `@2048`/`@4096` rung; a missing rung
|
|
63
|
-
falls back to the original automatically — never a broken boot.
|
|
64
|
-
|
|
65
54
|
For sharper reflections/lighting, pre-filter it with `PMREMGenerator`:
|
|
66
55
|
|
|
67
56
|
```ts
|
|
@@ -87,7 +76,7 @@ scene.background = texture; // keep the raw texture for the visible sky
|
|
|
87
76
|
|
|
88
77
|
## Troubleshooting
|
|
89
78
|
|
|
90
|
-
- **"Not authorized"** — run `npx @genex-ai/cli-demo@
|
|
79
|
+
- **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
|
|
91
80
|
- **"Out of credits" (`insufficient_credits`)** — the account has no credits left for
|
|
92
81
|
this skybox generation. Tell the user the facts the CLI printed: their balance, this
|
|
93
82
|
generation's cost, and when their credits refill. Then offer to continue the build
|
|
@@ -225,7 +225,7 @@ first one is the one a screenshot of the whole arena will not show you.
|
|
|
225
225
|
|
|
226
226
|
## Troubleshooting
|
|
227
227
|
|
|
228
|
-
- **"Not authorized"** — run `npx @genex-ai/cli-demo@
|
|
228
|
+
- **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
|
|
229
229
|
- **"Out of credits" (`insufficient_credits`)** — the account has no credits left for
|
|
230
230
|
this texture generation. Tell the user the facts the CLI printed: their balance,
|
|
231
231
|
this generation's cost, and when their credits refill. Then offer to continue the
|
|
@@ -145,7 +145,7 @@ set belongs to `$genex-ai-hud` — both build on `npx genex image`/`video`.
|
|
|
145
145
|
|
|
146
146
|
## Troubleshooting
|
|
147
147
|
|
|
148
|
-
- **"Not authorized"** — run `npx @genex-ai/cli-demo@
|
|
148
|
+
- **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
|
|
149
149
|
- **"Prompt rejected"** — the provider's content-safety filter blocked the prompt.
|
|
150
150
|
This is non-retryable; retrying the same wording fails again. Rewrite the prompt.
|
|
151
151
|
- **Nothing plays / black surface** — the first `video.play()` must run inside a user
|
|
@@ -71,7 +71,7 @@ Add `--json` for machine-readable output.
|
|
|
71
71
|
|
|
72
72
|
1. `git clone <clone URL from the output> <name>` — pick a short one-word name.
|
|
73
73
|
2. `cd <name>`, then run init on the SAME CLI channel your current project
|
|
74
|
-
uses: `npx @genex-ai/cli-demo@
|
|
74
|
+
uses: `npx @genex-ai/cli-demo@latest init <name>` — or `@dev` when you're
|
|
75
75
|
on the dev stand (unsure? `dashboardOrigins` in your current project's
|
|
76
76
|
`.genex/project.json` says which). Never use `--force`. This creates your
|
|
77
77
|
own project; the original is untouched.
|
|
@@ -130,7 +130,7 @@ and re-link the clone to the same live game:
|
|
|
130
130
|
```bash
|
|
131
131
|
git clone <the game's repo url> my-game && cd my-game
|
|
132
132
|
npm install
|
|
133
|
-
npx @genex-ai/cli-demo@
|
|
133
|
+
npx @genex-ai/cli-demo@latest link <slug> # slug = the name in the play URL
|
|
134
134
|
```
|
|
135
135
|
|
|
136
136
|
Don't know the slug? **`npx genex list`** prints every game on your account —
|
|
@@ -157,7 +157,7 @@ Safe to run any time — genex-owned skills are refreshed to the latest version,
|
|
|
157
157
|
and your own files are never touched:
|
|
158
158
|
|
|
159
159
|
```bash
|
|
160
|
-
npx @genex-ai/cli-demo@
|
|
160
|
+
npx @genex-ai/cli-demo@latest init
|
|
161
161
|
```
|
|
162
162
|
|
|
163
163
|
Use `--force` only if you intentionally want your own existing files overwritten
|
|
@@ -32,10 +32,7 @@ reference before adding selective bloom to a composed scene.
|
|
|
32
32
|
- selective bloom requires mutating scene materials every frame without restoration guarantees;
|
|
33
33
|
- transparent particles disappear from extraction because pass ownership is unclear;
|
|
34
34
|
- bloom radius changes wildly with resolution;
|
|
35
|
-
- highlights become gray because energy is clamped too early
|
|
36
|
-
- bloom ships un-tiered: phone tiers run the light post level
|
|
37
|
-
(`$genex-threejs-adaptive-quality`) — bloom is a desktop-tier pass, and its
|
|
38
|
-
full-res HDR target is exactly the allocation phones get killed for.
|
|
35
|
+
- highlights become gray because energy is clamped too early.
|
|
39
36
|
|
|
40
37
|
## Routing boundary
|
|
41
38
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Use this reference to choose bloom ownership, signal order, selective contribution, and scene-relative emissive ranges without making bloom responsible for the underlying form.
|
|
4
4
|
|
|
5
|
-
> **Renderer note:** this reference assumes `WebGPURenderer` + TSL node materials. Check the project's actual renderer first — the Genex scaffold ships vanilla WebGL three.js. On WebGL, adapt the technique with standard materials / `EffectComposer` passes or pick a simpler alternative; never switch renderers mid-project.
|
|
5
|
+
> **Renderer note:** this reference assumes `WebGPURenderer` + TSL node materials. Check the project's actual renderer first — the Genex scaffold ships vanilla WebGL three.js. On WebGL, adapt the technique with standard materials / `EffectComposer` passes or pick a simpler alternative; never switch renderers mid-project.
|
|
6
6
|
|
|
7
7
|
## Contents
|
|
8
8
|
|
|
@@ -35,12 +35,9 @@ rules, floating-origin shot, pointer controls, and implementation limits.
|
|
|
35
35
|
|
|
36
36
|
## Aiming and pointer lock
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
is ON by default on desktop — a click locks the pointer and raw mouse movement
|
|
42
|
-
drives the view — so mostly you decide whether to turn it OFF. Name the bucket in
|
|
43
|
-
the build plan:
|
|
38
|
+
On the bundled `FollowCamera`, **pointer-lock aim is ON by default** on desktop:
|
|
39
|
+
a click locks the pointer and raw mouse movement drives the view. You rarely turn
|
|
40
|
+
it on — you decide whether to turn it OFF. Name the bucket in the build plan:
|
|
44
41
|
|
|
45
42
|
- **MANDATORY** — first-person of any kind (FPS, walking sim, horror) and any
|
|
46
43
|
mouse-aimed action (third-person shooter, turret/range). Lock is on by default;
|
|
@@ -50,16 +47,11 @@ the build plan:
|
|
|
50
47
|
`genex controller character` game). On by default; leave it on. Opt out with
|
|
51
48
|
`pointerLockAim: false` only for a stated reason (a cursor-heavy UI at the core
|
|
52
49
|
of play).
|
|
53
|
-
- **
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
- **NEVER** — cursor-core games where the pointer IS the gameplay tool (top-down
|
|
59
|
-
click-to-move, tower defense, builders, card/board/puzzle) and spectator/orbit
|
|
60
|
-
showcases. These **must pass `pointerLockAim: false`** — otherwise the bundled
|
|
61
|
-
camera grabs the cursor on the first click. (Touch needs nothing: pointer lock
|
|
62
|
-
doesn't exist there and the mode no-ops on coarse pointers.)
|
|
50
|
+
- **NEVER** — cursor-core games (top-down click-to-move, tower defense, builders,
|
|
51
|
+
card/board/puzzle) and spectator/orbit showcases. These **must pass
|
|
52
|
+
`pointerLockAim: false`** — otherwise the bundled camera grabs the cursor on the
|
|
53
|
+
first click. (Touch needs nothing: pointer lock doesn't exist there and the mode
|
|
54
|
+
no-ops on coarse pointers.)
|
|
63
55
|
|
|
64
56
|
**Mechanism — games on the bundled controller (most games):** do NOT hand-roll
|
|
65
57
|
lock handling. Aim is already enabled; the kit ships a ready-made cue overlay —
|
|
@@ -121,36 +113,6 @@ grants the permission.
|
|
|
121
113
|
(trackpad "natural scrolling" only flips the wheel). If look feels inverted it's a
|
|
122
114
|
sign bug in the rig, not a device quirk — fix the sign, don't sniff the trackpad.
|
|
123
115
|
|
|
124
|
-
## The screen-direction contract
|
|
125
|
-
|
|
126
|
-
Every input axis has one correct on-screen direction, for every rig, bundled or
|
|
127
|
-
hand-rolled. These four invariants are testable and non-negotiable:
|
|
128
|
-
|
|
129
|
-
1. Mouse/touchpad RIGHT turns the view right; mouse UP looks up (down only behind
|
|
130
|
-
an explicit invert option the player chose).
|
|
131
|
-
2. `KeyD`/ArrowRight moves or turns the player toward screen-RIGHT; `KeyA`/
|
|
132
|
-
ArrowLeft toward screen-left. Same for a touch stick's +x.
|
|
133
|
-
3. Drag-pan picks ONE convention — grab-the-world (terrain follows the pointer)
|
|
134
|
-
or move-the-camera — and BOTH axes obey it. One axis each is the
|
|
135
|
-
"diagonals feel twisted" bug.
|
|
136
|
-
4. See the OS-setting note above: inversion is always your sign, never the device.
|
|
137
|
-
|
|
138
|
-
The formula that settles every sign argument: `screenRight = cross(cameraForward, worldUp)`.
|
|
139
|
-
For a Y-up world and forward `(sin yaw, 0, cos yaw)`, screen-right is
|
|
140
|
-
`(-cos yaw, 0, sin yaw)`. **Warning — `(cos yaw, 0, -sin yaw)` is the LEFT
|
|
141
|
-
vector** (that's `cross(worldUp, cameraForward)`), and writing it as "right" is
|
|
142
|
-
the single most-shipped direction bug in generated games: two independent
|
|
143
|
-
projects inverted their A/D exactly this way. Related trap: positive
|
|
144
|
-
`rotation.y` turns a +Z-facing object toward +X, which is screen-LEFT from a
|
|
145
|
-
chase camera behind it — so "positive yaw = turn right" is false in this basis.
|
|
146
|
-
|
|
147
|
-
Never derive signs by intuition — intuition about right-handed frames is wrong
|
|
148
|
-
about half the time and has been wrong in every shipped instance. Copy a
|
|
149
|
-
verified pair (sign AND basis together) from
|
|
150
|
-
[references/camera-rigs.md](references/camera-rigs.md), then confirm with the
|
|
151
|
-
input-direction part of the smoke check: hold D and watch which way the world
|
|
152
|
-
answers.
|
|
153
|
-
|
|
154
116
|
## Non-negotiable rules
|
|
155
117
|
|
|
156
118
|
- Use subject dimensions to derive offsets; do not tune one fixed distance for
|
|
@@ -160,8 +122,6 @@ answers.
|
|
|
160
122
|
- During an explicit handoff, use one interpolation stage. Do not stack a
|
|
161
123
|
transition blend and a second follow smoother over the same interval.
|
|
162
124
|
- Re-sync yaw/pitch from the camera when pointer lock is acquired.
|
|
163
|
-
- Hand-rolled steering/pan/look math copies a verified basis from the reference
|
|
164
|
-
and passes the input-direction check — signs are never derived by intuition.
|
|
165
125
|
- Update the projection matrix whenever FOV, near, far, or aspect changes.
|
|
166
126
|
- Keep stars or infinite backgrounds camera-relative when large translation
|
|
167
127
|
would create false parallax or precision loss.
|
|
@@ -11,7 +11,6 @@ Use this reference for scale-aware chase, side, orbit, authored-shot, pointer-lo
|
|
|
11
11
|
- Explicit camera handoffs
|
|
12
12
|
- cinematic implementation shot ownership
|
|
13
13
|
- Pointer-look and movement constraints
|
|
14
|
-
- Verified screen-direction bases
|
|
15
14
|
- Floating origin and background handling
|
|
16
15
|
- Projection and lifecycle ownership
|
|
17
16
|
- Failure modes and diagnostics
|
|
@@ -167,9 +166,6 @@ yaw -= mouseDeltaX * 0.0022
|
|
|
167
166
|
pitch -= mouseDeltaY * 0.0018
|
|
168
167
|
```
|
|
169
168
|
|
|
170
|
-
Expected on screen: mouse-right orbits the view right, mouse-up tilts it up —
|
|
171
|
-
verify both axes against the screen-direction contract before retuning the scales.
|
|
172
|
-
|
|
173
169
|
Pitch bounds vary by flight mode. The implementation also enforces camera height above
|
|
174
170
|
the ship:
|
|
175
171
|
|
|
@@ -285,9 +281,6 @@ distance = movementSpeed * dt
|
|
|
285
281
|
|
|
286
282
|
Default speed is `9`, sensitivity `0.0023`.
|
|
287
283
|
|
|
288
|
-
Expected on screen: mouse-right turns the view right, mouse-up looks up — assert
|
|
289
|
-
both axes (yaw-only evidence has let inverted pitch ship).
|
|
290
|
-
|
|
291
284
|
Keys are cleared on:
|
|
292
285
|
|
|
293
286
|
- pointer-lock exit;
|
|
@@ -302,61 +295,6 @@ Scene-specific constraints then run after controls:
|
|
|
302
295
|
|
|
303
296
|
Input control and spatial constraint are separate layers.
|
|
304
297
|
|
|
305
|
-
## Verified screen-direction bases
|
|
306
|
-
|
|
307
|
-
Copy these pairs whole — the sign and the basis are only correct TOGETHER. Each
|
|
308
|
-
was derived from `screenRight = cross(cameraForward, worldUp)` and verified
|
|
309
|
-
against the on-screen result; if you change one half, re-verify with the
|
|
310
|
-
input-direction check instead of reasoning about it.
|
|
311
|
-
|
|
312
|
-
**Chase-cam steering** (vehicle/character heading, camera behind):
|
|
313
|
-
|
|
314
|
-
```text
|
|
315
|
-
heading = (sin yaw, 0, cos yaw) // matches rotation.y for a +Z-front model
|
|
316
|
-
yaw -= steer * rate * dt // steer: D/right = +1, A/left = -1
|
|
317
|
-
position += heading * speed * dt
|
|
318
|
-
camera at position - heading * dist, lookAt(position)
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
Why the minus: the camera looks along `heading`, so screen-right is
|
|
322
|
-
`cross(heading, up) = (-cos yaw, 0, sin yaw)`, while `d(heading)/d(yaw) =
|
|
323
|
-
(cos yaw, 0, -sin yaw)` — exactly screen-LEFT. Increasing yaw always veers the
|
|
324
|
-
nose left on screen, so "D turns right" needs `yaw -=`. (Equivalently
|
|
325
|
-
`yaw += steer` is correct only with heading `(-sin yaw, 0, cos yaw)` — a pair,
|
|
326
|
-
never a lone sign.)
|
|
327
|
-
|
|
328
|
-
**RTS / overhead pan camera** (fixed pitch, yaw-orbiting):
|
|
329
|
-
|
|
330
|
-
```text
|
|
331
|
-
right = (-cos yaw, 0, sin yaw) // pitch-independent screen-right on the ground
|
|
332
|
-
forwardGround = (sin yaw, 0, cos yaw) // into the screen along the ground
|
|
333
|
-
D / ArrowRight: target += right * pan A / ArrowLeft: target -= right * pan
|
|
334
|
-
W / ArrowUp: target += forwardGround * pan S: target -= forwardGround * pan
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
Drag-pan, grab-the-world (terrain follows the pointer; both axes, one
|
|
338
|
-
convention — `movementY` is positive DOWNWARD):
|
|
339
|
-
|
|
340
|
-
```text
|
|
341
|
-
target -= right * movementX * k
|
|
342
|
-
target += forwardGround * movementY * k
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
Move-the-camera convention = flip BOTH signs, never one. The classic shipped bug
|
|
346
|
-
writes `right = (cos yaw, 0, -sin yaw)` — that is `cross(up, forward)`, the LEFT
|
|
347
|
-
vector — inverting A/D and the horizontal drag while W/S stay correct.
|
|
348
|
-
|
|
349
|
-
**Pointer-look** (locked mouse driving yaw/pitch, Euler order `YXZ`):
|
|
350
|
-
|
|
351
|
-
```text
|
|
352
|
-
yaw -= movementX * sensitivity // mouse-right -> view turns RIGHT
|
|
353
|
-
pitch -= movementY * sensitivity // mouse-up -> view tilts UP
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
Expected on screen, both axes, before any tuning: a straight-ahead landmark
|
|
357
|
-
slides LEFT when the mouse moves right (the view pans right) and slides DOWN
|
|
358
|
-
when the mouse moves up (the view tilts up).
|
|
359
|
-
|
|
360
298
|
## Floating origin and background handling
|
|
361
299
|
|
|
362
300
|
The Saturn scene first computes a virtual camera pose, stores its orientation
|
|
@@ -162,10 +162,7 @@ From `@genex-ai/embed-sdk/sentry` (crash reporting; exactly these two):
|
|
|
162
162
|
- `sentryCanvasSnapshot(canvas)` — session replay records the DOM, not the 3D
|
|
163
163
|
canvas; call this once per frame at the END of the render loop so replays
|
|
164
164
|
show actual gameplay. Works for BOTH WebGL and WebGPU renderers; internally
|
|
165
|
-
throttled, so calling at 60fps is fine
|
|
166
|
-
no-op (and session replay/tracing sample down): each capture is a full-canvas
|
|
167
|
-
GPU readback, exactly the overhead phones get memory-killed for — mobile
|
|
168
|
-
replays are DOM-only by design, on-error replays still record everywhere:
|
|
165
|
+
throttled, so calling at 60fps is fine:
|
|
169
166
|
|
|
170
167
|
```ts
|
|
171
168
|
function animate() {
|
|
@@ -37,10 +37,7 @@ no matter how good it looks.
|
|
|
37
37
|
unlocked drag-to-turn camera feels imprecise no matter how tight the numbers
|
|
38
38
|
are. The bucket rule + the bundled `FollowCamera` aim mode live in
|
|
39
39
|
`$genex-threejs-camera-direction`; on the bundled controller it's ON by default
|
|
40
|
-
(with a ready-made cue), not hand-rolled events.
|
|
41
|
-
movement key or look axis whose on-screen direction contradicts its label is a
|
|
42
|
-
defect, not a tuning issue — the screen-direction contract and verified bases
|
|
43
|
-
are in `$genex-threejs-camera-direction`.
|
|
40
|
+
(with a ready-made cue), not hand-rolled events.
|
|
44
41
|
|
|
45
42
|
## Movement: snappy beats realistic
|
|
46
43
|
|
|
@@ -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 |
|
|
30
|
+
| Settings | when there is anything 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
|
|
|
@@ -79,40 +79,25 @@ lap counter in a game without laps). `--aspect 16:9 --quality high
|
|
|
79
79
|
--no-wait`, enqueued FIRST of all art; the URL goes into the style-brief
|
|
80
80
|
comment.
|
|
81
81
|
|
|
82
|
-
**Share it
|
|
83
|
-
When the concept lands,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
question that parks the art pipeline is how a finished game ships bare walls
|
|
96
|
-
and a placeholder HUD — strictly worse than re-rolling a few assets later.
|
|
97
|
-
**Feedback triggers a LOOP whenever it arrives:** if the user comes back
|
|
98
|
-
disliking ANYTHING — immediately or an hour later — regenerate with their
|
|
99
|
-
exact notes (`--candidates 2–3` gives them options to choose from), open +
|
|
100
|
-
link the new frame, and ask again the same non-blocking way. Carry every note
|
|
82
|
+
**Share it before building on it — actually SHOW the image, don't just ask.**
|
|
83
|
+
When the concept lands, pick it up with `genex wait <id> --open` (or generate it
|
|
84
|
+
with `--open`): it opens in the user's browser AND prints the link. Paste that
|
|
85
|
+
URL as a clickable link in your approval message — a URL is invisible in a
|
|
86
|
+
terminal, and "do you like it?" with no picture in front of the user is the #1
|
|
87
|
+
way this checkpoint fails (they end up digging logs for the file path). Then ask
|
|
88
|
+
ONE structured question — "this is roughly how the game will look: keep it, or
|
|
89
|
+
change something?" — with 2–3 concrete adjustment options. Keep building
|
|
90
|
+
gameplay-neutral work (scaffold, physics, netcode) while waiting, but do NOT
|
|
91
|
+
anchor further art to an unapproved frame. **Approval is a LOOP, not a
|
|
92
|
+
one-shot:** if the user dislikes ANYTHING, regenerate with their exact notes
|
|
93
|
+
(`--candidates 2–3` gives them options to choose from), open + link the new
|
|
94
|
+
frame, and ask again — repeat until they actually approve. Carry every note
|
|
101
95
|
forward so each round compounds; if two rounds don't converge, offer 2–3
|
|
102
|
-
distinct directions instead of re-rolling blind
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
the
|
|
107
|
-
the old frame: the menu still is re-edited (`--edit`) against the new frame
|
|
108
|
-
and its video re-run once from the new still (`$genex-ai-menu` — a
|
|
109
|
-
user-driven style change re-opens its one-video rule), and the HUD chrome
|
|
110
|
-
re-runs its pipeline from Stage 1 with the new frame as the `--edit` anchor
|
|
111
|
-
(`$genex-ai-hud` — budget the full serial chain; it is the most expensive
|
|
112
|
-
re-anchor in the set). Style-neutral assets (most textures, sfx, models)
|
|
113
|
-
usually survive — judge each in one line. The same "open it + paste the
|
|
114
|
-
link" rule covers every image the user weighs in on — the menu still, the
|
|
115
|
-
HUD mockup candidates.
|
|
96
|
+
distinct directions as a structured question instead of re-rolling blind. The
|
|
97
|
+
HUD mockup, the menu, and every downstream asset wait for a frame the user has
|
|
98
|
+
signed off — a single "meh" is never permission to move on. The same "open it +
|
|
99
|
+
paste the link" rule covers every image the user weighs in on — the menu still,
|
|
100
|
+
the HUD mockup candidates.
|
|
116
101
|
|
|
117
102
|
**The concept anchors STYLE, not truth.** Palette, materials, light, and
|
|
118
103
|
register come from the frame; CONTENT comes from the game contract. When
|
|
@@ -265,15 +250,8 @@ document.addEventListener("keydown", (e) => {
|
|
|
265
250
|
so ALSO keep the pointer-lock-loss → pause path (`pointerlockchange`: if
|
|
266
251
|
unlocked while `playing`, `setPhase("paused")`). Escape then always pauses; it
|
|
267
252
|
only *also* drops fullscreen on browsers without the lock — unavoidable there.
|
|
268
|
-
- **
|
|
269
|
-
|
|
270
|
-
`enterImmersive` and Keyboard Lock entirely. But ANY game that locks the
|
|
271
|
-
pointer during play — aim games AND keyboard-only racers/platformers/runners
|
|
272
|
-
under the lock-or-tool rule (next section) — keeps the Escape → pause path and
|
|
273
|
-
the `pointerlockchange` fallback (if unlocked while `playing`, pause): without
|
|
274
|
-
it, Esc frees the cursor while the game keeps running. Keyboard-only games may
|
|
275
|
-
still skip Keyboard Lock + fullscreen; the lock + pause/resume path is the
|
|
276
|
-
non-negotiable part.
|
|
253
|
+
- **Only for immersive/pointer-lock games.** A top-down or menu-driven game never
|
|
254
|
+
captures the mouse and has no window to shrink — skip all of this.
|
|
277
255
|
- **Dashboard embed:** no setup needed — the platform's game frame grants keyboard
|
|
278
256
|
lock (and pointer lock + fullscreen), so Escape-to-pause works the same inside
|
|
279
257
|
`/world/` + `/draft/` as it does standalone (`<slug>.genex.technology`).
|
|
@@ -283,28 +261,6 @@ menu — trackpads feel slower than mice, so let the player tune it. On the bund
|
|
|
283
261
|
camera the setter is live: `slider.oninput = () => { followCam.aimSensitivity = +slider.value; };`
|
|
284
262
|
(radians per pixel; default `0.0023`, a usable range is ~`0.0008`–`0.005`).
|
|
285
263
|
|
|
286
|
-
## The cursor during play: locked or a tool
|
|
287
|
-
|
|
288
|
-
During play the OS cursor is either the gameplay tool (cursor-core: click-to-move,
|
|
289
|
-
tower defense, builders, card/board — it stays visible, that's correct) or it is
|
|
290
|
-
**locked away — including keyboard-only games** (racer, platformer, runner): an
|
|
291
|
-
arrow parked over the action for the whole session is a shipped defect. Games on
|
|
292
|
-
the bundled `FollowCamera` get the lock free (on by default). A hand-rolled game
|
|
293
|
-
locks with ~6 lines, reusing this section's Escape flow:
|
|
294
|
-
|
|
295
|
-
```ts
|
|
296
|
-
// In the Play/Start/Resume CLICK handler (lock needs a user gesture):
|
|
297
|
-
canvas.requestPointerLock?.(); // hides the cursor, focuses the game
|
|
298
|
-
// Already in the Escape recipe above: pointerlockchange → if unlocked while
|
|
299
|
-
// playing, pause; the Resume click re-locks. Keyboard games need nothing more —
|
|
300
|
-
// no reticle, no aim code; the lock just parks the cursor.
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
If the lock is genuinely unavailable (a third-party embed without
|
|
304
|
-
`allow="pointer-lock"`), fall back to hiding the idle cursor over the canvas:
|
|
305
|
-
`canvas.style.cursor = "none"` after ~2s without `pointermove`, restored
|
|
306
|
-
instantly on move. Menus and pause screens always keep their cursor.
|
|
307
|
-
|
|
308
264
|
## The loader
|
|
309
265
|
|
|
310
266
|
The loader is the first thing every player sees — a bare "Loading… 3/5" over
|
|
@@ -406,16 +362,6 @@ Order the HUD by what the player loses the game for ignoring:
|
|
|
406
362
|
- **Contrast against the real scene.** Test text over the brightest AND
|
|
407
363
|
darkest areas of actual gameplay; a soft dark plate or text-shadow beats
|
|
408
364
|
restyling per level.
|
|
409
|
-
- **Panel and button corners come from `border-radius`, not a CSS clip.**
|
|
410
|
-
Don't chamfer, notch, or slice corners with `clip-path: polygon(...)` or a
|
|
411
|
-
`mask` for a "hi-tech" look: a raw CSS clip hard-cuts the box, so it shears
|
|
412
|
-
off whatever sits near the corner (text, padding, the focus ring, a glow)
|
|
413
|
-
and leaves a jagged aliased diagonal that reads as *broken*, not as a
|
|
414
|
-
designed bevel. Soft corners are `border-radius`; a genuinely angular or
|
|
415
|
-
ornamented frame is a generated frame sprite (`$genex-ai-hud` chrome, or a
|
|
416
|
-
Tier-3 9-slice panel), never hand-cut in CSS. This governs decorative
|
|
417
|
-
panel/button **shape** only — it does not touch the masked-fill HUD reveal
|
|
418
|
-
or `genex ui` masks, which are the correct uses of `mask`/`clip-path`.
|
|
419
365
|
- **One cohesion layer.** A single full-screen vignette div (a subtle radial
|
|
420
366
|
gradient darkening the corners, optionally faint grain) over canvas + UI is
|
|
421
367
|
the cheapest way to make DOM-over-WebGL read as one composed image instead
|
|
@@ -426,13 +372,11 @@ Order the HUD by what the player loses the game for ignoring:
|
|
|
426
372
|
`vUv` grain shimmers.
|
|
427
373
|
- **Desktop first.** Verify at desktop sizes and survive window resizes
|
|
428
374
|
without clipping; don't design phone layouts or test mobile viewports unless
|
|
429
|
-
the user asks.
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
the adaptive-quality tier at boot (`$genex-threejs-adaptive-quality`), which
|
|
435
|
-
keeps the shared link from being a dead OR crashing link on a phone.
|
|
375
|
+
the user asks. Exception: touch *input* is wired by default when a recipe
|
|
376
|
+
fits — a bundled controller's built-in touch controls, or the touch kit +
|
|
377
|
+
recipes in `$genex-threejs-touch-controls` — behind
|
|
378
|
+
`navigator.maxTouchPoints > 0`, invisible on desktop, so the shared link
|
|
379
|
+
isn't dead on a phone (skipping needs a one-line reason, not silence).
|
|
436
380
|
|
|
437
381
|
## Wire UI to game state, never the reverse
|
|
438
382
|
|
|
@@ -455,9 +399,6 @@ architecture and consume the shared style brief.
|
|
|
455
399
|
- HUD sprites never enqueued at the gate — the placeholder CSS shipped as the
|
|
456
400
|
final HUD.
|
|
457
401
|
- No pause screen, or a pause that isn't bound to Escape.
|
|
458
|
-
- The OS arrow parked over the action for the whole session in a keyboard-driven
|
|
459
|
-
game (the cursor is either a gameplay tool or locked away — see the cursor
|
|
460
|
-
section).
|
|
461
402
|
- A style brief whose fonts were never actually loaded (a system-stack display
|
|
462
403
|
font at runtime).
|
|
463
404
|
- A micro-element (reticle, cue, toast, damage number) left as default CSS
|
|
@@ -467,11 +408,6 @@ architecture and consume the shared style brief.
|
|
|
467
408
|
- Hard-cut phase swaps, a menu whose elements just appear, numbers that
|
|
468
409
|
teleport.
|
|
469
410
|
- A silent menu; a bare "Loading…" over black.
|
|
470
|
-
- The art pipeline parked on an unanswered look question — the question is
|
|
471
|
-
advisory: queue Tier-2 + the asset set against the shown frame and keep
|
|
472
|
-
moving; silence is acceptance.
|
|
473
|
-
- Panel or button corners chamfered/notched with `clip-path`/`mask` instead of
|
|
474
|
-
`border-radius` — the corner looks sheared off, not designed.
|
|
475
411
|
- UI panels covering the player or the thing about to kill them.
|
|
476
412
|
- Layout shifting as numbers grow.
|
|
477
413
|
- A fail state with no visible restart key, or a restart that reloads the page.
|
|
@@ -10,8 +10,7 @@ says what it's made of in THIS game.
|
|
|
10
10
|
|
|
11
11
|
Every capsule below assumes the base rules from the skill: corners/edges for
|
|
12
12
|
UI, one display + one body font, tabular numerals, contrast plates over
|
|
13
|
-
arbitrary scenes
|
|
14
|
-
frame — never a raw CSS `clip-path`/`mask` chamfer.
|
|
13
|
+
arbitrary scenes.
|
|
15
14
|
|
|
16
15
|
## Fantasy / action RPG
|
|
17
16
|
|
|
@@ -43,11 +43,6 @@ ownership boundaries between whole-scene and effect-local graphs.
|
|
|
43
43
|
- Build pass toggles and effect-only views before tuning.
|
|
44
44
|
- UI rendered in the same target needs an explicit protection strategy.
|
|
45
45
|
- Do not load all atomic post skills by default. Route only the effects actually requested.
|
|
46
|
-
- Budget the pipeline per device tier (`$genex-threejs-adaptive-quality`):
|
|
47
|
-
phone pixel budget ≈ 1,000,000 px at DPR ≤ 1.25–1.5, desktop ≈ 1,650,000 px —
|
|
48
|
-
every full-res pass target multiplies that cost, so phone tiers run the light
|
|
49
|
-
post level and per-pass resolution scales (0.4–0.5 DPR blurs) are the norm,
|
|
50
|
-
not an optimization.
|
|
51
46
|
|
|
52
47
|
## Routing boundary
|
|
53
48
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Use this reference to compose shared scene buffers, lighting effects, atmosphere, bloom, exposure, tone mapping, grading, and feature-local render targets with explicit ownership.
|
|
4
4
|
|
|
5
|
-
> **Renderer note:** this reference assumes `WebGPURenderer` + TSL node materials. Check the project's actual renderer first — the Genex scaffold ships vanilla WebGL three.js. On WebGL, adapt the technique with standard materials / `EffectComposer` passes or pick a simpler alternative; never switch renderers mid-project.
|
|
5
|
+
> **Renderer note:** this reference assumes `WebGPURenderer` + TSL node materials. Check the project's actual renderer first — the Genex scaffold ships vanilla WebGL three.js. On WebGL, adapt the technique with standard materials / `EffectComposer` passes or pick a simpler alternative; never switch renderers mid-project.
|
|
6
6
|
|
|
7
7
|
## Contents
|
|
8
8
|
|
|
@@ -107,11 +107,7 @@ kill-switch diagnostic.
|
|
|
107
107
|
whole rig after a tone-mapping change is self-inflicted.
|
|
108
108
|
- Never repair unbalanced light ratios with exposure — fix the lights.
|
|
109
109
|
- Flicker from elapsed time, never per-frame randomness.
|
|
110
|
-
- Dispose lights and their shadow maps with the level that spawned them
|
|
111
|
-
the rest of the level with them: traverse the outgoing scene and dispose
|
|
112
|
-
geometry, materials, AND textures separately (three frees nothing; material
|
|
113
|
-
dispose does not touch textures). Leaked levels march phones toward the
|
|
114
|
-
OS memory kill — `$genex-threejs-adaptive-quality` owns the budget watch.
|
|
110
|
+
- Dispose lights and their shadow maps with the level that spawned them.
|
|
115
111
|
- The rig must read with post off: time of day and where-to-go, before bloom.
|
|
116
112
|
|
|
117
113
|
## Routing boundary
|
|
@@ -536,13 +536,7 @@ fights (many writers). A ball on `objects` glides and has one owner. That's the
|
|
|
536
536
|
`stateRaw` is the raw latest (hit-tests, discrete values). A reconnect-grace seat remains in this
|
|
537
537
|
map with `connected: false`. `avatarUrl` is that player's verified VRM pick (server-set, `''`
|
|
538
538
|
when unknown) — in a VRM-lane game render each remote with
|
|
539
|
-
`
|
|
540
|
-
N remotes share one set of geometry/textures instead of re-parsing per player — retarget
|
|
541
|
-
clips once on `loadVrmClone.base(url)` and play them on each clone's own mixer); never
|
|
542
|
-
publish avatar URLs through `me.set`. On phone tiers, animate and fully draw only the
|
|
543
|
-
nearest `tier.remoteAvatarCap` remotes (`$genex-threejs-adaptive-quality`) — freeze the
|
|
544
|
-
mixer and billboard or hide the rest; a room allows up to 64 players and 64 live avatars
|
|
545
|
-
is a real phone memory kill on its own.
|
|
539
|
+
`loadVrm(p.avatarUrl || "./assets/avatar.vrm")`; never publish avatar URLs through `me.set`.
|
|
546
540
|
- `room.activePlayers` — the connected-only subset of `room.players`; use its size for live quorum.
|
|
547
541
|
- `room.objects` — shared objects nobody owns until claimed (a ball, an NPC):
|
|
548
542
|
- `claim(id)` — **legacy** optimistic request. It flips local ownership immediately and is corrected
|
|
@@ -275,12 +275,9 @@ room.me.set({
|
|
|
275
275
|
|
|
276
276
|
// Remote players: a VISUAL-ONLY avatar — NO Rapier body, NO controller instance for remotes.
|
|
277
277
|
// Build each remote's visual from THEIR OWN model: in a VRM-lane game that is
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
//
|
|
281
|
-
// them) — retarget clips once against loadVrmClone.base(url).vrm and drive each clone's own
|
|
282
|
-
// AnimationMixer. Never reuse your own avatar OBJECT for a remote (clones, not references).
|
|
283
|
-
// Phone tiers animate only the nearest tier.remoteAvatarCap remotes (adaptive-quality skill). Position/rotation from smoothed state; animation from the
|
|
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
|
|
284
281
|
// synced flags via the avatar's own update(flags, dt). The character-controller skill's
|
|
285
282
|
// animations reference owns the flag set.
|
|
286
283
|
const pl = room.players.get(id)!;
|
|
@@ -26,7 +26,6 @@ already resolved — constructing a collider before WASM init throws.
|
|
|
26
26
|
| tall dynamic props, posts | `capsuleCollider` / `cylinderCollider` | stable standing shapes |
|
|
27
27
|
| pickups, triggers, zones | any shape + `{ sensor: true, mass: 0 }` | overlap events, no contact forces |
|
|
28
28
|
| the player, cars, drones | none of the above — `npx genex controller` | controllers own their collider recipes |
|
|
29
|
-
| any prop on a PHONE tier (`$genex-threejs-adaptive-quality`) | prefer `cuboidCollider`/hull over trimesh | trimesh contacts scale with triangle count — a phone CPU/memory tax; keep trimesh for static level geometry only |
|
|
30
29
|
|
|
31
30
|
## Explicit primitive helpers
|
|
32
31
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Use this reference for a bounded-cost WebGPU/TSL ambient-visibility pass with half-resolution horizon integration, bent normals, bilateral reconstruction, and directional ambient tint.
|
|
4
4
|
|
|
5
|
-
> **Renderer note:** this reference assumes `WebGPURenderer` + TSL node materials. Check the project's actual renderer first — the Genex scaffold ships vanilla WebGL three.js. On WebGL, adapt the technique with standard materials / `EffectComposer` passes or pick a simpler alternative; never switch renderers mid-project.
|
|
5
|
+
> **Renderer note:** this reference assumes `WebGPURenderer` + TSL node materials. Check the project's actual renderer first — the Genex scaffold ships vanilla WebGL three.js. On WebGL, adapt the technique with standard materials / `EffectComposer` passes or pick a simpler alternative; never switch renderers mid-project.
|
|
6
6
|
|
|
7
7
|
## Contents
|
|
8
8
|
|
|
@@ -12,12 +12,6 @@ and shadows shimmer, swim, or run out of coverage.
|
|
|
12
12
|
|
|
13
13
|
Use a single shadow map only when its receiver region is genuinely bounded. For large moving views, make shadow coverage an explicit spatial hierarchy.
|
|
14
14
|
|
|
15
|
-
**Phone budgets ride the quality tier** (`$genex-threejs-adaptive-quality`):
|
|
16
|
-
shadow maps ≤1024² on phones (512² on the low tier — a 4096² map alone is
|
|
17
|
-
~67 MB of the phone's whole GPU budget), at most 2 cascades where desktop runs
|
|
18
|
-
4, and `shadowMap.autoUpdate = false` for static scenes (re-render on demand:
|
|
19
|
-
a shadow pass is a full extra scene render every frame otherwise).
|
|
20
|
-
|
|
21
15
|
## Cached clipmap workflow
|
|
22
16
|
|
|
23
17
|
1. Define concentric light-space square levels.
|