@dreamboard-games/sdk 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (369) hide show
  1. package/LICENSE.md +96 -0
  2. package/README.md +12 -0
  3. package/dist/HandView-ncJIVLhN.d.ts +193 -0
  4. package/dist/ResourceCounter-CTREyF73.d.ts +102 -0
  5. package/dist/ThemeProvider-fy0_QzgO.d.ts +99 -0
  6. package/dist/bundle-TIZcw8LB.d.ts +281 -0
  7. package/dist/cards-Sl3b40Mv.d.ts +13 -0
  8. package/dist/chunk-7YAHLYBR.js +481 -0
  9. package/dist/chunk-7YAHLYBR.js.map +1 -0
  10. package/dist/chunk-FDNZTDD6.js +8085 -0
  11. package/dist/chunk-FDNZTDD6.js.map +1 -0
  12. package/dist/chunk-GKKBPPSW.js +598 -0
  13. package/dist/chunk-GKKBPPSW.js.map +1 -0
  14. package/dist/chunk-I46YJSOD.js +1 -0
  15. package/dist/chunk-I46YJSOD.js.map +1 -0
  16. package/dist/chunk-KAELH4KC.js +104 -0
  17. package/dist/chunk-KAELH4KC.js.map +1 -0
  18. package/dist/chunk-PZ5AY32C.js +10 -0
  19. package/dist/chunk-PZ5AY32C.js.map +1 -0
  20. package/dist/chunk-T3ZKNUZ7.js +1 -0
  21. package/dist/chunk-T3ZKNUZ7.js.map +1 -0
  22. package/dist/chunk-T52J5RMF.js +1 -0
  23. package/dist/chunk-T52J5RMF.js.map +1 -0
  24. package/dist/chunk-TDSWKVZ4.js +5401 -0
  25. package/dist/chunk-TDSWKVZ4.js.map +1 -0
  26. package/dist/chunk-U5C6BONG.js +34 -0
  27. package/dist/chunk-U5C6BONG.js.map +1 -0
  28. package/dist/chunk-VDXOF4FW.js +69 -0
  29. package/dist/chunk-VDXOF4FW.js.map +1 -0
  30. package/dist/chunk-VFTAA4WO.js +115 -0
  31. package/dist/chunk-VFTAA4WO.js.map +1 -0
  32. package/dist/chunk-WN74KVNY.js +17 -0
  33. package/dist/chunk-WN74KVNY.js.map +1 -0
  34. package/dist/chunk-WYPQ3GG5.js +10990 -0
  35. package/dist/chunk-WYPQ3GG5.js.map +1 -0
  36. package/dist/components-D5ZRE2Hl.d.ts +1451 -0
  37. package/dist/generated/runtime/primitives.d.ts +12 -0
  38. package/dist/generated/runtime/primitives.js +180 -0
  39. package/dist/generated/runtime/primitives.js.map +1 -0
  40. package/dist/generated/runtime-api.d.ts +3 -0
  41. package/dist/generated/runtime-api.js +2 -0
  42. package/dist/generated/runtime-api.js.map +1 -0
  43. package/dist/generated/runtime.d.ts +14 -0
  44. package/dist/generated/runtime.js +18 -0
  45. package/dist/generated/runtime.js.map +1 -0
  46. package/dist/generated/workspace-contract.d.ts +14 -0
  47. package/dist/generated/workspace-contract.js +14 -0
  48. package/dist/generated/workspace-contract.js.map +1 -0
  49. package/dist/hex-board-view-D_07hO6O.d.ts +933 -0
  50. package/dist/hex-color-MhOyuY-o.d.ts +8 -0
  51. package/dist/index-BwqPQtBu.d.ts +1433 -0
  52. package/dist/index.d.ts +1 -0
  53. package/dist/index.js +12 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/infrastructure/reducer-bundle-abi.d.ts +1083 -0
  56. package/dist/infrastructure/reducer-bundle-abi.js +14 -0
  57. package/dist/infrastructure/reducer-bundle-abi.js.map +1 -0
  58. package/dist/infrastructure/workspace-codegen.d.ts +53 -0
  59. package/dist/infrastructure/workspace-codegen.js +44 -0
  60. package/dist/infrastructure/workspace-codegen.js.map +1 -0
  61. package/dist/manifest-contract-BNHVGFtU.d.ts +9 -0
  62. package/dist/package-set.d.ts +13 -0
  63. package/dist/package-set.js +12 -0
  64. package/dist/package-set.js.map +1 -0
  65. package/dist/primitive-props-DpKs-GCr.d.ts +11 -0
  66. package/dist/reducer.d.ts +3786 -0
  67. package/dist/reducer.js +8131 -0
  68. package/dist/reducer.js.map +1 -0
  69. package/dist/runtime/primitives.d.ts +226 -0
  70. package/dist/runtime/primitives.js +180 -0
  71. package/dist/runtime/primitives.js.map +1 -0
  72. package/dist/runtime/types/runtime-api.d.ts +1 -0
  73. package/dist/runtime/types/runtime-api.js +2 -0
  74. package/dist/runtime/types/runtime-api.js.map +1 -0
  75. package/dist/runtime/workspace-contract.d.ts +172 -0
  76. package/dist/runtime/workspace-contract.js +14 -0
  77. package/dist/runtime/workspace-contract.js.map +1 -0
  78. package/dist/runtime-api-3dshj6kK.d.ts +101 -0
  79. package/dist/runtime-api-DWxvTr-O.d.ts +379 -0
  80. package/dist/runtime.d.ts +58 -0
  81. package/dist/runtime.js +13 -0
  82. package/dist/runtime.js.map +1 -0
  83. package/dist/slots-1GPGihk8.d.ts +8 -0
  84. package/dist/testing.d.ts +149 -0
  85. package/dist/testing.js +513 -0
  86. package/dist/testing.js.map +1 -0
  87. package/dist/types.d.ts +496 -0
  88. package/dist/types.js +28 -0
  89. package/dist/types.js.map +1 -0
  90. package/dist/ui/components.d.ts +16 -0
  91. package/dist/ui/components.js +192 -0
  92. package/dist/ui/components.js.map +1 -0
  93. package/dist/ui/defaults.d.ts +19 -0
  94. package/dist/ui/defaults.js +104 -0
  95. package/dist/ui/defaults.js.map +1 -0
  96. package/dist/ui/plugin-styles.css +250 -0
  97. package/dist/ui/types/player-state.d.ts +365 -0
  98. package/dist/ui/types/player-state.js +1 -0
  99. package/dist/ui/types/player-state.js.map +1 -0
  100. package/dist/ui-contract-iQfTtUSL.d.ts +1161 -0
  101. package/dist/ui.d.ts +320 -0
  102. package/dist/ui.js +253 -0
  103. package/dist/ui.js.map +1 -0
  104. package/package.json +199 -0
  105. package/src/generated/reducer-contract/builders.ts +90 -0
  106. package/src/generated/reducer-contract/version.ts +9 -0
  107. package/src/generated/reducer-contract/wire.ts +100 -0
  108. package/src/generated/reducer-contract/zod.ts +101 -0
  109. package/src/generated/runtime/primitives.ts +2 -0
  110. package/src/generated/runtime-api.ts +5 -0
  111. package/src/generated/runtime.ts +35 -0
  112. package/src/generated/workspace-contract.ts +2 -0
  113. package/src/index.ts +7 -0
  114. package/src/infrastructure/reducer-bundle-abi.ts +8 -0
  115. package/src/infrastructure/reducer-contract/bundle.ts +37 -0
  116. package/src/infrastructure/workspace-codegen/hex-geometry.ts +69 -0
  117. package/src/infrastructure/workspace-codegen/index.ts +64 -0
  118. package/src/infrastructure/workspace-codegen/manifest-contract.ts +6632 -0
  119. package/src/infrastructure/workspace-codegen/manifest-validation.ts +795 -0
  120. package/src/infrastructure/workspace-codegen/ownership.ts +131 -0
  121. package/src/infrastructure/workspace-codegen/preset-card-sets.ts +169 -0
  122. package/src/infrastructure/workspace-codegen/seeds.ts +1705 -0
  123. package/src/infrastructure/workspace-codegen.ts +1 -0
  124. package/src/package-set.ts +19 -0
  125. package/src/reducer/authoring/contract.ts +157 -0
  126. package/src/reducer/authoring/effect.ts +224 -0
  127. package/src/reducer/authoring/game.ts +23 -0
  128. package/src/reducer/authoring/interaction.ts +98 -0
  129. package/src/reducer/authoring/phase.ts +300 -0
  130. package/src/reducer/authoring/types.ts +70 -0
  131. package/src/reducer/authoring/validation.ts +382 -0
  132. package/src/reducer/authoring/view-stage.ts +68 -0
  133. package/src/reducer/authoring.ts +29 -0
  134. package/src/reducer/bundle/ingress-bundle.ts +491 -0
  135. package/src/reducer/bundle/trusted/engine-instruction-resolver.ts +254 -0
  136. package/src/reducer/bundle/trusted/flow-instruction-resolver.ts +73 -0
  137. package/src/reducer/bundle/trusted/instruction-runner.ts +414 -0
  138. package/src/reducer/bundle/trusted/interaction-authorization.ts +137 -0
  139. package/src/reducer/bundle/trusted/interaction-collectors.ts +859 -0
  140. package/src/reducer/bundle/trusted/interaction-decision.ts +747 -0
  141. package/src/reducer/bundle/trusted/interaction-resolver.ts +95 -0
  142. package/src/reducer/bundle/trusted/interaction-types.ts +171 -0
  143. package/src/reducer/bundle/trusted/lifecycle-runner.ts +427 -0
  144. package/src/reducer/bundle/trusted/projection-builder.ts +356 -0
  145. package/src/reducer/bundle/trusted/projection-context.ts +39 -0
  146. package/src/reducer/bundle/trusted/rng-sampler.ts +150 -0
  147. package/src/reducer/bundle/trusted/runtime-registry.ts +120 -0
  148. package/src/reducer/bundle/trusted/runtime-scope.ts +336 -0
  149. package/src/reducer/bundle/trusted/simultaneous-player.ts +97 -0
  150. package/src/reducer/bundle/trusted/stage-resolver.ts +87 -0
  151. package/src/reducer/bundle/trusted/static-projection.ts +116 -0
  152. package/src/reducer/bundle/trusted/trusted-runtime-args.ts +97 -0
  153. package/src/reducer/bundle/trusted/trusted-runtime-result.ts +39 -0
  154. package/src/reducer/bundle/trusted/trusted-setup-profiles.ts +43 -0
  155. package/src/reducer/bundle/trusted/trusted-state-codec.ts +48 -0
  156. package/src/reducer/bundle/trusted-bundle.ts +97 -0
  157. package/src/reducer/bundle/types.ts +171 -0
  158. package/src/reducer/bundle.ts +2 -0
  159. package/src/reducer/client-param-schemas.ts +57 -0
  160. package/src/reducer/compose.ts +34 -0
  161. package/src/reducer/core/runtime-input.ts +30 -0
  162. package/src/reducer/core/runtime-instruction.ts +59 -0
  163. package/src/reducer/core/types.ts +62 -0
  164. package/src/reducer/definition-index.ts +277 -0
  165. package/src/reducer/derived.ts +106 -0
  166. package/src/reducer/effects.ts +92 -0
  167. package/src/reducer/engine/runtime-instruction-engine.ts +155 -0
  168. package/src/reducer/ingress/decode-runtime-input.ts +7 -0
  169. package/src/reducer/ingress/decode-session-state.ts +9 -0
  170. package/src/reducer/ingress/encode-session-state.ts +6 -0
  171. package/src/reducer/ingress/input-codec.ts +18 -0
  172. package/src/reducer/ingress/phase-schemas.ts +62 -0
  173. package/src/reducer/ingress/raw-types.ts +107 -0
  174. package/src/reducer/ingress/runtime-codec.ts +14 -0
  175. package/src/reducer/ingress/runtime-payload.ts +13 -0
  176. package/src/reducer/ingress/session-codec.ts +392 -0
  177. package/src/reducer/ingress/types.ts +6 -0
  178. package/src/reducer/inputs/boardInput.ts +217 -0
  179. package/src/reducer/inputs/boardTarget.ts +190 -0
  180. package/src/reducer/inputs/cardInput.ts +86 -0
  181. package/src/reducer/inputs/cardTarget.ts +101 -0
  182. package/src/reducer/inputs/choiceTarget.ts +104 -0
  183. package/src/reducer/inputs/defineInputs.ts +71 -0
  184. package/src/reducer/inputs/formInput.ts +809 -0
  185. package/src/reducer/inputs/many.ts +120 -0
  186. package/src/reducer/inputs/promptInput.ts +87 -0
  187. package/src/reducer/inputs/rngInput.ts +58 -0
  188. package/src/reducer/inputs/targetRule.ts +123 -0
  189. package/src/reducer/inputs.ts +41 -0
  190. package/src/reducer/model/definition.ts +1072 -0
  191. package/src/reducer/model/extract.ts +745 -0
  192. package/src/reducer/model/manifest.ts +570 -0
  193. package/src/reducer/model/queries.ts +641 -0
  194. package/src/reducer/model/runtime.ts +264 -0
  195. package/src/reducer/model/spec.ts +1386 -0
  196. package/src/reducer/model/table.ts +260 -0
  197. package/src/reducer/model.ts +7 -0
  198. package/src/reducer/ops.ts +1034 -0
  199. package/src/reducer/parse-utils.ts +28 -0
  200. package/src/reducer/per-player.ts +422 -0
  201. package/src/reducer/rng.ts +69 -0
  202. package/src/reducer/schema-helpers.ts +185 -0
  203. package/src/reducer/setup-bootstrap-helpers.ts +171 -0
  204. package/src/reducer/setup-bootstrap.ts +481 -0
  205. package/src/reducer/table-ops.ts +2671 -0
  206. package/src/reducer/table-queries.ts +372 -0
  207. package/src/reducer/transaction.ts +120 -0
  208. package/src/reducer.ts +314 -0
  209. package/src/runtime/primitives.ts +1 -0
  210. package/src/runtime/types/runtime-api.ts +1 -0
  211. package/src/runtime/workspace-contract.ts +32 -0
  212. package/src/runtime-internal/components/InteractionForm.tsx +1309 -0
  213. package/src/runtime-internal/components/PluginRuntime.tsx +103 -0
  214. package/src/runtime-internal/components/board/target-layer.ts +70 -0
  215. package/src/runtime-internal/context/ClientParamSchemaContext.tsx +44 -0
  216. package/src/runtime-internal/context/InteractionDraftContext.tsx +279 -0
  217. package/src/runtime-internal/context/PluginSessionContext.tsx +47 -0
  218. package/src/runtime-internal/context/PluginStateContext.tsx +262 -0
  219. package/src/runtime-internal/context/RuntimeContext.tsx +96 -0
  220. package/src/runtime-internal/defaults/components.tsx +409 -0
  221. package/src/runtime-internal/defaults/index.ts +11 -0
  222. package/src/runtime-internal/errors/ValidationError.ts +29 -0
  223. package/src/runtime-internal/hooks/useActivePlayers.ts +33 -0
  224. package/src/runtime-internal/hooks/useBoardInteractions.ts +665 -0
  225. package/src/runtime-internal/hooks/useGameSelector.ts +105 -0
  226. package/src/runtime-internal/hooks/useGameView.ts +9 -0
  227. package/src/runtime-internal/hooks/useInteractionByKey.ts +354 -0
  228. package/src/runtime-internal/hooks/useInteractionHandle.ts +438 -0
  229. package/src/runtime-internal/hooks/useIsMyTurn.ts +20 -0
  230. package/src/runtime-internal/hooks/useLobby.ts +76 -0
  231. package/src/runtime-internal/hooks/useMe.ts +48 -0
  232. package/src/runtime-internal/hooks/usePlayerInfo.ts +28 -0
  233. package/src/runtime-internal/hooks/usePlayerTurnOrder.ts +23 -0
  234. package/src/runtime-internal/hooks/usePluginRuntime.ts +147 -0
  235. package/src/runtime-internal/hooks/useSeatInbox.ts +61 -0
  236. package/src/runtime-internal/hooks/useSimultaneousPhase.ts +10 -0
  237. package/src/runtime-internal/index.ts +42 -0
  238. package/src/runtime-internal/internal.ts +43 -0
  239. package/src/runtime-internal/plugin-styles.css +250 -0
  240. package/src/runtime-internal/primitives/board.tsx +459 -0
  241. package/src/runtime-internal/primitives/dialog-lifecycle.ts +58 -0
  242. package/src/runtime-internal/primitives/dice.tsx +79 -0
  243. package/src/runtime-internal/primitives/game-ui-provider.tsx +35 -0
  244. package/src/runtime-internal/primitives/game.tsx +387 -0
  245. package/src/runtime-internal/primitives/hand-intent-adapter.ts +147 -0
  246. package/src/runtime-internal/primitives/hand-surface.tsx +594 -0
  247. package/src/runtime-internal/primitives/index.ts +196 -0
  248. package/src/runtime-internal/primitives/interaction-form-binding.tsx +56 -0
  249. package/src/runtime-internal/primitives/interaction-submit.ts +90 -0
  250. package/src/runtime-internal/primitives/interaction.tsx +987 -0
  251. package/src/runtime-internal/primitives/phase.tsx +43 -0
  252. package/src/runtime-internal/primitives/player-roster.tsx +302 -0
  253. package/src/runtime-internal/primitives/primitive-props.tsx +101 -0
  254. package/src/runtime-internal/primitives/prompt.tsx +255 -0
  255. package/src/runtime-internal/primitives/ui.tsx +60 -0
  256. package/src/runtime-internal/primitives/zone.tsx +791 -0
  257. package/src/runtime-internal/reducer.ts +30 -0
  258. package/src/runtime-internal/runtime/createPluginRuntimeAPI.ts +605 -0
  259. package/src/runtime-internal/types/plugin-state.ts +508 -0
  260. package/src/runtime-internal/types/reducer-state.ts +24 -0
  261. package/src/runtime-internal/types/runtime-api.ts +114 -0
  262. package/src/runtime-internal/ui-contract.ts +519 -0
  263. package/src/runtime-internal/utils/card-intent-adapter.ts +546 -0
  264. package/src/runtime-internal/utils/interaction-inputs.ts +492 -0
  265. package/src/runtime-internal/utils/interaction-labels.ts +23 -0
  266. package/src/runtime-internal/utils/interaction-router.ts +273 -0
  267. package/src/runtime-internal/utils/interaction-status.ts +74 -0
  268. package/src/runtime-internal/workspace-contract.ts +1170 -0
  269. package/src/runtime.ts +34 -0
  270. package/src/testing/create-expect-api.ts +352 -0
  271. package/src/testing/create-test-runtime.ts +381 -0
  272. package/src/testing/definitions.ts +127 -0
  273. package/src/testing/index.ts +3 -0
  274. package/src/testing.ts +1 -0
  275. package/src/type-stubs/manifest-contract.d.ts +42 -0
  276. package/src/type-stubs/manifest-contract.js +72 -0
  277. package/src/type-stubs/ui-contract.d.ts +5 -0
  278. package/src/type-stubs/ui-contract.js +1 -0
  279. package/src/types/authoring-card-properties.type-test.ts +266 -0
  280. package/src/types/authoring.ts +1282 -0
  281. package/src/types/cards.ts +19 -0
  282. package/src/types/contracts.ts +1550 -0
  283. package/src/types/generated-helpers.ts +35 -0
  284. package/src/types/index.ts +147 -0
  285. package/src/types/slots.ts +11 -0
  286. package/src/types.ts +1 -0
  287. package/src/ui/components/ActionButton.tsx +97 -0
  288. package/src/ui/components/ActionPanel.tsx +315 -0
  289. package/src/ui/components/Card.tsx +378 -0
  290. package/src/ui/components/CardDragSurface.tsx +1076 -0
  291. package/src/ui/components/ChromeSuppressionContext.tsx +70 -0
  292. package/src/ui/components/CostDisplay.tsx +145 -0
  293. package/src/ui/components/DiceRoller.tsx +581 -0
  294. package/src/ui/components/Drawer.tsx +180 -0
  295. package/src/ui/components/ErrorBoundary.tsx +275 -0
  296. package/src/ui/components/GameEndDisplay.tsx +398 -0
  297. package/src/ui/components/GameSkeleton.tsx +260 -0
  298. package/src/ui/components/Hand.tsx +468 -0
  299. package/src/ui/components/HandDock.tsx +299 -0
  300. package/src/ui/components/HandView.tsx +441 -0
  301. package/src/ui/components/MobileHandTray.tsx +381 -0
  302. package/src/ui/components/MoreActions.tsx +143 -0
  303. package/src/ui/components/PhaseIndicator.tsx +341 -0
  304. package/src/ui/components/PlayArea.tsx +146 -0
  305. package/src/ui/components/PrimaryActionButton.tsx +336 -0
  306. package/src/ui/components/PrimaryButton.tsx +45 -0
  307. package/src/ui/components/ResourceCounter.tsx +270 -0
  308. package/src/ui/components/StagingZone.tsx +134 -0
  309. package/src/ui/components/ThemedButton.tsx +113 -0
  310. package/src/ui/components/Toast.tsx +264 -0
  311. package/src/ui/components/board/HexGrid.tsx +1294 -0
  312. package/src/ui/components/board/NetworkGraph.tsx +476 -0
  313. package/src/ui/components/board/SlotSystem.tsx +388 -0
  314. package/src/ui/components/board/SquareGrid.tsx +1165 -0
  315. package/src/ui/components/board/TrackBoard.tsx +496 -0
  316. package/src/ui/components/board/ZoneMap.tsx +448 -0
  317. package/src/ui/components/board/hex-board-view.ts +123 -0
  318. package/src/ui/components/board/index.ts +142 -0
  319. package/src/ui/components/board/interaction-accessibility.ts +21 -0
  320. package/src/ui/components/board/target-layer.ts +66 -0
  321. package/src/ui/components/card-render-content.type-test.ts +27 -0
  322. package/src/ui/components/hand-layout-math.ts +163 -0
  323. package/src/ui/components/hand-pointer-engine.ts +413 -0
  324. package/src/ui/components/index.ts +245 -0
  325. package/src/ui/components.ts +1 -0
  326. package/src/ui/defaults/components.tsx +106 -0
  327. package/src/ui/defaults/index.ts +8 -0
  328. package/src/ui/defaults.ts +1 -0
  329. package/src/ui/errors/ValidationError.ts +29 -0
  330. package/src/ui/helpers/cards.ts +19 -0
  331. package/src/ui/helpers/track-board.ts +211 -0
  332. package/src/ui/hooks/useBoardTopology.ts +316 -0
  333. package/src/ui/hooks/useCards.ts +10 -0
  334. package/src/ui/hooks/useHandCardPointer.ts +381 -0
  335. package/src/ui/hooks/useHandLayout.ts +378 -0
  336. package/src/ui/hooks/useHandPresentation.ts +121 -0
  337. package/src/ui/hooks/useHexBoard.ts +74 -0
  338. package/src/ui/hooks/useHexGrid.ts +185 -0
  339. package/src/ui/hooks/useIsMobile.ts +35 -0
  340. package/src/ui/hooks/usePanZoom.ts +278 -0
  341. package/src/ui/hooks/useSquareBoard.ts +124 -0
  342. package/src/ui/hooks/useSquareGrid.ts +328 -0
  343. package/src/ui/index.ts +98 -0
  344. package/src/ui/internal/ui/alert.tsx +51 -0
  345. package/src/ui/internal/ui/button.tsx +58 -0
  346. package/src/ui/internal/ui/dialog.tsx +134 -0
  347. package/src/ui/internal/ui/input.tsx +21 -0
  348. package/src/ui/internal/ui/label.tsx +21 -0
  349. package/src/ui/internal/ui/select.tsx +129 -0
  350. package/src/ui/internal/ui/tooltip.tsx +54 -0
  351. package/src/ui/internal/ui/utils.ts +5 -0
  352. package/src/ui/plugin-styles.css +250 -0
  353. package/src/ui/primitives/dialog-lifecycle.ts +58 -0
  354. package/src/ui/primitives/dice.tsx +79 -0
  355. package/src/ui/primitives/primitive-props.tsx +101 -0
  356. package/src/ui/theme/ThemeProvider.tsx +252 -0
  357. package/src/ui/theme/board.ts +61 -0
  358. package/src/ui/theme/css-vars.ts +105 -0
  359. package/src/ui/theme/derive.ts +240 -0
  360. package/src/ui/theme/index.ts +61 -0
  361. package/src/ui/theme/presets/arcade.ts +261 -0
  362. package/src/ui/theme/presets/studio.ts +261 -0
  363. package/src/ui/theme/presets/tabletop.ts +266 -0
  364. package/src/ui/theme/tokens.ts +392 -0
  365. package/src/ui/types/hex-color.ts +20 -0
  366. package/src/ui/types/player-state.ts +463 -0
  367. package/src/ui/types/tiled-board.ts +785 -0
  368. package/src/ui/types/visual-state.ts +137 -0
  369. package/src/ui.ts +1 -0
