@genex-ai/cli-demo 0.75.0-dev.194 → 0.76.0-dev.195
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 +13166 -12801
- package/package.json +1 -1
- package/templates/skills/genex-ai-character/SKILL.md +4 -1
- package/templates/skills/genex-ai-hud/SKILL.md +191 -28
- package/templates/skills/genex-ai-hud/references/masked-fill.md +54 -0
- package/templates/skills/genex-ai-hud/references/stage1-prompt-template.md +28 -7
- package/templates/skills/genex-ai-hud/references/stage2-prompt-template.md +8 -4
- package/templates/skills/genex-ai-menu/SKILL.md +84 -18
- package/templates/skills/genex-threejs-character-controller/SKILL.md +4 -1
- package/templates/skills/genex-threejs-game-content/SKILL.md +3 -1
- package/templates/skills/genex-threejs-game-ui/SKILL.md +60 -35
- package/templates/skills/genex-threejs-game-ui/references/style-capsules.md +17 -0
- package/templates/skills/genex-threejs-multiplayer/SKILL.md +3 -0
- package/templates/skills/genex-threejs-skill-router/SKILL.md +4 -1
- package/templates/skills/genex-threejs-skill-router/references/routing-map.md +18 -6
- package/templates/skills/genex-threejs-visual-validation/SKILL.md +4 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genex-ai/cli-demo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.76.0-dev.195",
|
|
4
4
|
"description": "Set up your project's agent workspace (.claude/.codex/.cursor in the game folder), authorize, create a game project, generate AI assets, and publish (genex CLI).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -43,7 +43,10 @@ Meshy Image-to-3D first produces an unremeshed high-detail model. Show its
|
|
|
43
43
|
front, back, left, and right views and report its measured face count. Preserve
|
|
44
44
|
that model in R2. Before rigging, ask the user to approve a separate
|
|
45
45
|
10,000-face triangle remesh. The 10k remesh—not the high-detail source—is
|
|
46
|
-
rigged and animated.
|
|
46
|
+
rigged and animated. (For these approvals, use your environment's structured
|
|
47
|
+
question tool when it has one — Claude Code: `AskUserQuestion`; Codex:
|
|
48
|
+
`request_user_input`; if it has none, e.g. Cursor, a short numbered list in
|
|
49
|
+
chat.)
|
|
47
50
|
|
|
48
51
|
The high-detail pre-rig generation stays in the selected neutral A-pose. There
|
|
49
52
|
is no dynamic-pose concept and no silent T-pose fallback. After the user has
|
|
@@ -31,7 +31,7 @@ ring) that no hand-written CSS can fake.
|
|
|
31
31
|
## Three layers — plates are DOM, chrome is sprites, data is DOM
|
|
32
32
|
|
|
33
33
|
- **Plate (DOM).** The backing surface behind a widget is built in CSS — in
|
|
34
|
-
whatever register the brief and concept
|
|
34
|
+
whatever register the brief and concept mockup call for: smoked glass
|
|
35
35
|
(`background: rgba(<darkest hue>, 0.35–0.6)` + `backdrop-filter: blur(6–12px)`
|
|
36
36
|
and its `-webkit-` twin) when the style wants translucency, a solid painted
|
|
37
37
|
plate, a subtle gradient — or no plate at all for an outline-led look.
|
|
@@ -62,6 +62,32 @@ ring) that no hand-written CSS can fake.
|
|
|
62
62
|
identity-bearing reticle (engraved ring, sculpted brackets) is chrome —
|
|
63
63
|
put it on the sheet like any other asset.
|
|
64
64
|
|
|
65
|
+
### Sprite vs CSS — two decision rules
|
|
66
|
+
|
|
67
|
+
- **Rule A — container vs content (the FUSED-unit test).** When a widget's
|
|
68
|
+
frame and its interior detail are one crafted unit — an engraved border
|
|
69
|
+
flowing into an engraved interior, a medallion whose emblem grows out of
|
|
70
|
+
its ring — separating them and reassembling in CSS coordinates is fragile:
|
|
71
|
+
keep them FUSED in one sprite and treat the whole thing as chrome. When
|
|
72
|
+
the interior is runtime territory (a fill channel, a number, map blips),
|
|
73
|
+
the container is the sprite and the content is DOM — the default split.
|
|
74
|
+
- **Rule B — image vs code (the 5-minute test).** If CSS can build the
|
|
75
|
+
element in under ~5 minutes without losing fidelity — flat plates, simple
|
|
76
|
+
dots/pips, plain strokes, a chamfered corner — it is CSS. If it needs
|
|
77
|
+
craft (material, ornament, painterly texture), it is a sprite. One
|
|
78
|
+
exception cuts the other way: a static label engraved/embossed into a
|
|
79
|
+
frame's craft stays BAKED in the sprite (`baked_static` below) even
|
|
80
|
+
though DOM text is "code".
|
|
81
|
+
- **CSS-chrome recipes — the middle ground.** Between bare CSS and the full
|
|
82
|
+
sprite pipeline sits brief-styled CSS chrome, right for utilitarian panels
|
|
83
|
+
and secondary screens: a two-hue gradient frame (border + inset
|
|
84
|
+
box-shadow in brief hues), a clip-path chamfer (execution bar per
|
|
85
|
+
`$genex-threejs-game-ui`'s corner rules), a 9-slice-ish panel from nested
|
|
86
|
+
divs (outer div = border hue, inset div = plate hue, 2–3px reveal). What
|
|
87
|
+
makes these legitimate: **CSS elements are styled FROM THE BRIEF — hue,
|
|
88
|
+
weight, texture. Default-gray CSS anywhere on screen is a defect** (the
|
|
89
|
+
classic failure: score pips shipped as unstyled "○ ●" system glyphs).
|
|
90
|
+
|
|
65
91
|
## Framing rules — internalize before prompting
|
|
66
92
|
|
|
67
93
|
The HUD overlays a **live 3D scene**. The pixels between widgets show the game.
|
|
@@ -118,7 +144,32 @@ buckets. The Stage-2 prompt KEEPS or REMOVES accordingly:
|
|
|
118
144
|
|
|
119
145
|
The test: "is this fixed identity artwork, or should runtime code own it?"
|
|
120
146
|
Baking a runtime value into a sprite is a failure; stripping a carved identity
|
|
121
|
-
label flattens the art.
|
|
147
|
+
label flattens the art. **One label per widget:** whoever the table says owns
|
|
148
|
+
a word, owns it alone — if a sprite ships with a `baked_static` label, the
|
|
149
|
+
DOM must never render the same word again on that widget (the double-label
|
|
150
|
+
failure). The classification survives to wiring: carry it into the code
|
|
151
|
+
comments, not just this analysis.
|
|
152
|
+
|
|
153
|
+
### Placing runtime text on frame sprites — measured, never eyeballed
|
|
154
|
+
|
|
155
|
+
- **Position from `innerBBox`.** The trim/extract sidecars (`.bbox.json`)
|
|
156
|
+
carry `innerBBox` — the frame's central transparent cavity. Box the DOM
|
|
157
|
+
text to `innerBBox` scaled to the widget's on-screen size; never hand-tune
|
|
158
|
+
magic paddings until it "looks right" (they break on the first resize or
|
|
159
|
+
art swap). If `innerBBox` is null on a genuine frame (no cavity), fall
|
|
160
|
+
back to the frame's visual center and say so in the wiring notes — solid
|
|
161
|
+
plates without a cavity are DOM plates anyway (three layers).
|
|
162
|
+
- **Occupancy bands.** Value text fills 65–85% of its zone's height; labels
|
|
163
|
+
55–75%. Below the band the text rattles inside the frame; above it, it
|
|
164
|
+
crowds the art.
|
|
165
|
+
- **Width buffers for display fonts.** Display faces run wide: budget +25%
|
|
166
|
+
width over a naive estimate, +40% for heavy weights in uppercase, +50% for
|
|
167
|
+
heavy + uppercase + serif — then verify `scrollWidth <= clientWidth` at
|
|
168
|
+
the widest real value (the 888,888 test).
|
|
169
|
+
- **`genex ui text-color` is a MANDATORY step for every widget that carries
|
|
170
|
+
DOM text** — sample the mockup region and use the returned hex verbatim.
|
|
171
|
+
Free-picking a "close enough" palette color is how text drifts off the
|
|
172
|
+
art's actual plate.
|
|
122
173
|
|
|
123
174
|
## Icons & mechanics must match the game — diff before Stage 2
|
|
124
175
|
|
|
@@ -135,8 +186,10 @@ are committing to build):
|
|
|
135
186
|
grenade slot on a rifle-only HUD, an armor bar with no armor, a minimap over
|
|
136
187
|
no map — is a failure, and "the model drew it so I kept it" is how it happens.
|
|
137
188
|
|
|
138
|
-
The mockup
|
|
139
|
-
EXISTS. When the picture and the mechanics disagree, the mechanics win.
|
|
189
|
+
The mockup — which IS the game concept — anchors STYLE; the game contract owns
|
|
190
|
+
WHAT EXISTS. When the picture and the mechanics disagree, the mechanics win.
|
|
191
|
+
Cut widgets are recorded in the UI plan message as "deferred from mockup"
|
|
192
|
+
(`$genex-threejs-game-ui`) — never silently wired, never silently dropped.
|
|
140
193
|
|
|
141
194
|
## The pipeline
|
|
142
195
|
|
|
@@ -146,24 +199,30 @@ printed. Fill the two prompt templates —
|
|
|
146
199
|
and [references/stage2-prompt-template.md](references/stage2-prompt-template.md)
|
|
147
200
|
— before Stages 1 and 2.
|
|
148
201
|
|
|
149
|
-
**Order of work: kick Stage 1 off as your FIRST action
|
|
150
|
-
gate
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
202
|
+
**Order of work: kick Stage 1 off as your FIRST action at the UI plan
|
|
203
|
+
gate — the Stage-1 mockup IS the game concept.** There is no separate
|
|
204
|
+
UI-free concept image before it: this one generation carries scene + HUD,
|
|
205
|
+
serves as the user's style checkpoint, and anchors all later art
|
|
206
|
+
(`$genex-threejs-game-ui` owns the checkpoint choreography). The scene half
|
|
207
|
+
of the prompt is written in TEXT from the game plan — `[GAME_SCENE]` in the
|
|
208
|
+
Stage-1 template: setting, the moment, what the player is doing, lighting —
|
|
209
|
+
never `--edit`-anchored to a prior image (there is none). Then write the
|
|
210
|
+
widget layout and wiring code (placement, masked-fill scaffolding,
|
|
211
|
+
plain-CSS placeholder bars) while it renders — the CSS HUD keeps
|
|
212
|
+
the game playable until the sprites land. The mockup is a STYLE anchor
|
|
213
|
+
only: the widget set and
|
|
156
214
|
layout come from the element inventory and the game contract — a mechanic
|
|
157
|
-
the
|
|
215
|
+
the mockup invented (a lap counter, a stamina orb) does not enter the HUD,
|
|
158
216
|
and a mechanic it failed to show still does. Generate 2 mockup candidates in one
|
|
159
217
|
call (`--candidates 2`) and pick the better one: a re-roll costs the whole
|
|
160
218
|
serial chain, a second candidate costs nothing extra in wall-clock. If the
|
|
161
|
-
user's concept-loop feedback
|
|
162
|
-
re-run
|
|
163
|
-
|
|
219
|
+
user's concept-loop feedback rejects the style after Stage 2+ ran,
|
|
220
|
+
re-run from Stage 1 with their notes — cheaper than it sounds (one image
|
|
221
|
+
is the whole concept now), so say so in one line and do it.
|
|
164
222
|
|
|
165
223
|
```bash
|
|
166
|
-
# Stage 1 — full
|
|
224
|
+
# Stage 1 — the game CONCEPT: full HUD composited over the game's own scene,
|
|
225
|
+
# described in TEXT (one generation covers concept + layout reference).
|
|
167
226
|
# Two candidates in one call; pick the better, save its URL:
|
|
168
227
|
npx genex image "<filled stage-1 prompt>" --size 2560x1440 --quality high --candidates 2
|
|
169
228
|
|
|
@@ -178,11 +237,15 @@ npx genex image "clean sheet" --clean <sheet-url>
|
|
|
178
237
|
# Names in READING ORDER: top-to-bottom, then left-to-right within a band:
|
|
179
238
|
npx genex ui extract --in <cleaned-url> --out-dir public/assets/hud --names hp-frame,ammo-frame,minimap-ring,weapon-icon
|
|
180
239
|
|
|
181
|
-
# Progress masks — for every bar/meter with a generated frame. The
|
|
182
|
-
# sheet holds a clean frame cell PLUS a same-size annotated duplicate
|
|
183
|
-
# fill zones painted pure green #00ff00; this converts the green into
|
|
184
|
-
# mask + the fillBox (FB) the DOM fill reads
|
|
185
|
-
|
|
240
|
+
# Progress masks — for every CONTINUOUS bar/meter with a generated frame. The
|
|
241
|
+
# Stage-2 sheet holds a clean frame cell PLUS a same-size annotated duplicate
|
|
242
|
+
# with the fill zones painted pure green #00ff00; this converts the green into
|
|
243
|
+
# an alpha mask + the fillBox (FB) the DOM fill reads (+ per-segment fillBoxes
|
|
244
|
+
# in `segments` for one-frame-N-slots meters). --auto finds the cell pairs
|
|
245
|
+
# itself — prefer it; fall back to hand-computed --pairs crop rects only when
|
|
246
|
+
# it reports ambiguity:
|
|
247
|
+
npx genex ui masks --in <cleaned-url> --out-dir public/assets/hud --auto --names hp
|
|
248
|
+
# explicit fallback: --pairs "hp:cx,cy,w,h:ax,ay,w,h:1"
|
|
186
249
|
# pairs = name : clean-cell crop (px) : annotated-cell crop (px) : expected green components
|
|
187
250
|
|
|
188
251
|
# Text colors — sample the mockup instead of free-picking from the palette:
|
|
@@ -208,6 +271,24 @@ To fix ONE sprite, don't re-run the pipeline:
|
|
|
208
271
|
its alpha content and reports its real pixel dims — the source of truth for
|
|
209
272
|
the box↔art aspect rule below.
|
|
210
273
|
|
|
274
|
+
### Crop guards — catch a bad sheet before it ships
|
|
275
|
+
|
|
276
|
+
- **`extract --expect N`** (N = your `--names` count) asserts the component
|
|
277
|
+
count and hard-errors BEFORE writing any file, listing what it found. Use
|
|
278
|
+
it on every extraction — a miscount is otherwise silent and mis-names
|
|
279
|
+
everything after the gap.
|
|
280
|
+
- Extraction also **warns** when a component touches the sheet canvas edge
|
|
281
|
+
(the canvas sliced it — regenerate the sheet with more margin around every
|
|
282
|
+
element) or looks like a fragment (extreme aspect / near-empty box — try
|
|
283
|
+
`--dilate` to glue split pieces).
|
|
284
|
+
- **gpt-image-2 silently squashes past 3:1** — never request a canvas with
|
|
285
|
+
aspect beyond 3:1. For thin strips (a wide bar frame), generate inside a
|
|
286
|
+
≤3:1 canvas with margins, then `genex ui trim` down to the art.
|
|
287
|
+
- **Fix-up recrop, never a Stage-2 re-run for one sprite.** One bad crop:
|
|
288
|
+
re-extract from the cleaned sheet with adjusted `--min-pixels`/`--dilate`,
|
|
289
|
+
or region-`--edit` the sheet and re-extract. Re-running Stage 2 re-rolls
|
|
290
|
+
every OTHER sprite too — the most expensive way to fix one.
|
|
291
|
+
|
|
211
292
|
## Composition rules (each one is a documented failure class)
|
|
212
293
|
|
|
213
294
|
- **Continuous fills = masked reveal.** HP, mana, fuel, XP, stamina, charge —
|
|
@@ -236,6 +317,43 @@ To fix ONE sprite, don't re-run the pipeline:
|
|
|
236
317
|
in a comment (`/* no plate — reads against <reason> */`). Bare digits look
|
|
237
318
|
fine over the dev background and vanish over a bright scene.
|
|
238
319
|
|
|
320
|
+
## Discrete vs continuous — classify every meter before Stage 2
|
|
321
|
+
|
|
322
|
+
**The rule: does the quantity change in whole units the player counts?**
|
|
323
|
+
Hearts, lives, ammo bullets, stars, mana pips, wave markers → DISCRETE.
|
|
324
|
+
HP %, fuel, XP, stamina, charge → CONTINUOUS. The two ship through different
|
|
325
|
+
recipes, and classifying late means re-doing the sheet:
|
|
326
|
+
|
|
327
|
+
- **Discrete = repeated sprites, NEVER a masked fill.** A masked reveal
|
|
328
|
+
swept across a row of icons slices an icon mid-body at most values — the
|
|
329
|
+
classic badly-masked hearts. Ship one `<img>` per unit
|
|
330
|
+
(`Array.from({ length: count })`), with partial states as sprite VARIANTS —
|
|
331
|
+
full/half/empty cells requested on the Stage-2 sheet as separate same-size
|
|
332
|
+
cells. Stacking (empty cell under a lit cell, dimmed vs lit) beats swapping
|
|
333
|
+
when the art allows it.
|
|
334
|
+
- **Overflow pre-flight** before placing:
|
|
335
|
+
`max_count × item_w + (max_count − 1) × gap ≤ widget_w` — at MAX count,
|
|
336
|
+
not the current one.
|
|
337
|
+
- **Anchor rule:** align the row to ONE end (start or end, matching the
|
|
338
|
+
widget's screen anchor); never center a count that changes — it reflows.
|
|
339
|
+
- Simple-shape counters CSS renders crisper than any sprite (plain
|
|
340
|
+
dots/pips) stay CSS by Rule B — but styled from the brief: hue, stroke,
|
|
341
|
+
glow, state change. Unstyled system glyphs are the defect.
|
|
342
|
+
- **Continuous = the masked-fill pattern below.** Frame sprite + green-key
|
|
343
|
+
mask + fillBox-relative clip. Never a `*-fill.png`, never a naive width%.
|
|
344
|
+
- **Segmented continuous meters** (ONE frame, N visible slots, fractional
|
|
345
|
+
value — a posture/heat bar with slot dividers): use the `segments` array
|
|
346
|
+
the masks JSON writes next to `fillBox` (per-slot fillBoxes, sorted
|
|
347
|
+
left-to-right). Fill `Math.floor(v)` segments fully (each clipped to 100%
|
|
348
|
+
of its own fillBox), clip segment `Math.floor(v) + 1` fractionally INSIDE
|
|
349
|
+
its own fillBox, leave the rest empty. Never sweep one clip across all
|
|
350
|
+
slots — the union `fillBox` is for single-channel fills only.
|
|
351
|
+
- **Never bake a label mid-channel.** A label or ornament painted in the
|
|
352
|
+
MIDDLE of a fill channel splits the mask into fragments and the fill into
|
|
353
|
+
pieces. Labels sit above/beside the channel or on the frame's end caps —
|
|
354
|
+
it's a Stage-2 prompt rule; if a sheet comes back violating it, region-edit
|
|
355
|
+
that cell before running masks.
|
|
356
|
+
|
|
239
357
|
## The masked-fill DOM pattern (the crown jewel)
|
|
240
358
|
|
|
241
359
|
Full annotated version with all direction variants and a worked HP-bar
|
|
@@ -369,11 +487,42 @@ Two hard rules:
|
|
|
369
487
|
`$genex-threejs-visual-validation`'s capture discipline. Judge the pixels,
|
|
370
488
|
not your intent.
|
|
371
489
|
|
|
490
|
+
## The closing wiring audit — the pipeline's final stage, not optional
|
|
491
|
+
|
|
492
|
+
The most expensive failure this pipeline has produced in the field is not
|
|
493
|
+
bad art — it is validated assets that never got WIRED: masks sitting on disk
|
|
494
|
+
while the shipped fill was a naive width%, frame sprites stretched into
|
|
495
|
+
boxes of the wrong aspect. Close every HUD build with this audit:
|
|
496
|
+
|
|
497
|
+
1. **Wired-or-reasoned table.** Every PNG in `public/assets/hud/` is either
|
|
498
|
+
referenced in code/CSS or has a one-line written reason it was cut. No
|
|
499
|
+
third state.
|
|
500
|
+
2. **No naive %-fills.** Grep your own code for dynamic width/height percent
|
|
501
|
+
writes — every continuous fill goes through the masked-fill clip with a
|
|
502
|
+
real `FB` from the masks JSON.
|
|
503
|
+
3. **Box aspect = sprite aspect** for every placed widget, computed from the
|
|
504
|
+
trim/extract sidecar dims — not from the mockup, never by eye.
|
|
505
|
+
4. **Every mask referenced.** Each `<name>-mask.png` appears in a CSS
|
|
506
|
+
`mask-image` (or its widget has a written reason).
|
|
507
|
+
5. **Text placement from `innerBBox`, colors from `genex ui text-color`** —
|
|
508
|
+
verbatim hex, no free-picked palette colors.
|
|
509
|
+
6. Run **`npx genex ui audit`** (it also runs automatically as a preflight in
|
|
510
|
+
`genex preview`/`publish`) and clear or explain every finding — its
|
|
511
|
+
findings are heuristics, so "checked, fine because X" is a valid close.
|
|
512
|
+
|
|
513
|
+
**The subagent handoff rule.** If stages 2–3 ran in a subagent or an earlier
|
|
514
|
+
session, the wiring agent MUST read the produced `*.annotated-progress.json`
|
|
515
|
+
and `.bbox.json` files from disk before wiring — a prose summary of them
|
|
516
|
+
does not count. fillBox numbers, `segments`, and real sprite dims do not
|
|
517
|
+
survive paraphrase; the canonical version of this failure is a subagent
|
|
518
|
+
reporting "masks validated" while the parent ships width% fills.
|
|
519
|
+
|
|
372
520
|
## Cost & latency honesty
|
|
373
521
|
|
|
374
|
-
A full HUD is **~
|
|
375
|
-
sprite re-rolls
|
|
376
|
-
|
|
522
|
+
A full HUD is **~9 image generations** (mockup + deconstruct + clean + a few
|
|
523
|
+
sprite re-rolls — the mockup doubles as the game concept, so there is no
|
|
524
|
+
separate concept spend), a couple of minutes each at high quality — budget an
|
|
525
|
+
hour end to end, not five minutes. That fits comfortably inside the image rate
|
|
377
526
|
limit; local `genex ui` steps are free and instant. Two rules keep the clock
|
|
378
527
|
honest: the sprite pipeline runs WHILE you build (kick Stage 1 first, code
|
|
379
528
|
against CSS placeholders, swap sprites in as stages land — never make the
|
|
@@ -406,15 +555,22 @@ after a bad single costs the whole chain).
|
|
|
406
555
|
`--no-wait` enqueue and continue — `npx genex wait <id>` picks the result
|
|
407
556
|
up later (safe to re-run; never creates a new generation).
|
|
408
557
|
- `npx genex ui extract --in <png|url> --out-dir <dir> --names a,b,c` — also
|
|
409
|
-
writes a `.bbox.json` sidecar per sprite
|
|
558
|
+
writes a `.bbox.json` sidecar per sprite (with `innerBBox` for text
|
|
559
|
+
placement); `--expect <n>` hard-errors on a component miscount before
|
|
560
|
+
writing anything; `--min-pixels <n>` lowers the
|
|
410
561
|
component threshold when a small sprite is missed.
|
|
411
|
-
- `npx genex ui masks --in <png|url> --out-dir <dir> --
|
|
412
|
-
|
|
413
|
-
|
|
562
|
+
- `npx genex ui masks --in <png|url> --out-dir <dir> --auto [--names a,b]` —
|
|
563
|
+
detects the clean/annotated cell pairs itself; explicit fallback
|
|
564
|
+
`--pairs "name:cx,cy,w,h:ax,ay,w,h:n"`. Emits `<name>-frame.png`,
|
|
565
|
+
`<name>-mask.png`, an overlay, and the JSON with `fillBox` (`FB`) plus
|
|
566
|
+
per-slot `segments` for segmented meters.
|
|
414
567
|
- `npx genex ui text-color --in <png|url> --box x,y,w,h` — deterministic
|
|
415
568
|
eyedropper: background/plate color + dark/light/chromatic ink candidates.
|
|
416
569
|
Use the returned hex verbatim for the DOM text over that region.
|
|
417
570
|
- `npx genex ui trim --in <png>` — crop to alpha content + report real dims.
|
|
571
|
+
- `npx genex ui audit [--dir public/assets/hud] [--src src]` — the mechanical
|
|
572
|
+
wiring scan (unreferenced sprites/masks, naive %-fill patterns); warn-only,
|
|
573
|
+
`--strict` exits 1 on findings.
|
|
418
574
|
|
|
419
575
|
## Troubleshooting
|
|
420
576
|
|
|
@@ -443,6 +599,13 @@ after a bad single costs the whole chain).
|
|
|
443
599
|
duplicate drifted from the clean cell (different scale/position) or the
|
|
444
600
|
green isn't flat `#00ff00`. Region-edit the sheet (`--edit <sheet-url>`)
|
|
445
601
|
asking for a same-size duplicate with flat green fill zones, then re-run.
|
|
602
|
+
- **`masks --auto` reports ambiguity or a missing twin** — it never guesses:
|
|
603
|
+
fall back to explicit `--pairs` with hand-read crop rects for just that
|
|
604
|
+
meter (the error lists the candidate cells it saw).
|
|
605
|
+
- **The green mask splits into unexpected components** — a label or ornament
|
|
606
|
+
is baked mid-channel. Region-edit that cell to move the label onto the
|
|
607
|
+
frame's end caps (see the mid-channel rule), or treat it as a segmented
|
|
608
|
+
meter and wire the `segments` array.
|
|
446
609
|
- **Digits or `$`/`%` come back hollow after `--remove-bg`** — closed loops
|
|
447
610
|
read as background to the default cutter. Regenerate with `--bg-mode glyph`.
|
|
448
611
|
- **A widget looks squashed** — the placement box aspect doesn't match the
|
|
@@ -55,6 +55,60 @@ liquid rises). For an orb whose empty top would show the scene through the
|
|
|
55
55
|
glass, add a dark cavity div (a circle at the `FB` box) BEHIND the fill so
|
|
56
56
|
the empty portion reads as deep glass rather than a hole.
|
|
57
57
|
|
|
58
|
+
## Segmented meters — the `segments` array
|
|
59
|
+
|
|
60
|
+
A meter whose frame has N visible slots but a CONTINUOUS value (a posture or
|
|
61
|
+
heat bar with dividers) never sweeps ONE clip across all slots — the union
|
|
62
|
+
`FB` would light half a slot's divider at most values. The masks JSON writes
|
|
63
|
+
`segments` next to `fillBox`: per-slot fillBoxes sorted left-to-right, each
|
|
64
|
+
`{ index, fillBox }` in the same 0..1 space. Wire it per slot:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
// v in [0, N] — e.g. 2.4 = two full slots + 40% of the third.
|
|
68
|
+
function setSegmented(fill: HTMLElement[], segments: { fillBox: FB }[], v: number): void {
|
|
69
|
+
segments.forEach((seg, i) => {
|
|
70
|
+
const local = Math.max(0, Math.min(1, v - i)); // this slot's own 0..1
|
|
71
|
+
const b = seg.fillBox;
|
|
72
|
+
const cx = (b.x + local * b.w) * 100;
|
|
73
|
+
// One fill div per slot, all inside the same mask div:
|
|
74
|
+
fill[i]!.style.clipPath = `polygon(${b.x * 100}% 0%, ${cx}% 0%, ${cx}% 100%, ${b.x * 100}% 100%)`;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Full slots clip to 100% of their own box, the fractional slot clips inside
|
|
80
|
+
its own box, empty slots clip to zero width. One fill div per slot (same
|
|
81
|
+
gradient, same mask parent) keeps each slot's edge inside its own channel.
|
|
82
|
+
|
|
83
|
+
## Discrete counters are NOT masked fills
|
|
84
|
+
|
|
85
|
+
Hearts, lives, ammo pips, stars — anything counted in whole units — never go
|
|
86
|
+
through this pattern at all. A mask swept across a row of hearts slices a
|
|
87
|
+
heart mid-body at most values:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
// DON'T: one mask + width clip across a row of heart icons.
|
|
91
|
+
// DO: repeated <img> per unit, variants for partial states.
|
|
92
|
+
const hearts = document.getElementById("hud-hearts")!;
|
|
93
|
+
function setHearts(hp: number, max: number): void { // hp may be 2.5
|
|
94
|
+
hearts.replaceChildren(
|
|
95
|
+
...Array.from({ length: max }, (_, i) => {
|
|
96
|
+
const img = document.createElement("img");
|
|
97
|
+
const v = Math.max(0, Math.min(1, hp - i));
|
|
98
|
+
img.src = v === 1 ? "/assets/hud/heart-full.png"
|
|
99
|
+
: v >= 0.5 ? "/assets/hud/heart-half.png"
|
|
100
|
+
: "/assets/hud/heart-empty.png";
|
|
101
|
+
return img;
|
|
102
|
+
}),
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The full/half/empty cells come from the Stage-2 sheet as separate same-size
|
|
108
|
+
cells (see the stage-2 template). Pre-flight the row at MAX count:
|
|
109
|
+
`max × item_w + (max − 1) × gap ≤ widget_w`, and anchor the row to one end —
|
|
110
|
+
never center a count that changes.
|
|
111
|
+
|
|
58
112
|
## The `data-fill-*` contract
|
|
59
113
|
|
|
60
114
|
Stamp these on the inner fill div, derived from the SAME variables that
|
|
@@ -1,15 +1,29 @@
|
|
|
1
|
-
# Stage 1 prompt template — full-HUD mockup
|
|
1
|
+
# Stage 1 prompt template — the game concept: full-HUD mockup
|
|
2
2
|
|
|
3
3
|
Fill the four placeholders, then pass the whole text as the prompt to
|
|
4
|
-
`npx genex image "<filled prompt>" --size 2560x1440 --quality high`.
|
|
4
|
+
`npx genex image "<filled prompt>" --size 2560x1440 --quality high --candidates 2`.
|
|
5
|
+
This image IS the game concept — the user's style checkpoint and the anchor
|
|
6
|
+
for all later art — so the scene half deserves the same care as the HUD half.
|
|
5
7
|
|
|
6
8
|
Placeholders:
|
|
7
9
|
|
|
8
10
|
- `[GENRE_BRIEF]` — one-line genre description, anchored in a recognizable
|
|
9
11
|
register ("a dark gothic action RPG", "a sun-bleached rally racing game",
|
|
10
12
|
"a hand-painted storybook platformer").
|
|
11
|
-
- `[GAME_SCENE]` — what's behind the HUD
|
|
12
|
-
|
|
13
|
+
- `[GAME_SCENE]` — what's behind the HUD, written RICH and from the game
|
|
14
|
+
plan (this is the concept's scene — a thin phrase wastes the checkpoint):
|
|
15
|
+
the setting, the moment, what the player is doing right now (the verb),
|
|
16
|
+
what threatens them, what they're chasing, and the lighting. Only the
|
|
17
|
+
scene may show 3D depth — never the HUD. Examples:
|
|
18
|
+
- "a rain-slick neon alley mid-chase, the player character vaulting a
|
|
19
|
+
barrier toward a glowing extraction gate, two drones closing in from
|
|
20
|
+
behind, magenta signage cutting through blue dusk"
|
|
21
|
+
- "a torchlit dungeon arena mid-duel, the player's knight raising a
|
|
22
|
+
shield against a lunging skeletal champion, a health shrine glowing in
|
|
23
|
+
a far alcove, embers drifting in the dark"
|
|
24
|
+
- "a sun-bleached desert rally stage mid-drift, the player's buggy
|
|
25
|
+
kicking up dust through a canyon gate marked with checkpoint flags, a
|
|
26
|
+
rival truck closing on the left, late-afternoon glare"
|
|
13
27
|
- `[STYLE_BRIEF]` — your full 3–5 sentence style brief with the named 4–5 hue
|
|
14
28
|
palette. Do NOT append the per-sprite cutout sentence here — this is a full
|
|
15
29
|
frame, not a cutout.
|
|
@@ -39,6 +53,13 @@ not deconstruct cleanly (angled panel edges have no clean silhouette, so
|
|
|
39
53
|
Stage 2 produces sliced, skewed cutouts). If the mockup comes back tilted,
|
|
40
54
|
regenerate it before proceeding; do not try to salvage it downstream.
|
|
41
55
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
56
|
+
One more Stage-1 rule that pays off at mask time: **meter channels must be
|
|
57
|
+
continuous** — never place a label or ornament in the MIDDLE of a fill
|
|
58
|
+
channel (it splits the mask and the fill into fragments); labels sit above or
|
|
59
|
+
beside the channel, or on the frame's end caps. If the mockup comes back
|
|
60
|
+
with a mid-channel label, keep it only if you'll wire that meter as
|
|
61
|
+
segmented (`segments` in the masks JSON) — otherwise regenerate.
|
|
62
|
+
|
|
63
|
+
The mockup is the **game concept AND the layout reference**: save its URL,
|
|
64
|
+
compare the finished HUD against it, and sample runtime text colors from it
|
|
65
|
+
with `npx genex ui text-color`.
|
|
@@ -19,9 +19,13 @@ Fill `[ASSET_LIST]`, then pass the whole text as the prompt to
|
|
|
19
19
|
translucent or solid: plates are rebuilt at runtime in CSS (rgba,
|
|
20
20
|
backdrop-filter, or a solid fill — whatever matches the mockup), so ask
|
|
21
21
|
for the panel's frame/brackets/ornament, not the panel surface itself;
|
|
22
|
-
- **requests the annotated duplicate** for every bar/meter frame
|
|
23
|
-
template's progress block below covers the mechanics — your item just
|
|
24
|
-
"output the clean frame + annotated duplicate pair")
|
|
22
|
+
- **requests the annotated duplicate** for every CONTINUOUS bar/meter frame
|
|
23
|
+
(the template's progress block below covers the mechanics — your item just
|
|
24
|
+
says "output the clean frame + annotated duplicate pair");
|
|
25
|
+
- **requests variant cells for discrete icon counters** — hearts, ammo
|
|
26
|
+
pips, stars ship as repeated sprites, not masks, so their item asks for
|
|
27
|
+
the states as SEPARATE same-size cells ("the heart icon: one full, one
|
|
28
|
+
half, one empty cell") instead of an annotated pair.
|
|
25
29
|
|
|
26
30
|
## The template
|
|
27
31
|
|
|
@@ -34,7 +38,7 @@ Lay these assets on a pure flat white #ffffff background, separated by at least
|
|
|
34
38
|
|
|
35
39
|
If an asset is a generated progress/bar/meter frame, output TWO CELLS immediately beside each other:
|
|
36
40
|
1. LEFT CELL — the clean production asset the game will use. Preserve exact style, baked_static labels, frame metal, bevels, dividers, scratches, proportions, and texture. Remove runtime dynamic fill and values. Do not paint technical colors on this clean cell.
|
|
37
|
-
2. RIGHT CELL — an annotated duplicate of the same production asset. It must be the same asset, same scale, same canvas bounds, same position, and same outer shape as the left cell. The only difference: paint runtime-fill zones with pure green key color #00ff00. Green marks only the places where runtime bar/progress fill should appear. Paint the green as a FLAT, UNIFORM, fully-saturated #00ff00 fill — no shading, no gradient, no inner shadow, no vignette, NO DARKENING TOWARD THE EDGES, no lighting, no highlights, no texture; constant color edge-to-edge with a HARD, CRISP boundary against the frame. The green is a chroma-key, not a lit surface — any edge shading makes the extracted alpha mask ragged. For
|
|
41
|
+
2. RIGHT CELL — an annotated duplicate of the same production asset. It must be the same asset, same scale, same canvas bounds, same position, and same outer shape as the left cell. The only difference: paint runtime-fill zones with pure green key color #00ff00. Green marks only the places where runtime bar/progress fill should appear. Paint the green as a FLAT, UNIFORM, fully-saturated #00ff00 fill — no shading, no gradient, no inner shadow, no vignette, NO DARKENING TOWARD THE EDGES, no lighting, no highlights, no texture; constant color edge-to-edge with a HARD, CRISP boundary against the frame. The green is a chroma-key, not a lit surface — any edge shading makes the extracted alpha mask ragged. For segmented meters, paint each segment slot as a separate green shape; do not merge slots into one continuous strip and do not paint half-segments. Never place a label or ornament in the middle of a fill channel — labels belong above/beside the channel or on the frame's end caps.
|
|
38
42
|
|
|
39
43
|
Do NOT create a separate black-background mask cell. Do NOT create a standalone simplified silhouette. The right cell is a registration-safe annotation map; local tooling derives the alpha mask from its green pixels and uses the left cell as the frame.
|
|
40
44
|
|
|
@@ -38,6 +38,53 @@ might suggest. Two hard rules for the frame prompt:
|
|
|
38
38
|
menus baked into the image. All of that is DOM on top. If the image model
|
|
39
39
|
draws UI into the frame, the prompt was wrong — rewrite and regenerate.
|
|
40
40
|
|
|
41
|
+
This dedicated UI-free **menu still is the ONLY valid `--frame` input** for
|
|
42
|
+
the menu video. The game concept is the HUD mockup now (`$genex-ai-hud`
|
|
43
|
+
Stage 1) — it has a HUD baked into it, so feeding it to `genex video
|
|
44
|
+
--frame` ships a menu with a HUD floating in the backdrop: an instant
|
|
45
|
+
defect, not a shortcut. Anchor the still to the mockup with
|
|
46
|
+
`--edit <mockup-url>` so menu and world share one palette and light — then
|
|
47
|
+
animate the STILL.
|
|
48
|
+
|
|
49
|
+
## Choose the composition — one archetype per game, justified
|
|
50
|
+
|
|
51
|
+
The single most common menu failure is every game shipping the same
|
|
52
|
+
left-rail layout regardless of genre. Before writing menu markup, pick ONE
|
|
53
|
+
archetype and justify it from the style brief in the UI plan message
|
|
54
|
+
(`$genex-threejs-game-ui`'s gate) — **defaulting to left-rail without a
|
|
55
|
+
reason is the failure mode this section exists to kill:**
|
|
56
|
+
|
|
57
|
+
- **Left rail** — title upper-left or top, buttons stacked left of center
|
|
58
|
+
(~38%), vista breathing on the right. Fits: exploration, RPG, anything
|
|
59
|
+
whose still has a strong right-side subject. (The worked example below
|
|
60
|
+
implements this one — it is ONE archetype, not the default.)
|
|
61
|
+
- **Centered stack** — logotype dominant top-center, buttons in a tight
|
|
62
|
+
column directly under it. Fits: title-driven games, arcade, sports,
|
|
63
|
+
anything with a strong wordmark. Delta: center the title block, buttons
|
|
64
|
+
`left: 50%; transform: translateX(-50%)`.
|
|
65
|
+
- **Bottom command bar** — buttons in one horizontal row along the bottom
|
|
66
|
+
edge, title above the fold. Fits: fighting, racing, arcade cabinets.
|
|
67
|
+
Delta: a flex row pinned to `bottom: 8%`, generous letter-spacing.
|
|
68
|
+
- **Boxed plate buttons** — buttons carry visible plates (brief-styled CSS
|
|
69
|
+
plates, or sprite chrome from the HUD sheet). Fits: RPG/fantasy,
|
|
70
|
+
crafted/ornate briefs. Delta: `.menu-btn` gets a background plate,
|
|
71
|
+
border, and hover lift instead of bare text.
|
|
72
|
+
- **Diegetic corner** — buttons anchored into a calm region OF THE SCENE
|
|
73
|
+
(a doorway, a dashboard, dead sky). Fits: horror, immersive sims; pairs
|
|
74
|
+
with a still prompted to leave negative space ("the lower right third is
|
|
75
|
+
calm open water").
|
|
76
|
+
- **Minimal fullbleed** — the vista is the hero; tiny corner links, no
|
|
77
|
+
stack at all. Fits: art games, ambient toys. Delta: 2–3 small text links
|
|
78
|
+
bottom-left, heavy letter-spacing, nothing over the subject.
|
|
79
|
+
|
|
80
|
+
**Second choice — button treatment,** stated in the same line: bare text
|
|
81
|
+
(cinematic, the example below) / CSS plate (styled FROM the brief —
|
|
82
|
+
gradients, borders, chamfers per the game-ui corner rules; default-gray
|
|
83
|
+
plates are a defect) / sprite chrome (from the HUD sheet or a dedicated
|
|
84
|
+
generation — Tier 2b, when the brief is ornate). The per-genre lean lives
|
|
85
|
+
in the style capsules (`$genex-threejs-game-ui`'s
|
|
86
|
+
references/style-capsules.md) — a lean, not a rule.
|
|
87
|
+
|
|
41
88
|
## Single-frame vs two-frame
|
|
42
89
|
|
|
43
90
|
- **Single-frame (default — use this).** Generate ONE image and pass it as
|
|
@@ -65,9 +112,10 @@ might suggest. Two hard rules for the frame prompt:
|
|
|
65
112
|
|
|
66
113
|
```bash
|
|
67
114
|
# 1. The frame — a still of the scene the loop returns to (this example is a
|
|
68
|
-
# painterly meadow; YOUR prompt comes from YOUR game's style brief).
|
|
69
|
-
#
|
|
70
|
-
#
|
|
115
|
+
# painterly meadow; YOUR prompt comes from YOUR game's style brief). Anchor
|
|
116
|
+
# the still to the concept mockup with --edit <mockup-url> so menu and world
|
|
117
|
+
# share one palette and light (the still stays UI-free; the mockup itself is
|
|
118
|
+
# NEVER the video frame — it has a HUD in it):
|
|
71
119
|
npx genex image "windswept alpine meadow at golden hour, wildflowers leaning in the gusts, painterly light, cinematic wide shot. Edge-to-edge cinematic composition. Full-bleed 16:9 frame. No UI elements, no text, no buttons in the frame." --aspect 16:9 --quality high
|
|
72
120
|
# -> https://assets.genex.technology/generations/<id>/image-main
|
|
73
121
|
|
|
@@ -150,8 +198,10 @@ fallback, not a downgrade to apologize for.
|
|
|
150
198
|
## Wire it as a phase screen
|
|
151
199
|
|
|
152
200
|
The menu is one `data-phase` screen in the `$genex-threejs-game-ui`
|
|
153
|
-
architecture (the `#ui` overlay + `setPhase()` state machine). Complete
|
|
154
|
-
|
|
201
|
+
architecture (the `#ui` overlay + `setPhase()` state machine). Complete
|
|
202
|
+
worked example — this implements the **left rail** archetype with **bare
|
|
203
|
+
text** buttons; adapt the positions and treatment to YOUR chosen archetype
|
|
204
|
+
(the wiring — stagger, selection, intents — carries to all of them):
|
|
155
205
|
|
|
156
206
|
```html
|
|
157
207
|
<div id="ui">
|
|
@@ -288,15 +338,23 @@ One display font + one body font per menu. Give text its own contrast against
|
|
|
288
338
|
the moving video — layered text-shadows or a subtle dark plate (avoid heavy
|
|
289
339
|
text strokes — they read as a browser game, not a title screen).
|
|
290
340
|
|
|
291
|
-
**Title treatment
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
341
|
+
**Title treatment — the generated logotype is the DEFAULT, not an upsell.**
|
|
342
|
+
Every game with a menu gets a generated wordmark (Tier 2; skipping it needs
|
|
343
|
+
a one-line stated reason in the UI plan message — "the brief is minimal
|
|
344
|
+
fullbleed and a set wordmark would fight the vista" is a reason; silence is
|
|
345
|
+
not):
|
|
346
|
+
|
|
347
|
+
- **Logotype (default yes):**
|
|
348
|
+
`npx genex image "the word 'EMBERFALL' as an ornate engraved game logo, <style brief>" --transparent`
|
|
349
|
+
— the wordmark alone on a transparent background, in the brief's display
|
|
350
|
+
register, no extra text or scenery. Clean with `--bg-mode glyph` if letter
|
|
351
|
+
counters get eaten, trim with `npx genex ui trim`. Short names (one or two
|
|
352
|
+
words) come out best. Wire it as the menu title AND the loader mark; the
|
|
353
|
+
DOM keeps an accessible text fallback (`aria-label` or visually-hidden
|
|
354
|
+
text).
|
|
355
|
+
- **Layered CSS (the fallback while it renders, or the stated-reason
|
|
356
|
+
skip):** gradient ink via `background-clip: text` + stacked shadows (a
|
|
357
|
+
tight dark one for contrast, a wide soft one for glow).
|
|
300
358
|
|
|
301
359
|
## Tips
|
|
302
360
|
|
|
@@ -308,10 +366,15 @@ upgrades, in order of effort:
|
|
|
308
366
|
still frame right first (images are cheap to redo), then animate it once.
|
|
309
367
|
The one exception: a user-driven style change (the game-ui concept loop
|
|
310
368
|
re-anchored the look) re-opens this rule once — re-edit the still
|
|
311
|
-
(`--edit` against the new concept
|
|
312
|
-
still. Agent-initiated polish never does.
|
|
313
|
-
- **
|
|
314
|
-
|
|
369
|
+
(`--edit` against the new concept mockup) and re-run the video from the
|
|
370
|
+
new still. Agent-initiated polish never does.
|
|
371
|
+
- **1080p is the default — leave it.** The menu clip is full-screen key art,
|
|
372
|
+
the first moving thing the player sees, and 720p visibly softens it on any
|
|
373
|
+
modern display. `genex video` renders 1080p by default; pass
|
|
374
|
+
`--resolution 720p` only as an explicit cost fallback (about half the
|
|
375
|
+
credits) when the user asks to economize. The flip side of 1080p: getting
|
|
376
|
+
the phone rule above wrong now costs twice as much bandwidth — poster on
|
|
377
|
+
phone tiers, always.
|
|
315
378
|
- **Pause/victory/defeat variants reuse the same video — as GRADES.** Same
|
|
316
379
|
`<video>` element or URL, different emotion via CSS `filter` on the
|
|
317
380
|
background: pause = a plain dark overlay (`rgba(0,0,0,0.55)`); defeat =
|
|
@@ -341,6 +404,9 @@ upgrades, in order of effort:
|
|
|
341
404
|
genuine state change; expect a loop seam.
|
|
342
405
|
- `--duration <sec>` (video) — 4, 6, or 8 for frame-conditioned clips;
|
|
343
406
|
default 8.
|
|
407
|
+
- `--resolution <720p|1080p>` (video) — default 1080p; `720p` is the
|
|
408
|
+
explicit cost fallback (~half the credits). Loop clips (`--loop`) ignore
|
|
409
|
+
it (that model has no resolution parameter).
|
|
344
410
|
- `--aspect 16:9 --quality high` (image) — the right settings for a menu frame.
|
|
345
411
|
- `--no-wait` — enqueue and return immediately with the generation id; pick
|
|
346
412
|
the result up later with `npx genex wait <id>` (safe to re-run — it attaches
|
|
@@ -57,7 +57,10 @@ 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.
|
|
60
|
+
rigged and animated. (For these approvals, use your environment's structured
|
|
61
|
+
question tool when it has one — Claude Code: `AskUserQuestion`; Codex:
|
|
62
|
+
`request_user_input`; if it has none, e.g. Cursor, a short numbered list in
|
|
63
|
+
chat.)
|
|
61
64
|
|
|
62
65
|
That is a separate, **same-rig Meshy-native lane**. Its animation-only GLBs are
|
|
63
66
|
accepted only when their skeleton signature matches the active character
|