@codexo/exojs 0.7.12 → 0.7.13
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 +334 -0
- package/dist/esm/core/Application.d.ts +3 -1
- package/dist/esm/core/Application.js +7 -6
- package/dist/esm/core/Application.js.map +1 -1
- package/dist/esm/core/Scene.d.ts +30 -0
- package/dist/esm/core/Scene.js +56 -0
- package/dist/esm/core/Scene.js.map +1 -1
- package/dist/esm/core/SceneManager.js +2 -2
- package/dist/esm/core/SceneManager.js.map +1 -1
- package/dist/esm/debug/DebugOverlay.js +2 -2
- package/dist/esm/debug/DebugOverlay.js.map +1 -1
- package/dist/esm/debug/PointerStackLayer.js +1 -1
- package/dist/esm/debug/PointerStackLayer.js.map +1 -1
- package/dist/esm/index.js +4 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/input/ArcadeStickGamepadMapping.js +18 -19
- package/dist/esm/input/ArcadeStickGamepadMapping.js.map +1 -1
- package/dist/esm/input/Gamepad.d.ts +164 -62
- package/dist/esm/input/Gamepad.js +290 -134
- package/dist/esm/input/Gamepad.js.map +1 -1
- package/dist/esm/input/GamepadAxis.d.ts +120 -0
- package/dist/esm/input/GamepadAxis.js +106 -0
- package/dist/esm/input/GamepadAxis.js.map +1 -0
- package/dist/esm/input/GamepadButton.d.ts +110 -0
- package/dist/esm/input/GamepadButton.js +99 -0
- package/dist/esm/input/GamepadButton.js.map +1 -0
- package/dist/esm/input/GamepadDefinitions.js +4 -0
- package/dist/esm/input/GamepadDefinitions.js.map +1 -1
- package/dist/esm/input/GamepadMapping.d.ts +28 -24
- package/dist/esm/input/GamepadMapping.js +33 -16
- package/dist/esm/input/GamepadMapping.js.map +1 -1
- package/dist/esm/input/GamepadPromptLayouts.d.ts +10 -8
- package/dist/esm/input/GamepadPromptLayouts.js +21 -20
- package/dist/esm/input/GamepadPromptLayouts.js.map +1 -1
- package/dist/esm/input/GenericDualAnalogGamepadMapping.d.ts +6 -3
- package/dist/esm/input/GenericDualAnalogGamepadMapping.js +55 -46
- package/dist/esm/input/GenericDualAnalogGamepadMapping.js.map +1 -1
- package/dist/esm/input/InputBinding.d.ts +74 -0
- package/dist/esm/input/InputBinding.js +100 -0
- package/dist/esm/input/InputBinding.js.map +1 -0
- package/dist/esm/input/InputManager.d.ts +79 -33
- package/dist/esm/input/InputManager.js +229 -104
- package/dist/esm/input/InputManager.js.map +1 -1
- package/dist/esm/input/InteractionManager.d.ts +1 -1
- package/dist/esm/input/InteractionManager.js +13 -13
- package/dist/esm/input/InteractionManager.js.map +1 -1
- package/dist/esm/input/JoyConLeftGamepadMapping.d.ts +14 -9
- package/dist/esm/input/JoyConLeftGamepadMapping.js +39 -9
- package/dist/esm/input/JoyConLeftGamepadMapping.js.map +1 -1
- package/dist/esm/input/JoyConRightGamepadMapping.d.ts +14 -9
- package/dist/esm/input/JoyConRightGamepadMapping.js +35 -9
- package/dist/esm/input/JoyConRightGamepadMapping.js.map +1 -1
- package/dist/esm/input/Pointer.d.ts +84 -71
- package/dist/esm/input/Pointer.js +71 -71
- package/dist/esm/input/Pointer.js.map +1 -1
- package/dist/esm/input/SteamDeckGamepadMapping.d.ts +18 -0
- package/dist/esm/input/SteamDeckGamepadMapping.js +76 -0
- package/dist/esm/input/SteamDeckGamepadMapping.js.map +1 -0
- package/dist/esm/input/index.d.ts +7 -4
- package/dist/esm/input/types.d.ts +0 -76
- package/dist/esm/input/types.js +1 -80
- package/dist/esm/input/types.js.map +1 -1
- package/dist/esm/resources/CacheFirstStrategy.d.ts +7 -4
- package/dist/esm/resources/CacheFirstStrategy.js +11 -8
- package/dist/esm/resources/CacheFirstStrategy.js.map +1 -1
- package/dist/esm/resources/CacheStrategy.d.ts +14 -6
- package/dist/esm/resources/Loader.d.ts +8 -3
- package/dist/esm/resources/Loader.js +19 -37
- package/dist/esm/resources/Loader.js.map +1 -1
- package/dist/esm/resources/NetworkOnlyStrategy.d.ts +3 -0
- package/dist/esm/resources/NetworkOnlyStrategy.js +8 -3
- package/dist/esm/resources/NetworkOnlyStrategy.js.map +1 -1
- package/dist/esm/resources/factories/ImageFactory.d.ts +2 -2
- package/dist/esm/resources/factories/ImageFactory.js.map +1 -1
- package/dist/esm/resources/factories/TextureFactory.d.ts +2 -2
- package/dist/esm/resources/factories/TextureFactory.js.map +1 -1
- package/dist/esm/resources/factories/VttFactory.d.ts +3 -3
- package/dist/esm/resources/factories/VttFactory.js +83 -6
- package/dist/esm/resources/factories/VttFactory.js.map +1 -1
- package/dist/exo.esm.js +1390 -795
- package/dist/exo.esm.js.map +1 -1
- package/package.json +2 -1
- package/dist/esm/input/GamepadChannels.d.ts +0 -47
- package/dist/esm/input/GamepadChannels.js +0 -53
- package/dist/esm/input/GamepadChannels.js.map +0 -1
- package/dist/esm/input/GamepadControl.d.ts +0 -33
- package/dist/esm/input/GamepadControl.js +0 -42
- package/dist/esm/input/GamepadControl.js.map +0 -1
- package/dist/esm/input/Input.d.ts +0 -52
- package/dist/esm/input/Input.js +0 -90
- package/dist/esm/input/Input.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,340 @@ All notable changes to ExoJS are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.7.13] - 2026-05-07
|
|
8
|
+
|
|
9
|
+
Major gamepad-input refactor. Replaces the `new Input(...)` +
|
|
10
|
+
`inputManager.add(...)` pattern with a fluent listener API, splits the
|
|
11
|
+
unified `GamepadChannel` enum into disjoint `GamepadButton` /
|
|
12
|
+
`GamepadAxis` for type-safe button-vs-axis distinction, introduces
|
|
13
|
+
always-4 stable gamepad slots with disconnect-aware listeners, and adds
|
|
14
|
+
rumble, generic per-pad signals, slot-strategy configuration, aggregate
|
|
15
|
+
signed stick channels, and Joy-Con-honest mappings.
|
|
16
|
+
|
|
17
|
+
### Added — Listener API
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// Per inputManager (manual unbind):
|
|
21
|
+
app.input.onTrigger(GamepadButton.South, () => player.jump());
|
|
22
|
+
app.input.onActive(GamepadAxis.LeftStickX, (v) => player.x += v * 5);
|
|
23
|
+
app.input.onStart([Keyboard.Space, GamepadButton.South], () => fire());
|
|
24
|
+
|
|
25
|
+
// Per gamepad (slot-aware, listener survives disconnect/reconnect):
|
|
26
|
+
const pad = app.input.getGamepad(0);
|
|
27
|
+
pad.onTrigger(GamepadButton.South, () => p1.jump());
|
|
28
|
+
|
|
29
|
+
// Per scene (auto-disposed on scene unload):
|
|
30
|
+
this.inputs.onTrigger(Keyboard.Escape, () => this.app.sceneManager.popScene());
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Each method returns an `InputBinding` with `.unbind()` for manual
|
|
34
|
+
lifecycle. Single channel or array of channels is accepted.
|
|
35
|
+
|
|
36
|
+
### Added — Always-4 gamepad slots
|
|
37
|
+
|
|
38
|
+
`InputManager.gamepads` is now a fixed
|
|
39
|
+
`readonly [Gamepad, Gamepad, Gamepad, Gamepad]` tuple. Each `Gamepad`
|
|
40
|
+
instance lives for the application's lifetime; check `pad.connected` for
|
|
41
|
+
hardware presence. Listeners attached when a slot is empty automatically
|
|
42
|
+
activate when a pad connects to that slot — no rebinding required.
|
|
43
|
+
|
|
44
|
+
Convenience accessors on `app.input`:
|
|
45
|
+
|
|
46
|
+
- `getGamepad(slot)` — readable single-slot accessor (equivalent to
|
|
47
|
+
`gamepads[slot]`).
|
|
48
|
+
- `connectedGamepads: readonly Gamepad[]` — only the currently-attached
|
|
49
|
+
pads, in slot order.
|
|
50
|
+
- `connectedGamepadCount: number`
|
|
51
|
+
- `firstConnectedGamepad: Gamepad | null`
|
|
52
|
+
- `hasGamepad: boolean`
|
|
53
|
+
|
|
54
|
+
Per-pad: `pad.internalIndex` returns the browser's `Gamepad.index` for
|
|
55
|
+
the attached hardware (or `null` when disconnected). Low-level escape
|
|
56
|
+
hatch — prefer `pad.slot` for stable application-side identity.
|
|
57
|
+
|
|
58
|
+
### Added — Slot strategy
|
|
59
|
+
|
|
60
|
+
`new Application({ gamepadSlotStrategy: 'sticky' | 'compact' })` —
|
|
61
|
+
default `'sticky'` (each pad keeps its slot through disconnects).
|
|
62
|
+
`'compact'` shifts higher-numbered pads down to fill gaps after a
|
|
63
|
+
disconnect (good for hot-seat couch coop where "the first N pads are
|
|
64
|
+
the N players" is the desired semantic).
|
|
65
|
+
|
|
66
|
+
In compact mode, the disconnect signal fires on the slot that *ended
|
|
67
|
+
up* empty after the shift (not the slot the disconnected hardware
|
|
68
|
+
originally occupied), keeping `pad.connected === false` consistent with
|
|
69
|
+
the fired event. Slots that received a different physical pad through
|
|
70
|
+
the shift dispatch a separate signal:
|
|
71
|
+
|
|
72
|
+
- `pad.onPadReassigned: Signal<[fromSlot: 0 | 1 | 2 | 3]>`
|
|
73
|
+
- `app.input.onAnyGamepadReassigned: Signal<[Gamepad, fromSlot]>`
|
|
74
|
+
|
|
75
|
+
so player-binding code can re-resolve which `Gamepad` belongs to which
|
|
76
|
+
player when slots renumber.
|
|
77
|
+
|
|
78
|
+
### Added — Generic signals
|
|
79
|
+
|
|
80
|
+
Per-pad:
|
|
81
|
+
- `pad.onConnect: Signal<[]>`
|
|
82
|
+
- `pad.onDisconnect: Signal<[]>`
|
|
83
|
+
- `pad.onButtonDown: Signal<[GamepadButton, number]>`
|
|
84
|
+
- `pad.onButtonUp: Signal<[GamepadButton, number]>`
|
|
85
|
+
- `pad.onAxisChange: Signal<[GamepadAxis, number]>`
|
|
86
|
+
|
|
87
|
+
Aggregate across all pads:
|
|
88
|
+
- `inputManager.onAnyGamepadButtonDown: Signal<[Gamepad, GamepadButton, number]>`
|
|
89
|
+
- `inputManager.onAnyGamepadButtonUp: Signal<[Gamepad, GamepadButton, number]>`
|
|
90
|
+
- `inputManager.onAnyGamepadAxisChange: Signal<[Gamepad, GamepadAxis, number]>`
|
|
91
|
+
|
|
92
|
+
### Added — Vibration
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
if (pad.canVibrate) {
|
|
96
|
+
await pad.vibrate({ duration: 200, weakMagnitude: 0.5, strongMagnitude: 1.0 });
|
|
97
|
+
}
|
|
98
|
+
pad.stopVibration();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Wraps the W3C `vibrationActuator.playEffect('dual-rumble')` API. Silent
|
|
102
|
+
no-op on platforms without haptic support — use `pad.canVibrate` to
|
|
103
|
+
detect availability for UI gating. Trigger-rumble (PS5 / Xbox Series
|
|
104
|
+
adaptive triggers) is not exposed because browser support is currently
|
|
105
|
+
Chrome-only and non-standard.
|
|
106
|
+
|
|
107
|
+
### Added — Aggregate axis channels
|
|
108
|
+
|
|
109
|
+
`GamepadAxis.LeftStickX`, `LeftStickY`, `RightStickX`, `RightStickY` —
|
|
110
|
+
signed -1..1 values that consume the full bipolar range of the physical
|
|
111
|
+
stick. Use these for stick-style movement input; the existing
|
|
112
|
+
direction-split channels (`LeftStickLeft`, `LeftStickRight`, etc.)
|
|
113
|
+
remain available for buttons-style 0..1 input.
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
// Stick-style — one binding per axis, signed value:
|
|
117
|
+
this.inputs.onActive(GamepadAxis.LeftStickX, (x) => player.x += x * 5);
|
|
118
|
+
|
|
119
|
+
// Buttons-style — separate bindings per direction, 0..1 each:
|
|
120
|
+
this.inputs.onActive(GamepadAxis.LeftStickLeft, (v) => player.x -= v * 5);
|
|
121
|
+
this.inputs.onActive(GamepadAxis.LeftStickRight, (v) => player.x += v * 5);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Added — `pad.hasChannel(channel)` capability check
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
if (pad.hasChannel(GamepadAxis.RightStickX)) {
|
|
128
|
+
pad.onActive(GamepadAxis.RightStickX, (v) => crosshair.x += v * 8);
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Returns `true` only when the pad's mapping declares the requested
|
|
133
|
+
channel. Useful for graceful degradation on devices with limited
|
|
134
|
+
hardware (e.g. single Joy-Con without a right stick).
|
|
135
|
+
|
|
136
|
+
### Added — `Scene.inputs` proxy
|
|
137
|
+
|
|
138
|
+
Bindings created via `this.inputs.onTrigger(...)` etc. are automatically
|
|
139
|
+
disposed when the scene unloads. No manual cleanup tracking required.
|
|
140
|
+
Internally tracks each binding and calls `.unbind()` in `Scene.destroy`.
|
|
141
|
+
|
|
142
|
+
### Added — Steam Deck / Steam Virtual Gamepad / Valve fallback
|
|
143
|
+
|
|
144
|
+
New `SteamDeckGamepadMapping` covers the raw HID layout reported by the
|
|
145
|
+
Steam Deck (and likely future Valve hardware) when Steam Input is *not*
|
|
146
|
+
intercepting the device. Indices follow the SDL_GameControllerDB Linux
|
|
147
|
+
entry: face buttons at 3-6, D-pad at 16-19, paddles at 20-23, triggers
|
|
148
|
+
as analog axes 8/9.
|
|
149
|
+
|
|
150
|
+
Routing rules added to `builtInGamepadDefinitions`:
|
|
151
|
+
|
|
152
|
+
| Browser ID | Mapping |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `28de:1102`, `28de:1142` | `SteamControllerGamepadMapping` (existing, original Steam Controller raw) |
|
|
155
|
+
| `28de:11ff` (Steam Virtual Gamepad — any controller via Steam Input) | `GenericDualAnalogGamepadMapping` (W3C standard Xbox emulation) |
|
|
156
|
+
| `28de:1205` | `SteamDeckGamepadMapping` (raw Steam Deck) |
|
|
157
|
+
| Vendor `28de` (anything else from Valve, e.g. future Steam Controller 2 raw) | `SteamDeckGamepadMapping` (best-effort fallback) |
|
|
158
|
+
|
|
159
|
+
Enum: `GamepadMappingFamily.SteamDeck` added.
|
|
160
|
+
|
|
161
|
+
### Added — Paddle2/3/4 buttons + Touchpad2X/Y axes
|
|
162
|
+
|
|
163
|
+
The per-gamepad channel allocation is repartitioned into 32 button
|
|
164
|
+
slots + 32 axis slots (was 21 / 22 with mid-block axis indices). 24
|
|
165
|
+
named buttons (`South`-`Paddle4`) plus 8 reserved slots; 24 named axes
|
|
166
|
+
(stick split + aggregate + dual-touchpad XY + 4 auxiliary bipolar) plus
|
|
167
|
+
8 reserved slots. The reserved slots are accessible to custom mappings
|
|
168
|
+
without colliding with future named additions.
|
|
169
|
+
|
|
170
|
+
New named channels:
|
|
171
|
+
|
|
172
|
+
- `GamepadButton.Paddle2`, `.Paddle3`, `.Paddle4` — extra paddles
|
|
173
|
+
/ back buttons on Xbox Elite, PS5 Edge, Steam Deck (R4/L5/R5).
|
|
174
|
+
- `GamepadAxis.Touchpad2X`, `.Touchpad2Y` — secondary touchpad on
|
|
175
|
+
dual-touchpad hardware (Steam Deck right pad).
|
|
176
|
+
|
|
177
|
+
User code that previously read `GamepadButton.Paddle1` etc. is
|
|
178
|
+
unaffected — channel **values** changed (offsets re-laid-out), but the
|
|
179
|
+
namespace constants resolve to the new offsets transparently.
|
|
180
|
+
|
|
181
|
+
### Added — JoyCon-honest mappings
|
|
182
|
+
|
|
183
|
+
`JoyConLeftGamepadMapping` and `JoyConRightGamepadMapping` no longer
|
|
184
|
+
inherit the full DualAnalog 16-axis layout. Each declares only channels
|
|
185
|
+
that physically exist on the device (one stick mapped to LeftStick
|
|
186
|
+
channels, four face buttons, SL/SR shoulders, Minus/Plus, Capture/Home,
|
|
187
|
+
stick-click). Right-stick channels and other phantom hardware are
|
|
188
|
+
intentionally absent — `pad.hasChannel(GamepadAxis.RightStickX)` returns
|
|
189
|
+
`false` on a solo Joy-Con.
|
|
190
|
+
|
|
191
|
+
### Changed — `app.inputManager` renamed to `app.input` (BREAKING)
|
|
192
|
+
|
|
193
|
+
For consistency with `app.audio` and parity with the brevity of
|
|
194
|
+
`app.tweens` / `app.loader` / `app.interaction`. All call sites that
|
|
195
|
+
read or wrote `app.inputManager` need a one-token rename.
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
// Before:
|
|
199
|
+
app.inputManager.onTrigger(GamepadButton.South, () => fire());
|
|
200
|
+
app.inputManager.gamepads[0];
|
|
201
|
+
|
|
202
|
+
// After:
|
|
203
|
+
app.input.onTrigger(GamepadButton.South, () => fire());
|
|
204
|
+
app.input.getGamepad(0);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Fixed — Compact-mode disconnect ordering
|
|
208
|
+
|
|
209
|
+
In `'compact'` slot strategy, `onDisconnect` previously fired on the
|
|
210
|
+
slot the disconnected hardware originally occupied — *before* the
|
|
211
|
+
compaction shift moved a different physical pad into that slot. User
|
|
212
|
+
code observing the event would see `pad.connected === true` because
|
|
213
|
+
the slot had been silently re-bound by the shift. Now compaction is
|
|
214
|
+
applied first (silent), and `onDisconnect` fires on the slot that
|
|
215
|
+
ended up empty (the trailing slot). Sticky behaviour is unchanged.
|
|
216
|
+
|
|
217
|
+
### Changed — Channel naming (BREAKING)
|
|
218
|
+
|
|
219
|
+
The unified `GamepadChannel` enum is split into two disjoint enums for
|
|
220
|
+
nominal type safety:
|
|
221
|
+
|
|
222
|
+
| Old | New (user-facing) | New (internal type) |
|
|
223
|
+
|---|---|---|
|
|
224
|
+
| `GamepadChannel.ButtonSouth` | `GamepadButton.South` | `GamepadButtonChannel.South` |
|
|
225
|
+
| `GamepadChannel.ButtonEast` | `GamepadButton.East` | `GamepadButtonChannel.East` |
|
|
226
|
+
| `GamepadChannel.LeftShoulder` | `GamepadButton.LeftShoulder` | `GamepadButtonChannel.LeftShoulder` |
|
|
227
|
+
| `GamepadChannel.LeftStickLeft` | `GamepadAxis.LeftStickLeft` | `GamepadAxisChannel.LeftStickLeft` |
|
|
228
|
+
| ... | ... | ... |
|
|
229
|
+
|
|
230
|
+
User code references the namespace mirrors (`GamepadButton.X`,
|
|
231
|
+
`GamepadAxis.Y`) — same `Pointer.X` / `Keyboard.Space` convention. Type
|
|
232
|
+
checking now rejects passing a button channel where an axis is expected
|
|
233
|
+
(and vice versa).
|
|
234
|
+
|
|
235
|
+
### Changed — `GamepadControl` removed (BREAKING)
|
|
236
|
+
|
|
237
|
+
`GamepadControl` is replaced by two concrete classes:
|
|
238
|
+
|
|
239
|
+
- `GamepadButton` — wraps a button index + channel, with optional
|
|
240
|
+
`invert` and `threshold` options. `transformValue(v)` clamps to [0, 1].
|
|
241
|
+
- `GamepadAxis` — wraps an axis index + channel, with optional `invert`,
|
|
242
|
+
`normalize`, `threshold`, and the new `bipolar` flag.
|
|
243
|
+
`transformValue(v)` clamps to [-1, +1] and applies the pipeline.
|
|
244
|
+
|
|
245
|
+
Custom mappings construct these directly via `new GamepadButton(index, channel)`
|
|
246
|
+
/ `new GamepadAxis(index, channel, options)` —
|
|
247
|
+
`GamepadMapping.createControls()` is removed.
|
|
248
|
+
|
|
249
|
+
### Changed — `Input` class replaced by `InputBinding` (BREAKING)
|
|
250
|
+
|
|
251
|
+
`new Input(channel, { onTrigger: cb })` + `inputManager.add(input)` is
|
|
252
|
+
gone. Use `inputManager.onTrigger(channel, cb)` / `pad.onTrigger(...)` /
|
|
253
|
+
`scene.inputs.onTrigger(...)` instead. Returned `InputBinding` exposes
|
|
254
|
+
the same `onStart`/`onActive`/`onStop`/`onTrigger` Signals plus a
|
|
255
|
+
`.unbind()` method.
|
|
256
|
+
|
|
257
|
+
### Changed — `inputManager.add/remove/clear/getGamepad/onGamepadUpdated` removed (BREAKING)
|
|
258
|
+
|
|
259
|
+
The push-input-objects-into-the-manager API is fully replaced by the
|
|
260
|
+
factory-method API. `getGamepad(index)` is replaced by direct
|
|
261
|
+
`gamepads[slot]` indexing. `onGamepadUpdated` is replaced by
|
|
262
|
+
`onAnyGamepadButtonDown` / `onAnyGamepadButtonUp` /
|
|
263
|
+
`onAnyGamepadAxisChange` which carry semantic transition information
|
|
264
|
+
instead of firing every frame.
|
|
265
|
+
|
|
266
|
+
### Changed — `Gamepad` constructor signature (BREAKING)
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
// Before:
|
|
270
|
+
new Gamepad(index, channels, mapping)
|
|
271
|
+
new Gamepad(browserGamepad, channels, definition)
|
|
272
|
+
|
|
273
|
+
// After (engine-internal — InputManager handles slot allocation):
|
|
274
|
+
new Gamepad(slot, channels)
|
|
275
|
+
// followed by pad._bind(browserGamepad, definition) on connect
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
User code does not construct `Gamepad` instances directly. Reads from
|
|
279
|
+
`pad.info` / `pad.mapping` / `pad.connected` instead of the previous
|
|
280
|
+
`pad.name` / `pad.label` / `pad.vendorId` / etc. inline accessors.
|
|
281
|
+
|
|
282
|
+
### Migration guide
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
// Before:
|
|
286
|
+
import { Input, GamepadChannel, Keyboard } from '@codexo/exojs';
|
|
287
|
+
|
|
288
|
+
const jump = new Input(GamepadChannel.ButtonSouth, { onTrigger: () => player.jump() });
|
|
289
|
+
app.input.add(jump);
|
|
290
|
+
|
|
291
|
+
// After (any of three styles, depending on lifecycle):
|
|
292
|
+
import { GamepadButton, Keyboard } from '@codexo/exojs';
|
|
293
|
+
|
|
294
|
+
// Manual lifecycle
|
|
295
|
+
const binding = app.input.onTrigger(GamepadButton.South, () => player.jump());
|
|
296
|
+
binding.unbind(); // when done
|
|
297
|
+
|
|
298
|
+
// Auto-disposed on scene unload
|
|
299
|
+
this.inputs.onTrigger(GamepadButton.South, () => player.jump());
|
|
300
|
+
|
|
301
|
+
// Pinned to a specific pad slot
|
|
302
|
+
this.app.input.gamepads[0].onTrigger(GamepadButton.South, () => player.jump());
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
// Stick movement — before:
|
|
307
|
+
const moveLeft = new Input(GamepadChannel.LeftStickLeft);
|
|
308
|
+
const moveRight = new Input(GamepadChannel.LeftStickRight);
|
|
309
|
+
app.input.add(moveLeft);
|
|
310
|
+
app.input.add(moveRight);
|
|
311
|
+
// per frame: const x = moveRight.value - moveLeft.value;
|
|
312
|
+
|
|
313
|
+
// After (signed aggregate channel):
|
|
314
|
+
this.inputs.onActive(GamepadAxis.LeftStickX, (x) => player.x += x * 5);
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
// Custom mapping — before:
|
|
319
|
+
import { GamepadMapping, GamepadChannel } from '@codexo/exojs';
|
|
320
|
+
const buttons = GamepadMapping.createControls([
|
|
321
|
+
[0, GamepadChannel.ButtonSouth],
|
|
322
|
+
[1, GamepadChannel.ButtonEast],
|
|
323
|
+
]);
|
|
324
|
+
|
|
325
|
+
// After:
|
|
326
|
+
import { GamepadButton, GamepadMapping, GamepadMappingFamily } from '@codexo/exojs';
|
|
327
|
+
class MyMapping extends GamepadMapping {
|
|
328
|
+
public readonly family = GamepadMappingFamily.GenericDualAnalog;
|
|
329
|
+
public constructor() {
|
|
330
|
+
super(
|
|
331
|
+
[
|
|
332
|
+
new GamepadButton(0, GamepadButton.South),
|
|
333
|
+
new GamepadButton(1, GamepadButton.East),
|
|
334
|
+
],
|
|
335
|
+
[],
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
7
341
|
## [0.7.12] - 2026-05-07
|
|
8
342
|
|
|
9
343
|
API audit cleanup pass — implements collision-response computation that was
|
|
@@ -12,6 +12,7 @@ import type { Scene } from './Scene';
|
|
|
12
12
|
import type { CacheStore } from '@/resources/CacheStore';
|
|
13
13
|
import type { RenderBackend } from '@/rendering/RenderBackend';
|
|
14
14
|
import type { GamepadDefinition } from '@/input/GamepadDefinitions';
|
|
15
|
+
import type { GamepadSlotStrategy } from '@/input/InputManager';
|
|
15
16
|
import { type AudioManager } from '@/audio/AudioManager';
|
|
16
17
|
export declare enum ApplicationStatus {
|
|
17
18
|
Loading = 1,
|
|
@@ -28,6 +29,7 @@ export interface ApplicationOptions {
|
|
|
28
29
|
spriteRendererBatchSize: number;
|
|
29
30
|
particleRendererBatchSize: number;
|
|
30
31
|
gamepadDefinitions: Array<GamepadDefinition>;
|
|
32
|
+
gamepadSlotStrategy: GamepadSlotStrategy;
|
|
31
33
|
pointerDistanceThreshold: number;
|
|
32
34
|
webglAttributes: WebGLContextAttributes;
|
|
33
35
|
resourcePath: string;
|
|
@@ -77,7 +79,7 @@ export declare class Application {
|
|
|
77
79
|
readonly options: ApplicationOptions;
|
|
78
80
|
readonly canvas: HTMLCanvasElement;
|
|
79
81
|
readonly loader: Loader;
|
|
80
|
-
readonly
|
|
82
|
+
readonly input: InputManager;
|
|
81
83
|
readonly interaction: InteractionManager;
|
|
82
84
|
readonly sceneManager: SceneManager;
|
|
83
85
|
readonly tweens: TweenManager;
|
|
@@ -30,6 +30,7 @@ const defaultAppSettings = {
|
|
|
30
30
|
spriteRendererBatchSize: 4096, // ~ 262kb
|
|
31
31
|
particleRendererBatchSize: 8192, // ~ 1.18mb
|
|
32
32
|
gamepadDefinitions: [],
|
|
33
|
+
gamepadSlotStrategy: 'sticky',
|
|
33
34
|
pointerDistanceThreshold: 10,
|
|
34
35
|
webglAttributes: {
|
|
35
36
|
alpha: false,
|
|
@@ -75,7 +76,7 @@ class Application {
|
|
|
75
76
|
options;
|
|
76
77
|
canvas;
|
|
77
78
|
loader;
|
|
78
|
-
|
|
79
|
+
input;
|
|
79
80
|
interaction;
|
|
80
81
|
sceneManager;
|
|
81
82
|
tweens = new TweenManager();
|
|
@@ -117,7 +118,7 @@ class Application {
|
|
|
117
118
|
});
|
|
118
119
|
this._backendType = this.resolveInitialBackendType();
|
|
119
120
|
this._backend = this.createBackend(this._backendType);
|
|
120
|
-
this.
|
|
121
|
+
this.input = new InputManager(this);
|
|
121
122
|
this.interaction = new InteractionManager(this);
|
|
122
123
|
this.sceneManager = new SceneManager(this);
|
|
123
124
|
this._updateHandler = this.update.bind(this);
|
|
@@ -126,7 +127,7 @@ class Application {
|
|
|
126
127
|
this._documentVisible = document.visibilityState === 'visible';
|
|
127
128
|
document.addEventListener('visibilitychange', this._visibilityChangeHandler);
|
|
128
129
|
}
|
|
129
|
-
this.
|
|
130
|
+
this.input.onCanvasFocusChange.add((focused) => {
|
|
130
131
|
this.onCanvasFocusChange.dispatch(focused);
|
|
131
132
|
});
|
|
132
133
|
this.onVisibilityChange.add((visible) => {
|
|
@@ -163,7 +164,7 @@ class Application {
|
|
|
163
164
|
return this._capabilities;
|
|
164
165
|
}
|
|
165
166
|
get canvasFocused() {
|
|
166
|
-
return this.
|
|
167
|
+
return this.input.canvasFocused;
|
|
167
168
|
}
|
|
168
169
|
get documentVisible() {
|
|
169
170
|
return this._documentVisible;
|
|
@@ -221,7 +222,7 @@ class Application {
|
|
|
221
222
|
const frameDelta = this._frameClock.elapsedTime;
|
|
222
223
|
const frameStart = performance.now();
|
|
223
224
|
this.backend.resetStats();
|
|
224
|
-
this.
|
|
225
|
+
this.input.update();
|
|
225
226
|
this.interaction.update();
|
|
226
227
|
getAudioManager().update();
|
|
227
228
|
this.tweens.update(frameDelta.seconds);
|
|
@@ -294,7 +295,7 @@ class Application {
|
|
|
294
295
|
this.stop();
|
|
295
296
|
this.loader.destroy();
|
|
296
297
|
this.interaction.destroy();
|
|
297
|
-
this.
|
|
298
|
+
this.input.destroy();
|
|
298
299
|
this.tweens.destroy();
|
|
299
300
|
this._backend.destroy();
|
|
300
301
|
this.sceneManager.destroy();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Application.js","sources":["../../../../src/core/Application.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"Application.js","sources":["../../../../src/core/Application.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
package/dist/esm/core/Scene.d.ts
CHANGED
|
@@ -6,6 +6,24 @@ import type { RenderNode } from '@/rendering/RenderNode';
|
|
|
6
6
|
import type { Application } from './Application';
|
|
7
7
|
import type { Pointer } from '@/input/Pointer';
|
|
8
8
|
import type { Vector } from '@/math/Vector';
|
|
9
|
+
import type { InputBinding, InputBindingOptions, InputChannel } from '@/input/InputBinding';
|
|
10
|
+
/**
|
|
11
|
+
* Scene-bound input proxy that automatically disposes its bindings when
|
|
12
|
+
* the owning scene unloads. Created lazily on first access via
|
|
13
|
+
* {@link Scene.inputs}; do not instantiate directly.
|
|
14
|
+
*/
|
|
15
|
+
declare class SceneInputs {
|
|
16
|
+
private readonly _scene;
|
|
17
|
+
private readonly _bindings;
|
|
18
|
+
constructor(_scene: Scene);
|
|
19
|
+
onStart(channel: InputChannel | ReadonlyArray<InputChannel>, callback: (value: number) => void, options?: InputBindingOptions): InputBinding;
|
|
20
|
+
onActive(channel: InputChannel | ReadonlyArray<InputChannel>, callback: (value: number) => void, options?: InputBindingOptions): InputBinding;
|
|
21
|
+
onStop(channel: InputChannel | ReadonlyArray<InputChannel>, callback: (value: number) => void, options?: InputBindingOptions): InputBinding;
|
|
22
|
+
onTrigger(channel: InputChannel | ReadonlyArray<InputChannel>, callback: (value: number) => void, options?: InputBindingOptions): InputBinding;
|
|
23
|
+
/** @internal Called by Scene.destroy. */
|
|
24
|
+
_disposeAll(): void;
|
|
25
|
+
private _track;
|
|
26
|
+
}
|
|
9
27
|
/**
|
|
10
28
|
* How a {@link Scene} composes with scenes already on the stack.
|
|
11
29
|
* - `'overlay'`: render on top, scenes below also render and update.
|
|
@@ -88,6 +106,7 @@ export declare class Scene {
|
|
|
88
106
|
protected readonly _root: Container;
|
|
89
107
|
protected _stackMode: SceneStackMode;
|
|
90
108
|
protected _inputMode: SceneInputMode;
|
|
109
|
+
protected _inputs: SceneInputs | null;
|
|
91
110
|
get app(): Application | null;
|
|
92
111
|
set app(app: Application | null);
|
|
93
112
|
/**
|
|
@@ -104,6 +123,16 @@ export declare class Scene {
|
|
|
104
123
|
* scene's responsibility.
|
|
105
124
|
*/
|
|
106
125
|
get root(): Container;
|
|
126
|
+
/**
|
|
127
|
+
* Scene-bound input registry. Bindings created via
|
|
128
|
+
* `this.inputs.onTrigger(...)` etc. are automatically disposed when the
|
|
129
|
+
* scene unloads — no manual cleanup required.
|
|
130
|
+
*
|
|
131
|
+
* Lazily instantiated on first access; throws if accessed before
|
|
132
|
+
* {@link Scene.app} is set (i.e. before the scene is registered with
|
|
133
|
+
* a {@link SceneManager}).
|
|
134
|
+
*/
|
|
135
|
+
get inputs(): SceneInputs;
|
|
107
136
|
get stackMode(): SceneStackMode;
|
|
108
137
|
set stackMode(mode: SceneStackMode);
|
|
109
138
|
get inputMode(): SceneInputMode;
|
|
@@ -162,3 +191,4 @@ export declare class Scene {
|
|
|
162
191
|
unload(_loader: Loader): Promise<void> | void;
|
|
163
192
|
destroy(): void;
|
|
164
193
|
}
|
|
194
|
+
export {};
|
package/dist/esm/core/Scene.js
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
import { Container } from '../rendering/Container.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Scene-bound input proxy that automatically disposes its bindings when
|
|
5
|
+
* the owning scene unloads. Created lazily on first access via
|
|
6
|
+
* {@link Scene.inputs}; do not instantiate directly.
|
|
7
|
+
*/
|
|
8
|
+
class SceneInputs {
|
|
9
|
+
_scene;
|
|
10
|
+
_bindings = new Set();
|
|
11
|
+
constructor(_scene) {
|
|
12
|
+
this._scene = _scene;
|
|
13
|
+
}
|
|
14
|
+
onStart(channel, callback, options) {
|
|
15
|
+
return this._track(this._scene.app.input.onStart(channel, callback, options));
|
|
16
|
+
}
|
|
17
|
+
onActive(channel, callback, options) {
|
|
18
|
+
return this._track(this._scene.app.input.onActive(channel, callback, options));
|
|
19
|
+
}
|
|
20
|
+
onStop(channel, callback, options) {
|
|
21
|
+
return this._track(this._scene.app.input.onStop(channel, callback, options));
|
|
22
|
+
}
|
|
23
|
+
onTrigger(channel, callback, options) {
|
|
24
|
+
return this._track(this._scene.app.input.onTrigger(channel, callback, options));
|
|
25
|
+
}
|
|
26
|
+
/** @internal Called by Scene.destroy. */
|
|
27
|
+
_disposeAll() {
|
|
28
|
+
for (const binding of Array.from(this._bindings)) {
|
|
29
|
+
binding.unbind();
|
|
30
|
+
}
|
|
31
|
+
this._bindings.clear();
|
|
32
|
+
}
|
|
33
|
+
_track(binding) {
|
|
34
|
+
this._bindings.add(binding);
|
|
35
|
+
return binding;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
3
38
|
/**
|
|
4
39
|
* A scene's lifecycle host. Subclass to define scene behavior:
|
|
5
40
|
*
|
|
@@ -23,6 +58,7 @@ class Scene {
|
|
|
23
58
|
_root = new Container();
|
|
24
59
|
_stackMode = 'overlay';
|
|
25
60
|
_inputMode = 'capture';
|
|
61
|
+
_inputs = null;
|
|
26
62
|
get app() {
|
|
27
63
|
return this._app;
|
|
28
64
|
}
|
|
@@ -45,6 +81,24 @@ class Scene {
|
|
|
45
81
|
get root() {
|
|
46
82
|
return this._root;
|
|
47
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Scene-bound input registry. Bindings created via
|
|
86
|
+
* `this.inputs.onTrigger(...)` etc. are automatically disposed when the
|
|
87
|
+
* scene unloads — no manual cleanup required.
|
|
88
|
+
*
|
|
89
|
+
* Lazily instantiated on first access; throws if accessed before
|
|
90
|
+
* {@link Scene.app} is set (i.e. before the scene is registered with
|
|
91
|
+
* a {@link SceneManager}).
|
|
92
|
+
*/
|
|
93
|
+
get inputs() {
|
|
94
|
+
if (this._inputs === null) {
|
|
95
|
+
if (this._app === null) {
|
|
96
|
+
throw new Error('Scene.inputs is unavailable before the scene is attached to an Application.');
|
|
97
|
+
}
|
|
98
|
+
this._inputs = new SceneInputs(this);
|
|
99
|
+
}
|
|
100
|
+
return this._inputs;
|
|
101
|
+
}
|
|
48
102
|
get stackMode() {
|
|
49
103
|
return this._stackMode;
|
|
50
104
|
}
|
|
@@ -141,6 +195,8 @@ class Scene {
|
|
|
141
195
|
// override in subclass
|
|
142
196
|
}
|
|
143
197
|
destroy() {
|
|
198
|
+
this._inputs?._disposeAll();
|
|
199
|
+
this._inputs = null;
|
|
144
200
|
this._root.destroy();
|
|
145
201
|
this._app = null;
|
|
146
202
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Scene.js","sources":["../../../../src/core/Scene.ts"],"sourcesContent":[null],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"Scene.js","sources":["../../../../src/core/Scene.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -266,7 +266,7 @@ class SceneManager {
|
|
|
266
266
|
return { updateScenes, drawScenes };
|
|
267
267
|
}
|
|
268
268
|
_subscribeInputRouting() {
|
|
269
|
-
const inputManager = this._app.
|
|
269
|
+
const inputManager = this._app.input;
|
|
270
270
|
inputManager?.onKeyDown?.add?.(this._handleKeyDown);
|
|
271
271
|
inputManager?.onKeyUp?.add?.(this._handleKeyUp);
|
|
272
272
|
inputManager?.onPointerEnter?.add?.(this._handlePointerEnter);
|
|
@@ -280,7 +280,7 @@ class SceneManager {
|
|
|
280
280
|
inputManager?.onMouseWheel?.add?.(this._handleMouseWheel);
|
|
281
281
|
}
|
|
282
282
|
_unsubscribeInputRouting() {
|
|
283
|
-
const inputManager = this._app.
|
|
283
|
+
const inputManager = this._app.input;
|
|
284
284
|
inputManager?.onKeyDown?.remove?.(this._handleKeyDown);
|
|
285
285
|
inputManager?.onKeyUp?.remove?.(this._handleKeyUp);
|
|
286
286
|
inputManager?.onPointerEnter?.remove?.(this._handlePointerEnter);
|