@seriousgaming/sdk-tools 0.0.0-stage → 1.0.0-alpha.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.
Files changed (391) hide show
  1. package/LICENSE +93 -0
  2. package/README.md +36 -2
  3. package/dist/bundling/logic-exports.d.ts +34 -0
  4. package/dist/bundling/node-builtins.d.ts +21 -0
  5. package/dist/bundling/transpiler.d.ts +7 -0
  6. package/dist/cli.js +27368 -0
  7. package/dist/client/dev-server.d.ts +59 -0
  8. package/dist/client/index.d.ts +28 -0
  9. package/dist/client/stub-services.d.ts +32 -0
  10. package/dist/client/test-session.d.ts +195 -0
  11. package/dist/client.js +16884 -0
  12. package/dist/core/asset-reference-translator.d.ts +46 -0
  13. package/dist/core/clock.d.ts +57 -0
  14. package/dist/core/faults.d.ts +65 -0
  15. package/dist/core/game-settings.d.ts +65 -0
  16. package/dist/core/history.d.ts +89 -0
  17. package/dist/core/listen-with-fallback.d.ts +30 -0
  18. package/dist/core/mutation-queue.d.ts +61 -0
  19. package/dist/core/package-scenario.d.ts +89 -0
  20. package/dist/core/participant-registry.d.ts +109 -0
  21. package/dist/core/pending-changes.d.ts +14 -0
  22. package/dist/core/protocol.d.ts +83 -0
  23. package/dist/core/scenario-drafts.d.ts +32 -0
  24. package/dist/core/session-endpoints.d.ts +108 -0
  25. package/dist/core/session-gates.d.ts +75 -0
  26. package/dist/core/session-host.d.ts +94 -0
  27. package/dist/core/session-refusals.d.ts +56 -0
  28. package/dist/core/session-rewind.d.ts +32 -0
  29. package/dist/core/session-roster.d.ts +128 -0
  30. package/dist/core/session-surfaces.d.ts +32 -0
  31. package/dist/core/session-ticks.d.ts +18 -0
  32. package/dist/core/session-timers.d.ts +84 -0
  33. package/dist/core/session-writes.d.ts +40 -0
  34. package/dist/core/session.d.ts +385 -0
  35. package/dist/core/settings-locks.d.ts +22 -0
  36. package/dist/core/team-names.d.ts +52 -0
  37. package/dist/core/team-state-store.d.ts +209 -0
  38. package/dist/core/tick-timer.d.ts +75 -0
  39. package/dist/dev/blob-links.d.ts +10 -0
  40. package/dist/dev/console/assets/index-DgFglsnA.js +204 -0
  41. package/dist/dev/console/index.html +12 -0
  42. package/dist/dev/console-path.d.ts +19 -0
  43. package/dist/dev/lockfile.d.ts +124 -0
  44. package/dist/dev/package-watcher.d.ts +21 -0
  45. package/dist/dev/routes.d.ts +67 -0
  46. package/dist/dev/shell.d.ts +260 -0
  47. package/dist/dev/surfaces.d.ts +41 -0
  48. package/dist/dev/tools-identity.d.ts +23 -0
  49. package/dist/dev/view/batch.d.ts +172 -0
  50. package/dist/dev/view/commands.d.ts +75 -0
  51. package/dist/dev/view/route.d.ts +58 -0
  52. package/dist/dev/view/view.d.ts +78 -0
  53. package/dist/dev/view/viewer.d.ts +32 -0
  54. package/dist/discovery/config.d.ts +9 -0
  55. package/dist/discovery/manifest-paths.d.ts +21 -0
  56. package/dist/discovery/removed-fields.d.ts +90 -0
  57. package/dist/docs/api/deck.md +386 -0
  58. package/dist/docs/api/index.md +67 -0
  59. package/dist/docs/api/sdk-commands.md +286 -0
  60. package/dist/docs/api/sdk-e2e.md +433 -0
  61. package/dist/docs/api/sdk-projection.md +207 -0
  62. package/dist/docs/api/sdk-testing.md +214 -0
  63. package/dist/docs/api/sdk-tools-client.md +560 -0
  64. package/dist/docs/api/sdk-ui-testing.md +231 -0
  65. package/dist/docs/api/sdk-ui.md +1269 -0
  66. package/dist/docs/api/sdk.md +2140 -0
  67. package/dist/docs/changelog-0.x.md +1156 -0
  68. package/dist/docs/changelog.md +236 -0
  69. package/dist/docs/cli-and-dev-server.md +217 -0
  70. package/dist/docs/cli-error-codes.md +154 -0
  71. package/dist/docs/cli-reference.md +2488 -0
  72. package/dist/docs/cli-simulation-testing.md +222 -0
  73. package/dist/docs/concepts/index.md +46 -0
  74. package/dist/docs/concepts/terminology.md +322 -0
  75. package/dist/docs/environment-variables.md +102 -0
  76. package/dist/docs/getting-started.md +145 -0
  77. package/dist/docs/guides/ai-facilitation.md +220 -0
  78. package/dist/docs/guides/capabilities.md +460 -0
  79. package/dist/docs/guides/endpoints.md +335 -0
  80. package/dist/docs/guides/engine-testing.md +477 -0
  81. package/dist/docs/guides/engine.md +527 -0
  82. package/dist/docs/guides/file-handling.md +405 -0
  83. package/dist/docs/guides/games.md +176 -0
  84. package/dist/docs/guides/global-settings.md +94 -0
  85. package/dist/docs/guides/guide.md +123 -0
  86. package/dist/docs/guides/hooks.md +183 -0
  87. package/dist/docs/guides/index.md +51 -0
  88. package/dist/docs/guides/internationalization.md +288 -0
  89. package/dist/docs/guides/llm-integration.md +635 -0
  90. package/dist/docs/guides/multi-team-games.md +586 -0
  91. package/dist/docs/guides/patterns.md +391 -0
  92. package/dist/docs/guides/presentation.md +196 -0
  93. package/dist/docs/guides/production-constraints.md +130 -0
  94. package/dist/docs/guides/scenario-editor.md +143 -0
  95. package/dist/docs/guides/scenarios.md +515 -0
  96. package/dist/docs/guides/session.md +972 -0
  97. package/dist/docs/guides/settings.md +458 -0
  98. package/dist/docs/guides/setup.md +193 -0
  99. package/dist/docs/guides/speech-generation.md +233 -0
  100. package/dist/docs/guides/starter-game.md +164 -0
  101. package/dist/docs/guides/testing.md +575 -0
  102. package/dist/docs/guides/tick-controller.md +569 -0
  103. package/dist/docs/guides/type-safety.md +516 -0
  104. package/dist/docs/guides/ui.md +1389 -0
  105. package/dist/docs/guides/upgrading.md +636 -0
  106. package/dist/docs/guides/validators.md +217 -0
  107. package/dist/docs/guides/waiting-room.md +244 -0
  108. package/dist/docs/index.md +41 -0
  109. package/dist/docs/recipes/act-on-the-session-from-an-endpoint.md +95 -0
  110. package/dist/docs/recipes/adapt-a-game-for-walkthroughs.md +133 -0
  111. package/dist/docs/recipes/adapt-ui-for-observers.md +74 -0
  112. package/dist/docs/recipes/call-endpoint-from-ui.md +109 -0
  113. package/dist/docs/recipes/check-a-package-from-a-script.md +117 -0
  114. package/dist/docs/recipes/create-capability.md +66 -0
  115. package/dist/docs/recipes/create-endpoint.md +127 -0
  116. package/dist/docs/recipes/create-engine.md +111 -0
  117. package/dist/docs/recipes/create-game.md +70 -0
  118. package/dist/docs/recipes/create-guide.md +75 -0
  119. package/dist/docs/recipes/create-hook.md +80 -0
  120. package/dist/docs/recipes/create-presentation.md +142 -0
  121. package/dist/docs/recipes/create-scenario-editor.md +102 -0
  122. package/dist/docs/recipes/create-scenario.md +98 -0
  123. package/dist/docs/recipes/create-session-ui.md +116 -0
  124. package/dist/docs/recipes/create-settings.md +88 -0
  125. package/dist/docs/recipes/create-setup.md +115 -0
  126. package/dist/docs/recipes/create-tick-controller.md +65 -0
  127. package/dist/docs/recipes/create-user-interface.md +96 -0
  128. package/dist/docs/recipes/create-validator.md +67 -0
  129. package/dist/docs/recipes/create-waiting-room-ui.md +109 -0
  130. package/dist/docs/recipes/declare-api-uses.md +67 -0
  131. package/dist/docs/recipes/design-state-for-concurrent-writes.md +96 -0
  132. package/dist/docs/recipes/distribute-package.md +80 -0
  133. package/dist/docs/recipes/e2e-testing.md +116 -0
  134. package/dist/docs/recipes/end-game-on-condition.md +154 -0
  135. package/dist/docs/recipes/fix-duplicate-packages.md +101 -0
  136. package/dist/docs/recipes/index.md +86 -0
  137. package/dist/docs/recipes/make-an-endpoint-external.md +101 -0
  138. package/dist/docs/recipes/negotiate-across-teams.md +164 -0
  139. package/dist/docs/recipes/observe-other-teams-state.md +119 -0
  140. package/dist/docs/recipes/publish-a-package.md +139 -0
  141. package/dist/docs/recipes/remember-a-viewers-choice.md +55 -0
  142. package/dist/docs/recipes/review-a-past-day.md +73 -0
  143. package/dist/docs/recipes/share-assets-across-scenarios.md +120 -0
  144. package/dist/docs/recipes/share-logic-between-engine-and-ui.md +130 -0
  145. package/dist/docs/recipes/show-all-teams-participants.md +109 -0
  146. package/dist/docs/recipes/start-from-an-empty-package.md +169 -0
  147. package/dist/docs/recipes/take-a-file-in-an-endpoint.md +82 -0
  148. package/dist/docs/recipes/test-a-multi-role-game.md +51 -0
  149. package/dist/docs/recipes/test-user-interface.md +95 -0
  150. package/dist/docs/recipes/test-with-engine.md +115 -0
  151. package/dist/docs/recipes/upload-and-display-files.md +148 -0
  152. package/dist/docs/recipes/use-request-play.md +65 -0
  153. package/dist/docs/recipes/use-request-tick.md +75 -0
  154. package/dist/docs/troubleshooting.md +816 -0
  155. package/dist/execution/blob-inputs.d.ts +57 -0
  156. package/dist/execution/bundle-reload.d.ts +42 -0
  157. package/dist/execution/config-resolver.d.ts +127 -0
  158. package/dist/execution/configuration-builder.d.ts +66 -0
  159. package/dist/execution/context-composition.d.ts +161 -0
  160. package/dist/execution/endpoint-actions.d.ts +9 -0
  161. package/dist/execution/endpoint-payloads.d.ts +32 -0
  162. package/dist/execution/endpoint-runner.d.ts +129 -0
  163. package/dist/execution/engine-state.d.ts +40 -0
  164. package/dist/execution/executor-callbacks.d.ts +56 -0
  165. package/dist/execution/executor.d.ts +436 -0
  166. package/dist/execution/gates.d.ts +45 -0
  167. package/dist/execution/hook-chain.d.ts +25 -0
  168. package/dist/execution/logic-calls.d.ts +190 -0
  169. package/dist/execution/logic-failure.d.ts +84 -0
  170. package/dist/execution/logic-loader.d.ts +54 -0
  171. package/dist/execution/logic-result.d.ts +76 -0
  172. package/dist/execution/tick-controller-call.d.ts +32 -0
  173. package/dist/execution/types.d.ts +48 -0
  174. package/dist/generation/ts-type.d.ts +39 -0
  175. package/dist/guide/locale.d.ts +12 -0
  176. package/dist/guide/video-registry.d.ts +42 -0
  177. package/dist/help-examples.d.ts +125 -0
  178. package/dist/host/adapter.d.ts +67 -0
  179. package/dist/host/host-channel.d.ts +222 -0
  180. package/dist/host/index.d.ts +20 -0
  181. package/dist/host/protocol.d.ts +783 -0
  182. package/dist/host/surfaces.d.ts +42 -0
  183. package/dist/host/theme.d.ts +55 -0
  184. package/dist/host.js +583 -0
  185. package/dist/prompts/index.d.ts +7 -0
  186. package/dist/prompts/schema-builder.d.ts +29 -0
  187. package/dist/prompts/types.d.ts +108 -0
  188. package/dist/prompts/validators.d.ts +32 -0
  189. package/dist/runtime/capability-scope.d.ts +6 -0
  190. package/dist/runtime/context-merge.d.ts +29 -0
  191. package/dist/runtime/context-projection.d.ts +41 -0
  192. package/dist/runtime/guarded-callbacks.d.ts +15 -0
  193. package/dist/runtime/index.d.ts +27 -0
  194. package/dist/runtime/manifest-version.d.ts +55 -0
  195. package/dist/runtime/tick-validation.d.ts +25 -0
  196. package/dist/runtime.js +346 -0
  197. package/dist/schema.json +1546 -0
  198. package/dist/server/vite-plugin.d.ts +46 -0
  199. package/dist/services/tts/client.d.ts +51 -0
  200. package/dist/services/tts/elevenlabs.d.ts +24 -0
  201. package/dist/services/tts/types.d.ts +44 -0
  202. package/dist/storage/asset-resolver.d.ts +49 -0
  203. package/dist/storage/blob-store.d.ts +41 -0
  204. package/dist/templates/endpoint/logic.test.ts.liquid +61 -0
  205. package/dist/templates/endpoint/logic.ts.liquid +25 -0
  206. package/dist/templates/engine/init.json.liquid +7 -0
  207. package/dist/templates/engine/logic-aggregate.test.ts.liquid +90 -0
  208. package/dist/templates/engine/logic-aggregate.ts.liquid +46 -0
  209. package/dist/templates/engine/logic.test.ts.liquid +61 -0
  210. package/dist/templates/engine/logic.ts.liquid +32 -0
  211. package/dist/templates/engine/run.json.liquid +7 -0
  212. package/dist/templates/guide/01-at-a-glance.md.liquid +19 -0
  213. package/dist/templates/guide/02-preparation.md.liquid +18 -0
  214. package/dist/templates/guide/03-running-the-session.md.liquid +37 -0
  215. package/dist/templates/hook/logic.test.ts.liquid +46 -0
  216. package/dist/templates/hook/logic.ts.liquid +12 -0
  217. package/dist/templates/package/CLAUDE.md.template +338 -0
  218. package/dist/templates/package/DESIGN.md.liquid +144 -0
  219. package/dist/templates/package/README.md.liquid +143 -0
  220. package/dist/templates/package/claude/rules/workflow-create-capability.md +26 -0
  221. package/dist/templates/package/claude/rules/workflow-create-endpoint.md +35 -0
  222. package/dist/templates/package/claude/rules/workflow-create-engine.md +35 -0
  223. package/dist/templates/package/claude/rules/workflow-create-guide.md +40 -0
  224. package/dist/templates/package/claude/rules/workflow-create-presentation.md +37 -0
  225. package/dist/templates/package/claude/rules/workflow-create-user-interface.md +31 -0
  226. package/dist/templates/package/claude/rules/workflow-publish-package.md +54 -0
  227. package/dist/templates/package/claude/rules/workflow-test-engine-or-ui.md +30 -0
  228. package/dist/templates/package/claude/rules/workflow-update-sdk-version.md +43 -0
  229. package/dist/templates/package/claude/settings.json.template +16 -0
  230. package/dist/templates/package/gitignore.template +15 -0
  231. package/dist/templates/package/global-setup.ts.template +21 -0
  232. package/dist/templates/package/globals.d.ts.template +2 -0
  233. package/dist/templates/package/oxfmtrc.json.template +14 -0
  234. package/dist/templates/package/oxlintrc.json.template +238 -0
  235. package/dist/templates/package/package.json.liquid +65 -0
  236. package/dist/templates/package/playwright.config.ts.liquid +19 -0
  237. package/dist/templates/package/pnpm-workspace.yaml.template +27 -0
  238. package/dist/templates/package/test-setup.ts.liquid +7 -0
  239. package/dist/templates/package/tsconfig.json.liquid +15 -0
  240. package/dist/templates/package/vite.config.ts.liquid +19 -0
  241. package/dist/templates/package/vitest.config.ts.liquid +25 -0
  242. package/dist/templates/package/vitest.engine.config.ts.liquid +12 -0
  243. package/dist/templates/presentation/index.html.liquid +20 -0
  244. package/dist/templates/presentation/src/App.tsx.liquid +49 -0
  245. package/dist/templates/presentation/src/Slides.tsx.liquid +81 -0
  246. package/dist/templates/presentation/src/i18n.ts.liquid +54 -0
  247. package/dist/templates/presentation/src/main.tsx.liquid +14 -0
  248. package/dist/templates/scenario_editor/src/App.test.tsx.liquid +30 -0
  249. package/dist/templates/scenario_editor/src/App.tsx.liquid +95 -0
  250. package/dist/templates/scenario_editor/src/i18n.ts.liquid +44 -0
  251. package/dist/templates/session/src/App.test.tsx.liquid +60 -0
  252. package/dist/templates/session/src/App.tsx.liquid +128 -0
  253. package/dist/templates/session/src/i18n.ts.liquid +53 -0
  254. package/dist/templates/session/src/main.tsx.liquid +48 -0
  255. package/dist/templates/session/src/theme.ts.liquid +46 -0
  256. package/dist/templates/settings-editor/index.html.liquid +12 -0
  257. package/dist/templates/settings-editor/src/main.tsx.liquid +48 -0
  258. package/dist/templates/settings-editor/src/theme.ts.liquid +24 -0
  259. package/dist/templates/setup/src/App.test.tsx.liquid +39 -0
  260. package/dist/templates/setup/src/App.tsx.liquid +102 -0
  261. package/dist/templates/setup/src/i18n.ts.liquid +47 -0
  262. package/dist/templates/starter-game/capabilities/briefing/capability.sdk.json +18 -0
  263. package/dist/templates/starter-game/capabilities/plan/capability.sdk.json +17 -0
  264. package/dist/templates/starter-game/capabilities/results/capability.sdk.json +61 -0
  265. package/dist/templates/starter-game/capabilities/roles/capability.sdk.json +17 -0
  266. package/dist/templates/starter-game/capabilities/weather/capability.sdk.json +23 -0
  267. package/dist/templates/starter-game/engine/defaults.ts +81 -0
  268. package/dist/templates/starter-game/engine/engine.sdk.json +12 -0
  269. package/dist/templates/starter-game/engine/logic.test.ts +221 -0
  270. package/dist/templates/starter-game/engine/logic.ts +149 -0
  271. package/dist/templates/starter-game/engine/test-helpers.ts +74 -0
  272. package/dist/templates/starter-game/engine/types.ts +139 -0
  273. package/dist/templates/starter-game/guide/content/en/01-at-a-glance.md +51 -0
  274. package/dist/templates/starter-game/guide/content/en/02-preparation.md +35 -0
  275. package/dist/templates/starter-game/guide/content/en/03-running-the-day.md +58 -0
  276. package/dist/templates/starter-game/guide/guide.sdk.json +10 -0
  277. package/dist/templates/starter-game/guide/guide.test.ts +108 -0
  278. package/dist/templates/starter-game/hooks/assignproducts/defaults.ts +37 -0
  279. package/dist/templates/starter-game/hooks/assignproducts/hook.sdk.json +13 -0
  280. package/dist/templates/starter-game/hooks/assignproducts/logic/logic.test.ts +77 -0
  281. package/dist/templates/starter-game/hooks/assignproducts/logic/logic.ts +47 -0
  282. package/dist/templates/starter-game/hooks/assignproducts/types.ts +55 -0
  283. package/dist/templates/starter-game/package.json +68 -0
  284. package/dist/templates/starter-game/playwright.config.ts +19 -0
  285. package/dist/templates/starter-game/scenarios/heatwave/scenario.sdk.json +20 -0
  286. package/dist/templates/starter-game/scenarios/ordinary_week/scenario.sdk.json +12 -0
  287. package/dist/templates/starter-game/seriousgaming.sdk.json +23 -0
  288. package/dist/templates/starter-game/session/defaults.ts +80 -0
  289. package/dist/templates/starter-game/session/index.html +12 -0
  290. package/dist/templates/starter-game/session/session.sdk.json +11 -0
  291. package/dist/templates/starter-game/session/src/App.test.tsx +307 -0
  292. package/dist/templates/starter-game/session/src/App.tsx +309 -0
  293. package/dist/templates/starter-game/session/src/Section.tsx +37 -0
  294. package/dist/templates/starter-game/session/src/TeamDoor.tsx +96 -0
  295. package/dist/templates/starter-game/session/src/format.ts +8 -0
  296. package/dist/templates/starter-game/session/src/i18n.ts +51 -0
  297. package/dist/templates/starter-game/session/src/main.tsx +48 -0
  298. package/dist/templates/starter-game/session/src/theme.ts +45 -0
  299. package/dist/templates/starter-game/session/types.ts +135 -0
  300. package/dist/templates/starter-game/settings/engine/settings.sdk.json +50 -0
  301. package/dist/templates/starter-game/settings/menu/settings.sdk.json +78 -0
  302. package/dist/templates/starter-game/settings/session/settings.sdk.json +23 -0
  303. package/dist/templates/starter-game/settings/ui/settings.sdk.json +25 -0
  304. package/dist/templates/starter-game/test-setup.ts +7 -0
  305. package/dist/templates/starter-game/testing/e2e/game.spec.ts +139 -0
  306. package/dist/templates/starter-game/testing/e2e/global-setup.ts +21 -0
  307. package/dist/templates/starter-game/testing/engine/game.engine.test.ts +171 -0
  308. package/dist/templates/starter-game/tsconfig.json +19 -0
  309. package/dist/templates/starter-game/ui/defaults.ts +60 -0
  310. package/dist/templates/starter-game/ui/index.html +12 -0
  311. package/dist/templates/starter-game/ui/src/App.test.tsx +138 -0
  312. package/dist/templates/starter-game/ui/src/App.tsx +175 -0
  313. package/dist/templates/starter-game/ui/src/DayBar.test.tsx +78 -0
  314. package/dist/templates/starter-game/ui/src/DayBar.tsx +72 -0
  315. package/dist/templates/starter-game/ui/src/HistoryPanel.test.tsx +74 -0
  316. package/dist/templates/starter-game/ui/src/HistoryPanel.tsx +120 -0
  317. package/dist/templates/starter-game/ui/src/MakeRow.tsx +129 -0
  318. package/dist/templates/starter-game/ui/src/Section.tsx +37 -0
  319. package/dist/templates/starter-game/ui/src/ThemeToggle.tsx +49 -0
  320. package/dist/templates/starter-game/ui/src/TodayPanel.test.tsx +179 -0
  321. package/dist/templates/starter-game/ui/src/TodayPanel.tsx +92 -0
  322. package/dist/templates/starter-game/ui/src/YesterdayPanel.tsx +142 -0
  323. package/dist/templates/starter-game/ui/src/format.ts +12 -0
  324. package/dist/templates/starter-game/ui/src/i18n.ts +95 -0
  325. package/dist/templates/starter-game/ui/src/main.tsx +48 -0
  326. package/dist/templates/starter-game/ui/src/menu.ts +18 -0
  327. package/dist/templates/starter-game/ui/src/test-helpers.ts +58 -0
  328. package/dist/templates/starter-game/ui/src/theme.ts +45 -0
  329. package/dist/templates/starter-game/ui/src/writes.ts +43 -0
  330. package/dist/templates/starter-game/ui/types.ts +137 -0
  331. package/dist/templates/starter-game/ui/ui.sdk.json +11 -0
  332. package/dist/templates/starter-game/validators/capacity/defaults.ts +37 -0
  333. package/dist/templates/starter-game/validators/capacity/logic/logic.test.ts +96 -0
  334. package/dist/templates/starter-game/validators/capacity/logic/logic.ts +45 -0
  335. package/dist/templates/starter-game/validators/capacity/types.ts +55 -0
  336. package/dist/templates/starter-game/validators/capacity/validator.sdk.json +11 -0
  337. package/dist/templates/starter-game/vite.config.ts +19 -0
  338. package/dist/templates/starter-game/vitest.config.ts +15 -0
  339. package/dist/templates/starter-game/vitest.engine.config.ts +19 -0
  340. package/dist/templates/starter-game/waiting_room/defaults.ts +40 -0
  341. package/dist/templates/starter-game/waiting_room/index.html +12 -0
  342. package/dist/templates/starter-game/waiting_room/src/App.test.tsx +102 -0
  343. package/dist/templates/starter-game/waiting_room/src/App.tsx +194 -0
  344. package/dist/templates/starter-game/waiting_room/src/i18n.ts +33 -0
  345. package/dist/templates/starter-game/waiting_room/src/main.tsx +48 -0
  346. package/dist/templates/starter-game/waiting_room/src/theme.ts +45 -0
  347. package/dist/templates/starter-game/waiting_room/types.ts +59 -0
  348. package/dist/templates/starter-game/waiting_room/waiting_room.sdk.json +10 -0
  349. package/dist/templates/tick-controller/logic.ts.liquid +8 -0
  350. package/dist/templates/ui/index.html.liquid +12 -0
  351. package/dist/templates/ui/src/App.test.tsx.liquid +41 -0
  352. package/dist/templates/ui/src/App.tsx.liquid +103 -0
  353. package/dist/templates/ui/src/i18n.ts.liquid +47 -0
  354. package/dist/templates/ui/src/main.tsx.liquid +48 -0
  355. package/dist/templates/ui/src/theme.ts.liquid +46 -0
  356. package/dist/templates/validator/logic.test.ts.liquid +42 -0
  357. package/dist/templates/validator/logic.ts.liquid +21 -0
  358. package/dist/templates/waiting-room/index.html.liquid +12 -0
  359. package/dist/templates/waiting-room/src/App.test.tsx.liquid +57 -0
  360. package/dist/templates/waiting-room/src/App.tsx.liquid +118 -0
  361. package/dist/templates/waiting-room/src/i18n.ts.liquid +44 -0
  362. package/dist/templates/waiting-room/src/main.tsx.liquid +48 -0
  363. package/dist/templates/waiting-room/src/theme.ts.liquid +46 -0
  364. package/dist/templating/resource-metadata.d.ts +131 -0
  365. package/dist/types.d.ts +14 -0
  366. package/dist/utils/atomic-write.d.ts +40 -0
  367. package/dist/utils/cli-error.d.ts +64 -0
  368. package/dist/utils/document-parser-client.d.ts +20 -0
  369. package/dist/utils/env-loader.d.ts +40 -0
  370. package/dist/utils/error-codes.d.ts +335 -0
  371. package/dist/utils/errors.d.ts +19 -0
  372. package/dist/utils/global-settings.d.ts +65 -0
  373. package/dist/utils/llm-client.d.ts +34 -0
  374. package/dist/utils/logger.d.ts +36 -0
  375. package/dist/utils/output.d.ts +109 -0
  376. package/dist/utils/platform.d.ts +14 -0
  377. package/dist/utils/prompt.d.ts +36 -0
  378. package/dist/utils/real-path.d.ts +6 -0
  379. package/dist/utils/schema-properties.d.ts +35 -0
  380. package/dist/validation/ajv.d.ts +17 -0
  381. package/dist/validation/facilitator-guide-validator.d.ts +27 -0
  382. package/dist/validation/findings.d.ts +40 -0
  383. package/dist/validation/game-constraints.d.ts +10 -0
  384. package/dist/validation/game-validator.d.ts +34 -0
  385. package/dist/validation/package-validation.d.ts +41 -0
  386. package/dist/validation/package-validator.d.ts +19 -0
  387. package/dist/validation/resource-validator.d.ts +79 -0
  388. package/dist/validation/schema-defaults-validator.d.ts +29 -0
  389. package/dist/validation/schema-validation.d.ts +115 -0
  390. package/dist/validation/semver.d.ts +9 -0
  391. package/package.json +122 -3
