@jgengine/react 0.38.0 → 0.38.1
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/CHANGELOG.md +19 -0
- package/dist/gameMenu.js +11 -1
- package/dist/gameMenuSaves.js +37 -25
- package/dist/hudTheme.js +6 -2
- package/package.json +2 -2
- package/skills/jgengine/api.md +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -26,6 +26,25 @@ At publish, rename this heading to the new version and mirror the entries into
|
|
|
26
26
|
`packages/core/src/meta/changelog.ts` (the typed `CHANGELOG` export).
|
|
27
27
|
-->
|
|
28
28
|
|
|
29
|
+
## 0.38.1
|
|
30
|
+
|
|
31
|
+
### Migrate
|
|
32
|
+
|
|
33
|
+
- **Bump lockstep SDK packages to `^0.38.1`:** `@jgengine/{core,rapier,react,ws,node,sql,convex,shell,editor,assets,navbake}`. CLI `jgengine` is `0.35.1`; `@jgengine/github` is `0.25.1`.
|
|
34
|
+
- Nothing to migrate. `variantLevels()` was renamed to `ModelVariantConfig.shadows` before any release shipped it, so no published version ever exported it and no consumer can be holding one. A level that wants to stop paying the near level's shadow cost writes `{ url, shadows: "none" }`; leaving `shadows` out keeps the model's own answer.
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- `ModelVariantConfig.shadows` (`@jgengine/core/world/modelLod`): a model variant level declares its own shadow participation as a plain field, `"inherit" | "cast" | "receive" | "both" | "none"`. `"inherit"`, the default, keeps the model's own `shadows`, so every existing model draws as before; a far level set to `"none"` leaves the shadow pass while still drawing its mesh.
|
|
39
|
+
- `ModelShadowMode` (`@jgengine/core/world/modelLod`) names the four-value shadow vocabulary, and `ModelConfig.shadows` uses it.
|
|
40
|
+
- `variantLevelModel` (`@jgengine/shell/render/singleVariantLod`) is the one place that resolves what a level draws and how it shadows; the single prop, batched prop and scatter paths all ask it, so a level's asset and its shadow answer cannot disagree.
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- `SaveSlotsPane` cards are one box each: equal tracks, `grid-auto-rows: 1fr`, a card edge that reads over a bright scene, and a name that ellipsises instead of widening the card. A save with a long name and one with none produce the same card box.
|
|
45
|
+
- `GameMenu` puts the primary verbs on their own scrim, so their labels stay legible over whatever the live scene is showing instead of relying on a text shadow.
|
|
46
|
+
- The theme emits three menu tokens the slot card and the verb surface read: `--jg-menu-card-height` (`clamp(244px, 27vh, 300px)`), `--jg-menu-card-thumb` (`clamp(88px, 14vh, 160px)`) and `--jg-menu-surface-radius` (`8px`). A game overrides them in its own `HudTheme` instead of patching the menu components.
|
|
47
|
+
|
|
29
48
|
## 0.38.0
|
|
30
49
|
|
|
31
50
|
### Migrate
|
package/dist/gameMenu.js
CHANGED
|
@@ -266,7 +266,17 @@ export function GameMenu({ items, initialId, onSelect, onBack, onHighlight, deta
|
|
|
266
266
|
nav.containerProps.onKeyDown(event);
|
|
267
267
|
if (event.key === "ArrowDown" || event.key === "ArrowUp")
|
|
268
268
|
event.stopPropagation();
|
|
269
|
-
}, children: [_jsx("div", { "data-jg-game-menu-
|
|
269
|
+
}, children: [_jsx("div", { "data-jg-game-menu-nav-surface": "", "aria-hidden": "true", style: {
|
|
270
|
+
position: "absolute",
|
|
271
|
+
inset: "-16px -22px",
|
|
272
|
+
borderRadius: "var(--jg-menu-surface-radius, 8px)",
|
|
273
|
+
background: "linear-gradient(96deg, rgba(4,7,11,0.6) 0%, rgba(4,7,11,0.34) 56%, rgba(4,7,11,0) 100%)",
|
|
274
|
+
maskImage: "linear-gradient(180deg, transparent 0, #000 9%, #000 91%, transparent 100%)",
|
|
275
|
+
WebkitMaskImage: "linear-gradient(180deg, transparent 0, #000 9%, #000 91%, transparent 100%)",
|
|
276
|
+
backdropFilter: "blur(2px)",
|
|
277
|
+
WebkitBackdropFilter: "blur(2px)",
|
|
278
|
+
pointerEvents: "none",
|
|
279
|
+
} }), _jsx("div", { "data-jg-game-menu-rail": "", "aria-hidden": "true", style: {
|
|
270
280
|
position: "absolute",
|
|
271
281
|
left: 0,
|
|
272
282
|
right: 8,
|
package/dist/gameMenuSaves.js
CHANGED
|
@@ -14,15 +14,18 @@ export const SAVE_SLOT_CHARACTER_KEY = "character";
|
|
|
14
14
|
const cardSurface = {
|
|
15
15
|
position: "relative",
|
|
16
16
|
width: "100%",
|
|
17
|
+
minWidth: 0,
|
|
18
|
+
height: "var(--jg-menu-card-height, clamp(244px, 27vh, 300px))",
|
|
17
19
|
boxSizing: "border-box",
|
|
20
|
+
overflow: "hidden",
|
|
18
21
|
display: "flex",
|
|
19
22
|
flexDirection: "column",
|
|
20
23
|
gap: 8,
|
|
21
|
-
minWidth: 0,
|
|
22
24
|
padding: 10,
|
|
23
25
|
borderRadius: "var(--jg-menu-card-radius, 12px)",
|
|
24
|
-
background: "linear-gradient(180deg, rgba(16,22,30,0.
|
|
25
|
-
|
|
26
|
+
background: "linear-gradient(180deg, rgba(16,22,30,0.9), rgba(8,11,16,0.94))",
|
|
27
|
+
border: "1px solid rgba(255,255,255,0.14)",
|
|
28
|
+
boxShadow: "inset 0 0 0 1px rgba(255,255,255,0.05), 0 14px 34px -18px rgba(0,0,0,0.9)",
|
|
26
29
|
backdropFilter: "blur(6px)",
|
|
27
30
|
color: "var(--jg-text, #f2f6fb)",
|
|
28
31
|
fontFamily: hudFont.body,
|
|
@@ -67,9 +70,9 @@ export function SaveSlotCard({ slot, now = Date.now, recent = false, onSelect, o
|
|
|
67
70
|
cursor: onSelect === undefined ? "default" : "pointer",
|
|
68
71
|
alignItems: "flex-start",
|
|
69
72
|
justifyContent: "flex-end",
|
|
70
|
-
border: "
|
|
73
|
+
border: "1px solid rgba(255,255,255,0.1)",
|
|
71
74
|
boxShadow: "inset 0 0 0 1px rgba(255,255,255,0.07), inset 0 0 40px -18px rgba(125,211,252,0.4), 0 10px 26px -20px rgba(0,0,0,0.9)",
|
|
72
|
-
background: "linear-gradient(180deg, rgba(12,17,24,0.
|
|
75
|
+
background: "linear-gradient(180deg, rgba(12,17,24,0.82), rgba(6,9,13,0.9))",
|
|
73
76
|
...style,
|
|
74
77
|
}, children: [_jsx("div", { "data-save-slot-thumb": "", "data-empty": "", style: {
|
|
75
78
|
width: "100%",
|
|
@@ -94,7 +97,8 @@ export function SaveSlotCard({ slot, now = Date.now, recent = false, onSelect, o
|
|
|
94
97
|
}, children: [_jsxs("div", { "data-save-slot-thumb": "", style: {
|
|
95
98
|
position: "relative",
|
|
96
99
|
width: "100%",
|
|
97
|
-
|
|
100
|
+
flexShrink: 0,
|
|
101
|
+
height: "var(--jg-menu-card-thumb, clamp(88px, 14vh, 160px))",
|
|
98
102
|
borderRadius: 8,
|
|
99
103
|
overflow: "hidden",
|
|
100
104
|
background: "radial-gradient(120% 120% at 30% 20%, rgba(125,211,252,0.22), rgba(8,12,18,0.9))",
|
|
@@ -124,6 +128,10 @@ export function SaveSlotCard({ slot, now = Date.now, recent = false, onSelect, o
|
|
|
124
128
|
fontWeight: 800,
|
|
125
129
|
letterSpacing: "0.01em",
|
|
126
130
|
textShadow: "0 2px 12px rgba(0,0,0,0.8)",
|
|
131
|
+
maxWidth: "calc(100% - 16px)",
|
|
132
|
+
whiteSpace: "nowrap",
|
|
133
|
+
overflow: "hidden",
|
|
134
|
+
textOverflow: "ellipsis",
|
|
127
135
|
}, children: slot.name ?? slot.id }), recent ? (_jsx("span", { "data-save-slot-recent": "", style: {
|
|
128
136
|
position: "absolute",
|
|
129
137
|
top: 6,
|
|
@@ -231,6 +239,10 @@ export function SaveSlotsPane({ model, onContinue, onLoad, onNew, onDelete, head
|
|
|
231
239
|
}, children: ["Continue ", recent.name ?? recent.id] }))] }), _jsx("div", { ...nav.containerProps, "data-save-slots-grid": "", style: {
|
|
232
240
|
display: "grid",
|
|
233
241
|
gridTemplateColumns: columns === "auto" ? "repeat(auto-fill, minmax(230px, 1fr))" : `repeat(${columns}, minmax(0, 1fr))`,
|
|
242
|
+
// Every card gets the same box: equal tracks, equal rows, and content that cannot widen it.
|
|
243
|
+
gridAutoRows: "auto",
|
|
244
|
+
alignItems: "stretch",
|
|
245
|
+
flex: 1,
|
|
234
246
|
gap: hudSpace("md"),
|
|
235
247
|
minHeight: 0,
|
|
236
248
|
overflowY: "auto",
|
|
@@ -240,25 +252,25 @@ export function SaveSlotsPane({ model, onContinue, onLoad, onNew, onDelete, head
|
|
|
240
252
|
paddingBottom: 4,
|
|
241
253
|
}, children: slots.map((slot) => {
|
|
242
254
|
const active = nav.activeId === slot.id;
|
|
243
|
-
return (_jsx(
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
255
|
+
return (_jsx(SaveSlotCard, { slot: slot, now: now, recent: recent !== null && recent.id === slot.id, ...(onLoad === undefined && onNew === undefined
|
|
256
|
+
? {}
|
|
257
|
+
: {
|
|
258
|
+
onSelect: (chosen) => {
|
|
259
|
+
if (chosen.empty)
|
|
260
|
+
onNew?.(chosen);
|
|
261
|
+
else
|
|
262
|
+
onLoad?.(chosen);
|
|
263
|
+
},
|
|
264
|
+
}), ...(onDelete === undefined ? {} : { onDelete }), style: {
|
|
265
|
+
minWidth: 0,
|
|
266
|
+
...(active
|
|
267
|
+
? {
|
|
268
|
+
boxShadow: "inset 0 0 0 1px var(--jg-accent, #7dd3fc), 0 0 0 1px rgba(125,211,252,0.5), 0 18px 40px -18px rgba(0,0,0,0.95)",
|
|
269
|
+
transform: "translateY(-2px)",
|
|
270
|
+
transition: `transform ${hudDuration("fast")} ${hudEase("spring")}`,
|
|
271
|
+
}
|
|
272
|
+
: {}),
|
|
273
|
+
} }, slot.id));
|
|
262
274
|
}) })] }));
|
|
263
275
|
}
|
|
264
276
|
/**
|
package/dist/hudTheme.js
CHANGED
|
@@ -105,10 +105,14 @@ export function hudThemeVars(theme) {
|
|
|
105
105
|
"--jg-frame-bg": frame.bg,
|
|
106
106
|
"--jg-frame-border": frame.border,
|
|
107
107
|
"--jg-frame-radius": frame.radius,
|
|
108
|
-
// The game menu's
|
|
109
|
-
//
|
|
108
|
+
// The game menu's design tokens: a logo sized off the display step, card corners that follow the
|
|
109
|
+
// frame radius, and the card's fixed height and thumbnail band, so a slot card is the same box
|
|
110
|
+
// whatever it holds and a game can retune the menu from its theme.
|
|
110
111
|
"--jg-menu-logo-size": "clamp(30px, 4.6vw, 66px)",
|
|
111
112
|
"--jg-menu-card-radius": frame.radius,
|
|
113
|
+
"--jg-menu-card-height": "clamp(244px, 27vh, 300px)",
|
|
114
|
+
"--jg-menu-card-thumb": "clamp(88px, 14vh, 160px)",
|
|
115
|
+
"--jg-menu-surface-radius": "8px",
|
|
112
116
|
"--jg-frame-glow": frame.glow,
|
|
113
117
|
"--jg-slot-bg": slot.bg,
|
|
114
118
|
"--jg-slot-border": slot.border,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jgengine/react",
|
|
3
|
-
"version": "0.38.
|
|
3
|
+
"version": "0.38.1",
|
|
4
4
|
"description": "React UI layer for JGengine: GameProvider, hooks, and headless primitives over @jgengine/core.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"styles": "bun scripts/styles.ts"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@jgengine/core": "^0.38.
|
|
38
|
+
"@jgengine/core": "^0.38.1"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"react": "^19.0.0",
|
package/skills/jgengine/api.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
- `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
|
|
8
8
|
- `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
|
|
9
|
-
- `VERSION` (const): const VERSION: "0.38.
|
|
9
|
+
- `VERSION` (const): const VERSION: "0.38.1" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
|
|
10
10
|
|
|
11
11
|
## @jgengine/core/authoring
|
|
12
12
|
|
|
@@ -285,7 +285,7 @@
|
|
|
285
285
|
|
|
286
286
|
- `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
|
|
287
287
|
- `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
|
|
288
|
-
- `VERSION` (const): const VERSION: "0.38.
|
|
288
|
+
- `VERSION` (const): const VERSION: "0.38.1" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
|
|
289
289
|
|
|
290
290
|
## @jgengine/core/runtime/adapter
|
|
291
291
|
|