@benev/tact 0.1.0-4 → 0.1.0-5

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 (99) hide show
  1. package/README.md +4 -3
  2. package/package.json +4 -4
  3. package/s/core/bindings/parts/defaults.ts +1 -0
  4. package/s/core/bindings/parts/lens-algo.ts +5 -1
  5. package/s/core/bindings/parts/lookup-proxies.ts +17 -0
  6. package/s/core/bindings/types.ts +1 -0
  7. package/s/core/devices/standard/gamepad.ts +1 -1
  8. package/s/core/devices/standard/pointer.ts +4 -0
  9. package/s/deck/components/components.ts +22 -0
  10. package/s/deck/components/deck-bindings/component.ts +99 -0
  11. package/s/{demo/ui/tact-demo → deck/components/deck-bindings}/style.css.ts +3 -1
  12. package/s/deck/components/deck-overlay/component.ts +51 -0
  13. package/s/deck/{views → components}/deck-overlay/style.css.ts +0 -2
  14. package/s/deck/components/framework.ts +17 -0
  15. package/s/deck/deck.ts +12 -7
  16. package/s/deck/index.ts +2 -2
  17. package/s/deck/parts/db.ts +1 -1
  18. package/s/demo/main.bundle.ts +7 -2
  19. package/s/demo/ui/theater/styles.css.ts +1 -0
  20. package/s/demo/ui/theater/view.ts +51 -44
  21. package/s/demo/ui/theater/virtual/view.ts +1 -1
  22. package/s/demo/ui/utils/loader.ts +2 -2
  23. package/s/index.html.ts +1 -1
  24. package/s/nubs/vpad/styles.css.ts +4 -4
  25. package/s/utils/types.ts +19 -0
  26. package/x/core/bindings/parts/defaults.js +1 -0
  27. package/x/core/bindings/parts/defaults.js.map +1 -1
  28. package/x/core/bindings/parts/lens-algo.js +5 -1
  29. package/x/core/bindings/parts/lens-algo.js.map +1 -1
  30. package/x/core/bindings/parts/lookup-proxies.d.ts +1 -0
  31. package/x/core/bindings/parts/lookup-proxies.js +19 -0
  32. package/x/core/bindings/parts/lookup-proxies.js.map +1 -0
  33. package/x/core/bindings/types.d.ts +1 -0
  34. package/x/core/devices/standard/gamepad.js +1 -1
  35. package/x/core/devices/standard/gamepad.js.map +1 -1
  36. package/x/core/devices/standard/pointer.js +4 -0
  37. package/x/core/devices/standard/pointer.js.map +1 -1
  38. package/x/deck/components/components.d.ts +14 -0
  39. package/x/deck/components/components.js +9 -0
  40. package/x/deck/components/components.js.map +1 -0
  41. package/x/deck/components/deck-bindings/component.d.ts +6 -0
  42. package/x/deck/components/deck-bindings/component.js +83 -0
  43. package/x/deck/components/deck-bindings/component.js.map +1 -0
  44. package/x/deck/components/deck-bindings/style.css.js +5 -0
  45. package/x/deck/components/deck-bindings/style.css.js.map +1 -0
  46. package/x/deck/components/deck-overlay/component.d.ts +6 -0
  47. package/x/deck/components/deck-overlay/component.js +44 -0
  48. package/x/deck/components/deck-overlay/component.js.map +1 -0
  49. package/x/deck/components/deck-overlay/style.css.js.map +1 -0
  50. package/x/deck/components/framework.d.ts +7 -0
  51. package/x/deck/components/framework.js +13 -0
  52. package/x/deck/components/framework.js.map +1 -0
  53. package/x/deck/deck.d.ts +8 -6
  54. package/x/deck/deck.js +12 -7
  55. package/x/deck/deck.js.map +1 -1
  56. package/x/deck/index.d.ts +2 -2
  57. package/x/deck/index.js +2 -2
  58. package/x/deck/index.js.map +1 -1
  59. package/x/deck/parts/db.d.ts +1 -1
  60. package/x/deck/parts/db.js +1 -1
  61. package/x/deck/parts/db.js.map +1 -1
  62. package/x/demo/main.bundle.js +8 -2
  63. package/x/demo/main.bundle.js.map +1 -1
  64. package/x/demo/main.bundle.min.js +90 -45
  65. package/x/demo/main.bundle.min.js.map +4 -4
  66. package/x/demo/ui/theater/styles.css.js +1 -0
  67. package/x/demo/ui/theater/styles.css.js.map +1 -1
  68. package/x/demo/ui/theater/view.d.ts +367 -1
  69. package/x/demo/ui/theater/view.js +25 -17
  70. package/x/demo/ui/theater/view.js.map +1 -1
  71. package/x/demo/ui/theater/virtual/view.js +1 -1
  72. package/x/demo/ui/theater/virtual/view.js.map +1 -1
  73. package/x/demo/ui/utils/loader.d.ts +2 -1
  74. package/x/demo/ui/utils/loader.js +2 -2
  75. package/x/demo/ui/utils/loader.js.map +1 -1
  76. package/x/index.html +3 -3
  77. package/x/index.html.js +1 -1
  78. package/x/nubs/vpad/styles.css.js +4 -4
  79. package/x/utils/types.d.ts +3 -0
  80. package/x/utils/types.js +3 -0
  81. package/x/utils/types.js.map +1 -0
  82. package/s/deck/views/deck-overlay/component.ts +0 -48
  83. package/s/deck/views/framework.ts +0 -14
  84. package/s/demo/ui/tact-demo/component.ts +0 -13
  85. package/x/deck/views/deck-overlay/component.d.ts +0 -2
  86. package/x/deck/views/deck-overlay/component.js +0 -40
  87. package/x/deck/views/deck-overlay/component.js.map +0 -1
  88. package/x/deck/views/deck-overlay/style.css.js.map +0 -1
  89. package/x/deck/views/framework.d.ts +0 -3
  90. package/x/deck/views/framework.js +0 -8
  91. package/x/deck/views/framework.js.map +0 -1
  92. package/x/demo/ui/tact-demo/component.d.ts +0 -4
  93. package/x/demo/ui/tact-demo/component.js +0 -12
  94. package/x/demo/ui/tact-demo/component.js.map +0 -1
  95. package/x/demo/ui/tact-demo/style.css.js +0 -3
  96. package/x/demo/ui/tact-demo/style.css.js.map +0 -1
  97. /package/x/deck/{views/deck-overlay → components/deck-bindings}/style.css.d.ts +0 -0
  98. /package/x/{demo/ui/tact-demo → deck/components/deck-overlay}/style.css.d.ts +0 -0
  99. /package/x/deck/{views → components}/deck-overlay/style.css.js +0 -0
