@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,185 @@
1
+ /**
2
+ * useHexGrid hook - Headless logic for hex grid games
3
+ *
4
+ * Provides utilities for:
5
+ * - Coordinate conversion and neighbor finding
6
+ * - Distance calculations
7
+ * - Tile lookups
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * const { getNeighbors, getDistance, getTile } = useHexGrid(tiles);
12
+ *
13
+ * // Find all adjacent tiles
14
+ * const neighbors = getNeighbors('center');
15
+ *
16
+ * // Check if two tiles are adjacent
17
+ * const isAdjacent = getDistance('tile1', 'tile2') === 1;
18
+ * ```
19
+ */
20
+
21
+ import { useMemo, useCallback } from "react";
22
+
23
+ // ============================================================================
24
+ // Types
25
+ // ============================================================================
26
+
27
+ export interface HexTileData {
28
+ /** Unique tile identifier */
29
+ id: string;
30
+ /** Axial coordinate Q */
31
+ q: number;
32
+ /** Axial coordinate R */
33
+ r: number;
34
+ /** Tile type */
35
+ type?: string;
36
+ /** Additional data */
37
+ data?: Record<string, unknown>;
38
+ }
39
+
40
+ export interface UseHexGridReturn {
41
+ /** Get a tile by ID */
42
+ getTile: (tileId: string) => HexTileData | undefined;
43
+ /** Get a tile by coordinates */
44
+ getTileAt: (q: number, r: number) => HexTileData | undefined;
45
+ /** Get neighboring tiles */
46
+ getNeighbors: (tileId: string) => HexTileData[];
47
+ /** Get distance between two tiles */
48
+ getDistance: (fromId: string, toId: string) => number;
49
+ /** Get all tiles within a range */
50
+ getHexesInRange: (centerId: string, range: number) => HexTileData[];
51
+ /** Convert axial to cube coordinates */
52
+ axialToCube: (q: number, r: number) => { x: number; y: number; z: number };
53
+ /** Convert cube to axial coordinates */
54
+ cubeToAxial: (x: number, y: number, z: number) => { q: number; r: number };
55
+ }
56
+
57
+ // ============================================================================
58
+ // Axial direction vectors
59
+ // ============================================================================
60
+
61
+ const AXIAL_DIRECTIONS = [
62
+ { q: 1, r: 0 },
63
+ { q: 1, r: -1 },
64
+ { q: 0, r: -1 },
65
+ { q: -1, r: 0 },
66
+ { q: -1, r: 1 },
67
+ { q: 0, r: 1 },
68
+ ];
69
+
70
+ // ============================================================================
71
+ // Hook Implementation
72
+ // ============================================================================
73
+
74
+ export function useHexGrid(tiles: HexTileData[]): UseHexGridReturn {
75
+ // Create lookup maps
76
+ const tileById = useMemo(() => {
77
+ return new Map(tiles.map((t) => [t.id, t]));
78
+ }, [tiles]);
79
+
80
+ const tileByCoord = useMemo(() => {
81
+ return new Map(tiles.map((t) => [`${t.q},${t.r}`, t]));
82
+ }, [tiles]);
83
+
84
+ // Get tile by ID
85
+ const getTile = useCallback(
86
+ (tileId: string): HexTileData | undefined => {
87
+ return tileById.get(tileId);
88
+ },
89
+ [tileById],
90
+ );
91
+
92
+ // Get tile by coordinates
93
+ const getTileAt = useCallback(
94
+ (q: number, r: number): HexTileData | undefined => {
95
+ return tileByCoord.get(`${q},${r}`);
96
+ },
97
+ [tileByCoord],
98
+ );
99
+
100
+ // Get neighboring tiles
101
+ const getNeighbors = useCallback(
102
+ (tileId: string): HexTileData[] => {
103
+ const tile = tileById.get(tileId);
104
+ if (!tile) return [];
105
+
106
+ const neighbors: HexTileData[] = [];
107
+ for (const dir of AXIAL_DIRECTIONS) {
108
+ const neighbor = tileByCoord.get(`${tile.q + dir.q},${tile.r + dir.r}`);
109
+ if (neighbor) {
110
+ neighbors.push(neighbor);
111
+ }
112
+ }
113
+ return neighbors;
114
+ },
115
+ [tileById, tileByCoord],
116
+ );
117
+
118
+ // Calculate distance between two tiles
119
+ const getDistance = useCallback(
120
+ (fromId: string, toId: string): number => {
121
+ const from = tileById.get(fromId);
122
+ const to = tileById.get(toId);
123
+ if (!from || !to) return Infinity;
124
+
125
+ // Hex distance formula using axial coordinates
126
+ return (
127
+ (Math.abs(from.q - to.q) +
128
+ Math.abs(from.q + from.r - to.q - to.r) +
129
+ Math.abs(from.r - to.r)) /
130
+ 2
131
+ );
132
+ },
133
+ [tileById],
134
+ );
135
+
136
+ // Get all tiles within range
137
+ const getHexesInRange = useCallback(
138
+ (centerId: string, range: number): HexTileData[] => {
139
+ const center = tileById.get(centerId);
140
+ if (!center) return [];
141
+
142
+ const results: HexTileData[] = [];
143
+
144
+ for (let dq = -range; dq <= range; dq++) {
145
+ const minR = Math.max(-range, -dq - range);
146
+ const maxR = Math.min(range, -dq + range);
147
+ for (let dr = minR; dr <= maxR; dr++) {
148
+ const tile = tileByCoord.get(`${center.q + dq},${center.r + dr}`);
149
+ if (tile) {
150
+ results.push(tile);
151
+ }
152
+ }
153
+ }
154
+
155
+ return results;
156
+ },
157
+ [tileById, tileByCoord],
158
+ );
159
+
160
+ // Convert axial to cube coordinates
161
+ const axialToCube = useCallback(
162
+ (q: number, r: number): { x: number; y: number; z: number } => {
163
+ return { x: q, z: r, y: -q - r };
164
+ },
165
+ [],
166
+ );
167
+
168
+ // Convert cube to axial coordinates
169
+ const cubeToAxial = useCallback(
170
+ (x: number, _y: number, z: number): { q: number; r: number } => {
171
+ return { q: x, r: z };
172
+ },
173
+ [],
174
+ );
175
+
176
+ return {
177
+ getTile,
178
+ getTileAt,
179
+ getNeighbors,
180
+ getDistance,
181
+ getHexesInRange,
182
+ axialToCube,
183
+ cubeToAxial,
184
+ };
185
+ }
@@ -0,0 +1,35 @@
1
+ import { useState, useEffect } from "react";
2
+
3
+ const MOBILE_BREAKPOINT = 768;
4
+
5
+ /**
6
+ * Hook to detect if the user is on a mobile/small screen device
7
+ * @param breakpoint - The width threshold in pixels (default: 768)
8
+ * @returns boolean indicating if the screen is mobile-sized
9
+ */
10
+ export function useIsMobile(breakpoint: number = MOBILE_BREAKPOINT): boolean {
11
+ const [isMobile, setIsMobile] = useState(() => {
12
+ // SSR-safe: default to false if window is not available
13
+ if (typeof window === "undefined") return false;
14
+ return window.innerWidth < breakpoint;
15
+ });
16
+
17
+ useEffect(() => {
18
+ if (typeof window === "undefined") return;
19
+
20
+ const mediaQuery = window.matchMedia(`(max-width: ${breakpoint - 1}px)`);
21
+
22
+ const handleChange = (e: MediaQueryListEvent | MediaQueryList) => {
23
+ setIsMobile(e.matches);
24
+ };
25
+
26
+ // Set initial value
27
+ handleChange(mediaQuery);
28
+
29
+ // Listen for changes
30
+ mediaQuery.addEventListener("change", handleChange);
31
+ return () => mediaQuery.removeEventListener("change", handleChange);
32
+ }, [breakpoint]);
33
+
34
+ return isMobile;
35
+ }
@@ -0,0 +1,278 @@
1
+ /**
2
+ * usePanZoom hook - Unified pan and zoom gestures using @use-gesture/react
3
+ *
4
+ * Provides a declarative API for pan and zoom interactions on board components.
5
+ * Works with both SVG (via viewBox) and HTML (via CSS transforms) elements.
6
+ *
7
+ * Features:
8
+ * - Single finger/mouse drag for panning
9
+ * - Pinch-to-zoom on touch devices
10
+ * - Mouse wheel zoom on desktop
11
+ * - Configurable zoom limits
12
+ * - Optional momentum/inertia
13
+ *
14
+ * @example SVG usage (NetworkGraph, HexGrid, etc.)
15
+ * ```tsx
16
+ * const { transform, bind, resetTransform } = usePanZoom({
17
+ * enabled: enablePanZoom,
18
+ * minZoom: 0.5,
19
+ * maxZoom: 3,
20
+ * });
21
+ *
22
+ * // Apply to viewBox calculation
23
+ * const viewBoxWidth = contentWidth / transform.zoom;
24
+ * const viewBoxX = baseX - transform.pan.x;
25
+ *
26
+ * <svg {...bind()} style={{ touchAction: 'none' }}>
27
+ * ...
28
+ * </svg>
29
+ * ```
30
+ *
31
+ * @example HTML usage (SlotSystem, etc.)
32
+ * ```tsx
33
+ * const { transform, bind, style } = usePanZoom({
34
+ * enabled: enablePanZoom,
35
+ * mode: 'css',
36
+ * });
37
+ *
38
+ * <div {...bind()} style={{ ...style, touchAction: 'none' }}>
39
+ * ...
40
+ * </div>
41
+ * ```
42
+ */
43
+
44
+ import { useState, useCallback, useEffect, useMemo } from "react";
45
+ import { useGesture, type Handler } from "@use-gesture/react";
46
+
47
+ export interface PanZoomTransform {
48
+ /** Current zoom level (1 = 100%) */
49
+ zoom: number;
50
+ /** Current pan offset */
51
+ pan: { x: number; y: number };
52
+ }
53
+
54
+ export interface UsePanZoomOptions {
55
+ /** Whether pan/zoom is enabled */
56
+ enabled?: boolean;
57
+ /** Initial zoom level */
58
+ initialZoom?: number;
59
+ /** Minimum zoom level */
60
+ minZoom?: number;
61
+ /** Maximum zoom level */
62
+ maxZoom?: number;
63
+ /** Initial pan offset */
64
+ initialPan?: { x: number; y: number };
65
+ /** Transform mode: 'viewbox' for SVG, 'css' for HTML elements */
66
+ mode?: "viewbox" | "css";
67
+ /** Zoom sensitivity for wheel events (default: 0.002) */
68
+ wheelSensitivity?: number;
69
+ /** Called when transform changes */
70
+ onTransformChange?: (transform: PanZoomTransform) => void;
71
+ }
72
+
73
+ /** Type for gesture bind function that returns props to spread on element
74
+ * Note: We omit ref from the return type to avoid conflicts with explicit refs on elements.
75
+ * The gesture library handles its own internal ref binding.
76
+ */
77
+ type GestureBindFunction = () => Omit<React.HTMLAttributes<Element>, "ref">;
78
+
79
+ export interface UsePanZoomReturn {
80
+ /** Current transform state */
81
+ transform: PanZoomTransform;
82
+ /** Gesture handlers to spread on the target element - always returns spreadable props */
83
+ bind: GestureBindFunction;
84
+ /** Reset transform to initial values */
85
+ resetTransform: () => void;
86
+ /** Set zoom programmatically */
87
+ setZoom: (zoom: number) => void;
88
+ /** Set pan programmatically */
89
+ setPan: (pan: { x: number; y: number }) => void;
90
+ /** CSS transform style (for mode: 'css') */
91
+ style: React.CSSProperties;
92
+ /** Whether currently dragging/panning */
93
+ isDragging: boolean;
94
+ /** Whether currently pinching */
95
+ isPinching: boolean;
96
+ }
97
+
98
+ /**
99
+ * Hook for pan and zoom gestures on board components
100
+ */
101
+ export function usePanZoom(options: UsePanZoomOptions = {}): UsePanZoomReturn {
102
+ const {
103
+ enabled = true,
104
+ initialZoom = 1,
105
+ minZoom = 0.5,
106
+ maxZoom = 3,
107
+ initialPan = { x: 0, y: 0 },
108
+ mode = "viewbox",
109
+ wheelSensitivity = 0.002,
110
+ onTransformChange,
111
+ } = options;
112
+
113
+ const [zoom, setZoomState] = useState(initialZoom);
114
+ const [pan, setPanState] = useState(initialPan);
115
+ const [isDragging, setIsDragging] = useState(false);
116
+ const [isPinching, setIsPinching] = useState(false);
117
+
118
+ // Clamp zoom to bounds
119
+ const clampZoom = useCallback(
120
+ (z: number) => Math.min(maxZoom, Math.max(minZoom, z)),
121
+ [minZoom, maxZoom],
122
+ );
123
+
124
+ // Update transform and notify
125
+ const updateTransform = useCallback(
126
+ (newZoom: number, newPan: { x: number; y: number }) => {
127
+ const clampedZoom = clampZoom(newZoom);
128
+ setZoomState(clampedZoom);
129
+ setPanState(newPan);
130
+ onTransformChange?.({ zoom: clampedZoom, pan: newPan });
131
+ },
132
+ [clampZoom, onTransformChange],
133
+ );
134
+
135
+ // Gesture bindings
136
+ const bind = useGesture(
137
+ {
138
+ onDrag: (({
139
+ delta: [dx, dy],
140
+ active,
141
+ pinching,
142
+ }: Parameters<Handler<"drag">>[0]) => {
143
+ if (!enabled || pinching) return;
144
+
145
+ setIsDragging(active);
146
+
147
+ if (active) {
148
+ // For viewbox mode, we invert and scale the delta
149
+ // For CSS mode, we apply directly
150
+ const scaleFactor = mode === "viewbox" ? 1 / zoom : 1;
151
+ setPanState((prev) => ({
152
+ x: prev.x + dx * scaleFactor,
153
+ y: prev.y + dy * scaleFactor,
154
+ }));
155
+ }
156
+ }) as Handler<"drag">,
157
+ onPinch: (({
158
+ offset: [scale],
159
+ active,
160
+ }: Parameters<Handler<"pinch">>[0]) => {
161
+ if (!enabled) return;
162
+
163
+ setIsPinching(active);
164
+
165
+ if (active) {
166
+ const newZoom = clampZoom(scale);
167
+ setZoomState(newZoom);
168
+ onTransformChange?.({ zoom: newZoom, pan });
169
+ }
170
+ }) as Handler<"pinch">,
171
+ onWheel: (({ delta: [, dy], event }: Parameters<Handler<"wheel">>[0]) => {
172
+ if (!enabled) return;
173
+
174
+ event.preventDefault();
175
+ const newZoom = clampZoom(zoom - dy * wheelSensitivity);
176
+ setZoomState(newZoom);
177
+ onTransformChange?.({ zoom: newZoom, pan });
178
+ }) as Handler<"wheel">,
179
+ },
180
+ {
181
+ drag: {
182
+ enabled,
183
+ filterTaps: true,
184
+ },
185
+ pinch: {
186
+ enabled,
187
+ scaleBounds: { min: minZoom, max: maxZoom },
188
+ from: () => [zoom, 0],
189
+ },
190
+ wheel: {
191
+ enabled,
192
+ eventOptions: { passive: false },
193
+ },
194
+ },
195
+ );
196
+
197
+ // Reset to initial values
198
+ const resetTransform = useCallback(() => {
199
+ updateTransform(initialZoom, initialPan);
200
+ }, [initialZoom, initialPan, updateTransform]);
201
+
202
+ useEffect(() => {
203
+ updateTransform(initialZoom, initialPan);
204
+ }, [initialZoom, initialPan.x, initialPan.y, updateTransform]);
205
+
206
+ // Programmatic setters
207
+ const setZoom = useCallback(
208
+ (newZoom: number) => {
209
+ updateTransform(clampZoom(newZoom), pan);
210
+ },
211
+ [pan, clampZoom, updateTransform],
212
+ );
213
+
214
+ const setPan = useCallback(
215
+ (newPan: { x: number; y: number }) => {
216
+ updateTransform(zoom, newPan);
217
+ },
218
+ [zoom, updateTransform],
219
+ );
220
+
221
+ // CSS transform style for HTML mode
222
+ const style = useMemo<React.CSSProperties>(
223
+ () =>
224
+ mode === "css"
225
+ ? {
226
+ transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`,
227
+ transformOrigin: "center center",
228
+ }
229
+ : {},
230
+ [mode, pan.x, pan.y, zoom],
231
+ );
232
+
233
+ // Current transform state
234
+ const transform = useMemo<PanZoomTransform>(
235
+ () => ({ zoom, pan }),
236
+ [zoom, pan],
237
+ );
238
+
239
+ // Wrap bind to ensure it always returns spreadable props (never void)
240
+ // We exclude 'ref' from the result to avoid type conflicts with explicit element refs
241
+ const safeBind: GestureBindFunction = useCallback(() => {
242
+ const result = bind();
243
+ // If bind returns void (shouldn't happen with our config), return empty object
244
+ // Destructure to omit ref, avoiding type conflicts with SVG/HTML element refs
245
+
246
+ const { ref: _ref, ...propsWithoutRef } = (result ??
247
+ {}) as React.HTMLAttributes<Element> & { ref?: unknown };
248
+ return propsWithoutRef;
249
+ }, [bind]);
250
+
251
+ return {
252
+ transform,
253
+ bind: safeBind,
254
+ resetTransform,
255
+ setZoom,
256
+ setPan,
257
+ style,
258
+ isDragging,
259
+ isPinching,
260
+ };
261
+ }
262
+
263
+ /**
264
+ * Helper to calculate SVG viewBox with pan/zoom applied
265
+ */
266
+ export function calculateViewBox(
267
+ bounds: { minX: number; minY: number; width: number; height: number },
268
+ transform: PanZoomTransform,
269
+ ): string {
270
+ const viewBoxWidth = bounds.width / transform.zoom;
271
+ const viewBoxHeight = bounds.height / transform.zoom;
272
+ const viewBoxX =
273
+ bounds.minX + (bounds.width - viewBoxWidth) / 2 - transform.pan.x;
274
+ const viewBoxY =
275
+ bounds.minY + (bounds.height - viewBoxHeight) / 2 - transform.pan.y;
276
+
277
+ return `${viewBoxX} ${viewBoxY} ${viewBoxWidth} ${viewBoxHeight}`;
278
+ }
@@ -0,0 +1,124 @@
1
+ import { useCallback, useMemo } from "react";
2
+ import type {
3
+ AnySquareBoardInput,
4
+ BoardSpaceIdOf,
5
+ NormalizedSquareBoard,
6
+ NormalizedSquareCellOf,
7
+ } from "../types/tiled-board.js";
8
+ import { normalizeSquareBoardInput } from "../types/tiled-board.js";
9
+ import { useBoardTopology } from "./useBoardTopology.js";
10
+
11
+ type NeighborMode = "orthogonal" | "diagonal" | "all";
12
+ type DistanceMetric = "manhattan" | "chebyshev";
13
+
14
+ export function useSquareBoard<const TBoard extends AnySquareBoardInput>(
15
+ board: TBoard,
16
+ ) {
17
+ const normalizedBoard = useMemo<NormalizedSquareBoard<TBoard>>(
18
+ () => normalizeSquareBoardInput(board),
19
+ [board],
20
+ );
21
+ const topology = useBoardTopology(board);
22
+
23
+ const cellByCoordinate = useMemo(
24
+ () =>
25
+ new Map(
26
+ normalizedBoard.cells.map(
27
+ (cell) => [`${cell.row},${cell.col}`, cell] as const,
28
+ ),
29
+ ),
30
+ [normalizedBoard.cells],
31
+ );
32
+
33
+ const getCell = useCallback(
34
+ (cellId: BoardSpaceIdOf<TBoard>) => {
35
+ return topology.getSpace(cellId) as
36
+ | NormalizedSquareCellOf<TBoard>
37
+ | undefined;
38
+ },
39
+ [topology],
40
+ );
41
+
42
+ const getCellAt = useCallback(
43
+ (row: number, col: number) => {
44
+ return cellByCoordinate.get(`${row},${col}`) as
45
+ | NormalizedSquareCellOf<TBoard>
46
+ | undefined;
47
+ },
48
+ [cellByCoordinate],
49
+ );
50
+
51
+ const getNeighbors = useCallback(
52
+ (cellId: BoardSpaceIdOf<TBoard>, mode: NeighborMode = "orthogonal") => {
53
+ const cell = getCell(cellId);
54
+ if (!cell) {
55
+ return [] as Array<NormalizedSquareCellOf<TBoard>>;
56
+ }
57
+
58
+ const offsets: ReadonlyArray<readonly [number, number]> =
59
+ mode === "diagonal"
60
+ ? [
61
+ [-1, -1],
62
+ [-1, 1],
63
+ [1, -1],
64
+ [1, 1],
65
+ ]
66
+ : mode === "all"
67
+ ? [
68
+ [-1, 0],
69
+ [0, 1],
70
+ [1, 0],
71
+ [0, -1],
72
+ [-1, -1],
73
+ [-1, 1],
74
+ [1, -1],
75
+ [1, 1],
76
+ ]
77
+ : [
78
+ [-1, 0],
79
+ [0, 1],
80
+ [1, 0],
81
+ [0, -1],
82
+ ];
83
+
84
+ return offsets
85
+ .map(([rowOffset, colOffset]) =>
86
+ getCellAt(cell.row + rowOffset, cell.col + colOffset),
87
+ )
88
+ .filter(
89
+ (candidate): candidate is NormalizedSquareCellOf<TBoard> =>
90
+ candidate !== undefined,
91
+ );
92
+ },
93
+ [getCell, getCellAt],
94
+ );
95
+
96
+ const getDistance = useCallback(
97
+ (
98
+ fromCellId: BoardSpaceIdOf<TBoard>,
99
+ toCellId: BoardSpaceIdOf<TBoard>,
100
+ metric: DistanceMetric = "manhattan",
101
+ ) => {
102
+ const fromCell = getCell(fromCellId);
103
+ const toCell = getCell(toCellId);
104
+ if (!fromCell || !toCell) {
105
+ return Number.POSITIVE_INFINITY;
106
+ }
107
+ const rowDistance = Math.abs(fromCell.row - toCell.row);
108
+ const colDistance = Math.abs(fromCell.col - toCell.col);
109
+ return metric === "chebyshev"
110
+ ? Math.max(rowDistance, colDistance)
111
+ : rowDistance + colDistance;
112
+ },
113
+ [getCell],
114
+ );
115
+
116
+ return {
117
+ ...topology,
118
+ board: normalizedBoard,
119
+ getCell,
120
+ getCellAt,
121
+ getNeighbors,
122
+ getDistance,
123
+ };
124
+ }