@@ -0,0 +1,546 @@
1
+ import type { InteractionUiStore } from "../context/InteractionDraftContext.js";
2
+ import type {
3
+ InteractionDescriptor,
4
+ PluginStateSnapshot,
5
+ ZoneHandlesSnapshot,
6
+ } from "../types/plugin-state.js";
7
+ import {
8
+ inputByKey,
9
+ inputByTarget,
10
+ isResolvedTargetDomain,
11
+ isTargetDomain,
12
+ } from "./interaction-inputs.js";
13
+ import {
14
+ claimInteractionSubmit,
15
+ clearInteractionRoute,
16
+ markInteractionPending,
17
+ routeCardInputIntent,
18
+ shouldRouteInteractionPending,
19
+ type InteractionDraftReadiness,
20
+ type RoutedInteractionTargetResult,
21
+ } from "./interaction-router.js";
22
+ import { isInteractionAvailable } from "./interaction-status.js";
23
+
24
+ /**
25
+ * Opaque drop-target identifier emitted by SDK presentation. The runtime
26
+ * adapter resolves it back into a typed `(inputKey, value)` pair against the
27
+ * descriptor of the card the drop is for.
28
+ *
29
+ * Two encodings are supported, both opaque to SDK presentation:
30
+ *
31
+ * - `dreamboard:drop:input:<inputKey>:<value>` — explicit collector input
32
+ * key. Used by callers (CLI/scaffold tests, lower-level adapters) that
33
+ * already know the descriptor input shape.
34
+ * - `dreamboard:drop:kind:<targetKind>:<value>` — typed kind reference.
35
+ * Used by the generated hand surface, where authors describe a target by
36
+ * its domain kind (`card` for staging, `space`/`edge`/`vertex`/`tile`
37
+ * for board destinations). The runtime adapter resolves it to the
38
+ * matching collector input on the live descriptor at drop time.
39
+ */
40
+ export type RuntimeDropTargetId = string;
41
+
42
+ const DROP_TARGET_PREFIX = "dreamboard:drop";
43
+
44
+ export type RuntimeDropTargetKind =
45
+ | "card"
46
+ | "space"
47
+ | "edge"
48
+ | "vertex"
49
+ | "tile";
50
+
51
+ /**
52
+ * Build an opaque drop-target id keyed by the descriptor input name. Used
53
+ * when the caller already knows the collector input shape.
54
+ */
55
+ export function encodeRuntimeDropTargetId(
56
+ inputKey: string,
57
+ value: string,
58
+ ): RuntimeDropTargetId {
59
+ return `${DROP_TARGET_PREFIX}:input:${inputKey}:${value}`;
60
+ }
61
+
62
+ /**
63
+ * Build an opaque drop-target id keyed by typed target kind. Used by the
64
+ * generated hand surface, where authors do not (and should not) know the
65
+ * collector input names.
66
+ */
67
+ export function encodeRuntimeDropTargetKind(
68
+ kind: RuntimeDropTargetKind,
69
+ value: string,
70
+ ): RuntimeDropTargetId {
71
+ return `${DROP_TARGET_PREFIX}:kind:${kind}:${value}`;
72
+ }
73
+
74
+ export type DecodedRuntimeDropTarget =
75
+ | { mode: "input"; inputKey: string; value: string }
76
+ | { mode: "kind"; kind: RuntimeDropTargetKind; value: string };
77
+
78
+ export function decodeRuntimeDropTargetId(
79
+ targetId: RuntimeDropTargetId,
80
+ ): DecodedRuntimeDropTarget | null {
81
+ if (!targetId.startsWith(`${DROP_TARGET_PREFIX}:`)) return null;
82
+ const rest = targetId.slice(DROP_TARGET_PREFIX.length + 1);
83
+ if (rest.startsWith("input:")) {
84
+ const body = rest.slice("input:".length);
85
+ const sep = body.indexOf(":");
86
+ if (sep === -1) return null;
87
+ return {
88
+ mode: "input",
89
+ inputKey: body.slice(0, sep),
90
+ value: body.slice(sep + 1),
91
+ };
92
+ }
93
+ if (rest.startsWith("kind:")) {
94
+ const body = rest.slice("kind:".length);
95
+ const sep = body.indexOf(":");
96
+ if (sep === -1) return null;
97
+ const kind = body.slice(0, sep) as RuntimeDropTargetKind;
98
+ const value = body.slice(sep + 1);
99
+ if (
100
+ kind === "card" ||
101
+ kind === "space" ||
102
+ kind === "edge" ||
103
+ kind === "vertex" ||
104
+ kind === "tile"
105
+ ) {
106
+ return { mode: "kind", kind, value };
107
+ }
108
+ return null;
109
+ }
110
+ // Legacy format, kept for any external callers still using
111
+ // `dreamboard:drop:<inputKey>:<value>`. New writers should use one of the
112
+ // namespaced encoders above.
113
+ const sep = rest.indexOf(":");
114
+ if (sep === -1) return null;
115
+ return {
116
+ mode: "input",
117
+ inputKey: rest.slice(0, sep),
118
+ value: rest.slice(sep + 1),
119
+ };
120
+ }
121
+
122
+ export interface CardIntentAdapterContext {
123
+ store: InteractionUiStore;
124
+ /** Project-side snapshot of all available interactions (gameplay slice). */
125
+ availableInteractions: readonly InteractionDescriptor[];
126
+ /** Zone snapshot for the originating hand. */
127
+ zoneSnapshot: ZoneHandlesSnapshot | null;
128
+ /** Submit through the canonical runtime path. */
129
+ submit: (
130
+ descriptor: InteractionDescriptor,
131
+ params: Record<string, unknown>,
132
+ ) => Promise<void>;
133
+ /**
134
+ * Optional explicit interaction key. When provided, the adapter only routes
135
+ * intents through this interaction; otherwise it picks the first interaction
136
+ * eligible for the card.
137
+ */
138
+ interactionKey?: string;
139
+ }
140
+
141
+ export type CardIntentInput =
142
+ | { type: "activate"; cardId: string }
143
+ | { type: "drop"; cardId: string; targetId: string };
144
+
145
+ export type CardIntentResult =
146
+ | { status: "ignored"; reason: CardIntentIgnoredReason }
147
+ | {
148
+ status: "pending";
149
+ descriptor: InteractionDescriptor;
150
+ readiness: InteractionDraftReadiness;
151
+ params: Record<string, unknown>;
152
+ }
153
+ | {
154
+ status: "submitted";
155
+ descriptor: InteractionDescriptor;
156
+ readiness: InteractionDraftReadiness;
157
+ params: Record<string, unknown>;
158
+ }
159
+ | {
160
+ status: "submitting";
161
+ descriptor: InteractionDescriptor;
162
+ readiness: InteractionDraftReadiness;
163
+ params: Record<string, unknown>;
164
+ }
165
+ | {
166
+ status: "error";
167
+ descriptor: InteractionDescriptor;
168
+ error: unknown;
169
+ };
170
+
171
+ export type CardIntentIgnoredReason =
172
+ | "no-descriptor"
173
+ | "interaction-unavailable"
174
+ | "no-card-input"
175
+ | "card-not-eligible"
176
+ | "drop-target-not-decodable"
177
+ | "drop-target-input-unknown"
178
+ | "drop-target-not-eligible"
179
+ | "ambiguous-drop"
180
+ | "already-submitting";
181
+
182
+ interface CardRouteCandidate {
183
+ descriptor: InteractionDescriptor;
184
+ cardInputKey: string;
185
+ }
186
+
187
+ /**
188
+ * Enumerate descriptors that can accept this card. Used both to pick a
189
+ * single-action route for `activate` intents and to filter joint
190
+ * `(card, destination)` matches for `drop` intents.
191
+ */
192
+ function listCardRouteCandidates(
193
+ ctx: CardIntentAdapterContext,
194
+ cardId: string,
195
+ ): CardRouteCandidate[] {
196
+ const explicitKey = ctx.interactionKey;
197
+ const candidates = ctx.zoneSnapshot
198
+ ? (ctx.zoneSnapshot.playableByCardId[cardId] ?? [])
199
+ : ctx.availableInteractions.filter(
200
+ (descriptor) =>
201
+ !explicitKey ||
202
+ descriptor.interactionKey === explicitKey ||
203
+ descriptor.interactionId === explicitKey,
204
+ );
205
+ const result: CardRouteCandidate[] = [];
206
+ for (const descriptor of candidates) {
207
+ if (explicitKey && descriptor.interactionKey !== explicitKey) continue;
208
+ if (!isInteractionAvailable(descriptor)) continue;
209
+ const targetInput = inputByTarget(descriptor, "card", cardId);
210
+ if (targetInput) {
211
+ result.push({ descriptor, cardInputKey: targetInput.key });
212
+ continue;
213
+ }
214
+ const fallback = descriptor.inputs.find((input) => input.key === "cardId");
215
+ if (fallback && isTargetDomain(fallback.domain)) {
216
+ result.push({ descriptor, cardInputKey: fallback.key });
217
+ }
218
+ }
219
+ return result;
220
+ }
221
+
222
+ /**
223
+ * Apply an SDK `CardIntent` (generic activate/drop) to canonical Dreamboard
224
+ * collector state. Returns the runtime classification for the call site to
225
+ * react to (pending vs submitted vs ignored).
226
+ *
227
+ * Behavior:
228
+ * - `activate` is mapped onto `routeCardInputIntent` with no destination.
229
+ * - `drop` decodes the opaque target id; when it points at a typed input on
230
+ * the same descriptor, both the card and the destination are written
231
+ * atomically before readiness/`autoWhenReady` is evaluated.
232
+ * - Disabled, unavailable or ineligible intents return `ignored` even if the
233
+ * caller emits them.
234
+ */
235
+ export async function applyCardIntent(
236
+ ctx: CardIntentAdapterContext,
237
+ intent: CardIntentInput,
238
+ ): Promise<CardIntentResult> {
239
+ const candidates = listCardRouteCandidates(ctx, intent.cardId);
240
+ if (candidates.length === 0) {
241
+ return { status: "ignored", reason: "no-descriptor" };
242
+ }
243
+ // Filter out candidates whose card input rejects this card. The card
244
+ // domain may be unresolved (lazy) — those still pass since their
245
+ // eligibility is computed from the draft itself.
246
+ const cardEligible = candidates.filter(({ descriptor, cardInputKey }) => {
247
+ const cardInput = inputByKey(descriptor, cardInputKey);
248
+ if (!cardInput) return false;
249
+ if (!isResolvedTargetDomain(cardInput.domain)) return true;
250
+ return cardInput.domain.eligibleTargets.includes(intent.cardId);
251
+ });
252
+ if (cardEligible.length === 0) {
253
+ return { status: "ignored", reason: "card-not-eligible" };
254
+ }
255
+
256
+ let descriptor: InteractionDescriptor;
257
+ let cardInputKey: string;
258
+ let dropTarget: { inputKey: string; value: string } | undefined;
259
+
260
+ if (intent.type === "drop") {
261
+ const decoded = decodeRuntimeDropTargetId(intent.targetId);
262
+ if (!decoded) {
263
+ return { status: "ignored", reason: "drop-target-not-decodable" };
264
+ }
265
+ // Score every card-eligible candidate against the decoded destination.
266
+ // A descriptor is a "match" only when it accepts both the card and the
267
+ // dropped target; ambiguity is reported explicitly so authors can fix
268
+ // the underlying descriptor projection rather than getting silent
269
+ // submissions of the wrong action.
270
+ const matches = cardEligible.flatMap((candidate) => {
271
+ const resolvedInputKey =
272
+ decoded.mode === "input"
273
+ ? decoded.inputKey
274
+ : resolveDropTargetInputKey(
275
+ candidate.descriptor,
276
+ decoded.kind,
277
+ decoded.value,
278
+ );
279
+ if (!resolvedInputKey) return [];
280
+ const dropInput = inputByKey(candidate.descriptor, resolvedInputKey);
281
+ if (!dropInput) return [];
282
+ if (
283
+ isResolvedTargetDomain(dropInput.domain) &&
284
+ !dropInput.domain.eligibleTargets.includes(decoded.value)
285
+ ) {
286
+ return [];
287
+ }
288
+ return [
289
+ {
290
+ ...candidate,
291
+ dropTarget: { inputKey: resolvedInputKey, value: decoded.value },
292
+ },
293
+ ];
294
+ });
295
+ if (matches.length === 0) {
296
+ // Distinguish "no descriptor declares this input/kind at all" from
297
+ // "the dropped value is not eligible for any descriptor that does".
298
+ const anyKnowsKey = cardEligible.some((candidate) => {
299
+ if (decoded.mode === "input") {
300
+ return (
301
+ inputByKey(candidate.descriptor, decoded.inputKey) !== undefined
302
+ );
303
+ }
304
+ return (
305
+ resolveDropTargetInputKey(
306
+ candidate.descriptor,
307
+ decoded.kind,
308
+ decoded.value,
309
+ ) !== null
310
+ );
311
+ });
312
+ return {
313
+ status: "ignored",
314
+ reason: anyKnowsKey
315
+ ? "drop-target-not-eligible"
316
+ : "drop-target-input-unknown",
317
+ };
318
+ }
319
+ if (matches.length > 1) {
320
+ // Ambiguity: more than one descriptor accepts both this card and this
321
+ // destination. Signal so callers/tests catch the descriptor design
322
+ // bug rather than the runtime silently picking one.
323
+ return { status: "ignored", reason: "ambiguous-drop" };
324
+ }
325
+ descriptor = matches[0]!.descriptor;
326
+ cardInputKey = matches[0]!.cardInputKey;
327
+ dropTarget = matches[0]!.dropTarget;
328
+ } else {
329
+ descriptor = cardEligible[0]!.descriptor;
330
+ cardInputKey = cardEligible[0]!.cardInputKey;
331
+ }
332
+
333
+ if (!isInteractionAvailable(descriptor)) {
334
+ return { status: "ignored", reason: "interaction-unavailable" };
335
+ }
336
+ if (!inputByKey(descriptor, cardInputKey)) {
337
+ return { status: "ignored", reason: "no-card-input" };
338
+ }
339
+
340
+ const routed: RoutedInteractionTargetResult = routeCardInputIntent(
341
+ ctx.store,
342
+ descriptor,
343
+ {
344
+ cardInputKey,
345
+ cardId: intent.cardId,
346
+ dropTarget,
347
+ },
348
+ );
349
+
350
+ if (shouldRouteInteractionPending(descriptor, routed.readiness)) {
351
+ markInteractionPending(ctx.store, descriptor);
352
+ return {
353
+ status: "pending",
354
+ descriptor,
355
+ readiness: routed.readiness,
356
+ params: routed.params,
357
+ };
358
+ }
359
+
360
+ if (!claimInteractionSubmit(ctx.store, descriptor)) {
361
+ return {
362
+ status: "submitting",
363
+ descriptor,
364
+ readiness: routed.readiness,
365
+ params: routed.params,
366
+ };
367
+ }
368
+
369
+ try {
370
+ await ctx.submit(descriptor, routed.params);
371
+ clearInteractionRoute(ctx.store, descriptor);
372
+ return {
373
+ status: "submitted",
374
+ descriptor,
375
+ readiness: routed.readiness,
376
+ params: routed.params,
377
+ };
378
+ } catch (error) {
379
+ return { status: "error", descriptor, error };
380
+ } finally {
381
+ ctx.store.setSubmitting(descriptor.interactionKey, false);
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Resolve a typed drop-target kind/value pair to the descriptor's collector
387
+ * input key. Authors describe targets at the type level (e.g. board space
388
+ * `hex-a`) but the descriptor names that input by its authored collector
389
+ * key (e.g. `spaceId`). This bridges the two without surfacing collector
390
+ * names in the authoring API.
391
+ */
392
+ function resolveDropTargetInputKey(
393
+ descriptor: InteractionDescriptor,
394
+ kind: RuntimeDropTargetKind,
395
+ value: string,
396
+ ): string | null {
397
+ // Prefer an input whose authoritative resolved domain advertises this
398
+ // value as eligible. Falls back to a kind-only match for lazy domains.
399
+ let kindOnlyMatch: string | null = null;
400
+ for (const input of descriptor.inputs) {
401
+ if (!matchesDropTargetKind(input.domain, kind)) continue;
402
+ if (
403
+ isResolvedTargetDomain(input.domain) &&
404
+ input.domain.eligibleTargets.includes(value)
405
+ ) {
406
+ return input.key;
407
+ }
408
+ if (kindOnlyMatch === null) {
409
+ kindOnlyMatch = input.key;
410
+ }
411
+ }
412
+ return kindOnlyMatch;
413
+ }
414
+
415
+ function matchesDropTargetKind(
416
+ domain: InteractionDescriptor["inputs"][number]["domain"],
417
+ kind: RuntimeDropTargetKind,
418
+ ): boolean {
419
+ if (kind === "card") {
420
+ return isTargetDomain(domain) && domain.type === "cardTarget";
421
+ }
422
+ return (
423
+ isTargetDomain(domain) &&
424
+ domain.type === "boardTarget" &&
425
+ domain.targetKind === kind
426
+ );
427
+ }
428
+
429
+ /**
430
+ * Project descriptor + draft state into per-card visual flags used by the
431
+ * runtime hand surface. Each entry tracks which card ids are currently part
432
+ * of any card-target draft, and which of those have field validation errors.
433
+ */
434
+ export interface DraftCardProjectionEntry {
435
+ descriptor: InteractionDescriptor;
436
+ cardInputKeys: readonly string[];
437
+ draftCardIds: ReadonlySet<string>;
438
+ invalidCardIds: ReadonlySet<string>;
439
+ }
440
+
441
+ export function projectDraftCardState(
442
+ availableInteractions: readonly InteractionDescriptor[],
443
+ drafts: Readonly<Record<string, Readonly<Record<string, unknown>>>>,
444
+ validate: (
445
+ descriptor: InteractionDescriptor,
446
+ draft: Readonly<Record<string, unknown>>,
447
+ ) => Partial<Record<string, readonly string[]>>,
448
+ ): DraftCardProjectionEntry[] {
449
+ const entries: DraftCardProjectionEntry[] = [];
450
+ for (const descriptor of availableInteractions) {
451
+ const cardInputs = descriptor.inputs.filter(
452
+ (input) =>
453
+ isTargetDomain(input.domain) && input.domain.type === "cardTarget",
454
+ );
455
+ if (cardInputs.length === 0) continue;
456
+ const draft = drafts[descriptor.interactionKey] ?? {};
457
+ const draftCardIds = new Set<string>();
458
+ for (const input of cardInputs) {
459
+ const value = draft[input.key];
460
+ if (Array.isArray(value)) {
461
+ for (const item of value) {
462
+ if (typeof item === "string") draftCardIds.add(item);
463
+ }
464
+ } else if (typeof value === "string") {
465
+ draftCardIds.add(value);
466
+ }
467
+ }
468
+ const fieldErrors = validate(descriptor, draft);
469
+ const invalidCardIds = new Set<string>();
470
+ for (const input of cardInputs) {
471
+ if ((fieldErrors[input.key]?.length ?? 0) === 0) continue;
472
+ const value = draft[input.key];
473
+ if (Array.isArray(value)) {
474
+ for (const item of value) {
475
+ if (typeof item === "string") invalidCardIds.add(item);
476
+ }
477
+ } else if (typeof value === "string") {
478
+ invalidCardIds.add(value);
479
+ }
480
+ }
481
+ entries.push({
482
+ descriptor,
483
+ cardInputKeys: cardInputs.map((input) => input.key),
484
+ draftCardIds,
485
+ invalidCardIds,
486
+ });
487
+ }
488
+ return entries;
489
+ }
490
+
491
+ export interface ProjectedCardVisualState {
492
+ selected: boolean;
493
+ invalid: boolean;
494
+ }
495
+
496
+ /**
497
+ * Combine the per-descriptor projection into a single per-card flag tuple.
498
+ */
499
+ export function visualStateForCard(
500
+ cardId: string,
501
+ projection: readonly DraftCardProjectionEntry[],
502
+ ): ProjectedCardVisualState {
503
+ let selected = false;
504
+ let invalid = false;
505
+ for (const entry of projection) {
506
+ if (entry.draftCardIds.has(cardId)) selected = true;
507
+ if (entry.invalidCardIds.has(cardId)) invalid = true;
508
+ }
509
+ return { selected, invalid };
510
+ }
511
+
512
+ /**
513
+ * Return the set of card ids that are currently part of a many-selection
514
+ * draft for any descriptor in the zone. Used by the hand view to drop
515
+ * selected cards out of the visible hand layout while keeping the runtime
516
+ * source of truth in the zone snapshot.
517
+ */
518
+ export function selectedCardIdsForZone(
519
+ store: Pick<InteractionUiStore, "getDraft">,
520
+ zone: string,
521
+ state: PluginStateSnapshot,
522
+ ): readonly string[] {
523
+ const result = new Set<string>();
524
+ for (const descriptor of state.gameplay.availableInteractions) {
525
+ const cardInput = descriptor.inputs.find((input) => {
526
+ if (!isTargetDomain(input.domain)) return false;
527
+ if (input.domain.type !== "cardTarget") return false;
528
+ const declaredZones =
529
+ input.domain.zoneId !== undefined
530
+ ? [input.domain.zoneId]
531
+ : (input.domain.zoneIds ?? []);
532
+ return declaredZones.length === 0 || declaredZones.includes(zone);
533
+ });
534
+ if (!cardInput) continue;
535
+ if (!isTargetDomain(cardInput.domain)) continue;
536
+ if (cardInput.domain.type !== "cardTarget") continue;
537
+ const draft = store.getDraft(descriptor.interactionKey);
538
+ const value = draft[cardInput.key];
539
+ if (cardInput.domain.selection?.mode === "many" && Array.isArray(value)) {
540
+ for (const item of value) {
541
+ if (typeof item === "string") result.add(item);
542
+ }
543
+ }
544
+ }
545
+ return [...result];
546
+ }