package/README.md CHANGED
@@ -1,5 +1,4 @@
1
1
 
2
-
3
2
  > [!CAUTION]
4
3
  > ### 🚨🚨 TACT IS UNDER DEVELOPMENT!! 🚨🚨
5
4
  > *everything is half-broken right now.. just gimmie a minute to finish coding this, will ya?*
@@ -246,14 +245,16 @@ the deck ties together all the important pieces of tact into a single user exper
246
245
  ["code", "KeyA", {
247
246
  scale: 1,
248
247
  invert: false,
249
- deadzone: 0,
250
248
  timing: ["direct"],
251
249
  }]
252
250
  ```
253
251
  - defaults shown
254
252
  - `scale` is sensitivity, the value gets multiplied by this
255
253
  - `invert` will invert a value by subtracting it from 1
256
- - `deadzone` ignores values below the threshold (and remaps to preserve the range)
254
+ - `clamp` clamps the value with a lower and upper bound
255
+ - `range` restricts value to the given range, and remaps that range 0 to 1
256
+ - `bottom` zeroes the value if it's less than the given bottom value
257
+ - `top` clamps the value to an upper bound
257
258
  - `timing` lets you specify special timing considerations
258
259
  - `["direct"]` ignores timing considerations
259
260
  - `["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-4",
3
+ "version": "0.1.0-5",
4
4
  "description": "keybindings and gamepad support for web games",
5
5
  "license": "MIT",
6
6
  "author": "Chase Moskal <chasemoskal@gmail.com>",
@@ -34,9 +34,9 @@
34
34
  "dependencies": {
35
35
  "@benev/math": "^0.2.0-4",
36
36
  "@e280/kv": "^0.1.0",
37
- "@e280/sly": "^0.2.0-16",
38
- "@e280/strata": "^0.2.0-13",
39
- "@e280/stz": "^0.2.5"
37
+ "@e280/sly": "^0.2.0-24",
38
+ "@e280/strata": "^0.2.0-14",
39
+ "@e280/stz": "^0.2.7"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@e280/science": "^0.1.2",
@@ -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 = Math.max(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
+ //
@@ -34,6 +34,7 @@ export type Atom = string | (
34
34
  export type CodeSettings = {
35
35
  scale: number
36
36
  invert: boolean
37
+ clamp: null | [number, number]
37
38
  range: null | [number, number]
38
39
  bottom: null | number
39
40
  top: null | number
@@ -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
  },
@@ -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
+
@@ -1,4 +1,6 @@
1
1
 
2
2
  import {css} from "lit"
3
- export default css``
3
+ export default css`
4
+
5
+ `
4
6
 
@@ -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}">&lt;</button>
24
+ <div class=icon>${skin.icon}</div>
25
+ <button @click="${next}">&gt;</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
+
@@ -108,5 +108,3 @@ export default css`
108
108
 
109
109
  `
110
110
 
111
-
112
-
@@ -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 { dom } from "@e280/sly"
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 = ob({DeckOverlay}).map(fn => fn(this))
51
- components = ob(this.views).map(v => v.component().props(_c => []))
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 "./views/deck-overlay/component.js"
11
- export * from "./views/deck-overlay/style.css.js"
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
 
@@ -57,7 +57,7 @@ export class Db {
57
57
  })
58
58
  }
59
59
 
60
- async assignPortToProfile(index: number, profileId: string | null) {
60
+ async assignPortProfile(index: number, profileId: string | null) {
61
61
  return this.#mutateAndSave(catalog => {
62
62
  catalog.portProfiles[index] = profileId
63
63
  })
@@ -1,8 +1,13 @@
1
1
 
2
2
  import {dom} from "@e280/sly"
3
- import {TactDemo} from "./ui/tact-demo/component.js"
3
+ import {Game} from "./game/game.js"
4
+ import {DemoTheater} from "./ui/theater/view.js"
4
5
 
5
- dom.register({TactDemo})
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
 
@@ -40,6 +40,7 @@ export const styles = css`
40
40
  right: 0;
41
41
 
42
42
  display: flex;
43
+ flex-direction: column;
43
44
  justify-content: center;
44
45
  align-items: center;
45
46
  }
@@ -1,53 +1,60 @@
1
1
 
2
2
  import {html} from "lit"
3
- import {cssReset, view} from "@e280/sly"
4
3
  import {repeat} from "lit/directives/repeat.js"
4
+ import {BaseElement, cssReset, view} from "@e280/sly"
5
5
 
6
6
  import {styles} from "./styles.css.js"
7
7
  import {Game} from "../../game/game.js"
8
8
  import {VirtualDeviceView} from "./virtual/view.js"
9
9
  import {VirtualDevice} from "../../game/parts/virtual-device.js"
10
-
11
- export const Theater = view(use => (game: Game) => {
12
- use.css(cssReset, styles)
13
- use.mount(() => game.loop(60))
14
- use.mount(() => game.deck.hub.on(use.render))
15
-
16
- const addVirtual = () => game.plug(new VirtualDevice(game.deck.hub))
17
- const revealOverlay = () => game.deck.overlayVisibility.bump()
18
-
19
- const virtualDevices = game.deck.hub.ports
20
- .flatMap(port => port.devices.array())
21
- .filter(device => device instanceof VirtualDevice)
22
- .map(device => ({device, skin: game.deck.deviceSkins.get(device)}))
23
- .sort((a, b) => a.skin.label < b.skin.label ? -1 : 1)
24
-
25
- return html`
26
- <div class=surface>
27
- ${game.renderer.canvas}
28
- ${game.deck.views.DeckOverlay()}
29
- </div>
30
-
31
- <div class=dlist>
32
- ${repeat(
33
- virtualDevices,
34
- d => d.skin.label,
35
- ({device, skin}) => {
36
- return VirtualDeviceView
37
- .props(game.deck.hub, device, skin)
38
- .attr("style", `--color: ${skin.color};`)
39
- .render()
40
- },
41
- )}
42
-
43
- <button @click="${addVirtual}">
44
-
45
- </button>
46
-
47
- <button @click="${revealOverlay}">
48
- 👁️
49
- </button>
50
- </div>
51
- `
52
- })
10
+ import {DeckBindings} from "../../../deck/components/deck-bindings/component.js"
11
+
12
+ export class DemoTheater extends (
13
+ view(use => (game: Game) => {
14
+ use.css(cssReset, styles)
15
+ use.mount(() => game.loop(60))
16
+ use.mount(() => game.deck.hub.on(use.render))
17
+
18
+ const addVirtual = () => game.plug(new VirtualDevice(game.deck.hub))
19
+ const revealOverlay = () => game.deck.overlayVisibility.bump()
20
+
21
+ const virtualDevices = game.deck.hub.ports
22
+ .flatMap(port => port.devices.array())
23
+ .filter(device => device instanceof VirtualDevice)
24
+ .map(device => ({device, skin: game.deck.deviceSkins.get(device)}))
25
+ .sort((a, b) => a.skin.label < b.skin.label ? -1 : 1)
26
+
27
+ return html`
28
+ <div class=surface>
29
+ ${game.renderer.canvas}
30
+ ${game.deck.views.DeckOverlay()}
31
+ </div>
32
+
33
+ <div class=dlist>
34
+ ${repeat(
35
+ virtualDevices,
36
+ d => d.skin.label,
37
+ ({device, skin}) => {
38
+ return VirtualDeviceView
39
+ .props(game.deck.hub, device, skin)
40
+ .attr("style", `--color: ${skin.color};`)
41
+ .render()
42
+ },
43
+ )}
44
+
45
+ <button @click="${addVirtual}">
46
+
47
+ </button>
48
+
49
+ <button @click="${revealOverlay}">
50
+ 👁️
51
+ </button>
52
+ </div>
53
+
54
+ ${DeckBindings.view(game.deck)}
55
+ `
56
+ })
57
+ .component(class extends BaseElement { game!: Game })
58
+ .props(el => [el.game])
59
+ ) {}
53
60
 
@@ -14,7 +14,7 @@ export const VirtualDeviceView = view(use => (
14
14
  ) => {
15
15
 
16
16
  use.styles(cssReset, styleCss)
17
- use.attrs.string.device = "virtual"
17
+ use.attrs.strings.device = "virtual"
18
18
 
19
19
  const unplug = () => hub.unplug(device)
20
20
 
@@ -1,5 +1,5 @@
1
1
 
2
- import {makeLoader} from "@e280/sly"
2
+ import {loaders} from "@e280/sly"
3
3
 
4
- export const loader = makeLoader()
4
+ export const loader = loaders.make()
5
5
 
package/s/index.html.ts CHANGED
@@ -37,7 +37,7 @@ export default ssg.page(import.meta.url, async orb => ({
37
37
  </div>
38
38
  </header>
39
39
 
40
- <tact-demo></tact-demo>
40
+ <demo-theater></demo-theater>
41
41
 
42
42
  <section>
43
43
  <h3>controls</h3>
@@ -85,11 +85,11 @@ button {
85
85
  flex-direction: row-reverse;
86
86
  }
87
87
 
88
- [x-code^="g.trigger"] {
88
+ [x-code^="gamepad.trigger"] {
89
89
  width: 6em;
90
90
  }
91
91
 
92
- [x-code^="g.bumper"] {
92
+ [x-code^="gamepad.bumper"] {
93
93
  width: 4em;
94
94
  }
95
95
 
@@ -121,11 +121,11 @@ button {
121
121
  width: max(15cqw, 15cqh);
122
122
  }
123
123
 
124
- [x-code^="g.trigger"] {
124
+ [x-code^="gamepad.trigger"] {
125
125
  width: 9cqw;
126
126
  }
127
127
 
128
- [x-code^="g.bumper"] {
128
+ [x-code^="gamepad.bumper"] {
129
129
  width: 7cqw;
130
130
  }
131
131
  }
@@ -0,0 +1,19 @@
1
+
2
+ // TODO replace these types when they're available in stz
3
+
4
+ export type First<A extends any[]> = (
5
+ A extends [infer X, ...any[]]
6
+ ? X
7
+ : never
8
+ )
9
+
10
+ export type DropFirst<A extends any[]> = (
11
+ A extends [any, ...infer X]
12
+ ? X
13
+ : never
14
+ )
15
+
16
+ export type DropFirstParam<Fn extends (...params: any[]) => any> = (
17
+ (...params: DropFirst<Parameters<Fn>>) => ReturnType<Fn>
18
+ )
19
+
@@ -10,6 +10,7 @@ function defaultCodeSettings() {
10
10
  return {
11
11
  scale: 1,
12
12
  invert: false,
13
+ clamp: null,
13
14
  range: null,
14
15
  bottom: null,
15
16
  top: null,
@@ -1 +1 @@
1
- {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../../../s/core/bindings/parts/defaults.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAA;AAElC,MAAM,UAAU,gBAAgB,CAAC,CAAC,EAAC,EAAC,QAAQ,CAAO;IAClD,OAAO;QACN,SAAS,EAAE,CAAC;QACZ,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,sBAAsB,CAAC,QAAQ,CAAC;KAC1C,CAAA;AACF,CAAC;AAED,SAAS,mBAAmB;IAC3B,OAAO;QACN,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,KAAK;QACb,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,IAAI;QACT,MAAM,EAAE,CAAC,QAAQ,CAAC;KAClB,CAAA;AACF,CAAC;AAED,SAAS,sBAAsB,CAAC,UAAiC,EAAE;IAClE,OAAO;QACN,GAAG,mBAAmB,EAAE;QACxB,GAAG,OAAO;KACV,CAAA;AACF,CAAC"}
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../../../s/core/bindings/parts/defaults.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAA;AAElC,MAAM,UAAU,gBAAgB,CAAC,CAAC,EAAC,EAAC,QAAQ,CAAO;IAClD,OAAO;QACN,SAAS,EAAE,CAAC;QACZ,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,sBAAsB,CAAC,QAAQ,CAAC;KAC1C,CAAA;AACF,CAAC;AAED,SAAS,mBAAmB;IAC3B,OAAO;QACN,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,KAAK;QACb,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,IAAI;QACT,MAAM,EAAE,CAAC,QAAQ,CAAC;KAClB,CAAA;AACF,CAAC;AAED,SAAS,sBAAsB,CAAC,UAAiC,EAAE;IAClE,OAAO;QACN,GAAG,mBAAmB,EAAE;QACxB,GAAG,OAAO;KACV,CAAA;AACF,CAAC"}
@@ -4,6 +4,10 @@ import { isPressed } from "./is-pressed.js";
4
4
  import { defaultHoldTime } from "./defaults.js";
5
5
  export const lensAlgo = (now, state, v) => pipe(v).line(function clippings(value) {
6
6
  const { settings } = state;
7
+ if (settings.clamp) {
8
+ const [bottom, top] = settings.clamp;
9
+ value = Scalar.clamp(value, bottom, top);
10
+ }
7
11
  if (settings.range) {
8
12
  const [bottom, top] = settings.range;
9
13
  value = Scalar.isBetween(value, bottom, top)
@@ -11,7 +15,7 @@ export const lensAlgo = (now, state, v) => pipe(v).line(function clippings(value
11
15
  : 0;
12
16
  }
13
17
  if (settings.bottom)
14
- value = Math.max(settings.bottom, value);
18
+ value = (value < settings.bottom) ? 0 : value;
15
19
  if (settings.top)
16
20
  value = Math.min(settings.top, value);
17
21
  return value;