@@ -0,0 +1,111 @@
1
+ # Create an engine
2
+
3
+ Write the engine that moves the game on each tick: here, one that reads a price and writes the day's revenue.
4
+
5
+ **Keywords:** create engine, new engine, engine example, add engine, simple engine, update engine, Init, Run
6
+
7
+ ## Prerequisites
8
+
9
+ - A capability to read (here `pricing`, with `BasePrice`) and one to write (here `sales`, with `Revenue` and `DailySales`); see [Create a capability](create-capability.md)
10
+ - A settings resource for the engine's parameters (here `demand`, with `DailyUnitsSold`); see [Create settings](create-settings.md)
11
+ - `seriousgaming.sdk.json` in your working directory
12
+
13
+ ## Steps
14
+
15
+ 1. Declare what the engine reads, writes, and takes as settings. A game holds one engine, in the `engine/` slot, and the starter game already has it, so in a package made with `new package` update it:
16
+
17
+ ```bash
18
+ pnpm run sdk update engine --patch '[
19
+ { "op": "replace", "path": "/definition/reads", "value": ["pricing"] },
20
+ { "op": "replace", "path": "/definition/writes", "value": ["sales"] },
21
+ { "op": "replace", "path": "/definition/settings", "value": ["demand"] }
22
+ ]'
23
+ ```
24
+
25
+ In a package made with `new package --empty`, create it:
26
+
27
+ ```bash
28
+ pnpm run sdk new engine '{
29
+ "definition": {
30
+ "reads": ["pricing"],
31
+ "writes": ["sales"],
32
+ "settings": ["demand"]
33
+ },
34
+ "logic": { "directory": ".", "entrypoint": "logic.ts" },
35
+ "rootDirectory": "."
36
+ }'
37
+ ```
38
+
39
+ Either command regenerates `engine/types.ts`. `update engine` leaves `engine/logic.ts` alone.
40
+
41
+ 2. Write `Init` and `Run` in `engine/logic.ts`. Each returns what it writes under `capabilities`, spreading rather than mutating:
42
+
43
+ ```typescript
44
+ import { InitializationFunction, RunFunction } from '@seriousgaming/sdk';
45
+
46
+ import type { Callbacks, Context, Settings } from './types';
47
+
48
+ export const Init: InitializationFunction<Context, Settings, Callbacks> = async ({
49
+ context,
50
+ settings,
51
+ }) => ({
52
+ capabilities: {
53
+ ...context,
54
+ sales: { ...context.sales, Revenue: 0, DailySales: settings.demand.DailyUnitsSold },
55
+ },
56
+ });
57
+
58
+ export const Run: RunFunction<Context, Settings, Callbacks> = async ({
59
+ context,
60
+ settings,
61
+ }) => ({
62
+ capabilities: {
63
+ ...context,
64
+ sales: {
65
+ ...context.sales,
66
+ Revenue: context.pricing.BasePrice * context.sales.DailySales,
67
+ DailySales: settings.demand.DailyUnitsSold,
68
+ },
69
+ },
70
+ });
71
+ ```
72
+
73
+ 3. If you replaced the starter game's engine, replace or delete `engine/logic.test.ts` and the starter's other engine files, which test the old logic.
74
+
75
+ 4. In a package made with `--empty`, set how long the game runs (the starter already sets `maxTicks`):
76
+
77
+ ```bash
78
+ pnpm run sdk update package --patch '[{ "op": "add", "path": "/maxTicks", "value": 10 }]'
79
+ ```
80
+
81
+ 5. Build:
82
+
83
+ ```bash
84
+ pnpm run build
85
+ ```
86
+
87
+ ## Verify
88
+
89
+ ```bash
90
+ pnpm run sdk init
91
+ pnpm run sdk tick
92
+ pnpm run sdk view
93
+ ```
94
+
95
+ `sales.Revenue` is `BasePrice` times the previous day's `DailySales`, and `sales.DailySales` is the `demand` setting.
96
+
97
+ ## Troubleshooting
98
+
99
+ | Problem | Solution |
100
+ | --------------------------------------- | --------------------------------------------------------------- |
101
+ | `new engine` refuses: the game has one | Use `update engine` (step 1) |
102
+ | `context.pricing` is a type error | Add `pricing` to `reads`; the command regenerates `types.ts` |
103
+ | `settings.demand` is undefined | List `demand` in the engine's `settings` |
104
+ | The tick fails with a flat-result error | Return the new state under `capabilities`, not at the top level |
105
+ | The engine's write is refused | The engine returned a capability outside its `writes` |
106
+
107
+ ## Related
108
+
109
+ - [Engine guide](../guides/engine.md): the model, results, memory between ticks, aggregate engines, and the language environment
110
+ - [Test a whole game in-process](test-with-engine.md)
111
+ - [Create a user interface](create-user-interface.md)
@@ -0,0 +1,70 @@
1
+ # Shape your game
2
+
3
+ Set what your package's game is: its name in each locale, how long it runs, and its teams.
4
+
5
+ **Keywords:** create game, new game, game definition, game setup, game manifest, seriousgaming.sdk.json, ticks, teams, locales, update package
6
+
7
+ ## Prerequisites
8
+
9
+ - A package (see [Getting started](../getting-started.md)). A package is a game: there is no `new game`, and the game runs whatever resources sit beside its manifest
10
+ - `seriousgaming.sdk.json` in your working directory
11
+
12
+ ## Steps
13
+
14
+ 1. Name the game in each locale it supports. Patch the field rather than replacing the manifest, so the fields you do not name stay as they are:
15
+
16
+ ```bash
17
+ pnpm run sdk update package --patch '[
18
+ { "op": "replace", "path": "/locales/en/name", "value": "Retail Simulation" }
19
+ ]'
20
+ ```
21
+
22
+ 2. Set how many ticks the game runs, one per meaningful period or phase:
23
+
24
+ ```bash
25
+ pnpm run sdk update package --patch '[{ "op": "add", "path": "/maxTicks", "value": 12 }]'
26
+ ```
27
+
28
+ For a game that ends on a goal rather than a count, see [End a game when a condition is met](end-game-on-condition.md). Do not set a large `maxTicks` 'just in case', and do not keep a tick number, a status, or a phase in context: the SDK tracks them.
29
+
30
+ 3. Set the teams: the interaction mode and how many teams a session may have:
31
+
32
+ ```bash
33
+ pnpm run sdk update package --patch '[
34
+ { "op": "add", "path": "/teams", "value": { "mode": "independent", "min": 1, "max": 8 } }
35
+ ]'
36
+ ```
37
+
38
+ See [Play modes](../guides/multi-team-games.md#play-modes) for `independent` and `shared-state`.
39
+
40
+ 4. Build:
41
+
42
+ ```bash
43
+ pnpm run build
44
+ ```
45
+
46
+ ## Verify
47
+
48
+ ```bash
49
+ pnpm run sdk init
50
+ pnpm run sdk tick
51
+ pnpm run sdk view
52
+ ```
53
+
54
+ `init` runs the engine's `Init`, and `view` shows `completedTicks: 1` after one tick. To play with different settings without changing their defaults, see [Overriding settings from the CLI](../guides/settings.md#from-the-cli).
55
+
56
+ ## Troubleshooting
57
+
58
+ | Problem | Solution |
59
+ | ----------------------------------------------------- | ------------------------------------------------------------------------------ |
60
+ | The build reports no engine | Check `engine/engine.sdk.json` exists |
61
+ | The build warns that only the engine can end the game | There is no `maxTicks`; expected for a goal-based game |
62
+ | A patch fails on a missing path | Use `add` for a field the manifest does not have yet, `replace` for one it has |
63
+ | Detailed errors | Run `pnpm run sdk build --validate-only --json` |
64
+
65
+ ## Related
66
+
67
+ - [Games guide](../guides/games.md): the manifest, host controls, and goal-based games
68
+ - [Create settings](create-settings.md)
69
+ - [Create a setup screen](create-setup.md)
70
+ - [Drive a game from the CLI](../cli-simulation-testing.md)
@@ -0,0 +1,75 @@
1
+ # Create a facilitator guide
2
+
3
+ Bundle a facilitator guide with your game: markdown chapters shown on the facilitator's page.
4
+
5
+ **Keywords:** create facilitator guide, new facilitator guide, cheat sheet, run sheet, facilitation notes, session script, markdown guide, say do timing
6
+
7
+ ## Prerequisites
8
+
9
+ - A package with `seriousgaming.sdk.json` in your working directory
10
+
11
+ ## Steps
12
+
13
+ 1. Declare the guide's locales and titles. A game holds at most one guide, in the `guide/` slot, and the starter game already fills it, so in a package made with `new package` update it:
14
+
15
+ ```bash
16
+ pnpm run sdk update guide --patch '[
17
+ { "op": "add", "path": "/definition/locales/de", "value": { "name": "Moderationsleitfaden" } }
18
+ ]'
19
+ ```
20
+
21
+ In a package without one, create it, which scaffolds a chapter skeleton for every locale:
22
+
23
+ ```bash
24
+ pnpm run sdk new guide '{
25
+ "definition": {
26
+ "locales": {
27
+ "en": { "name": "Facilitator guide" },
28
+ "de": { "name": "Moderationsleitfaden" }
29
+ }
30
+ },
31
+ "rootDirectory": "."
32
+ }'
33
+ ```
34
+
35
+ 2. Write the chapters as markdown files in `guide/content/<locale>/`, ordered by file name, with the same file names in every locale (`01-at-a-glance.md`, `02-preparation.md`, and so on).
36
+
37
+ 3. Mark the live script with admonitions:
38
+
39
+ ```markdown
40
+ :::say
41
+ Welcome everyone. Today you are running a company for three simulated years.
42
+ :::
43
+
44
+ :::do
45
+ Form the teams and hand each team its device.
46
+ :::
47
+ ```
48
+
49
+ `timing`, `note`, `warning`, and `tip` work the same way. See [Content rules](../guides/guide.md#content-rules) for headings, images, and video blocks.
50
+
51
+ 4. Put images in `guide/assets/` and reference them relatively from a chapter: `![Market diagram](../../assets/market-diagram.png)`.
52
+
53
+ ## Verify
54
+
55
+ ```bash
56
+ pnpm run sdk build --validate-only
57
+ ```
58
+
59
+ Validation warns when a locale is missing a chapter the reference locale has, and fails on a malformed video block or an image that does not resolve. Then open `/guide` in the dev server: the page has its own locale picker and a print button.
60
+
61
+ ## Troubleshooting
62
+
63
+ | Problem | Solution |
64
+ | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
65
+ | `new guide` fails with `RESOURCE_EXISTS` | The slot is filled: use `update guide` and edit the chapters, or `pnpm run sdk delete guide --yes` first |
66
+ | A chapter shows a 'not yet translated' note | That file is missing from the selected locale's directory; content falls back per file to the reference locale |
67
+ | A video renders an error block | The provider must be `youtube` and the id an 11-character YouTube id |
68
+ | An image does not display | The path must resolve inside `guide/`, for example `../../assets/diagram.png` from a chapter |
69
+ | Raw HTML appears as text | By design: the renderer escapes HTML. Use markdown, admonitions, and video blocks |
70
+
71
+ ## Related
72
+
73
+ - [Facilitator guides](../guides/guide.md): writing guidance and the full content format
74
+ - [Create a presentation](create-presentation.md)
75
+ - [Internationalisation](../guides/internationalization.md)
@@ -0,0 +1,80 @@
1
+ # Create a hook
2
+
3
+ React to a lifecycle signal, such as a participant joining a team, outside the tick loop.
4
+
5
+ **Keywords:** create hook, new hook, lifecycle hook, participant join, participant move, out-of-tick
6
+
7
+ ## Prerequisites
8
+
9
+ - A capability for the hook to write (here `roles`, with an `Assignments` map keyed by participant id); see [Create a capability](create-capability.md)
10
+ - `seriousgaming.sdk.json` in your working directory
11
+
12
+ ## Steps
13
+
14
+ 1. Create the hook, naming its signal and what it reads and writes:
15
+
16
+ ```bash
17
+ pnpm run sdk new hook '{
18
+ "definition": {
19
+ "identifier": "assignroles",
20
+ "signal": "participantJoin",
21
+ "reads": ["roles"],
22
+ "writes": ["roles"]
23
+ },
24
+ "logic": { "directory": "logic", "entrypoint": "logic.ts" },
25
+ "rootDirectory": "."
26
+ }'
27
+ ```
28
+
29
+ This writes `hooks/assignroles/` with `hook.sdk.json`, `logic/logic.ts`, and a generated `types.ts` that pins the signal and its payload. The directory is the whole of the wiring.
30
+
31
+ 2. Write `Run` in `hooks/assignroles/logic/logic.ts`, returning what it writes under `capabilities`:
32
+
33
+ ```typescript
34
+ import type { HookFunction } from '../types';
35
+
36
+ export const Run: HookFunction = async ({ context, participant }) => ({
37
+ capabilities: {
38
+ ...context,
39
+ roles: {
40
+ ...context.roles,
41
+ Assignments: {
42
+ ...context.roles.Assignments,
43
+ [participant.id]: context.roles.Assignments[participant.id] ?? 'observer',
44
+ },
45
+ },
46
+ },
47
+ });
48
+ ```
49
+
50
+ 3. If several hooks subscribe to the same signal and order matters, number their directories: they run in directory-name order.
51
+
52
+ 4. Build:
53
+
54
+ ```bash
55
+ pnpm run build
56
+ ```
57
+
58
+ ## Verify
59
+
60
+ ```bash
61
+ pnpm run sdk participant add Alice --team 1
62
+ pnpm run sdk view
63
+ ```
64
+
65
+ Adding a participant fires `participantJoin`, and the team's `roles.Assignments` holds an entry for the new participant.
66
+
67
+ ## Troubleshooting
68
+
69
+ | Problem | Solution |
70
+ | ------------------------------- | ---------------------------------------------------------------------------------------- |
71
+ | The hook never fires | Check `hooks/<identifier>/hook.sdk.json` exists and `signal` is spelled as a signal name |
72
+ | `context.roles` is a type error | Add `roles` to the hook's `reads`; a hook is handed only what it declares |
73
+ | The write is refused | The hook returned a capability outside its `writes` |
74
+ | `participant` is undefined | The hook is bound to a signal whose payload has no `participant`; check `signal` |
75
+
76
+ ## Related
77
+
78
+ - [Hooks guide](../guides/hooks.md): signals and payloads, ordering, settings, and testing
79
+ - [Create a validator](create-validator.md)
80
+ - [Test a whole game in-process](test-with-engine.md)
@@ -0,0 +1,142 @@
1
+ # Create a presentation
2
+
3
+ Ship the facilitator's slide deck with the game, so the briefing, the round dividers, the debriefs and the results travel with the package rather than in an email after train the trainer.
4
+
5
+ **Keywords:** presentation, slides, slide deck, deck, briefing, debrief, results slide, PowerPoint, PDF export, facilitator slides, usePresentation, @seriousgaming/deck
6
+
7
+ ## What you'll build
8
+
9
+ A presentation in the `presentation/` slot that:
10
+
11
+ - Opens with a title slide, an agenda revealed one point per click, and a results slide
12
+ - Renders with no session at all, showing labelled sample figures in place of results
13
+ - Shows every team's results once a session is running
14
+ - Exports to PDF, editable PowerPoint and PNG from its own controls
15
+
16
+ A game holds at most one presentation. It is read-only: it reads every team's state, but writes nothing and calls no endpoint. Only the facilitator sees it, and the room sees it because the facilitator shares or projects their screen. See the [presentation guide](../guides/presentation.md) for the full picture.
17
+
18
+ ## Prerequisites
19
+
20
+ - A game to attach the deck to; see [Shape your game](create-game.md)
21
+ - `@seriousgaming/deck` in your `package.json`, at the same version as the SDK. A newly scaffolded package already has it; an older one adds it:
22
+ ```bash
23
+ pnpm add @seriousgaming/deck@<your SDK version>
24
+ ```
25
+ - `seriousgaming.sdk.json` in your working directory
26
+
27
+ ## Steps
28
+
29
+ ### 1. Create the presentation
30
+
31
+ ```bash
32
+ pnpm run sdk new presentation '{
33
+ "definition": {
34
+ "reads": ["results"],
35
+ "settings": ["engine"]
36
+ },
37
+ "rootDirectory": ".",
38
+ "ui": {
39
+ "entrypoint": "index.html"
40
+ }
41
+ }'
42
+ ```
43
+
44
+ `reads` names the capabilities the deck shows, from every team. `settings` names the settings resources it varies on. Neither `writes`, `uses` nor `endpoints` is accepted. This creates:
45
+
46
+ ```
47
+ presentation/
48
+ ├── presentation.sdk.json
49
+ ├── index.html
50
+ ├── types.ts
51
+ └── src/
52
+ ├── main.tsx
53
+ ├── App.tsx
54
+ ├── Slides.tsx
55
+ └── i18n.ts
56
+ ```
57
+
58
+ ### 2. Write the slides
59
+
60
+ `presentation/src/Slides.tsx` returns an array, and every element of it is one slide. Use the deck's building blocks for anything a facilitator might want to edit after exporting (see [Habits that keep an export faithful](../guides/presentation.md#habits-that-keep-an-export-faithful)):
61
+
62
+ ```tsx
63
+ import { Bullets, Heading, Slide, Table, Text } from '@seriousgaming/deck';
64
+
65
+ import type { PresentationSession } from '../types';
66
+
67
+ export function slides({ session }: { session: PresentationSession | null }) {
68
+ return [
69
+ <Slide key="agenda" transition="slide" notes="Reveal each point in turn.">
70
+ <div style={{ padding: '120px 140px' }}>
71
+ <Heading>Today</Heading>
72
+ <Bullets stepped items={['Meet your team', 'Play the rounds', 'Review together']} />
73
+ </div>
74
+ </Slide>,
75
+
76
+ <Slide key="results" transition="rise">
77
+ <div style={{ padding: '120px 140px' }}>
78
+ <Heading>Results</Heading>
79
+ {session ? (
80
+ <Table
81
+ columns={['Team', 'Round']}
82
+ align={['start', 'end']}
83
+ rows={session.teams.map((team) => [
84
+ team.name,
85
+ session.data.teams[team.teamId]?.completedTicks ?? 0,
86
+ ])}
87
+ />
88
+ ) : (
89
+ <Text>Sample data: results appear here once the session has started</Text>
90
+ )}
91
+ </div>
92
+ </Slide>,
93
+ ];
94
+ }
95
+ ```
96
+
97
+ - Give every slide a `key`. The deck remembers the slide a facilitator was on by that name, so a slide that comes and goes with a setting does not shift them onto the wrong one
98
+ - `stepped` on `Bullets` reveals one item per click. Wrap anything else in `<Step at={n}>` to do the same
99
+ - `notes` go to nobody on screen and into PowerPoint's notes pane on export
100
+
101
+ ### 3. Make it work with no session
102
+
103
+ `session` is `null` whenever the deck is shown outside a session: in a game's library, while a facilitator rehearses, or to export it before the day. Every slide must still make sense then. Where a slide would show results, show sample or placeholder figures and say so on the slide.
104
+
105
+ ### 4. Route every word through i18n
106
+
107
+ The scaffold keeps every word in `src/i18n.ts`, in English, Italian and Arabic, and sets the deck's language and direction from `usePresentation().locale`. Add a key there for each new word, and a translation for each locale the game supports, rather than writing words into a slide.
108
+
109
+ ### 5. Build
110
+
111
+ ```bash
112
+ pnpm run build
113
+ ```
114
+
115
+ ## Verify
116
+
117
+ ```bash
118
+ pnpm run sdk dev
119
+ ```
120
+
121
+ Open http://localhost:3000/presentation for the deck during the session, or http://localhost:3000/presentation?preview for the deck as it looks with no session. Then:
122
+
123
+ - Press the right arrow, space or page down to advance, O for the overview, and F for fullscreen
124
+ - Move the pointer to show the controls, and use **Export** to download a PDF, a PowerPoint file and a PNG of the current slide
125
+ - Open the PowerPoint file and check that headings, bullets and tables are editable text
126
+
127
+ ## Troubleshooting
128
+
129
+ | Problem | Solution |
130
+ | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
131
+ | `Cannot find module '@seriousgaming/deck'` | Add the deck package at the SDK's version (see prerequisites), then `pnpm install` |
132
+ | The whole deck is one slide | The slides are wrapped in a component of your own. Return them as an array, or make each component render one `Slide` |
133
+ | The deck shows blank or broken with `?preview` | A slide reads `session` without checking for `null` |
134
+ | `data` is empty for a team | Add the capability to the presentation's `reads`, then run `pnpm run sdk generate` |
135
+ | An export differs from the screen | See [Habits that keep an export faithful](../guides/presentation.md#habits-that-keep-an-export-faithful) |
136
+ | The deck shows the wrong slides for a scenario | Branch on settings and scenario assets, never on `game.scenarioName` |
137
+
138
+ ## Related
139
+
140
+ - [Presentation guide](../guides/presentation.md): the slot, the deck library, resume and export
141
+ - [Create a facilitator guide](create-guide.md): the run sheet beside the deck
142
+ - [Create a scenario](create-scenario.md): vary the deck through settings and assets
@@ -0,0 +1,102 @@
1
+ # Create a scenario editor
2
+
3
+ Give people a screen for building new scenarios for your released game, without rebuilding it.
4
+
5
+ **Keywords:** scenario editor, scenario builder, custom scenarios, author scenario, save as scenario, customScenarios, settings editor, configures
6
+
7
+ ## What you'll build
8
+
9
+ A scenario editor at `scenario_editor/` that edits the `engine` and `ui` settings. The host offers save-as-scenario from it, never from setup. See the [scenario editor guide](../guides/scenario-editor.md) for when a game needs one.
10
+
11
+ ## Prerequisites
12
+
13
+ - Settings resources for the editor to edit; see [Create a settings resource](create-settings.md)
14
+ - `seriousgaming.sdk.json` in your working directory
15
+
16
+ ## Steps
17
+
18
+ ### 1. Switch custom scenarios on
19
+
20
+ The editor is optional; this declaration is what lets a hosted runtime save scenarios for the game:
21
+
22
+ ```bash
23
+ pnpm run sdk update package --patch '[
24
+ { "op": "add", "path": "/customScenarios", "value": { "supported": true } }
25
+ ]'
26
+ ```
27
+
28
+ ### 2. Create the slot
29
+
30
+ ```bash
31
+ pnpm run sdk new scenario_editor '{
32
+ "definition": {
33
+ "configures": ["engine", "ui"]
34
+ },
35
+ "rootDirectory": ".",
36
+ "ui": { "entrypoint": "index.html" }
37
+ }'
38
+ ```
39
+
40
+ This creates `scenario_editor/` with `scenario_editor.sdk.json`, `index.html`, `src/{main,App,i18n,theme}`, and the generated `types.ts` and `defaults.ts`.
41
+
42
+ ### 3. Build the editor
43
+
44
+ Open `scenario_editor/src/App.tsx`. It uses the same hooks as setup:
45
+
46
+ ```tsx
47
+ import { useSettingsEditor } from '@seriousgaming/sdk/ui';
48
+ import { Stack, TextField } from '@mui/material';
49
+ import type { Settings } from '../types';
50
+
51
+ function App() {
52
+ const { settings, updateSettings } = useSettingsEditor<Settings>();
53
+
54
+ return (
55
+ <Stack spacing={2}>
56
+ <TextField
57
+ label="Maximum price"
58
+ type="number"
59
+ value={settings.ui.MaxPrice}
60
+ onChange={(e) =>
61
+ void updateSettings({
62
+ ui: { ...settings.ui, MaxPrice: Number(e.target.value) },
63
+ })
64
+ }
65
+ />
66
+ </Stack>
67
+ );
68
+ }
69
+
70
+ export default App;
71
+ ```
72
+
73
+ Do not add a save button or call `requestPlay`: the host owns saving, and ignores `requestPlay` from the editor.
74
+
75
+ ### 4. Edit a scenario in the dev server
76
+
77
+ ```bash
78
+ pnpm run sdk dev
79
+ ```
80
+
81
+ Open the dev drawer, then **Scenario**, then **Edit** on a scenario (or **Add scenario**). The editor opens on `/scenario-editor`. Change a value and click **Save**.
82
+
83
+ ## Verify
84
+
85
+ - [ ] `scenarios/<identifier>/scenario.sdk.json` holds the value you changed, under its settings identifier
86
+ - [ ] Selecting that scenario starts a session with the value
87
+
88
+ ## Troubleshooting
89
+
90
+ **Edit opens nothing to edit**
91
+
92
+ The package has no `scenario_editor/scenario_editor.sdk.json`. Without an editor, set values with `pnpm run sdk configure` and add a scenario from the current settings.
93
+
94
+ **An agent cannot tell what a setting means**
95
+
96
+ Describe every property in the settings schema: `title`, `description` with units, `minimum` and `maximum`, and `enum` where the choices are closed. An agent edits a game with no editor UI from those alone.
97
+
98
+ ## Related
99
+
100
+ - [Create a setup screen](create-setup.md)
101
+ - [Create a scenario](create-scenario.md)
102
+ - [Scenarios guide](../guides/scenarios.md)
@@ -0,0 +1,98 @@
1
+ # Create a scenario
2
+
3
+ Bundle a game flavour with settings overrides and static assets.
4
+
5
+ **Keywords:** create scenario, new scenario, game variant, game flavour, difficulty preset, storyline, scenario assets
6
+
7
+ ## What you'll build
8
+
9
+ A scenario called `hard_mode` that overrides the engine's `demand` settings and includes a briefing PDF.
10
+
11
+ ## Prerequisites
12
+
13
+ - A package with a `demand` settings resource that declares `BaseDemand` and `InflationRate` (see [Create a settings resource](create-settings.md))
14
+ - `seriousgaming.sdk.json` in your working directory
15
+
16
+ ## Steps
17
+
18
+ ### 1. Create the scenario
19
+
20
+ ```bash
21
+ pnpm run sdk new scenario '{
22
+ "definition": {
23
+ "identifier": "hard_mode",
24
+ "locales": {
25
+ "en": {
26
+ "name": "Hard Mode",
27
+ "description": "Higher costs, lower demand"
28
+ }
29
+ },
30
+ "settings": {
31
+ "demand": { "BaseDemand": 30, "InflationRate": 0.15 }
32
+ }
33
+ },
34
+ "rootDirectory": "."
35
+ }'
36
+ ```
37
+
38
+ Overrides are keyed by settings identifier and are partial: a key you leave out falls through to its default. Every resource that lists `demand` in its `settings` receives the overridden values.
39
+
40
+ ### 2. Add assets
41
+
42
+ ```bash
43
+ cp briefing.pdf scenarios/hard_mode/assets/shared/
44
+ ```
45
+
46
+ ### 3. Mark it as the default
47
+
48
+ ```bash
49
+ pnpm run sdk update scenario hard_mode --patch '[
50
+ { "op": "add", "path": "/definition/default", "value": true }
51
+ ]'
52
+ ```
53
+
54
+ ### 4. Load assets in a UI
55
+
56
+ Scenario assets are referenced under the `asset:` URI scheme (see [Asset references](../guides/file-handling.md#asset-references)):
57
+
58
+ ```typescript
59
+ const { getAssetUrl } = useUserInterfaceCallbacks();
60
+ return <a href={getAssetUrl('asset:shared/briefing.pdf')}>Download briefing</a>;
61
+ ```
62
+
63
+ ## Verify
64
+
65
+ ```bash
66
+ # Check the overrides against each settings resource's settingsSchema
67
+ pnpm run sdk build --validate-only
68
+
69
+ # CLI
70
+ pnpm run sdk init --scenario hard_mode
71
+ pnpm run sdk tick
72
+
73
+ # Dev server
74
+ pnpm run sdk dev --scenario hard_mode
75
+ ```
76
+
77
+ The game should initialise with `BaseDemand: 30` and `InflationRate: 0.15`. A facilitator can still override these values through the game's setup screen: the scenario is a starting point, not a lock.
78
+
79
+ You should now have:
80
+
81
+ - `scenarios/hard_mode/scenario.sdk.json`, the scenario definition
82
+ - `scenarios/hard_mode/assets/shared/briefing.pdf`, the static asset
83
+
84
+ ## Troubleshooting
85
+
86
+ | Problem | Solution |
87
+ | ---------------------------------------- | ----------------------------------------------------------------------------------- |
88
+ | Build rejects an override key | The settings resource's `settingsSchema` does not declare it, usually a misspelling |
89
+ | Build rejects a settings identifier | The package holds no settings resource by that name |
90
+ | Override has no effect in the UI | The UI does not list those settings in its `settings` array |
91
+ | Build refuses a default scenario | A restricted scenario cannot also be the default |
92
+ | Facilitator value wins over the scenario | By design: the session overrides a facilitator sets win over scenario values |
93
+
94
+ ## Related
95
+
96
+ - [Scenarios guide](../guides/scenarios.md): the model, validation, resolution order, team names and restricted scenarios
97
+ - [Share assets across scenarios](./share-assets-across-scenarios.md)
98
+ - [Create a settings resource](create-settings.md)