@jgengine/shell 0.11.0 → 0.12.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.
Files changed (130) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/CombatPresentation.d.ts +5 -0
  3. package/dist/CombatPresentation.js +8 -0
  4. package/dist/GameHost.d.ts +25 -1
  5. package/dist/GameHost.js +60 -4
  6. package/dist/GamePlayer.d.ts +5 -0
  7. package/dist/GamePlayer.js +5 -0
  8. package/dist/GamePlayerShell.d.ts +5 -0
  9. package/dist/GamePlayerShell.js +48 -358
  10. package/dist/GameUiPreview.js +3 -0
  11. package/dist/Shell3dPresentation.d.ts +63 -0
  12. package/dist/Shell3dPresentation.js +302 -0
  13. package/dist/ShellChrome.d.ts +51 -0
  14. package/dist/ShellChrome.js +51 -0
  15. package/dist/ShellHudPresentation.d.ts +41 -0
  16. package/dist/ShellHudPresentation.js +22 -0
  17. package/dist/audio/audioEngine.d.ts +4 -0
  18. package/dist/audio/audioEngine.js +111 -26
  19. package/dist/audio/audioWire.d.ts +22 -4
  20. package/dist/audio/audioWire.js +46 -3
  21. package/dist/audio/loopParams.d.ts +20 -0
  22. package/dist/audio/loopParams.js +28 -0
  23. package/dist/camera/GameCameraRig.js +6 -1
  24. package/dist/camera/cameraRigs.d.ts +3 -1
  25. package/dist/camera/cameraRigs.js +21 -3
  26. package/dist/camera/rigMath.d.ts +20 -0
  27. package/dist/camera/rigMath.js +29 -0
  28. package/dist/defineGame.d.ts +15 -1
  29. package/dist/defineGame.js +26 -4
  30. package/dist/devtools/DevtoolsOverlay.d.ts +4 -4
  31. package/dist/devtools/DevtoolsOverlay.js +28 -12
  32. package/dist/devtools/agentBridge.js +4 -0
  33. package/dist/devtools/perfDiagnose.js +1 -1
  34. package/dist/diagnostics/RuntimeDiagnostics.d.ts +7 -0
  35. package/dist/diagnostics/RuntimeDiagnostics.js +23 -12
  36. package/dist/environment/EnvironmentScene.js +12 -3
  37. package/dist/environment/terrainGroundColor.d.ts +9 -0
  38. package/dist/environment/terrainGroundColor.js +22 -0
  39. package/dist/gameKit.d.ts +27 -0
  40. package/dist/gameKit.js +29 -0
  41. package/dist/map/MapMarkerBeacons.d.ts +3 -2
  42. package/dist/postfx/PostProcessing.d.ts +9 -1
  43. package/dist/postfx/PostProcessing.js +11 -4
  44. package/dist/presentationResolve.d.ts +35 -0
  45. package/dist/presentationResolve.js +51 -0
  46. package/dist/registry.d.ts +1 -0
  47. package/dist/render/assetBase.d.ts +17 -0
  48. package/dist/render/assetBase.js +35 -0
  49. package/dist/render/modelLoad.js +4 -1
  50. package/dist/render/resolveModel.d.ts +15 -0
  51. package/dist/render/resolveModel.js +37 -2
  52. package/dist/scatter/InstancedScatter.js +5 -0
  53. package/dist/scatter/scatterProxies.js +24 -0
  54. package/dist/scene/AuthoredScene.d.ts +3 -1
  55. package/dist/scene/AuthoredScene.js +7 -2
  56. package/dist/scene/CityRenderer.d.ts +2 -0
  57. package/dist/scene/CityRenderer.js +1031 -0
  58. package/dist/scene/GrassFieldRenderer.js +53 -5
  59. package/dist/scene/PoleLineRenderer.d.ts +2 -0
  60. package/dist/scene/PoleLineRenderer.js +287 -0
  61. package/dist/scene/SoilPatchRenderer.js +70 -7
  62. package/dist/scene/WaterRenderer.js +34 -10
  63. package/dist/scene/builtinSceneKindRenderers.js +4 -0
  64. package/dist/scene/cityWindowMaterial.d.ts +16 -0
  65. package/dist/scene/cityWindowMaterial.js +81 -0
  66. package/dist/scene/sceneKindRenderers.d.ts +2 -0
  67. package/dist/settings/appliedSettings.d.ts +2 -1
  68. package/dist/settings/appliedSettings.js +4 -2
  69. package/dist/structures/TransformGizmo.d.ts +11 -1
  70. package/dist/structures/TransformGizmo.js +9 -5
  71. package/dist/terrain/GrassField.d.ts +11 -3
  72. package/dist/terrain/GrassField.js +16 -6
  73. package/dist/terrain/grassGeometry.d.ts +33 -1
  74. package/dist/terrain/grassGeometry.js +83 -21
  75. package/dist/terrain/grassMaterial.d.ts +18 -0
  76. package/dist/terrain/grassMaterial.js +66 -13
  77. package/dist/terrain/heightfieldGeometry.d.ts +34 -0
  78. package/dist/terrain/heightfieldGeometry.js +109 -0
  79. package/dist/terrain/index.d.ts +1 -0
  80. package/dist/terrain/index.js +1 -0
  81. package/dist/terrain/soilPatchMaterial.d.ts +15 -2
  82. package/dist/terrain/soilPatchMaterial.js +46 -8
  83. package/dist/terrain/terrainDetailMaterial.js +15 -2
  84. package/dist/water/Ocean.d.ts +7 -1
  85. package/dist/water/Ocean.js +16 -3
  86. package/dist/water/OceanConfig.d.ts +9 -0
  87. package/dist/water/OceanConfig.js +6 -0
  88. package/dist/water/OceanMaterial.d.ts +12 -0
  89. package/dist/water/OceanMaterial.js +9 -0
  90. package/dist/water/OceanShader.d.ts +2 -2
  91. package/dist/water/OceanShader.js +78 -10
  92. package/dist/world/PlaceScene.d.ts +11 -0
  93. package/dist/world/PlaceScene.js +27 -0
  94. package/dist/world/WorldScene.js +29 -2
  95. package/dist/worldSky.d.ts +7 -1
  96. package/dist/worldSky.js +11 -1
  97. package/package.json +4 -4
  98. package/skills/game-design/SKILL.md +28 -0
  99. package/skills/game-design/agents/openai.yaml +4 -0
  100. package/skills/game-design/references/application-playbook.md +170 -0
  101. package/skills/game-design/references/field-guide.md +288 -0
  102. package/skills/jgengine/SKILL.md +7 -4
  103. package/skills/jgengine/api.md +172 -79
  104. package/skills/jgengine/capabilities.md +104 -2
  105. package/skills/jgengine/recipes/minimal-game.md +88 -0
  106. package/skills/jgengine-ui/SKILL.md +15 -10
  107. package/skills/jgengine-ui/api.md +202 -47
  108. package/skills/jgengine-ui/capabilities.md +71 -2
  109. package/skills/jgengine-ui/recipes/portable-minimap.md +150 -0
  110. package/skills/jgengine-ui/reference.md +20 -7
  111. package/skills/jgengine-ui/references/visual-scorecard.md +1 -1
  112. package/skills/jgengine-world/SKILL.md +13 -0
  113. package/skills/jgengine-world/api.md +419 -15
  114. package/skills/jgengine-world/capabilities.md +108 -2
  115. package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
  116. package/skills/jgengine-world/reference.md +43 -4
  117. package/skills/level-design/SKILL.md +54 -0
  118. package/skills/level-design/agents/openai.yaml +4 -0
  119. package/skills/level-design/references/application-playbook.md +192 -0
  120. package/skills/level-design/references/field-guide.md +337 -0
  121. package/skills/level-design/references/live-editor-loop.md +179 -0
  122. package/dist/cartridge/runtime.d.ts +0 -15
  123. package/dist/cartridge/runtime.js +0 -556
  124. package/dist/cartridge/spec.d.ts +0 -188
  125. package/dist/cartridge/spec.js +0 -19
  126. package/dist/cartridge/validate.d.ts +0 -2
  127. package/dist/cartridge/validate.js +0 -78
  128. package/dist/cartridge.d.ts +0 -145
  129. package/dist/cartridge.js +0 -246
  130. package/skills/jgengine/reference-cartridge.md +0 -72
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { DefaultSurface } from "../render/defaultSurface.js";
4
+ /** Render extent (m) standing in for an `Infinity` flat-ground axis — far past the default fog. */
5
+ const UNBOUNDED_RENDER_EXTENT = 2048;
6
+ const GROUND_COLOR = "#5c6b52";
7
+ function clampExtent(value) {
8
+ return Number.isFinite(value) ? value : UNBOUNDED_RENDER_EXTENT;
9
+ }
10
+ /**
11
+ * The substrate of a place world, rendered plainly: a flat slab or a round planet under the engine
12
+ * default sky. This is deliberately not a diorama — sky look, foliage, props, and sculpt are scene
13
+ * content the editor authors; `voxel` grounds are realized by the game's generation systems and
14
+ * `board` grounds by the game's own 2D face, so both mount nothing here.
15
+ * @internal
16
+ */
17
+ export function PlaceScene({ feature }) {
18
+ const ground = feature.ground;
19
+ const size = useMemo(() => ground.mode === "flat" ? [clampExtent(ground.size.x), clampExtent(ground.size.z)] : undefined, [ground]);
20
+ if (ground.mode === "flat" && size !== undefined) {
21
+ return (_jsxs("mesh", { "rotation-x": -Math.PI / 2, receiveShadow: true, children: [_jsx("planeGeometry", { args: [size[0], size[1]] }), _jsx(DefaultSurface, { color: GROUND_COLOR, roughness: 0.95 })] }));
22
+ }
23
+ if (ground.mode === "round") {
24
+ return (_jsxs("mesh", { position: [0, -ground.size.radius, 0], receiveShadow: true, children: [_jsx("sphereGeometry", { args: [ground.size.radius, 64, 48] }), _jsx(DefaultSurface, { color: GROUND_COLOR, roughness: 0.95 })] }));
25
+ }
26
+ return null;
27
+ }
@@ -4,6 +4,7 @@ import { useEffect, useMemo, useRef } from "react";
4
4
  import * as THREE from "three";
