@jgengine/core 0.7.0 → 0.9.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.
Files changed (329) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +2 -0
  3. package/dist/ai/flock.d.ts +36 -0
  4. package/dist/ai/flock.js +182 -0
  5. package/dist/ai/groupAssist.d.ts +19 -0
  6. package/dist/ai/groupAssist.js +59 -0
  7. package/dist/ai/laneSelect.d.ts +21 -0
  8. package/dist/ai/laneSelect.js +37 -0
  9. package/dist/ai/mobBrain.d.ts +68 -0
  10. package/dist/ai/mobBrain.js +115 -0
  11. package/dist/ai/spawnDirector.d.ts +5 -0
  12. package/dist/ai/spawnDirector.js +14 -2
  13. package/dist/ai/threat.d.ts +2 -0
  14. package/dist/ai/threat.js +34 -0
  15. package/dist/anim/easing.d.ts +14 -0
  16. package/dist/anim/easing.js +55 -0
  17. package/dist/behaviour/behaviour.d.ts +136 -0
  18. package/dist/behaviour/behaviour.js +388 -0
  19. package/dist/cards/cardPile.d.ts +1 -0
  20. package/dist/cards/cardPile.js +12 -3
  21. package/dist/cartridge/runtime.d.ts +15 -0
  22. package/dist/cartridge/runtime.js +556 -0
  23. package/dist/cartridge/spec.d.ts +188 -0
  24. package/dist/cartridge/spec.js +19 -0
  25. package/dist/cartridge/validate.d.ts +2 -0
  26. package/dist/cartridge/validate.js +78 -0
  27. package/dist/combat/abilityKit.d.ts +22 -2
  28. package/dist/combat/abilityKit.js +72 -13
  29. package/dist/combat/castRunner.d.ts +40 -0
  30. package/dist/combat/castRunner.js +56 -0
  31. package/dist/combat/comboPoints.d.ts +14 -0
  32. package/dist/combat/comboPoints.js +52 -0
  33. package/dist/combat/defensiveWindow.d.ts +1 -1
  34. package/dist/combat/defensiveWindow.js +5 -3
  35. package/dist/combat/effects.d.ts +1 -1
  36. package/dist/combat/effects.js +9 -6
  37. package/dist/combat/projectiles.d.ts +64 -6
  38. package/dist/combat/projectiles.js +232 -74
  39. package/dist/combat/resistance.d.ts +16 -4
  40. package/dist/combat/resistance.js +43 -7
  41. package/dist/combat/resourcePool.d.ts +20 -0
  42. package/dist/combat/resourcePool.js +55 -0
  43. package/dist/combat/shotOrigin.d.ts +40 -0
  44. package/dist/combat/shotOrigin.js +57 -0
  45. package/dist/combat/telegraph.d.ts +30 -1
  46. package/dist/combat/telegraph.js +61 -0
  47. package/dist/commands/commandRegistry.d.ts +1 -1
  48. package/dist/commands/commandRegistry.js +2 -1
  49. package/dist/crafting/recipe.js +4 -1
  50. package/dist/data/dataSource.d.ts +26 -0
  51. package/dist/data/dataSource.js +93 -0
  52. package/dist/data/devProxy.d.ts +11 -0
  53. package/dist/data/devProxy.js +38 -0
  54. package/dist/data/fetchJson.d.ts +20 -0
  55. package/dist/data/fetchJson.js +43 -0
  56. package/dist/data/jsonDataSource.d.ts +4 -0
  57. package/dist/data/jsonDataSource.js +6 -0
  58. package/dist/devtools/devtools.d.ts +205 -0
  59. package/dist/devtools/devtools.js +832 -0
  60. package/dist/devtools/transformTunables.d.ts +14 -0
  61. package/dist/devtools/transformTunables.js +38 -0
  62. package/dist/devtools/tunableSchema.d.ts +140 -0
  63. package/dist/devtools/tunableSchema.js +476 -0
  64. package/dist/faction/factions.d.ts +33 -0
  65. package/dist/faction/factions.js +76 -0
  66. package/dist/faction/reputation.d.ts +32 -0
  67. package/dist/faction/reputation.js +82 -0
  68. package/dist/game/chat.d.ts +68 -0
  69. package/dist/game/chat.js +173 -0
  70. package/dist/game/chatFilter.d.ts +15 -0
  71. package/dist/game/chatFilter.js +55 -0
  72. package/dist/game/controlGate.d.ts +4 -0
  73. package/dist/game/controlGate.js +7 -0
  74. package/dist/game/defineGame.d.ts +10 -2
  75. package/dist/game/defineGame.js +2 -1
  76. package/dist/game/events.d.ts +35 -0
  77. package/dist/game/gamePhase.d.ts +20 -0
  78. package/dist/game/gamePhase.js +21 -0
  79. package/dist/game/levelSequence.d.ts +44 -0
  80. package/dist/game/levelSequence.js +78 -0
  81. package/dist/game/lootTable.d.ts +10 -1
  82. package/dist/game/lootTable.js +27 -7
  83. package/dist/game/playableGame.d.ts +286 -6
  84. package/dist/game/playableGame.js +6 -1
  85. package/dist/game/progression.d.ts +1 -0
  86. package/dist/game/progression.js +23 -2
  87. package/dist/game/quest.d.ts +7 -3
  88. package/dist/game/quest.js +17 -8
  89. package/dist/game/race.d.ts +44 -1
  90. package/dist/game/race.js +116 -11
  91. package/dist/game/recordBook.d.ts +29 -0
  92. package/dist/game/recordBook.js +86 -0
  93. package/dist/game/social.d.ts +42 -0
  94. package/dist/game/social.js +122 -0
  95. package/dist/game/spawnPoints.d.ts +19 -0
  96. package/dist/game/spawnPoints.js +23 -0
  97. package/dist/game/talents.d.ts +47 -0
  98. package/dist/game/talents.js +140 -0
  99. package/dist/game/worldItem.d.ts +3 -0
  100. package/dist/game/worldItem.js +12 -6
  101. package/dist/index.d.ts +1 -0
  102. package/dist/index.js +1 -0
  103. package/dist/input/actionBindings.d.ts +10 -0
  104. package/dist/input/actionBindings.js +14 -0
  105. package/dist/input/axisInput.d.ts +26 -3
  106. package/dist/input/axisInput.js +44 -4
  107. package/dist/input/bindingOverrides.d.ts +25 -0
  108. package/dist/input/bindingOverrides.js +95 -0
  109. package/dist/input/gestureSurface.d.ts +31 -0
  110. package/dist/input/gestureSurface.js +120 -0
  111. package/dist/input/pointer.d.ts +45 -0
  112. package/dist/input/pointer.js +48 -0
  113. package/dist/input/pointerAxis.d.ts +30 -0
  114. package/dist/input/pointerAxis.js +31 -0
  115. package/dist/input/touchScheme.d.ts +89 -0
  116. package/dist/input/touchScheme.js +153 -0
  117. package/dist/item/affix.d.ts +1 -1
  118. package/dist/item/affix.js +1 -19
  119. package/dist/meta/changelog.d.ts +1 -1
  120. package/dist/meta/changelog.js +59 -1
  121. package/dist/movement/dash.d.ts +3 -0
  122. package/dist/movement/dash.js +19 -5
  123. package/dist/movement/glideModel.d.ts +44 -0
  124. package/dist/movement/glideModel.js +54 -0
  125. package/dist/movement/grappleSwing.d.ts +34 -0
  126. package/dist/movement/grappleSwing.js +56 -0
  127. package/dist/movement/leaderTrail.d.ts +29 -0
  128. package/dist/movement/leaderTrail.js +67 -0
  129. package/dist/movement/movementModel.d.ts +36 -3
  130. package/dist/movement/movementModel.js +81 -5
  131. package/dist/movement/steering.d.ts +27 -0
  132. package/dist/movement/steering.js +40 -0
  133. package/dist/movement/voxelController.d.ts +61 -0
  134. package/dist/movement/voxelController.js +229 -0
  135. package/dist/multiplayer/chatContract.d.ts +42 -0
  136. package/dist/multiplayer/chatContract.js +57 -0
  137. package/dist/multiplayer/feedWriteGate.d.ts +10 -0
  138. package/dist/multiplayer/feedWriteGate.js +12 -0
  139. package/dist/multiplayer/identity.d.ts +13 -0
  140. package/dist/multiplayer/identity.js +20 -0
  141. package/dist/multiplayer/poseSyncGate.d.ts +1 -0
  142. package/dist/multiplayer/poseSyncGate.js +13 -1
  143. package/dist/multiplayer/presenceModel.d.ts +17 -2
  144. package/dist/multiplayer/presenceModel.js +30 -4
  145. package/dist/multiplayer/voiceContract.d.ts +44 -0
  146. package/dist/multiplayer/voiceContract.js +108 -0
  147. package/dist/nav/corridors.d.ts +30 -0
  148. package/dist/nav/corridors.js +69 -0
  149. package/dist/nav/navConstrain.d.ts +14 -0
  150. package/dist/nav/navConstrain.js +26 -0
  151. package/dist/nav/navFromEnvironment.d.ts +11 -0
  152. package/dist/nav/navFromEnvironment.js +16 -0
  153. package/dist/nav/navGrid.d.ts +10 -0
  154. package/dist/nav/navGrid.js +48 -5
  155. package/dist/nav/pathFollow.d.ts +4 -2
  156. package/dist/nav/pathFollow.js +5 -3
  157. package/dist/nav/railGraph.d.ts +66 -0
  158. package/dist/nav/railGraph.js +129 -0
  159. package/dist/nav/timetable.d.ts +41 -0
  160. package/dist/nav/timetable.js +94 -0
  161. package/dist/physics/ballisticSweep.d.ts +18 -0
  162. package/dist/physics/ballisticSweep.js +49 -0
  163. package/dist/physics/buoyancy.d.ts +6 -0
  164. package/dist/physics/buoyancy.js +14 -0
  165. package/dist/physics/flowTube.d.ts +32 -0
  166. package/dist/physics/flowTube.js +64 -0
  167. package/dist/physics/forceVolume.d.ts +27 -0
  168. package/dist/physics/forceVolume.js +43 -5
  169. package/dist/physics/kinematicVehicle.d.ts +52 -0
  170. package/dist/physics/kinematicVehicle.js +81 -0
  171. package/dist/physics/physicsWorld.d.ts +54 -8
  172. package/dist/physics/physicsWorld.js +400 -79
  173. package/dist/physics/ragdoll.js +1 -1
  174. package/dist/physics/spatialGrid.d.ts +1 -1
  175. package/dist/physics/spatialGrid.js +5 -0
  176. package/dist/physics/vehicleBody.d.ts +6 -0
  177. package/dist/physics/vehicleBody.js +18 -18
  178. package/dist/puzzle/cellGrid.d.ts +26 -0
  179. package/dist/puzzle/cellGrid.js +110 -0
  180. package/dist/puzzle/fallingPiece.d.ts +24 -0
  181. package/dist/puzzle/fallingPiece.js +51 -0
  182. package/dist/random/nameGen.d.ts +18 -0
  183. package/dist/random/nameGen.js +35 -0
  184. package/dist/random/rng.d.ts +2 -0
  185. package/dist/random/rng.js +23 -0
  186. package/dist/random/seedLink.d.ts +5 -0
  187. package/dist/random/seedLink.js +35 -0
  188. package/dist/runtime/adapter.d.ts +35 -0
  189. package/dist/runtime/adapter.js +37 -1
  190. package/dist/runtime/cameraDirector.d.ts +15 -0
  191. package/dist/runtime/cameraDirector.js +31 -0
  192. package/dist/runtime/commandRunner.d.ts +2 -2
  193. package/dist/runtime/commandRunner.js +2 -2
  194. package/dist/runtime/gameContext.d.ts +65 -2
  195. package/dist/runtime/gameContext.js +280 -9
  196. package/dist/runtime/gameRuntime.d.ts +5 -1
  197. package/dist/runtime/gameRuntime.js +13 -12
  198. package/dist/runtime/hostPersistence.d.ts +30 -1
  199. package/dist/runtime/hostPersistence.js +70 -5
  200. package/dist/runtime/inputSnapshot.d.ts +12 -0
  201. package/dist/runtime/inputSnapshot.js +17 -0
  202. package/dist/runtime/motionIntents.d.ts +33 -0
  203. package/dist/runtime/motionIntents.js +43 -0
  204. package/dist/runtime/snapshot.d.ts +1 -0
  205. package/dist/runtime/snapshot.js +1 -1
  206. package/dist/runtime/transport.d.ts +32 -0
  207. package/dist/runtime/visibility.d.ts +74 -0
  208. package/dist/runtime/visibility.js +127 -0
  209. package/dist/scene/colliders.d.ts +44 -0
  210. package/dist/scene/colliders.js +77 -0
  211. package/dist/scene/entityStore.d.ts +30 -5
  212. package/dist/scene/entityStore.js +83 -13
  213. package/dist/scene/movementSpeed.d.ts +35 -0
  214. package/dist/scene/movementSpeed.js +20 -0
  215. package/dist/scene/objectQuery.d.ts +29 -0
  216. package/dist/scene/objectQuery.js +140 -0
  217. package/dist/scene/objectStore.d.ts +13 -0
  218. package/dist/scene/objectStore.js +130 -6
  219. package/dist/scene/paintLayer.d.ts +15 -0
  220. package/dist/scene/paintLayer.js +53 -0
  221. package/dist/scene/sceneRaycast.d.ts +80 -0
  222. package/dist/scene/sceneRaycast.js +284 -0
  223. package/dist/scene/spatial.d.ts +17 -1
  224. package/dist/scene/spatial.js +140 -17
  225. package/dist/sensor/concealment.d.ts +21 -0
  226. package/dist/sensor/concealment.js +63 -0
  227. package/dist/sensor/freezeMonitor.d.ts +17 -0
  228. package/dist/sensor/freezeMonitor.js +35 -0
  229. package/dist/sensor/recordingBuffer.d.ts +6 -0
  230. package/dist/sensor/recordingBuffer.js +7 -0
  231. package/dist/sensor/replayLoop.d.ts +39 -0
  232. package/dist/sensor/replayLoop.js +64 -0
  233. package/dist/sensor/visionCone.d.ts +31 -0
  234. package/dist/sensor/visionCone.js +72 -0
  235. package/dist/session/extraction.d.ts +2 -2
  236. package/dist/session/extraction.js +13 -2
  237. package/dist/session/roles.d.ts +6 -0
  238. package/dist/session/roles.js +32 -0
  239. package/dist/session/roundState.d.ts +41 -17
  240. package/dist/session/roundState.js +67 -38
  241. package/dist/settings/settingsModel.d.ts +97 -0
  242. package/dist/settings/settingsModel.js +100 -0
  243. package/dist/stats/statModifiers.d.ts +5 -2
  244. package/dist/stats/statModifiers.js +32 -14
  245. package/dist/store/observableKeyedStore.js +8 -2
  246. package/dist/survival/decayMeter.d.ts +1 -1
  247. package/dist/survival/decayMeter.js +0 -1
  248. package/dist/tactics/fallingGrid.d.ts +62 -0
  249. package/dist/tactics/fallingGrid.js +158 -0
  250. package/dist/tactics/tacticalGrid.d.ts +11 -0
  251. package/dist/tactics/tacticalGrid.js +17 -0
  252. package/dist/time/beatClock.d.ts +18 -0
  253. package/dist/time/beatClock.js +24 -0
  254. package/dist/time/idleProgress.d.ts +29 -0
  255. package/dist/time/idleProgress.js +31 -0
  256. package/dist/time/serverTick.d.ts +7 -1
  257. package/dist/time/serverTick.js +27 -4
  258. package/dist/time/simClock.d.ts +25 -1
  259. package/dist/time/simClock.js +28 -3
  260. package/dist/time/stateSchedule.d.ts +57 -0
  261. package/dist/time/stateSchedule.js +121 -0
  262. package/dist/turn/commit.d.ts +2 -2
  263. package/dist/turn/commit.js +2 -2
  264. package/dist/turn/intent.d.ts +14 -0
  265. package/dist/turn/intent.js +29 -0
  266. package/dist/turn/turnLoop.d.ts +2 -0
  267. package/dist/turn/turnLoop.js +8 -1
  268. package/dist/ui/hudLayout.d.ts +58 -0
  269. package/dist/ui/hudLayout.js +207 -0
  270. package/dist/ui/hudScale.d.ts +44 -0
  271. package/dist/ui/hudScale.js +55 -0
  272. package/dist/visibility/assetStreaming.d.ts +66 -0
  273. package/dist/visibility/assetStreaming.js +201 -0
  274. package/dist/visibility/bounds.d.ts +66 -0
  275. package/dist/visibility/bounds.js +113 -0
  276. package/dist/visibility/camera.d.ts +21 -0
  277. package/dist/visibility/camera.js +3 -0
  278. package/dist/visibility/config.d.ts +21 -0
  279. package/dist/visibility/config.js +1 -0
  280. package/dist/visibility/diagnostics.d.ts +26 -0
  281. package/dist/visibility/diagnostics.js +36 -0
  282. package/dist/visibility/distance.d.ts +11 -0
  283. package/dist/visibility/distance.js +30 -0
  284. package/dist/visibility/frustum.d.ts +47 -0
  285. package/dist/visibility/frustum.js +186 -0
  286. package/dist/visibility/occlusion.d.ts +36 -0
  287. package/dist/visibility/occlusion.js +45 -0
  288. package/dist/visibility/settings.d.ts +75 -0
  289. package/dist/visibility/settings.js +49 -0
  290. package/dist/visibility/simulationCulling.d.ts +34 -0
  291. package/dist/visibility/simulationCulling.js +36 -0
  292. package/dist/visibility/spatialIndex.d.ts +45 -0
  293. package/dist/visibility/spatialIndex.js +198 -0
  294. package/dist/visibility/visibilitySystem.d.ts +90 -0
  295. package/dist/visibility/visibilitySystem.js +257 -0
  296. package/dist/world/buildings.d.ts +6 -0
  297. package/dist/world/buildings.js +152 -0
  298. package/dist/world/carve.d.ts +7 -2
  299. package/dist/world/carve.js +17 -7
  300. package/dist/world/cellStates.d.ts +45 -0
  301. package/dist/world/cellStates.js +103 -0
  302. package/dist/world/environmentSummary.d.ts +61 -0
  303. package/dist/world/environmentSummary.js +138 -0
  304. package/dist/world/features.d.ts +138 -9
  305. package/dist/world/features.js +73 -2
  306. package/dist/world/gridInstances.d.ts +12 -0
  307. package/dist/world/gridInstances.js +160 -0
  308. package/dist/world/lod.d.ts +17 -0
  309. package/dist/world/lod.js +66 -0
  310. package/dist/world/mapLayers.d.ts +60 -0
  311. package/dist/world/mapLayers.js +44 -0
  312. package/dist/world/massing.d.ts +45 -0
  313. package/dist/world/massing.js +581 -0
  314. package/dist/world/minimap.d.ts +13 -1
  315. package/dist/world/minimap.js +21 -2
  316. package/dist/world/placementController.d.ts +22 -1
  317. package/dist/world/placementController.js +56 -0
  318. package/dist/world/terrain.d.ts +62 -1
  319. package/dist/world/terrain.js +253 -9
  320. package/dist/world/voxelField.d.ts +54 -0
  321. package/dist/world/voxelField.js +241 -0
  322. package/dist/world/water.d.ts +7 -0
  323. package/dist/world/water.js +19 -4
  324. package/dist/world/weather.d.ts +3 -18
  325. package/dist/world/weather.js +4 -17
  326. package/dist/world/windZones.d.ts +47 -0
  327. package/dist/world/windZones.js +59 -0
  328. package/llms.txt +4983 -0
  329. package/package.json +14 -3
