@genex-ai/cli-demo 0.78.1-dev.203 → 0.80.2-dev.213
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 +12 -5
- package/package.json +1 -1
- package/templates/README.md +1 -1
- package/templates/controllers/character/character-controller.ts +97 -0
- package/templates/skills/genex-ai-character/SKILL.md +2 -4
- package/templates/skills/genex-ai-hud/SKILL.md +46 -19
- package/templates/skills/genex-ai-menu/SKILL.md +13 -10
- package/templates/skills/genex-ai-model/SKILL.md +12 -6
- package/templates/skills/genex-game-director/SKILL.md +265 -0
- package/templates/skills/genex-game-director/references/design-contract.md +148 -0
- package/templates/skills/{genex-threejs-skill-router → genex-game-director}/references/routing-map.md +70 -67
- package/templates/skills/genex-getting-started/SKILL.md +3 -2
- package/templates/skills/genex-threejs-adaptive-quality/SKILL.md +9 -7
- package/templates/skills/genex-threejs-character-controller/SKILL.md +12 -9
- package/templates/skills/genex-threejs-embed-auth/SKILL.md +6 -48
- package/templates/skills/genex-threejs-game-content/SKILL.md +3 -4
- package/templates/skills/genex-threejs-game-ui/SKILL.md +23 -57
- package/templates/skills/genex-threejs-game-ui/references/style-capsules.md +7 -4
- package/templates/skills/genex-threejs-multiplayer/SKILL.md +7 -2
- package/templates/skills/genex-threejs-visual-validation/SKILL.md +2 -4
- package/templates/skills/genex-threejs-skill-router/SKILL.md +0 -266
|
@@ -128,15 +128,17 @@ const gltfLoader = createGltfLoader(renderer); // meshopt always; KTX2 when the
|
|
|
128
128
|
const gltf = await loadModelWithFallback(
|
|
129
129
|
MODEL_URL, tier, (u) => gltfLoader.loader.loadAsync(u), { ktx2: gltfLoader.ktx2 },
|
|
130
130
|
);
|
|
131
|
-
// Provider PBR ships mirror-metal (metalness~1
|
|
132
|
-
// swims with camera motion
|
|
131
|
+
// Provider PBR sometimes ships mirror-metal (metalness~1 + near-zero roughness)
|
|
132
|
+
// that reflects the sky env and swims with camera motion. Tame ONLY that extreme
|
|
133
|
+
// — do NOT flatten every material to 0.6 (it dulls legitimately metallic props):
|
|
133
134
|
gltf.scene.traverse((o) => {
|
|
134
135
|
const m = (o as THREE.Mesh).material as THREE.MeshStandardMaterial;
|
|
135
|
-
if (m?.isMeshStandardMaterial)
|
|
136
|
-
|
|
137
|
-
m.
|
|
138
|
-
m.
|
|
136
|
+
if (!m?.isMeshStandardMaterial) return;
|
|
137
|
+
if (m.metalness > 0.85 && m.roughness < 0.2) {
|
|
138
|
+
m.metalness = 0.7;
|
|
139
|
+
m.roughness = Math.max(m.roughness, 0.3);
|
|
139
140
|
}
|
|
141
|
+
m.envMapIntensity = Math.min(m.envMapIntensity, 0.8);
|
|
140
142
|
});
|
|
141
143
|
```
|
|
142
144
|
|
|
@@ -162,7 +164,7 @@ not the player's account. Default Auto.
|
|
|
162
164
|
at most 2 cascades on phones (`$genex-threejs-shadow-systems`).
|
|
163
165
|
- Post: phone floor is a BUILT tone-mapping/output pass (`postLevel: 'light'`
|
|
164
166
|
adds FXAA/vignette); SSAO, volumetrics, and DoF are desktop-tier only
|
|
165
|
-
(`$genex-
|
|
167
|
+
(`$genex-game-director`'s routing map owns the floor wording).
|
|
166
168
|
- Particles/scatter: multiply counts by `tier.particleScale`; render heavy
|
|
167
169
|
transparency at half resolution and upsample.
|
|
168
170
|
- Animation: distant mixers update at 1/2–1/4 rate; multiplayer remotes above
|
|
@@ -57,10 +57,8 @@ Meshy Image-to-3D first produces an unremeshed high-detail model. Show its
|
|
|
57
57
|
front, back, left, and right views and report its measured face count. Preserve
|
|
58
58
|
that model in R2. Before rigging, ask the user to approve a separate
|
|
59
59
|
10,000-face triangle remesh. The 10k remesh—not the high-detail source—is
|
|
60
|
-
rigged and animated. (For these approvals, use your
|
|
61
|
-
|
|
62
|
-
`request_user_input`; if it has none, e.g. Cursor, a short numbered list in
|
|
63
|
-
chat.)
|
|
60
|
+
rigged and animated. (For these approvals, use your question tool when you
|
|
61
|
+
have one; if you have none, a short numbered list in chat.)
|
|
64
62
|
|
|
65
63
|
That is a separate, **same-rig Meshy-native lane**. Its animation-only GLBs are
|
|
66
64
|
accepted only when their skeleton signature matches the active character
|
|
@@ -320,11 +318,16 @@ it. Simulating remote players' physics locally guarantees divergence — every
|
|
|
320
318
|
client would compute a different world. Never render every remote with your
|
|
321
319
|
own avatar file: players picked their looks, show them.
|
|
322
320
|
|
|
323
|
-
- Publish
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
`
|
|
327
|
-
|
|
321
|
+
- **Publish `character.netState()`** on the fixed 10–20 Hz tick (never per frame):
|
|
322
|
+
`room.me.set(character.netState())`. It bundles the network-safe position, a four-number
|
|
323
|
+
quaternion, and the six animation booleans in one call. It uses `netPos`, **not** `currPos` —
|
|
324
|
+
`currPos` is the raw physics capsule whose Y bobs on the float-suspension spring, so publishing
|
|
325
|
+
it makes a *standing* remote player visibly bob up and down. `netState()` snaps the grounded Y to
|
|
326
|
+
the settled height (raw while airborne, so jumps still arc). Never reduce rotation to a scalar yaw.
|
|
327
|
+
- On each remote, apply the SDK's **smoothed** copy with
|
|
328
|
+
`applyNetState(remoteObject, players.get(id).state)` (sets position + rotation), and feed the same
|
|
329
|
+
six booleans (`onGround`, `falling`, `moving`, `running`, `jumping`, `crouching`) to that remote's
|
|
330
|
+
`CharacterAnimations` — see the animations reference. Never publish `currPos` directly.
|
|
328
331
|
- Only the owning client runs `MotionActionDriver`. Remotes play the same
|
|
329
332
|
one-shot event while following smoothed owner-authored position/rotation;
|
|
330
333
|
their animation mixer never moves them through the world.
|
|
@@ -34,26 +34,19 @@ Guest sessions have **no** overlay — the game just plays.
|
|
|
34
34
|
## Install
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
npm i @genex-ai/embed-sdk
|
|
37
|
+
npm i @genex-ai/embed-sdk
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
(
|
|
41
|
-
|
|
42
|
-
installed if you followed Step 3 of the scaffold; repeated here so this skill
|
|
43
|
-
is self-contained.)
|
|
40
|
+
(Already installed if you followed Step 3 of the scaffold; repeated here so
|
|
41
|
+
this skill is self-contained.)
|
|
44
42
|
|
|
45
43
|
## Bootstrap (required, every game)
|
|
46
44
|
|
|
47
45
|
```ts
|
|
48
|
-
// main.ts — the FIRST
|
|
49
|
-
import { initGameSentry } from "@genex-ai/embed-sdk/sentry";
|
|
46
|
+
// main.ts — the FIRST thing in the boot sequence, before any other game code
|
|
50
47
|
import { initEmbed } from "@genex-ai/embed-sdk";
|
|
51
48
|
import { GENEX } from "./genex.config";
|
|
52
49
|
|
|
53
|
-
// Crash reporting + session replay FIRST — so even a failure inside the auth
|
|
54
|
-
// boot below gets reported. One required field; never pass tokens to it.
|
|
55
|
-
initGameSentry({ slug: GENEX.slug });
|
|
56
|
-
|
|
57
50
|
initEmbed({
|
|
58
51
|
slug: GENEX.slug,
|
|
59
52
|
apiUrl: GENEX.apiUrl,
|
|
@@ -153,29 +146,6 @@ Server write limits (per player, per minute): **60 player-saves, 120
|
|
|
153
146
|
world-saves, 30 score submits**. A debounced ~1/sec checkpoint never gets near
|
|
154
147
|
them — only a save-per-frame loop does (it surfaces as HTTP 429).
|
|
155
148
|
|
|
156
|
-
From `@genex-ai/embed-sdk/sentry` (crash reporting; exactly these two):
|
|
157
|
-
|
|
158
|
-
- `initGameSentry({ slug, dsn?, environment? })` — call once, BEFORE
|
|
159
|
-
`initEmbed()`. Only `slug` is required; the shared Genex Sentry project DSN
|
|
160
|
-
is built in. Errors, tracing, and session replay all start here; the current
|
|
161
|
-
player (account or guest) is attached automatically (no code needed).
|
|
162
|
-
- `sentryCanvasSnapshot(canvas)` — session replay records the DOM, not the 3D
|
|
163
|
-
canvas; call this once per frame at the END of the render loop so replays
|
|
164
|
-
show actual gameplay. Works for BOTH WebGL and WebGPU renderers; internally
|
|
165
|
-
throttled, so calling at 60fps is fine. On TOUCH devices it is a deliberate
|
|
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:
|
|
169
|
-
|
|
170
|
-
```ts
|
|
171
|
-
function animate() {
|
|
172
|
-
requestAnimationFrame(animate);
|
|
173
|
-
// ...game update...
|
|
174
|
-
renderer.render(scene, camera);
|
|
175
|
-
sentryCanvasSnapshot(renderer.domElement); // AFTER render, same frame
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
149
|
## Saving progress (per-player — every player has their own slot)
|
|
180
150
|
|
|
181
151
|
Use the SDK helpers; never hand-roll fetch calls to the state API. Progression,
|
|
@@ -224,16 +194,6 @@ their Genex account) and keep-best — submitting a worse score changes nothing
|
|
|
224
194
|
post when they sign in. Send a consistent `mode` per board. Scores are
|
|
225
195
|
client-reported (arcade-style trust) — don't present them as anti-cheat.
|
|
226
196
|
|
|
227
|
-
## Crash reporting rules
|
|
228
|
-
|
|
229
|
-
- `initGameSentry` has token scrubbing built in (the sign-in return-trip pass
|
|
230
|
-
in URLs is redacted automatically). Never wrap, reimplement, or bypass it —
|
|
231
|
-
and never add Sentry options that capture network request/response bodies.
|
|
232
|
-
- Don't call `Sentry.init` yourself or add a second error reporter —
|
|
233
|
-
`initGameSentry` is the one entry point.
|
|
234
|
-
- Manual capture is fine where a try/catch swallows a real bug:
|
|
235
|
-
`import * as Sentry from "@sentry/browser"; Sentry.captureException(err)`.
|
|
236
|
-
|
|
237
197
|
## NEVER log the tokens
|
|
238
198
|
|
|
239
199
|
**NEVER log the return value of `getEmbedToken()` or `getColyseusAuth()` — not
|
|
@@ -328,10 +288,8 @@ Rules:
|
|
|
328
288
|
|
|
329
289
|
## Checklist
|
|
330
290
|
|
|
331
|
-
- [ ] `
|
|
332
|
-
|
|
333
|
-
- [ ] `sentryCanvasSnapshot(renderer.domElement)` runs after `renderer.render()`
|
|
334
|
-
in the main loop (WebGL and WebGPU alike).
|
|
291
|
+
- [ ] `initEmbed(...)` is the very first call in `main.ts`, with all three
|
|
292
|
+
config fields.
|
|
335
293
|
- [ ] `genex.config.ts` includes `dashboardOrigins` (from `.genex/project.json`).
|
|
336
294
|
- [ ] Multiplayer and player-name UI await `waitForPlayer()` — NEVER
|
|
337
295
|
`waitForAuth()` (guests would hang forever). Both `connect()` and
|
|
@@ -48,11 +48,10 @@ Rules that make the contract real:
|
|
|
48
48
|
- **Scope belongs to the user.** Building a small first slice is the right
|
|
49
49
|
ORDER (`$genex-threejs-game-ui`'s v0 beat still applies) — but the slice is
|
|
50
50
|
a milestone on the way to the contract, never a quiet replacement for it.
|
|
51
|
-
If the full ask genuinely doesn't fit, shrinking any line is a
|
|
51
|
+
If the full ask genuinely doesn't fit, shrinking any line is a
|
|
52
52
|
question to the user with real options — never a silent cut justified as
|
|
53
|
-
"standard practice". (Use your
|
|
54
|
-
|
|
55
|
-
if it has none, e.g. Cursor, a short numbered list in chat.)
|
|
53
|
+
"standard practice". (Use your question tool when you have one; if you
|
|
54
|
+
have none, a short numbered list in chat.)
|
|
56
55
|
- **Minute ten is the design test.** If the honest answer is "the same sixty
|
|
57
56
|
seconds, again", the contract needs another beat (a new area unlocks, a
|
|
58
57
|
quest chain escalates, a build comes online) before any polish work.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: genex-threejs-game-ui
|
|
3
|
-
description: Design the
|
|
3
|
+
description: Design the UI HUD interface of a Genex Three.js game — plan the full screen set up front (loader, menu, HUD, pause/win/lose, lobby) under one shared art direction, then build it as an animated DOM overlay. Use for every new game before writing UI code, and whenever the game needs on-screen text, meters, buttons, or menus, or the interface reads as a generic dashboard, covers the action, or shifts as numbers change.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Genex Three.js Game UI
|
|
@@ -43,10 +43,7 @@ The table lists screens; **elements are inventoried separately**. Walk the
|
|
|
43
43
|
whole loop in your head — loader → menu → spawn → action → pickup → damage →
|
|
44
44
|
death → retry → win — and write down EVERY on-screen element the player will
|
|
45
45
|
ever see: the reticle and each of its states, aim/interact cues, toasts,
|
|
46
|
-
damage numbers, kill feeds, timers, countdowns, pickup popups
|
|
47
|
-
gets a treatment from the brief. **Nothing ships looking like default
|
|
48
|
-
browser CSS** — an element styled like a bare `<div>` or a system button is
|
|
49
|
-
a bug wherever it appears, listed or not.
|
|
46
|
+
damage numbers, kill feeds, timers, countdowns, pickup popups.
|
|
50
47
|
|
|
51
48
|
**2. One shared style brief — for the WHOLE game, not just the UI.** Write it
|
|
52
49
|
once — 4–5 named hues, materials, one display + one body font, mood — and
|
|
@@ -61,17 +58,12 @@ is LOADED for real — a Google Fonts `<link>` (or `@font-face`) in
|
|
|
61
58
|
ships as a system-stack fallback (`Arial Black`, `Impact`) is the same bug in
|
|
62
59
|
type.
|
|
63
60
|
|
|
64
|
-
**3.
|
|
65
|
-
[references/style-capsules.md](references/style-capsules.md), name 2–3 top
|
|
66
|
-
AAA games of the genre, and state in one line which structural conventions
|
|
67
|
-
you're borrowing. The bar is what those games ship, not "good enough for a
|
|
68
|
-
demo". Conventions only — never logos, exact layouts, or trade dress. The
|
|
69
|
-
same 2–3 names carry into the router's visual-direction gate for the scene.
|
|
70
|
-
Then turn references + brief into ONE **concept mockup** — the game concept
|
|
61
|
+
**3. Make ONE concept mockup** — the game concept
|
|
71
62
|
and the HUD Stage-1 mockup are the SAME image, generated once (never a
|
|
72
63
|
separate UI-free concept first): a single image of a PLAYABLE MOMENT of this
|
|
73
64
|
game with its complete HUD composited over it, built with `$genex-ai-hud`'s
|
|
74
|
-
Stage-1 prompt template.
|
|
65
|
+
Stage-1 prompt template. For genre conventions to borrow, skim
|
|
66
|
+
[references/style-capsules.md](references/style-capsules.md). The scene half of the prompt comes from the game
|
|
75
67
|
contract in TEXT, not from a prior image: what the player is DOING
|
|
76
68
|
mid-action (the verb), what threatens them right now (enemy silhouettes),
|
|
77
69
|
what they are chasing (the objective — a finish gate, a goal, a pickup),
|
|
@@ -95,9 +87,9 @@ clickable links saying which one you picked and why — a URL is invisible in a
|
|
|
95
87
|
terminal, and "do you like it?" with no picture in front of the user is the
|
|
96
88
|
#1 way this checkpoint fails (they end up digging logs for the file path).
|
|
97
89
|
|
|
98
|
-
**Then ask for the yes with your
|
|
99
|
-
|
|
100
|
-
|
|
90
|
+
**Then ask for the yes with your question tool** — the one that shows the
|
|
91
|
+
user clickable options; a short numbered list in chat only where there is
|
|
92
|
+
none. ONE question — "this is roughly
|
|
101
93
|
how the game and its HUD will look — keep this direction, or change
|
|
102
94
|
something?" — with concrete keep / change options. This confirmation is
|
|
103
95
|
REQUIRED for every game: the concept sets the STYLE every later asset
|
|
@@ -155,11 +147,10 @@ an invented mechanic, or the absence of a real one, from a picture.
|
|
|
155
147
|
|
|
156
148
|
**4. Ask only when genuinely ambiguous.** If the concept pins the mood (a
|
|
157
149
|
"gothic horror dungeon crawler" pins it), decide and state the plan in one
|
|
158
|
-
line. Only when the art direction is truly open, ask ONE
|
|
150
|
+
line. Only when the art direction is truly open, ask ONE question
|
|
159
151
|
with 2–3 concrete directions, each naming its palette + font pair — using
|
|
160
|
-
your
|
|
161
|
-
|
|
162
|
-
Cursor), a short numbered list in chat. Never ask about the screen
|
|
152
|
+
your question tool when you have one; if you have none, a short numbered
|
|
153
|
+
list in chat. Never ask about the screen
|
|
163
154
|
inventory — it derives from the game type.
|
|
164
155
|
|
|
165
156
|
**5. Style follows THIS game's concept.** The examples in every Genex skill
|
|
@@ -463,43 +454,18 @@ Order the HUD by what the player loses the game for ignoring:
|
|
|
463
454
|
- **Contrast against the real scene.** Test text over the brightest AND
|
|
464
455
|
darkest areas of actual gameplay; a soft dark plate or text-shadow beats
|
|
465
456
|
restyling per level.
|
|
466
|
-
- **
|
|
467
|
-
`clip-path
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
`genex ui` masks remain the other established uses of `mask`/`clip-path`.
|
|
479
|
-
- **The #1 chamfer defect: a frame that STOPS at the cut.** A plain
|
|
480
|
-
`border` or `box-shadow` does NOT follow a `clip-path` chamfer — the clip
|
|
481
|
-
shears it off along the diagonal, so the straight sides keep their frame
|
|
482
|
-
while the cut edge goes bare and the panel reads as broken. Two clean
|
|
483
|
-
fixes: prefer **`border-radius`** when a soft corner reads fine (it keeps
|
|
484
|
-
its `border` natively — no clip needed); for a HARD angular cut, draw the
|
|
485
|
-
frame by clipping TWO stacked layers to the SAME polygon — outer = the
|
|
486
|
-
frame, inner (inset by the frame width) = the fill — so the outer shows
|
|
487
|
-
through as a uniform edge on the diagonal too:
|
|
488
|
-
|
|
489
|
-
```css
|
|
490
|
-
/* Chamfered panel whose frame follows the cut. Never `border` + clip-path. */
|
|
491
|
-
.panel {
|
|
492
|
-
--chamfer: 16px; --edge: 2px; /* --edge = frame width */
|
|
493
|
-
--cut: polygon(var(--chamfer) 0, 100% 0, 100% calc(100% - var(--chamfer)),
|
|
494
|
-
calc(100% - var(--chamfer)) 100%, 0 100%, 0 var(--chamfer));
|
|
495
|
-
clip-path: var(--cut); background: var(--frame-hue); /* this IS the frame */
|
|
496
|
-
padding: var(--edge); /* revealed all around, incl. the diagonal */
|
|
497
|
-
}
|
|
498
|
-
.panel > .panel__fill { clip-path: var(--cut); background: var(--plate-hue); }
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
Same rule for chamfered buttons and any notched plate; verify the frame
|
|
502
|
-
is unbroken at every corner over real gameplay.
|
|
457
|
+
- **Panel and button corners come from `border-radius` or a generated frame
|
|
458
|
+
sprite — never a raw `clip-path`/`mask` chamfer.** A CSS-cut angular corner
|
|
459
|
+
is the recurring "cut corners" defect: the clip shears off borders, shadows,
|
|
460
|
+
and any content that sits near the corner, and it re-breaks the instant the
|
|
461
|
+
padding, font, or value length changes — so it can only be held together by
|
|
462
|
+
a per-build visual check that is easy to skip. It is not worth that fragility.
|
|
463
|
+
For a soft corner use `border-radius` (it keeps its `border`/`box-shadow`
|
|
464
|
+
natively). For a genuinely angular or ornamented "hi-tech" frame, generate it
|
|
465
|
+
as chrome (`$genex-ai-hud`, or a Tier-3 9-slice panel) and lay the DOM over
|
|
466
|
+
it — that reads richer and physically cannot shear. `mask`/`clip-path` stay
|
|
467
|
+
reserved for their ONE established HUD use: the masked-fill progress reveal
|
|
468
|
+
driven by `genex ui` masks. Never for corner shaping.
|
|
503
469
|
- **One cohesion layer.** A single full-screen vignette div (a subtle radial
|
|
504
470
|
gradient darkening the corners, optionally faint grain) over canvas + UI is
|
|
505
471
|
the cheapest way to make DOM-over-WebGL read as one composed image instead
|
|
@@ -11,10 +11,13 @@ says what it's made of in THIS game.
|
|
|
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 for bare
|
|
13
13
|
text over arbitrary scenes (never a second plate stacked behind an opaque
|
|
14
|
-
frame sprite), and panel/button corners
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
frame sprite), and panel/button corners done the durable way — `border-radius`
|
|
15
|
+
for soft corners (it keeps its `border`/`box-shadow` natively), or a generated
|
|
16
|
+
frame (`$genex-ai-hud` chrome / a Tier-3 9-slice panel) with the DOM laid over
|
|
17
|
+
it for genuinely angular looks. Raw CSS `clip-path`/`mask` corner cuts are
|
|
18
|
+
banned per the skill — they shear borders, shadows, and near-corner content,
|
|
19
|
+
and re-break on any padding/font change; `mask`/`clip-path` stay reserved for
|
|
20
|
+
their ONE established HUD use, the masked-fill progress reveal.
|
|
18
21
|
|
|
19
22
|
## Fantasy / action RPG
|
|
20
23
|
|
|
@@ -67,8 +67,7 @@ Infer this yourself when the experience is clear. Do **not** make the player cho
|
|
|
67
67
|
preset, or config. Ask one plain-language question only when the design genuinely supports both
|
|
68
68
|
models and the answer changes the experience — for example: *"Should this be one ongoing arena
|
|
69
69
|
people drop into, or a fresh fair match that waits for everyone and then starts together?"*
|
|
70
|
-
(Use your
|
|
71
|
-
`AskUserQuestion`; Codex: `request_user_input`; if it has none, e.g. Cursor, a short numbered
|
|
70
|
+
(Use your question tool when you have one; if you have none, a short numbered
|
|
72
71
|
list in chat.)
|
|
73
72
|
|
|
74
73
|
| Player experience | Model | Why |
|
|
@@ -621,6 +620,12 @@ than silently disappearing. The budget math that matters:
|
|
|
621
620
|
`players.get(id).state` directly (already smoothed); every object from `objects.get(id).state`.
|
|
622
621
|
4. **Create-or-reuse one mesh per id**; remove a player's mesh on `'leave'`.
|
|
623
622
|
|
|
623
|
+
> **Physics character?** If your player is the `genex controller character` capsule, do NOT
|
|
624
|
+
> hand-build the state from the body position — publish `room.me.set(character.netState())` and
|
|
625
|
+
> apply remotes with `applyNetState(mesh, players.get(id).state)`. The controller's raw `currPos.y`
|
|
626
|
+
> bobs on its float-suspension spring; `netState()` publishes a settled ground Y so a standing remote
|
|
627
|
+
> doesn't bob. See `$genex-threejs-character-controller` → "Multiplayer rule".
|
|
628
|
+
|
|
624
629
|
## Rotation: sync a quaternion, not an angle
|
|
625
630
|
|
|
626
631
|
Send rotation as a 4-number quaternion `q: mesh.quaternion.toArray()`; on the remote do
|
|
@@ -40,10 +40,8 @@ Meshy Image-to-3D first produces an unremeshed high-detail model. Show its
|
|
|
40
40
|
front, back, left, and right views and report its measured face count. Preserve
|
|
41
41
|
that model in R2. Before rigging, ask the user to approve a separate
|
|
42
42
|
10,000-face triangle remesh. The 10k remesh—not the high-detail source—is
|
|
43
|
-
rigged and animated. (For these approvals, use your
|
|
44
|
-
|
|
45
|
-
`request_user_input`; if it has none, e.g. Cursor, a short numbered list in
|
|
46
|
-
chat.)
|
|
43
|
+
rigged and animated. (For these approvals, use your question tool when you
|
|
44
|
+
have one; if you have none, a short numbered list in chat.)
|
|
47
45
|
|
|
48
46
|
The selected high-detail model remains in a neutral A-pose before animation.
|
|
49
47
|
Record evidence that the user saw its four views and face count before
|