5
5
  import { objectVisualScale } from "@jgengine/core/scene/objectStore";
6
6
  import { WORLD_ITEM_ENTITY_NAME } from "@jgengine/core/game/worldItem";
7
+ import { beginFallbackSeam, endFallbackPass, reportFallbackSeam, } from "@jgengine/core/devtools/fallbackSeams";
7
8
  import { useGameContext } from "@jgengine/react/provider";
8
9
  import { useSceneEntityIds, useSceneObjectIds, useGameStore, usePlayer, useTarget } from "@jgengine/react/hooks";
9
10
  import { colorFromId } from "../worldSky.js";
@@ -118,8 +119,12 @@ function RockField() {
118
119
  return (_jsx(_Fragment, { children: rocks.map((rock) => (_jsxs("mesh", { position: [rock.x, 0.25 * rock.scale, rock.z], rotation: [0.1, rock.rotation, -0.08], scale: [rock.scale * 1.4, rock.scale * 0.7, rock.scale], castShadow: true, receiveShadow: true, children: [_jsx("dodecahedronGeometry", { args: [0.8, 1] }), _jsx(DefaultSurface, { color: "#6b6f63", roughness: 0.95 })] }, rock.id))) }));
119
120
  }
120
121
  function WorldEnvironment({ environment: Environment }) {
122
+ // Dev diagnostic (no-op unless armed): a missing environment component means the default green
123
+ // ground/rocks stand in for an unauthored scene. Re-zero then report so this is idempotent.
124
+ beginFallbackSeam("ground");
121
125
  if (Environment !== undefined)
122
126
  return _jsx(Environment, {});
127
+ reportFallbackSeam("ground", "noScene");
123
128
  return (_jsxs(_Fragment, { children: [_jsx(GroundPlane, {}), _jsx(RockField, {})] }));
124
129
  }
