@diffenderfer-games/hub 2.0.0-next.0 → 2.0.0-next.10
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/CHANGELOG.md +163 -0
- package/LICENSE +21 -21
- package/README.md +203 -139
- package/dist/auto.d.ts +8 -8
- package/dist/auto.js +3 -3
- package/dist/avatar-pixi.d.ts +165 -0
- package/dist/avatar-pixi.d.ts.map +1 -0
- package/dist/avatar-pixi.js +299 -0
- package/dist/avatar-pixi.js.map +1 -0
- package/dist/avatar-svg.d.ts +4 -0
- package/dist/avatar-svg.js +5 -0
- package/dist/avatar-three.d.ts +69 -0
- package/dist/avatar-three.d.ts.map +1 -0
- package/dist/avatar-three.js +49 -0
- package/dist/avatar-three.js.map +1 -0
- package/dist/avatar.d.ts +7 -0
- package/dist/avatar.js +500 -0
- package/dist/avatar.js.map +1 -0
- package/dist/daily.d.ts +2 -2
- package/dist/doctor/cli.mjs +119 -28
- package/dist/doctor/cli.mjs.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +3 -3
- package/dist/input.d.ts +2 -2
- package/dist/input.js +2 -2
- package/dist/mp.d.ts +3 -3
- package/dist/race.d.ts +1 -1
- package/dist/rooms.d.ts +3 -3
- package/dist/rooms.js +1 -1
- package/dist/shared/animator.d.ts +104 -0
- package/dist/shared/animator.d.ts.map +1 -0
- package/dist/shared/art.js +1946 -0
- package/dist/shared/art.js.map +1 -0
- package/dist/shared/atlas.d.ts +138 -0
- package/dist/shared/atlas.d.ts.map +1 -0
- package/dist/shared/avatar.d.ts +123 -0
- package/dist/shared/avatar.d.ts.map +1 -0
- package/dist/shared/bridge.js +18 -4
- package/dist/shared/bridge.js.map +1 -1
- package/dist/shared/client-version.gen.js +1 -1
- package/dist/shared/daily.d.ts +145 -19
- package/dist/shared/daily.d.ts.map +1 -1
- package/dist/shared/daily.js +138 -25
- package/dist/shared/daily.js.map +1 -1
- package/dist/shared/defineProperty.js +39 -0
- package/dist/shared/describe.d.ts +32 -0
- package/dist/shared/describe.d.ts.map +1 -0
- package/dist/shared/describe.js +109 -0
- package/dist/shared/describe.js.map +1 -0
- package/dist/shared/globals.js +9 -42
- package/dist/shared/globals.js.map +1 -1
- package/dist/shared/index.d.ts +1122 -46
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/input.d.ts +74 -14
- package/dist/shared/input.d.ts.map +1 -1
- package/dist/shared/input.js +179 -25
- package/dist/shared/input.js.map +1 -1
- package/dist/shared/json-guards.js +48 -0
- package/dist/shared/json-guards.js.map +1 -0
- package/dist/shared/latest-state.js +1 -1
- package/dist/shared/live-canvas.js +62 -0
- package/dist/shared/live-canvas.js.map +1 -0
- package/dist/shared/mp.js +10 -2
- package/dist/shared/mp.js.map +1 -1
- package/dist/shared/multiplayer-types.d.ts +15 -2
- package/dist/shared/multiplayer-types.d.ts.map +1 -1
- package/dist/shared/overlays.js +800 -0
- package/dist/shared/overlays.js.map +1 -0
- package/dist/shared/page-stack.js +2 -1
- package/dist/shared/page-stack.js.map +1 -1
- package/dist/shared/pose-key.js +249 -0
- package/dist/shared/pose-key.js.map +1 -0
- package/dist/shared/race-types.d.ts +1 -1
- package/dist/shared/race.js +1 -1
- package/dist/shared/room-types.d.ts +28 -3
- package/dist/shared/room-types.d.ts.map +1 -1
- package/dist/shared/rooms.d.ts.map +1 -1
- package/dist/shared/rooms.js +23 -4
- package/dist/shared/rooms.js.map +1 -1
- package/dist/shared/runtime-opener.js +1 -1
- package/dist/shared/scene.d.ts +90 -0
- package/dist/shared/scene.d.ts.map +1 -0
- package/dist/shared/social.d.ts +90 -9
- package/dist/shared/social.d.ts.map +1 -1
- package/dist/shared/social.js +6 -1
- package/dist/shared/social.js.map +1 -1
- package/dist/shared/src.js +4563 -667
- package/dist/shared/src.js.map +1 -1
- package/dist/shared/svg-markup.js +2354 -0
- package/dist/shared/svg-markup.js.map +1 -0
- package/dist/shared/svg.js +27 -0
- package/dist/shared/svg.js.map +1 -0
- package/dist/shared/types.d.ts +174 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/wire-types.d.ts +6 -2
- package/dist/shared/wire-types.d.ts.map +1 -1
- package/dist/social.d.ts +5 -5
- package/dist/social.js +2 -2
- package/dist/turns-rules.d.ts +2 -0
- package/dist/turns-rules.js +1 -0
- package/dist/turns.d.ts +61 -0
- package/dist/turns.d.ts.map +1 -0
- package/dist/turns.js +183 -0
- package/dist/turns.js.map +1 -0
- package/package.json +125 -89
- package/src/auto.ts +39 -39
- package/src/avatar/adapters/pixi-avatar.ts +73 -0
- package/src/avatar/adapters/pixi-crowd.ts +329 -0
- package/src/avatar/adapters/pixi-types.ts +84 -0
- package/src/avatar/adapters/three.ts +126 -0
- package/src/avatar/animator/animator.ts +285 -0
- package/src/avatar/animator/reactions.ts +44 -0
- package/src/avatar/animator/schedule.ts +73 -0
- package/src/avatar/art/beard.ts +49 -0
- package/src/avatar/art/glasses.ts +67 -0
- package/src/avatar/art/hair.ts +254 -0
- package/src/avatar/art/headwear.ts +75 -0
- package/src/avatar/art/index.ts +21 -0
- package/src/avatar/art/shape.ts +87 -0
- package/src/avatar/art-store.ts +36 -0
- package/src/avatar/atlas.ts +246 -0
- package/src/avatar/catalog-view.ts +14 -0
- package/src/avatar/colour.ts +109 -0
- package/src/avatar/describe.ts +79 -0
- package/src/avatar/face.ts +187 -0
- package/src/avatar/geom.ts +173 -0
- package/src/avatar/layout.ts +47 -0
- package/src/avatar/look-like.ts +52 -0
- package/src/avatar/outputs/bitmap.ts +75 -0
- package/src/avatar/outputs/canvas-paint.ts +177 -0
- package/src/avatar/outputs/canvas.ts +62 -0
- package/src/avatar/outputs/custom-element.ts +140 -0
- package/src/avatar/outputs/element.ts +58 -0
- package/src/avatar/outputs/live-canvas.ts +57 -0
- package/src/avatar/outputs/overlay-svg.ts +22 -0
- package/src/avatar/outputs/pose-key.ts +30 -0
- package/src/avatar/outputs/svg-markup.ts +113 -0
- package/src/avatar/outputs/svg.ts +41 -0
- package/src/avatar/overlays.ts +128 -0
- package/src/avatar/render/body.ts +116 -0
- package/src/avatar/render/colours.ts +81 -0
- package/src/avatar/render/compose.ts +320 -0
- package/src/avatar/render/context.ts +117 -0
- package/src/avatar/render/eyes.ts +78 -0
- package/src/avatar/render/eyewear.ts +118 -0
- package/src/avatar/render/frame.ts +73 -0
- package/src/avatar/render/head.ts +81 -0
- package/src/avatar/render/mouth.ts +86 -0
- package/src/avatar/render/props.ts +91 -0
- package/src/avatar/render/types.ts +93 -0
- package/src/avatar/render/walker-parts.ts +121 -0
- package/src/avatar/render/walker.ts +199 -0
- package/src/avatar/scene.ts +119 -0
- package/src/avatar-pixi.ts +20 -0
- package/src/avatar-svg.ts +21 -0
- package/src/avatar-three.ts +18 -0
- package/src/avatar.ts +63 -0
- package/src/core/avatar/avatar-cache.ts +95 -0
- package/src/core/avatar/avatar-ref.ts +34 -0
- package/src/core/avatar/avatar-types.ts +43 -0
- package/src/core/avatar/hub-avatar.ts +308 -0
- package/src/core/connection.ts +408 -299
- package/src/core/errors.ts +160 -147
- package/src/core/game-data.ts +40 -38
- package/src/core/hub-economy.ts +216 -179
- package/src/core/hub-progress.ts +269 -205
- package/src/core/hub.ts +352 -131
- package/src/core/menu-control.ts +61 -61
- package/src/core/offline/cloud-saves.ts +62 -0
- package/src/core/offline/events.ts +50 -50
- package/src/core/offline/favorites.ts +21 -21
- package/src/core/offline/hub-kinds/avatar-kind.ts +42 -0
- package/src/core/offline/hub-kinds/daily-kind.ts +68 -0
- package/src/core/offline/hub-kinds/economy-kinds.ts +86 -0
- package/src/core/offline/hub-kinds/game-fields.ts +2 -0
- package/src/core/offline/hub-kinds/index.ts +52 -0
- package/src/core/offline/hub-kinds/legacy-ops.ts +37 -0
- package/src/core/offline/hub-kinds/progress-kinds.ts +165 -0
- package/src/core/offline/hub-kinds/resume-kind.ts +108 -0
- package/src/core/offline/hub-kinds/saved-kind.ts +93 -0
- package/src/core/offline/kind-adapters.ts +48 -0
- package/src/core/offline/local-inventory.ts +64 -0
- package/src/core/offline/local-store.ts +304 -261
- package/src/core/offline/offline-api.ts +65 -0
- package/src/core/offline/outbox-entry.ts +59 -0
- package/src/core/offline/outbox-kinds.ts +78 -0
- package/src/core/offline/outbox-merge.ts +39 -0
- package/src/core/offline/outbox-replayer.ts +141 -0
- package/src/core/offline/outbox-store.ts +85 -0
- package/src/core/offline/outbox.ts +232 -0
- package/src/core/offline/queue.ts +126 -171
- package/src/core/offline/replay-lease.ts +87 -0
- package/src/core/offline/replay-policy.ts +52 -0
- package/src/core/page-account.ts +121 -0
- package/src/core/page.ts +87 -74
- package/src/core/rest/endpoint-types.ts +22 -22
- package/src/core/rest/rest-client.ts +163 -152
- package/src/core/rest/routes.gen.ts +144 -88
- package/src/core/resume/hub-resume.ts +286 -0
- package/src/core/resume/local-resume.ts +130 -0
- package/src/core/resume/resume-list.ts +65 -0
- package/src/core/resume/resume-request.ts +52 -0
- package/src/core/resume/resume-types.ts +64 -0
- package/src/core/saved/daily-saves.ts +196 -0
- package/src/core/saved/daily-seed.ts +16 -0
- package/src/core/saved/hub-saved.ts +221 -0
- package/src/core/saved/local-saved.ts +122 -0
- package/src/core/saved/saved-list.ts +129 -0
- package/src/core/saved/saved-open.ts +104 -0
- package/src/core/saved/saved-order.ts +49 -0
- package/src/core/saved/saved-types.ts +24 -0
- package/src/core/storage/json-guards.ts +80 -74
- package/src/core/storage/key-value.ts +66 -66
- package/src/core/ticket.ts +43 -43
- package/src/core/turns/hub-turns.ts +161 -0
- package/src/core/turns/turn-game.ts +510 -0
- package/src/core/turns/your-turn-buzz.ts +69 -0
- package/src/core/types.ts +134 -134
- package/src/core/version/client-version.gen.ts +2 -2
- package/src/core/version/hub-version.ts +62 -62
- package/src/core/version/semver.ts +97 -97
- package/src/daily/daily-system.ts +276 -161
- package/src/daily/page-daily.ts +36 -36
- package/src/daily/types.ts +105 -67
- package/src/daily.ts +10 -10
- package/src/doctor/checks.ts +86 -76
- package/src/doctor/cli.ts +101 -106
- package/src/doctor/hub-version-fetch.ts +43 -0
- package/src/doctor/tsconfig.json +12 -12
- package/src/doctor/world-check.ts +61 -0
- package/src/globals.ts +115 -110
- package/src/index.ts +68 -50
- package/src/input/device-state.ts +146 -146
- package/src/input/edges.ts +55 -55
- package/src/input/focus-ring.ts +13 -0
- package/src/input/gamepad.ts +61 -61
- package/src/input/input-events.ts +32 -32
- package/src/input/input-registry.ts +171 -164
- package/src/input/input-system.ts +406 -393
- package/src/input/legacy-controls.ts +64 -64
- package/src/input/modality.ts +122 -0
- package/src/input/nav-state.ts +200 -191
- package/src/input/navigator.ts +182 -171
- package/src/input/on-screen-controls.ts +101 -101
- package/src/input/page-control.ts +43 -43
- package/src/input/page-input.ts +193 -193
- package/src/input/player-remaps.ts +77 -77
- package/src/input/source-values.ts +116 -116
- package/src/input/spatial.ts +47 -47
- package/src/input/types.ts +331 -331
- package/src/input/zero-config.ts +164 -177
- package/src/input.ts +26 -22
- package/src/mp.ts +10 -10
- package/src/overlay/controls-panel.ts +163 -163
- package/src/overlay/dom.ts +46 -46
- package/src/overlay/layout-clusters.ts +162 -162
- package/src/overlay/layout-geometry.ts +136 -136
- package/src/overlay/layout.ts +203 -203
- package/src/overlay/listener-scope.ts +23 -23
- package/src/overlay/on-screen-keyboard.ts +137 -137
- package/src/overlay/overlay.ts +234 -208
- package/src/overlay/styles.ts +13 -12
- package/src/overlay/virtual-controls.ts +262 -262
- package/src/race.ts +10 -10
- package/src/realtime/bridge.ts +126 -121
- package/src/realtime/cross-bundle.ts +29 -29
- package/src/realtime/fallback-notice.ts +48 -48
- package/src/realtime/hub-link.ts +65 -65
- package/src/realtime/latest-state.ts +33 -33
- package/src/realtime/multiplayer-forwarder.ts +40 -28
- package/src/realtime/multiplayer-types.ts +66 -52
- package/src/realtime/page-runtime.ts +60 -60
- package/src/realtime/race-forwarder.ts +59 -59
- package/src/realtime/race-types.ts +132 -132
- package/src/realtime/room-types.ts +151 -125
- package/src/realtime/rooms-forwarder.ts +104 -79
- package/src/realtime/runtime-api.ts +74 -49
- package/src/realtime/runtime-opener.ts +61 -61
- package/src/realtime/social-forwarder.ts +77 -72
- package/src/realtime/social-types.ts +86 -78
- package/src/realtime/types.ts +54 -53
- package/src/realtime/wire-types.ts +79 -72
- package/src/realtime/world-types.ts +20 -0
- package/src/rooms.ts +10 -10
- package/src/social.ts +19 -18
- package/src/turns-kit/check-rules.ts +281 -0
- package/src/turns-rules.ts +12 -0
- package/src/turns.ts +14 -0
- package/src/types.ts +13 -13
- package/src/uistack/page-stack.ts +45 -45
- package/src/uistack/play-suspension.ts +82 -82
- package/src/uistack/types.ts +76 -76
- package/src/uistack/ui-stack.ts +144 -144
package/src/input/zero-config.ts
CHANGED
|
@@ -1,177 +1,164 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The zero-config fallback for games that never call `hub.input.define()`:
|
|
3
|
-
* on the catalog page a gamepad moves a highlight across the game tiles; in
|
|
4
|
-
* a game it presses the keys `game.controls` maps its buttons to. Runs each
|
|
5
|
-
* frame only while the menu is closed and no game has taken over input.
|
|
6
|
-
*/
|
|
7
|
-
import type { RepeatingEdges } from './edges';
|
|
8
|
-
import { anyPadDirections, isAnyPadButtonPressed, isPadButtonPressed, PAD_BUTTON, padDirections } from './gamepad';
|
|
9
|
-
import type { Direction } from './gamepad';
|
|
10
|
-
import type { LegacyControls } from './legacy-controls';
|
|
11
|
-
import { controlMapFor } from './legacy-controls';
|
|
12
|
-
import { findNearestInDirection, rectOf } from './spatial';
|
|
13
|
-
import { isTypingTarget } from './device-state';
|
|
14
|
-
|
|
15
|
-
/** Synthetic keys stay pressed past half deflection. */
|
|
16
|
-
const SYNTH_DEADZONE = 0.5;
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
['
|
|
24
|
-
['
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
readonly
|
|
38
|
-
readonly
|
|
39
|
-
readonly
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
Object.defineProperty(event, '
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/** One frame of the zero-config fallback. */
|
|
167
|
-
export function runZeroConfigFrame(frame: ZeroConfigFrame): void {
|
|
168
|
-
if (frame.gamepads.length === 0) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
ensureFocusStyle();
|
|
172
|
-
if (frame.slug === null) {
|
|
173
|
-
navigateCatalog(frame);
|
|
174
|
-
} else {
|
|
175
|
-
synthesizeKeys(frame);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* The zero-config fallback for games that never call `hub.input.define()`:
|
|
3
|
+
* on the catalog page a gamepad moves a highlight across the game tiles; in
|
|
4
|
+
* a game it presses the keys `game.controls` maps its buttons to. Runs each
|
|
5
|
+
* frame only while the menu is closed and no game has taken over input.
|
|
6
|
+
*/
|
|
7
|
+
import type { RepeatingEdges } from './edges';
|
|
8
|
+
import { anyPadDirections, isAnyPadButtonPressed, isPadButtonPressed, PAD_BUTTON, padDirections } from './gamepad';
|
|
9
|
+
import type { Direction } from './gamepad';
|
|
10
|
+
import type { LegacyControls } from './legacy-controls';
|
|
11
|
+
import { controlMapFor } from './legacy-controls';
|
|
12
|
+
import { findNearestInDirection, rectOf } from './spatial';
|
|
13
|
+
import { isTypingTarget } from './device-state';
|
|
14
|
+
|
|
15
|
+
/** Synthetic keys stay pressed past half deflection. */
|
|
16
|
+
const SYNTH_DEADZONE = 0.5;
|
|
17
|
+
/** The catalog tile highlight; its style (keyboard and gamepad players only) is in `modality.ts`. */
|
|
18
|
+
const FOCUS_CLASS = 'gp-focus';
|
|
19
|
+
|
|
20
|
+
/** `KeyboardEvent.code` → its `key` and legacy `keyCode`. */
|
|
21
|
+
const KEY_FOR_CODE = new Map<string, readonly [string, number]>([
|
|
22
|
+
['ArrowUp', ['ArrowUp', 38]], ['ArrowDown', ['ArrowDown', 40]], ['ArrowLeft', ['ArrowLeft', 37]], ['ArrowRight', ['ArrowRight', 39]],
|
|
23
|
+
['Space', [' ', 32]], ['Enter', ['Enter', 13]], ['Escape', ['Escape', 27]], ['Tab', ['Tab', 9]], ['Backspace', ['Backspace', 8]],
|
|
24
|
+
['ShiftLeft', ['Shift', 16]], ['ControlLeft', ['Control', 17]], ['AltLeft', ['Alt', 18]],
|
|
25
|
+
]);
|
|
26
|
+
for (let code = 65; code <= 90; code += 1) {
|
|
27
|
+
const letter = String.fromCharCode(code);
|
|
28
|
+
KEY_FOR_CODE.set(`Key${letter}`, [letter.toLowerCase(), code]);
|
|
29
|
+
}
|
|
30
|
+
for (let digit = 0; digit <= 9; digit += 1) {
|
|
31
|
+
KEY_FOR_CODE.set(`Digit${String(digit)}`, [String(digit), 48 + digit]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** What the fallback reads from the input system each frame. */
|
|
35
|
+
export interface ZeroConfigFrame {
|
|
36
|
+
readonly gamepads: readonly Gamepad[];
|
|
37
|
+
readonly slug: string | null;
|
|
38
|
+
readonly controls: LegacyControls;
|
|
39
|
+
readonly navEdges: RepeatingEdges;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Dispatch a synthetic key event (with the legacy `keyCode`/`which` old games read) on the focused element. */
|
|
43
|
+
function dispatchKey(type: 'keydown' | 'keyup', code: string): void {
|
|
44
|
+
const [key, keyCode] = KEY_FOR_CODE.get(code) ?? [code, 0];
|
|
45
|
+
const active = document.activeElement;
|
|
46
|
+
const target: EventTarget = active !== null && active !== document.body ? active : document.body;
|
|
47
|
+
const event = new KeyboardEvent(type, { key, code, bubbles: true, cancelable: true });
|
|
48
|
+
Object.defineProperty(event, 'keyCode', { get: () => keyCode });
|
|
49
|
+
Object.defineProperty(event, 'which', { get: () => keyCode });
|
|
50
|
+
target.dispatchEvent(event);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The keys each pad holds down, by pad index. */
|
|
54
|
+
const heldCodes = new Map<number, Set<string>>();
|
|
55
|
+
|
|
56
|
+
function releaseAllKeys(): void {
|
|
57
|
+
for (const [padIndex, codes] of heldCodes) {
|
|
58
|
+
for (const code of codes) {
|
|
59
|
+
dispatchKey('keyup', code);
|
|
60
|
+
}
|
|
61
|
+
heldCodes.set(padIndex, new Set());
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** In a game: press and release the mapped keys to match each pad. */
|
|
66
|
+
function synthesizeKeys(frame: ZeroConfigFrame): void {
|
|
67
|
+
if (isTypingTarget(document.activeElement)) {
|
|
68
|
+
releaseAllKeys();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
frame.gamepads.forEach((pad, padIndex) => {
|
|
72
|
+
const map = controlMapFor(frame.controls, padIndex);
|
|
73
|
+
const directions = padDirections(pad, SYNTH_DEADZONE);
|
|
74
|
+
const wanted = new Set<string>();
|
|
75
|
+
for (const direction of ['up', 'down', 'left', 'right'] as const) {
|
|
76
|
+
if (directions[direction]) {
|
|
77
|
+
wanted.add(map[direction]);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
for (const [buttonIndex, code] of map.buttons) {
|
|
81
|
+
if (isPadButtonPressed(pad, buttonIndex)) {
|
|
82
|
+
wanted.add(code);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const held = heldCodes.get(padIndex) ?? new Set<string>();
|
|
86
|
+
wanted.forEach((code) => {
|
|
87
|
+
if (!held.has(code)) {
|
|
88
|
+
dispatchKey('keydown', code);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
held.forEach((code) => {
|
|
92
|
+
if (!wanted.has(code)) {
|
|
93
|
+
dispatchKey('keyup', code);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
heldCodes.set(padIndex, wanted);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** The visible game tiles on the catalog page. */
|
|
101
|
+
function visibleTiles(): HTMLElement[] {
|
|
102
|
+
return [...document.querySelectorAll<HTMLElement>('.grid .card')].filter((card) => card.offsetParent !== null);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function highlightTile(tiles: readonly HTMLElement[], index: number): void {
|
|
106
|
+
tiles.forEach((tile) => {
|
|
107
|
+
tile.classList.remove(FOCUS_CLASS);
|
|
108
|
+
});
|
|
109
|
+
const tile = tiles[index];
|
|
110
|
+
tile?.classList.add(FOCUS_CLASS);
|
|
111
|
+
tile?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** On the catalog page: move the highlight across the tiles; A or Start opens one. */
|
|
115
|
+
function navigateCatalog(frame: ZeroConfigFrame): void {
|
|
116
|
+
const held = anyPadDirections(frame.gamepads, SYNTH_DEADZONE);
|
|
117
|
+
const isAccepting = isAnyPadButtonPressed(frame.gamepads, PAD_BUTTON.A) || isAnyPadButtonPressed(frame.gamepads, PAD_BUTTON.START);
|
|
118
|
+
const fired: Record<Direction, boolean> = {
|
|
119
|
+
up: frame.navEdges.fires('lu', held.up),
|
|
120
|
+
down: frame.navEdges.fires('ld', held.down),
|
|
121
|
+
left: frame.navEdges.fires('ll', held.left),
|
|
122
|
+
right: frame.navEdges.fires('lr', held.right),
|
|
123
|
+
};
|
|
124
|
+
const shouldAccept = frame.navEdges.fires('la', isAccepting) && isAccepting;
|
|
125
|
+
const tiles = visibleTiles();
|
|
126
|
+
if (tiles.length === 0) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const focused = tiles.findIndex((tile) => tile.classList.contains(FOCUS_CLASS));
|
|
130
|
+
const focusedTile = tiles[focused];
|
|
131
|
+
if (focusedTile === undefined) {
|
|
132
|
+
highlightTile(tiles, 0);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (shouldAccept) {
|
|
136
|
+
const href = focusedTile.getAttribute('href');
|
|
137
|
+
if (href === null) {
|
|
138
|
+
focusedTile.click();
|
|
139
|
+
} else {
|
|
140
|
+
location.href = href;
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const direction = (['up', 'down', 'left', 'right'] as const).find((candidate) => fired[candidate]);
|
|
145
|
+
if (direction === undefined) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const next = findNearestInDirection(tiles.map(rectOf), focused, direction);
|
|
149
|
+
if (next >= 0) {
|
|
150
|
+
highlightTile(tiles, next);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** One frame of the zero-config fallback. */
|
|
155
|
+
export function runZeroConfigFrame(frame: ZeroConfigFrame): void {
|
|
156
|
+
if (frame.gamepads.length === 0) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (frame.slug === null) {
|
|
160
|
+
navigateCatalog(frame);
|
|
161
|
+
} else {
|
|
162
|
+
synthesizeKeys(frame);
|
|
163
|
+
}
|
|
164
|
+
}
|
package/src/input.ts
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `@diffenderfer-games/hub/input`: the input system (`hub.input`): the
|
|
3
|
-
* page-wide {@link getInput}, the {@link InputSystem} class, the on-screen
|
|
4
|
-
* control layout, and the overlay stack behind `hub.overlay`.
|
|
5
|
-
*
|
|
6
|
-
* @packageDocumentation
|
|
7
|
-
*/
|
|
8
|
-
export { InputSystem } from './input/input-system';
|
|
9
|
-
export type { InputSystemOptions } from './input/input-system';
|
|
10
|
-
export { getInput, INPUT_SINGLETON_API, isInputSystem, parseInputOverrides } from './input/page-input';
|
|
11
|
-
export type { InputOptions } from './input/page-input';
|
|
12
|
-
export {
|
|
13
|
-
export
|
|
14
|
-
export type
|
|
15
|
-
export {
|
|
16
|
-
export {
|
|
17
|
-
export type
|
|
18
|
-
export {
|
|
19
|
-
export
|
|
20
|
-
export {
|
|
21
|
-
export {
|
|
22
|
-
export
|
|
1
|
+
/**
|
|
2
|
+
* `@diffenderfer-games/hub/input`: the input system (`hub.input`): the
|
|
3
|
+
* page-wide {@link getInput}, the {@link InputSystem} class, the on-screen
|
|
4
|
+
* control layout, and the overlay stack behind `hub.overlay`.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
export { InputSystem } from './input/input-system';
|
|
9
|
+
export type { InputSystemOptions } from './input/input-system';
|
|
10
|
+
export { getInput, INPUT_SINGLETON_API, isInputSystem, parseInputOverrides } from './input/page-input';
|
|
11
|
+
export type { InputOptions } from './input/page-input';
|
|
12
|
+
export { FOCUS_RING_SHADOW } from './input/focus-ring';
|
|
13
|
+
export { MODALITY_ATTRIBUTE, trackInputModality } from './input/modality';
|
|
14
|
+
export type { InputModality } from './input/modality';
|
|
15
|
+
export { isPageInputControl } from './input/page-control';
|
|
16
|
+
export type { PageInputControl } from './input/page-control';
|
|
17
|
+
export type * from './input/types';
|
|
18
|
+
export type { AutoNavigateTarget } from './input/navigator';
|
|
19
|
+
export { Overlay } from './overlay/overlay';
|
|
20
|
+
export { layoutControls } from './overlay/layout';
|
|
21
|
+
export type { LayoutOptions } from './overlay/layout';
|
|
22
|
+
export { boxesTouch, controlSize } from './overlay/layout-geometry';
|
|
23
|
+
export type { Insets, LayoutBox, LayoutItem } from './overlay/layout-geometry';
|
|
24
|
+
export { getUiStack, isUiStack } from './uistack/page-stack';
|
|
25
|
+
export { UI_STACK_VERSION } from './uistack/ui-stack';
|
|
26
|
+
export type * from './uistack/types';
|
package/src/mp.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `@diffenderfer-games/hub/mp`: the multiplayer forwarder (`hub.mp`):
|
|
3
|
-
* invites, launches, the leave guard and own-server tickets.
|
|
4
|
-
*
|
|
5
|
-
* @packageDocumentation
|
|
6
|
-
*/
|
|
7
|
-
export { multiplayerForwarder as mp } from './realtime/multiplayer-forwarder';
|
|
8
|
-
export type * from './realtime/multiplayer-types';
|
|
9
|
-
export type { InviteCreated } from './realtime/wire-types';
|
|
10
|
-
export type { Invite, JoinInfo, Launch, LaunchTicket, Party } from '@diffenderfer-games/hub-contract';
|
|
1
|
+
/**
|
|
2
|
+
* `@diffenderfer-games/hub/mp`: the multiplayer forwarder (`hub.mp`):
|
|
3
|
+
* invites, launches, the leave guard and own-server tickets.
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
export { multiplayerForwarder as mp } from './realtime/multiplayer-forwarder';
|
|
8
|
+
export type * from './realtime/multiplayer-types';
|
|
9
|
+
export type { InviteCreated, InviteLink } from './realtime/wire-types';
|
|
10
|
+
export type { Invite, JoinInfo, Launch, LaunchTicket, Party } from '@diffenderfer-games/hub-contract';
|