@seriousgaming/sdk-tools 0.0.0-stage → 1.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +93 -0
- package/README.md +38 -2
- package/dist/bundling/logic-exports.d.ts +34 -0
- package/dist/bundling/node-builtins.d.ts +21 -0
- package/dist/bundling/transpiler.d.ts +7 -0
- package/dist/cli.js +27404 -0
- package/dist/client/dev-server.d.ts +59 -0
- package/dist/client/index.d.ts +28 -0
- package/dist/client/stub-services.d.ts +32 -0
- package/dist/client/test-session.d.ts +195 -0
- package/dist/client.js +16920 -0
- package/dist/core/asset-reference-translator.d.ts +46 -0
- package/dist/core/clock.d.ts +57 -0
- package/dist/core/faults.d.ts +65 -0
- package/dist/core/game-settings.d.ts +65 -0
- package/dist/core/history.d.ts +89 -0
- package/dist/core/listen-with-fallback.d.ts +30 -0
- package/dist/core/mutation-queue.d.ts +61 -0
- package/dist/core/package-scenario.d.ts +89 -0
- package/dist/core/participant-registry.d.ts +109 -0
- package/dist/core/pending-changes.d.ts +14 -0
- package/dist/core/protocol.d.ts +83 -0
- package/dist/core/scenario-drafts.d.ts +32 -0
- package/dist/core/session-endpoints.d.ts +108 -0
- package/dist/core/session-gates.d.ts +75 -0
- package/dist/core/session-host.d.ts +94 -0
- package/dist/core/session-refusals.d.ts +56 -0
- package/dist/core/session-rewind.d.ts +32 -0
- package/dist/core/session-roster.d.ts +128 -0
- package/dist/core/session-surfaces.d.ts +32 -0
- package/dist/core/session-ticks.d.ts +18 -0
- package/dist/core/session-timers.d.ts +84 -0
- package/dist/core/session-writes.d.ts +40 -0
- package/dist/core/session.d.ts +385 -0
- package/dist/core/settings-locks.d.ts +22 -0
- package/dist/core/team-names.d.ts +52 -0
- package/dist/core/team-state-store.d.ts +218 -0
- package/dist/core/tick-timer.d.ts +75 -0
- package/dist/dev/blob-links.d.ts +10 -0
- package/dist/dev/console/assets/index-DgFglsnA.js +204 -0
- package/dist/dev/console/index.html +12 -0
- package/dist/dev/console-path.d.ts +19 -0
- package/dist/dev/lockfile.d.ts +124 -0
- package/dist/dev/package-watcher.d.ts +21 -0
- package/dist/dev/routes.d.ts +67 -0
- package/dist/dev/shell.d.ts +260 -0
- package/dist/dev/surfaces.d.ts +41 -0
- package/dist/dev/tools-identity.d.ts +23 -0
- package/dist/dev/view/batch.d.ts +172 -0
- package/dist/dev/view/commands.d.ts +75 -0
- package/dist/dev/view/route.d.ts +58 -0
- package/dist/dev/view/view.d.ts +78 -0
- package/dist/dev/view/viewer.d.ts +32 -0
- package/dist/discovery/config.d.ts +9 -0
- package/dist/discovery/manifest-paths.d.ts +21 -0
- package/dist/discovery/removed-fields.d.ts +90 -0
- package/dist/docs/api/deck.md +386 -0
- package/dist/docs/api/index.md +67 -0
- package/dist/docs/api/sdk-commands.md +286 -0
- package/dist/docs/api/sdk-e2e.md +433 -0
- package/dist/docs/api/sdk-projection.md +207 -0
- package/dist/docs/api/sdk-testing.md +214 -0
- package/dist/docs/api/sdk-tools-client.md +560 -0
- package/dist/docs/api/sdk-ui-testing.md +231 -0
- package/dist/docs/api/sdk-ui.md +1269 -0
- package/dist/docs/api/sdk.md +2140 -0
- package/dist/docs/changelog-0.x.md +1156 -0
- package/dist/docs/changelog.md +241 -0
- package/dist/docs/cli-and-dev-server.md +217 -0
- package/dist/docs/cli-error-codes.md +156 -0
- package/dist/docs/cli-reference.md +2489 -0
- package/dist/docs/cli-simulation-testing.md +222 -0
- package/dist/docs/concepts/index.md +46 -0
- package/dist/docs/concepts/terminology.md +322 -0
- package/dist/docs/environment-variables.md +102 -0
- package/dist/docs/getting-started.md +145 -0
- package/dist/docs/guides/ai-facilitation.md +220 -0
- package/dist/docs/guides/capabilities.md +460 -0
- package/dist/docs/guides/endpoints.md +335 -0
- package/dist/docs/guides/engine-testing.md +477 -0
- package/dist/docs/guides/engine.md +527 -0
- package/dist/docs/guides/file-handling.md +405 -0
- package/dist/docs/guides/games.md +176 -0
- package/dist/docs/guides/global-settings.md +94 -0
- package/dist/docs/guides/guide.md +123 -0
- package/dist/docs/guides/hooks.md +183 -0
- package/dist/docs/guides/index.md +51 -0
- package/dist/docs/guides/internationalization.md +288 -0
- package/dist/docs/guides/llm-integration.md +635 -0
- package/dist/docs/guides/multi-team-games.md +586 -0
- package/dist/docs/guides/patterns.md +391 -0
- package/dist/docs/guides/presentation.md +196 -0
- package/dist/docs/guides/production-constraints.md +130 -0
- package/dist/docs/guides/scenario-editor.md +143 -0
- package/dist/docs/guides/scenarios.md +515 -0
- package/dist/docs/guides/session.md +972 -0
- package/dist/docs/guides/settings.md +458 -0
- package/dist/docs/guides/setup.md +193 -0
- package/dist/docs/guides/speech-generation.md +233 -0
- package/dist/docs/guides/starter-game.md +164 -0
- package/dist/docs/guides/testing.md +577 -0
- package/dist/docs/guides/tick-controller.md +569 -0
- package/dist/docs/guides/type-safety.md +516 -0
- package/dist/docs/guides/ui.md +1389 -0
- package/dist/docs/guides/upgrading.md +636 -0
- package/dist/docs/guides/validators.md +217 -0
- package/dist/docs/guides/waiting-room.md +244 -0
- package/dist/docs/index.md +41 -0
- package/dist/docs/recipes/act-on-the-session-from-an-endpoint.md +95 -0
- package/dist/docs/recipes/adapt-a-game-for-walkthroughs.md +133 -0
- package/dist/docs/recipes/adapt-ui-for-observers.md +74 -0
- package/dist/docs/recipes/call-endpoint-from-ui.md +109 -0
- package/dist/docs/recipes/check-a-package-from-a-script.md +117 -0
- package/dist/docs/recipes/create-capability.md +66 -0
- package/dist/docs/recipes/create-endpoint.md +127 -0
- package/dist/docs/recipes/create-engine.md +111 -0
- package/dist/docs/recipes/create-game.md +70 -0
- package/dist/docs/recipes/create-guide.md +75 -0
- package/dist/docs/recipes/create-hook.md +80 -0
- package/dist/docs/recipes/create-presentation.md +142 -0
- package/dist/docs/recipes/create-scenario-editor.md +102 -0
- package/dist/docs/recipes/create-scenario.md +98 -0
- package/dist/docs/recipes/create-session-ui.md +116 -0
- package/dist/docs/recipes/create-settings.md +88 -0
- package/dist/docs/recipes/create-setup.md +115 -0
- package/dist/docs/recipes/create-tick-controller.md +65 -0
- package/dist/docs/recipes/create-user-interface.md +96 -0
- package/dist/docs/recipes/create-validator.md +67 -0
- package/dist/docs/recipes/create-waiting-room-ui.md +109 -0
- package/dist/docs/recipes/declare-api-uses.md +67 -0
- package/dist/docs/recipes/design-state-for-concurrent-writes.md +96 -0
- package/dist/docs/recipes/distribute-package.md +80 -0
- package/dist/docs/recipes/e2e-testing.md +116 -0
- package/dist/docs/recipes/end-game-on-condition.md +154 -0
- package/dist/docs/recipes/fix-duplicate-packages.md +101 -0
- package/dist/docs/recipes/index.md +86 -0
- package/dist/docs/recipes/make-an-endpoint-external.md +101 -0
- package/dist/docs/recipes/negotiate-across-teams.md +164 -0
- package/dist/docs/recipes/observe-other-teams-state.md +119 -0
- package/dist/docs/recipes/publish-a-package.md +139 -0
- package/dist/docs/recipes/remember-a-viewers-choice.md +55 -0
- package/dist/docs/recipes/review-a-past-day.md +73 -0
- package/dist/docs/recipes/share-assets-across-scenarios.md +120 -0
- package/dist/docs/recipes/share-logic-between-engine-and-ui.md +130 -0
- package/dist/docs/recipes/show-all-teams-participants.md +109 -0
- package/dist/docs/recipes/start-from-an-empty-package.md +169 -0
- package/dist/docs/recipes/take-a-file-in-an-endpoint.md +82 -0
- package/dist/docs/recipes/test-a-multi-role-game.md +51 -0
- package/dist/docs/recipes/test-user-interface.md +95 -0
- package/dist/docs/recipes/test-with-engine.md +115 -0
- package/dist/docs/recipes/upload-and-display-files.md +148 -0
- package/dist/docs/recipes/use-request-play.md +65 -0
- package/dist/docs/recipes/use-request-tick.md +75 -0
- package/dist/docs/troubleshooting.md +816 -0
- package/dist/execution/blob-inputs.d.ts +57 -0
- package/dist/execution/bundle-reload.d.ts +42 -0
- package/dist/execution/config-resolver.d.ts +127 -0
- package/dist/execution/configuration-builder.d.ts +66 -0
- package/dist/execution/context-composition.d.ts +161 -0
- package/dist/execution/endpoint-actions.d.ts +9 -0
- package/dist/execution/endpoint-payloads.d.ts +32 -0
- package/dist/execution/endpoint-runner.d.ts +129 -0
- package/dist/execution/engine-state.d.ts +40 -0
- package/dist/execution/executor-callbacks.d.ts +56 -0
- package/dist/execution/executor.d.ts +436 -0
- package/dist/execution/gates.d.ts +45 -0
- package/dist/execution/hook-chain.d.ts +25 -0
- package/dist/execution/logic-calls.d.ts +190 -0
- package/dist/execution/logic-failure.d.ts +84 -0
- package/dist/execution/logic-loader.d.ts +54 -0
- package/dist/execution/logic-result.d.ts +76 -0
- package/dist/execution/tick-controller-call.d.ts +32 -0
- package/dist/execution/types.d.ts +48 -0
- package/dist/generation/ts-type.d.ts +39 -0
- package/dist/guide/locale.d.ts +12 -0
- package/dist/guide/video-registry.d.ts +42 -0
- package/dist/help-examples.d.ts +125 -0
- package/dist/host/adapter.d.ts +67 -0
- package/dist/host/host-channel.d.ts +222 -0
- package/dist/host/index.d.ts +20 -0
- package/dist/host/protocol.d.ts +783 -0
- package/dist/host/surfaces.d.ts +42 -0
- package/dist/host/theme.d.ts +55 -0
- package/dist/host.js +583 -0
- package/dist/prompts/index.d.ts +7 -0
- package/dist/prompts/schema-builder.d.ts +29 -0
- package/dist/prompts/types.d.ts +108 -0
- package/dist/prompts/validators.d.ts +32 -0
- package/dist/runtime/capability-scope.d.ts +6 -0
- package/dist/runtime/context-merge.d.ts +29 -0
- package/dist/runtime/context-projection.d.ts +41 -0
- package/dist/runtime/guarded-callbacks.d.ts +15 -0
- package/dist/runtime/index.d.ts +27 -0
- package/dist/runtime/manifest-version.d.ts +55 -0
- package/dist/runtime/tick-validation.d.ts +25 -0
- package/dist/runtime.js +346 -0
- package/dist/schema.json +1546 -0
- package/dist/server/vite-plugin.d.ts +46 -0
- package/dist/services/tts/client.d.ts +51 -0
- package/dist/services/tts/elevenlabs.d.ts +24 -0
- package/dist/services/tts/types.d.ts +44 -0
- package/dist/storage/asset-resolver.d.ts +49 -0
- package/dist/storage/blob-store.d.ts +41 -0
- package/dist/templates/endpoint/logic.test.ts.liquid +61 -0
- package/dist/templates/endpoint/logic.ts.liquid +25 -0
- package/dist/templates/engine/init.json.liquid +7 -0
- package/dist/templates/engine/logic-aggregate.test.ts.liquid +90 -0
- package/dist/templates/engine/logic-aggregate.ts.liquid +46 -0
- package/dist/templates/engine/logic.test.ts.liquid +61 -0
- package/dist/templates/engine/logic.ts.liquid +32 -0
- package/dist/templates/engine/run.json.liquid +7 -0
- package/dist/templates/guide/01-at-a-glance.md.liquid +19 -0
- package/dist/templates/guide/02-preparation.md.liquid +18 -0
- package/dist/templates/guide/03-running-the-session.md.liquid +37 -0
- package/dist/templates/hook/logic.test.ts.liquid +46 -0
- package/dist/templates/hook/logic.ts.liquid +12 -0
- package/dist/templates/package/CLAUDE.md.template +338 -0
- package/dist/templates/package/DESIGN.md.liquid +144 -0
- package/dist/templates/package/README.md.liquid +143 -0
- package/dist/templates/package/claude/rules/workflow-create-capability.md +26 -0
- package/dist/templates/package/claude/rules/workflow-create-endpoint.md +35 -0
- package/dist/templates/package/claude/rules/workflow-create-engine.md +35 -0
- package/dist/templates/package/claude/rules/workflow-create-guide.md +40 -0
- package/dist/templates/package/claude/rules/workflow-create-presentation.md +37 -0
- package/dist/templates/package/claude/rules/workflow-create-user-interface.md +31 -0
- package/dist/templates/package/claude/rules/workflow-publish-package.md +54 -0
- package/dist/templates/package/claude/rules/workflow-test-engine-or-ui.md +30 -0
- package/dist/templates/package/claude/rules/workflow-update-sdk-version.md +43 -0
- package/dist/templates/package/claude/settings.json.template +16 -0
- package/dist/templates/package/gitignore.template +15 -0
- package/dist/templates/package/global-setup.ts.template +21 -0
- package/dist/templates/package/globals.d.ts.template +2 -0
- package/dist/templates/package/oxfmtrc.json.template +14 -0
- package/dist/templates/package/oxlintrc.json.template +238 -0
- package/dist/templates/package/package.json.liquid +65 -0
- package/dist/templates/package/playwright.config.ts.liquid +19 -0
- package/dist/templates/package/pnpm-workspace.yaml.template +27 -0
- package/dist/templates/package/test-setup.ts.liquid +7 -0
- package/dist/templates/package/tsconfig.json.liquid +15 -0
- package/dist/templates/package/vite.config.ts.liquid +19 -0
- package/dist/templates/package/vitest.config.ts.liquid +25 -0
- package/dist/templates/package/vitest.engine.config.ts.liquid +12 -0
- package/dist/templates/presentation/index.html.liquid +20 -0
- package/dist/templates/presentation/src/App.tsx.liquid +49 -0
- package/dist/templates/presentation/src/Slides.tsx.liquid +81 -0
- package/dist/templates/presentation/src/i18n.ts.liquid +54 -0
- package/dist/templates/presentation/src/main.tsx.liquid +14 -0
- package/dist/templates/scenario_editor/src/App.test.tsx.liquid +30 -0
- package/dist/templates/scenario_editor/src/App.tsx.liquid +95 -0
- package/dist/templates/scenario_editor/src/i18n.ts.liquid +44 -0
- package/dist/templates/session/src/App.test.tsx.liquid +60 -0
- package/dist/templates/session/src/App.tsx.liquid +128 -0
- package/dist/templates/session/src/i18n.ts.liquid +53 -0
- package/dist/templates/session/src/main.tsx.liquid +48 -0
- package/dist/templates/session/src/theme.ts.liquid +46 -0
- package/dist/templates/settings-editor/index.html.liquid +12 -0
- package/dist/templates/settings-editor/src/main.tsx.liquid +48 -0
- package/dist/templates/settings-editor/src/theme.ts.liquid +24 -0
- package/dist/templates/setup/src/App.test.tsx.liquid +39 -0
- package/dist/templates/setup/src/App.tsx.liquid +102 -0
- package/dist/templates/setup/src/i18n.ts.liquid +47 -0
- package/dist/templates/starter-game/capabilities/briefing/capability.sdk.json +18 -0
- package/dist/templates/starter-game/capabilities/plan/capability.sdk.json +17 -0
- package/dist/templates/starter-game/capabilities/results/capability.sdk.json +61 -0
- package/dist/templates/starter-game/capabilities/roles/capability.sdk.json +17 -0
- package/dist/templates/starter-game/capabilities/weather/capability.sdk.json +23 -0
- package/dist/templates/starter-game/engine/defaults.ts +81 -0
- package/dist/templates/starter-game/engine/engine.sdk.json +12 -0
- package/dist/templates/starter-game/engine/logic.test.ts +221 -0
- package/dist/templates/starter-game/engine/logic.ts +149 -0
- package/dist/templates/starter-game/engine/test-helpers.ts +74 -0
- package/dist/templates/starter-game/engine/types.ts +139 -0
- package/dist/templates/starter-game/guide/content/en/01-at-a-glance.md +51 -0
- package/dist/templates/starter-game/guide/content/en/02-preparation.md +35 -0
- package/dist/templates/starter-game/guide/content/en/03-running-the-day.md +58 -0
- package/dist/templates/starter-game/guide/guide.sdk.json +10 -0
- package/dist/templates/starter-game/guide/guide.test.ts +108 -0
- package/dist/templates/starter-game/hooks/assignproducts/defaults.ts +37 -0
- package/dist/templates/starter-game/hooks/assignproducts/hook.sdk.json +13 -0
- package/dist/templates/starter-game/hooks/assignproducts/logic/logic.test.ts +77 -0
- package/dist/templates/starter-game/hooks/assignproducts/logic/logic.ts +47 -0
- package/dist/templates/starter-game/hooks/assignproducts/types.ts +55 -0
- package/dist/templates/starter-game/package.json +68 -0
- package/dist/templates/starter-game/playwright.config.ts +19 -0
- package/dist/templates/starter-game/scenarios/heatwave/scenario.sdk.json +20 -0
- package/dist/templates/starter-game/scenarios/ordinary_week/scenario.sdk.json +12 -0
- package/dist/templates/starter-game/seriousgaming.sdk.json +23 -0
- package/dist/templates/starter-game/session/defaults.ts +80 -0
- package/dist/templates/starter-game/session/index.html +12 -0
- package/dist/templates/starter-game/session/session.sdk.json +11 -0
- package/dist/templates/starter-game/session/src/App.test.tsx +307 -0
- package/dist/templates/starter-game/session/src/App.tsx +309 -0
- package/dist/templates/starter-game/session/src/Section.tsx +37 -0
- package/dist/templates/starter-game/session/src/TeamDoor.tsx +96 -0
- package/dist/templates/starter-game/session/src/format.ts +8 -0
- package/dist/templates/starter-game/session/src/i18n.ts +51 -0
- package/dist/templates/starter-game/session/src/main.tsx +48 -0
- package/dist/templates/starter-game/session/src/theme.ts +45 -0
- package/dist/templates/starter-game/session/types.ts +135 -0
- package/dist/templates/starter-game/settings/engine/settings.sdk.json +50 -0
- package/dist/templates/starter-game/settings/menu/settings.sdk.json +78 -0
- package/dist/templates/starter-game/settings/session/settings.sdk.json +23 -0
- package/dist/templates/starter-game/settings/ui/settings.sdk.json +25 -0
- package/dist/templates/starter-game/test-setup.ts +7 -0
- package/dist/templates/starter-game/testing/e2e/game.spec.ts +139 -0
- package/dist/templates/starter-game/testing/e2e/global-setup.ts +21 -0
- package/dist/templates/starter-game/testing/engine/game.engine.test.ts +171 -0
- package/dist/templates/starter-game/tsconfig.json +19 -0
- package/dist/templates/starter-game/ui/defaults.ts +60 -0
- package/dist/templates/starter-game/ui/index.html +12 -0
- package/dist/templates/starter-game/ui/src/App.test.tsx +138 -0
- package/dist/templates/starter-game/ui/src/App.tsx +175 -0
- package/dist/templates/starter-game/ui/src/DayBar.test.tsx +78 -0
- package/dist/templates/starter-game/ui/src/DayBar.tsx +72 -0
- package/dist/templates/starter-game/ui/src/HistoryPanel.test.tsx +74 -0
- package/dist/templates/starter-game/ui/src/HistoryPanel.tsx +120 -0
- package/dist/templates/starter-game/ui/src/MakeRow.tsx +129 -0
- package/dist/templates/starter-game/ui/src/Section.tsx +37 -0
- package/dist/templates/starter-game/ui/src/ThemeToggle.tsx +49 -0
- package/dist/templates/starter-game/ui/src/TodayPanel.test.tsx +179 -0
- package/dist/templates/starter-game/ui/src/TodayPanel.tsx +92 -0
- package/dist/templates/starter-game/ui/src/YesterdayPanel.tsx +142 -0
- package/dist/templates/starter-game/ui/src/format.ts +12 -0
- package/dist/templates/starter-game/ui/src/i18n.ts +95 -0
- package/dist/templates/starter-game/ui/src/main.tsx +48 -0
- package/dist/templates/starter-game/ui/src/menu.ts +18 -0
- package/dist/templates/starter-game/ui/src/test-helpers.ts +58 -0
- package/dist/templates/starter-game/ui/src/theme.ts +45 -0
- package/dist/templates/starter-game/ui/src/writes.ts +43 -0
- package/dist/templates/starter-game/ui/types.ts +137 -0
- package/dist/templates/starter-game/ui/ui.sdk.json +11 -0
- package/dist/templates/starter-game/validators/capacity/defaults.ts +37 -0
- package/dist/templates/starter-game/validators/capacity/logic/logic.test.ts +96 -0
- package/dist/templates/starter-game/validators/capacity/logic/logic.ts +45 -0
- package/dist/templates/starter-game/validators/capacity/types.ts +55 -0
- package/dist/templates/starter-game/validators/capacity/validator.sdk.json +11 -0
- package/dist/templates/starter-game/vite.config.ts +19 -0
- package/dist/templates/starter-game/vitest.config.ts +15 -0
- package/dist/templates/starter-game/vitest.engine.config.ts +19 -0
- package/dist/templates/starter-game/waiting_room/defaults.ts +40 -0
- package/dist/templates/starter-game/waiting_room/index.html +12 -0
- package/dist/templates/starter-game/waiting_room/src/App.test.tsx +102 -0
- package/dist/templates/starter-game/waiting_room/src/App.tsx +194 -0
- package/dist/templates/starter-game/waiting_room/src/i18n.ts +33 -0
- package/dist/templates/starter-game/waiting_room/src/main.tsx +48 -0
- package/dist/templates/starter-game/waiting_room/src/theme.ts +45 -0
- package/dist/templates/starter-game/waiting_room/types.ts +59 -0
- package/dist/templates/starter-game/waiting_room/waiting_room.sdk.json +10 -0
- package/dist/templates/tick-controller/logic.ts.liquid +8 -0
- package/dist/templates/ui/index.html.liquid +12 -0
- package/dist/templates/ui/src/App.test.tsx.liquid +41 -0
- package/dist/templates/ui/src/App.tsx.liquid +103 -0
- package/dist/templates/ui/src/i18n.ts.liquid +47 -0
- package/dist/templates/ui/src/main.tsx.liquid +48 -0
- package/dist/templates/ui/src/theme.ts.liquid +46 -0
- package/dist/templates/validator/logic.test.ts.liquid +42 -0
- package/dist/templates/validator/logic.ts.liquid +21 -0
- package/dist/templates/waiting-room/index.html.liquid +12 -0
- package/dist/templates/waiting-room/src/App.test.tsx.liquid +57 -0
- package/dist/templates/waiting-room/src/App.tsx.liquid +118 -0
- package/dist/templates/waiting-room/src/i18n.ts.liquid +44 -0
- package/dist/templates/waiting-room/src/main.tsx.liquid +48 -0
- package/dist/templates/waiting-room/src/theme.ts.liquid +46 -0
- package/dist/templating/resource-metadata.d.ts +131 -0
- package/dist/types.d.ts +14 -0
- package/dist/utils/atomic-write.d.ts +40 -0
- package/dist/utils/cli-error.d.ts +64 -0
- package/dist/utils/document-parser-client.d.ts +20 -0
- package/dist/utils/env-loader.d.ts +40 -0
- package/dist/utils/error-codes.d.ts +339 -0
- package/dist/utils/errors.d.ts +19 -0
- package/dist/utils/global-settings.d.ts +65 -0
- package/dist/utils/llm-client.d.ts +34 -0
- package/dist/utils/logger.d.ts +36 -0
- package/dist/utils/output.d.ts +109 -0
- package/dist/utils/platform.d.ts +14 -0
- package/dist/utils/prompt.d.ts +36 -0
- package/dist/utils/real-path.d.ts +6 -0
- package/dist/utils/schema-properties.d.ts +35 -0
- package/dist/validation/ajv.d.ts +17 -0
- package/dist/validation/facilitator-guide-validator.d.ts +27 -0
- package/dist/validation/findings.d.ts +40 -0
- package/dist/validation/game-constraints.d.ts +10 -0
- package/dist/validation/game-validator.d.ts +34 -0
- package/dist/validation/package-validation.d.ts +41 -0
- package/dist/validation/package-validator.d.ts +19 -0
- package/dist/validation/resource-validator.d.ts +79 -0
- package/dist/validation/schema-defaults-validator.d.ts +29 -0
- package/dist/validation/schema-validation.d.ts +115 -0
- package/dist/validation/semver.d.ts +9 -0
- package/package.json +123 -3
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
# Scenarios
|
|
2
|
+
|
|
3
|
+
A scenario is a named set of settings overrides and static assets that makes a distinct flavour of a game: a different storyline, difficulty preset, or themed variant. This guide explains the model, then covers creating, running, and authoring scenarios.
|
|
4
|
+
|
|
5
|
+
## The model
|
|
6
|
+
|
|
7
|
+
Games often ship several variants. A business simulation might have 'Standard', 'AI Disruption', and 'Merger' editions that share one engine and one set of UIs but differ in starting values, narrative text, and media. Without scenarios each variant is either a separate game, duplicating everything, or a manual configuration exercise for the facilitator.
|
|
8
|
+
|
|
9
|
+
A scenario packages the differences as one selectable unit. It holds two things:
|
|
10
|
+
|
|
11
|
+
1. **Settings overrides**: values that override the game's [settings](./settings.md) for this variant, keyed by settings identifier
|
|
12
|
+
2. **Static assets**: files (images, videos, documents) in the scenario's own `assets/` directory, which the engine and UIs reach through `asset:<path>` references (see [Asset references](./file-handling.md#asset-references))
|
|
13
|
+
|
|
14
|
+
The facilitator picks a scenario when the session starts, and the game runs with its values as a starting point. Its overrides sit between the settings defaults and whatever the facilitator changes for the session (see [Resolution order](#resolution-order)), so a scenario is a starting point, not a lock.
|
|
15
|
+
|
|
16
|
+
- **Data-only.** Scenarios carry no logic. They override settings values that the engine, hooks, validators, and UIs already interpret. For different behaviour, put conditional logic in the engine and drive it through settings
|
|
17
|
+
- **Fixed for the session.** A scenario's overrides reach the game through `Init`, so switching scenario means starting again from tick 0
|
|
18
|
+
- **Optional.** Games work without scenarios
|
|
19
|
+
- **One may be the default.** A scenario can mark itself `default: true`, and it is used whenever none is chosen
|
|
20
|
+
- **One may be restricted.** A scenario marked `restricted: true` is built for one audience rather than every client the package is shared with. The package never names that audience: the runtime hosting the game decides who has been granted it
|
|
21
|
+
- **The directory is the declaration.** A scenario is available because it exists under `scenarios/`, and nothing references it
|
|
22
|
+
|
|
23
|
+
Scenarios come from two places, and they meet in the same settings layer. **Author-time scenarios** are part of the package: you write them by hand, or save them from the dev server's scenario editor, and check them in with the rest of the game. **Custom scenarios** are built by facilitators or customer organisations at session time in a hosted runtime, for a game that opts in (see [Custom scenarios](#custom-scenarios-production-runtimes)). The runtime stores them; they never become part of the package.
|
|
24
|
+
|
|
25
|
+
### When to use scenarios
|
|
26
|
+
|
|
27
|
+
Use scenarios when:
|
|
28
|
+
|
|
29
|
+
- You want to ship several flavours of the same game (different storylines, difficulty levels, themes)
|
|
30
|
+
- Variants share the same engine and UIs but need different starting settings or different media
|
|
31
|
+
- You want facilitators to choose a variant when a session starts
|
|
32
|
+
|
|
33
|
+
You do not need scenarios if your game has only one variant, if the differences are small enough for a single [setup screen](./setup.md), or if you need to switch variants in the middle of play (a scenario is fixed for the session).
|
|
34
|
+
|
|
35
|
+
## What you'll learn
|
|
36
|
+
|
|
37
|
+
- How to create a scenario with settings overrides and assets
|
|
38
|
+
- How to initialise a game with a specific scenario
|
|
39
|
+
- How to load scenario assets in UIs
|
|
40
|
+
- How to test scenarios with the dev server and CLI
|
|
41
|
+
- When to bump `scenarioFormat` so a saved custom scenario is never applied to a game it no longer fits
|
|
42
|
+
|
|
43
|
+
## Prerequisites
|
|
44
|
+
|
|
45
|
+
You need an existing game with at least one engine. If you don't have one:
|
|
46
|
+
|
|
47
|
+
- [Create a Capability](./capabilities.md)
|
|
48
|
+
- [Create an engine](./engine.md)
|
|
49
|
+
- [Shaping Games](./games.md)
|
|
50
|
+
|
|
51
|
+
## Creating a scenario
|
|
52
|
+
|
|
53
|
+
### 1. Create the scenario resource
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pnpm run sdk new scenario '{
|
|
57
|
+
"definition": {
|
|
58
|
+
"identifier": "ai_influence",
|
|
59
|
+
"locales": {
|
|
60
|
+
"en": {
|
|
61
|
+
"name": "AI Influence",
|
|
62
|
+
"description": "A scenario where AI disrupts the market"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"settings": {
|
|
66
|
+
"engine": {
|
|
67
|
+
"BaseDemand": 50,
|
|
68
|
+
"AIFactor": 1.5
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"rootDirectory": "."
|
|
73
|
+
}'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This creates:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
scenarios/ai_influence/
|
|
80
|
+
├── scenario.sdk.json
|
|
81
|
+
└── assets/
|
|
82
|
+
└── shared/
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The directory is the declaration: nothing registers it.
|
|
86
|
+
|
|
87
|
+
### 2. Add assets (optional)
|
|
88
|
+
|
|
89
|
+
Place static files in the `assets/` directory:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
scenarios/ai_influence/
|
|
93
|
+
└── assets/
|
|
94
|
+
└── shared/
|
|
95
|
+
├── hero.jpg
|
|
96
|
+
├── briefing.pdf
|
|
97
|
+
└── intro-video.mp4
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Files in a scenario's `assets/` directory are referenced as `asset:<path>` and resolve only while that scenario is active. To share one file across several scenarios without copying it, put it in a package-level `shared-assets/` directory and reference it as `shared:<path>` (see [Sharing assets across scenarios](#sharing-assets-across-scenarios) below).
|
|
101
|
+
|
|
102
|
+
### 3. Mark it as the default (optional)
|
|
103
|
+
|
|
104
|
+
Nothing references a scenario: the directory under `scenarios/` is the whole of the declaration. To have this one picked when no `--scenario` flag is given, set `default` on the scenario itself:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
pnpm run sdk update scenario ai_influence --patch '[
|
|
108
|
+
{ "op": "add", "path": "/definition/default", "value": true }
|
|
109
|
+
]'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Important:** At most one scenario per package may have `"default": true`. If a default is set, it is used automatically when no `--scenario` flag is provided.
|
|
113
|
+
|
|
114
|
+
A scenario cannot set a setting the game locks with `readOnly`, or a game setting it fixes with `gameSettingsConstraints`: the build refuses it with `SETTINGS_LOCKED`, pointing at the value, even when the value matches the game's own. Remove it from the scenario. See [Lock a setting](./settings.md#lock-a-setting).
|
|
115
|
+
|
|
116
|
+
### 4. Restrict it to one audience (optional)
|
|
117
|
+
|
|
118
|
+
Most scenarios are variants every client gets. Some are built for one client, and those should not appear in everybody's scenario picker. Set `restricted` on the scenario:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
pnpm run sdk update scenario viking_edition --patch '[
|
|
122
|
+
{ "op": "add", "path": "/definition/restricted", "value": true }
|
|
123
|
+
]'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The flag says the scenario is for a particular audience. It never says who they are: that belongs to the runtime hosting the game, which knows about organisations and grants, and keeping it out of the package is what lets the same package be shared between clients.
|
|
127
|
+
|
|
128
|
+
What a production runtime does with the flag is its own business, but it must not offer a restricted scenario for selection, list it, resolve it by identifier, or serve its assets to a caller it has not granted it to.
|
|
129
|
+
|
|
130
|
+
Three things are worth knowing before you rely on it:
|
|
131
|
+
|
|
132
|
+
- **The dev server ignores it.** There are no organisations locally and the package is yours, so restricted scenarios are offered exactly like any other. You cannot test the restriction from here
|
|
133
|
+
- **A restricted scenario cannot also be the default.** A default is what a caller gets when it picks nothing, so it has to be one every caller can be offered. The build refuses a scenario that sets both
|
|
134
|
+
- **It does not cover `shared:` assets.** Files under the package-level `shared-assets/` directory resolve whatever scenario is active, so anything belonging to one client goes under that scenario's own `assets/`, not in `shared-assets/`
|
|
135
|
+
|
|
136
|
+
The flag protects the scenario only on a runtime that implements grants: one that does not recognise the field offers the scenario normally. What it always does is record the intent in the package, reviewed alongside the content it describes, rather than leaving it to a setting somebody remembers to tick after the upload.
|
|
137
|
+
|
|
138
|
+
## Scenario definition
|
|
139
|
+
|
|
140
|
+
A scenario is a directory under `scenarios/`, named by its identifier:
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
scenarios/ai_influence/
|
|
144
|
+
├── scenario.sdk.json # Locales, settings overrides, default and restricted flags
|
|
145
|
+
└── assets/
|
|
146
|
+
└── shared/ # Static files referenced as asset:<path>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The `scenario.sdk.json` file:
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"definition": {
|
|
154
|
+
"locales": {
|
|
155
|
+
"en": {
|
|
156
|
+
"name": "AI Influence",
|
|
157
|
+
"description": "A scenario focused on AI-driven market disruption"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"settings": {
|
|
161
|
+
"engine": {
|
|
162
|
+
"BaseDemand": 50,
|
|
163
|
+
"AIFactor": 1.5
|
|
164
|
+
},
|
|
165
|
+
"ui": {
|
|
166
|
+
"showAIPanel": true
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"rootDirectory": "."
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The `settings` block is keyed by settings identifier (the directory name under `settings/`), then by settings property. The scenario itself is named by its directory, so its bundle carries no `identifier`. At most one scenario per package may set `"default": true`.
|
|
175
|
+
|
|
176
|
+
## Settings overrides
|
|
177
|
+
|
|
178
|
+
A scenario overrides [settings resources](./settings.md), keyed by
|
|
179
|
+
settings identifier. It sets only the properties it changes; everything else
|
|
180
|
+
keeps its default. Here the package holds `settings/engine/`, `settings/ui/`
|
|
181
|
+
and `settings/session/`:
|
|
182
|
+
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"definition": {
|
|
186
|
+
"locales": { "en": { "name": "Hard Mode" } },
|
|
187
|
+
"settings": {
|
|
188
|
+
"engine": { "BaseDemand": 30, "InflationRate": 0.15 },
|
|
189
|
+
"ui": { "showHints": false },
|
|
190
|
+
"session": { "ShowJoinLinks": false }
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Validation
|
|
197
|
+
|
|
198
|
+
Every override is checked against the named settings resource's `settingsSchema`, by `sdk build` and `sdk build --validate-only` as well as at session start. Overrides are partial, so omitting a key is fine and it falls through to its default. What fails is a key the schema does not declare, usually a misspelling, or a declared key set to a value the schema rejects.
|
|
199
|
+
|
|
200
|
+
One more thing fails: an identifier that names no settings resource the package declares. It is an override that reads as applied and resolves nothing, so the build catches a misspelling rather than the session it was meant to change.
|
|
201
|
+
|
|
202
|
+
A failure names the settings resource and the offending key. Read it as a question about both sides: the override may be wrong, or the settings schema may have moved on without the scenario following.
|
|
203
|
+
|
|
204
|
+
### The number of rounds and the teams
|
|
205
|
+
|
|
206
|
+
The number of ticks, the team bounds and names, and whether the waiting room opens on start are the built-in `game` settings, so a scenario overrides them under `settings.game` like any other settings resource. A short edition of the game:
|
|
207
|
+
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"definition": {
|
|
211
|
+
"locales": { "en": { "name": "Short" } },
|
|
212
|
+
"settings": {
|
|
213
|
+
"game": { "maxTicks": 4, "teams": { "max": 4 } }
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`teams.mode` is not among them: a game is independent or shared-state whichever scenario is active. See [The game settings](./settings.md#the-game-settings) for every field.
|
|
220
|
+
|
|
221
|
+
### Resolution order
|
|
222
|
+
|
|
223
|
+
A scenario's overrides sit between the settings defaults and the session overrides, so a facilitator can still change a value for one session: the scenario is a starting point, not a lock. See [Overriding settings](./settings.md#overriding-settings) for the full resolution order.
|
|
224
|
+
|
|
225
|
+
## Overriding team names
|
|
226
|
+
|
|
227
|
+
A scenario can also rename teams, which is handy when each scenario is a themed variant with its own set of brands. Set `game.teams.defaultNames` in its `settings` (an ordered, localised list, the same shape as a game's `teams.defaultNames`). The scenario's list replaces the game's whole whenever the scenario is active, so list a name for every team the scenario expects.
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"definition": {
|
|
232
|
+
"locales": { "en": { "name": "Soft drinks" } },
|
|
233
|
+
"settings": {
|
|
234
|
+
"game": {
|
|
235
|
+
"teams": {
|
|
236
|
+
"defaultNames": [
|
|
237
|
+
{ "en": { "name": "Coca-Cola" } },
|
|
238
|
+
{ "en": { "name": "Pepsi" } },
|
|
239
|
+
{ "en": { "name": "Fanta" } }
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Entries are applied by the stable team index: entry N names the team with index N, the same as a game's `teams.defaultNames`. A re-added team recovers its scenario entry along with its index. Names resolve in the session's locale, fall back to another declared locale and then to the positional default ('Team N'), and remain advisory: operators can rename teams at session setup. See [Multi-team games](./multi-team-games.md#naming-teams) for the full resolution rules.
|
|
249
|
+
|
|
250
|
+
## Running with scenarios
|
|
251
|
+
|
|
252
|
+
### CLI
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
# Initialize with a specific scenario
|
|
256
|
+
pnpm run sdk init --scenario ai_influence
|
|
257
|
+
|
|
258
|
+
# Initialize with the default scenario (if one is marked default)
|
|
259
|
+
pnpm run sdk init
|
|
260
|
+
|
|
261
|
+
# Tick as normal: the scenario is remembered across ticks
|
|
262
|
+
pnpm run sdk tick
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Dev server
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
# Start with a specific scenario
|
|
269
|
+
pnpm run sdk dev --scenario ai_influence
|
|
270
|
+
|
|
271
|
+
# Start with the default scenario
|
|
272
|
+
pnpm run sdk dev
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
A scenario's overrides reach your game through `Init`, so a session already
|
|
276
|
+
several ticks in has passed the only moment they mean anything. Switching one is
|
|
277
|
+
therefore a restart rather than an adjustment: the dev drawer's **Scenario** tab
|
|
278
|
+
confirms first, then returns every team to tick 0 (and a game with a
|
|
279
|
+
configuration step back to it), so you can configure on top of the new scenario
|
|
280
|
+
before starting.
|
|
281
|
+
|
|
282
|
+
From a terminal, the same thing:
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
pnpm run sdk scenario ai_influence # or `none` for the settings defaults
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Managing scenarios while the server runs
|
|
289
|
+
|
|
290
|
+
The **Scenario** tab is a small manager, and everything it does writes into your
|
|
291
|
+
own source tree:
|
|
292
|
+
|
|
293
|
+
- **Activate** one, with the confirmation above
|
|
294
|
+
- **Add scenario** asks for an identifier (a short lowercase name, which names
|
|
295
|
+
the directory) and where its values start from: the package's own
|
|
296
|
+
settings defaults, or a copy of one you already have. It writes
|
|
297
|
+
`scenarios/<identifier>/scenario.sdk.json` straight away from the session put
|
|
298
|
+
on that starting point, and opens the scenario editor on the new scenario. A
|
|
299
|
+
copy carries everything its source declares, its locales and descriptions
|
|
300
|
+
included, under the new identifier as its name, and is never the default
|
|
301
|
+
- **Edit** opens the editor on an existing scenario, leaving the session where
|
|
302
|
+
it is: the editor edits a draft of the scenario, which reaches a session only
|
|
303
|
+
once it is saved and a session is started on it
|
|
304
|
+
- **Delete** removes the directory and its assets. The active scenario is
|
|
305
|
+
refused, because the session is resolved against it: switch to another one
|
|
306
|
+
first
|
|
307
|
+
|
|
308
|
+
A production runtime saves a facilitator's scenario to its own store and never
|
|
309
|
+
writes into a package, so all of this is author-time tooling rather than part of
|
|
310
|
+
the runtime contract.
|
|
311
|
+
|
|
312
|
+
### The scenario editor
|
|
313
|
+
|
|
314
|
+
The editor is your game's [`scenario_editor` slot](./scenario-editor.md),
|
|
315
|
+
opened **on** one scenario at `/scenario-editor`. It has no entry of its own
|
|
316
|
+
(no menu item, no surface to navigate to), because an editor with nowhere to
|
|
317
|
+
save is a screen that wastes the work somebody does on it. Add and Edit are the
|
|
318
|
+
ways in.
|
|
319
|
+
|
|
320
|
+
It opens in a new tab, and it edits a draft of that scenario, not the session:
|
|
321
|
+
the session you were looking at keeps its scenario and settings while you work,
|
|
322
|
+
and only **Save** changes anything, by writing the draft into the scenario's
|
|
323
|
+
bundle.
|
|
324
|
+
|
|
325
|
+
**Save** writes the settings back into that scenario's bundle, replacing its
|
|
326
|
+
`settings` and leaving every other field as you wrote it. **Done** closes the tab's business and returns you to the session.
|
|
327
|
+
|
|
328
|
+
A game with no `scenario_editor` slot has
|
|
329
|
+
nothing to author scenarios in; the values can still be set with `sdk configure` (keyed by settings identifier)
|
|
330
|
+
and captured by adding a scenario from the current settings.
|
|
331
|
+
|
|
332
|
+
## Loading scenario assets in UIs
|
|
333
|
+
|
|
334
|
+
A scenario's files are read through `asset:<path>` references, where `<path>` is relative to the scenario's `assets/` directory; package-level files use `shared:<path>` (see [Sharing assets across scenarios](#sharing-assets-across-scenarios)). Every surface resolves them the same way, with `useAssetUrl` or the `getAssetUrl` callback, and logic reads them with `readAsset`:
|
|
335
|
+
|
|
336
|
+
```tsx
|
|
337
|
+
import { useAssetUrl } from '@seriousgaming/sdk/ui';
|
|
338
|
+
|
|
339
|
+
function HeroImage() {
|
|
340
|
+
const src = useAssetUrl('asset:shared/hero.jpg');
|
|
341
|
+
return <img src={src} alt="Hero" />;
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
[Asset references](./file-handling.md#asset-references) covers the schemes, how a reference becomes a URL, and what happens when no scenario is active.
|
|
346
|
+
|
|
347
|
+
## Sharing assets across scenarios
|
|
348
|
+
|
|
349
|
+
When two scenarios play the same storyline but differ in a config value, copying the storyline's media into both `assets/` directories means every later edit must be made twice. A package-level `shared-assets/` directory removes the duplication: store each file once and reference it as `shared:<path>` from any scenario.
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
my-package/
|
|
353
|
+
├── shared-assets/
|
|
354
|
+
│ └── storyline/
|
|
355
|
+
│ ├── hero.jpg
|
|
356
|
+
│ └── intro-video.mp4
|
|
357
|
+
├── scenarios/
|
|
358
|
+
│ ├── ai_influence/scenario.sdk.json
|
|
359
|
+
│ └── merger_influence/scenario.sdk.json
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Both scenarios reference the same file, anywhere an `asset:` reference is valid:
|
|
363
|
+
|
|
364
|
+
```json
|
|
365
|
+
{
|
|
366
|
+
"definition": {
|
|
367
|
+
"settings": {
|
|
368
|
+
"engine": {
|
|
369
|
+
"Hero": "shared:storyline/hero.jpg"
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
- `shared:<path>` resolves against `shared-assets/` at the package root, never against a scenario, so it works even when no scenario is active
|
|
377
|
+
- There is no shadowing: a scenario that needs its own version of a file references `asset:<path>` and ships that file in its own `assets/` directory
|
|
378
|
+
- The directory is folder-convention only: no schema, declaration, or CRUD. `seriousgaming-sdk build` copies `shared-assets/` into the bundle root, and a hosted runtime resolves `shared:` references the same way the dev server does
|
|
379
|
+
|
|
380
|
+
Settings duplication between the two scenarios is fine; asset duplication is the part that drifts. See the [share assets across scenarios recipe](../recipes/share-assets-across-scenarios.md) for the full task.
|
|
381
|
+
|
|
382
|
+
## Updating a scenario
|
|
383
|
+
|
|
384
|
+
Replace the full definition:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
pnpm run sdk update scenario ai_influence '{
|
|
388
|
+
"definition": {
|
|
389
|
+
"identifier": "ai_influence",
|
|
390
|
+
"locales": {
|
|
391
|
+
"en": { "name": "AI Influence (Updated)" },
|
|
392
|
+
"fr": { "name": "Influence IA" }
|
|
393
|
+
},
|
|
394
|
+
"settings": {
|
|
395
|
+
"engine": { "BaseDemand": 40 }
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
"rootDirectory": "."
|
|
399
|
+
}'
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Or apply a patch:
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
pnpm run sdk update scenario ai_influence --patch '[
|
|
406
|
+
{ "op": "replace", "path": "/definition/locales/en/name", "value": "AI Influence v2" },
|
|
407
|
+
{ "op": "replace", "path": "/definition/settings/engine/BaseDemand", "value": 40 }
|
|
408
|
+
]'
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## Deleting a scenario
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
pnpm run sdk delete scenario ai_influence --yes
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
This removes the scenario directory, which is the whole of its declaration. The
|
|
418
|
+
dev drawer's **Scenario** tab does the same thing while the server runs, which is
|
|
419
|
+
the quicker route when you have just saved one by accident.
|
|
420
|
+
|
|
421
|
+
## Build output
|
|
422
|
+
|
|
423
|
+
When you run `pnpm run sdk build`, scenarios are included in the output:
|
|
424
|
+
|
|
425
|
+
- Scenario definitions are written to `seriousgaming.json` under the `scenarios` array
|
|
426
|
+
- Scenario assets are copied to `dist/scenarios/<identifier>/assets/`
|
|
427
|
+
|
|
428
|
+
## Best practices
|
|
429
|
+
|
|
430
|
+
1. **Use scenarios for variant bundles, not minor tweaks.** If the difference is a single settings value, a setup screen is simpler.
|
|
431
|
+
|
|
432
|
+
2. **Keep scenarios data-only.** Don't put logic in scenarios: use settings to drive conditional behaviour.
|
|
433
|
+
|
|
434
|
+
3. **Organise assets by purpose.** Use `shared/` for locale-independent files. If you need locale-specific assets, use locale subdirectories (e.g. `en/`, `fr/`) and reference the appropriate path from a settings value.
|
|
435
|
+
|
|
436
|
+
4. **Mark a default.** If your game has scenarios, mark one as `default: true` so facilitators don't have to remember the identifier.
|
|
437
|
+
|
|
438
|
+
5. **Validate overrides against settings schemas.** Scenario settings values are validated against each named settings resource's `settingsSchema` during build. If a value doesn't match, the build will fail.
|
|
439
|
+
|
|
440
|
+
## Custom scenarios (production runtimes)
|
|
441
|
+
|
|
442
|
+
Games designed to be customised by end users (facilitators or customer organisations who save their own scenarios at session time and reuse them across sessions) opt in with one declaration on the game definition:
|
|
443
|
+
|
|
444
|
+
```json
|
|
445
|
+
{
|
|
446
|
+
"identifier": "com.example.cyber",
|
|
447
|
+
"customScenarios": { "supported": true }
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
The field is a **production-policy signal**. A hosted runtime that recognises it keeps the scenarios facilitators save across sessions and offers them in the scenario picker beside the game's built-in ones. A saved scenario's overrides apply in the same layer as a built-in scenario's, between the settings defaults and the session overrides. When a scenario is copied, files it references with `asset:<path>` are copied into runtime storage, so the copy keeps working if the original changes; `shared:<path>` references are left as they are.
|
|
452
|
+
|
|
453
|
+
How saved scenarios are named, scoped and edited is up to the runtime.
|
|
454
|
+
|
|
455
|
+
Save-as-scenario is offered from the game's [`scenario_editor`](./scenario-editor.md) slot only, never from [`setup`](./setup.md). Setup is a separate, session-only configuration step: its output lands in the session-override layer and is never persisted as a scenario.
|
|
456
|
+
|
|
457
|
+
The editor is optional. `customScenarios.supported` is what switches custom scenarios on, and a game whose settings schemas describe each value well (a title, a description with units, a range, an `enum` where the choices are closed) can be edited by an AI agent, or in a runtime's generic form, with no editor UI at all. See [Describe every setting](./settings.md#describe-every-setting).
|
|
458
|
+
|
|
459
|
+
### Scenario format: when to bump it
|
|
460
|
+
|
|
461
|
+
A custom scenario outlives the release it was saved against: a facilitator saves one today and runs it after your next update. Schema validation catches a setting that was renamed or removed, but not one whose meaning changed, so you tell the runtime with `scenarioFormat` in `seriousgaming.sdk.json`:
|
|
462
|
+
|
|
463
|
+
```json
|
|
464
|
+
{
|
|
465
|
+
"identifier": "com.example.cyber",
|
|
466
|
+
"customScenarios": { "supported": true },
|
|
467
|
+
"scenarioFormat": 2
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
It is an integer of at least 1, and leaving it out means 1. A runtime stores the format and your package version with every custom scenario it saves, and refuses to apply a saved scenario whose format differs from your package's, naming both. A scenario saved under the same format is still validated against your current settings schemas each time it is applied.
|
|
472
|
+
|
|
473
|
+
Bump it when a scenario saved against the previous release may no longer be correct:
|
|
474
|
+
|
|
475
|
+
- A setting removed, renamed, or reshaped (an object split in two, a number that becomes an enum)
|
|
476
|
+
- A change in what a value means (a percentage that becomes a fraction, a per-round amount that becomes a total)
|
|
477
|
+
- A change in how the game loads scenario assets (a reference resolved from a different path)
|
|
478
|
+
- A lock or a narrower range on a setting a saved scenario may already set: a new `readOnly` in a settings schema, or a new or tighter entry in `gameSettingsConstraints` (see [Lock a setting](./settings.md#lock-a-setting)). A lock is enforced when a value is written, so the format is what stops an older scenario that carries the value from applying
|
|
479
|
+
|
|
480
|
+
Do not bump it for a purely additive change, such as a new setting with a default: an older scenario leaves the new setting at its default and still applies. Bumping when you did not need to costs facilitators their saved scenarios, so bump only for a change that would make an old scenario wrong.
|
|
481
|
+
|
|
482
|
+
Package scenarios under `scenarios/` carry no format. They ship with the package, so they always match it, and the dev server's save writes none.
|
|
483
|
+
|
|
484
|
+
The dev server is an author-time tool, not a runtime simulator, so it does not persist runtime-built scenarios. It has its own author-time save flow, described below.
|
|
485
|
+
|
|
486
|
+
## Save as a scenario (dev server)
|
|
487
|
+
|
|
488
|
+
The dev drawer's **Scenario** tab adds, edits, and deletes package scenarios (see [Managing scenarios while the server runs](#managing-scenarios-while-the-server-runs)). Each writes into the package on disk, which is the whole of the wiring, so a saved scenario behaves identically to one authored by hand.
|
|
489
|
+
|
|
490
|
+
The scenario editor page's **Save** button writes the editor's draft into the scenario it was opened on, as a real `scenarios/<identifier>/scenario.sdk.json` bundle. Any `blob:*` references in that configuration are materialised as files under the scenario's `assets/shared/` and rewritten to `asset:*`, so the resulting bundle is self-contained and ready to check in. `shared:*` references are left intact, because they already point at the package-level `shared-assets/` directory. Only `settings` is replaced, the number of rounds and the team settings under `settings.game` among them: the scenario's locales, `default`, `restricted` and anything else in the bundle stay as they were. A setting the game locks with `readOnly` is left out of what is written, since the build refuses a scenario that names one, and a save whose settings break a schema, a locked value changed or a value out of range, is refused with nothing written.
|
|
491
|
+
|
|
492
|
+
Typical edit flow:
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
pnpm run sdk dev --scenario baseline
|
|
496
|
+
# open the dev drawer, then Scenario, then Edit on baseline
|
|
497
|
+
# change values in the scenario editor, then click Save
|
|
498
|
+
# scenarios/baseline/scenario.sdk.json is overwritten on disk
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
This is the author-time counterpart to runtime custom scenarios (above): the same primitive, with the reference translation running the opposite way.
|
|
502
|
+
|
|
503
|
+
| Flow | Where the scenario lives | Translation direction |
|
|
504
|
+
| ----------------------------------------------------------------- | ----------------------------------- | --------------------- |
|
|
505
|
+
| Runtime custom scenarios (`customScenarios: { supported: true }`) | Runtime blob store | `asset:*` → `blob:*` |
|
|
506
|
+
| Author-time package scenarios (SDK dev server) | `scenarios/<id>/` under the package | `blob:*` → `asset:*` |
|
|
507
|
+
|
|
508
|
+
Hosted runtimes do not surface this author-time save. Whether they offer their own save to facilitators is controlled by `customScenarios`, and the dev server offers its own regardless, because the author owns the package.
|
|
509
|
+
|
|
510
|
+
## Next steps
|
|
511
|
+
|
|
512
|
+
- [Shaping games](./games.md): set what the game is
|
|
513
|
+
- [Building a scenario editor](./scenario-editor.md): the screen for authoring lasting scenarios
|
|
514
|
+
- [Building a setup screen](./setup.md): the short form at session creation
|
|
515
|
+
- [Internationalisation](./internationalization.md): multi-language support for scenario locales
|