@jgengine/shell 0.18.1 → 0.21.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/CHANGELOG.md +504 -7
- package/dist/GameHost.d.ts +12 -1
- package/dist/GameHost.js +14 -1
- package/dist/GamePlayerShell.js +132 -17
- package/dist/Shell3dPresentation.d.ts +5 -11
- package/dist/Shell3dPresentation.js +73 -11
- package/dist/ShellChrome.d.ts +2 -1
- package/dist/ShellChrome.js +22 -6
- package/dist/ShellHudPresentation.d.ts +20 -2
- package/dist/ShellHudPresentation.js +41 -6
- package/dist/audio/AudioComponents.js +6 -2
- package/dist/audio/audioEngine.d.ts +24 -0
- package/dist/audio/audioEngine.js +231 -83
- package/dist/audio/audioWire.d.ts +3 -0
- package/dist/audio/audioWire.js +9 -3
- package/dist/audio/loopParams.d.ts +39 -0
- package/dist/audio/loopParams.js +43 -0
- package/dist/audio/synthEngine.d.ts +7 -1
- package/dist/audio/synthEngine.js +103 -38
- package/dist/camera/GameCameraRig.js +3 -2
- package/dist/camera/GameFirstPersonCamera.d.ts +6 -4
- package/dist/camera/GameFirstPersonCamera.js +68 -27
- package/dist/camera/Viewports.d.ts +34 -0
- package/dist/camera/Viewports.js +123 -0
- package/dist/camera/cameraRigs.js +76 -62
- package/dist/camera/chaseHeading.d.ts +9 -0
- package/dist/camera/chaseHeading.js +10 -0
- package/dist/camera/customMuzzle.d.ts +14 -0
- package/dist/camera/customMuzzle.js +68 -0
- package/dist/camera/index.d.ts +1 -0
- package/dist/camera/index.js +1 -0
- package/dist/camera/orbitCameraMath.js +2 -2
- package/dist/camera/rigMath.d.ts +82 -4
- package/dist/camera/rigMath.js +133 -15
- package/dist/camera/rigResolve.d.ts +3 -0
- package/dist/camera/rigResolve.js +11 -0
- package/dist/combat/ProjectileModels.d.ts +31 -0
- package/dist/combat/ProjectileModels.js +70 -0
- package/dist/commandSink.d.ts +1 -2
- package/dist/commandSink.js +3 -2
- package/dist/defineGame.d.ts +19 -3
- package/dist/defineGame.js +39 -7
- package/dist/devtools/DevtoolsOverlay.d.ts +2 -69
- package/dist/devtools/DevtoolsOverlay.js +15 -167
- package/dist/devtools/DevtoolsRuntime.d.ts +7 -0
- package/dist/devtools/DevtoolsRuntime.js +61 -0
- package/dist/devtools/agentBridge.d.ts +6 -0
- package/dist/devtools/agentBridge.js +16 -2
- package/dist/devtools/devtoolsReports.d.ts +68 -0
- package/dist/devtools/devtoolsReports.js +100 -0
- package/dist/devtools/latencyInstrumentation.d.ts +3 -0
- package/dist/devtools/latencyInstrumentation.js +11 -0
- package/dist/devtools/playtestProbe.d.ts +4 -0
- package/dist/devtools/playtestProbe.js +22 -0
- package/dist/diagnostics/FpsCounter.d.ts +17 -0
- package/dist/diagnostics/FpsCounter.js +32 -0
- package/dist/drivers/FrameDriver.js +35 -20
- package/dist/drivers/FrameRateLimiter.d.ts +9 -0
- package/dist/drivers/FrameRateLimiter.js +39 -0
- package/dist/drivers/HudOnlyDriver.d.ts +6 -1
- package/dist/drivers/HudOnlyDriver.js +32 -14
- package/dist/environment/DayNightSky.js +5 -5
- package/dist/environment/Daylight.d.ts +35 -1
- package/dist/environment/Daylight.js +98 -28
- package/dist/environment/EnvironmentScene.js +11 -10
- package/dist/environment/VolumetricClouds.js +20 -2
- package/dist/environment/daylightCycle.d.ts +20 -0
- package/dist/environment/daylightCycle.js +59 -7
- package/dist/environment/sunShadowMath.d.ts +45 -0
- package/dist/environment/sunShadowMath.js +50 -0
- package/dist/input/gamepadPoll.d.ts +47 -0
- package/dist/input/gamepadPoll.js +142 -0
- package/dist/input/gamepadSource.d.ts +11 -1
- package/dist/input/gamepadSource.js +117 -71
- package/dist/input/mouseLook.js +2 -1
- package/dist/input/padHaptics.d.ts +17 -0
- package/dist/input/padHaptics.js +32 -0
- package/dist/input/pointerLock.d.ts +11 -0
- package/dist/input/pointerLock.js +19 -0
- package/dist/inputSink.d.ts +6 -6
- package/dist/inputSink.js +60 -21
- package/dist/lazyShell3dPresentation.d.ts +9 -0
- package/dist/lazyShell3dPresentation.js +24 -0
- package/dist/materialOverride.d.ts +42 -0
- package/dist/materialOverride.js +95 -36
- package/dist/multiplayer.d.ts +33 -3
- package/dist/multiplayer.js +105 -22
- package/dist/pointer/pointerService.d.ts +2 -0
- package/dist/pointer/pointerService.js +12 -2
- package/dist/postfx/PostProcessing.d.ts +11 -1
- package/dist/postfx/PostProcessing.js +14 -42
- package/dist/postfx/gradeShader.d.ts +1 -1
- package/dist/postfx/gradeShader.js +30 -2
- package/dist/postfx/shadowPrepass.d.ts +3 -0
- package/dist/postfx/shadowPrepass.js +18 -0
- package/dist/postfx/stylizePass.d.ts +23 -0
- package/dist/postfx/stylizePass.js +216 -0
- package/dist/presentationRecovery.d.ts +75 -0
- package/dist/presentationRecovery.js +204 -0
- package/dist/presentationRecovery3d.d.ts +4 -0
- package/dist/presentationRecovery3d.js +32 -0
- package/dist/presentationResolve.d.ts +8 -1
- package/dist/presentationResolve.js +5 -2
- package/dist/render/CascadedShadows.d.ts +7 -2
- package/dist/render/CascadedShadows.js +98 -20
- package/dist/render/EnvironmentLighting.js +74 -35
- package/dist/render/HairCards.d.ts +7 -0
- package/dist/render/HairCards.js +23 -0
- package/dist/render/SceneModels.js +52 -78
- package/dist/render/SkinnedInstances.d.ts +91 -0
- package/dist/render/SkinnedInstances.js +249 -0
- package/dist/render/TextureFiltering.d.ts +16 -0
- package/dist/render/TextureFiltering.js +64 -0
- package/dist/render/authoredSurfaceMaterial.d.ts +43 -0
- package/dist/render/authoredSurfaceMaterial.js +108 -0
- package/dist/render/displayColor.d.ts +33 -0
- package/dist/render/displayColor.js +138 -0
- package/dist/render/materialAppearanceSignals.d.ts +23 -0
- package/dist/render/materialAppearanceSignals.js +58 -0
- package/dist/render/materialAsset.d.ts +98 -0
- package/dist/render/materialAsset.js +454 -0
- package/dist/render/measureBounds.js +16 -3
- package/dist/render/measureCollisionMesh.js +8 -1
- package/dist/render/modelAssets.d.ts +8 -0
- package/dist/render/modelAssets.js +43 -0
- package/dist/render/modelBindPose.d.ts +5 -0
- package/dist/render/modelBindPose.js +35 -0
- package/dist/render/modelLoad.d.ts +32 -0
- package/dist/render/modelLoad.js +70 -1
- package/dist/render/modelNodeVisibility.d.ts +6 -0
- package/dist/render/modelNodeVisibility.js +18 -0
- package/dist/render/modelRender.d.ts +18 -1
- package/dist/render/modelRender.js +81 -3
- package/dist/render/projectedOverdraw.d.ts +35 -0
- package/dist/render/projectedOverdraw.js +204 -0
- package/dist/render/resolveModel.d.ts +12 -2
- package/dist/render/resolveModel.js +25 -4
- package/dist/render/rigNode.d.ts +26 -0
- package/dist/render/rigNode.js +32 -0
- package/dist/render/spriteRender.d.ts +4 -0
- package/dist/render/spriteRender.js +5 -0
- package/dist/render/staticShapeInstances.d.ts +34 -0
- package/dist/render/staticShapeInstances.js +78 -0
- package/dist/render/useFootIk.d.ts +53 -4
- package/dist/render/useFootIk.js +262 -70
- package/dist/render/useModelAnimation.d.ts +50 -0
- package/dist/render/useModelAnimation.js +245 -99
- package/dist/render/useModelInstance.d.ts +25 -0
- package/dist/render/useModelInstance.js +43 -0
- package/dist/scatter/scatterModels.d.ts +3 -2
- package/dist/scatter/scatterModels.js +15 -7
- package/dist/scene/AuthoredScene.d.ts +23 -6
- package/dist/scene/AuthoredScene.js +46 -9
- package/dist/scene/CityRenderer.js +6 -6
- package/dist/scene/GeneratedAssetRenderer.js +11 -42
- package/dist/settings/QuickControls.js +1 -1
- package/dist/settings/SettingsMenu.js +11 -18
- package/dist/settings/SettingsRuntime.d.ts +5 -0
- package/dist/settings/SettingsRuntime.js +29 -2
- package/dist/settings/appliedSettings.d.ts +9 -3
- package/dist/settings/appliedSettings.js +6 -5
- package/dist/settings/settingsController.d.ts +3 -0
- package/dist/settings/settingsController.js +47 -3
- package/dist/shellControlSuspension.d.ts +18 -0
- package/dist/shellControlSuspension.js +28 -0
- package/dist/shellInputPublication.d.ts +28 -0
- package/dist/shellInputPublication.js +49 -0
- package/dist/shellPointerInput.d.ts +18 -0
- package/dist/shellPointerInput.js +49 -0
- package/dist/structures/BuildingKitBatch.d.ts +3 -1
- package/dist/structures/BuildingKitBatch.js +35 -56
- package/dist/structures/BuildingRenderBudget.d.ts +23 -0
- package/dist/structures/BuildingRenderBudget.js +54 -0
- package/dist/structures/GeneratedBuilding.d.ts +3 -15
- package/dist/structures/GeneratedBuilding.js +33 -22
- package/dist/structures/buildingKitMaterials.d.ts +20 -0
- package/dist/structures/buildingKitMaterials.js +70 -0
- package/dist/structures/buildingSpatialBatch.d.ts +11 -0
- package/dist/structures/buildingSpatialBatch.js +45 -0
- package/dist/structures/buildingSurface.d.ts +21 -0
- package/dist/structures/buildingSurface.js +134 -0
- package/dist/terrain/GrassField.d.ts +2 -1
- package/dist/terrain/GrassField.js +59 -5
- package/dist/terrain/grassGeometry.d.ts +10 -0
- package/dist/terrain/grassGeometry.js +55 -0
- package/dist/terrain/grassMaterial.js +2 -2
- package/dist/terrain/terrainDetailMaterial.d.ts +3 -3
- package/dist/terrain/terrainDetailMaterial.js +7 -7
- package/dist/touch/TouchControlsOverlay.js +4 -4
- package/dist/useShellMultiplayerSync.d.ts +1 -1
- package/dist/useShellMultiplayerSync.js +9 -3
- package/dist/vfx/ParticleField.d.ts +23 -20
- package/dist/vfx/ParticleField.js +168 -50
- package/dist/visibility/CullingProvider.js +2 -62
- package/dist/visibility/cullingDriver.d.ts +9 -0
- package/dist/visibility/cullingDriver.js +68 -0
- package/dist/weather/AuthoredWeatherLayer.d.ts +16 -0
- package/dist/weather/AuthoredWeatherLayer.js +31 -0
- package/dist/weather/DustField.d.ts +2 -1
- package/dist/weather/DustField.js +17 -3
- package/dist/weather/FireSpreadLayer.d.ts +4 -2
- package/dist/weather/FireSpreadLayer.js +5 -11
- package/dist/weather/LightningStrike.d.ts +4 -1
- package/dist/weather/LightningStrike.js +13 -17
- package/dist/weather/RainField.d.ts +2 -1
- package/dist/weather/RainField.js +17 -3
- package/dist/weather/RainImpactField.d.ts +16 -0
- package/dist/weather/RainImpactField.js +89 -0
- package/dist/weather/SnowField.d.ts +2 -1
- package/dist/weather/SnowField.js +17 -3
- package/dist/weather/WeatherLayer.d.ts +11 -2
- package/dist/weather/WeatherLayer.js +30 -6
- package/dist/weather/index.d.ts +2 -0
- package/dist/weather/index.js +2 -0
- package/dist/weather/weatherMath.d.ts +2 -0
- package/dist/weather/weatherMath.js +8 -0
- package/dist/weather/weatherShelter.d.ts +18 -0
- package/dist/weather/weatherShelter.js +75 -0
- package/dist/weather/weatherUniforms.d.ts +40 -1
- package/dist/weather/weatherUniforms.js +29 -9
- package/dist/world/AuthoredFlocks.d.ts +22 -0
- package/dist/world/AuthoredFlocks.js +87 -0
- package/dist/world/StaticObjectModels.d.ts +8 -0
- package/dist/world/StaticObjectModels.js +75 -0
- package/dist/world/WorldHud.d.ts +14 -6
- package/dist/world/WorldHud.js +25 -12
- package/dist/world/WorldParticles.d.ts +10 -23
- package/dist/world/WorldParticles.js +210 -62
- package/dist/world/WorldScene.d.ts +3 -1
- package/dist/world/WorldScene.js +41 -26
- package/dist/world/staticObjectBatches.d.ts +35 -0
- package/dist/world/staticObjectBatches.js +163 -0
- package/dist/world/worldBarSamples.d.ts +37 -33
- package/dist/world/worldBarSamples.js +117 -75
- package/package.json +4 -4
- package/skills/ce-handoff/SKILL.md +2 -2
- package/skills/game-design/SKILL.md +2 -2
- package/skills/jgengine/SKILL.md +28 -6
- package/skills/jgengine/api.md +139 -99
- package/skills/jgengine/capabilities.md +28 -0
- package/skills/jgengine/recipes/minimal-game.md +10 -2
- package/skills/jgengine-ui/SKILL.md +16 -17
- package/skills/jgengine-ui/api.md +603 -365
- package/skills/jgengine-ui/capabilities.md +131 -1
- package/skills/jgengine-ui/reference-primitives.md +179 -0
- package/skills/jgengine-ui/reference.md +4 -81
- package/skills/jgengine-world/SKILL.md +25 -4
- package/skills/jgengine-world/api.md +1045 -655
- package/skills/jgengine-world/capabilities.md +246 -9
- package/skills/jgengine-world/recipes/character-animation.md +62 -0
- package/skills/jgengine-world/recipes/controls.md +48 -0
- package/skills/jgengine-world/recipes/flight-feel.md +76 -0
- package/skills/jgengine-world/recipes/npc-senses.md +55 -0
- package/skills/jgengine-world/recipes/vehicle-feel.md +87 -0
- package/skills/jgengine-world/reference.md +180 -4
- package/skills/jgengine-world/visibility.md +139 -0
- package/skills/level-design/SKILL.md +1 -1
- package/dist/render/testFixtures/proceduralSpriteAtlas.d.ts +0 -15
- package/dist/render/testFixtures/proceduralSpriteAtlas.js +0 -30
- package/dist/render/testFixtures/proceduralTileLayer.d.ts +0 -13
- package/dist/render/testFixtures/proceduralTileLayer.js +0 -30
|
@@ -12,6 +12,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
12
12
|
|
|
13
13
|
- `collectAuthoredTriggers` (function) · `import { collectAuthoredTriggers } from "@jgengine/shell/gameKit"`
|
|
14
14
|
|
|
15
|
+
## chase-view-cycle — cycle a vehicle camera between chase, hood and cockpit views at runtime
|
|
16
|
+
|
|
17
|
+
- `nextChaseView` (function) · `import { nextChaseView } from "@jgengine/core/runtime/cameraDirector"`
|
|
18
|
+
|
|
15
19
|
## client-side — input prediction with replay reconciliation
|
|
16
20
|
|
|
17
21
|
- `createPredictionBuffer` (function) · `import { createPredictionBuffer } from "@jgengine/core/runtime/prediction"`
|
|
@@ -20,6 +24,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
20
24
|
|
|
21
25
|
- `GameContextModels` (interface) · `import { GameContextModels } from "@jgengine/core/runtime/gameContext"`
|
|
22
26
|
|
|
27
|
+
## command-number — validate finite, bounded numbers and integers at command boundaries
|
|
28
|
+
|
|
29
|
+
- `readInputNumber` (function) · `import { readInputNumber } from "@jgengine/core/runtime/commandInput"`
|
|
30
|
+
|
|
31
|
+
## command-parse — parse untrusted command input once so every command stage sees typed, bounded values
|
|
32
|
+
|
|
33
|
+
- `defineCommand` (function) · `import { defineCommand } from "@jgengine/core/runtime/commandRunner"`
|
|
34
|
+
|
|
23
35
|
## command-quantity — validate bounded whole-item counts at command boundaries
|
|
24
36
|
|
|
25
37
|
- `readQuantity` (function) · `import { readQuantity } from "@jgengine/core/runtime/commandInput"`
|
|
@@ -40,6 +52,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
40
52
|
|
|
41
53
|
- `EditorCatalogDefinition` (interface) · `import { EditorCatalogDefinition } from "@jgengine/shell/gameKit"`
|
|
42
54
|
|
|
55
|
+
## fire-input — bind a key or mouse button to a named action that runs the same-named command with the aim; repeatMs auto-fires while held
|
|
56
|
+
|
|
57
|
+
- `ActionCodesMap` (type) · `import { ActionCodesMap } from "@jgengine/core/authoring"`
|
|
58
|
+
|
|
43
59
|
## game-system — declare a composable capability with its own schedule and lifecycle
|
|
44
60
|
|
|
45
61
|
- `SystemDefinition` (interface) · `import { SystemDefinition } from "@jgengine/shell/gameKit"`
|
|
@@ -96,6 +112,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
96
112
|
|
|
97
113
|
- `createInputRecorder` (function) · `import { createInputRecorder } from "@jgengine/core/runtime/inputRecorder"`
|
|
98
114
|
|
|
115
|
+
## local-players — Couch co-op seats: devices hot-join into slots, each with its own user id and input snapshot.
|
|
116
|
+
|
|
117
|
+
- `createLocalPlayers` (function) · `import { createLocalPlayers } from "@jgengine/core/runtime/localPlayers"`
|
|
118
|
+
|
|
99
119
|
## loot-table — validate a loot table definition for use with the registry
|
|
100
120
|
|
|
101
121
|
- `lootTable` (function) · `import { lootTable } from "@jgengine/core/authoring"`
|
|
@@ -178,6 +198,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
178
198
|
|
|
179
199
|
- `defineStore` (function) · `import { defineStore } from "@jgengine/shell/gameKit"`
|
|
180
200
|
|
|
201
|
+
## warn-once — emit a dev-only warning a single time per call site
|
|
202
|
+
|
|
203
|
+
- `warnOnce` (function) · `import { warnOnce } from "@jgengine/core/devtools/warnOnce"`
|
|
204
|
+
|
|
181
205
|
## world-chunk-key — map world positions to persisted chunk keys at a declared cell size
|
|
182
206
|
|
|
183
207
|
- `chunkKeyOf` (function) · `import { chunkKeyOf } from "@jgengine/core/runtime/worldChunks"`
|
|
@@ -193,3 +217,7 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
193
217
|
## world-environment — compose editor/preset-derived outdoor dressing — terrain, weather, water, structures — into a legacy environment feature
|
|
194
218
|
|
|
195
219
|
- `environment` (function) · `import { environment } from "@jgengine/shell/gameKit"`
|
|
220
|
+
|
|
221
|
+
## world-item-pickup — pick up dropped items: ctx.scene.worldItem nearestInRadius → pickup into the player's inventory
|
|
222
|
+
|
|
223
|
+
- `SceneWorldItemContext` (interface) · `import { SceneWorldItemContext } from "@jgengine/core/runtime/gameContext"`
|
|
@@ -6,6 +6,11 @@ authored scene edited in the browser, one system, one store slot, an empty-canva
|
|
|
6
6
|
and a win condition. Every new game starts here; add combat, multiplayer, or deeper
|
|
7
7
|
world features only after this loop plays.
|
|
8
8
|
|
|
9
|
+
Every extension follows the [framework-first decision](../SKILL.md#framework-first-decisions):
|
|
10
|
+
compose an installed SDK capability, improve its upstream contract if needed, then
|
|
11
|
+
remove superseded game glue after published adoption. The game owns its rules and art;
|
|
12
|
+
it should not recreate input, model lifecycle, storage or UI accessibility machinery.
|
|
13
|
+
|
|
9
14
|
## 1. Scaffold
|
|
10
15
|
|
|
11
16
|
`npx jgengine create <name>` (inside the engine monorepo: `bun run new:game "<id-or-title>"`).
|
|
@@ -45,6 +50,9 @@ spatial place. When the game *is* a place, declare only substrate + laws with `w
|
|
|
45
50
|
`@jgengine/core/world/place` (e.g. `{ id, ground: { mode: "flat", size: { x: Infinity, z: Infinity } }, physics: { gravity: -24 } }`,
|
|
46
51
|
or `mode: "board"` for 2D). Never seed, sky, or vegetation in `world` — the engine renders its
|
|
47
52
|
default sky until you author one in the editor, and foliage is editor scatter over the ground.
|
|
53
|
+
A created 3D game instead ships hills as a terrain sculpt in `editor.scene.json` and a `world.ts`
|
|
54
|
+
that consumes it with `environment({ sculpt })` via `environmentContentFromDocument`; the file
|
|
55
|
+
holds only the ground palette. Reshape the hills in the editor, not in code.
|
|
48
56
|
|
|
49
57
|
|
|
50
58
|
```ts
|
|
@@ -77,8 +85,8 @@ direction. Compose the shipped building blocks the moment you need them (`StatBa
|
|
|
77
85
|
`Coins`, `InventoryGrid`, `CharacterSheet`, window shells from `jgengine-ui`), then reskin via
|
|
78
86
|
`HudTheme` tokens. Reaching for those is using the engine correctly, not incomplete work. What
|
|
79
87
|
the engine does not ship is a whole finished game *face* or genre theme preset — do not leave an
|
|
80
|
-
unarranged, unskinned generic dashboard as the product.
|
|
81
|
-
|
|
88
|
+
unarranged, unskinned generic dashboard as the product. Custom markup can use headless
|
|
89
|
+
SDK behavior; a missing reusable behavior is an upstream gap (see `jgengine-ui`).
|
|
82
90
|
|
|
83
91
|
## 3. Author, play, win
|
|
84
92
|
|
|
@@ -9,17 +9,17 @@ description: Build composable, accessible HUDs, menus, feedback, and responsive
|
|
|
9
9
|
|
|
10
10
|
This skill owns player-facing presentation: HUDs, menus, overlays, layout, responsive behavior, accessibility, touch/controller presentation, feedback, previews, and UI chrome. World rendering belongs to `jgengine-world`; state ownership stays in gameplay/combat.
|
|
11
11
|
|
|
12
|
-
Search [capabilities.md](capabilities.md)
|
|
12
|
+
Search [capabilities.md](capabilities.md) by intent and use [api.md](api.md) for signatures. [reference.md](reference.md) is the presentation quality guide (screen inventory, layout modes, main menu, settings, motion, mobile controls, rejection criteria, definition of done); [reference-primitives.md](reference-primitives.md) covers how the shipped blocks compose, rendering/post-processing, and the first-person viewmodel. Visual review uses the scorecard in [jgengine-verify](../jgengine-verify/references/visual-scorecard.md).
|
|
13
13
|
|
|
14
14
|
## Canonical workflow
|
|
15
15
|
|
|
16
|
-
1. Write the game's UI art direction
|
|
17
|
-
2. Define the real UI states: attract, main menu
|
|
16
|
+
1. Write the game's UI art direction before any screen: player fantasy, emotional tone, shape language, material language, typography roles (display / body / numerical / labels), motion, icon, and sound language, information hierarchy, and forbidden patterns (for example generic rounded dashboard cards, pill buttons, long centered paragraphs during play, persistent keyboard-instruction grids, equally weighted bordered panels, website-style modals). A theme is not done when only colors and fonts change; it must also shape composition, geometry, spacing, borders, icons, motion, density, terminology, and touch controls. Stock glass widgets are not a stand-in for this step.
|
|
17
|
+
2. Define the real UI states: attract, main menu, character create/select where relevant, live play, pause, settings, credits, results, empty/error, relevant overlays, and a death/downed screen when the player can die (see product rules).
|
|
18
18
|
3. Read state through selectors/hooks; keep simulation mutation behind commands.
|
|
19
|
-
4. Compose this game's UI
|
|
20
|
-
5. Make keyboard, pointer, touch, controller, focus, and screen-reader behavior explicit.
|
|
21
|
-
6. Add preview fixtures using the real components for fast deterministic capture.
|
|
22
|
-
7. Verify desktop and mobile layouts through `jgengine-verify
|
|
19
|
+
4. Compose this game's UI from the shipped building blocks, then reskin: `InventoryGrid`, `usePanels`/`PanelHost`/`Window` (hotkeys, ESC, and z-stacking above the HUD are handled, so never hand-roll a `z-*` or keydown listener for a window), `CharacterSheet`/`Paperdoll`, stat/vitals bars, action/selection bars, and `EntityPreview` (`@jgengine/shell/render/EntityPreview`) for a live 3D character portrait. Hand-roll markup only where no block fits. When a second presentation is plausible, split data / renderer / chrome (see [reference-primitives.md](reference-primitives.md)).
|
|
20
|
+
5. Make keyboard, pointer, touch, controller, focus, and screen-reader behavior explicit. For dialogs whose open state already belongs to the game, use `useDialogBehavior({ open, onClose })` (`@jgengine/react/dialogBehavior`) and attach its ref to the caller-owned dialog root; keep the skin, accessible name, `role="dialog"`, `aria-modal`, and `tabIndex={-1}` in the game. `ModalHost` shares this behavior when a `ModalStack` owns the state.
|
|
21
|
+
6. Add preview fixtures using the real components for fast deterministic capture. Shipped engine HUD primitives are registered in `@jgengine/react`'s `PREVIEW_FIXTURES`; in the monorepo capture one with `bun run shoot --fixture <name>` (`--list` shows the set).
|
|
22
|
+
7. Verify desktop and mobile layouts through `jgengine-verify`, and check [reference.md](reference.md) §14 rejection criteria and the definition of done before claiming UI complete. A HUD that could pass for another game's default chrome fails visual review.
|
|
23
23
|
|
|
24
24
|
Existing React games keep their entity store and use the focused
|
|
25
25
|
[portable minimap recipe](recipes/portable-minimap.md); no `GameProvider`,
|
|
@@ -27,22 +27,21 @@ Existing React games keep their entity store and use the focused
|
|
|
27
27
|
|
|
28
28
|
## Product rules
|
|
29
29
|
|
|
30
|
-
- **Every game owns its UI end-to-end.** Custom composition, skin, placement, terminology, motion, and one main menu. The website/runner is a bare loader.
|
|
31
|
-
- **The main menu is a game front-end, not marketing.** The runner loads straight into the game's own menu; it offers the real front-end verbs the game supports — New Game, Continue/Load (save slots), Create/Choose character or class, Settings, Credits — each an authored screen in the game's art direction, not a landing page or raw scaffold. See [reference.md](reference.md)
|
|
30
|
+
- **Every game owns its UI end-to-end.** Custom composition, skin, placement, terminology, motion, and one main menu. The website/runner is a bare loader. Composing and reskinning the shipped blocks is correct use; a genre HUD kit, theme preset, or unarranged default stack dropped in as the game's identity is not.
|
|
31
|
+
- **The main menu is a game front-end, not marketing.** The runner loads straight into the game's own menu; it offers the real front-end verbs the game supports — New Game, Continue/Load (save slots), Create/Choose character or class, Settings, Credits — each an authored screen in the game's art direction, not a landing page or raw scaffold. See [reference.md](reference.md#main-menu).
|
|
32
32
|
- **Settings is game-owned and reachable from a sensible place.** Every game ships settings as *its* settings — skinned and placed inline with its UI (main menu and pause), never the engine's stock face floated into a corner. Credits are a reachable in-game screen, not attribution buried in a build artifact.
|
|
33
|
-
- **Route the front-end with `useMenuRouter`, and generate the credits.** `useMenuRouter(root)` is the screen stack behind title → save select → settings → credits: `open`/`back`/`replace`/`reset`, `path` for depth, and Escape-to-back bound by default (`escapeToBack: false` when the game owns Escape). `menuStackReducer` is the same transition as a pure function
|
|
34
|
-
-
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
37
|
-
-
|
|
38
|
-
- **Player death gets a visible screen and respawn feedback — never a silent teleport.** When the game can kill or down the player, build the moment `game-design` requires: an authored death/downed overlay that reads the lethal event, communicates the consequence, and surfaces the way back (respawn/revive/restart affordance) with legible feedback. Drive it from the existing state primitive — `createDownedState` (`@jgengine/core/combat`) already models a downed/bleed-out-then-revive lifecycle — so the screen reflects real state instead of a hand-rolled flag; mount the overlay inside `HudCanvas` like any other window. A lethal hit that just resets position with no on-screen acknowledgement is a presentation gap, not a finished flow.
|
|
33
|
+
- **Route the front-end with `useMenuRouter`, and generate the credits.** `useMenuRouter(root)` is the screen stack behind title → save select → settings → credits: `open`/`back`/`replace`/`reset`, `path` for depth, and Escape-to-back bound by default (`escapeToBack: false` when the game owns Escape). `menuStackReducer` is the same transition as a pure function. For credits, `creditsForSourceIds(ids)` (`@jgengine/assets/credits`) turns the pack ids a game declares to `buildCatalog` into licensed, attributed sections, `mergeCredits` folds them into hand-authored lines, and `CreditsScreen` renders the result HudTheme-skinned.
|
|
34
|
+
- **Skin the shared chrome with one `HudTheme` token object.** `hudThemeVars(theme)` emits the whole `--jg-*` vocabulary — bar fills and troughs, `HudFrame variation="themed"`, painted slots, the minimap ring, plus surfaces, edges, text, status colors, fonts, and rarity — so one theme spread on any HUD ancestor reskins the `@jgengine/react` primitives and the `registry/jgengine` blocks together. Author your own with `deriveHudTheme({ accent, surface })` or `hudTheme({ ... })`; `HUD_THEME_PRESETS` / `resolveHudTheme("<preset>")` are demo/scaffold starting points, never a game's identity. A component that needs a token no theme emits fails `check-hud-tokens` — add it to `HudTheme` rather than inventing a second vocabulary. Caller `style`/`renderItem` overrides still win.
|
|
35
|
+
- **Paint slot icons with `IconTreatment`, never render raw `itemId` strings.** It draws a `GameIcon` glyph over a school/element-keyed gradient with gloss, vignette, and optional count/keycap badges, reading the `--jg-slot-*` / `--jg-accent` tokens. `treatedItemIcon(itemId)` / `treatedActionIcon(action)` are ready adapters for hotbars and ability bars.
|
|
36
|
+
- **Player death gets a visible screen and respawn feedback — never a silent teleport.** Build the moment `game-design` requires: an authored death/downed overlay that reads the lethal event, communicates the consequence, and surfaces the way back (respawn/revive/restart). Drive it from `createDownedState` (`@jgengine/core/combat`) rather than a hand-rolled flag, and mount it inside `HudCanvas`.
|
|
37
|
+
- **Browser interruption listeners are shared.** Use `useBrowserSuspension` from `@jgengine/react/browserLifecycle` for blur, hidden-page and pointer-lock loss. Keep the decision to pause, release controls or preserve multiplayer simulation in the callback; use options to disable unwanted triggers.
|
|
39
38
|
- Layout and skin remain caller-controlled; shared primitives own reusable behavior, not product look.
|
|
39
|
+
- Use `ScrollRail` for horizontal controls that can overflow: visible navigation and focus reveal keep every item reachable while the caller owns markup and selection. Keep item widths from shrinking when labels must stay readable.
|
|
40
40
|
- SSR-visible output is hydration-stable; round computed SVG values at the boundary.
|
|
41
41
|
|
|
42
42
|
## Shared-world interaction rules
|
|
43
43
|
|
|
44
44
|
- Every rejected verb displays its reason on the triggering surface. Use `useServerSession(transport, gameId)` for join lifecycle. Join failure blocks play with `JoinGate` and retry; returning `{ ok: false }` without feedback is incomplete.
|
|
45
|
-
- The first tutorial verb works within 60 seconds from spawn with starting inventory. Land, power, and slots are granted or purchasable in-context; tutorial locks must not hide prerequisites.
|
|
46
45
|
- Placement previews display claim cost and affordability inline with `TerritoryOverlay`.
|
|
47
46
|
- `ChatPanel` owns collapsed/expanded state, own-message styling, Enter focus and Escape blur; standalone hosts pass `messages`, `userId`, and `onSend` (typed `{ ok, reason }`), while context-backed games use channel props. Use native inputs so shell typing-target suspension applies.
|
|
48
47
|
- Register Tailwind `@source` for consumed package files and inspect `bun run shoot <gameId> --mode ui` captures of join, chat, and placement feedback.
|
|
@@ -53,4 +52,4 @@ Existing React games keep their entity store and use the focused
|
|
|
53
52
|
- Do not duplicate inventory, combat, quest, or selection state inside components.
|
|
54
53
|
- A static facsimile preview does not test the real UI; compose production components with fixtures.
|
|
55
54
|
- Visual quality is judged from rendered evidence, not component counts or prose.
|
|
56
|
-
- Shown HUD UI must fit the player viewport. `HudCanvas`
|
|
55
|
+
- Shown HUD UI must fit the player viewport. `HudCanvas` checks every registered `HudPanel`, any element tagged `data-hud-window`, and its own direct children: a *visible* surface crossing a viewport edge gets a red dev overlay, a `console.warn`, and `data-hud-overflow` (which fails `bun run shoot`). Hidden or parked surfaces never trip it; deliberate bleed opts out with `data-hud-allow-overflow`. Mount custom windows inside `HudCanvas` (tag deeper ones `data-hud-window`) so the check can see them.
|