@benev/tact 0.2.0 → 0.3.0-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.
Files changed (495) hide show
  1. package/README.md +48 -390
  2. package/package.json +25 -27
  3. package/s/_archive/README.md +435 -0
  4. package/s/_archive/deck/deck.ts +69 -0
  5. package/s/_archive/demo/main.bundle.ts +10 -0
  6. package/s/_archive/demo/main.css +85 -0
  7. package/s/_archive/index.html.ts +61 -0
  8. package/s/_archive/index.ts +8 -0
  9. package/s/_archive/tests.test.ts +6 -0
  10. package/s/_archive/utils/circular-clamp.ts +14 -0
  11. package/s/_archive/utils/evergreen.ts +10 -0
  12. package/s/_archive/utils/split-axis.ts +15 -0
  13. package/s/assets/b.png +0 -0
  14. package/s/core/atom/defaults.ts +32 -0
  15. package/s/core/atom/lens-algo.ts +84 -0
  16. package/s/core/atom/types.ts +44 -0
  17. package/s/core/bindings/normalize.ts +27 -0
  18. package/s/core/bindings/shape.ts +15 -0
  19. package/s/core/bindings/table.ts +22 -0
  20. package/s/core/intent/bucket.ts +28 -0
  21. package/s/core/intent/consts.ts +4 -0
  22. package/s/core/intent/decode.ts +23 -0
  23. package/s/core/intent/encode.ts +20 -0
  24. package/s/core/intent/merge.ts +15 -0
  25. package/s/core/parts/action.ts +36 -0
  26. package/s/core/parts/sample-map.ts +24 -0
  27. package/s/core/resolvers/actions.ts +30 -0
  28. package/s/core/resolvers/intents.ts +106 -0
  29. package/s/core/types.ts +40 -0
  30. package/s/deck/controller.ts +35 -0
  31. package/s/deck/deck.ts +76 -53
  32. package/s/deck/parts/profiles.ts +39 -0
  33. package/s/deck/parts/runtime.ts +11 -0
  34. package/s/deck/parts/settings.ts +30 -0
  35. package/s/deck/port.ts +35 -0
  36. package/s/deck/types.ts +16 -0
  37. package/s/demo/demo-app/element.ts +17 -0
  38. package/s/demo/demo-app/style.css.ts +10 -0
  39. package/s/demo/main.bundle.ts +67 -6
  40. package/s/demo/main.css +6 -8
  41. package/s/device/devices.ts +24 -0
  42. package/s/device/gamepad.ts +42 -0
  43. package/s/device/keyboard.ts +33 -0
  44. package/s/device/pad/on-pad.ts +50 -0
  45. package/s/device/pad/pad.ts +10 -0
  46. package/s/device/pointer.ts +97 -0
  47. package/s/device/sampler.ts +25 -0
  48. package/s/device/stick.ts +24 -0
  49. package/s/gamepad/gamepad-app/element.ts +65 -0
  50. package/s/gamepad/gamepad-app/style.css.ts +73 -0
  51. package/s/gamepad/index.html.ts +44 -0
  52. package/s/gamepad/main.bundle.ts +6 -0
  53. package/s/gamepad/main.css +60 -0
  54. package/s/index-ui.ts +3 -0
  55. package/s/index.html.ts +10 -17
  56. package/s/index.ts +28 -5
  57. package/s/test.ts +339 -0
  58. package/s/ui/views/desk/style.css.ts +70 -0
  59. package/s/ui/views/desk/view.ts +122 -0
  60. package/s/utils/circular-clamp.ts +2 -2
  61. package/s/utils/do-async.ts +5 -0
  62. package/s/utils/freeze-clone.ts +7 -0
  63. package/s/utils/identifier.ts +30 -0
  64. package/s/utils/insert.ts +6 -0
  65. package/s/utils/is-down.ts +5 -0
  66. package/s/utils/make-id.ts +7 -0
  67. package/s/utils/remap.ts +7 -0
  68. package/s/utils/shift-limit.ts +9 -0
  69. package/s/utils/sort-by-key.ts +7 -0
  70. package/s/utils/tmax.ts +7 -0
  71. package/s/utils/tmin.ts +7 -0
  72. package/x/_archive/demo/main.css +85 -0
  73. package/x/assets/b.png +0 -0
  74. package/x/core/{bindings/parts → atom}/defaults.d.ts +1 -1
  75. package/x/core/atom/defaults.js.map +1 -0
  76. package/x/core/{bindings/parts → atom}/lens-algo.d.ts +1 -1
  77. package/x/core/{bindings/parts → atom}/lens-algo.js +8 -8
  78. package/x/core/atom/lens-algo.js.map +1 -0
  79. package/x/core/{bindings → atom}/types.d.ts +1 -15
  80. package/x/core/{devices → atom}/types.js.map +1 -1
  81. package/x/core/bindings/normalize.d.ts +2 -0
  82. package/x/core/bindings/normalize.js +17 -0
  83. package/x/core/bindings/normalize.js.map +1 -0
  84. package/x/core/bindings/shape.d.ts +2 -0
  85. package/x/core/bindings/shape.js +10 -0
  86. package/x/core/bindings/shape.js.map +1 -0
  87. package/x/core/bindings/table.d.ts +2 -0
  88. package/x/core/bindings/table.js +15 -0
  89. package/x/core/bindings/table.js.map +1 -0
  90. package/x/core/intent/bucket.d.ts +7 -0
  91. package/x/core/intent/bucket.js +21 -0
  92. package/x/core/intent/bucket.js.map +1 -0
  93. package/x/core/intent/consts.d.ts +2 -0
  94. package/x/core/intent/consts.js +3 -0
  95. package/x/core/intent/consts.js.map +1 -0
  96. package/x/core/intent/decode.d.ts +3 -0
  97. package/x/core/intent/decode.js +18 -0
  98. package/x/core/intent/decode.js.map +1 -0
  99. package/x/core/intent/encode.d.ts +3 -0
  100. package/x/core/intent/encode.js +15 -0
  101. package/x/core/intent/encode.js.map +1 -0
  102. package/x/core/intent/merge.d.ts +3 -0
  103. package/x/core/intent/merge.js +10 -0
  104. package/x/core/intent/merge.js.map +1 -0
  105. package/x/core/{bindings → parts}/action.d.ts +5 -3
  106. package/x/core/parts/action.js +30 -0
  107. package/x/core/parts/action.js.map +1 -0
  108. package/x/core/parts/sample-map.d.ts +6 -0
  109. package/x/core/{bindings → parts}/sample-map.js +2 -3
  110. package/x/core/parts/sample-map.js.map +1 -0
  111. package/x/core/resolvers/actions.d.ts +2 -0
  112. package/x/core/resolvers/actions.js +23 -0
  113. package/x/core/resolvers/actions.js.map +1 -0
  114. package/x/core/resolvers/intents.d.ts +2 -0
  115. package/x/core/{bindings/resolver.js → resolvers/intents.js} +39 -43
  116. package/x/core/resolvers/intents.js.map +1 -0
  117. package/x/core/types.d.ts +43 -0
  118. package/x/core/types.js +2 -0
  119. package/x/core/types.js.map +1 -0
  120. package/x/deck/controller.d.ts +11 -0
  121. package/x/deck/controller.js +28 -0
  122. package/x/deck/controller.js.map +1 -0
  123. package/x/deck/deck.d.ts +30 -26
  124. package/x/deck/deck.js +64 -43
  125. package/x/deck/deck.js.map +1 -1
  126. package/x/deck/parts/profiles.d.ts +12 -0
  127. package/x/deck/parts/profiles.js +31 -0
  128. package/x/deck/parts/profiles.js.map +1 -0
  129. package/x/deck/parts/runtime.d.ts +8 -0
  130. package/x/deck/parts/runtime.js +7 -0
  131. package/x/deck/parts/runtime.js.map +1 -0
  132. package/x/deck/parts/settings.d.ts +11 -0
  133. package/x/deck/parts/settings.js +26 -0
  134. package/x/deck/parts/settings.js.map +1 -0
  135. package/x/deck/port.d.ts +10 -0
  136. package/x/deck/port.js +24 -0
  137. package/x/deck/port.js.map +1 -0
  138. package/x/deck/types.d.ts +11 -0
  139. package/x/deck/types.js +2 -0
  140. package/x/deck/types.js.map +1 -0
  141. package/x/demo/demo-app/element.d.ts +3 -0
  142. package/x/demo/demo-app/element.js +13 -0
  143. package/x/demo/demo-app/element.js.map +1 -0
  144. package/x/demo/demo-app/style.css.js +9 -0
  145. package/x/demo/demo-app/style.css.js.map +1 -0
  146. package/x/demo/main.bundle.js +53 -5
  147. package/x/demo/main.bundle.js.map +1 -1
  148. package/x/demo/main.bundle.min.js +106 -395
  149. package/x/demo/main.bundle.min.js.LEGAL.txt +33 -0
  150. package/x/demo/main.bundle.min.js.map +4 -4
  151. package/x/demo/main.css +6 -8
  152. package/x/device/devices.d.ts +7 -0
  153. package/x/device/devices.js +17 -0
  154. package/x/device/devices.js.map +1 -0
  155. package/x/device/gamepad.d.ts +9 -0
  156. package/x/device/gamepad.js +37 -0
  157. package/x/device/gamepad.js.map +1 -0
  158. package/x/{core/devices/standard → device}/keyboard.d.ts +1 -1
  159. package/x/{core/devices/standard → device}/keyboard.js +4 -2
  160. package/x/device/keyboard.js.map +1 -0
  161. package/x/device/pad/on-pad.d.ts +3 -0
  162. package/x/device/pad/on-pad.js +42 -0
  163. package/x/device/pad/on-pad.js.map +1 -0
  164. package/x/device/pad/pad.d.ts +6 -0
  165. package/x/device/pad/pad.js +11 -0
  166. package/x/device/pad/pad.js.map +1 -0
  167. package/x/{core/devices/standard → device}/pointer.d.ts +2 -2
  168. package/x/{core/devices/standard → device}/pointer.js +4 -4
  169. package/x/device/pointer.js.map +1 -0
  170. package/x/device/sampler.d.ts +9 -0
  171. package/x/device/sampler.js +19 -0
  172. package/x/device/sampler.js.map +1 -0
  173. package/x/{core/devices/standard → device}/stick.d.ts +2 -3
  174. package/x/{core/devices/standard → device}/stick.js +4 -6
  175. package/x/device/stick.js.map +1 -0
  176. package/x/gamepad/gamepad-app/element.d.ts +1 -0
  177. package/x/gamepad/gamepad-app/element.js +54 -0
  178. package/x/gamepad/gamepad-app/element.js.map +1 -0
  179. package/x/gamepad/gamepad-app/style.css.js +72 -0
  180. package/x/gamepad/gamepad-app/style.css.js.map +1 -0
  181. package/x/gamepad/index.html +35 -0
  182. package/x/gamepad/index.html.d.ts +2 -0
  183. package/x/gamepad/index.html.js +41 -0
  184. package/x/gamepad/index.html.js.map +1 -0
  185. package/x/gamepad/main.bundle.js +4 -0
  186. package/x/gamepad/main.bundle.js.map +1 -0
  187. package/x/gamepad/main.bundle.min.js +126 -0
  188. package/x/gamepad/main.bundle.min.js.LEGAL.txt +33 -0
  189. package/x/gamepad/main.bundle.min.js.map +7 -0
  190. package/x/gamepad/main.css +60 -0
  191. package/x/index-ui.d.ts +1 -0
  192. package/x/index-ui.js +2 -0
  193. package/x/index-ui.js.map +1 -0
  194. package/x/index.d.ts +27 -5
  195. package/x/index.html +17 -24
  196. package/x/index.html.js +10 -17
  197. package/x/index.html.js.map +1 -1
  198. package/x/index.js +27 -5
  199. package/x/index.js.map +1 -1
  200. package/x/test.d.ts +9 -0
  201. package/x/test.js +307 -0
  202. package/x/test.js.map +1 -0
  203. package/x/ui/views/desk/style.css.js +69 -0
  204. package/x/ui/views/desk/style.css.js.map +1 -0
  205. package/x/ui/views/desk/view.d.ts +7 -0
  206. package/x/ui/views/desk/view.js +102 -0
  207. package/x/ui/views/desk/view.js.map +1 -0
  208. package/x/utils/circular-clamp.js +2 -2
  209. package/x/utils/circular-clamp.js.map +1 -1
  210. package/x/utils/do-async.d.ts +1 -0
  211. package/x/utils/do-async.js +4 -0
  212. package/x/utils/do-async.js.map +1 -0
  213. package/x/utils/freeze-clone.d.ts +1 -0
  214. package/x/utils/freeze-clone.js +5 -0
  215. package/x/utils/freeze-clone.js.map +1 -0
  216. package/x/utils/identifier.d.ts +6 -0
  217. package/x/utils/identifier.js +25 -0
  218. package/x/utils/identifier.js.map +1 -0
  219. package/x/utils/insert.d.ts +1 -0
  220. package/x/utils/insert.js +5 -0
  221. package/x/utils/insert.js.map +1 -0
  222. package/x/utils/is-down.d.ts +1 -0
  223. package/x/utils/is-down.js +4 -0
  224. package/x/utils/is-down.js.map +1 -0
  225. package/x/utils/make-id.d.ts +1 -0
  226. package/x/utils/make-id.js +5 -0
  227. package/x/utils/make-id.js.map +1 -0
  228. package/x/utils/remap.d.ts +1 -0
  229. package/x/utils/remap.js +6 -0
  230. package/x/utils/remap.js.map +1 -0
  231. package/x/utils/shift-limit.d.ts +2 -0
  232. package/x/utils/shift-limit.js +7 -0
  233. package/x/utils/shift-limit.js.map +1 -0
  234. package/x/utils/sort-by-key.d.ts +1 -0
  235. package/x/utils/sort-by-key.js +6 -0
  236. package/x/utils/sort-by-key.js.map +1 -0
  237. package/x/utils/{quick-math.d.ts → tmax.d.ts} +0 -1
  238. package/x/utils/tmax.js +6 -0
  239. package/x/utils/tmax.js.map +1 -0
  240. package/x/utils/tmin.d.ts +1 -0
  241. package/x/utils/tmin.js +6 -0
  242. package/x/utils/tmin.js.map +1 -0
  243. package/s/tests.test.ts +0 -6
  244. package/x/core/bindings/action.js +0 -24
  245. package/x/core/bindings/action.js.map +0 -1
  246. package/x/core/bindings/parts/defaults.js.map +0 -1
  247. package/x/core/bindings/parts/is-pressed.d.ts +0 -1
  248. package/x/core/bindings/parts/is-pressed.js +0 -4
  249. package/x/core/bindings/parts/is-pressed.js.map +0 -1
  250. package/x/core/bindings/parts/lens-algo.js.map +0 -1
  251. package/x/core/bindings/parts/lookup-proxies.js +0 -19
  252. package/x/core/bindings/parts/lookup-proxies.js.map +0 -1
  253. package/x/core/bindings/resolver.d.ts +0 -9
  254. package/x/core/bindings/resolver.js.map +0 -1
  255. package/x/core/bindings/sample-map.d.ts +0 -7
  256. package/x/core/bindings/sample-map.js.map +0 -1
  257. package/x/core/bindings/types.js +0 -4
  258. package/x/core/bindings/types.js.map +0 -1
  259. package/x/core/core.test.d.ts +0 -13
  260. package/x/core/core.test.js +0 -138
  261. package/x/core/core.test.js.map +0 -1
  262. package/x/core/devices/auto-gamepads.d.ts +0 -2
  263. package/x/core/devices/auto-gamepads.js +0 -6
  264. package/x/core/devices/auto-gamepads.js.map +0 -1
  265. package/x/core/devices/device.d.ts +0 -5
  266. package/x/core/devices/device.js +0 -7
  267. package/x/core/devices/device.js.map +0 -1
  268. package/x/core/devices/infra/group.d.ts +0 -7
  269. package/x/core/devices/infra/group.js +0 -21
  270. package/x/core/devices/infra/group.js.map +0 -1
  271. package/x/core/devices/infra/sampler.d.ts +0 -9
  272. package/x/core/devices/infra/sampler.js +0 -18
  273. package/x/core/devices/infra/sampler.js.map +0 -1
  274. package/x/core/devices/standard/gamepad.d.ts +0 -11
  275. package/x/core/devices/standard/gamepad.js +0 -65
  276. package/x/core/devices/standard/gamepad.js.map +0 -1
  277. package/x/core/devices/standard/index.d.ts +0 -6
  278. package/x/core/devices/standard/index.js +0 -7
  279. package/x/core/devices/standard/index.js.map +0 -1
  280. package/x/core/devices/standard/keyboard.js.map +0 -1
  281. package/x/core/devices/standard/pointer.js.map +0 -1
  282. package/x/core/devices/standard/primary.d.ts +0 -10
  283. package/x/core/devices/standard/primary.js +0 -17
  284. package/x/core/devices/standard/primary.js.map +0 -1
  285. package/x/core/devices/standard/stick.js.map +0 -1
  286. package/x/core/devices/standard/vpad.d.ts +0 -7
  287. package/x/core/devices/standard/vpad.js +0 -20
  288. package/x/core/devices/standard/vpad.js.map +0 -1
  289. package/x/core/devices/types.d.ts +0 -1
  290. package/x/core/hub/hub.d.ts +0 -32
  291. package/x/core/hub/hub.js +0 -101
  292. package/x/core/hub/hub.js.map +0 -1
  293. package/x/core/hub/meta-bindings.d.ts +0 -2
  294. package/x/core/hub/meta-bindings.js +0 -21
  295. package/x/core/hub/meta-bindings.js.map +0 -1
  296. package/x/core/hub/parts/connected.d.ts +0 -14
  297. package/x/core/hub/parts/connected.js +0 -12
  298. package/x/core/hub/parts/connected.js.map +0 -1
  299. package/x/core/hub/port.d.ts +0 -9
  300. package/x/core/hub/port.js +0 -19
  301. package/x/core/hub/port.js.map +0 -1
  302. package/x/core/hub/types.d.ts +0 -9
  303. package/x/core/hub/types.js +0 -2
  304. package/x/core/hub/types.js.map +0 -1
  305. package/x/core/index.d.ts +0 -15
  306. package/x/core/index.js +0 -16
  307. package/x/core/index.js.map +0 -1
  308. package/x/core/testing/testing.d.ts +0 -52
  309. package/x/core/testing/testing.js +0 -45
  310. package/x/core/testing/testing.js.map +0 -1
  311. package/x/deck/index.d.ts +0 -9
  312. package/x/deck/index.js +0 -10
  313. package/x/deck/index.js.map +0 -1
  314. package/x/deck/parts/catalog.d.ts +0 -22
  315. package/x/deck/parts/catalog.js +0 -35
  316. package/x/deck/parts/catalog.js.map +0 -1
  317. package/x/deck/parts/db.d.ts +0 -17
  318. package/x/deck/parts/db.js +0 -52
  319. package/x/deck/parts/db.js.map +0 -1
  320. package/x/deck/parts/device-skins/device-icons.d.ts +0 -12
  321. package/x/deck/parts/device-skins/device-icons.js +0 -27
  322. package/x/deck/parts/device-skins/device-icons.js.map +0 -1
  323. package/x/deck/parts/device-skins/device-skin.d.ts +0 -14
  324. package/x/deck/parts/device-skins/device-skin.js +0 -22
  325. package/x/deck/parts/device-skins/device-skin.js.map +0 -1
  326. package/x/deck/parts/local-storage-kv.d.ts +0 -2
  327. package/x/deck/parts/local-storage-kv.js +0 -6
  328. package/x/deck/parts/local-storage-kv.js.map +0 -1
  329. package/x/deck/parts/merge-bindings.d.ts +0 -2
  330. package/x/deck/parts/merge-bindings.js +0 -15
  331. package/x/deck/parts/merge-bindings.js.map +0 -1
  332. package/x/deck/parts/overlay-visibility.d.ts +0 -18
  333. package/x/deck/parts/overlay-visibility.js +0 -35
  334. package/x/deck/parts/overlay-visibility.js.map +0 -1
  335. package/x/deck/views/bindings/style.css.js +0 -5
  336. package/x/deck/views/bindings/style.css.js.map +0 -1
  337. package/x/deck/views/bindings/view.d.ts +0 -2
  338. package/x/deck/views/bindings/view.js +0 -80
  339. package/x/deck/views/bindings/view.js.map +0 -1
  340. package/x/deck/views/overlay/style.css.js +0 -109
  341. package/x/deck/views/overlay/style.css.js.map +0 -1
  342. package/x/deck/views/overlay/view.d.ts +0 -2
  343. package/x/deck/views/overlay/view.js +0 -40
  344. package/x/deck/views/overlay/view.js.map +0 -1
  345. package/x/demo/game/game.d.ts +0 -17
  346. package/x/demo/game/game.js +0 -63
  347. package/x/demo/game/game.js.map +0 -1
  348. package/x/demo/game/parts/agent.d.ts +0 -7
  349. package/x/demo/game/parts/agent.js +0 -8
  350. package/x/demo/game/parts/agent.js.map +0 -1
  351. package/x/demo/game/parts/game-bindings.d.ts +0 -15
  352. package/x/demo/game/parts/game-bindings.js +0 -10
  353. package/x/demo/game/parts/game-bindings.js.map +0 -1
  354. package/x/demo/game/parts/logic.d.ts +0 -8
  355. package/x/demo/game/parts/logic.js +0 -21
  356. package/x/demo/game/parts/logic.js.map +0 -1
  357. package/x/demo/game/parts/player.d.ts +0 -14
  358. package/x/demo/game/parts/player.js +0 -26
  359. package/x/demo/game/parts/player.js.map +0 -1
  360. package/x/demo/game/parts/renderer.d.ts +0 -13
  361. package/x/demo/game/parts/renderer.js +0 -91
  362. package/x/demo/game/parts/renderer.js.map +0 -1
  363. package/x/demo/game/parts/state.d.ts +0 -8
  364. package/x/demo/game/parts/state.js +0 -20
  365. package/x/demo/game/parts/state.js.map +0 -1
  366. package/x/demo/game/parts/virtual-device.d.ts +0 -8
  367. package/x/demo/game/parts/virtual-device.js +0 -11
  368. package/x/demo/game/parts/virtual-device.js.map +0 -1
  369. package/x/demo/ui/theater/styles.css.d.ts +0 -1
  370. package/x/demo/ui/theater/styles.css.js +0 -57
  371. package/x/demo/ui/theater/styles.css.js.map +0 -1
  372. package/x/demo/ui/theater/view.d.ts +0 -2
  373. package/x/demo/ui/theater/view.js +0 -45
  374. package/x/demo/ui/theater/view.js.map +0 -1
  375. package/x/demo/ui/theater/virtual/style.css.js +0 -42
  376. package/x/demo/ui/theater/virtual/style.css.js.map +0 -1
  377. package/x/demo/ui/theater/virtual/view.d.ts +0 -4
  378. package/x/demo/ui/theater/virtual/view.js +0 -19
  379. package/x/demo/ui/theater/virtual/view.js.map +0 -1
  380. package/x/demo/ui/utils/loader.d.ts +0 -2
  381. package/x/demo/ui/utils/loader.js +0 -3
  382. package/x/demo/ui/utils/loader.js.map +0 -1
  383. package/x/nubs/index.d.ts +0 -3
  384. package/x/nubs/index.js +0 -4
  385. package/x/nubs/index.js.map +0 -1
  386. package/x/nubs/lookpad/styles.d.ts +0 -1
  387. package/x/nubs/lookpad/styles.js +0 -21
  388. package/x/nubs/lookpad/styles.js.map +0 -1
  389. package/x/nubs/lookpad/view.d.ts +0 -1
  390. package/x/nubs/lookpad/view.js +0 -33
  391. package/x/nubs/lookpad/view.js.map +0 -1
  392. package/x/nubs/stick/style.css.d.ts +0 -2
  393. package/x/nubs/stick/style.css.js +0 -69
  394. package/x/nubs/stick/style.css.js.map +0 -1
  395. package/x/nubs/stick/view.d.ts +0 -2
  396. package/x/nubs/stick/view.js +0 -95
  397. package/x/nubs/stick/view.js.map +0 -1
  398. package/x/nubs/vpad/styles.css.d.ts +0 -2
  399. package/x/nubs/vpad/styles.css.js +0 -133
  400. package/x/nubs/vpad/styles.css.js.map +0 -1
  401. package/x/nubs/vpad/utils/gamepad-inputs.d.ts +0 -29
  402. package/x/nubs/vpad/utils/gamepad-inputs.js +0 -31
  403. package/x/nubs/vpad/utils/gamepad-inputs.js.map +0 -1
  404. package/x/nubs/vpad/utils/prevent-default-touch-shenanigans.d.ts +0 -1
  405. package/x/nubs/vpad/utils/prevent-default-touch-shenanigans.js +0 -9
  406. package/x/nubs/vpad/utils/prevent-default-touch-shenanigans.js.map +0 -1
  407. package/x/nubs/vpad/utils/touch-tracking.d.ts +0 -6
  408. package/x/nubs/vpad/utils/touch-tracking.js +0 -55
  409. package/x/nubs/vpad/utils/touch-tracking.js.map +0 -1
  410. package/x/nubs/vpad/view.d.ts +0 -2
  411. package/x/nubs/vpad/view.js +0 -123
  412. package/x/nubs/vpad/view.js.map +0 -1
  413. package/x/tests.test.d.ts +0 -1
  414. package/x/tests.test.js +0 -4
  415. package/x/tests.test.js.map +0 -1
  416. package/x/utils/dispensers.d.ts +0 -7
  417. package/x/utils/dispensers.js +0 -16
  418. package/x/utils/dispensers.js.map +0 -1
  419. package/x/utils/gamepads.d.ts +0 -14
  420. package/x/utils/gamepads.js +0 -40
  421. package/x/utils/gamepads.js.map +0 -1
  422. package/x/utils/quick-math.js +0 -11
  423. package/x/utils/quick-math.js.map +0 -1
  424. /package/s/{core → _archive/core}/bindings/action.ts +0 -0
  425. /package/s/{core → _archive/core}/bindings/parts/defaults.ts +0 -0
  426. /package/s/{core → _archive/core}/bindings/parts/is-pressed.ts +0 -0
  427. /package/s/{core → _archive/core}/bindings/parts/lens-algo.ts +0 -0
  428. /package/s/{core → _archive/core}/bindings/parts/lookup-proxies.ts +0 -0
  429. /package/s/{core → _archive/core}/bindings/resolver.ts +0 -0
  430. /package/s/{core → _archive/core}/bindings/sample-map.ts +0 -0
  431. /package/s/{core → _archive/core}/bindings/types.ts +0 -0
  432. /package/s/{core → _archive/core}/core.test.ts +0 -0
  433. /package/s/{core → _archive/core}/devices/auto-gamepads.ts +0 -0
  434. /package/s/{core → _archive/core}/devices/device.ts +0 -0
  435. /package/s/{core → _archive/core}/devices/infra/group.ts +0 -0
  436. /package/s/{core → _archive/core}/devices/infra/sampler.ts +0 -0
  437. /package/s/{core → _archive/core}/devices/standard/gamepad.ts +0 -0
  438. /package/s/{core → _archive/core}/devices/standard/index.ts +0 -0
  439. /package/s/{core → _archive/core}/devices/standard/keyboard.ts +0 -0
  440. /package/s/{core → _archive/core}/devices/standard/pointer.ts +0 -0
  441. /package/s/{core → _archive/core}/devices/standard/primary.ts +0 -0
  442. /package/s/{core → _archive/core}/devices/standard/stick.ts +0 -0
  443. /package/s/{core → _archive/core}/devices/standard/vpad.ts +0 -0
  444. /package/s/{core → _archive/core}/devices/types.ts +0 -0
  445. /package/s/{core → _archive/core}/hub/hub.ts +0 -0
  446. /package/s/{core → _archive/core}/hub/meta-bindings.ts +0 -0
  447. /package/s/{core → _archive/core}/hub/parts/connected.ts +0 -0
  448. /package/s/{core → _archive/core}/hub/port.ts +0 -0
  449. /package/s/{core → _archive/core}/hub/types.ts +0 -0
  450. /package/s/{core → _archive/core}/index.ts +0 -0
  451. /package/s/{core → _archive/core}/testing/testing.ts +0 -0
  452. /package/s/{deck → _archive/deck}/index.ts +0 -0
  453. /package/s/{deck → _archive/deck}/parts/catalog.ts +0 -0
  454. /package/s/{deck → _archive/deck}/parts/db.ts +0 -0
  455. /package/s/{deck → _archive/deck}/parts/device-skins/device-icons.ts +0 -0
  456. /package/s/{deck → _archive/deck}/parts/device-skins/device-skin.ts +0 -0
  457. /package/s/{deck → _archive/deck}/parts/local-storage-kv.ts +0 -0
  458. /package/s/{deck → _archive/deck}/parts/merge-bindings.ts +0 -0
  459. /package/s/{deck → _archive/deck}/parts/overlay-visibility.ts +0 -0
  460. /package/s/{deck → _archive/deck}/views/bindings/style.css.ts +0 -0
  461. /package/s/{deck → _archive/deck}/views/bindings/view.ts +0 -0
  462. /package/s/{deck → _archive/deck}/views/overlay/style.css.ts +0 -0
  463. /package/s/{deck → _archive/deck}/views/overlay/view.ts +0 -0
  464. /package/s/{demo → _archive/demo}/game/game.ts +0 -0
  465. /package/s/{demo → _archive/demo}/game/parts/agent.ts +0 -0
  466. /package/s/{demo → _archive/demo}/game/parts/game-bindings.ts +0 -0
  467. /package/s/{demo → _archive/demo}/game/parts/logic.ts +0 -0
  468. /package/s/{demo → _archive/demo}/game/parts/player.ts +0 -0
  469. /package/s/{demo → _archive/demo}/game/parts/renderer.ts +0 -0
  470. /package/s/{demo → _archive/demo}/game/parts/state.ts +0 -0
  471. /package/s/{demo → _archive/demo}/game/parts/virtual-device.ts +0 -0
  472. /package/s/{demo → _archive/demo}/ui/theater/styles.css.ts +0 -0
  473. /package/s/{demo → _archive/demo}/ui/theater/view.ts +0 -0
  474. /package/s/{demo → _archive/demo}/ui/theater/virtual/style.css.ts +0 -0
  475. /package/s/{demo → _archive/demo}/ui/theater/virtual/view.ts +0 -0
  476. /package/s/{demo → _archive/demo}/ui/utils/loader.ts +0 -0
  477. /package/s/{nubs → _archive/nubs}/index.ts +0 -0
  478. /package/s/{nubs → _archive/nubs}/lookpad/styles.ts +0 -0
  479. /package/s/{nubs → _archive/nubs}/lookpad/view.ts +0 -0
  480. /package/s/{nubs → _archive/nubs}/stick/style.css.ts +0 -0
  481. /package/s/{nubs → _archive/nubs}/stick/view.ts +0 -0
  482. /package/s/{nubs → _archive/nubs}/vpad/styles.css.ts +0 -0
  483. /package/s/{nubs → _archive/nubs}/vpad/utils/gamepad-inputs.ts +0 -0
  484. /package/s/{nubs → _archive/nubs}/vpad/utils/prevent-default-touch-shenanigans.ts +0 -0
  485. /package/s/{nubs → _archive/nubs}/vpad/utils/touch-tracking.ts +0 -0
  486. /package/s/{nubs → _archive/nubs}/vpad/view.ts +0 -0
  487. /package/s/{utils → _archive/utils}/dispensers.ts +0 -0
  488. /package/s/{utils → _archive/utils}/gamepads.ts +0 -0
  489. /package/s/{utils → _archive/utils}/quick-math.ts +0 -0
  490. /package/x/core/{bindings/parts → atom}/defaults.js +0 -0
  491. /package/x/core/{devices → atom}/types.js +0 -0
  492. /package/x/{deck/views/bindings → demo/demo-app}/style.css.d.ts +0 -0
  493. /package/x/{deck/views/overlay → gamepad/gamepad-app}/style.css.d.ts +0 -0
  494. /package/x/{core/bindings/parts/lookup-proxies.d.ts → gamepad/main.bundle.d.ts} +0 -0
  495. /package/x/{demo/ui/theater/virtual → ui/views/desk}/style.css.d.ts +0 -0
