@benev/tact 0.1.0-4 → 0.1.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.
- package/README.md +4 -15
- package/package.json +9 -9
- package/s/core/bindings/parts/defaults.ts +3 -2
- package/s/core/bindings/parts/lens-algo.ts +5 -1
- package/s/core/bindings/parts/lookup-proxies.ts +17 -0
- package/s/core/bindings/resolver.ts +24 -17
- package/s/core/bindings/types.ts +1 -0
- package/s/core/core.test.ts +22 -0
- package/s/core/devices/standard/gamepad.ts +1 -1
- package/s/core/devices/standard/pointer.ts +4 -0
- package/s/core/testing/testing.ts +2 -1
- package/s/deck/components/components.ts +22 -0
- package/s/deck/components/deck-bindings/component.ts +99 -0
- package/s/{demo/ui/tact-demo → deck/components/deck-bindings}/style.css.ts +3 -1
- package/s/deck/components/deck-overlay/component.ts +51 -0
- package/s/deck/{views → components}/deck-overlay/style.css.ts +0 -2
- package/s/deck/components/framework.ts +17 -0
- package/s/deck/deck.ts +12 -7
- package/s/deck/index.ts +2 -2
- package/s/deck/parts/db.ts +1 -1
- package/s/demo/main.bundle.ts +7 -2
- package/s/demo/ui/theater/styles.css.ts +1 -0
- package/s/demo/ui/theater/view.ts +51 -44
- package/s/demo/ui/theater/virtual/view.ts +1 -1
- package/s/demo/ui/utils/loader.ts +2 -2
- package/s/index.html.ts +1 -1
- package/s/nubs/vpad/styles.css.ts +4 -4
- package/s/utils/types.ts +19 -0
- package/x/core/bindings/parts/defaults.d.ts +1 -1
- package/x/core/bindings/parts/defaults.js +3 -2
- package/x/core/bindings/parts/defaults.js.map +1 -1
- package/x/core/bindings/parts/lens-algo.js +5 -1
- package/x/core/bindings/parts/lens-algo.js.map +1 -1
- package/x/core/bindings/parts/lookup-proxies.d.ts +1 -0
- package/x/core/bindings/parts/lookup-proxies.js +19 -0
- package/x/core/bindings/parts/lookup-proxies.js.map +1 -0
- package/x/core/bindings/resolver.js +20 -16
- package/x/core/bindings/resolver.js.map +1 -1
- package/x/core/bindings/types.d.ts +1 -0
- package/x/core/core.test.d.ts +1 -0
- package/x/core/core.test.js +21 -0
- package/x/core/core.test.js.map +1 -1
- package/x/core/devices/infra/group.d.ts +1 -2
- package/x/core/devices/standard/gamepad.js +1 -1
- package/x/core/devices/standard/gamepad.js.map +1 -1
- package/x/core/devices/standard/keyboard.d.ts +1 -4
- package/x/core/devices/standard/pointer.d.ts +1 -4
- package/x/core/devices/standard/pointer.js +4 -0
- package/x/core/devices/standard/pointer.js.map +1 -1
- package/x/core/hub/port.d.ts +2 -3
- package/x/core/testing/testing.d.ts +5 -0
- package/x/core/testing/testing.js +1 -0
- package/x/core/testing/testing.js.map +1 -1
- package/x/deck/components/components.d.ts +14 -0
- package/x/deck/components/components.js +9 -0
- package/x/deck/components/components.js.map +1 -0
- package/x/deck/components/deck-bindings/component.d.ts +6 -0
- package/x/deck/components/deck-bindings/component.js +83 -0
- package/x/deck/components/deck-bindings/component.js.map +1 -0
- package/x/deck/components/deck-bindings/style.css.js +5 -0
- package/x/deck/components/deck-bindings/style.css.js.map +1 -0
- package/x/deck/components/deck-overlay/component.d.ts +6 -0
- package/x/deck/components/deck-overlay/component.js +44 -0
- package/x/deck/components/deck-overlay/component.js.map +1 -0
- package/x/deck/components/deck-overlay/style.css.js.map +1 -0
- package/x/deck/components/framework.d.ts +7 -0
- package/x/deck/components/framework.js +13 -0
- package/x/deck/components/framework.js.map +1 -0
- package/x/deck/deck.d.ts +9 -10
- package/x/deck/deck.js +12 -7
- package/x/deck/deck.js.map +1 -1
- package/x/deck/index.d.ts +2 -2
- package/x/deck/index.js +2 -2
- package/x/deck/index.js.map +1 -1
- package/x/deck/parts/catalog.d.ts +1 -2
- package/x/deck/parts/db.d.ts +2 -5
- package/x/deck/parts/db.js +1 -1
- package/x/deck/parts/db.js.map +1 -1
- package/x/deck/parts/overlay-visibility.d.ts +1 -4
- package/x/demo/game/game.d.ts +1 -4
- package/x/demo/main.bundle.js +8 -2
- package/x/demo/main.bundle.js.map +1 -1
- package/x/demo/main.bundle.min.js +91 -46
- package/x/demo/main.bundle.min.js.map +4 -4
- package/x/demo/ui/theater/styles.css.js +1 -0
- package/x/demo/ui/theater/styles.css.js.map +1 -1
- package/x/demo/ui/theater/view.d.ts +367 -1
- package/x/demo/ui/theater/view.js +25 -17
- package/x/demo/ui/theater/view.js.map +1 -1
- package/x/demo/ui/theater/virtual/view.js +1 -1
- package/x/demo/ui/theater/virtual/view.js.map +1 -1
- package/x/demo/ui/utils/loader.d.ts +2 -1
- package/x/demo/ui/utils/loader.js +2 -2
- package/x/demo/ui/utils/loader.js.map +1 -1
- package/x/index.html +21 -21
- package/x/index.html.js +1 -1
- package/x/nubs/stick/component.d.ts +1 -1
- package/x/nubs/vpad/component.d.ts +1 -1
- package/x/nubs/vpad/styles.css.js +4 -4
- package/x/utils/types.d.ts +3 -0
- package/x/utils/types.js +3 -0
- package/x/utils/types.js.map +1 -0
- package/s/deck/views/deck-overlay/component.ts +0 -48
- package/s/deck/views/framework.ts +0 -14
- package/s/demo/ui/tact-demo/component.ts +0 -13
- package/x/deck/views/deck-overlay/component.d.ts +0 -2
- package/x/deck/views/deck-overlay/component.js +0 -40
- package/x/deck/views/deck-overlay/component.js.map +0 -1
- package/x/deck/views/deck-overlay/style.css.js.map +0 -1
- package/x/deck/views/framework.d.ts +0 -3
- package/x/deck/views/framework.js +0 -8
- package/x/deck/views/framework.js.map +0 -1
- package/x/demo/ui/tact-demo/component.d.ts +0 -4
- package/x/demo/ui/tact-demo/component.js +0 -12
- package/x/demo/ui/tact-demo/component.js.map +0 -1
- package/x/demo/ui/tact-demo/style.css.js +0 -3
- package/x/demo/ui/tact-demo/style.css.js.map +0 -1
- /package/x/deck/{views/deck-overlay → components/deck-bindings}/style.css.d.ts +0 -0
- /package/x/{demo/ui/tact-demo → deck/components/deck-overlay}/style.css.d.ts +0 -0
- /package/x/deck/{views → components}/deck-overlay/style.css.js +0 -0
package/README.md
CHANGED
|
@@ -1,17 +1,4 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
3
|
-
> [!CAUTION]
|
|
4
|
-
> ### 🚨🚨 TACT IS UNDER DEVELOPMENT!! 🚨🚨
|
|
5
|
-
> *everything is half-broken right now.. just gimmie a minute to finish coding this, will ya?*
|
|
6
|
-
|
|
7
|
-
<br></br>
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
<br></br>
|
|
14
|
-
|
|
15
2
|
# 🎮 @benev/tact
|
|
16
3
|
> *web game input library, from keypress to couch co-op*
|
|
17
4
|
|
|
@@ -246,14 +233,16 @@ the deck ties together all the important pieces of tact into a single user exper
|
|
|
246
233
|
["code", "KeyA", {
|
|
247
234
|
scale: 1,
|
|
248
235
|
invert: false,
|
|
249
|
-
deadzone: 0,
|
|
250
236
|
timing: ["direct"],
|
|
251
237
|
}]
|
|
252
238
|
```
|
|
253
239
|
- defaults shown
|
|
254
240
|
- `scale` is sensitivity, the value gets multiplied by this
|
|
255
241
|
- `invert` will invert a value by subtracting it from 1
|
|
256
|
-
- `
|
|
242
|
+
- `clamp` clamps the value with a lower and upper bound
|
|
243
|
+
- `range` restricts value to the given range, and remaps that range 0 to 1
|
|
244
|
+
- `bottom` zeroes the value if it's less than the given bottom value
|
|
245
|
+
- `top` clamps the value to an upper bound
|
|
257
246
|
- `timing` lets you specify special timing considerations
|
|
258
247
|
- `["direct"]` ignores timing considerations
|
|
259
248
|
- `["tap", 250]` only fires for taps under 250ms
|
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",
|
|
4
4
|
"description": "keybindings and gamepad support for web games",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Chase Moskal <chasemoskal@gmail.com>",
|
|
@@ -29,21 +29,21 @@
|
|
|
29
29
|
"count": "find s -path '*/_archive' -prune -o -name '*.ts' -exec wc -l {} +"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"lit": "^3.3.
|
|
32
|
+
"lit": "^3.3.2"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@benev/math": "^0.2.0
|
|
35
|
+
"@benev/math": "^0.2.0",
|
|
36
36
|
"@e280/kv": "^0.1.0",
|
|
37
|
-
"@e280/sly": "^0.2.
|
|
38
|
-
"@e280/strata": "^0.2.
|
|
39
|
-
"@e280/stz": "^0.2.
|
|
37
|
+
"@e280/sly": "^0.2.5",
|
|
38
|
+
"@e280/strata": "^0.2.8",
|
|
39
|
+
"@e280/stz": "^0.2.24"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@e280/science": "^0.1.
|
|
43
|
-
"@e280/scute": "^0.1.
|
|
42
|
+
"@e280/science": "^0.1.8",
|
|
43
|
+
"@e280/scute": "^0.1.5",
|
|
44
44
|
"http-server": "^14.1.1",
|
|
45
45
|
"npm-run-all": "^4.1.5",
|
|
46
|
-
"typescript": "^5.9.
|
|
46
|
+
"typescript": "^5.9.3"
|
|
47
47
|
},
|
|
48
48
|
"repository": {
|
|
49
49
|
"type": "git",
|
|
@@ -3,10 +3,10 @@ import {Code, CodeSettings, CodeState} from "../types.js"
|
|
|
3
3
|
|
|
4
4
|
export const defaultHoldTime = 250
|
|
5
5
|
|
|
6
|
-
export function defaultCodeState([,,settings]: Code): CodeState {
|
|
6
|
+
export function defaultCodeState([,,settings]: Code, now: number): CodeState {
|
|
7
7
|
return {
|
|
8
8
|
lastValue: 0,
|
|
9
|
-
holdStart:
|
|
9
|
+
holdStart: now,
|
|
10
10
|
settings: defaultifyCodeSettings(settings),
|
|
11
11
|
}
|
|
12
12
|
}
|
|
@@ -15,6 +15,7 @@ function defaultCodeSettings(): CodeSettings {
|
|
|
15
15
|
return {
|
|
16
16
|
scale: 1,
|
|
17
17
|
invert: false,
|
|
18
|
+
clamp: null,
|
|
18
19
|
range: null,
|
|
19
20
|
bottom: null,
|
|
20
21
|
top: null,
|
|
@@ -13,6 +13,10 @@ export const lensAlgo = (
|
|
|
13
13
|
|
|
14
14
|
function clippings(value) {
|
|
15
15
|
const {settings} = state
|
|
16
|
+
if (settings.clamp) {
|
|
17
|
+
const [bottom, top] = settings.clamp
|
|
18
|
+
value = Scalar.clamp(value, bottom, top)
|
|
19
|
+
}
|
|
16
20
|
if (settings.range) {
|
|
17
21
|
const [bottom, top] = settings.range
|
|
18
22
|
value = Scalar.isBetween(value, bottom, top)
|
|
@@ -24,7 +28,7 @@ export const lensAlgo = (
|
|
|
24
28
|
)
|
|
25
29
|
: 0
|
|
26
30
|
}
|
|
27
|
-
if (settings.bottom) value =
|
|
31
|
+
if (settings.bottom) value = (value < settings.bottom) ? 0 : value
|
|
28
32
|
if (settings.top) value = Math.min(settings.top, value)
|
|
29
33
|
return value
|
|
30
34
|
},
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// // TODO
|
|
2
|
+
//
|
|
3
|
+
// import {Bindings} from "../types.js"
|
|
4
|
+
//
|
|
5
|
+
// export function makeLookupProxies<B extends Bindings>(
|
|
6
|
+
// bindings: B,
|
|
7
|
+
// ) {
|
|
8
|
+
//
|
|
9
|
+
// const getModeProxy = (mode: string) => new Proxy(bindings[mode], {
|
|
10
|
+
// get: (_, action: string) => {},
|
|
11
|
+
// })
|
|
12
|
+
//
|
|
13
|
+
// return new Proxy(bindings, {
|
|
14
|
+
// get: (_, mode: string) => getModeProxy(mode),
|
|
15
|
+
// })
|
|
16
|
+
// }
|
|
17
|
+
//
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
2
|
+
import {pub, obMap, GMap} from "@e280/stz"
|
|
3
3
|
import {Action} from "./action.js"
|
|
4
4
|
import {SampleMap} from "./sample-map.js"
|
|
5
5
|
import {lensAlgo} from "./parts/lens-algo.js"
|
|
@@ -12,7 +12,7 @@ export class Resolver<B extends Bindings> {
|
|
|
12
12
|
#modes = new Set<keyof B>()
|
|
13
13
|
#sampleMap = new SampleMap()
|
|
14
14
|
#now = 0
|
|
15
|
-
#codeStates = new
|
|
15
|
+
#codeStates = new GMap<string, CodeState>()
|
|
16
16
|
#update = pub()
|
|
17
17
|
|
|
18
18
|
constructor(public bindings: B) {
|
|
@@ -20,7 +20,7 @@ export class Resolver<B extends Bindings> {
|
|
|
20
20
|
const action = new Action()
|
|
21
21
|
this.#update.subscribe(() => {
|
|
22
22
|
action.value = this.#modes.has(mode)
|
|
23
|
-
? this.#resolveAtom()(atom)
|
|
23
|
+
? this.#resolveAtom([])(atom, mode as string)
|
|
24
24
|
: 0
|
|
25
25
|
})
|
|
26
26
|
return action
|
|
@@ -35,24 +35,31 @@ export class Resolver<B extends Bindings> {
|
|
|
35
35
|
return this.actions
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
#resolveCode(
|
|
38
|
+
#resolveCode(path: string[], code: string, settings?: Partial<CodeSettings>) {
|
|
39
39
|
const state = this.#codeStates.guarantee(
|
|
40
|
-
|
|
41
|
-
() => defaultCodeState(["code", code, settings]),
|
|
40
|
+
path.join("/"),
|
|
41
|
+
() => defaultCodeState(["code", code, settings], this.#now),
|
|
42
42
|
)
|
|
43
43
|
const value = this.#sampleMap.get(code) ?? 0
|
|
44
44
|
return lensAlgo(this.#now, state, value)
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
#resolveAtom = (
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
#resolveAtom = (path: string[]) => (atom: Atom, zone: string | number): number => {
|
|
48
|
+
const nextPath = [
|
|
49
|
+
...path,
|
|
50
|
+
String(zone),
|
|
51
|
+
typeof atom === "string" ? atom : atom[0],
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
const resolveAtom = this.#resolveAtom(nextPath)
|
|
55
|
+
|
|
56
|
+
if (typeof atom === "string")
|
|
57
|
+
return this.#resolveCode(nextPath, atom)
|
|
58
|
+
|
|
52
59
|
else switch (atom[0]) {
|
|
53
60
|
case "code": {
|
|
54
61
|
const [, code, settings] = atom
|
|
55
|
-
return this.#resolveCode(
|
|
62
|
+
return this.#resolveCode(nextPath, code, settings)
|
|
56
63
|
}
|
|
57
64
|
case "and": {
|
|
58
65
|
const [,...atoms] = atom
|
|
@@ -66,13 +73,13 @@ export class Resolver<B extends Bindings> {
|
|
|
66
73
|
}
|
|
67
74
|
case "not": {
|
|
68
75
|
const [, subject] = atom
|
|
69
|
-
const value = resolveAtom(subject)
|
|
76
|
+
const value = resolveAtom(subject, "subject")
|
|
70
77
|
return (value > 0) ? 0 : 1
|
|
71
78
|
}
|
|
72
79
|
case "cond": {
|
|
73
80
|
const [, subject, guard] = atom
|
|
74
|
-
return (resolveAtom(guard) > 0)
|
|
75
|
-
? resolveAtom(subject)
|
|
81
|
+
return (resolveAtom(guard, "guard") > 0)
|
|
82
|
+
? resolveAtom(subject, "subject")
|
|
76
83
|
: 0
|
|
77
84
|
}
|
|
78
85
|
case "mods": {
|
|
@@ -85,9 +92,9 @@ export class Resolver<B extends Bindings> {
|
|
|
85
92
|
maybe(modifiers.alt ?? false, "AltLeft", "AltRight"),
|
|
86
93
|
maybe(modifiers.meta ?? false, "MetaLeft", "MetaRight"),
|
|
87
94
|
maybe(modifiers.shift ?? false, "ShiftLeft", "ShiftRight"),
|
|
88
|
-
]])
|
|
95
|
+
]], "guard")
|
|
89
96
|
return (guard > 0)
|
|
90
|
-
? resolveAtom(subject)
|
|
97
|
+
? resolveAtom(subject, "subject")
|
|
91
98
|
: 0
|
|
92
99
|
}
|
|
93
100
|
}
|
package/s/core/bindings/types.ts
CHANGED
package/s/core/core.test.ts
CHANGED
|
@@ -24,6 +24,28 @@ export default Science.suite({
|
|
|
24
24
|
}
|
|
25
25
|
}),
|
|
26
26
|
|
|
27
|
+
"hold timing": test(async() => {
|
|
28
|
+
const {time, device, resolve} = testSetupAlpha()
|
|
29
|
+
{
|
|
30
|
+
time.frame = 1
|
|
31
|
+
device.setSample("KeyG", 0)
|
|
32
|
+
const actions = resolve()
|
|
33
|
+
expect(actions.basic.grenade.value).is(0)
|
|
34
|
+
}
|
|
35
|
+
{
|
|
36
|
+
time.frame = 2
|
|
37
|
+
device.setSample("KeyG", 1)
|
|
38
|
+
const actions = resolve()
|
|
39
|
+
expect(actions.basic.grenade.value).is(0)
|
|
40
|
+
}
|
|
41
|
+
{
|
|
42
|
+
time.frame = 15
|
|
43
|
+
device.setSample("KeyG", 1)
|
|
44
|
+
const actions = resolve()
|
|
45
|
+
expect(actions.basic.grenade.value).is(1)
|
|
46
|
+
}
|
|
47
|
+
}),
|
|
48
|
+
|
|
27
49
|
"hub": Science.suite({
|
|
28
50
|
"device inputs work": test(async() => {
|
|
29
51
|
const {hub, time} = testSetupBravo()
|
|
@@ -59,7 +59,7 @@ export class GamepadDevice extends SamplerDevice {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
#pollSticks(gamepad: Gamepad) {
|
|
62
|
-
const [leftX, leftY, rightX, rightY] = gamepad.axes
|
|
62
|
+
const [leftX = 0, leftY = 0, rightX = 0, rightY = 0] = gamepad.axes
|
|
63
63
|
|
|
64
64
|
const stickLeft = splitVector(
|
|
65
65
|
circularClamp(new Vec2(leftX, leftY), this.range)
|
|
@@ -31,6 +31,10 @@ export class PointerDevice extends SamplerDevice {
|
|
|
31
31
|
},
|
|
32
32
|
|
|
33
33
|
wheel: (event: WheelEvent) => {
|
|
34
|
+
this.sampleMap.set("pointer.wheel.right", 0)
|
|
35
|
+
this.sampleMap.set("pointer.wheel.left", 0)
|
|
36
|
+
this.sampleMap.set("pointer.wheel.up", 0)
|
|
37
|
+
this.sampleMap.set("pointer.wheel.down", 0)
|
|
34
38
|
for (const [code, value] of PointerDevice.wheelCodes(event))
|
|
35
39
|
this.setSample(code, value)
|
|
36
40
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {Hub} from "../hub/hub.js"
|
|
3
3
|
import {Port} from "../hub/port.js"
|
|
4
4
|
import {Device} from "../devices/device.js"
|
|
5
|
-
import {asBindings} from "../bindings/types.js"
|
|
5
|
+
import {asBindings, Code} from "../bindings/types.js"
|
|
6
6
|
import {Resolver} from "../bindings/resolver.js"
|
|
7
7
|
import {SampleMap} from "../bindings/sample-map.js"
|
|
8
8
|
import {SamplerDevice} from "../devices/infra/sampler.js"
|
|
@@ -20,6 +20,7 @@ export function testBindings() {
|
|
|
20
20
|
basic: {
|
|
21
21
|
jump: "Space",
|
|
22
22
|
shoot: "pointer.button.left",
|
|
23
|
+
grenade: <Code>["code", "KeyG", {timing: ["hold", 200]}]
|
|
23
24
|
},
|
|
24
25
|
})
|
|
25
26
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
import {ob} from "@e280/stz"
|
|
3
|
+
import {Deck} from "../deck.js"
|
|
4
|
+
import {DropFirstParam} from "../../utils/types.js"
|
|
5
|
+
import {DeckOverlay} from "./deck-overlay/component.js"
|
|
6
|
+
import {DeckBindings} from "./deck-bindings/component.js"
|
|
7
|
+
|
|
8
|
+
const components = {DeckOverlay, DeckBindings}
|
|
9
|
+
|
|
10
|
+
export const deckComponents = (deck: Deck<any>) => (
|
|
11
|
+
ob(components)
|
|
12
|
+
.map(C => class extends C { deck = deck })
|
|
13
|
+
) as DeckComponents
|
|
14
|
+
|
|
15
|
+
export type DeckComponents = typeof components
|
|
16
|
+
|
|
17
|
+
export type DeckViews = {
|
|
18
|
+
[P in keyof DeckComponents]: (
|
|
19
|
+
DropFirstParam<DeckComponents[P]["view"]>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
|
|
2
|
+
import {html} from "lit"
|
|
3
|
+
import {Bytename} from "@e280/stz"
|
|
4
|
+
import {cssReset, view} from "@e280/sly"
|
|
5
|
+
|
|
6
|
+
import {Deck} from "../../deck.js"
|
|
7
|
+
import styleCss from "./style.css.js"
|
|
8
|
+
import {DeckComponent} from "../framework.js"
|
|
9
|
+
import {Port} from "../../../core/hub/port.js"
|
|
10
|
+
import {Profile} from "../../parts/catalog.js"
|
|
11
|
+
import {Atom, Bindings, Bracket} from "../../../core/bindings/types.js"
|
|
12
|
+
|
|
13
|
+
export class DeckBindings extends (
|
|
14
|
+
view(use => (deck: Deck<any>) => {
|
|
15
|
+
use.css(cssReset, styleCss)
|
|
16
|
+
use.attrs.strings.deck = "bindings"
|
|
17
|
+
const {db, hub} = deck
|
|
18
|
+
|
|
19
|
+
const catalog = db.$catalog()
|
|
20
|
+
const defaultProfile: Profile = {id: "default", label: "default", bindings: deck.baseBindings}
|
|
21
|
+
const allProfiles = [defaultProfile, ...catalog.profiles.values()]
|
|
22
|
+
const $selectedProfileId = use.signal<string>("default")
|
|
23
|
+
const profile = db.$catalog().getProfile($selectedProfileId()) ?? defaultProfile
|
|
24
|
+
|
|
25
|
+
function renderPort(port: Port<Bindings>, index: number) {
|
|
26
|
+
const portProfile = catalog.getProfileForPort(index) ?? defaultProfile
|
|
27
|
+
return html`
|
|
28
|
+
<div class=port>
|
|
29
|
+
<span>port ${index + 1}</span>
|
|
30
|
+
<select>
|
|
31
|
+
${allProfiles.map(profile => html`
|
|
32
|
+
<option
|
|
33
|
+
data-id="${profile.id}"
|
|
34
|
+
?selected="${profile.id === portProfile.id}">
|
|
35
|
+
${profile.label}
|
|
36
|
+
</option>
|
|
37
|
+
`)}
|
|
38
|
+
</select>
|
|
39
|
+
</div>
|
|
40
|
+
`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function renderBindingBracket([mode, bracket]: [mode: string, bracket: Bracket]) {
|
|
44
|
+
return html`
|
|
45
|
+
<div class=bracket>
|
|
46
|
+
<strong class=mode>${mode}</strong>
|
|
47
|
+
<div>${Object.entries(bracket).map(renderBinds)}</div>
|
|
48
|
+
</div>
|
|
49
|
+
`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function renderBinds([action, atom]: [action: string, atom: Atom]) {
|
|
53
|
+
return html`
|
|
54
|
+
<div class=bind>
|
|
55
|
+
<span class=action>${action}</span>
|
|
56
|
+
</div>
|
|
57
|
+
`
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const clickClone = async() => {
|
|
61
|
+
const {bindings} = profile
|
|
62
|
+
const label = Bytename.random(4)
|
|
63
|
+
const p = await db.createProfile(label, bindings)
|
|
64
|
+
$selectedProfileId(p.id)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const deleteProfile = (id: string) => async() => {
|
|
68
|
+
await db.deleteProfile(id)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const onSelected = (event: InputEvent) => {
|
|
72
|
+
const select = event.target as HTMLSelectElement
|
|
73
|
+
const id = select.value
|
|
74
|
+
$selectedProfileId(id)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return html`
|
|
78
|
+
<div class=portlist>
|
|
79
|
+
${hub.ports.map(renderPort)}
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div class=bindable>
|
|
83
|
+
<select @input="${onSelected}">
|
|
84
|
+
${allProfiles.map(p => html`
|
|
85
|
+
<option value="${p.id}" ?selected="${p.id === profile.id}">${p.label}</option>
|
|
86
|
+
`)}
|
|
87
|
+
</select>
|
|
88
|
+
<button @click="${clickClone}">clone</button>
|
|
89
|
+
<button ?disabled="${profile.id === defaultProfile.id}" @click="${deleteProfile(profile.id)}">delete</button>
|
|
90
|
+
<div class=bindings>
|
|
91
|
+
${Object.entries(profile.bindings).map(renderBindingBracket)}
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
`
|
|
95
|
+
})
|
|
96
|
+
.component(DeckComponent)
|
|
97
|
+
.props(el => [el.deck])
|
|
98
|
+
) {}
|
|
99
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
|
|
2
|
+
import {html} from "lit"
|
|
3
|
+
import {cssReset, view} from "@e280/sly"
|
|
4
|
+
import {Deck} from "../../deck.js"
|
|
5
|
+
import styleCss from "./style.css.js"
|
|
6
|
+
import {DeckComponent} from "../framework.js"
|
|
7
|
+
import {Device} from "../../../core/devices/device.js"
|
|
8
|
+
|
|
9
|
+
export class DeckOverlay extends (
|
|
10
|
+
view(use => (deck: Deck<any>) => {
|
|
11
|
+
use.css(cssReset, styleCss)
|
|
12
|
+
use.attrs.strings.deck = "overlay"
|
|
13
|
+
const {hub, deviceSkins, overlayVisibility: {$visible, $showLabels}} = deck
|
|
14
|
+
|
|
15
|
+
function renderDevice(device: Device) {
|
|
16
|
+
const skin = deviceSkins.get(device)
|
|
17
|
+
const style = `--color: ${skin.color};`
|
|
18
|
+
const next = () => hub.shimmy(device, 1)
|
|
19
|
+
const previous = () => hub.shimmy(device, -1)
|
|
20
|
+
return html`
|
|
21
|
+
<div class=device style="${style}">
|
|
22
|
+
<div class="primary row">
|
|
23
|
+
<button @click="${previous}"><</button>
|
|
24
|
+
<div class=icon>${skin.icon}</div>
|
|
25
|
+
<button @click="${next}">></button>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
${$showLabels() ? html`
|
|
29
|
+
<div class="secondary row">
|
|
30
|
+
<div class=label>${skin.label}</div>
|
|
31
|
+
</div>
|
|
32
|
+
` : null}
|
|
33
|
+
</div>
|
|
34
|
+
`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return html`
|
|
38
|
+
<div class=portlist ?data-active="${$visible()}">
|
|
39
|
+
${hub.ports.map((port, index) => html`
|
|
40
|
+
<div class=port>
|
|
41
|
+
<header>P${index + 1}</header>
|
|
42
|
+
${port.devices.array().map(renderDevice)}
|
|
43
|
+
</div>
|
|
44
|
+
`)}
|
|
45
|
+
</div>
|
|
46
|
+
`
|
|
47
|
+
})
|
|
48
|
+
.component(DeckComponent)
|
|
49
|
+
.props(el => [el.deck])
|
|
50
|
+
) {}
|
|
51
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import {BaseElement} from "@e280/sly"
|
|
3
|
+
import {Deck} from "../deck.js"
|
|
4
|
+
|
|
5
|
+
export class DeckComponent extends BaseElement {
|
|
6
|
+
#deck: Deck<any> | undefined
|
|
7
|
+
|
|
8
|
+
get deck() {
|
|
9
|
+
if (!this.#deck) throw new Error(".deck was not set on component, but is required")
|
|
10
|
+
return this.#deck
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
set deck(d: Deck<any>) {
|
|
14
|
+
this.#deck = d
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
package/s/deck/deck.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import {Kv} from "@e280/kv"
|
|
3
|
+
import {dom} from "@e280/sly"
|
|
3
4
|
import {disposer, ob, range} from "@e280/stz"
|
|
4
5
|
|
|
5
6
|
import {Db} from "./parts/db.js"
|
|
@@ -8,13 +9,11 @@ import {Port} from "../core/hub/port.js"
|
|
|
8
9
|
import {Bindings} from "../core/bindings/types.js"
|
|
9
10
|
import {mergeBindings} from "./parts/merge-bindings.js"
|
|
10
11
|
import {MetaBindings, metaMode} from "../core/hub/types.js"
|
|
11
|
-
import {autoGamepads} from "../core/devices/auto-gamepads.js"
|
|
12
|
-
import {DeckOverlay} from "./views/deck-overlay/component.js"
|
|
13
12
|
import {makeMetaBindings} from "../core/hub/meta-bindings.js"
|
|
14
13
|
import {DeviceSkins} from "./parts/device-skins/device-skin.js"
|
|
15
14
|
import {OverlayVisibility} from "./parts/overlay-visibility.js"
|
|
16
15
|
import {PrimaryDevice} from "../core/devices/standard/primary.js"
|
|
17
|
-
import {
|
|
16
|
+
import {deckComponents, DeckViews} from "./components/components.js"
|
|
18
17
|
|
|
19
18
|
export type DeckOptions<B extends Bindings, MB extends MetaBindings = any> = {
|
|
20
19
|
kv: Kv
|
|
@@ -39,22 +38,28 @@ export class Deck<B extends Bindings, MB extends MetaBindings = any> {
|
|
|
39
38
|
?? makeMetaBindings(),
|
|
40
39
|
)
|
|
41
40
|
|
|
42
|
-
return new this(hub, db)
|
|
41
|
+
return new this(options.bindings, options.metaBindings, hub, db)
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
dispose = disposer()
|
|
46
45
|
deviceSkins = new DeviceSkins()
|
|
47
|
-
overlayVisibility: OverlayVisibility
|
|
48
46
|
primaryDevice = new PrimaryDevice()
|
|
47
|
+
overlayVisibility: OverlayVisibility
|
|
48
|
+
|
|
49
|
+
components = deckComponents(this)
|
|
49
50
|
|
|
50
|
-
views =
|
|
51
|
-
|
|
51
|
+
views = (
|
|
52
|
+
ob(this.components as any)
|
|
53
|
+
.map(c => (...a: any[]) => c.view(this, ...a))
|
|
54
|
+
) as DeckViews
|
|
52
55
|
|
|
53
56
|
registerComponents() {
|
|
54
57
|
dom.register(this.components)
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
constructor(
|
|
61
|
+
public baseBindings: B,
|
|
62
|
+
public baseMetaBindings: MB,
|
|
58
63
|
public hub: Hub<B, MB>,
|
|
59
64
|
public db: Db,
|
|
60
65
|
) {
|
package/s/deck/index.ts
CHANGED
|
@@ -7,8 +7,8 @@ export * from "./parts/local-storage-kv.js"
|
|
|
7
7
|
export * from "./parts/merge-bindings.js"
|
|
8
8
|
export * from "./parts/overlay-visibility.js"
|
|
9
9
|
|
|
10
|
-
export * from "./
|
|
11
|
-
export * from "./
|
|
10
|
+
export * from "./components/deck-overlay/component.js"
|
|
11
|
+
export * from "./components/deck-overlay/style.css.js"
|
|
12
12
|
|
|
13
13
|
export * from "./deck.js"
|
|
14
14
|
|
package/s/deck/parts/db.ts
CHANGED
|
@@ -57,7 +57,7 @@ export class Db {
|
|
|
57
57
|
})
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
async
|
|
60
|
+
async assignPortProfile(index: number, profileId: string | null) {
|
|
61
61
|
return this.#mutateAndSave(catalog => {
|
|
62
62
|
catalog.portProfiles[index] = profileId
|
|
63
63
|
})
|
package/s/demo/main.bundle.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
|
|
2
2
|
import {dom} from "@e280/sly"
|
|
3
|
-
import {
|
|
3
|
+
import {Game} from "./game/game.js"
|
|
4
|
+
import {DemoTheater} from "./ui/theater/view.js"
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
const game = await Game.load()
|
|
7
|
+
|
|
8
|
+
dom.register({
|
|
9
|
+
DemoTheater: class extends DemoTheater { game = game },
|
|
10
|
+
})
|
|
6
11
|
|
|
7
12
|
console.log("🎮 tact")
|
|
8
13
|
|