125
130
  function WorldActors({ entitySprites, entityModels, objectModels, objectStyles, assets, renderEntity, renderObject, selectedIds, hideLocalActor, }) {
@@ -133,22 +138,44 @@ function WorldActors({ entitySprites, entityModels, objectModels, objectStyles,
133
138
  const relation = ctx.scene.entity.canReceive(entity.id, "damage") === null ? "hostile" : "friendly";
134
139
  ctx.scene.entity.setTarget(controlledId, relation === "hostile" || entity.role === "npc" ? entity.id : null);
135
140
  };
141
+ // Dev diagnostic (no-op unless armed): re-zero the entity/object seams before this render re-tallies
142
+ // which actors fall back to primitives. Committing the log runs in a useEffect after the render.
143
+ beginFallbackSeam("entity");
144
+ beginFallbackSeam("object");
145
+ useEffect(() => {
146
+ endFallbackPass();
147
+ });
136
148
  return (_jsxs(_Fragment, { children: [entityIds.map((entityId) => {
137
149
  const entity = ctx.scene.entity.get(entityId);
138
150
  if (entity === null || entity.name === WORLD_ITEM_ENTITY_NAME)
139
151
  return null;
140
152
  if (hideLocalActor && entityId === controlledId)
141
153
  return null;
142
- return (_jsx(EntityMarker, { entity: entity, custom: renderEntity?.(entity), model: resolveEntityModel(entityModels?.[entity.name], assets, entity.name), sprite: entitySprites?.[entity.name], isLocal: entityId === controlledId, targeted: entityId === targetId, selected: selectedIds.has(entityId), onSelect: handleSelect }, entityId));
154
+ const custom = renderEntity?.(entity);
155
+ const model = resolveEntityModel(entityModels?.[entity.name], assets, entity.name);
156
+ const sprite = entitySprites?.[entity.name];
157
+ // Entity models resolve via the hard resolveModel (throws on a present-but-missing id), so
158
+ // reaching the primitive capsule with no model or sprite means the mapping was omitted.
159
+ if ((custom === undefined || custom === null) && model === undefined && sprite === undefined) {
160
+ reportFallbackSeam("entity", "omittedMapping");
161
+ }
162
+ return (_jsx(EntityMarker, { entity: entity, custom: custom, model: model, sprite: sprite, isLocal: entityId === controlledId, targeted: entityId === targetId, selected: selectedIds.has(entityId), onSelect: handleSelect }, entityId));
143
163
  }), objectIds.map((instanceId) => {
144
164
  const object = ctx.scene.object.get(instanceId);
145
165
  if (object === null)
146
166
  return null;
167
+ const custom = renderObject?.(object);
147
168
  const model = resolveModel(objectModels?.[object.catalogId], assets, {
148
169
  seam: "objectModels",
149
170
  key: object.catalogId,
150
171
  }) ?? tryResolveCatalogModel(object.catalogId, assets);
151
- return (_jsx(ObjectMarker, { object: object, custom: renderObject?.(object), model: model, style: objectStyles?.[object.catalogId] }, instanceId));
172
+ const style = objectStyles?.[object.catalogId];
173
+ // Reaching the primitive box means no model resolved. A present-but-unresolved objectModels
174
+ // key implies its asset pack is not pulled; an absent key is an omitted (often intended) mapping.
175
+ if ((custom === undefined || custom === null) && model === undefined && style?.hidden !== true) {
176
+ reportFallbackSeam("object", objectModels?.[object.catalogId] === undefined ? "omittedMapping" : "unpulledPack");
177
+ }
178
+ return (_jsx(ObjectMarker, { object: object, custom: custom, model: model, style: style }, instanceId));
152
179
  })] }));
153
180
  }
154
181
  export function WorldView({ entitySprites, entityModels, objectModels, objectStyles, environment, assets, renderEntity, renderObject, selectedIds, hideLocalActor, }) {
@@ -1,5 +1,11 @@
1
1
  import type { SkyEnvironmentDescriptor, WorldFeature } from "@jgengine/core/world/features";
2
- /** The world's declared sky, when its world feature is an environment with one (#196.1). @internal */
2
+ /**
3
+ * The sky in effect for a world feature (#196.1). Environments answer their declared sky; place
4
+ * worlds (`world()` — substrate + laws, no sky fields) get the engine default sky for 3D grounds,
5
+ * while `board` grounds get none (the game owns the 2D face it draws). An authored scene document's
6
+ * sky arrives through `backdrop`/`lighting`, which wins over this at the presentation layer.
7
+ * @internal
8
+ */
3
9
  export declare function resolveWorldSky(world: WorldFeature | undefined): SkyEnvironmentDescriptor | undefined;
4
10
  /** Deterministic HSL color from a stable instance id (default entity/object tint). @internal */
5
11
  export declare function colorFromId(id: string): string;
package/dist/worldSky.js CHANGED
@@ -1,5 +1,15 @@
1
- /** The world's declared sky, when its world feature is an environment with one (#196.1). @internal */
1
+ /** The engine default sky a 3D place world renders when no sky is authored in its scene document. */
2
+ const PLACE_DEFAULT_SKY = { kind: "sky", preset: "day", timeOfDay: false };
3
+ /**
4
+ * The sky in effect for a world feature (#196.1). Environments answer their declared sky; place
5
+ * worlds (`world()` — substrate + laws, no sky fields) get the engine default sky for 3D grounds,
6
+ * while `board` grounds get none (the game owns the 2D face it draws). An authored scene document's
7
+ * sky arrives through `backdrop`/`lighting`, which wins over this at the presentation layer.
8
+ * @internal
9
+ */
2
10
  export function resolveWorldSky(world) {
11
+ if (world?.kind === "place")
12
+ return world.ground.mode === "board" ? undefined : PLACE_DEFAULT_SKY;
3
13
  return world?.kind === "environment" ? world.sky : undefined;
4
14
  }
5
15
  /** Deterministic HSL color from a stable instance id (default entity/object tint). @internal */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jgengine/shell",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Game player shell for JGengine: React Three Fiber canvas, orbit camera, input tracking, HUD mounting, GameUiPreview, and a demo game. Consumers supply a GameRegistry.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -35,9 +35,9 @@
35
35
  "test": "bun test src"
36
36
  },
37
37
  "dependencies": {
38
- "@jgengine/core": "^0.11.0",
39
- "@jgengine/react": "^0.11.0",
40
- "@jgengine/ws": "^0.11.0"
38
+ "@jgengine/core": "^0.12.0",
39
+ "@jgengine/react": "^0.12.0",
40
+ "@jgengine/ws": "^0.12.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@react-three/drei": "^10.0.0",
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: game-design
3
+ description: Design, audit, implement, and validate player experience, loops, systems, progression, and balance.
4
+ ---
5
+
6
+ # Game design
7
+
8
+ ## Ownership
9
+
10
+ Own the intended player experience and the rules that produce it: fantasy, pillars, verbs, decisions, feedback, loops, resources, progression, challenge, failure, onboarding, and social dynamics. Treat design claims as hypotheses proved by play, not a feature inventory or genre imitation — no genre kits, presets, or archetypes; every game is a custom composition of needs (see [AGENTS.md](../../../AGENTS.md)).
11
+
12
+ Use `level-design` for spatial realization; route implementation to `jgengine-gameplay`, `jgengine-world`, `jgengine-combat`, `jgengine-ui`, `jgengine-multiplayer` once intent is coherent.
13
+
14
+ Read [references/application-playbook.md](references/application-playbook.md) only when the task explicitly calls for design depth — a design brief, a redesign, or "make this fun/better" work; it is not a mandatory step of creating a game. Read [references/field-guide.md](references/field-guide.md) when the task needs deeper loop, economy, progression, genre, accessibility, or research guidance.
15
+
16
+ ## Choose the mode
17
+
18
+ Greenfield: produce a vertical-slice contract (promise, pillars, core decision, loops, progression, failure/recovery) and build the smallest slice testing the riskiest assumption — see playbook §1. Existing game: reconstruct what it actually does from code and play, rank root problems by impact/confidence/reach/effort — see playbook §2.
19
+
20
+ “Improve with game design” is an implementation request, not just an audit: select the highest-leverage intervention, implement it through shared engine seams, and prove the changed player behavior.
21
+
22
+ ## Required output contract
23
+
24
+ Every design pass yields an observed journey, a north star (promise, pillars, anti-pillars, core decision), a loop/flow model, a ranked bottleneck list with cited evidence, an intervention stack, a chosen design slice, and acceptance evidence. See [references/application-playbook.md](references/application-playbook.md) for the full contract and execution rules (verb->feedback->consequence chains, loop/progression/challenge discipline, upstream ownership).
25
+
26
+ ## Completion
27
+
28
+ An audit is not completion for a build/improve request. Finish when the slice is playable, a fresh player can state goal/choice/consequence, failure/recovery behave as intended, and evidence supports the pillars. Use `jgengine-verify` and `workflow` to ship.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Game Design"
3
+ short_description: "Design coherent game loops and systems"
4
+ default_prompt: "Use $game-design to audit or design this game, implement its highest-leverage design slice, and prove the changed player behavior."
@@ -0,0 +1,170 @@
1
+ # Applying game design
2
+
3
+ Use this playbook to turn a pitch or an existing game into implemented, testable change. Its purpose is to prevent “design work” from ending as generic advice.
4
+
5
+ ## Contents
6
+
7
+ 1. Greenfield procedure
8
+ 2. Existing-game audit
9
+ 3. Mandatory models
10
+ 4. Ranking interventions
11
+ 5. Design-slice specification
12
+ 6. Implementation and proof
13
+ 7. Failure modes
14
+
15
+ ## 1. Greenfield procedure
16
+
17
+ ### Frame the bet
18
+
19
+ Write a compact contract before broad code or content:
20
+
21
+ | Field | Required form |
22
+ | --- | --- |
23
+ | audience/context | prior skills, player count, platform/input, session length, accessibility assumptions |
24
+ | player promise | “The player repeatedly [verb/decision] so they feel [specific experience]” |
25
+ | pillars | two or three observable behaviors or feelings |
26
+ | anti-pillars | experiences the game must not drift toward |
27
+ | core decision | situation, known information, viable options, tradeoff, consequence, recurrence |
28
+ | completion proof | one end-to-end scenario a target player can perform and explain |
29
+ | falsifier | observation that would show the design does not work |
30
+
31
+ ### Build the minimum design
32
+
33
+ 1. Model each core verb from cue through future consequence.
34
+ 2. Draw moment, encounter, session, and meta loops.
35
+ 3. Draw resources and feedback structures.
36
+ 4. Map player skills and progression channels.
37
+ 5. Define failure, recovery, stopping, and replay.
38
+ 6. Create a content grammar: a small set of mechanics crossed with contexts and constraints.
39
+ 7. Select the riskiest assumption and build one vertical design slice around it.
40
+
41
+ Do not build the entire feature list first. A vertical slice contains real input, meaningful state, feedback, one decision that recurs, failure/recovery, and a downstream consequence.
42
+
43
+ ## 2. Existing-game audit
44
+
45
+ ### Reconstruct reality
46
+
47
+ Inspect actual code, catalogs, scene documents, UI, tests, captures, and live play. Do not infer the game from its title or README.
48
+
49
+ Trace four journeys when applicable:
50
+
51
+ - **first minute:** first input, goal, threat, reward, confusion, and reason to continue
52
+ - **first objective:** learning sequence, decisions, failure, recovery, payoff, and next goal
53
+ - **representative session:** loop renewal, variety, resource pressure, build choices, pacing, and stopping point
54
+ - **campaign/meta:** unlock cadence, content reuse, escalation, economy stability, mastery, and ending/replay
55
+
56
+ For each journey, record timestamps or event order:
57
+
58
+ `cue -> player belief -> action -> system response -> feedback -> state change -> next choice`
59
+
60
+ Mark dead time, repeated decisions, forced actions, hidden consequences, false affordances, unexplained failure, and rewards that do not alter later play.
61
+
62
+ ### Build a system-coupling map
63
+
64
+ Inventory verbs, enemies/problems, items/tools, progression, economy, quests/objectives, world states, social systems, and failure. For each system ask:
65
+
66
+ - Which pillar does it serve?
67
+ - Which loop consumes its output?
68
+ - What player decision does it create or transform?
69
+ - Where is it taught, tested, combined, and mastered?
70
+ - What happens if it is removed?
71
+
72
+ Flag systems that are present but disconnected, content whose only variation is numbers or nouns, and rewards that bypass the core play.
73
+
74
+ ### Diagnose decision density
75
+
76
+ Do not maximize decisions per second. Find long spans where the player executes an already-solved action without new information, tradeoffs, expression, pressure, or mastery. Measure:
77
+
78
+ - time to first meaningful decision
79
+ - meaningful decisions per encounter/objective
80
+ - time between new information and commitment
81
+ - percentage of objectives using each verb or decision type
82
+ - repeated content before context changes
83
+ - time from failure to a useful retry
84
+
85
+ ## 3. Mandatory models
86
+
87
+ ### Loop table
88
+
89
+ | Horizon | Cue/goal | Decision/action | Feedback | State changed | Why repeat? | Failure risk |
90
+ | --- | --- | --- | --- | --- | --- | --- |
91
+
92
+ Reject any row whose “state changed” or “why repeat” is empty.
93
+
94
+ ### Resource-flow table
95
+
96
+ | Resource | Source | Store/cap | Spend/convert | Sink | Player decision | Feedback/runaway risk |
97
+ | --- | --- | --- | --- | --- | --- | --- |
98
+
99
+ Include time, health, space, information, attention, action opportunities, and social trust when relevant.
100
+
101
+ ### Progression table
102
+
103
+ | Unlock/reward | Channel | New decision or capability | Content it recontextualizes | Risk of invalidation/grind | Proof |
104
+ | --- | --- | --- | --- | --- | --- |
105
+
106
+ Channels are mastery, access, breadth, power, and expression/status. Passive percentages without a changed decision must justify their place.
107
+
108
+ ### Objective/encounter variety matrix
109
+
110
+ Cross objective verbs with information state, constraints, enemy/problem behavior, topology, resource pressure, failure condition, and consequence. This exposes campaigns where every mission is the same verb with different nouns.
111
+
112
+ ## 4. Ranking interventions
113
+
114
+ Separate symptoms from root causes. “Quests are boring” is a symptom. “Every quest uses the same kill-count transition and no objective changes space, resources, or strategy” is a testable cause.
115
+
116
+ Rank each candidate:
117
+
118
+ | Candidate | Player behavior changed | Pillar impact | Reach | Evidence/confidence | Effort/risk | Dependencies | Shared owner |
119
+ | --- | --- | --- | --- | --- | --- | --- | --- |
120
+
121
+ Use three horizons:
122
+
123
+ - **Minimum correction:** remove the largest contradiction or unblock the loop.
124
+ - **Strong target:** make one representative slice deliver the promise end to end.
125
+ - **Multiplier:** expand the proven grammar across content, progression, social play, or replay.
126
+
127
+ Choose by leverage, not novelty. Prefer a change that improves many encounters or future games over bespoke content with the same underlying decision.
128
+
129
+ ## 5. Design-slice specification
130
+
131
+ The selected slice must state:
132
+
133
+ - before behavior and evidence
134
+ - target behavior and player belief
135
+ - mechanics/dynamics expected to cause the change
136
+ - objective/encounter sequence and pacing beats
137
+ - resources, rewards, failure, recovery, and downstream consequence
138
+ - affected catalogs/config, shared package seams, scene semantics, UI feedback, and tests
139
+ - tuning variables with starting hypotheses and safe bounds
140
+ - explicit non-goals and content held constant
141
+ - acceptance scenario and falsifiers
142
+
143
+ If another game could use the mechanic, define the package primitive first and adopt it here. Keep game-local code for content and feel.
144
+
145
+ ## 6. Implementation and proof
146
+
147
+ When the user asks to build or improve:
148
+
149
+ 1. Implement the shared primitive or use an existing capability.
150
+ 2. Adopt it in one complete game slice.
151
+ 3. Author spatial content through `level-design` and the editor.
152
+ 4. Add deterministic tests for transitions, resources, failure, and progression.
153
+ 5. Exercise the observable scenario with representative input.
154
+ 6. Capture before/after evidence for behavior, not only appearance.
155
+ 7. Evaluate the falsifier honestly; revise or remove a failed intervention.
156
+
157
+ Useful evidence includes time to first decision, objective completion, route choice, build choice, resource state, failure cause, retry time, objective-verb distribution, and a player’s ability to explain goal/action/consequence. Metrics need a named hypothesis; do not optimize them in isolation.
158
+
159
+ ## 7. Failure modes
160
+
161
+ - producing a long GDD instead of a playable slice
162
+ - listing features without naming changed decisions
163
+ - adding content to a shallow objective grammar
164
+ - using passive progression to disguise unchanged play
165
+ - copying a genre’s surface without its causal dynamics
166
+ - treating more rewards as more motivation
167
+ - fixing comprehension only with text or HUD
168
+ - reporting a diagnosis after the user asked for improvement
169
+ - calling deterministic tests proof that the experience works
170
+ - calling a prettier screenshot proof that the loop works
@@ -0,0 +1,288 @@
1
+ # Game design field guide
2
+
3
+ Use this reference when a task needs more than the canonical workflow in [`SKILL.md`](../SKILL.md). It is a synthesis of research and shipped-game practice, not a universal formula. Select the tools that expose the current design risk and validate them with players.
4
+
5
+ ## Contents
6
+
7
+ 1. Experience hypotheses
8
+ 2. Actions, feedback, and decisions
9
+ 3. Nested loops
10
+ 4. Systems and economies
11
+ 5. Progression and challenge
12
+ 6. Onboarding and accessibility
13
+ 7. Multiplayer and social play
14
+ 8. Content structure and genre lenses
15
+ 9. Prototyping and playtesting
16
+ 10. JGengine translation
17
+ 11. Diagnostic questions
18
+ 12. Research basis
19
+
20
+ ## 1. Experience hypotheses
21
+
22
+ ### Write a working contract
23
+
24
+ Use a compact table in the issue, task, or conversation. Do not preserve speculative prose as a large design document.
25
+
26
+ | Question | Useful answer | Weak answer |
27
+ | --- | --- | --- |
28
+ | Who plays, where, and for how long? | “Two friends, 20-minute online co-op runs” | “Everyone” |
29
+ | What do they repeatedly do? | “Scout, plan a breach, improvise when it fails” | “Experience action” |
30
+ | What should dominate the experience? | “Tense coordination, expressive tools, recoverable chaos” | “Fun and immersive” |
31
+ | What must it not become? | “Inventory chores, solved loadouts, long spectator time” | “Not boring” |
32
+ | What proves the loop? | “A new pair completes one objective, explains its failure, and chooses a different second approach” | “Players like it” |
33
+
34
+ Treat pillars as prioritization constraints. Make each pillar observable and give it an anti-pillar. When two features conflict, the pillar decides which survives.
35
+
36
+ ### Trace experience in both directions
37
+
38
+ Use the Mechanics-Dynamics-Aesthetics separation as a causal check:
39
+
40
+ - **Experience:** the intended emotional or social response.
41
+ - **Dynamics:** the behavior that should emerge during play.
42
+ - **Mechanics:** the rules, data, controls, and feedback likely to produce that behavior.
43
+
44
+ Design backward from experience, then simulate forward from mechanics. A stealth meter does not guarantee tension; examine whether information, enemy response, recovery, and level geometry actually produce cautious planning.
45
+
46
+ Use autonomy, competence, and relatedness as diagnostics, not mandatory quotas:
47
+
48
+ - **Autonomy:** choices allow ownership and expression rather than cosmetic branching.
49
+ - **Competence:** players can understand improvement and attribute outcomes to actions.
50
+ - **Relatedness:** players can contribute, recognize others, and form meaningful social context.
51
+
52
+ ## 2. Actions, feedback, and decisions
53
+
54
+ ### Model a playable verb
55
+
56
+ For every core verb, specify:
57
+
58
+ 1. cue and available information
59
+ 2. player intention and input
60
+ 3. target and eligibility rules
61
+ 4. simulation/state transition
62
+ 5. immediate visual, audio, haptic, and systemic feedback
63
+ 6. consequence that affects a later choice
64
+ 7. skill the player is expected to learn
65
+ 8. counterplay, cost, risk, or limitation
66
+
67
+ An animation without a state consequence is presentation. A state change the player cannot perceive cannot reliably teach. Good moment-to-moment feel combines predictable physical response, amplified event importance, and assistance that honors player intention.
68
+
69
+ ### Test whether a choice is meaningful
70
+
71
+ A decision usually needs:
72
+
73
+ - at least two viable options the player can distinguish
74
+ - enough information to form a plan, with uncertainty appropriate to the fantasy
75
+ - a tradeoff rather than a universally dominant answer
76
+ - a perceivable consequence at the promised time scale
77
+ - an effect on future state, knowledge, position, relationships, or opportunity
78
+
79
+ Not every input needs strategic depth. Execution, expression, discovery, role-play, and timing can carry play. Be precise about which kind of agency the design promises.
80
+
81
+ Audit common choice failures:
82
+
83
+ - **blind:** relevant information arrives only after commitment
84
+ - **fake:** outcomes converge without expressive or narrative value
85
+ - **solved:** one option dominates across contexts
86
+ - **noisy:** feedback cannot be attributed to the choice
87
+ - **overloaded:** too many new variables must be evaluated at once
88
+ - **inert:** consequence does not alter anything the player values
89
+
90
+ ## 3. Nested loops
91
+
92
+ ### Loop anatomy
93
+
94
+ Write each loop as:
95
+
96
+ `state/cue -> goal -> informed action -> simulation -> feedback -> changed state -> next decision`
97
+
98
+ The return state must differ in a useful way: new information, depleted or gained resources, changed position, higher mastery, altered relationships, new capability, or escalated world state. “Fight enemies, get loot, repeat” is incomplete until the design explains how loot changes subsequent fights and why choices remain interesting.
99
+
100
+ ### Time horizons
101
+
102
+ | Horizon | Typical concern | Validation |
103
+ | --- | --- | --- |
104
+ | moment-to-moment | control, targeting, timing, feedback | Can players predict and correct an action? |
105
+ | encounter/task | tactics, puzzle, risk, recovery | Do multiple verbs and resources create decisions? |
106
+ | session/run | pacing, goals, build arc, stopping | Does the session reach a satisfying change or climax? |
107
+ | campaign/meta | progression, variety, mastery, expression | Do unlocks create new play instead of only larger numbers? |
108
+ | community | cooperation, competition, identity, shared stories | Can players contribute and recover from social friction? |
109
+
110
+ Check coupling. The short loop must feed the long loop, and long-loop rewards must renew rather than trivialize the short loop.
111
+
112
+ ## 4. Systems and economies
113
+
114
+ ### Map flows before tuning
115
+
116
+ For every tangible or abstract resource, record:
117
+
118
+ - **source:** creates it
119
+ - **pool/store:** holds it and defines capacity or decay
120
+ - **converter:** changes it into another resource or state
121
+ - **trade:** exchanges resources between owners
122
+ - **gate:** requires a threshold or condition
123
+ - **sink:** removes it from circulation
124
+
125
+ Include time, attention, space, health, information, social trust, action opportunities, and risk when they behave like resources. Draw connections and simulate several player strategies before choosing numbers.
126
+
127
+ ### Audit feedback structures
128
+
129
+ - Positive feedback amplifies an advantage; it can make growth satisfying but also cause runaway leaders.
130
+ - Negative feedback resists deviation; it can stabilize play but feel punitive when it erases earned advantage.
131
+ - A loop’s speed, delay, visibility, durability, and cap matter as much as its sign.
132
+ - Randomness changes distribution, not only average outcome. Examine worst cases, streaks, and player control.
133
+
134
+ Give resources clear jobs. A currency with no recurring sink accumulates into irrelevance; a sink without valued outcomes becomes tax. Use opportunity costs to create decisions, and cap or decay stockpiles only when that behavior supports the experience.
135
+
136
+ ### Balance relationships, not isolated values
137
+
138
+ Maintain a tuning table with units, baseline, min/max, dependency, player-facing purpose, and test evidence. Derive related values from a small set of legible baselines. Inspect:
139
+
140
+ - time-to-effect and time-to-recover
141
+ - expected value and variance
142
+ - throughput, capacity, scarcity, and replacement rate
143
+ - breakpoints where an option changes from viable to dominant
144
+ - compounding across upgrades and feedback loops
145
+ - edge cases at zero, maximum, and repeated use
146
+
147
+ ## 5. Progression and challenge
148
+
149
+ ### Separate progression channels
150
+
151
+ - **Mastery:** the player learns execution, planning, recognition, or social coordination.
152
+ - **Content:** new spaces, problems, opponents, or stories become available.
153
+ - **Breadth:** new tools or combinations expand the possibility space.
154
+ - **Power:** existing actions become numerically stronger.
155
+ - **Expression/status:** appearance, identity, collection, or public accomplishment changes.
156
+
157
+ Prefer unlocks that create new decisions or recontextualize mastered skills. Numerical power is useful when it makes growth legible, but unchecked vertical scaling invalidates content and narrows viable options.
158
+
159
+ Build a skill graph: assumed prior skills -> introduced skill -> safe practice -> independent test -> combination -> transformed use -> mastery proof. Provide fast paths or optional refreshers for players who arrive with different prior knowledge.
160
+
161
+ ### Treat difficulty as a vector
162
+
163
+ Tune cognitive load, precision, timing, planning depth, memory, sensory discrimination, resource pressure, punishment, uncertainty, coordination, and persistence separately. A single easy/normal/hard multiplier cannot serve every barrier.
164
+
165
+ Failure should answer:
166
+
167
+ - What happened and why?
168
+ - What can the player try differently?
169
+ - How much meaningful progress is lost?
170
+ - How quickly can the player act again?
171
+ - Does recovery preserve tension without demanding repetition already mastered?
172
+
173
+ Dynamic adjustment can change pressure frequency, assistance, resource supply, or challenge amplitude, but it must remain predictable enough for players to learn and must not counterfeit achievement.
174
+
175
+ ## 6. Onboarding and accessibility
176
+
177
+ Teach inside representative play:
178
+
179
+ 1. prime attention before the mechanic matters
180
+ 2. invite the action with low failure cost
181
+ 3. give immediate, redundant feedback
182
+ 4. allow repetition or experimentation
183
+ 5. test without step-by-step prompting
184
+ 6. combine with one known mechanic
185
+ 7. make help recallable and skippable where appropriate
186
+
187
+ Do not assume genre literacy, dual-stick control, rapid reading, color discrimination, precise timing, hearing, or uninterrupted attention. Preserve the intended experience through remapping, simplified input, adjustable timing, pause, granular challenge assists, redundant cues, readable objectives, and reduced repetition.
188
+
189
+ ## 7. Multiplayer and social play
190
+
191
+ Design the social system before selecting transport:
192
+
193
+ - define cooperative and competitive relationships, team sizes, and information boundaries
194
+ - ensure every role has understandable contribution and moments of agency
195
+ - limit involuntary downtime and give eliminated players meaningful next actions
196
+ - specify join, leave, disconnect, reconnect, and uneven-player behavior
197
+ - distinguish team comeback from hidden punishment of skilled play
198
+ - bound griefing, collusion, kingmaking, smurfing, spawn abuse, and reward farming
199
+ - test communication-light play and accessibility of coordination signals
200
+
201
+ For persistent systems, model inflation, hoarding, market manipulation, time-zone advantage, seasonal resets, and what happens when population is sparse.
202
+
203
+ ## 8. Content structure and genre lenses
204
+
205
+ Create a content matrix from mechanics and contexts rather than brainstorming isolated features. Useful axes include verb, target, constraint, topology, information state, resource state, opponent behavior, time pressure, social relationship, and consequence. Combine a few axes at a time and reserve unexplored combinations for progression.
206
+
207
+ Apply genre lenses without treating them as templates:
208
+
209
+ - **action/combat:** readability, positioning, threat priority, counterplay, recovery, expressive kit
210
+ - **platforming/racing:** movement mastery, line choice, anticipation, risk, restart cost, readable boundaries
211
+ - **puzzle:** information sufficiency, hypothesis formation, state legibility, undo/reset, insight rather than busywork
212
+ - **strategy/management:** forecasts, opportunity cost, feedback loops, viable plans, recovery from early errors
213
+ - **survival/crafting:** scarcity rhythms, transformation chains, expedition risk, homeward payoff, anti-grind
214
+ - **narrative/social:** role expression, relationship consequences, authored versus emergent story, respectful irreversibility
215
+ - **sandbox/open world:** self-directed goals, systemic interaction, discovery density, world response, return value
216
+
217
+ ## 9. Prototyping and playtesting
218
+
219
+ ### Prototype risk, not polish
220
+
221
+ Name the riskiest assumption: control feel, decision depth, loop renewal, economy stability, social coordination, or content feasibility. Build the smallest slice that can disprove it with real input, real state transitions, and representative feedback.
222
+
223
+ ### Use a test protocol
224
+
225
+ Record:
226
+
227
+ - hypothesis and decision the test will inform
228
+ - participant profile and prior skills
229
+ - build/version, scenario, starting state, and task
230
+ - observable success/failure thresholds
231
+ - events and metrics to capture
232
+ - moderator script that avoids teaching or defending the design
233
+ - findings separated into behavior, interpretation, severity, confidence, and proposed cause
234
+
235
+ Observe before interviewing. Ask players what they thought was happening, what they planned, and what evidence shaped the plan. Preferences are valuable but do not replace behavior. Telemetry describes what happened at scale; it rarely explains why.
236
+
237
+ Use rapid iterative testing for obvious, high-confidence usability defects: make a small fix, test it with the next appropriate participant, and verify that it solves the problem without creating another. Do not churn balance or appeal based on one participant.
238
+
239
+ Classify findings:
240
+
241
+ - **comprehension:** goal, rule, state, or feedback misunderstood
242
+ - **execution:** intention clear but control/precision/timing blocks action
243
+ - **balance:** options or outcomes violate intended tradeoffs
244
+ - **pacing:** pressure, rest, novelty, or payoff arrives at the wrong rate
245
+ - **motivation:** player sees no valued reason to continue
246
+ - **accessibility:** an avoidable barrier excludes a player
247
+ - **technical:** implementation differs from the design contract
248
+
249
+ ## 10. JGengine translation
250
+
251
+ - Keep the design contract and acceptance criteria in the tracked issue/PR, not a speculative document tree.
252
+ - Put definitions, costs, rewards, tiers, recipes, and formulas in typed catalogs or config.
253
+ - Put mutable state in serializable shared primitives and transitions in systems/commands.
254
+ - Put placement, routes, terrain, markers, zones, foliage, and asset instances in `editor.scene.json` via `jgengine-editor`.
255
+ - Query authored ids and semantics through `jgengine-world`; never copy coordinates into rules.
256
+ - Use deterministic injected randomness and headless tests for loops, economies, and failure states.
257
+ - Add telemetry only for a named design question and avoid collecting unnecessary player data.
258
+ - If a reusable rule is missing, implement the narrow package primitive with the game as first adopter.
259
+
260
+ ## 11. Diagnostic questions
261
+
262
+ Before calling a design coherent, ask:
263
+
264
+ - Can a player state the immediate goal, available verbs, and likely consequences?
265
+ - What interesting decision repeats, and how does context stop it becoming solved?
266
+ - What does the player learn in the first minute, first session, and tenth session?
267
+ - Which state changes make each loop worth repeating?
268
+ - What behavior does each reward actually incentivize?
269
+ - Where can positive feedback create a runaway result?
270
+ - Which barriers are intentional challenge and which are accidental exclusion?
271
+ - What happens after failure, success, mastery, interruption, and return?
272
+ - What breaks with one player, the maximum player count, or a disconnect?
273
+ - What evidence would cause the team to remove or redesign the feature?
274
+
275
+ ## 12. Research basis
276
+
277
+ These sources provide lenses and evidence, not commandments:
278
+
279
+ - Robin Hunicke, Marc LeBlanc, and Robert Zubek, [“MDA: A Formal Approach to Game Design and Game Research”](https://users.cs.northwestern.edu/~hunicke/MDA.pdf): trace mechanics, runtime dynamics, and intended experience causally and avoid using “fun” as the whole vocabulary.
280
+ - Richard Ryan and collaborators, [Player Experience of Needs Satisfaction](https://selfdeterminationtheory.org/player-experience-of-needs-satisfaction-pens/): empirical motivation lens around autonomy, competence, and relatedness.
281
+ - Joris Dormans, [“Simulating Mechanics to Study Emergence in Games”](https://ojs.aaai.org/index.php/AIIDE/article/view/12477): model resource flows, internal economies, and emergent feedback before implementation.
282
+ - Daniel Cook, [“The Chemistry of Game Design”](https://www.gamedeveloper.com/design/the-chemistry-of-game-design): action/simulation/feedback/learning atoms and skill-chain analysis.
283
+ - Robin Hunicke and Vernell Chapman, [“AI for Dynamic Difficulty Adjustment in Games”](https://users.cs.northwestern.edu/~hunicke/pubs/Hamlet.pdf): difficulty, resource supply, uncertainty, and the limitations of adjustment systems.
284
+ - Christiane Birk and colleagues, [“Designing Game Feel: A Survey”](https://arxiv.org/abs/2011.09201): physical tuning, feedback amplification, and intent-supporting streamlining.
285
+ - GDC, [“Prime, Teach, Observe”](https://gdcvault.com/play/1021120/Prime-Teach-Observe-Tutorializing-Innovative): teach mechanics through player modeling and iterative observation.
286
+ - Microsoft Games Studios, [“Using the RITE Method to Improve Products”](https://jpattonassociates.com/wp-content/uploads/2015/04/rite_method.pdf): rapidly fix and empirically verify high-confidence usability problems.
287
+ - Microsoft, [Xbox Accessibility Guidelines](https://learn.microsoft.com/en-us/xbox/accessibility/guidelines): player-informed guidance for input, objectives, feedback, difficulty, timing, sensory access, and communication.
288
+ - Matthias Worch, [“Decisions That Matter”](https://gdcvault.com/play/1020570/): connect informed choice, agency, consequence, and level context.