@@ -0,0 +1,435 @@
1
+
2
+ # 🎮 @benev/tact
3
+ > *web game input library, from keypress to couch co-op*
4
+
5
+ ```ts
6
+ npm install @benev/tact
7
+ ```
8
+
9
+ tact is a toolkit for handling user inputs on the web.
10
+ it's good at user-customizable keybindings, multiple gamepad support, and mobile ui.
11
+
12
+ - 🛹 **[#deck](#deck)** full setup with localstorage persistence
13
+ - 🎮 **[#devices](#devices)** produce user input samples
14
+ - 🧩 **[#bindings](#bindings)** describe how actions interpret samples
15
+ - 🔌 **[#port](#port)** updates actions by interpreting samples
16
+ - 🛞 **[#hub](#hub)** plugs devices into ports (multi-gamepad couch co-op!)
17
+ - 📱 **[#nubs](#nubs)** is mobile ui virtual gamepad stuff
18
+
19
+
20
+ <br/><br/>
21
+ <a id="deck"></a>
22
+
23
+ ## 🍋 tact deck
24
+ > *full setup with ui, batteries included*
25
+
26
+ the deck ties together all the important pieces of tact into a single user experience, complete with ui views.
27
+
28
+ tact's ui is built with [`@e280/sly` shadow views](https://github.com/e280/sly).
29
+
30
+ ### 🛹 deck setup
31
+ - **import stuff from tact**
32
+ ```ts
33
+ import * as tact from "@benev/tact"
34
+ ```
35
+ - **setup your deck, and your game's bindings**
36
+ ```ts
37
+ const deck = await tact.Deck.load({
38
+
39
+ // how many player ports are possible? 1 is fine..
40
+ portCount: 4,
41
+
42
+ // where to store the user-customized bindings
43
+ kv: tact.localStorageKv(),
44
+
45
+ // default archetypal bindings for your game
46
+ bindings: {
47
+ walking: {forward: "KeyW", jump: "Space"},
48
+ gunning: {
49
+ shoot: ["or", "pointer.button.left", "gamepad.trigger.right"],
50
+ },
51
+ },
52
+ })
53
+ ```
54
+
55
+ ### 🛹 plug devices into the hub
56
+ - **plug a keyboard/mouse player into the hub**
57
+ ```ts
58
+ deck.hub.plug(new tact.PrimaryDevice())
59
+ ```
60
+ - **automatically detect and plug gamepads**
61
+ ```ts
62
+ tact.autoGamepads(deck.hub.plug)
63
+ ```
64
+
65
+ ### 🛹 do your gameplay
66
+ - **poll the deck, interrogate actions**
67
+ ```ts
68
+ myGameLoop(() => {
69
+
70
+ // do your polling
71
+ const [p1, p2, p3, p4] = deck.hub.poll()
72
+
73
+ // check if the first player is pressing "forward" action
74
+ p1.actions.walking.forward.pressed // true
75
+
76
+ // check how hard the second player is pulling that trigger
77
+ p2.actions.gunning.shoot.value // 0.123
78
+ })
79
+ ```
80
+
81
+ ### 🛹 deck ui: the overlay
82
+ - **render the deck overlay with sly**
83
+ ```ts
84
+ import {dom} from "@e280/sly"
85
+
86
+ dom.render(
87
+ dom("#game-ui"),
88
+ tact.DeckOverlay(deck),
89
+ )
90
+ ```
91
+ - **place the ui on top of your game canvas**
92
+ ```html
93
+ <div id="game-ui"></div>
94
+ ```
95
+
96
+
97
+
98
+ <br/><br/>
99
+ <a id="devices"></a>
100
+
101
+ ## 🍋 tact devices
102
+ > *sources of user input "samples"*
103
+
104
+ ### 🎮 polling is good, actually
105
+ - tact operates on the basis of *polling*
106
+ - *"but polling is bad"* says you — but no — you're wrong — polling is unironically *based,* and you *should* do it
107
+ - the gift of polling is total control over *when* inputs are processed, this is good for games
108
+ - i will elaborate no further 🗿
109
+
110
+ ### 🎮 basically how a device works
111
+ - make a device
112
+ ```ts
113
+ const keyboard = new tact.KeyboardDevice()
114
+ ```
115
+ - reading samples looks like this
116
+ ```ts
117
+ for (const sample of keyboard.samples())
118
+ console.log(sample) // ["KeyA", 1]
119
+ ```
120
+ - some devices have disposers to call when you're done with them
121
+ ```ts
122
+ keyboard.dispose()
123
+ ```
124
+
125
+ ### 🎮 samples explained
126
+ - a sample is a raw input tuple of type `[code: string, value: number]`
127
+ - a sample has a `code` string
128
+ - it's either a [standard keycode](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values), like `KeyA`
129
+ - or it's something we made up, like `pointer.button.left` or `gamepad.trigger.right`
130
+ - a sample has a `value` number
131
+ - `0` means *"nothing is going on"*
132
+ - `1` means *"pressed"*
133
+ - we don't like negative numbers
134
+ - values between `0` and `1`, like `0.123`, are how triggers and thumbsticks express themselves
135
+ - sometimes we use numbers greater then `1`, like for dots of pointer movement like in `pointer.move.up`
136
+ - don't worry about sensitivity, deadzones, values like `0.00001` — actions will account for all that using bindings later on
137
+
138
+ ### 🎮 sample code reference
139
+ - **KeyboardDevice**
140
+ - any [standard keycode](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values)
141
+ - `KeyA`
142
+ - `Space`
143
+ - `Digit2`
144
+ - etc
145
+ - **PointerDevice**
146
+ - mouse buttons
147
+ - `pointer.button.left`
148
+ - `pointer.button.right`
149
+ - `pointer.button.middle`
150
+ - `pointer.button.4`
151
+ - `pointer.button.5`
152
+ - mouse wheel
153
+ - `pointer.wheel.up`
154
+ - `pointer.wheel.down`
155
+ - `pointer.wheel.left`
156
+ - `pointer.wheel.right`
157
+ - mouse movements
158
+ - `pointer.move.up`
159
+ - `pointer.move.down`
160
+ - `pointer.move.left`
161
+ - `pointer.move.right`
162
+ - **GamepadDevice**
163
+ - gamepad buttons
164
+ - `gamepad.a`
165
+ - `gamepad.b`
166
+ - `gamepad.x`
167
+ - `gamepad.y`
168
+ - `gamepad.bumper.left`
169
+ - `gamepad.bumper.right`
170
+ - `gamepad.trigger.left`
171
+ - `gamepad.trigger.right`
172
+ - `gamepad.alpha`
173
+ - `gamepad.beta`
174
+ - `gamepad.stick.left.click`
175
+ - `gamepad.stick.right.click`
176
+ - `gamepad.up`
177
+ - `gamepad.down`
178
+ - `gamepad.left`
179
+ - `gamepad.right`
180
+ - `gamepad.gamma`
181
+ - gamepad sticks
182
+ - `gamepad.stick.left.up`
183
+ - `gamepad.stick.left.down`
184
+ - `gamepad.stick.left.left`
185
+ - `gamepad.stick.left.right`
186
+ - `gamepad.stick.right.up`
187
+ - `gamepad.stick.right.down`
188
+ - `gamepad.stick.right.left`
189
+ - `gamepad.stick.right.right`
190
+
191
+
192
+
193
+ <br/><br/>
194
+ <a id="bindings"></a>
195
+
196
+ ## 🍋 tact bindings
197
+ > *keybindings! they describe how actions interpret samples*
198
+
199
+ ### 🧩 bindings example
200
+ - **let's start with a small example:**
201
+ ```ts
202
+ const bindings = tact.asBindings({
203
+ walking: {forward: "KeyW", jump: "Space"},
204
+ gunning: {
205
+ shoot: ["or", "pointer.button.left", "gamepad.trigger.right"],
206
+ },
207
+ })
208
+ ```
209
+ - `walking` and `gunning` are **modes**
210
+ - `forward`, `jump`, and `shoot` are **actions**
211
+ - note that whole modes can be enabled or disabled during gameplay
212
+
213
+ ### 🧩 bindings are a lispy domain-specific-language
214
+ - **you can do complex stuff**
215
+ ```ts
216
+ ["or",
217
+ "KeyQ",
218
+ ["and",
219
+ "KeyA",
220
+ "KeyD",
221
+ ["not", "KeyS"],
222
+ ],
223
+ ]
224
+ ```
225
+ - press Q, or
226
+ - press A + D, while not pressing S
227
+ - **you can get really weird**
228
+ ```ts
229
+ ["cond",
230
+ ["code", "gamepad.trigger.right", {range: [0, 0.5], timing: ["tap"]}],
231
+ ["and", "gamepad.bumper.left", ["not", "gamepad.trigger.left"]],
232
+ ]
233
+ ```
234
+ - hold LB and tap RT halfway while not holding LT
235
+
236
+ ### 🧩 bindings atom reference
237
+ - **string** — strings are interpreted as "code" atoms with default settings
238
+ - **"code"** — allows you to customize the settings
239
+ ```ts
240
+ ["code", "KeyA", {
241
+ scale: 1,
242
+ invert: false,
243
+ timing: ["direct"],
244
+ }]
245
+ ```
246
+ - defaults shown
247
+ - `scale` is sensitivity, the value gets multiplied by this
248
+ - `invert` will invert a value by subtracting it from 1
249
+ - `clamp` clamps the value with a lower and upper bound
250
+ - `range` restricts value to the given range, and remaps that range 0 to 1
251
+ - `bottom` zeroes the value if it's less than the given bottom value
252
+ - `top` clamps the value to an upper bound
253
+ - `timing` lets you specify special timing considerations
254
+ - `["direct"]` ignores timing considerations
255
+ - `["tap", 250]` only fires for taps under 250ms
256
+ - `["hold", 250]` only fires for holds over 250ms
257
+ - **"or"** — resolves to the maximum value
258
+ ```ts
259
+ ["or", "KeyA", "KeyB", "KeyC"]
260
+ ```
261
+ - **"and"** — resolves to the minimum value
262
+ ```ts
263
+ ["and", "KeyA", "KeyB", "KeyC"]
264
+ ```
265
+ - **"not"** — resolves to the opposite effect
266
+ ```ts
267
+ ["not", "KeyA"]
268
+ ```
269
+ - **"cond"** — conditional situation (example for modifiers shown)
270
+ ```ts
271
+ ["cond", "KeyA", ["and",
272
+ ["or", "ControlLeft", "ControlRight"],
273
+ ["not", ["or", "AltLeft", "AltRight"]],
274
+ ["not", ["or", "MetaLeft", "MetaRight"]],
275
+ ["not", ["or", "ShiftLeft", "ShiftRight"]],
276
+ ]]
277
+ ```
278
+ - KeyA is the value that gets used
279
+ - but only if the following condition passes
280
+ - **"mods"** — macro for modifiers
281
+ ```ts
282
+ ["mods", "KeyA", {ctrl: true}]
283
+ ```
284
+ - equivalent to the "cond" example above
285
+ - `ctrl`, `alt`, `meta`, `shift` are available
286
+
287
+
288
+
289
+ <br/><br/>
290
+ <a id="port"></a>
291
+
292
+ ## 🍋 tact port
293
+ > *polling gives you "actions"*
294
+
295
+ a port represents a single playable port, and you poll it each frame to resolve actions for you to read.
296
+
297
+ ### 🔌 port setup
298
+ - **make a port**
299
+ ```ts
300
+ const port = new tact.Port(bindings)
301
+ ```
302
+ - **attach some devices to the port**
303
+ ```ts
304
+ port.devices
305
+ .add(new tact.KeyboardDevice())
306
+ .add(new tact.PointerDevice())
307
+ .add(new tact.VpadDevice())
308
+ ```
309
+ - you can add/delete devices from the set any time
310
+ - **manipulate modes**
311
+ ```ts
312
+ port.modes.clear()
313
+ port.modes.add("walking")
314
+ ```
315
+ - actions only happen for enabled modes
316
+ - you can toggle modes on and off by adding/deleting them from the modes set
317
+ - **you can update the bindings any time**
318
+ ```ts
319
+ port.bindings = freshBindings
320
+ ```
321
+ - **wire up gamepad auto connect/disconnect**
322
+ ```ts
323
+ tact.autoGamepads(device => {
324
+ port.devices.add(device)
325
+ return () => port.devices.delete(device)
326
+ })
327
+ ```
328
+
329
+ ### 🔌 interrogating actions
330
+ - **poll the port every frame**
331
+ ```ts
332
+ port.resolve()
333
+ ```
334
+ - **now you can inspect the `actions`**
335
+ ```ts
336
+ port.actions.walking.forward.value // 1
337
+ ```
338
+ - `walking` is a `mode`
339
+ - `forward` is an `action`
340
+ - `action.value` — current value
341
+ - `action.previous` — last frame's value
342
+ - `action.changed` — true if value and previous are different
343
+ - `action.pressed` — true if the value > 0
344
+ - `action.down` — true for one frame when the key goes from up to down
345
+ - `action.up` — true for one frame when the key goes from down to up
346
+
347
+
348
+
349
+ <br/><br/>
350
+ <a id="hub"></a>
351
+
352
+ ## 🍋 tact hub
353
+ > *multiple gamepads! couch co-op is so back*
354
+
355
+ you know the way old-timey game consoles had four controller ports on the front?
356
+
357
+ the hub embraces that analogy, helping you coordinate the plugging and unplugging of virtual controller devices into its virtual ports.
358
+
359
+ ### 🛞 create a hub with ports
360
+ - **make hub with multiple ports at the ready**
361
+ ```ts
362
+ const hub = new tact.Hub([
363
+ new tact.Port(bindings),
364
+ new tact.Port(bindings),
365
+ new tact.Port(bindings),
366
+ new tact.Port(bindings),
367
+ ])
368
+ ```
369
+ - yes that's right — each player port gets its own bindings 🤯
370
+
371
+ ### 🛞 plug in some devices
372
+ - **let's plug in the keyboard/mouse player**
373
+ ```ts
374
+ hub.plug(new tact.PrimaryDevice())
375
+ ```
376
+ - the hub requires a single device to represent a player, so you can use a `GroupDevice` to combine multple devices into one
377
+ - **wire up gamepad auto connect/disconnect**
378
+ ```ts
379
+ tact.autoGamepads(hub.plug)
380
+ ```
381
+
382
+ ### 🛞 now we're gaming
383
+ - **do your polling, interrogate those actions**
384
+ ```ts
385
+ const [p1, p2, p3, p4] = hub.poll()
386
+
387
+ p1.actions.walking.jump.value // 1
388
+ p2.actions.walking.jump.value // 0
389
+ ```
390
+
391
+
392
+
393
+ <br/><br/>
394
+ <a id="nubs"></a>
395
+
396
+ ## 🍋 tact nubs
397
+ > *mobile ui like virtual thumbsticks and buttons*
398
+
399
+ ### 📱 nubs setup
400
+ - **render nub views with sly**
401
+ ```ts
402
+ import {dom} from "@e280/sly"
403
+
404
+ const stick = new tact.StickDevice()
405
+
406
+ dom.render(
407
+ dom("#controls"),
408
+ tact.NubStick(stick),
409
+ )
410
+ ```
411
+
412
+ ### 📱 nub stick
413
+ - **place a mount point onto your page**
414
+ ```html
415
+ <div id="controls"></div>
416
+ ```
417
+ - **make the stick device yourself, then plug it into your hub or whatever**
418
+ ```ts
419
+ const stick = new tact.StickDevice()
420
+
421
+ dom.render(
422
+ dom("#controls"),
423
+ tact.NubStick(stick),
424
+ )
425
+
426
+ deck.hub.plug(stick)
427
+ ```
428
+
429
+
430
+
431
+ <br/><br/>
432
+ <a id="benev"></a>
433
+
434
+ ## 🍋 tact is by https://benevolent.games/
435
+ > *building the future of web games*
@@ -0,0 +1,69 @@
1
+
2
+ import {Kv} from "@e280/kv"
3
+ import {disposer, range} from "@e280/stz"
4
+
5
+ import {Db} from "./parts/db.js"
6
+ import {Hub} from "../core/hub/hub.js"
7
+ import {Port} from "../core/hub/port.js"
8
+ import {Bindings} from "../core/bindings/types.js"
9
+ import {mergeBindings} from "./parts/merge-bindings.js"
10
+ import {MetaBindings, metaMode} from "../core/hub/types.js"
11
+ import {makeMetaBindings} from "../core/hub/meta-bindings.js"
12
+ import {DeviceSkins} from "./parts/device-skins/device-skin.js"
13
+ import {OverlayVisibility} from "./parts/overlay-visibility.js"
14
+ import {PrimaryDevice} from "../core/devices/standard/primary.js"
15
+
16
+ export type DeckOptions<B extends Bindings, MB extends MetaBindings = any> = {
17
+ kv: Kv
18
+ bindings: B
19
+ portCount: number
20
+ metaBindings?: MB
21
+ }
22
+
23
+ export class Deck<B extends Bindings, MB extends MetaBindings = any> {
24
+ static async load<B extends Bindings, MB extends MetaBindings = any>(options: DeckOptions<B, MB>) {
25
+ const db = await Db.load(options.kv.store("catalog"))
26
+
27
+ const ports = range(options.portCount)
28
+ .map(index => db.$catalog().getProfileForPort(index))
29
+ .map(profile => mergeBindings(options.bindings, profile?.bindings))
30
+ .map(bindings => new Port<B>(bindings as B))
31
+
32
+ const hub = new Hub<B>(
33
+ ports,
34
+ db.$catalog().metaBindings
35
+ ?? options.metaBindings
36
+ ?? makeMetaBindings(),
37
+ )
38
+
39
+ return new this(options.bindings, options.metaBindings, hub, db)
40
+ }
41
+
42
+ dispose = disposer()
43
+ deviceSkins = new DeviceSkins()
44
+ primaryDevice = new PrimaryDevice()
45
+ overlayVisibility: OverlayVisibility
46
+
47
+ constructor(
48
+ public baseBindings: B,
49
+ public baseMetaBindings: MB,
50
+ public hub: Hub<B, MB>,
51
+ public db: Db,
52
+ ) {
53
+
54
+ this.overlayVisibility = new OverlayVisibility(hub, this.deviceSkins)
55
+
56
+ // meta reveal overlay
57
+ this.dispose.schedule(
58
+ hub.metaPort.actions[metaMode].revealOverlay.on(action => {
59
+ if (action.pressed)
60
+ this.overlayVisibility.bump()
61
+ })
62
+ )
63
+ }
64
+
65
+ get catalog() {
66
+ return this.db.$catalog()
67
+ }
68
+ }
69
+
@@ -0,0 +1,10 @@
1
+
2
+ import {dom} from "@e280/sly"
3
+ import {Game} from "./game/game.js"
4
+ import {DemoTheater} from "./ui/theater/view.js"
5
+
6
+ const game = await Game.load()
7
+
8
+ dom.render(dom("#demo-theater"), DemoTheater(game))
9
+
10
+ console.log("🎮 tact")
@@ -0,0 +1,85 @@
1
+
2
+ @layer vars, core, basics, page;
3
+
4
+ @layer vars {
5
+ :root {
6
+ color-scheme: dark;
7
+ --link: cyan;
8
+ --prime: #ccc;
9
+ --bg: #181818;
10
+ --bg2: #111111;
11
+ }
12
+ }
13
+
14
+ @layer core {
15
+ * {
16
+ padding: 0;
17
+ margin: 0;
18
+ box-sizing: border-box;
19
+ }
20
+
21
+ ::-webkit-scrollbar { width: 4px; }
22
+ ::-webkit-scrollbar-track { background: transparent; }
23
+ ::-webkit-scrollbar-thumb { background: #333; border-radius: 1em; }
24
+ ::-webkit-scrollbar-thumb:hover { background: #444; }
25
+
26
+ a {
27
+ color: var(--link);
28
+ text-decoration: none;
29
+
30
+ &:visited {
31
+ color: color-mix(in srgb, var(--link), purple 30%);
32
+ }
33
+
34
+ &:hover {
35
+ color: color-mix(in srgb, var(--link), white 10%);
36
+ text-decoration: underline;
37
+ }
38
+
39
+ &:active {
40
+ color: color-mix(in srgb, var(--link), white 50%);
41
+ }
42
+ }
43
+ }
44
+
45
+ @layer basics {
46
+ html { height: 100%; }
47
+ body { min-height: 100%; }
48
+
49
+ html, body {
50
+ font-family: sans-serif;
51
+ font-size: 12px;
52
+ color: var(--prime);
53
+ background: var(--bg);
54
+ }
55
+ }
56
+
57
+ @layer page {
58
+ body {
59
+ display: flex;
60
+ flex-direction: column;
61
+ align-items: center;
62
+
63
+ gap: 1em;
64
+ padding: 2em;
65
+
66
+ > * {
67
+ width: 100%;
68
+ max-width: 42em;
69
+ }
70
+
71
+ > header {
72
+ padding: 0 2em;
73
+ h1 small { font-size: 0.6em; font-weight: normal; }
74
+ * + * { margin-top: 0.5em; }
75
+ }
76
+
77
+ > section {
78
+ padding: 0 2em;
79
+ ul {
80
+ padding-left: 1em;
81
+ }
82
+ }
83
+ }
84
+ }
85
+
@@ -0,0 +1,61 @@
1
+
2
+ import {template, html, dataSvgEmoji, socialCard} from "@e280/scute"
3
+
4
+ const title = "@benev/tact"
5
+ const domain = "tact.benevolent.games"
6
+ const favicon = "/assets/b.png"
7
+ const description = "keybindings and gamepad support for web games"
8
+
9
+ export default template(import.meta.url, async orb => html`
10
+ <!doctype html>
11
+ <html>
12
+ <head>
13
+ <title>${title}</title>
14
+
15
+ <meta charset="utf-8"/>
16
+ <meta name="viewport" content="width=device-width,initial-scale=1"/>
17
+ <meta name="darkreader-lock"/>
18
+ <style>@layer base{html{background:#000}}</style>
19
+
20
+ <link rel="icon" href="${dataSvgEmoji("🎮")}"/>
21
+ <link rel="stylesheet" href="${orb.hashurl("demo/main.css")}"/>
22
+ <script type="module" src="${orb.hashurl("demo/main.bundle.min.js")}"></script>
23
+
24
+ ${socialCard({
25
+ title,
26
+ description,
27
+ themeColor: "#f2ea8e",
28
+ siteName: domain,
29
+ image: `https://${domain}${favicon}`,
30
+ })}
31
+ </head>
32
+ <body>
33
+ <header>
34
+ <h1>
35
+ <strong>@benev/tact</strong>
36
+ <small>v${orb.packageVersion()}</small>
37
+ </h1>
38
+ <div class=deets>
39
+ <p><em>"from keypress to couch co-op"</em></p>
40
+ <p>
41
+ tact is a user input toolkit for the web. it's good at customizable keybindings, and multiple gamepad support.
42
+ see <a href="https://github.com/benevolent-games/tact">github</a>,
43
+ see <a href="https://benevolent.games/">benevolent.games</a>.
44
+ </p>
45
+ </div>
46
+ </header>
47
+
48
+ <div id=demo-theater></div>
49
+
50
+ <section>
51
+ <h3>controls</h3>
52
+ <ul>
53
+ <li><strong>keyboard</strong> wasd, left-bracket, right-bracket, backslash.</li>
54
+ <li><strong>gamepad</strong> thumbsticks, hold beta/gamma and press bumpers or dpad left/right.</li>
55
+ <li><strong>virtual</strong> use your mouse to press the little buttons.</li>
56
+ </ul>
57
+ </section>
58
+ </body>
59
+ </html>
60
+ `)
61
+
@@ -0,0 +1,8 @@
1
+
2
+ export * from "./core/index.js"
3
+ export * from "./deck/index.js"
4
+ export * from "./nubs/index.js"
5
+ export * as nubs from "./nubs/index.js"
6
+
7
+ export * from "./utils/gamepads.js"
8
+
@@ -0,0 +1,6 @@
1
+
2
+ import {Science} from "@e280/science"
3
+ import bravo from "./bravo/test.js"
4
+
5
+ await Science.run({bravo})
6
+
@@ -0,0 +1,14 @@
1
+
2
+ import {Scalar, Vec2, Xy} from "@benev/math"
3
+
4
+ export function circularClamp(vector: Xy, range: Vec2) {
5
+ const v = Vec2.from(vector)
6
+ const distance = v.distance_(0, 0)
7
+ const modifiedDistance = Scalar.remap(
8
+ distance,
9
+ range.x, range.y,
10
+ 0, 1,
11
+ true,
12
+ )
13
+ return v.normalize().mulBy(modifiedDistance)
14
+ }
@@ -0,0 +1,10 @@
1
+
2
+ export function evergreen<V>(value: V, fn: () => V | null | undefined) {
3
+ let cached = value
4
+ return () => {
5
+ const next = fn()
6
+ if (next !== undefined && next !== null) cached = next
7
+ return cached
8
+ }
9
+ }
10
+