@benev/tact 0.1.0-1 → 0.1.0-3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +265 -140
- package/package.json +5 -3
- package/s/{station/parts → core/bindings}/action.ts +3 -9
- package/s/core/bindings/parts/defaults.ts +29 -0
- package/s/{station/parts/routines/lensing_algorithm.ts → core/bindings/parts/lens-algo.ts} +15 -14
- package/s/core/bindings/resolver.ts +96 -0
- package/s/core/bindings/types.ts +57 -0
- package/s/core/controllers/controller.ts +7 -0
- package/s/core/controllers/infra/group.ts +17 -0
- package/s/{station/devices → core/controllers}/infra/sampler.ts +3 -3
- package/s/{station/devices → core/controllers/standard}/gamepad.ts +5 -9
- package/s/core/controllers/standard/index.ts +7 -0
- package/s/{station/devices → core/controllers/standard}/keyboard.ts +3 -6
- package/s/{station/devices → core/controllers/standard}/pointer.ts +31 -37
- package/s/{nubs/stick/device.ts → core/controllers/standard/stick.ts} +3 -3
- package/s/{nubs/virtual-gamepad/device.ts → core/controllers/standard/virtual-gamepad.ts} +5 -5
- package/s/core/controllers/types.ts +4 -0
- package/s/core/core.test.ts +90 -0
- package/s/core/deck/deck.ts +40 -0
- package/s/core/deck/parts/bindings-depot.ts +24 -0
- package/s/core/deck/parts/local-storage-kv.ts +7 -0
- package/s/core/hub/auto-gamepads.ts +8 -0
- package/s/core/hub/bindings.ts +18 -0
- package/s/core/hub/hub.ts +102 -0
- package/s/core/hub/types.ts +14 -0
- package/s/core/index.ts +21 -0
- package/s/core/port/port.ts +34 -0
- package/s/core/port/utils/aggregate_samples_into_map.ts +20 -0
- package/s/core/port/utils/wipe_samples_map.ts +8 -0
- package/s/core/testing/testing.ts +50 -0
- package/s/demo/main.bundle.ts +2 -2
- package/s/index.ts +1 -11
- package/s/nubs/stick/view.ts +2 -2
- package/s/nubs/virtual-gamepad/view.ts +6 -6
- package/s/tests.test.ts +2 -4
- package/s/{station/utils/tmin.ts → utils/quick-math.ts} +6 -0
- package/x/{station/parts → core/bindings}/action.d.ts +1 -3
- package/x/{station/parts → core/bindings}/action.js +3 -10
- package/x/core/bindings/action.js.map +1 -0
- package/x/core/bindings/parts/defaults.d.ts +3 -0
- package/x/core/bindings/parts/defaults.js +23 -0
- package/x/core/bindings/parts/defaults.js.map +1 -0
- package/x/core/bindings/parts/is-pressed.js.map +1 -0
- package/x/core/bindings/parts/lens-algo.d.ts +2 -0
- package/x/{station/parts/routines/lensing_algorithm.js → core/bindings/parts/lens-algo.js} +12 -11
- package/x/core/bindings/parts/lens-algo.js.map +1 -0
- package/x/core/bindings/resolver.d.ts +8 -0
- package/x/core/bindings/resolver.js +87 -0
- package/x/core/bindings/resolver.js.map +1 -0
- package/x/core/bindings/types.d.ts +38 -0
- package/x/core/bindings/types.js +4 -0
- package/x/core/bindings/types.js.map +1 -0
- package/x/core/controllers/controller.d.ts +4 -0
- package/x/core/controllers/controller.js +3 -0
- package/x/core/controllers/controller.js.map +1 -0
- package/x/core/controllers/infra/group.d.ts +7 -0
- package/x/core/controllers/infra/group.js +13 -0
- package/x/core/controllers/infra/group.js.map +1 -0
- package/x/core/controllers/infra/sampler.d.ts +8 -0
- package/x/{station/devices → core/controllers}/infra/sampler.js +2 -2
- package/x/core/controllers/infra/sampler.js.map +1 -0
- package/x/core/controllers/standard/gamepad.d.ts +9 -0
- package/x/{station/devices → core/controllers/standard}/gamepad.js +4 -8
- package/x/core/controllers/standard/gamepad.js.map +1 -0
- package/x/core/controllers/standard/index.d.ts +5 -0
- package/x/core/controllers/standard/index.js +6 -0
- package/x/core/controllers/standard/index.js.map +1 -0
- package/x/{station/devices → core/controllers/standard}/keyboard.d.ts +3 -3
- package/x/{station/devices → core/controllers/standard}/keyboard.js +3 -6
- package/x/core/controllers/standard/keyboard.js.map +1 -0
- package/x/{station/devices → core/controllers/standard}/pointer.d.ts +3 -3
- package/x/{station/devices → core/controllers/standard}/pointer.js +26 -31
- package/x/core/controllers/standard/pointer.js.map +1 -0
- package/x/{nubs/stick/device.d.ts → core/controllers/standard/stick.d.ts} +2 -2
- package/x/{nubs/stick/device.js → core/controllers/standard/stick.js} +4 -4
- package/x/core/controllers/standard/stick.js.map +1 -0
- package/x/core/controllers/standard/virtual-gamepad.d.ts +7 -0
- package/x/{nubs/virtual-gamepad/device.js → core/controllers/standard/virtual-gamepad.js} +6 -6
- package/x/core/controllers/standard/virtual-gamepad.js.map +1 -0
- package/x/core/controllers/types.d.ts +2 -0
- package/x/core/controllers/types.js +2 -0
- package/x/core/controllers/types.js.map +1 -0
- package/x/core/core.test.d.ts +11 -0
- package/x/core/core.test.js +84 -0
- package/x/core/core.test.js.map +1 -0
- package/x/core/deck/deck.d.ts +16 -0
- package/x/core/deck/deck.js +31 -0
- package/x/core/deck/deck.js.map +1 -0
- package/x/core/deck/parts/bindings-depot.d.ts +9 -0
- package/x/core/deck/parts/bindings-depot.js +19 -0
- package/x/core/deck/parts/bindings-depot.js.map +1 -0
- package/x/core/deck/parts/local-storage-kv.d.ts +2 -0
- package/x/core/deck/parts/local-storage-kv.js +5 -0
- package/x/core/deck/parts/local-storage-kv.js.map +1 -0
- package/x/core/hub/auto-gamepads.d.ts +2 -0
- package/x/core/hub/auto-gamepads.js +6 -0
- package/x/core/hub/auto-gamepads.js.map +1 -0
- package/x/core/hub/bindings.d.ts +2 -0
- package/x/core/hub/bindings.js +16 -0
- package/x/core/hub/bindings.js.map +1 -0
- package/x/core/hub/hub.d.ts +28 -0
- package/x/core/hub/hub.js +91 -0
- package/x/core/hub/hub.js.map +1 -0
- package/x/core/hub/types.d.ts +9 -0
- package/x/core/hub/types.js +2 -0
- package/x/core/hub/types.js.map +1 -0
- package/x/core/index.d.ts +15 -0
- package/x/core/index.js +16 -0
- package/x/core/index.js.map +1 -0
- package/x/core/port/port.d.ts +12 -0
- package/x/core/port/port.js +25 -0
- package/x/core/port/port.js.map +1 -0
- package/x/core/port/utils/aggregate_samples_into_map.d.ts +3 -0
- package/x/core/port/utils/aggregate_samples_into_map.js +11 -0
- package/x/core/port/utils/aggregate_samples_into_map.js.map +1 -0
- package/x/core/port/utils/wipe_samples_map.d.ts +2 -0
- package/x/core/port/utils/wipe_samples_map.js +5 -0
- package/x/core/port/utils/wipe_samples_map.js.map +1 -0
- package/x/core/testing/testing.d.ts +38 -0
- package/x/core/testing/testing.js +42 -0
- package/x/core/testing/testing.js.map +1 -0
- package/x/demo/main.bundle.js +2 -2
- package/x/demo/main.bundle.js.map +1 -1
- package/x/demo/main.bundle.min.js +1 -1
- package/x/demo/main.bundle.min.js.map +4 -4
- package/x/index.d.ts +1 -11
- package/x/index.html +3 -3
- package/x/index.js +1 -11
- package/x/index.js.map +1 -1
- package/x/nubs/stick/view.d.ts +2 -2
- package/x/nubs/stick/view.js.map +1 -1
- package/x/nubs/virtual-gamepad/view.d.ts +2 -2
- package/x/nubs/virtual-gamepad/view.js +5 -5
- package/x/nubs/virtual-gamepad/view.js.map +1 -1
- package/x/tests.test.js +2 -4
- package/x/tests.test.js.map +1 -1
- package/x/{station/utils/tmax.d.ts → utils/quick-math.d.ts} +1 -0
- package/x/utils/quick-math.js +11 -0
- package/x/utils/quick-math.js.map +1 -0
- package/s/station/devices/infra/device.ts +0 -7
- package/s/station/devices/infra/group.ts +0 -17
- package/s/station/parts/defaults.ts +0 -28
- package/s/station/parts/resolver.ts +0 -73
- package/s/station/parts/routines/aggregate_samples_into_map.ts +0 -20
- package/s/station/parts/routines/build_updatable_actions_structure.ts +0 -29
- package/s/station/parts/switchboard-bindings.ts +0 -21
- package/s/station/station.test.ts +0 -86
- package/s/station/station.ts +0 -47
- package/s/station/switchboard.ts +0 -107
- package/s/station/testing/testing.ts +0 -47
- package/s/station/types.ts +0 -72
- package/s/station/utils/modprefix.ts +0 -16
- package/s/station/utils/tmax.ts +0 -7
- package/x/nubs/stick/device.js.map +0 -1
- package/x/nubs/virtual-gamepad/device.d.ts +0 -7
- package/x/nubs/virtual-gamepad/device.js.map +0 -1
- package/x/station/devices/gamepad.d.ts +0 -10
- package/x/station/devices/gamepad.js.map +0 -1
- package/x/station/devices/infra/device.d.ts +0 -4
- package/x/station/devices/infra/device.js +0 -3
- package/x/station/devices/infra/device.js.map +0 -1
- package/x/station/devices/infra/group.d.ts +0 -7
- package/x/station/devices/infra/group.js +0 -13
- package/x/station/devices/infra/group.js.map +0 -1
- package/x/station/devices/infra/sampler.d.ts +0 -8
- package/x/station/devices/infra/sampler.js.map +0 -1
- package/x/station/devices/keyboard.js.map +0 -1
- package/x/station/devices/pointer.js.map +0 -1
- package/x/station/parts/action.js.map +0 -1
- package/x/station/parts/defaults.d.ts +0 -5
- package/x/station/parts/defaults.js +0 -22
- package/x/station/parts/defaults.js.map +0 -1
- package/x/station/parts/resolver.d.ts +0 -10
- package/x/station/parts/resolver.js +0 -63
- package/x/station/parts/resolver.js.map +0 -1
- package/x/station/parts/routines/aggregate_samples_into_map.d.ts +0 -3
- package/x/station/parts/routines/aggregate_samples_into_map.js +0 -11
- package/x/station/parts/routines/aggregate_samples_into_map.js.map +0 -1
- package/x/station/parts/routines/build_updatable_actions_structure.d.ts +0 -5
- package/x/station/parts/routines/build_updatable_actions_structure.js +0 -18
- package/x/station/parts/routines/build_updatable_actions_structure.js.map +0 -1
- package/x/station/parts/routines/lensing_algorithm.d.ts +0 -2
- package/x/station/parts/routines/lensing_algorithm.js.map +0 -1
- package/x/station/parts/switchboard-bindings.d.ts +0 -2
- package/x/station/parts/switchboard-bindings.js +0 -19
- package/x/station/parts/switchboard-bindings.js.map +0 -1
- package/x/station/station.d.ts +0 -15
- package/x/station/station.js +0 -35
- package/x/station/station.js.map +0 -1
- package/x/station/station.test.d.ts +0 -11
- package/x/station/station.test.js +0 -80
- package/x/station/station.test.js.map +0 -1
- package/x/station/switchboard.d.ts +0 -30
- package/x/station/switchboard.js +0 -90
- package/x/station/switchboard.js.map +0 -1
- package/x/station/testing/testing.d.ts +0 -58
- package/x/station/testing/testing.js +0 -39
- package/x/station/testing/testing.js.map +0 -1
- package/x/station/types.d.ts +0 -56
- package/x/station/types.js +0 -5
- package/x/station/types.js.map +0 -1
- package/x/station/utils/is-pressed.js.map +0 -1
- package/x/station/utils/modprefix.d.ts +0 -1
- package/x/station/utils/modprefix.js +0 -16
- package/x/station/utils/modprefix.js.map +0 -1
- package/x/station/utils/tmax.js +0 -6
- package/x/station/utils/tmax.js.map +0 -1
- package/x/station/utils/tmin.d.ts +0 -1
- package/x/station/utils/tmin.js +0 -6
- package/x/station/utils/tmin.js.map +0 -1
- /package/s/{station/utils → core/bindings/parts}/is-pressed.ts +0 -0
- /package/x/{station/utils → core/bindings/parts}/is-pressed.d.ts +0 -0
- /package/x/{station/utils → core/bindings/parts}/is-pressed.js +0 -0
package/README.md
CHANGED
|
@@ -1,50 +1,126 @@
|
|
|
1
1
|
|
|
2
|
-
# @benev/tact
|
|
3
|
-
>
|
|
2
|
+
# 🎮 @benev/tact
|
|
3
|
+
> *web game input library, from keypress to couch co-op*
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
npm install @benev/tact
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- 🔌 **
|
|
13
|
-
-
|
|
9
|
+
- 🛹 **deck** full setup with localstorate persistence
|
|
10
|
+
- 🎮 **controllers** produce user input samples
|
|
11
|
+
- 🧩 **bindings** describe how actions interpret samples
|
|
12
|
+
- 🔌 **port** updates actions by interpreting samples
|
|
13
|
+
- 🛞 **hub** plugs controllers into ports (multi-gamepad couch co-op!)
|
|
14
|
+
- 📱 **nubs** is mobile ui virtual gamepad stuff
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
<br/><br/>
|
|
19
|
+
|
|
20
|
+
## 🍋 tact deck
|
|
21
|
+
> *the full setup*
|
|
22
|
+
|
|
23
|
+
the deck is the heart of tact, tying all the pieces together and putting a bow in it for you.
|
|
24
|
+
|
|
25
|
+
### 🛹 deck setup
|
|
26
|
+
- **import stuff from tact**
|
|
27
|
+
```ts
|
|
28
|
+
import * as tact from "@benev/tact"
|
|
29
|
+
```
|
|
30
|
+
- **setup your deck, and your game's bindings**
|
|
31
|
+
```ts
|
|
32
|
+
const deck = await tact.Deck.load({
|
|
33
|
+
|
|
34
|
+
// how many players ports are possible? 1 is fine..
|
|
35
|
+
portCount: 4,
|
|
36
|
+
|
|
37
|
+
// where to store the user-customized bindings
|
|
38
|
+
kv: tact.localStorageKv(),
|
|
39
|
+
|
|
40
|
+
// default archetypal bindings for your game
|
|
41
|
+
bindings: {
|
|
42
|
+
...tact.hubBindings(),
|
|
43
|
+
walking: {
|
|
44
|
+
forward: "KeyW",
|
|
45
|
+
jump: "Space",
|
|
46
|
+
},
|
|
47
|
+
gunning: {
|
|
48
|
+
shoot: ["or", "pointer.button.left", "gamepad.trigger.right"],
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 🛹 plug controllers into the hub
|
|
55
|
+
- **plug a keyboard/mouse player into the hub**
|
|
56
|
+
```ts
|
|
57
|
+
deck.hub.plug(
|
|
58
|
+
new tact.GroupController(
|
|
59
|
+
new tact.KeyboardController(),
|
|
60
|
+
new tact.PointerController(),
|
|
61
|
+
new tact.VirtualGamepadController(),
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
- **auto connect/disconnect gamepads as they come and go**
|
|
66
|
+
```ts
|
|
67
|
+
tact.autoGamepads(deck.hub.plug)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 🛹 do your gameplay
|
|
71
|
+
- **start with what modes you want enabled in your game**
|
|
72
|
+
```ts
|
|
73
|
+
for (const port of deck.ports)
|
|
74
|
+
port.modes.adds("walking", "gunning")
|
|
75
|
+
```
|
|
76
|
+
- **poll the deck, interrogate actions for your gameplay**
|
|
77
|
+
```ts
|
|
78
|
+
onEachTickInYourGame(() => {
|
|
79
|
+
|
|
80
|
+
// do your polling
|
|
81
|
+
const [p1, p2, p3, p4] = deck.hub.poll()
|
|
82
|
+
|
|
83
|
+
// check if the first player is pressing "forward" action
|
|
84
|
+
p1.walking.forward.pressed // true
|
|
85
|
+
|
|
86
|
+
// check how hard the second player is pulling that trigger
|
|
87
|
+
p2.gunning.shoot.value // 0.123
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
|
|
14
92
|
|
|
15
93
|
<br/><br/>
|
|
16
94
|
|
|
17
|
-
## 🍋 tact
|
|
18
|
-
>
|
|
95
|
+
## 🍋 tact controllers
|
|
96
|
+
> *sources of user input "samples"*
|
|
19
97
|
|
|
20
|
-
###
|
|
98
|
+
### 🎮 polling is good, actually
|
|
21
99
|
- tact operates on the basis of *polling*
|
|
22
100
|
- *"but polling is bad"* says you — but no — you're wrong — polling is unironically *based,* and you *should* do it
|
|
23
101
|
- in a game, we want to be processing our inputs *every frame*
|
|
24
102
|
- the gift of polling is total control over *when* inputs are processed
|
|
25
103
|
- i will elaborate no further 🗿
|
|
26
104
|
|
|
27
|
-
###
|
|
28
|
-
- make a
|
|
105
|
+
### 🎮 basically how a controller works
|
|
106
|
+
- make a controller
|
|
29
107
|
```ts
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const device = new KeyboardDevice(window)
|
|
108
|
+
const keyboard = new tact.KeyboardController()
|
|
33
109
|
```
|
|
34
110
|
- take samples each frame
|
|
35
111
|
```ts
|
|
36
|
-
const samples =
|
|
112
|
+
const samples = keyboard.takeSamples()
|
|
37
113
|
// [
|
|
38
114
|
// ["KeyA", 1],
|
|
39
115
|
// ["Space", 0]
|
|
40
116
|
// ]
|
|
41
117
|
```
|
|
42
|
-
-
|
|
118
|
+
- some controllers have disposers to call when you're done with them
|
|
43
119
|
```ts
|
|
44
|
-
|
|
120
|
+
keyboard.dispose()
|
|
45
121
|
```
|
|
46
122
|
|
|
47
|
-
###
|
|
123
|
+
### 🎮 samples explained
|
|
48
124
|
- a sample is a raw input of type `[code: string, value: number]`
|
|
49
125
|
- a sample has a `code` string
|
|
50
126
|
- it's either a [standard keycode](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values), like `KeyA`
|
|
@@ -57,37 +133,21 @@ npm install @benev/tact
|
|
|
57
133
|
- sometimes we use numbers greater then `1`, like for dots of pointer movement like in `pointer.move.up`
|
|
58
134
|
- don't worry about sensitivity, deadzones, values like `0.00001` — actions will account for all that using bindings later on
|
|
59
135
|
|
|
60
|
-
###
|
|
61
|
-
-
|
|
62
|
-
- consider a keycode like `KeyA`
|
|
63
|
-
- `ctrl-KeyA` means the "ctrl" modifier was held
|
|
64
|
-
- `alt-KeyA` means the "alt" modifier was held
|
|
65
|
-
- `meta-KeyA` means the "meta" modifier was held (command or windows keys)
|
|
66
|
-
- `shift-KeyA` means the "shift" modifier was held
|
|
67
|
-
- `ctrl-alt-meta-shift-KeyA` they can stack, but always in this order (the word `cams` helps remind me the valid order)
|
|
68
|
-
- `x-KeyA` means *no* modifier was held (exclusive)
|
|
69
|
-
- `KeyA` doesn't care if any modifiers were held or not
|
|
70
|
-
|
|
71
|
-
### 🥝 sample code reference
|
|
72
|
-
- **KeyboardDevice**
|
|
136
|
+
### 🎮 sample code reference
|
|
137
|
+
- **KeyboardController**
|
|
73
138
|
- any [standard keycode](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values)
|
|
74
139
|
- `KeyA`
|
|
75
140
|
- `Space`
|
|
76
141
|
- `Digit2`
|
|
77
142
|
- etc
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
- `alt-shift-Space`
|
|
81
|
-
- `x-Digit2`
|
|
82
|
-
- etc
|
|
83
|
-
- **PointerDevice**
|
|
84
|
-
- mouse buttons (plus modprefixes)
|
|
143
|
+
- **PointerController**
|
|
144
|
+
- mouse buttons
|
|
85
145
|
- `pointer.button.left`
|
|
86
146
|
- `pointer.button.right`
|
|
87
147
|
- `pointer.button.middle`
|
|
88
148
|
- `pointer.button.4`
|
|
89
149
|
- `pointer.button.5`
|
|
90
|
-
- mouse wheel
|
|
150
|
+
- mouse wheel
|
|
91
151
|
- `pointer.wheel.up`
|
|
92
152
|
- `pointer.wheel.down`
|
|
93
153
|
- `pointer.wheel.left`
|
|
@@ -97,7 +157,7 @@ npm install @benev/tact
|
|
|
97
157
|
- `pointer.move.down`
|
|
98
158
|
- `pointer.move.left`
|
|
99
159
|
- `pointer.move.right`
|
|
100
|
-
- **
|
|
160
|
+
- **GamepadController**
|
|
101
161
|
- gamepad buttons
|
|
102
162
|
- `gamepad.a`
|
|
103
163
|
- `gamepad.b`
|
|
@@ -126,58 +186,151 @@ npm install @benev/tact
|
|
|
126
186
|
- `gamepad.stick.right.left`
|
|
127
187
|
- `gamepad.stick.right.right`
|
|
128
188
|
|
|
189
|
+
|
|
190
|
+
|
|
129
191
|
<br/><br/>
|
|
130
192
|
|
|
131
193
|
## 🍋 tact bindings
|
|
132
|
-
> keybindings! they describe how actions interpret samples
|
|
194
|
+
> *keybindings! they describe how actions interpret samples*
|
|
133
195
|
|
|
134
|
-
###
|
|
135
|
-
- let's start with a small example
|
|
196
|
+
### 🧩 bindings example
|
|
197
|
+
- **let's start with a small example:**
|
|
136
198
|
```ts
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const bindings = asBindings({
|
|
199
|
+
const bindings = tact.asBindings({
|
|
140
200
|
walking: {
|
|
141
|
-
forward:
|
|
142
|
-
jump:
|
|
201
|
+
forward: "KeyW",
|
|
202
|
+
jump: "Space",
|
|
143
203
|
},
|
|
144
204
|
gunning: {
|
|
145
|
-
shoot: [
|
|
205
|
+
shoot: ["or", "pointer.button.left", "gamepad.trigger.right"],
|
|
146
206
|
},
|
|
147
207
|
})
|
|
148
208
|
```
|
|
149
209
|
- `walking` and `gunning` are **modes**
|
|
150
210
|
- `forward`, `jump`, and `shoot` are **actions**
|
|
151
|
-
-
|
|
152
|
-
|
|
153
|
-
|
|
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", {deadzone: 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
|
+
deadzone: 0.2,
|
|
244
|
+
timing: ["direct"],
|
|
245
|
+
}]
|
|
246
|
+
```
|
|
247
|
+
- defaults shown
|
|
248
|
+
- `scale` is sensitivity, the value gets multiplied by this
|
|
249
|
+
- `invert` will invert a value by subtracting it from 1
|
|
250
|
+
- `deadzone` ignores values below the threshold (and remaps to preserve the range)
|
|
251
|
+
- `timing` lets you specify special timing considerations
|
|
252
|
+
- `["direct"]` ignores timing considerations
|
|
253
|
+
- `["tap", 250]` only fires for taps under 250ms
|
|
254
|
+
- `["hold", 250]` only fires for holds over 250ms
|
|
255
|
+
- **"or"** — resolves to the maximum value
|
|
256
|
+
```ts
|
|
257
|
+
["or", "KeyA", "KeyB", "KeyC"]
|
|
258
|
+
```
|
|
259
|
+
- **"and"** — resolves to the minimum value
|
|
260
|
+
```ts
|
|
261
|
+
["and", "KeyA", "KeyB", "KeyC"]
|
|
262
|
+
```
|
|
263
|
+
- **"not"** — resolves to the opposite effect
|
|
264
|
+
```ts
|
|
265
|
+
["not", "KeyA"]
|
|
266
|
+
```
|
|
267
|
+
- **"cond"** — conditional situation (example for modifiers shown)
|
|
268
|
+
```ts
|
|
269
|
+
["cond", "KeyA", ["and",
|
|
270
|
+
["or", "ControlLeft", "ControlRight"],
|
|
271
|
+
["not", ["or", "AltLeft", "AltRight"]],
|
|
272
|
+
["not", ["or", "MetaLeft", "MetaRight"]],
|
|
273
|
+
["not", ["or", "ShiftLeft", "ShiftRight"]],
|
|
274
|
+
]]
|
|
275
|
+
```
|
|
276
|
+
- KeyA is the value that gets used
|
|
277
|
+
- but only if the following condition passes
|
|
278
|
+
- **"mods"** — macro for modifiers
|
|
279
|
+
```ts
|
|
280
|
+
["mods", "KeyA", {ctrl: true}]
|
|
281
|
+
```
|
|
282
|
+
- equivalent to the "cond" example above
|
|
283
|
+
- `ctrl`, `alt`, `meta`, `shift` are available
|
|
284
|
+
|
|
285
|
+
|
|
154
286
|
|
|
155
287
|
<br/><br/>
|
|
156
288
|
|
|
157
|
-
## 🍋 tact
|
|
158
|
-
> polling gives you actions
|
|
289
|
+
## 🍋 tact port
|
|
290
|
+
> *polling gives you "actions"*
|
|
159
291
|
|
|
160
|
-
|
|
161
|
-
- create a station
|
|
162
|
-
```ts
|
|
163
|
-
import {Station} from "@benev/tact"
|
|
292
|
+
a port represents a single playable port, and you poll it each frame to resolve actions for you to read.
|
|
164
293
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
294
|
+
### 🔌 port basics
|
|
295
|
+
- **make a port**
|
|
296
|
+
```ts
|
|
297
|
+
const port = new tact.Port(bindings)
|
|
298
|
+
```
|
|
299
|
+
- **attach some controllers to the port**
|
|
300
|
+
```ts
|
|
301
|
+
port.controllers
|
|
302
|
+
.add(new tact.KeyboardController())
|
|
303
|
+
.add(new tact.PointerController())
|
|
304
|
+
.add(new tact.VirtualGamepadController())
|
|
305
|
+
```
|
|
306
|
+
- you can add/delete controllers from the set any time
|
|
307
|
+
- **don't forget to enable modes!**
|
|
308
|
+
```ts
|
|
309
|
+
port.modes.add("walking")
|
|
310
|
+
```
|
|
311
|
+
- if you don't enable any modes, no actions will happen
|
|
312
|
+
- actions only happen for enabled modes
|
|
313
|
+
- you can toggle modes on and off by adding/deleting them from the modes set
|
|
314
|
+
- **you can update the bindings any time**
|
|
315
|
+
```ts
|
|
316
|
+
port.bindings = freshBindings
|
|
317
|
+
```
|
|
318
|
+
- **wire up gamepad auto connect/disconnect**
|
|
319
|
+
```ts
|
|
320
|
+
tact.autoGamepads(controller => {
|
|
321
|
+
port.controllers.add(controller)
|
|
322
|
+
return () => port.controllers.delete(controller)
|
|
323
|
+
})
|
|
171
324
|
```
|
|
172
325
|
|
|
173
|
-
###
|
|
174
|
-
- poll the
|
|
326
|
+
### 🔌 interrogating actions
|
|
327
|
+
- **poll the port every frame**
|
|
175
328
|
```ts
|
|
176
|
-
|
|
329
|
+
const actions = port.poll()
|
|
177
330
|
```
|
|
178
|
-
- now you
|
|
331
|
+
- **now you can inspect the `actions`**
|
|
179
332
|
```ts
|
|
180
|
-
|
|
333
|
+
actions.walking.forward.value // 1
|
|
181
334
|
```
|
|
182
335
|
- `walking` is a `mode`
|
|
183
336
|
- `forward` is an `action`
|
|
@@ -187,113 +340,85 @@ npm install @benev/tact
|
|
|
187
340
|
- `action.pressed` — true if the value > 0
|
|
188
341
|
- `action.down` — true for one frame when the key goes from up to down
|
|
189
342
|
- `action.up` — true for one frame when the key goes from down to up
|
|
190
|
-
- `action.on(action => {})` — react to changes ([`@e280/stz`](https://github.com/e280/stz) sub fn)
|
|
191
|
-
- `action.onDown(action => {})` — react only on down ([`@e280/stz`](https://github.com/e280/stz) sub fn)
|
|
192
343
|
|
|
193
|
-
### 🥝 more about station
|
|
194
|
-
- you can enable/disable modes like this (it's a set)
|
|
195
|
-
```ts
|
|
196
|
-
station.modes.add("gunning")
|
|
197
|
-
// now the "gunning" actions can fire
|
|
198
344
|
|
|
199
|
-
station.modes.delete("walking")
|
|
200
|
-
// now the "walking" actions *cannot* fire
|
|
201
|
-
```
|
|
202
|
-
- you can add/remove devices from the set any time
|
|
203
|
-
```ts
|
|
204
|
-
station.devices.add(new GamepadDevice(pad))
|
|
205
|
-
```
|
|
206
|
-
- you can update the bindings at runtime
|
|
207
|
-
```ts
|
|
208
|
-
station.bindings = bindings2
|
|
209
|
-
```
|
|
210
345
|
|
|
211
346
|
<br/><br/>
|
|
212
347
|
|
|
213
|
-
## 🍋 tact
|
|
214
|
-
> multiple gamepads! couch co-op is so back
|
|
348
|
+
## 🍋 tact hub
|
|
349
|
+
> *multiple gamepads! couch co-op is so back*
|
|
215
350
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
- import stuff:
|
|
220
|
-
```ts
|
|
221
|
-
import {
|
|
222
|
-
Switchboard, Station,
|
|
223
|
-
GroupDevice, GamepadDevice, KeyboardDevice, PointerDevice,
|
|
224
|
-
} from "@benev/tact"
|
|
225
|
-
```
|
|
351
|
+
you know the way old-timey game consoles had four controller ports on the front?
|
|
352
|
+
|
|
353
|
+
the hub embraces that analogy, helping you coordinate the plugging and unplugging of virtual controllers into its virtual ports.
|
|
226
354
|
|
|
227
|
-
###
|
|
228
|
-
- **adopt standard
|
|
355
|
+
### 🛞 create a hub with ports
|
|
356
|
+
- **adopt standard hub bindings**
|
|
229
357
|
```ts
|
|
230
|
-
|
|
231
|
-
|
|
358
|
+
const hubBindings = {
|
|
359
|
+
...yourBindings,
|
|
360
|
+
|
|
361
|
+
// mixin standard hub bindings
|
|
362
|
+
...tact.hubBindings(),
|
|
363
|
+
}
|
|
232
364
|
```
|
|
233
|
-
-
|
|
234
|
-
- gamepad: hold middle button and press bumpers
|
|
365
|
+
- hub bindings let players shimmy what port their controller is plugged into
|
|
366
|
+
- gamepad: hold gamma (middle button) and press bumpers
|
|
235
367
|
- keyboard: left bracket or right bracket
|
|
236
|
-
- **make
|
|
368
|
+
- **make hub with multiple ports at the ready**
|
|
237
369
|
```ts
|
|
238
|
-
const
|
|
239
|
-
new
|
|
240
|
-
new
|
|
241
|
-
new
|
|
242
|
-
new
|
|
370
|
+
const hub = new tact.Hub([
|
|
371
|
+
new tact.Port(hubBindings),
|
|
372
|
+
new tact.Port(hubBindings),
|
|
373
|
+
new tact.Port(hubBindings),
|
|
374
|
+
new tact.Port(hubBindings),
|
|
243
375
|
])
|
|
244
376
|
```
|
|
245
|
-
- yes that's right — each player
|
|
377
|
+
- yes that's right — each player port gets its own bindings 🤯
|
|
246
378
|
|
|
247
|
-
###
|
|
248
|
-
- **let's
|
|
379
|
+
### 🛞 plug in some controllers
|
|
380
|
+
- **let's plug in the keyboard/mouse player**
|
|
249
381
|
```ts
|
|
250
|
-
|
|
251
|
-
new
|
|
252
|
-
new
|
|
253
|
-
new
|
|
382
|
+
hub.plug(
|
|
383
|
+
new tact.GroupController(
|
|
384
|
+
new tact.KeyboardController(),
|
|
385
|
+
new tact.PointerController(),
|
|
386
|
+
new tact.VirtualGamepadController(),
|
|
254
387
|
)
|
|
255
388
|
)
|
|
256
389
|
```
|
|
257
|
-
- the
|
|
390
|
+
- the hub requires a single controller to represent a player, thus we can use a `GroupController` to combine multple controllers into one
|
|
258
391
|
- **wire up gamepad auto connect/disconnect**
|
|
259
392
|
```ts
|
|
260
|
-
|
|
393
|
+
tact.autoGamepads(hub.plug)
|
|
261
394
|
```
|
|
262
395
|
|
|
263
|
-
###
|
|
396
|
+
### 🛞 it's gaming time
|
|
264
397
|
- **do your polling, interrogate those actions**
|
|
265
398
|
```ts
|
|
266
|
-
const [p1, p2, p3, p4] =
|
|
267
|
-
|
|
268
|
-
// poll them all
|
|
269
|
-
switchboard.poll(Date.now())
|
|
399
|
+
const [p1, p2, p3, p4] = hub.poll()
|
|
270
400
|
|
|
271
|
-
p1.
|
|
272
|
-
p2.
|
|
401
|
+
p1.walking.jump.value // 1
|
|
402
|
+
p2.walking.jump.value // 0
|
|
273
403
|
```
|
|
274
404
|
|
|
275
|
-
|
|
276
|
-
- `switchboard.stations` — direct access to the array of stations
|
|
277
|
-
- `switchboard.isActive(p1)` — check if there's a switchboard-connected-device assigned to this station
|
|
278
|
-
- `switchboard.shimmy(device, 1)` — shimmy a device forward one station
|
|
279
|
-
- `switchboard.shimmy(device, -1)` — shimmy a device backward one station
|
|
280
|
-
- `switchboard.connect(device, p4)` — connect-or-reassign a device to a specific station
|
|
281
|
-
- `switchboard.connect(device)` — connect a device to the next unassigned station (or the last station)
|
|
282
|
-
- `switchboard.disconnect(device)` — unassign a device and forget about it
|
|
405
|
+
|
|
283
406
|
|
|
284
407
|
<br/><br/>
|
|
285
408
|
|
|
286
409
|
## 🍋 tact nubs
|
|
287
|
-
> mobile ui like virtual thumbsticks and buttons
|
|
410
|
+
> *mobile ui like virtual thumbsticks and buttons*
|
|
288
411
|
|
|
289
|
-
###
|
|
412
|
+
### 📱 nub stick
|
|
290
413
|
> TODO lol need to write docs
|
|
291
414
|
|
|
292
|
-
###
|
|
415
|
+
### 📱 nub virtual gamepad
|
|
293
416
|
> TODO lol need to write docs
|
|
294
417
|
|
|
418
|
+
|
|
419
|
+
|
|
295
420
|
<br/><br/>
|
|
296
421
|
|
|
297
422
|
## 🍋 tact is by https://benevolent.games/
|
|
298
|
-
> building the future of web games
|
|
423
|
+
> *building the future of web games*
|
|
299
424
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@benev/tact",
|
|
3
|
-
"version": "0.1.0-
|
|
3
|
+
"version": "0.1.0-3",
|
|
4
4
|
"description": "keybindings and gamepad support for web games",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Chase Moskal <chasemoskal@gmail.com>",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"main": "./x/index.js",
|
|
9
9
|
"sideEffects": false,
|
|
10
10
|
"exports": {
|
|
11
|
-
".": "./x/index.js"
|
|
11
|
+
".": "./x/index.js",
|
|
12
|
+
"./core": "./x/core/index.js"
|
|
12
13
|
},
|
|
13
14
|
"files": [
|
|
14
15
|
"x",
|
|
@@ -32,9 +33,10 @@
|
|
|
32
33
|
},
|
|
33
34
|
"dependencies": {
|
|
34
35
|
"@benev/math": "^0.2.0-1",
|
|
36
|
+
"@e280/kv": "^0.1.0",
|
|
35
37
|
"@e280/sly": "^0.1.1",
|
|
36
38
|
"@e280/strata": "^0.1.0",
|
|
37
|
-
"@e280/stz": "^0.2.0-
|
|
39
|
+
"@e280/stz": "^0.2.0-5"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
42
|
"@e280/science": "^0.1.1",
|
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
import {isPressed} from "../utils/is-pressed.js"
|
|
2
|
+
import {isPressed} from "./parts/is-pressed.js"
|
|
4
3
|
|
|
5
4
|
export class Action {
|
|
6
5
|
#value = 0
|
|
7
6
|
#previous = 0
|
|
8
7
|
|
|
9
|
-
static
|
|
8
|
+
static update(action: Action, value: number) {
|
|
10
9
|
action.#previous = action.#value
|
|
11
|
-
action.#value =
|
|
12
|
-
if (action.changed) action.on.pub(action)
|
|
13
|
-
if (action.down) action.onDown.pub(action)
|
|
10
|
+
action.#value = value
|
|
14
11
|
}
|
|
15
12
|
|
|
16
|
-
readonly on = sub<[Action]>()
|
|
17
|
-
readonly onDown = sub<[Action]>()
|
|
18
|
-
|
|
19
13
|
get value() { return this.#value }
|
|
20
14
|
get previous() { return this.#previous }
|
|
21
15
|
get changed() { return this.#value !== this.#previous }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
import {Code, CodeSettings, CodeState} from "../types.js"
|
|
3
|
+
|
|
4
|
+
export const defaultHoldTime = 250
|
|
5
|
+
|
|
6
|
+
export function defaultCodeState([,,settings]: Code): CodeState {
|
|
7
|
+
return {
|
|
8
|
+
lastValue: 0,
|
|
9
|
+
holdStart: 0,
|
|
10
|
+
settings: defaultifyCodeSettings(settings),
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function defaultCodeSettings(): CodeSettings {
|
|
15
|
+
return {
|
|
16
|
+
scale: 1,
|
|
17
|
+
invert: false,
|
|
18
|
+
deadzone: 0.2,
|
|
19
|
+
timing: ["direct"],
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function defaultifyCodeSettings(partial: Partial<CodeSettings> = {}): CodeSettings {
|
|
24
|
+
return {
|
|
25
|
+
...defaultCodeSettings(),
|
|
26
|
+
...partial,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|