@@ -0,0 +1,95 @@
1
+ export const BINDING_OVERRIDES_STORAGE_PREFIX = "jgengine:keybinds:";
2
+ export function bindingOverridesStorageKey(gameId) {
3
+ return `${BINDING_OVERRIDES_STORAGE_PREFIX}${gameId}`;
4
+ }
5
+ function defaultStorage() {
6
+ try {
7
+ if (typeof globalThis !== "undefined" && "localStorage" in globalThis) {
8
+ return globalThis.localStorage ?? null;
9
+ }
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ return null;
15
+ }
16
+ function isActionCodes(value) {
17
+ if (Array.isArray(value))
18
+ return value.every((code) => typeof code === "string");
19
+ if (value === null || typeof value !== "object")
20
+ return false;
21
+ const modes = value;
22
+ const okList = (list) => list === undefined || (Array.isArray(list) && list.every((code) => typeof code === "string"));
23
+ return okList(modes.hold) && okList(modes.toggle);
24
+ }
25
+ export function loadBindingOverrides(gameId, storage = defaultStorage()) {
26
+ if (storage == null)
27
+ return {};
28
+ try {
29
+ const raw = storage.getItem(bindingOverridesStorageKey(gameId));
30
+ if (raw === null)
31
+ return {};
32
+ const parsed = JSON.parse(raw);
33
+ if (parsed === null || typeof parsed !== "object")
34
+ return {};
35
+ const result = {};
36
+ for (const [action, codes] of Object.entries(parsed)) {
37
+ if (isActionCodes(codes))
38
+ result[action] = codes;
39
+ }
40
+ return result;
41
+ }
42
+ catch {
43
+ return {};
44
+ }
45
+ }
46
+ function persist(gameId, overrides, storage) {
47
+ if (storage == null)
48
+ return;
49
+ try {
50
+ if (Object.keys(overrides).length === 0)
51
+ storage.removeItem(bindingOverridesStorageKey(gameId));
52
+ else
53
+ storage.setItem(bindingOverridesStorageKey(gameId), JSON.stringify(overrides));
54
+ }
55
+ catch {
56
+ /* ignore quota / private-mode failures */
57
+ }
58
+ }
59
+ export function saveBindingOverride(gameId, action, codes, storage = defaultStorage()) {
60
+ const overrides = { ...loadBindingOverrides(gameId, storage ?? undefined), [action]: codes };
61
+ persist(gameId, overrides, storage);
62
+ return overrides;
63
+ }
64
+ export function clearBindingOverride(gameId, action, storage = defaultStorage()) {
65
+ const overrides = { ...loadBindingOverrides(gameId, storage ?? undefined) };
66
+ delete overrides[action];
67
+ persist(gameId, overrides, storage);
68
+ return overrides;
69
+ }
70
+ export function clearAllBindingOverrides(gameId, storage = defaultStorage()) {
71
+ if (storage == null)
72
+ return;
73
+ try {
74
+ storage.removeItem(bindingOverridesStorageKey(gameId));
75
+ }
76
+ catch {
77
+ /* ignore */
78
+ }
79
+ }
80
+ /**
81
+ * Merge player rebinds over a game's authored `input` map. Only actions the
82
+ * game already declares can be overridden; unknown override keys are ignored so
83
+ * a stale localStorage entry can't inject phantom actions.
84
+ */
85
+ export function applyBindingOverrides(input, overrides) {
86
+ if (Object.keys(overrides).length === 0)
87
+ return input;
88
+ const result = { ...input };
89
+ for (const action of Object.keys(input)) {
90
+ const override = overrides[action];
91
+ if (override !== undefined)
92
+ result[action] = override;
93
+ }
94
+ return result;
95
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Single-finger play-surface gesture recognizer for touch controls: taps,
3
+ * directional flick swipes, and continuous step drags all resolve to action
4
+ * names from a TouchGestureBindings declaration. Drag steps stream out of
5
+ * move() as the finger travels; taps and swipes resolve on end(). Timestamps
6
+ * are injected so the state machine stays pure; the capture layer owns touch
7
+ * identifiers and pointer capture.
8
+ */
9
+ import type { TouchGestureBindings } from "./touchScheme.js";
10
+ export interface GestureSurfaceTuning {
11
+ /** A finger that moves less than this (px) and lifts quickly is a tap. */
12
+ tapMoveThresholdPx: number;
13
+ tapMaxMs: number;
14
+ /** Minimum travel (px) for a lift to register as a swipe. */
15
+ swipeMinPx: number;
16
+ /** Minimum lift velocity (px/ms) for a swipe; slower travel is a drag that ends quietly. */
17
+ swipeMinVelocity: number;
18
+ /** Default travel (px) per repeated drag action when the binding sets none. */
19
+ dragStepPx: number;
20
+ }
21
+ export declare const DEFAULT_GESTURE_TUNING: GestureSurfaceTuning;
22
+ export interface GestureSurfaceTracker {
23
+ begin(x: number, y: number, nowMs: number): void;
24
+ /** Drag-step actions fired by this movement, in travel order. */
25
+ move(x: number, y: number): readonly string[];
26
+ /** Tap or swipe action resolved by lifting the finger, if any. */
27
+ end(x: number, y: number, nowMs: number): readonly string[];
28
+ cancel(): void;
29
+ isActive(): boolean;
30
+ }
31
+ export declare function createGestureSurfaceTracker(bindings: TouchGestureBindings, tuning?: GestureSurfaceTuning): GestureSurfaceTracker;
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Single-finger play-surface gesture recognizer for touch controls: taps,
3
+ * directional flick swipes, and continuous step drags all resolve to action
4
+ * names from a TouchGestureBindings declaration. Drag steps stream out of
5
+ * move() as the finger travels; taps and swipes resolve on end(). Timestamps
6
+ * are injected so the state machine stays pure; the capture layer owns touch
7
+ * identifiers and pointer capture.
8
+ */
9
+ export const DEFAULT_GESTURE_TUNING = {
10
+ tapMoveThresholdPx: 12,
11
+ tapMaxMs: 280,
12
+ swipeMinPx: 48,
13
+ swipeMinVelocity: 0.45,
14
+ dragStepPx: 36,
15
+ };
16
+ export function createGestureSurfaceTracker(bindings, tuning = DEFAULT_GESTURE_TUNING) {
17
+ const drag = bindings.drag;
18
+ const dragStepPx = drag?.stepPx ?? tuning.dragStepPx;
19
+ const dragBound = {
20
+ horizontal: drag?.left !== undefined || drag?.right !== undefined,
21
+ vertical: drag?.up !== undefined || drag?.down !== undefined,
22
+ };
23
+ let active = false;
24
+ let startX = 0;
25
+ let startY = 0;
26
+ let lastX = 0;
27
+ let lastY = 0;
28
+ let startTime = 0;
29
+ let moved = false;
30
+ let axis = null;
31
+ let dragAccum = 0;
32
+ let dragStepsFired = 0;
33
+ const commitAxis = (totalDx, totalDy) => {
34
+ if (axis !== null)
35
+ return;
36
+ axis = Math.abs(totalDx) >= Math.abs(totalDy) ? "horizontal" : "vertical";
37
+ };
38
+ const swipeFor = (totalDx, totalDy) => {
39
+ if (axis === "horizontal") {
40
+ return totalDx >= 0 ? bindings.swipeRight : bindings.swipeLeft;
41
+ }
42
+ return totalDy >= 0 ? bindings.swipeDown : bindings.swipeUp;
43
+ };
44
+ const dragActionFor = (direction) => {
45
+ if (axis === "horizontal")
46
+ return direction >= 0 ? drag?.right : drag?.left;
47
+ return direction >= 0 ? drag?.down : drag?.up;
48
+ };
49
+ return {
50
+ begin(x, y, nowMs) {
51
+ active = true;
52
+ startX = lastX = x;
53
+ startY = lastY = y;
54
+ startTime = nowMs;
55
+ moved = false;
56
+ axis = null;
57
+ dragAccum = 0;
58
+ dragStepsFired = 0;
59
+ },
60
+ move(x, y) {
61
+ if (!active)
62
+ return [];
63
+ const totalDx = x - startX;
64
+ const totalDy = y - startY;
65
+ if (!moved && Math.hypot(totalDx, totalDy) > tuning.tapMoveThresholdPx) {
66
+ moved = true;
67
+ commitAxis(totalDx, totalDy);
68
+ }
69
+ const fired = [];
70
+ if (moved && axis !== null && dragBound[axis]) {
71
+ const delta = axis === "horizontal" ? x - lastX : y - lastY;
72
+ if (delta !== 0 && dragAccum !== 0 && Math.sign(delta) !== Math.sign(dragAccum))
73
+ dragAccum = 0;
74
+ dragAccum += delta;
75
+ while (Math.abs(dragAccum) >= dragStepPx) {
76
+ const direction = Math.sign(dragAccum);
77
+ const action = dragActionFor(direction);
78
+ dragAccum -= direction * dragStepPx;
79
+ if (action !== undefined) {
80
+ fired.push(action);
81
+ dragStepsFired += 1;
82
+ }
83
+ }
84
+ }
85
+ lastX = x;
86
+ lastY = y;
87
+ return fired;
88
+ },
89
+ end(x, y, nowMs) {
90
+ if (!active)
91
+ return [];
92
+ active = false;
93
+ const totalDx = x - startX;
94
+ const totalDy = y - startY;
95
+ const elapsed = nowMs - startTime;
96
+ if (!moved) {
97
+ if (elapsed <= tuning.tapMaxMs && bindings.tap !== undefined)
98
+ return [bindings.tap];
99
+ return [];
100
+ }
101
+ const travel = Math.hypot(totalDx, totalDy);
102
+ const velocity = elapsed <= 0 ? Infinity : travel / elapsed;
103
+ if (travel < tuning.swipeMinPx || velocity < tuning.swipeMinVelocity)
104
+ return [];
105
+ const direction = axis === "horizontal" ? Math.sign(totalDx) : Math.sign(totalDy);
106
+ if (axis !== null && dragBound[axis] && dragActionFor(direction) !== undefined)
107
+ return [];
108
+ const swipe = swipeFor(totalDx, totalDy);
109
+ if (swipe === undefined || dragStepsFired > 0)
110
+ return [];
111
+ return [swipe];
112
+ },
113
+ cancel() {
114
+ active = false;
115
+ },
116
+ isActive() {
117
+ return active;
118
+ },
119
+ };
120
+ }
@@ -14,6 +14,19 @@ export interface PointerHit {
14
14
  entity: string | null;
15
15
  /** Topmost scene-object instance id under the cursor, or null. */
16
16
  object: string | null;
17
+ /** Texture-space UV at the hit, when the intersected mesh carries UVs; absent for the ground-plane fallback. */
18
+ uv?: {
19
+ u: number;
20
+ v: number;
21
+ };
22
+ /** Sampled `#rrggbb` color + PBR params from the hit mesh's `MeshStandardMaterial` (#151.2); `null`/unset when the hit surface has no standard material (e.g. the ground plane). */
23
+ material?: {
24
+ color: string;
25
+ metalness?: number;
26
+ roughness?: number;
27
+ } | null;
28
+ /** Index of the hit instance when the intersected mesh is a `THREE.InstancedMesh`; absent otherwise. */
29
+ instanceId?: number;
17
30
  }
18
31
  export type PointerButton = "primary" | "secondary" | "middle";
19
32
  /** Build an `origin → point` aim for `item.use` / projectiles, firing toward the cursor. */
@@ -22,3 +35,35 @@ export declare function aimToPoint(origin: PointerVec3, point: PointerVec3): Aim
22
35
  export declare function moveTargetFromHit(hit: PointerHit): PointerVec3;
23
36
  /** Project a pointer hit onto the XZ plane for navmesh routing (`findPath` takes `[x, z]`). */
24
37
  export declare function groundOf(hit: PointerHit): readonly [number, number];
38
+ /** Snapshot of an in-progress or just-released drag: origin/current cursor points plus the clamped pull vector. */
39
+ export interface DragState {
40
+ origin: PointerVec3;
41
+ current: PointerVec3;
42
+ /** `current - origin`, clamped to `maxPull` in length. */
43
+ pull: PointerVec3;
44
+ /** Length of `pull`, at most `maxPull`. */
45
+ magnitude: number;
46
+ /** `magnitude / maxPull`, in `[0, 1]`. `0` when `maxPull` is unset. */
47
+ fraction: number;
48
+ }
49
+ export type DragResult = DragState;
50
+ export interface DragCaptureConfig {
51
+ /** Clamp on pull-vector length. Unset (default) means unclamped. */
52
+ maxPull?: number;
53
+ /** Max distance from `origin` a `begin()` point may be to start a drag. Unset (default) means unrestricted. */
54
+ grabRadius?: number;
55
+ }
56
+ /** Renderer-agnostic drag-capture / pull-vector state machine for slingshot-style aiming, drawback abilities, and similar gestures. */
57
+ export interface DragCapture {
58
+ /** Start a drag at `origin` if `at` is within `grabRadius` of it. Returns whether the drag started. */
59
+ begin(origin: PointerVec3, at: PointerVec3): boolean;
60
+ /** Move the drag's current point. No-op when no drag is active. */
61
+ update(at: PointerVec3): void;
62
+ /** End the drag, returning its final state, or `null` if no drag was active. */
63
+ release(): DragResult | null;
64
+ /** Abort the drag without producing a result. */
65
+ cancel(): void;
66
+ /** The current drag state, or `null` when idle. */
67
+ state(): DragState | null;
68
+ }
69
+ export declare function createDragCapture(config?: DragCaptureConfig): DragCapture;
@@ -15,3 +15,51 @@ export function moveTargetFromHit(hit) {
15
15
  export function groundOf(hit) {
16
16
  return [hit.point[0], hit.point[2]];
17
17
  }
18
+ function subtractVec3(a, b) {
19
+ return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
20
+ }
21
+ function lengthVec3(v) {
22
+ return Math.hypot(v[0], v[1], v[2]);
23
+ }
24
+ export function createDragCapture(config = {}) {
25
+ const maxPull = config.maxPull ?? Number.POSITIVE_INFINITY;
26
+ const grabRadius = config.grabRadius ?? Number.POSITIVE_INFINITY;
27
+ let origin = null;
28
+ let current = null;
29
+ function snapshot() {
30
+ if (origin === null || current === null)
31
+ return null;
32
+ const offset = subtractVec3(current, origin);
33
+ const rawLength = lengthVec3(offset);
34
+ const scale = rawLength > maxPull && rawLength > 0 ? maxPull / rawLength : 1;
35
+ const pull = [offset[0] * scale, offset[1] * scale, offset[2] * scale];
36
+ const magnitude = Math.min(rawLength, maxPull);
37
+ const fraction = Number.isFinite(maxPull) && maxPull > 0 ? magnitude / maxPull : 0;
38
+ return { origin, current, pull, magnitude, fraction };
39
+ }
40
+ return {
41
+ begin(dragOrigin, at) {
42
+ if (lengthVec3(subtractVec3(at, dragOrigin)) > grabRadius)
43
+ return false;
44
+ origin = dragOrigin;
45
+ current = at;
46
+ return true;
47
+ },
48
+ update(at) {
49
+ if (origin === null)
50
+ return;
51
+ current = at;
52
+ },
53
+ release() {
54
+ const result = snapshot();
55
+ origin = null;
56
+ current = null;
57
+ return result;
58
+ },
59
+ cancel() {
60
+ origin = null;
61
+ current = null;
62
+ },
63
+ state: snapshot,
64
+ };
65
+ }
@@ -0,0 +1,30 @@
1
+ export interface PointerAxisState {
2
+ /** Horizontal pointer position over the play surface in `[-1, 1]`: `-1` at the left edge, `+1` at the right. */
3
+ x: number;
4
+ /** Vertical pointer position over the play surface in `[-1, 1]`, screen convention: `-1` at the top edge, `+1` at the bottom — negate for aim-up. */
5
+ y: number;
6
+ /** `false` after the pointer leaves the surface; the last position is retained. */
7
+ active: boolean;
8
+ }
9
+ /** Maps one pointer axis onto an analog axis target — the pointer-backed counterpart of an `AxisBinding`'s key lists. */
10
+ export interface PointerAxisBinding {
11
+ source: "x" | "y";
12
+ invert?: boolean;
13
+ /** Fraction of the half-range around center treated as zero; the remainder rescales to the full `[-1, 1]`. */
14
+ deadzone?: number;
15
+ /** Response-curve exponent on the magnitude: `1` linear (default), `>1` finer control near center. */
16
+ curve?: number;
17
+ }
18
+ export interface PointerSurfaceRect {
19
+ left: number;
20
+ top: number;
21
+ width: number;
22
+ height: number;
23
+ }
24
+ /** Normalize client coordinates against a surface rect into a `PointerAxisState`, clamped to `[-1, 1]` per axis. */
25
+ export declare function normalizePointerToAxis(clientX: number, clientY: number, rect: PointerSurfaceRect): PointerAxisState;
26
+ /**
27
+ * Resolve a pointer binding against the current pointer state: `null` when no pointer is active
28
+ * (callers fall back to their digital target), otherwise the deadzone/curve-shaped value in `[-1, 1]`.
29
+ */
30
+ export declare function pointerAxisValue(binding: PointerAxisBinding, state: PointerAxisState | null | undefined): number | null;
@@ -0,0 +1,31 @@
1
+ /** Normalize client coordinates against a surface rect into a `PointerAxisState`, clamped to `[-1, 1]` per axis. */
2
+ export function normalizePointerToAxis(clientX, clientY, rect) {
3
+ const width = rect.width > 0 ? rect.width : 1;
4
+ const height = rect.height > 0 ? rect.height : 1;
5
+ return {
6
+ x: clampUnit(((clientX - rect.left) / width) * 2 - 1),
7
+ y: clampUnit(((clientY - rect.top) / height) * 2 - 1),
8
+ active: true,
9
+ };
10
+ }
11
+ /**
12
+ * Resolve a pointer binding against the current pointer state: `null` when no pointer is active
13
+ * (callers fall back to their digital target), otherwise the deadzone/curve-shaped value in `[-1, 1]`.
14
+ */
15
+ export function pointerAxisValue(binding, state) {
16
+ if (state === null || state === undefined || !state.active)
17
+ return null;
18
+ let value = binding.source === "x" ? state.x : state.y;
19
+ if (binding.invert === true)
20
+ value = -value;
21
+ const deadzone = binding.deadzone ?? 0;
22
+ const magnitude = Math.abs(value);
23
+ if (magnitude <= deadzone)
24
+ return 0;
25
+ const scaled = (magnitude - deadzone) / (1 - deadzone);
26
+ const curved = Math.pow(Math.min(scaled, 1), binding.curve ?? 1);
27
+ return Math.sign(value) * curved;
28
+ }
29
+ function clampUnit(value) {
30
+ return value < -1 ? -1 : value > 1 ? 1 : value;
31
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Touch control scheme derived from a game's existing action bindings: the
3
+ * capture layer renders a virtual joystick, on-screen buttons, and a gesture
4
+ * surface, and feeds synthetic `touch:<action>` codes into the same
5
+ * ActionStateTracker the keyboard uses, so games gain touch play without any
6
+ * per-game input code. Games refine the derived defaults through
7
+ * TouchControlsConfig (gesture bindings, button curation) or opt out entirely
8
+ * with `touch: false`.
9
+ */
10
+ import { type ActionCodesMap } from "./actionBindings.js";
11
+ export declare const TOUCH_CODE_PREFIX = "touch:";
12
+ export declare function touchCode(action: string): string;
13
+ /** Every action gains a synthetic touch code alongside its physical codes. */
14
+ export declare function withTouchCodes(map: ActionCodesMap | undefined): ActionCodesMap;
15
+ export interface TouchDragBinding {
16
+ /** Action fired once per `stepPx` of travel toward that side. */
17
+ left?: string;
18
+ right?: string;
19
+ up?: string;
20
+ down?: string;
21
+ stepPx?: number;
22
+ }
23
+ export interface TouchGestureBindings {
24
+ /** Action fired by a quick still tap on the play surface. */
25
+ tap?: string;
26
+ /** Actions fired by a fast flick past the swipe threshold. */
27
+ swipeUp?: string;
28
+ swipeDown?: string;
29
+ swipeLeft?: string;
30
+ swipeRight?: string;
31
+ /** Continuous drag: repeats the directional action every `stepPx` of travel. Wins over swipes on its axis, except a flick can still fire the swipe binding for a direction the drag leaves unbound. */
32
+ drag?: TouchDragBinding;
33
+ }
34
+ export interface TouchButtonSpec {
35
+ action: string;
36
+ label?: string;
37
+ /** Glyph name from the capture layer's icon catalog (`@jgengine/react/gameIcons` `GameIconName`); unset derives one from the action name, `false` forces the text label. */
38
+ icon?: string | false;
39
+ /** Overrides the derived classification: `primary` renders as a large thumb button, `utility` as a small chip away from the thumb zones. */
40
+ kind?: TouchButtonKind;
41
+ }
42
+ export interface TouchControlsConfig {
43
+ /** `false` removes the virtual joystick even when movement actions are bound. */
44
+ movement?: false;
45
+ /** Curated on-screen buttons (order preserved); omit to derive one button per remaining action. */
46
+ buttons?: readonly (string | TouchButtonSpec)[];
47
+ /** Play-surface gestures; actions consumed here stop appearing as derived buttons. */
48
+ gestures?: TouchGestureBindings;
49
+ /** Drag-to-look on the play surface; defaults to true for first-person games. */
50
+ look?: boolean;
51
+ /** Radians of look rotation per pixel of touch travel. Default 0.005. */
52
+ lookSensitivity?: number;
53
+ /** Actions to leave off the derived button cluster. */
54
+ hidden?: readonly string[];
55
+ }
56
+ export interface TouchJoystick {
57
+ up: string | null;
58
+ down: string | null;
59
+ left: string | null;
60
+ right: string | null;
61
+ }
62
+ export type TouchButtonKind = "primary" | "utility";
63
+ export interface TouchButton {
64
+ action: string;
65
+ label: string;
66
+ /** Glyph hint for the capture layer: a name to render, `false` to force text, null to derive from the action name. */
67
+ icon: string | false | null;
68
+ /** `primary` = frequent gameplay verb, rendered as a large thumb button; `utility` = meta action (start, restart, pause, toggles), rendered as a small chip. */
69
+ kind: TouchButtonKind;
70
+ }
71
+ export interface TouchScheme {
72
+ joystick: TouchJoystick | null;
73
+ buttons: readonly TouchButton[];
74
+ gestures: TouchGestureBindings | null;
75
+ look: boolean;
76
+ lookSensitivity: number;
77
+ }
78
+ export declare function touchButtonKind(action: string): TouchButtonKind;
79
+ export declare function touchActionLabel(action: string): string;
80
+ export interface DeriveTouchSchemeOptions {
81
+ reserved: ReadonlySet<string>;
82
+ firstPerson: boolean;
83
+ config?: TouchControlsConfig | false;
84
+ }
85
+ /**
86
+ * Null means "render no touch controls" — either the game opted out or there
87
+ * is nothing to synthesize.
88
+ */
89
+ export declare function deriveTouchScheme(input: ActionCodesMap | undefined, { reserved, firstPerson, config }: DeriveTouchSchemeOptions): TouchScheme | null;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Touch control scheme derived from a game's existing action bindings: the
3
+ * capture layer renders a virtual joystick, on-screen buttons, and a gesture
4
+ * surface, and feeds synthetic `touch:<action>` codes into the same
5
+ * ActionStateTracker the keyboard uses, so games gain touch play without any
6
+ * per-game input code. Games refine the derived defaults through
7
+ * TouchControlsConfig (gesture bindings, button curation) or opt out entirely
8
+ * with `touch: false`.
9
+ */
10
+ import { isHotbarSlotAction } from "./actionBindings.js";
11
+ export const TOUCH_CODE_PREFIX = "touch:";
12
+ export function touchCode(action) {
13
+ return `${TOUCH_CODE_PREFIX}${action}`;
14
+ }
15
+ /** Every action gains a synthetic touch code alongside its physical codes. */
16
+ export function withTouchCodes(map) {
17
+ const result = {};
18
+ for (const action of Object.keys(map ?? {})) {
19
+ const codes = map[action];
20
+ const synthetic = touchCode(action);
21
+ if (Array.isArray(codes)) {
22
+ result[action] = [...codes, synthetic];
23
+ }
24
+ else {
25
+ const modes = codes;
26
+ const toggleOnly = (modes.toggle?.length ?? 0) > 0 && (modes.hold?.length ?? 0) === 0;
27
+ result[action] = toggleOnly
28
+ ? { hold: modes.hold, toggle: [...(modes.toggle ?? []), synthetic] }
29
+ : { hold: [...(modes.hold ?? []), synthetic], toggle: modes.toggle };
30
+ }
31
+ }
32
+ return result;
33
+ }
34
+ const DEFAULT_LOOK_SENSITIVITY = 0.005;
35
+ const JOYSTICK_AXES = {
36
+ up: ["moveForward", "moveUp", "forward", "accelerate", "throttleUp", "pitchUp", "climb"],
37
+ down: ["moveBack", "moveBackward", "moveDown", "backward", "reverse", "brake", "throttleDown", "pitchDown", "dive"],
38
+ left: ["moveLeft", "turnLeft", "steerLeft", "yawLeft", "strafeLeft", "bankLeft", "rollLeft"],
39
+ right: ["moveRight", "turnRight", "steerRight", "yawRight", "strafeRight", "bankRight", "rollRight"],
40
+ };
41
+ const BUTTONABLE_RESERVED = new Set(["jump", "sprint", "interact", "useAbility"]);
42
+ const UTILITY_ACTIONS = new Set([
43
+ "start",
44
+ "restart",
45
+ "reset",
46
+ "retry",
47
+ "pause",
48
+ "resume",
49
+ "menu",
50
+ "quit",
51
+ "exit",
52
+ "mute",
53
+ "unmute",
54
+ "help",
55
+ "settings",
56
+ "options",
57
+ "map",
58
+ "inventory",
59
+ "scoreboard",
60
+ "leaderboard",
61
+ ]);
62
+ const UTILITY_PREFIXES = ["toggle", "cycle", "switch", "open", "close", "show", "hide", "zoom"];
63
+ export function touchButtonKind(action) {
64
+ if (UTILITY_ACTIONS.has(action))
65
+ return "utility";
66
+ for (const prefix of UTILITY_PREFIXES) {
67
+ if (!action.startsWith(prefix))
68
+ continue;
69
+ const next = action.charAt(prefix.length);
70
+ if (next !== "" && next === next.toUpperCase())
71
+ return "utility";
72
+ }
73
+ return "primary";
74
+ }
75
+ export function touchActionLabel(action) {
76
+ const spaced = action.replace(/([a-z0-9])([A-Z])/g, "$1 $2");
77
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1);
78
+ }
79
+ function gestureActions(gestures) {
80
+ const used = new Set();
81
+ if (gestures === undefined)
82
+ return used;
83
+ for (const action of [gestures.tap, gestures.swipeUp, gestures.swipeDown, gestures.swipeLeft, gestures.swipeRight]) {
84
+ if (action !== undefined)
85
+ used.add(action);
86
+ }
87
+ const drag = gestures.drag;
88
+ for (const action of [drag?.left, drag?.right, drag?.up, drag?.down]) {
89
+ if (action !== undefined)
90
+ used.add(action);
91
+ }
92
+ return used;
93
+ }
94
+ /**
95
+ * Null means "render no touch controls" — either the game opted out or there
96
+ * is nothing to synthesize.
97
+ */
98
+ export function deriveTouchScheme(input, { reserved, firstPerson, config }) {
99
+ if (config === false)
100
+ return null;
101
+ const actions = Object.keys(input ?? {});
102
+ const bound = new Set(actions);
103
+ const joystickMapped = new Set();
104
+ let joystick = null;
105
+ if (config?.movement !== false) {
106
+ const resolveAxis = (candidates) => {
107
+ const action = candidates.find((candidate) => bound.has(candidate)) ?? null;
108
+ if (action !== null)
109
+ joystickMapped.add(action);
110
+ return action;
111
+ };
112
+ const axes = {
113
+ up: resolveAxis(JOYSTICK_AXES.up),
114
+ down: resolveAxis(JOYSTICK_AXES.down),
115
+ left: resolveAxis(JOYSTICK_AXES.left),
116
+ right: resolveAxis(JOYSTICK_AXES.right),
117
+ };
118
+ joystick = axes.up === null && axes.down === null && axes.left === null && axes.right === null ? null : axes;
119
+ }
120
+ const gestures = config?.gestures ?? null;
121
+ const consumedByGestures = gestureActions(config?.gestures);
122
+ const hidden = new Set(config?.hidden ?? []);
123
+ let buttons;
124
+ if (config?.buttons !== undefined) {
125
+ buttons = config.buttons.map((spec) => typeof spec === "string"
126
+ ? { action: spec, label: touchActionLabel(spec), icon: null, kind: touchButtonKind(spec) }
127
+ : {
128
+ action: spec.action,
129
+ label: spec.label ?? touchActionLabel(spec.action),
130
+ icon: spec.icon ?? null,
131
+ kind: spec.kind ?? touchButtonKind(spec.action),
132
+ });
133
+ }
134
+ else {
135
+ buttons = actions
136
+ .filter((action) => !joystickMapped.has(action))
137
+ .filter((action) => !isHotbarSlotAction(action))
138
+ .filter((action) => !consumedByGestures.has(action))
139
+ .filter((action) => !hidden.has(action))
140
+ .filter((action) => !reserved.has(action) || BUTTONABLE_RESERVED.has(action))
141
+ .map((action) => ({ action, label: touchActionLabel(action), icon: null, kind: touchButtonKind(action) }));
142
+ }
143
+ const look = config?.look ?? firstPerson;
144
+ if (joystick === null && buttons.length === 0 && gestures === null && !look)
145
+ return null;
146
+ return {
147
+ joystick,
148
+ buttons,
149
+ gestures,
150
+ look,
151
+ lookSensitivity: config?.lookSensitivity ?? DEFAULT_LOOK_SENSITIVITY,
152
+ };
153
+ }
@@ -45,7 +45,7 @@ export interface RolledItem {
45
45
  affixes: readonly RolledAffix[];
46
46
  stats: Record<string, number>;
47
47
  }
48
- export declare function seededRng(seed: string | number): () => number;
48
+ export { seededRng } from "../random/rng.js";
49
49
  export interface AffixRoller {
50
50
  rollRarity(rng: () => number): RarityTier;
51
51
  roll(base: ItemBaseDef, rarityId: string, rng: () => number): RolledItem;